Index: content/browser/renderer_host/backing_store_gtk.cc |
diff --git a/content/browser/renderer_host/backing_store_gtk.cc b/content/browser/renderer_host/backing_store_gtk.cc |
deleted file mode 100644 |
index 147ee4d224e637c49d20bfeca05b0ad29f2b3f80..0000000000000000000000000000000000000000 |
--- a/content/browser/renderer_host/backing_store_gtk.cc |
+++ /dev/null |
@@ -1,692 +0,0 @@ |
-// 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 "content/browser/renderer_host/backing_store_gtk.h" |
- |
-#include <cairo-xlib.h> |
-#include <gtk/gtk.h> |
-#include <stdlib.h> |
-#include <sys/ipc.h> |
-#include <sys/shm.h> |
-#include <X11/extensions/sync.h> |
- |
-#if defined(OS_OPENBSD) || defined(OS_FREEBSD) |
-#include <sys/endian.h> |
-#endif |
- |
-#include <algorithm> |
-#include <limits> |
-#include <queue> |
-#include <utility> |
- |
-#include "base/compiler_specific.h" |
-#include "base/logging.h" |
-#include "base/memory/singleton.h" |
-#include "base/metrics/histogram.h" |
-#include "base/time/time.h" |
-#include "content/browser/renderer_host/render_process_host_impl.h" |
-#include "skia/ext/platform_canvas.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
-#include "ui/base/gtk/gtk_signal.h" |
-#include "ui/base/x/x11_util_internal.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/rect_conversions.h" |
-#include "ui/gfx/x/x11_types.h" |
-#include "ui/surface/transport_dib.h" |
- |
-namespace content { |
-namespace { |
- |
-// Assume that somewhere along the line, someone will do width * height * 4 |
-// with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = |
-// 2**29 and floor(sqrt(2**29)) = 23170. |
- |
-// Max height and width for layers |
-static const int kMaxVideoLayerSize = 23170; |
- |
- |
-// X Backing Stores: |
-// |
-// Unlike Windows, where the backing store is kept in heap memory, we keep our |
-// backing store in the X server, as a pixmap. Thus expose events just require |
-// instructing the X server to copy from the backing store to the window. |
-// |
-// The backing store is in the same format as the visual which our main window |
-// is using. Bitmaps from the renderer are uploaded to the X server, either via |
-// shared memory or over the wire, and XRENDER is used to convert them to the |
-// correct format for the backing store. |
- |
-// Destroys the image and the associated shared memory structures. This is a |
-// helper function for code using shared memory. |
-void DestroySharedImage(XDisplay* display, |
- XImage* image, |
- XShmSegmentInfo* shminfo) { |
- XShmDetach(display, shminfo); |
- XDestroyImage(image); |
- shmdt(shminfo->shmaddr); |
-} |
- |
-// So we don't don't want to call XSync(), which can block the UI loop for |
-// ~100ms on first paint and is generally slow. We optionally use the |
-// XSyncExtension to push a callback into the X11 event queue and get a |
-// callback instead of blocking until the event queue is cleared. |
-// |
-// TODO(erg): If gfx::GetXDisplay() ever gets fixed to handle multiple Displays, |
-// this must be modified to be per Display instead of a Singleton. |
-class XSyncHandler { |
- public: |
- static XSyncHandler* GetInstance() { |
- return Singleton<XSyncHandler>::get(); |
- } |
- |
- bool Enabled() { |
- return loaded_extension_; |
- } |
- |
- void PushPaintCounter(TransportDIB* dib, |
- XDisplay* display, |
- Picture picture, |
- Pixmap pixmap, |
- const base::Closure& completion_callback); |
- |
- private: |
- friend struct DefaultSingletonTraits<XSyncHandler>; |
- |
- // A struct that has cleanup and callback tasks that were queued into the |
- // future and are run on |g_backing_store_sync_alarm| firing. |
- struct BackingStoreEvents { |
- BackingStoreEvents(TransportDIB* dib, XDisplay* d, Picture pic, Pixmap pix, |
- const base::Closure& c) |
- : dib(dib), |
- display(d), |
- picture(pic), |
- pixmap(pix), |
- closure(c) { |
- dib->IncreaseInFlightCounter(); |
- } |
- |
- TransportDIB* dib; |
- |
- // The display we're running on. |
- XDisplay* display; |
- |
- // Data to delete. |
- Picture picture; |
- Pixmap pixmap; |
- |
- // Callback once everything else is done. |
- base::Closure closure; |
- }; |
- |
- XSyncHandler(); |
- ~XSyncHandler(); |
- |
- // An event filter notified about all XEvents. We then filter out XSync |
- // events that are on counters that we made. |
- CHROMEG_CALLBACK_1(XSyncHandler, GdkFilterReturn, OnEvent, GdkXEvent*, |
- GdkEvent*); |
- |
- // Whether we successfully loaded XSyncExtension. |
- bool loaded_extension_; |
- |
- // The event ids returned to us by XSyncQueryExtension(). |
- int xsync_event_base_; |
- int xsync_error_base_; |
- |
- XSyncCounter backing_store_sync_counter_; |
- XSyncAlarm backing_store_sync_alarm_; |
- |
- // A queue of pending paints that we clean up after as alarms fire. |
- std::queue<BackingStoreEvents*> backing_store_events_; |
-}; |
- |
-void XSyncHandler::PushPaintCounter(TransportDIB* dib, |
- XDisplay* display, |
- Picture picture, |
- Pixmap pixmap, |
- const base::Closure& completion_callback) { |
- backing_store_events_.push(new BackingStoreEvents( |
- dib, display, picture, pixmap, completion_callback)); |
- |
- // Push a change counter event into the X11 event queue that will trigger our |
- // alarm when it is processed. |
- XSyncValue value; |
- XSyncIntToValue(&value, 1); |
- XSyncChangeCounter(gfx::GetXDisplay(), |
- backing_store_sync_counter_, |
- value); |
-} |
- |
-XSyncHandler::XSyncHandler() |
- : loaded_extension_(false), |
- xsync_event_base_(0), |
- xsync_error_base_(0), |
- backing_store_sync_counter_(0), |
- backing_store_sync_alarm_(0) { |
- XDisplay* display = gfx::GetXDisplay(); |
- if (XSyncQueryExtension(display, |
- &xsync_event_base_, |
- &xsync_error_base_)) { |
- // Create our monotonically increasing counter. |
- XSyncValue value; |
- XSyncIntToValue(&value, 0); |
- backing_store_sync_counter_ = XSyncCreateCounter(display, value); |
- |
- // Cerate our alarm that watches for changes to our counter. |
- XSyncAlarmAttributes attributes; |
- attributes.trigger.counter = backing_store_sync_counter_; |
- backing_store_sync_alarm_ = XSyncCreateAlarm(display, |
- XSyncCACounter, |
- &attributes); |
- |
- // Add our filter to the message loop to handle alarm triggers. |
- gdk_window_add_filter(NULL, &OnEventThunk, this); |
- |
- loaded_extension_ = true; |
- } |
-} |
- |
-XSyncHandler::~XSyncHandler() { |
- if (loaded_extension_) |
- gdk_window_remove_filter(NULL, &OnEventThunk, this); |
- |
- XSync(gfx::GetXDisplay(), False); |
- while (!backing_store_events_.empty()) { |
- // We delete the X11 resources we're holding onto. We don't run the |
- // callbacks because we are shutting down. |
- BackingStoreEvents* data = backing_store_events_.front(); |
- backing_store_events_.pop(); |
- XRenderFreePicture(data->display, data->picture); |
- XFreePixmap(data->display, data->pixmap); |
- data->dib->DecreaseInFlightCounter(); |
- delete data; |
- } |
-} |
- |
-GdkFilterReturn XSyncHandler::OnEvent(GdkXEvent* gdkxevent, |
- GdkEvent* event) { |
- XEvent* xevent = reinterpret_cast<XEvent*>(gdkxevent); |
- if (xevent->type == xsync_event_base_ + XSyncAlarmNotify) { |
- XSyncAlarmNotifyEvent* alarm_event = |
- reinterpret_cast<XSyncAlarmNotifyEvent*>(xevent); |
- if (alarm_event->alarm == backing_store_sync_alarm_) { |
- if (alarm_event->counter_value.hi == 0 && |
- alarm_event->counter_value.lo == 0) { |
- // We receive an event about the initial state of the counter during |
- // alarm creation. We must ignore this event instead of responding to |
- // it. |
- return GDK_FILTER_REMOVE; |
- } |
- |
- DCHECK(!backing_store_events_.empty()); |
- BackingStoreEvents* data = backing_store_events_.front(); |
- backing_store_events_.pop(); |
- |
- // We are responsible for deleting all the data in the struct now that |
- // we are finished with it. |
- XRenderFreePicture(data->display, data->picture); |
- XFreePixmap(data->display, data->pixmap); |
- |
- // Dispatch the closure we were given. |
- data->closure.Run(); |
- |
- data->dib->DecreaseInFlightCounter(); |
- delete data; |
- |
- return GDK_FILTER_REMOVE; |
- } |
- } |
- |
- return GDK_FILTER_CONTINUE; |
-} |
- |
-} // namespace |
- |
-BackingStoreGtk::BackingStoreGtk(RenderWidgetHost* widget, |
- const gfx::Size& size, |
- void* visual, |
- int depth) |
- : BackingStore(widget, size), |
- display_(gfx::GetXDisplay()), |
- shared_memory_support_(ui::QuerySharedMemorySupport(display_)), |
- use_render_(ui::QueryRenderSupport(display_)), |
- visual_(visual), |
- visual_depth_(depth), |
- root_window_(ui::GetX11RootWindow()) { |
-#if defined(OS_OPENBSD) || defined(OS_FREEBSD) |
- COMPILE_ASSERT(_BYTE_ORDER == _LITTLE_ENDIAN, assumes_little_endian); |
-#else |
- COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian); |
-#endif |
- |
- pixmap_ = XCreatePixmap(display_, root_window_, |
- size.width(), size.height(), depth); |
- |
- if (use_render_) { |
- picture_ = XRenderCreatePicture( |
- display_, pixmap_, |
- ui::GetRenderVisualFormat(display_, |
- static_cast<Visual*>(visual)), |
- 0, NULL); |
- pixmap_bpp_ = 0; |
- } else { |
- picture_ = 0; |
- pixmap_bpp_ = gfx::BitsPerPixelForPixmapDepth(display_, depth); |
- } |
- |
- pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL); |
-} |
- |
-BackingStoreGtk::BackingStoreGtk(RenderWidgetHost* widget, |
- const gfx::Size& size) |
- : BackingStore(widget, size), |
- display_(NULL), |
- shared_memory_support_(ui::SHARED_MEMORY_NONE), |
- use_render_(false), |
- pixmap_bpp_(0), |
- visual_(NULL), |
- visual_depth_(-1), |
- root_window_(0), |
- pixmap_(0), |
- picture_(0), |
- pixmap_gc_(NULL) { |
-} |
- |
-BackingStoreGtk::~BackingStoreGtk() { |
- // In unit tests, display_ may be NULL. |
- if (!display_) |
- return; |
- |
- XRenderFreePicture(display_, picture_); |
- XFreePixmap(display_, pixmap_); |
- XFreeGC(display_, static_cast<GC>(pixmap_gc_)); |
-} |
- |
-size_t BackingStoreGtk::MemorySize() { |
- if (!use_render_) |
- return size().GetArea() * (pixmap_bpp_ / 8); |
- else |
- return size().GetArea() * 4; |
-} |
- |
-void BackingStoreGtk::PaintRectWithoutXrender( |
- TransportDIB* bitmap, |
- const gfx::Rect& bitmap_rect, |
- const std::vector<gfx::Rect>& copy_rects) { |
- const int width = bitmap_rect.width(); |
- const int height = bitmap_rect.height(); |
- Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height, |
- visual_depth_); |
- |
- // Draw ARGB transport DIB onto our pixmap. |
- gfx::PutARGBImage(display_, visual_, visual_depth_, pixmap, |
- pixmap_gc_, static_cast<uint8*>(bitmap->memory()), |
- width, height); |
- |
- for (size_t i = 0; i < copy_rects.size(); i++) { |
- const gfx::Rect& copy_rect = copy_rects[i]; |
- XCopyArea(display_, |
- pixmap, // src |
- pixmap_, // dest |
- static_cast<GC>(pixmap_gc_), // gc |
- copy_rect.x() - bitmap_rect.x(), // src_x |
- copy_rect.y() - bitmap_rect.y(), // src_y |
- copy_rect.width(), // width |
- copy_rect.height(), // height |
- copy_rect.x(), // dest_x |
- copy_rect.y()); // dest_y |
- } |
- |
- XFreePixmap(display_, pixmap); |
-} |
- |
-void BackingStoreGtk::PaintToBackingStore( |
- RenderProcessHost* process, |
- TransportDIB::Id bitmap, |
- const gfx::Rect& bitmap_rect, |
- const std::vector<gfx::Rect>& copy_rects, |
- float scale_factor, |
- const base::Closure& completion_callback, |
- bool* scheduled_completion_callback) { |
- *scheduled_completion_callback = false; |
- |
- if (!display_) |
- return; |
- |
- if (bitmap_rect.IsEmpty()) |
- return; |
- |
- gfx::Rect pixel_bitmap_rect = gfx::ToEnclosedRect( |
- gfx::ScaleRect(bitmap_rect, scale_factor)); |
- const int width = pixel_bitmap_rect.width(); |
- const int height = pixel_bitmap_rect.height(); |
- |
- if (width <= 0 || width > kMaxVideoLayerSize || |
- height <= 0 || height > kMaxVideoLayerSize) |
- return; |
- |
- TransportDIB* dib = process->GetTransportDIB(bitmap); |
- if (!dib) |
- return; |
- |
- if (!use_render_) |
- return PaintRectWithoutXrender(dib, bitmap_rect, copy_rects); |
- |
- Picture picture; |
- Pixmap pixmap; |
- |
- if (shared_memory_support_ == ui::SHARED_MEMORY_PIXMAP) { |
- XShmSegmentInfo shminfo = {0}; |
- shminfo.shmseg = dib->MapToX(display_); |
- |
- // The NULL in the following is the |data| pointer: this is an artifact of |
- // Xlib trying to be helpful, rather than just exposing the X protocol. It |
- // assumes that we have the shared memory segment mapped into our memory, |
- // which we don't, and it's trying to calculate an offset by taking the |
- // difference between the |data| pointer and the address of the mapping in |
- // |shminfo|. Since both are NULL, the offset will be calculated to be 0, |
- // which is correct for us. |
- pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo, |
- width, height, 32); |
- } else { |
- // We don't have shared memory pixmaps. Fall back to creating a pixmap |
- // ourselves and putting an image on it. |
- pixmap = XCreatePixmap(display_, root_window_, width, height, 32); |
- GC gc = XCreateGC(display_, pixmap, 0, NULL); |
- |
- if (shared_memory_support_ == ui::SHARED_MEMORY_PUTIMAGE) { |
- const XID shmseg = dib->MapToX(display_); |
- |
- XShmSegmentInfo shminfo; |
- memset(&shminfo, 0, sizeof(shminfo)); |
- shminfo.shmseg = shmseg; |
- shminfo.shmaddr = static_cast<char*>(dib->memory()); |
- |
- XImage* image = XShmCreateImage(display_, static_cast<Visual*>(visual_), |
- 32, ZPixmap, |
- shminfo.shmaddr, &shminfo, |
- width, height); |
- |
- // This code path is important for performance and we have found that |
- // different techniques work better on different platforms. See |
- // http://code.google.com/p/chromium/issues/detail?id=44124. |
- // |
- // Checking for ARM is an approximation, but it seems to be a good one so |
- // far. |
-#if defined(ARCH_CPU_ARM_FAMILY) |
- for (size_t i = 0; i < copy_rects.size(); i++) { |
- const gfx::Rect& copy_rect = copy_rects[i]; |
- gfx::Rect pixel_copy_rect = gfx::ToEnclosedRect( |
- gfx::ScaleRect(copy_rect, scale_factor)); |
- XShmPutImage(display_, pixmap, gc, image, |
- pixel_copy_rect.x() - pixel_bitmap_rect.x(), /* source x */ |
- pixel_copy_rect.y() - pixel_bitmap_rect.y(), /* source y */ |
- pixel_copy_rect.x() - pixel_bitmap_rect.x(), /* dest x */ |
- pixel_copy_rect.y() - pixel_bitmap_rect.y(), /* dest y */ |
- pixel_copy_rect.width(), pixel_copy_rect.height(), |
- False /* send_event */); |
- } |
-#else |
- XShmPutImage(display_, pixmap, gc, image, |
- 0, 0 /* source x, y */, 0, 0 /* dest x, y */, |
- width, height, False /* send_event */); |
-#endif |
- XDestroyImage(image); |
- } else { // case SHARED_MEMORY_NONE |
- // No shared memory support, we have to copy the bitmap contents |
- // to the X server. Xlib wraps the underlying PutImage call |
- // behind several layers of functions which try to convert the |
- // image into the format which the X server expects. The |
- // following values hopefully disable all conversions. |
- XImage image; |
- memset(&image, 0, sizeof(image)); |
- |
- image.width = width; |
- image.height = height; |
- image.depth = 32; |
- image.bits_per_pixel = 32; |
- image.format = ZPixmap; |
- image.byte_order = LSBFirst; |
- image.bitmap_unit = 8; |
- image.bitmap_bit_order = LSBFirst; |
- image.bytes_per_line = width * 4; |
- image.red_mask = 0xff; |
- image.green_mask = 0xff00; |
- image.blue_mask = 0xff0000; |
- image.data = static_cast<char*>(dib->memory()); |
- |
- XPutImage(display_, pixmap, gc, &image, |
- 0, 0 /* source x, y */, 0, 0 /* dest x, y */, |
- width, height); |
- } |
- XFreeGC(display_, gc); |
- } |
- |
- picture = ui::CreatePictureFromSkiaPixmap(display_, pixmap); |
- |
- if (scale_factor != 1.0) { |
- float up_scale = 1.0 / scale_factor; |
- XTransform scaling = { { |
- { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0) }, |
- { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0) }, |
- { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(up_scale) } |
- } }; |
- XRenderSetPictureTransform(display_, picture, &scaling); |
- XRenderSetPictureFilter(display_, picture, FilterGood, NULL, 0); |
- } |
- for (size_t i = 0; i < copy_rects.size(); i++) { |
- const gfx::Rect& copy_rect = copy_rects[i]; |
- XRenderComposite(display_, |
- PictOpSrc, // op |
- picture, // src |
- 0, // mask |
- picture_, // dest |
- copy_rect.x() - bitmap_rect.x(), // src_x |
- copy_rect.y() - bitmap_rect.y(), // src_y |
- 0, // mask_x |
- 0, // mask_y |
- copy_rect.x(), // dest_x |
- copy_rect.y(), // dest_y |
- copy_rect.width(), // width |
- copy_rect.height()); // height |
- } |
- |
- // In the case of shared memory, we wait for the composite to complete so that |
- // we are sure that the X server has finished reading from the shared memory |
- // segment. |
- if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) { |
- XSyncHandler* handler = XSyncHandler::GetInstance(); |
- if (handler->Enabled()) { |
- *scheduled_completion_callback = true; |
- handler->PushPaintCounter( |
- dib, display_, picture, pixmap, completion_callback); |
- } else { |
- XSync(display_, False); |
- } |
- } |
- |
- if (*scheduled_completion_callback == false) { |
- // If we didn't schedule a callback, we need to delete our resources now. |
- XRenderFreePicture(display_, picture); |
- XFreePixmap(display_, pixmap); |
- } |
-} |
- |
-bool BackingStoreGtk::CopyFromBackingStore(const gfx::Rect& rect, |
- skia::PlatformBitmap* output) { |
- base::TimeTicks begin_time = base::TimeTicks::Now(); |
- |
- if (visual_depth_ < 24) { |
- // CopyFromBackingStore() copies pixels out of the XImage |
- // in a way that assumes that each component (red, green, |
- // blue) is a byte. This doesn't work on visuals which |
- // encode a pixel color with less than a byte per color. |
- return false; |
- } |
- |
- const int width = std::min(size().width(), rect.width()); |
- const int height = std::min(size().height(), rect.height()); |
- |
- XImage* image; |
- XShmSegmentInfo shminfo; // Used only when shared memory is enabled. |
- if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) { |
- // Use shared memory for faster copies when it's available. |
- Visual* visual = static_cast<Visual*>(visual_); |
- memset(&shminfo, 0, sizeof(shminfo)); |
- image = XShmCreateImage(display_, visual, 32, |
- ZPixmap, NULL, &shminfo, width, height); |
- if (!image) { |
- return false; |
- } |
- // Create the shared memory segment for the image and map it. |
- if (image->bytes_per_line == 0 || image->height == 0 || |
- static_cast<size_t>(image->height) > |
- (std::numeric_limits<size_t>::max() / image->bytes_per_line)) { |
- XDestroyImage(image); |
- return false; |
- } |
- shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, |
- IPC_CREAT|0600); |
- if (shminfo.shmid == -1) { |
- XDestroyImage(image); |
- LOG(WARNING) << "Failed to get shared memory segment. " |
- "Performance may be degraded."; |
- return false; |
- } else { |
- VLOG(1) << "Got shared memory segment " << shminfo.shmid; |
- } |
- |
- void* mapped_memory = shmat(shminfo.shmid, NULL, SHM_RDONLY); |
- shmctl(shminfo.shmid, IPC_RMID, 0); |
- if (mapped_memory == (void*)-1) { |
- XDestroyImage(image); |
- return false; |
- } |
- shminfo.shmaddr = image->data = static_cast<char*>(mapped_memory); |
- |
- if (!XShmAttach(display_, &shminfo) || |
- !XShmGetImage(display_, pixmap_, image, rect.x(), rect.y(), |
- AllPlanes)) { |
- DestroySharedImage(display_, image, &shminfo); |
- LOG(WARNING) << "X failed to get shared memory segment. " |
- "Performance may be degraded."; |
- return false; |
- } |
- |
- VLOG(1) << "Using X shared memory segment " << shminfo.shmid; |
- } else { |
- LOG(WARNING) << "Not using X shared memory."; |
- // Non-shared memory case just copy the image from the server. |
- image = XGetImage(display_, pixmap_, |
- rect.x(), rect.y(), width, height, |
- AllPlanes, ZPixmap); |
- } |
- |
- // TODO(jhawkins): Need to convert the image data if the image bits per pixel |
- // is not 32. |
- // Note that this also initializes the output bitmap as opaque. |
- if (!output->Allocate(width, height, true) || |
- image->bits_per_pixel != 32) { |
- if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) |
- DestroySharedImage(display_, image, &shminfo); |
- else |
- XDestroyImage(image); |
- return false; |
- } |
- |
- // The X image might have a different row stride, so iterate through |
- // it and copy each row out, only up to the pixels we're actually |
- // using. This code assumes a visual mode where a pixel is |
- // represented using a 32-bit unsigned int, with a byte per component. |
- const SkBitmap& bitmap = output->GetBitmap(); |
- SkAutoLockPixels alp(bitmap); |
- |
- for (int y = 0; y < height; y++) { |
- const uint32* src_row = reinterpret_cast<uint32*>( |
- &image->data[image->bytes_per_line * y]); |
- uint32* dest_row = bitmap.getAddr32(0, y); |
- for (int x = 0; x < width; ++x, ++dest_row) { |
- // Force alpha to be 0xff, because otherwise it causes rendering problems. |
- *dest_row = src_row[x] | 0xff000000; |
- } |
- } |
- |
- if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) |
- DestroySharedImage(display_, image, &shminfo); |
- else |
- XDestroyImage(image); |
- |
- HISTOGRAM_TIMES("BackingStore.RetrievalFromX", |
- base::TimeTicks::Now() - begin_time); |
- return true; |
-} |
- |
-void BackingStoreGtk::ScrollBackingStore(const gfx::Vector2d& delta, |
- const gfx::Rect& clip_rect, |
- const gfx::Size& view_size) { |
- if (!display_) |
- return; |
- |
- // We only support scrolling in one direction at a time. |
- DCHECK(delta.x() == 0 || delta.y() == 0); |
- |
- if (delta.y()) { |
- // Positive values of |delta|.y() scroll up |
- if (abs(delta.y()) < clip_rect.height()) { |
- XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_), |
- clip_rect.x() /* source x */, |
- std::max(clip_rect.y(), clip_rect.y() - delta.y()), |
- clip_rect.width(), |
- clip_rect.height() - abs(delta.y()), |
- clip_rect.x() /* dest x */, |
- std::max(clip_rect.y(), clip_rect.y() + delta.y()) /* dest y */ |
- ); |
- } |
- } else if (delta.x()) { |
- // Positive values of |delta|.x() scroll right |
- if (abs(delta.x()) < clip_rect.width()) { |
- XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_), |
- std::max(clip_rect.x(), clip_rect.x() - delta.x()), |
- clip_rect.y() /* source y */, |
- clip_rect.width() - abs(delta.x()), |
- clip_rect.height(), |
- std::max(clip_rect.x(), clip_rect.x() + delta.x()) /* dest x */, |
- clip_rect.y() /* dest x */); |
- } |
- } |
-} |
- |
-void BackingStoreGtk::XShowRect(const gfx::Point &origin, |
- const gfx::Rect& rect, XID target) { |
- XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_), |
- rect.x(), rect.y(), rect.width(), rect.height(), |
- rect.x() + origin.x(), rect.y() + origin.y()); |
-} |
- |
-#if defined(TOOLKIT_GTK) |
-void BackingStoreGtk::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) { |
- cairo_surface_t* surface = cairo_xlib_surface_create( |
- display_, pixmap_, static_cast<Visual*>(visual_), |
- size().width(), size().height()); |
- cairo_t* cr = gdk_cairo_create(target); |
- |
- cairo_translate(cr, rect.x(), rect.y()); |
- double x_scale = static_cast<double>(rect.width()) / size().width(); |
- double y_scale = static_cast<double>(rect.height()) / size().height(); |
- cairo_scale(cr, x_scale, y_scale); |
- |
- cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface); |
- cairo_pattern_set_filter(pattern, CAIRO_FILTER_BEST); |
- cairo_set_source(cr, pattern); |
- cairo_pattern_destroy(pattern); |
- |
- cairo_identity_matrix(cr); |
- |
- cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); |
- cairo_fill(cr); |
- cairo_destroy(cr); |
-} |
-#endif |
- |
-} // namespace content |