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.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"
37
38namespace content {
39namespace {
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
46static 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.
62void DestroySharedImage(Display* 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 ui::GetXDisplay() ever gets fixed to handle multiple Displays,
76// this must be modified to be per Display instead of a Singleton.
77class 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                        Display* 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, 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();
107    }
108
109    TransportDIB* dib;
110
111    // The display we're running on.
112    Display* 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
144void 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));
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(ui::GetXDisplay(),
157                     backing_store_sync_counter_,
158                     value);
159}
160
161XSyncHandler::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);
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
190XSyncHandler::~XSyncHandler() {
191  if (loaded_extension_)
192    gdk_window_remove_filter(NULL, &OnEventThunk, this);
193
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;
204  }
205}
206
207GdkFilterReturn 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
246BackingStoreGtk::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
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_ = ui::BitsPerPixelForPixmapDepth(display_, depth);
276  }
277
278  pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
279}
280
281BackingStoreGtk::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
296BackingStoreGtk::~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
306size_t BackingStoreGtk::MemorySize() {
307  if (!use_render_)
308    return size().GetArea() * (pixmap_bpp_ / 8);
309  else
310    return size().GetArea() * 4;
311}
312
313void 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  ui::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
344void 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
516bool 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
625void 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
660void 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)
668void 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
693