| /* |
| * Copyright (C) 2011, Igalia S.L. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "config.h" |
| #include "WidgetBackingStore.h" |
| |
| #include "GtkVersioning.h" |
| #include "RefPtrCairo.h" |
| #include <X11/Xlib.h> |
| #include <cairo-xlib.h> |
| #include <cairo.h> |
| #include <gdk/gdkx.h> |
| |
| namespace WebCore { |
| |
| class WidgetBackingStorePrivate { |
| WTF_MAKE_NONCOPYABLE(WidgetBackingStorePrivate); |
| WTF_MAKE_FAST_ALLOCATED; |
| |
| public: |
| Display* m_display; |
| Pixmap m_pixmap; |
| GC m_gc; |
| RefPtr<cairo_surface_t> m_surface; |
| |
| static PassOwnPtr<WidgetBackingStorePrivate> create(GtkWidget* widget, const IntSize& size) |
| { |
| return adoptPtr(new WidgetBackingStorePrivate(widget, size)); |
| } |
| |
| ~WidgetBackingStorePrivate() |
| { |
| XFreePixmap(m_display, m_pixmap); |
| XFreeGC(m_display, m_gc); |
| } |
| |
| private: |
| // We keep two copies of the surface here, which will double the memory usage, but increase |
| // scrolling performance since we do not have to keep reallocating a memory region during |
| // quick scrolling requests. |
| WidgetBackingStorePrivate(GtkWidget* widget, const IntSize& size) |
| { |
| GdkVisual* visual = gtk_widget_get_visual(widget); |
| GdkScreen* screen = gdk_visual_get_screen(visual); |
| m_display = GDK_SCREEN_XDISPLAY(screen); |
| m_pixmap = XCreatePixmap(m_display, |
| GDK_WINDOW_XID(gdk_screen_get_root_window(screen)), |
| size.width(), size.height(), |
| gdk_visual_get_depth(visual)); |
| m_gc = XCreateGC(m_display, m_pixmap, 0, 0); |
| |
| m_surface = adoptRef(cairo_xlib_surface_create(m_display, m_pixmap, |
| GDK_VISUAL_XVISUAL(visual), |
| size.width(), size.height())); |
| } |
| }; |
| |
| PassOwnPtr<WidgetBackingStore> WidgetBackingStore::create(GtkWidget* widget, const IntSize& size) |
| { |
| return adoptPtr(new WidgetBackingStore(widget, size)); |
| } |
| |
| WidgetBackingStore::WidgetBackingStore(GtkWidget* widget, const IntSize& size) |
| : m_private(WidgetBackingStorePrivate::create(widget, size)) |
| , m_size(size) |
| { |
| } |
| |
| WidgetBackingStore::~WidgetBackingStore() |
| { |
| } |
| |
| cairo_surface_t* WidgetBackingStore::cairoSurface() |
| { |
| return m_private->m_surface.get(); |
| } |
| |
| void WidgetBackingStore::scroll(const IntRect& scrollRect, const IntSize& scrollOffset) |
| { |
| IntRect targetRect(scrollRect); |
| targetRect.move(scrollOffset); |
| targetRect.intersect(scrollRect); |
| if (targetRect.isEmpty()) |
| return; |
| |
| cairo_surface_flush(m_private->m_surface.get()); |
| XCopyArea(m_private->m_display, m_private->m_pixmap, m_private->m_pixmap, m_private->m_gc, |
| targetRect.x() - scrollOffset.width(), targetRect.y() - scrollOffset.height(), |
| targetRect.width(), targetRect.height(), |
| targetRect.x(), targetRect.y()); |
| cairo_surface_mark_dirty_rectangle(m_private->m_surface.get(), |
| targetRect.x(), targetRect.y(), |
| targetRect.width(), targetRect.height()); |
| } |
| |
| } // namespace WebCore |