Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / backing_store_gtk.cc
bloba029fba1ce7364c1e0a6ea14ae5dd9bd6ef45c79
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/backing_store_gtk.h"
7 #include <cairo-xlib.h>
8 #include <gtk/gtk.h>
9 #include <stdlib.h>
10 #include <sys/ipc.h>
11 #include <sys/shm.h>
12 #include <X11/extensions/sync.h>
14 #if defined(OS_OPENBSD) || defined(OS_FREEBSD)
15 #include <sys/endian.h>
16 #endif
18 #include <algorithm>
19 #include <limits>
20 #include <queue>
21 #include <utility>
23 #include "base/compiler_specific.h"
24 #include "base/logging.h"
25 #include "base/memory/singleton.h"
26 #include "base/metrics/histogram.h"
27 #include "base/time.h"
28 #include "content/browser/renderer_host/render_process_host_impl.h"
29 #include "skia/ext/platform_canvas.h"
30 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "ui/base/gtk/gtk_signal.h"
32 #include "ui/base/x/x11_util.h"
33 #include "ui/base/x/x11_util_internal.h"
34 #include "ui/gfx/rect.h"
35 #include "ui/gfx/rect_conversions.h"
36 #include "ui/surface/transport_dib.h"
38 namespace content {
39 namespace {
41 // Assume that somewhere along the line, someone will do width * height * 4
42 // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 =
43 // 2**29 and floor(sqrt(2**29)) = 23170.
45 // Max height and width for layers
46 static const int kMaxVideoLayerSize = 23170;
49 // X Backing Stores:
51 // Unlike Windows, where the backing store is kept in heap memory, we keep our
52 // backing store in the X server, as a pixmap. Thus expose events just require
53 // instructing the X server to copy from the backing store to the window.
55 // The backing store is in the same format as the visual which our main window
56 // is using. Bitmaps from the renderer are uploaded to the X server, either via
57 // shared memory or over the wire, and XRENDER is used to convert them to the
58 // correct format for the backing store.
60 // Destroys the image and the associated shared memory structures. This is a
61 // helper function for code using shared memory.
62 void DestroySharedImage(Display* display,
63 XImage* image,
64 XShmSegmentInfo* shminfo) {
65 XShmDetach(display, shminfo);
66 XDestroyImage(image);
67 shmdt(shminfo->shmaddr);
70 // So we don't don't want to call XSync(), which can block the UI loop for
71 // ~100ms on first paint and is generally slow. We optionally use the
72 // XSyncExtension to push a callback into the X11 event queue and get a
73 // callback instead of blocking until the event queue is cleared.
75 // TODO(erg): If ui::GetXDisplay() ever gets fixed to handle multiple Displays,
76 // this must be modified to be per Display instead of a Singleton.
77 class XSyncHandler {
78 public:
79 static XSyncHandler* GetInstance() {
80 return Singleton<XSyncHandler>::get();
83 bool Enabled() {
84 return loaded_extension_;
87 void PushPaintCounter(TransportDIB* dib,
88 Display* display,
89 Picture picture,
90 Pixmap pixmap,
91 const base::Closure& completion_callback);
93 private:
94 friend struct DefaultSingletonTraits<XSyncHandler>;
96 // A struct that has cleanup and callback tasks that were queued into the
97 // future and are run on |g_backing_store_sync_alarm| firing.
98 struct BackingStoreEvents {
99 BackingStoreEvents(TransportDIB* dib, Display* d, Picture pic, Pixmap pix,
100 const base::Closure& c)
101 : dib(dib),
102 display(d),
103 picture(pic),
104 pixmap(pix),
105 closure(c) {
106 dib->IncreaseInFlightCounter();
109 TransportDIB* dib;
111 // The display we're running on.
112 Display* display;
114 // Data to delete.
115 Picture picture;
116 Pixmap pixmap;
118 // Callback once everything else is done.
119 base::Closure closure;
122 XSyncHandler();
123 ~XSyncHandler();
125 // An event filter notified about all XEvents. We then filter out XSync
126 // events that are on counters that we made.
127 CHROMEG_CALLBACK_1(XSyncHandler, GdkFilterReturn, OnEvent, GdkXEvent*,
128 GdkEvent*);
130 // Whether we successfully loaded XSyncExtension.
131 bool loaded_extension_;
133 // The event ids returned to us by XSyncQueryExtension().
134 int xsync_event_base_;
135 int xsync_error_base_;
137 XSyncCounter backing_store_sync_counter_;
138 XSyncAlarm backing_store_sync_alarm_;
140 // A queue of pending paints that we clean up after as alarms fire.
141 std::queue<BackingStoreEvents*> backing_store_events_;
144 void XSyncHandler::PushPaintCounter(TransportDIB* dib,
145 Display* display,
146 Picture picture,
147 Pixmap pixmap,
148 const base::Closure& completion_callback) {
149 backing_store_events_.push(new BackingStoreEvents(
150 dib, display, picture, pixmap, completion_callback));
152 // Push a change counter event into the X11 event queue that will trigger our
153 // alarm when it is processed.
154 XSyncValue value;
155 XSyncIntToValue(&value, 1);
156 XSyncChangeCounter(ui::GetXDisplay(),
157 backing_store_sync_counter_,
158 value);
161 XSyncHandler::XSyncHandler()
162 : loaded_extension_(false),
163 xsync_event_base_(0),
164 xsync_error_base_(0),
165 backing_store_sync_counter_(0),
166 backing_store_sync_alarm_(0) {
167 Display* display = ui::GetXDisplay();
168 if (XSyncQueryExtension(display,
169 &xsync_event_base_,
170 &xsync_error_base_)) {
171 // Create our monotonically increasing counter.
172 XSyncValue value;
173 XSyncIntToValue(&value, 0);
174 backing_store_sync_counter_ = XSyncCreateCounter(display, value);
176 // Cerate our alarm that watches for changes to our counter.
177 XSyncAlarmAttributes attributes;
178 attributes.trigger.counter = backing_store_sync_counter_;
179 backing_store_sync_alarm_ = XSyncCreateAlarm(display,
180 XSyncCACounter,
181 &attributes);
183 // Add our filter to the message loop to handle alarm triggers.
184 gdk_window_add_filter(NULL, &OnEventThunk, this);
186 loaded_extension_ = true;
190 XSyncHandler::~XSyncHandler() {
191 if (loaded_extension_)
192 gdk_window_remove_filter(NULL, &OnEventThunk, this);
194 XSync(ui::GetXDisplay(), False);
195 while (!backing_store_events_.empty()) {
196 // We delete the X11 resources we're holding onto. We don't run the
197 // callbacks because we are shutting down.
198 BackingStoreEvents* data = backing_store_events_.front();
199 backing_store_events_.pop();
200 XRenderFreePicture(data->display, data->picture);
201 XFreePixmap(data->display, data->pixmap);
202 data->dib->DecreaseInFlightCounter();
203 delete data;
207 GdkFilterReturn XSyncHandler::OnEvent(GdkXEvent* gdkxevent,
208 GdkEvent* event) {
209 XEvent* xevent = reinterpret_cast<XEvent*>(gdkxevent);
210 if (xevent->type == xsync_event_base_ + XSyncAlarmNotify) {
211 XSyncAlarmNotifyEvent* alarm_event =
212 reinterpret_cast<XSyncAlarmNotifyEvent*>(xevent);
213 if (alarm_event->alarm == backing_store_sync_alarm_) {
214 if (alarm_event->counter_value.hi == 0 &&
215 alarm_event->counter_value.lo == 0) {
216 // We receive an event about the initial state of the counter during
217 // alarm creation. We must ignore this event instead of responding to
218 // it.
219 return GDK_FILTER_REMOVE;
222 DCHECK(!backing_store_events_.empty());
223 BackingStoreEvents* data = backing_store_events_.front();
224 backing_store_events_.pop();
226 // We are responsible for deleting all the data in the struct now that
227 // we are finished with it.
228 XRenderFreePicture(data->display, data->picture);
229 XFreePixmap(data->display, data->pixmap);
231 // Dispatch the closure we were given.
232 data->closure.Run();
234 data->dib->DecreaseInFlightCounter();
235 delete data;
237 return GDK_FILTER_REMOVE;
241 return GDK_FILTER_CONTINUE;
244 } // namespace
246 BackingStoreGtk::BackingStoreGtk(RenderWidgetHost* widget,
247 const gfx::Size& size,
248 void* visual,
249 int depth)
250 : BackingStore(widget, size),
251 display_(ui::GetXDisplay()),
252 shared_memory_support_(ui::QuerySharedMemorySupport(display_)),
253 use_render_(ui::QueryRenderSupport(display_)),
254 visual_(visual),
255 visual_depth_(depth),
256 root_window_(ui::GetX11RootWindow()) {
257 #if defined(OS_OPENBSD) || defined(OS_FREEBSD)
258 COMPILE_ASSERT(_BYTE_ORDER == _LITTLE_ENDIAN, assumes_little_endian);
259 #else
260 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
261 #endif
263 pixmap_ = XCreatePixmap(display_, root_window_,
264 size.width(), size.height(), depth);
266 if (use_render_) {
267 picture_ = XRenderCreatePicture(
268 display_, pixmap_,
269 ui::GetRenderVisualFormat(display_,
270 static_cast<Visual*>(visual)),
271 0, NULL);
272 pixmap_bpp_ = 0;
273 } else {
274 picture_ = 0;
275 pixmap_bpp_ = ui::BitsPerPixelForPixmapDepth(display_, depth);
278 pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
281 BackingStoreGtk::BackingStoreGtk(RenderWidgetHost* widget,
282 const gfx::Size& size)
283 : BackingStore(widget, size),
284 display_(NULL),
285 shared_memory_support_(ui::SHARED_MEMORY_NONE),
286 use_render_(false),
287 pixmap_bpp_(0),
288 visual_(NULL),
289 visual_depth_(-1),
290 root_window_(0),
291 pixmap_(0),
292 picture_(0),
293 pixmap_gc_(NULL) {
296 BackingStoreGtk::~BackingStoreGtk() {
297 // In unit tests, display_ may be NULL.
298 if (!display_)
299 return;
301 XRenderFreePicture(display_, picture_);
302 XFreePixmap(display_, pixmap_);
303 XFreeGC(display_, static_cast<GC>(pixmap_gc_));
306 size_t BackingStoreGtk::MemorySize() {
307 if (!use_render_)
308 return size().GetArea() * (pixmap_bpp_ / 8);
309 else
310 return size().GetArea() * 4;
313 void BackingStoreGtk::PaintRectWithoutXrender(
314 TransportDIB* bitmap,
315 const gfx::Rect& bitmap_rect,
316 const std::vector<gfx::Rect>& copy_rects) {
317 const int width = bitmap_rect.width();
318 const int height = bitmap_rect.height();
319 Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height,
320 visual_depth_);
322 // Draw ARGB transport DIB onto our pixmap.
323 ui::PutARGBImage(display_, visual_, visual_depth_, pixmap,
324 pixmap_gc_, static_cast<uint8*>(bitmap->memory()),
325 width, height);
327 for (size_t i = 0; i < copy_rects.size(); i++) {
328 const gfx::Rect& copy_rect = copy_rects[i];
329 XCopyArea(display_,
330 pixmap, // src
331 pixmap_, // dest
332 static_cast<GC>(pixmap_gc_), // gc
333 copy_rect.x() - bitmap_rect.x(), // src_x
334 copy_rect.y() - bitmap_rect.y(), // src_y
335 copy_rect.width(), // width
336 copy_rect.height(), // height
337 copy_rect.x(), // dest_x
338 copy_rect.y()); // dest_y
341 XFreePixmap(display_, pixmap);
344 void BackingStoreGtk::PaintToBackingStore(
345 RenderProcessHost* process,
346 TransportDIB::Id bitmap,
347 const gfx::Rect& bitmap_rect,
348 const std::vector<gfx::Rect>& copy_rects,
349 float scale_factor,
350 const base::Closure& completion_callback,
351 bool* scheduled_completion_callback) {
352 *scheduled_completion_callback = false;
354 if (!display_)
355 return;
357 if (bitmap_rect.IsEmpty())
358 return;
360 gfx::Rect pixel_bitmap_rect = gfx::ToEnclosedRect(
361 gfx::ScaleRect(bitmap_rect, scale_factor));
362 const int width = pixel_bitmap_rect.width();
363 const int height = pixel_bitmap_rect.height();
365 if (width <= 0 || width > kMaxVideoLayerSize ||
366 height <= 0 || height > kMaxVideoLayerSize)
367 return;
369 TransportDIB* dib = process->GetTransportDIB(bitmap);
370 if (!dib)
371 return;
373 if (!use_render_)
374 return PaintRectWithoutXrender(dib, bitmap_rect, copy_rects);
376 Picture picture;
377 Pixmap pixmap;
379 if (shared_memory_support_ == ui::SHARED_MEMORY_PIXMAP) {
380 XShmSegmentInfo shminfo = {0};
381 shminfo.shmseg = dib->MapToX(display_);
383 // The NULL in the following is the |data| pointer: this is an artifact of
384 // Xlib trying to be helpful, rather than just exposing the X protocol. It
385 // assumes that we have the shared memory segment mapped into our memory,
386 // which we don't, and it's trying to calculate an offset by taking the
387 // difference between the |data| pointer and the address of the mapping in
388 // |shminfo|. Since both are NULL, the offset will be calculated to be 0,
389 // which is correct for us.
390 pixmap = XShmCreatePixmap(display_, root_window_, NULL, &shminfo,
391 width, height, 32);
392 } else {
393 // We don't have shared memory pixmaps. Fall back to creating a pixmap
394 // ourselves and putting an image on it.
395 pixmap = XCreatePixmap(display_, root_window_, width, height, 32);
396 GC gc = XCreateGC(display_, pixmap, 0, NULL);
398 if (shared_memory_support_ == ui::SHARED_MEMORY_PUTIMAGE) {
399 const XID shmseg = dib->MapToX(display_);
401 XShmSegmentInfo shminfo;
402 memset(&shminfo, 0, sizeof(shminfo));
403 shminfo.shmseg = shmseg;
404 shminfo.shmaddr = static_cast<char*>(dib->memory());
406 XImage* image = XShmCreateImage(display_, static_cast<Visual*>(visual_),
407 32, ZPixmap,
408 shminfo.shmaddr, &shminfo,
409 width, height);
411 // This code path is important for performance and we have found that
412 // different techniques work better on different platforms. See
413 // http://code.google.com/p/chromium/issues/detail?id=44124.
415 // Checking for ARM is an approximation, but it seems to be a good one so
416 // far.
417 #if defined(ARCH_CPU_ARM_FAMILY)
418 for (size_t i = 0; i < copy_rects.size(); i++) {
419 const gfx::Rect& copy_rect = copy_rects[i];
420 gfx::Rect pixel_copy_rect = gfx::ToEnclosedRect(
421 gfx::ScaleRect(copy_rect, scale_factor));
422 XShmPutImage(display_, pixmap, gc, image,
423 pixel_copy_rect.x() - pixel_bitmap_rect.x(), /* source x */
424 pixel_copy_rect.y() - pixel_bitmap_rect.y(), /* source y */
425 pixel_copy_rect.x() - pixel_bitmap_rect.x(), /* dest x */
426 pixel_copy_rect.y() - pixel_bitmap_rect.y(), /* dest y */
427 pixel_copy_rect.width(), pixel_copy_rect.height(),
428 False /* send_event */);
430 #else
431 XShmPutImage(display_, pixmap, gc, image,
432 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
433 width, height, False /* send_event */);
434 #endif
435 XDestroyImage(image);
436 } else { // case SHARED_MEMORY_NONE
437 // No shared memory support, we have to copy the bitmap contents
438 // to the X server. Xlib wraps the underlying PutImage call
439 // behind several layers of functions which try to convert the
440 // image into the format which the X server expects. The
441 // following values hopefully disable all conversions.
442 XImage image;
443 memset(&image, 0, sizeof(image));
445 image.width = width;
446 image.height = height;
447 image.depth = 32;
448 image.bits_per_pixel = 32;
449 image.format = ZPixmap;
450 image.byte_order = LSBFirst;
451 image.bitmap_unit = 8;
452 image.bitmap_bit_order = LSBFirst;
453 image.bytes_per_line = width * 4;
454 image.red_mask = 0xff;
455 image.green_mask = 0xff00;
456 image.blue_mask = 0xff0000;
457 image.data = static_cast<char*>(dib->memory());
459 XPutImage(display_, pixmap, gc, &image,
460 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
461 width, height);
463 XFreeGC(display_, gc);
466 picture = ui::CreatePictureFromSkiaPixmap(display_, pixmap);
468 if (scale_factor != 1.0) {
469 float up_scale = 1.0 / scale_factor;
470 XTransform scaling = { {
471 { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0) },
472 { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0) },
473 { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(up_scale) }
474 } };
475 XRenderSetPictureTransform(display_, picture, &scaling);
476 XRenderSetPictureFilter(display_, picture, FilterGood, NULL, 0);
478 for (size_t i = 0; i < copy_rects.size(); i++) {
479 const gfx::Rect& copy_rect = copy_rects[i];
480 XRenderComposite(display_,
481 PictOpSrc, // op
482 picture, // src
483 0, // mask
484 picture_, // dest
485 copy_rect.x() - bitmap_rect.x(), // src_x
486 copy_rect.y() - bitmap_rect.y(), // src_y
487 0, // mask_x
488 0, // mask_y
489 copy_rect.x(), // dest_x
490 copy_rect.y(), // dest_y
491 copy_rect.width(), // width
492 copy_rect.height()); // height
495 // In the case of shared memory, we wait for the composite to complete so that
496 // we are sure that the X server has finished reading from the shared memory
497 // segment.
498 if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) {
499 XSyncHandler* handler = XSyncHandler::GetInstance();
500 if (handler->Enabled()) {
501 *scheduled_completion_callback = true;
502 handler->PushPaintCounter(
503 dib, display_, picture, pixmap, completion_callback);
504 } else {
505 XSync(display_, False);
509 if (*scheduled_completion_callback == false) {
510 // If we didn't schedule a callback, we need to delete our resources now.
511 XRenderFreePicture(display_, picture);
512 XFreePixmap(display_, pixmap);
516 bool BackingStoreGtk::CopyFromBackingStore(const gfx::Rect& rect,
517 skia::PlatformBitmap* output) {
518 base::TimeTicks begin_time = base::TimeTicks::Now();
520 if (visual_depth_ < 24) {
521 // CopyFromBackingStore() copies pixels out of the XImage
522 // in a way that assumes that each component (red, green,
523 // blue) is a byte. This doesn't work on visuals which
524 // encode a pixel color with less than a byte per color.
525 return false;
528 const int width = std::min(size().width(), rect.width());
529 const int height = std::min(size().height(), rect.height());
531 XImage* image;
532 XShmSegmentInfo shminfo; // Used only when shared memory is enabled.
533 if (shared_memory_support_ != ui::SHARED_MEMORY_NONE) {
534 // Use shared memory for faster copies when it's available.
535 Visual* visual = static_cast<Visual*>(visual_);
536 memset(&shminfo, 0, sizeof(shminfo));
537 image = XShmCreateImage(display_, visual, 32,
538 ZPixmap, NULL, &shminfo, width, height);
539 if (!image) {
540 return false;
542 // Create the shared memory segment for the image and map it.
543 if (image->bytes_per_line == 0 || image->height == 0 ||
544 static_cast<size_t>(image->height) >
545 (std::numeric_limits<size_t>::max() / image->bytes_per_line)) {
546 XDestroyImage(image);
547 return false;
549 shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
550 IPC_CREAT|0600);
551 if (shminfo.shmid == -1) {
552 XDestroyImage(image);
553 LOG(WARNING) << "Failed to get shared memory segment. "
554 "Performance may be degraded.";
555 return false;
556 } else {
557 VLOG(1) << "Got shared memory segment " << shminfo.shmid;
560 void* mapped_memory = shmat(shminfo.shmid, NULL, SHM_RDONLY);
561 shmctl(shminfo.shmid, IPC_RMID, 0);
562 if (mapped_memory == (void*)-1) {
563 XDestroyImage(image);
564 return false;
566 shminfo.shmaddr = image->data = static_cast<char*>(mapped_memory);
568 if (!XShmAttach(display_, &shminfo) ||
569 !XShmGetImage(display_, pixmap_, image, rect.x(), rect.y(),
570 AllPlanes)) {
571 DestroySharedImage(display_, image, &shminfo);
572 LOG(WARNING) << "X failed to get shared memory segment. "
573 "Performance may be degraded.";
574 return false;
577 VLOG(1) << "Using X shared memory segment " << shminfo.shmid;
578 } else {
579 LOG(WARNING) << "Not using X shared memory.";
580 // Non-shared memory case just copy the image from the server.
581 image = XGetImage(display_, pixmap_,
582 rect.x(), rect.y(), width, height,
583 AllPlanes, ZPixmap);
586 // TODO(jhawkins): Need to convert the image data if the image bits per pixel
587 // is not 32.
588 // Note that this also initializes the output bitmap as opaque.
589 if (!output->Allocate(width, height, true) ||
590 image->bits_per_pixel != 32) {
591 if (shared_memory_support_ != ui::SHARED_MEMORY_NONE)
592 DestroySharedImage(display_, image, &shminfo);
593 else
594 XDestroyImage(image);
595 return false;
598 // The X image might have a different row stride, so iterate through
599 // it and copy each row out, only up to the pixels we're actually
600 // using. This code assumes a visual mode where a pixel is
601 // represented using a 32-bit unsigned int, with a byte per component.
602 const SkBitmap& bitmap = output->GetBitmap();
603 SkAutoLockPixels alp(bitmap);
605 for (int y = 0; y < height; y++) {
606 const uint32* src_row = reinterpret_cast<uint32*>(
607 &image->data[image->bytes_per_line * y]);
608 uint32* dest_row = bitmap.getAddr32(0, y);
609 for (int x = 0; x < width; ++x, ++dest_row) {
610 // Force alpha to be 0xff, because otherwise it causes rendering problems.
611 *dest_row = src_row[x] | 0xff000000;
615 if (shared_memory_support_ != ui::SHARED_MEMORY_NONE)
616 DestroySharedImage(display_, image, &shminfo);
617 else
618 XDestroyImage(image);
620 HISTOGRAM_TIMES("BackingStore.RetrievalFromX",
621 base::TimeTicks::Now() - begin_time);
622 return true;
625 void BackingStoreGtk::ScrollBackingStore(const gfx::Vector2d& delta,
626 const gfx::Rect& clip_rect,
627 const gfx::Size& view_size) {
628 if (!display_)
629 return;
631 // We only support scrolling in one direction at a time.
632 DCHECK(delta.x() == 0 || delta.y() == 0);
634 if (delta.y()) {
635 // Positive values of |delta|.y() scroll up
636 if (abs(delta.y()) < clip_rect.height()) {
637 XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
638 clip_rect.x() /* source x */,
639 std::max(clip_rect.y(), clip_rect.y() - delta.y()),
640 clip_rect.width(),
641 clip_rect.height() - abs(delta.y()),
642 clip_rect.x() /* dest x */,
643 std::max(clip_rect.y(), clip_rect.y() + delta.y()) /* dest y */
646 } else if (delta.x()) {
647 // Positive values of |delta|.x() scroll right
648 if (abs(delta.x()) < clip_rect.width()) {
649 XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
650 std::max(clip_rect.x(), clip_rect.x() - delta.x()),
651 clip_rect.y() /* source y */,
652 clip_rect.width() - abs(delta.x()),
653 clip_rect.height(),
654 std::max(clip_rect.x(), clip_rect.x() + delta.x()) /* dest x */,
655 clip_rect.y() /* dest x */);
660 void BackingStoreGtk::XShowRect(const gfx::Point &origin,
661 const gfx::Rect& rect, XID target) {
662 XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_),
663 rect.x(), rect.y(), rect.width(), rect.height(),
664 rect.x() + origin.x(), rect.y() + origin.y());
667 #if defined(TOOLKIT_GTK)
668 void BackingStoreGtk::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) {
669 cairo_surface_t* surface = cairo_xlib_surface_create(
670 display_, pixmap_, static_cast<Visual*>(visual_),
671 size().width(), size().height());
672 cairo_t* cr = gdk_cairo_create(target);
674 cairo_translate(cr, rect.x(), rect.y());
675 double x_scale = static_cast<double>(rect.width()) / size().width();
676 double y_scale = static_cast<double>(rect.height()) / size().height();
677 cairo_scale(cr, x_scale, y_scale);
679 cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
680 cairo_pattern_set_filter(pattern, CAIRO_FILTER_BEST);
681 cairo_set_source(cr, pattern);
682 cairo_pattern_destroy(pattern);
684 cairo_identity_matrix(cr);
686 cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
687 cairo_fill(cr);
688 cairo_destroy(cr);
690 #endif
692 } // namespace content