| // 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 |