summaryrefslogtreecommitdiff
path: root/chromium/ui/snapshot/snapshot_gtk.cc
blob: 8a2f8c1edd7003be501dde06f4e26109e1c7c07a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/snapshot/snapshot.h"

#include <gdk/gdkx.h>
#include <gtk/gtk.h>

#include "base/logging.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/rect.h"

namespace {

cairo_status_t SnapshotCallback(void* closure,
                                const unsigned char* data,
                                unsigned int length) {
  std::vector<unsigned char>* png_representation =
      static_cast<std::vector<unsigned char>*>(closure);

  size_t old_size = png_representation->size();
  png_representation->resize(old_size + length);
  memcpy(&(*png_representation)[old_size], data, length);
  return CAIRO_STATUS_SUCCESS;
}

}  // namespace

namespace ui {

bool GrabViewSnapshot(gfx::NativeView view_handle,
                        std::vector<unsigned char>* png_representation,
                        const gfx::Rect& snapshot_bounds) {
  GdkWindow* gdk_window = gtk_widget_get_window(view_handle);
  Display* display = GDK_WINDOW_XDISPLAY(gdk_window);
  XID win = GDK_WINDOW_XID(gdk_window);

  gfx::Rect window_bounds;
  if (ui::GetWindowRect(win, &window_bounds) == 0) {
    LOG(ERROR) << "Couldn't get window bounds";
    return false;
  }

  DCHECK_LE(snapshot_bounds.right(), window_bounds.width());
  DCHECK_LE(snapshot_bounds.bottom(), window_bounds.height());

  ui::XScopedImage image(XGetImage(
      display, win, snapshot_bounds.x(), snapshot_bounds.y(),
      snapshot_bounds.width(), snapshot_bounds.height(), AllPlanes, ZPixmap));
  if (!image.get()) {
    LOG(ERROR) << "Couldn't get image";
    return false;
  }
  if (image->depth != 24) {
    LOG(ERROR)<< "Unsupported image depth " << image->depth;
    return false;
  }
  cairo_surface_t* surface =
      cairo_image_surface_create_for_data(
          reinterpret_cast<unsigned char*>(image->data),
          CAIRO_FORMAT_RGB24,
          image->width,
          image->height,
          image->bytes_per_line);

  if (!surface) {
    LOG(ERROR) << "Unable to create Cairo surface from XImage data";
    return false;
  }
  cairo_surface_write_to_png_stream(
      surface, SnapshotCallback, png_representation);
  cairo_surface_destroy(surface);

  return true;
}

bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
                        std::vector<unsigned char>* png_representation,
                        const gfx::Rect& snapshot_bounds) {
  return GrabViewSnapshot(GTK_WIDGET(window_handle), png_representation,
      snapshot_bounds);
}

}  // namespace ui