- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / backing_store_gtk.cc
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.
4
5 #include "content/browser/renderer_host/backing_store_gtk.h"
6
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>
13
14 #if defined(OS_OPENBSD) || defined(OS_FREEBSD)
15 #include <sys/endian.h>
16 #endif
17
18 #include <algorithm>
19 #include <limits>
20 #include <queue>
21 #include <utility>
22
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/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_internal.h"
33 #include "ui/gfx/rect.h"
34 #include "ui/gfx/rect_conversions.h"
35 #include "ui/gfx/x/x11_types.h"
36 #include "ui/surface/transport_dib.h"
37
38 namespace content {
39 namespace {
40
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.
44
45 // Max height and width for layers
46 static const int kMaxVideoLayerSize = 23170;
47
48
49 // X Backing Stores:
50 //
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.
54 //
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.
59
60 // Destroys the image and the associated shared memory structures. This is a
61 // helper function for code using shared memory.
62 void DestroySharedImage(XDisplay* display,
63                         XImage* image,
64                         XShmSegmentInfo* shminfo) {
65   XShmDetach(display, shminfo);
66   XDestroyImage(image);
67   shmdt(shminfo->shmaddr);
68 }
69
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.
74 //
75 // TODO(erg): If gfx::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();
81   }
82
83   bool Enabled() {
84     return loaded_extension_;
85   }
86
87   void PushPaintCounter(TransportDIB* dib,
88                         XDisplay* display,
89                         Picture picture,
90                         Pixmap pixmap,
91                         const base::Closure& completion_callback);
92
93  private:
94   friend struct DefaultSingletonTraits<XSyncHandler>;
95
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, XDisplay* 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();
107     }
108
109     TransportDIB* dib;
110
111     // The display we're running on.
112     XDisplay* display;
113
114     // Data to delete.
115     Picture picture;
116     Pixmap pixmap;
117
118     // Callback once everything else is done.
119     base::Closure closure;
120   };
121
122   XSyncHandler();
123   ~XSyncHandler();
124
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*);
129
130   // Whether we successfully loaded XSyncExtension.
131   bool loaded_extension_;
132
133   // The event ids returned to us by XSyncQueryExtension().
134   int xsync_event_base_;
135   int xsync_error_base_;
136
137   XSyncCounter backing_store_sync_counter_;
138   XSyncAlarm backing_store_sync_alarm_;
139
140   // A queue of pending paints that we clean up after as alarms fire.
141   std::queue<BackingStoreEvents*> backing_store_events_;
142 };
143
144 void XSyncHandler::PushPaintCounter(TransportDIB* dib,
145                                     XDisplay* 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));
151
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(gfx::GetXDisplay(),
157                      backing_store_sync_counter_,
158                      value);
159 }
160
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   XDisplay* display = gfx::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);
175
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);
182
183     // Add our filter to the message loop to handle alarm triggers.
184     gdk_window_add_filter(NULL, &OnEventThunk, this);
185
186     loaded_extension_ = true;
187   }
188 }
189
190 XSyncHandler::~XSyncHandler() {
191   if (loaded_extension_)
192     gdk_window_remove_filter(NULL, &OnEventThunk, this);
193
194   XSync(gfx::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;
204   }
205 }
206
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;
220       }
221
222       DCHECK(!backing_store_events_.empty());
223       BackingStoreEvents* data = backing_store_events_.front();
224       backing_store_events_.pop();
225
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);
230
231       // Dispatch the closure we were given.
232       data->closure.Run();
233
234       data->dib->DecreaseInFlightCounter();
235       delete data;
236
237       return GDK_FILTER_REMOVE;
238     }
239   }
240
241   return GDK_FILTER_CONTINUE;
242 }
243
244 }  // namespace
245
246 BackingStoreGtk::BackingStoreGtk(RenderWidgetHost* widget,
247                                  const gfx::Size& size,
248                                  void* visual,
249                                  int depth)
250     : BackingStore(widget, size),
251       display_(gfx::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
262
263   pixmap_ = XCreatePixmap(display_, root_window_,
264                           size.width(), size.height(), depth);
265
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_ = gfx::BitsPerPixelForPixmapDepth(display_, depth);
276   }
277
278   pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
279 }
280
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) {
294 }
295
296 BackingStoreGtk::~BackingStoreGtk() {
297   // In unit tests, display_ may be NULL.
298   if (!display_)
299     return;
300
301   XRenderFreePicture(display_, picture_);
302   XFreePixmap(display_, pixmap_);
303   XFreeGC(display_, static_cast<GC>(pixmap_gc_));
304 }
305
306 size_t BackingStoreGtk::MemorySize() {
307   if (!use_render_)
308     return size().GetArea() * (pixmap_bpp_ / 8);
309   else
310     return size().GetArea() * 4;
311 }
312
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_);
321
322   // Draw ARGB transport DIB onto our pixmap.
323   gfx::PutARGBImage(display_, visual_, visual_depth_, pixmap,
324                     pixmap_gc_, static_cast<uint8*>(bitmap->memory()),
325                     width, height);
326
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
339   }
340
341   XFreePixmap(display_, pixmap);
342 }
343
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;
353
354   if (!display_)
355     return;
356
357   if (bitmap_rect.IsEmpty())
358     return;
359
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();
364
365   if (width <= 0 || width > kMaxVideoLayerSize ||
366       height <= 0 || height > kMaxVideoLayerSize)
367     return;
368
369   TransportDIB* dib = process->GetTransportDIB(bitmap);
370   if (!dib)
371     return;
372
373   if (!use_render_)
374     return PaintRectWithoutXrender(dib, bitmap_rect, copy_rects);
375
376   Picture picture;
377   Pixmap pixmap;
378
379   if (shared_memory_support_ == ui::SHARED_MEMORY_PIXMAP) {
380     XShmSegmentInfo shminfo = {0};
381     shminfo.shmseg = dib->MapToX(display_);
382
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);
397
398     if (shared_memory_support_ == ui::SHARED_MEMORY_PUTIMAGE) {
399       const XID shmseg = dib->MapToX(display_);
400
401       XShmSegmentInfo shminfo;
402       memset(&shminfo, 0, sizeof(shminfo));
403       shminfo.shmseg = shmseg;
404       shminfo.shmaddr = static_cast<char*>(dib->memory());
405
406       XImage* image = XShmCreateImage(display_, static_cast<Visual*>(visual_),
407                                       32, ZPixmap,
408                                       shminfo.shmaddr, &shminfo,
409                                       width, height);
410
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.
414       //
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 */);
429       }
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));
444
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());
458
459       XPutImage(display_, pixmap, gc, &image,
460                 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
461                 width, height);
462     }
463     XFreeGC(display_, gc);
464   }
465
466   picture = ui::CreatePictureFromSkiaPixmap(display_, pixmap);
467
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);
477   }
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
493   }
494
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);
506     }
507   }
508
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);
513   }
514 }
515
516 bool BackingStoreGtk::CopyFromBackingStore(const gfx::Rect& rect,
517                                            skia::PlatformBitmap* output) {
518   base::TimeTicks begin_time = base::TimeTicks::Now();
519
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;
526   }
527
528   const int width = std::min(size().width(), rect.width());
529   const int height = std::min(size().height(), rect.height());
530
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;
541     }
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;
548     }
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;
558     }
559
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;
565     }
566     shminfo.shmaddr = image->data = static_cast<char*>(mapped_memory);
567
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;
575     }
576
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);
584   }
585
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;
596   }
597
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);
604
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;
612     }
613   }
614
615   if (shared_memory_support_ != ui::SHARED_MEMORY_NONE)
616     DestroySharedImage(display_, image, &shminfo);
617   else
618     XDestroyImage(image);
619
620   HISTOGRAM_TIMES("BackingStore.RetrievalFromX",
621                   base::TimeTicks::Now() - begin_time);
622   return true;
623 }
624
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;
630
631   // We only support scrolling in one direction at a time.
632   DCHECK(delta.x() == 0 || delta.y() == 0);
633
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 */
644                 );
645     }
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 */);
656     }
657   }
658 }
659
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());
665 }
666
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);
673
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);
678
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);
683
684   cairo_identity_matrix(cr);
685
686   cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
687   cairo_fill(cr);
688   cairo_destroy(cr);
689 }
690 #endif
691
692 }  // namespace content