Skip to content

Commit

Permalink
[GTK] Add HighDPI support for non-accelerated compositing contents
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=131562

Patch by Owen Taylor <otaylor@redhat.com> on 2014-05-29
Reviewed by Anders Carlsson.

Source/WebCore:

No new tests. This will be tested once we have the proper dependencies in the WebKit testing
JHBuild.

Adapted by Michael Kuhn for 2.4 branch.

* platform/cairo/WidgetBackingStore.h:
(WebCore::WidgetBackingStore::WidgetBackingStore): Accept a device scale argument.
* platform/cairo/WidgetBackingStoreCairo.cpp: Use the device scale argument to make the surface the proper size and set the surface device scale.
* platform/cairo/WidgetBackingStoreCairo.h: Accept a device scale argument.
* platform/graphics/cairo/CairoUtilities.cpp: Add a new helper to set the device scale if Cairo built against is new enough.
* platform/graphics/cairo/CairoUtilities.h:
* platform/gtk/GtkVersioning.h: Add the HAVE_GTK_SCALE_FACTOR macro.
* platform/gtk/WidgetBackingStoreGtkX11.cpp: Use the device scale argument to make the surface the proper size and set the surface device scale.
* platform/gtk/WidgetBackingStoreGtkX11.h: Accept a device scale argument.

Source/WebKit2:

Adapted by Michael Kuhn for 2.4 branch.

* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(deviceScaleFactorChanged): Added this callback to pass scale changes to the page proxy.
(webkitWebViewBaseCreateWebPage): Attach the callback to the notify signal.
* UIProcess/WebPageProxy.cpp:
* UIProcess/cairo/BackingStoreCairo.cpp:
(WebKit::WebPageProxy::setCustomDeviceScaleFactor): Do not set a custom device scale factor for cairo when it's not supported.
(WebKit::createBackingStoreForGTK): Pass the scale factor to the WebCore backing store.
(WebKit::BackingStore::incorporateUpdate): Ditto.
  • Loading branch information
owtaylor authored and carlosgcampos committed May 18, 2015
1 parent 936d95f commit d860500
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 46 deletions.
22 changes: 22 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,25 @@
2014-05-29 Owen Taylor <otaylor@redhat.com>

[GTK] Add HighDPI support for non-accelerated compositing contents
https://bugs.webkit.org/show_bug.cgi?id=131562

Reviewed by Anders Carlsson.

No new tests. This will be tested once we have the proper dependencies in the WebKit testing
JHBuild.

Adapted by Michael Kuhn for 2.4 branch.

* platform/cairo/WidgetBackingStore.h:
(WebCore::WidgetBackingStore::WidgetBackingStore): Accept a device scale argument.
* platform/cairo/WidgetBackingStoreCairo.cpp: Use the device scale argument to make the surface the proper size and set the surface device scale.
* platform/cairo/WidgetBackingStoreCairo.h: Accept a device scale argument.
* platform/graphics/cairo/CairoUtilities.cpp: Add a new helper to set the device scale if Cairo built against is new enough.
* platform/graphics/cairo/CairoUtilities.h:
* platform/gtk/GtkVersioning.h: Add the HAVE_GTK_SCALE_FACTOR macro.
* platform/gtk/WidgetBackingStoreGtkX11.cpp: Use the device scale argument to make the surface the proper size and set the surface device scale.
* platform/gtk/WidgetBackingStoreGtkX11.h: Accept a device scale argument.

2015-05-03 Carlos Garcia Campos <cgarcia@igalia.com>

[GTK] API tests crashing on debug builds due to extra unref
Expand Down
11 changes: 9 additions & 2 deletions Source/WebCore/platform/cairo/WidgetBackingStore.h
Expand Up @@ -49,11 +49,18 @@ class WidgetBackingStore {
virtual cairo_surface_t* cairoSurface() = 0;
virtual void scroll(const IntRect& scrollRect, const IntSize& scrollOffset) = 0;
const IntSize& size() { return m_size; }
WidgetBackingStore(const IntSize& size) : m_size(size) { }
float deviceScaleFactor() { return m_deviceScaleFactor; }

WidgetBackingStore(const IntSize& size, float deviceScaleFactor)
: m_size(size)
, m_deviceScaleFactor(deviceScaleFactor)
{ }

virtual ~WidgetBackingStore() { }

private:
protected:
IntSize m_size;
float m_deviceScaleFactor;
};

} // namespace WebCore
Expand Down
18 changes: 10 additions & 8 deletions Source/WebCore/platform/cairo/WidgetBackingStoreCairo.cpp
Expand Up @@ -26,8 +26,10 @@

namespace WebCore {

static PassRefPtr<cairo_surface_t> createSurfaceForBackingStore(PlatformWidget widget, const IntSize& size)
static PassRefPtr<cairo_surface_t> createSurfaceForBackingStore(PlatformWidget widget, IntSize size, float deviceScaleFactor)
{
size.scale(deviceScaleFactor);

#if PLATFORM(GTK)
return adoptRef(gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR_ALPHA, size.width(), size.height()));
#else
Expand All @@ -36,20 +38,20 @@ static PassRefPtr<cairo_surface_t> createSurfaceForBackingStore(PlatformWidget w
#endif
}

PassOwnPtr<WidgetBackingStore> WidgetBackingStoreCairo::create(PlatformWidget widget, const IntSize& size)
PassOwnPtr<WidgetBackingStore> WidgetBackingStoreCairo::create(PlatformWidget widget, const IntSize& size, float deviceScaleFactor)
{
return adoptPtr(new WidgetBackingStoreCairo(widget, size));
return adoptPtr(new WidgetBackingStoreCairo(widget, size, deviceScaleFactor));
}

// 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.
WidgetBackingStoreCairo::WidgetBackingStoreCairo(PlatformWidget widget, const IntSize& size)
: WidgetBackingStore(size)
, m_surface(createSurfaceForBackingStore(widget, size))
, m_scrollSurface(createSurfaceForBackingStore(widget, size))

WidgetBackingStoreCairo::WidgetBackingStoreCairo(PlatformWidget widget, const IntSize& size, float deviceScaleFactor)
: WidgetBackingStore(size, deviceScaleFactor)
, m_surface(createSurfaceForBackingStore(widget, size, deviceScaleFactor))
, m_scrollSurface(createSurfaceForBackingStore(widget, size, deviceScaleFactor))
{
cairoSurfaceSetDeviceScale(m_surface.get(), deviceScaleFactor, deviceScaleFactor);
}

WidgetBackingStoreCairo::~WidgetBackingStoreCairo()
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/cairo/WidgetBackingStoreCairo.h
Expand Up @@ -26,8 +26,8 @@ namespace WebCore {
class WidgetBackingStoreCairo : public WidgetBackingStore {

public:
static PassOwnPtr<WidgetBackingStore> create(PlatformWidget, const IntSize&);
WidgetBackingStoreCairo(PlatformWidget, const IntSize&);
static PassOwnPtr<WidgetBackingStore> create(PlatformWidget, const IntSize&, float deviceScaleFactor);
WidgetBackingStoreCairo(PlatformWidget, const IntSize&, float deviceScaleFactor);
~WidgetBackingStoreCairo();
cairo_surface_t* cairoSurface();
void scroll(const IntRect&, const IntSize&);
Expand Down
12 changes: 12 additions & 0 deletions Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp
Expand Up @@ -36,6 +36,7 @@
#include "Path.h"
#include "PlatformPathCairo.h"
#include "RefPtrCairo.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>

#if ENABLE(ACCELERATED_2D_CANVAS)
Expand Down Expand Up @@ -259,4 +260,15 @@ IntSize cairoSurfaceSize(cairo_surface_t* surface)
}
}

void cairoSurfaceSetDeviceScale(cairo_surface_t* surface, double xScale, double yScale)
{
// This function was added pretty much simultaneous to when 1.13 was branched.
#if HAVE(CAIRO_SURFACE_SET_DEVICE_SCALE)
cairo_surface_set_device_scale(surface, xScale, yScale);
#else
UNUSED_PARAM(surface);
ASSERT_UNUSED(xScale, 1 == xScale);
ASSERT_UNUSED(yScale, 1 == yScale);
#endif
}
} // namespace WebCore
4 changes: 4 additions & 0 deletions Source/WebCore/platform/graphics/cairo/CairoUtilities.h
Expand Up @@ -31,6 +31,9 @@
#include "IntSize.h"
#include <cairo.h>

// This function was added pretty much simultaneous to when 1.13 was branched.
#define HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 13)

namespace WebCore {
class AffineTransform;
class Color;
Expand All @@ -56,6 +59,7 @@ void copyRectFromCairoSurfaceToContext(cairo_surface_t* from, cairo_t* to, const
void copyRectFromOneSurfaceToAnother(cairo_surface_t* from, cairo_surface_t* to, const IntSize& offset, const IntRect&, const IntSize& = IntSize(), cairo_operator_t = CAIRO_OPERATOR_OVER);

IntSize cairoSurfaceSize(cairo_surface_t*);
void cairoSurfaceSetDeviceScale(cairo_surface_t*, double xScale, double yScale);

} // namespace WebCore

Expand Down
28 changes: 18 additions & 10 deletions Source/WebCore/platform/gtk/WidgetBackingStoreGtkX11.cpp
Expand Up @@ -21,6 +21,7 @@

#if PLATFORM(GTK) && PLATFORM(X11) && defined(GDK_WINDOWING_X11)

#include "CairoUtilities.h"
#include "GtkVersioning.h"
#include "RefPtrCairo.h"
#include <cairo-xlib.h>
Expand All @@ -29,26 +30,28 @@

namespace WebCore {

PassOwnPtr<WidgetBackingStore> WidgetBackingStoreGtkX11::create(GtkWidget* widget, const IntSize& size)
PassOwnPtr<WidgetBackingStore> WidgetBackingStoreGtkX11::create(GtkWidget* widget, const IntSize& size, float deviceScaleFactor)
{
return adoptPtr(new WidgetBackingStoreGtkX11(widget, size));
return adoptPtr(new WidgetBackingStoreGtkX11(widget, size, deviceScaleFactor));
}

// 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.
WidgetBackingStoreGtkX11::WidgetBackingStoreGtkX11(GtkWidget* widget, const IntSize& size)
: WidgetBackingStore(size)
WidgetBackingStoreGtkX11::WidgetBackingStoreGtkX11(GtkWidget* widget, const IntSize& size, float deviceScaleFactor)
: WidgetBackingStore(size, deviceScaleFactor)
{
IntSize scaledSize = size;
scaledSize.scale(deviceScaleFactor);

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));
scaledSize.width(), scaledSize.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()));
GDK_VISUAL_XVISUAL(visual), scaledSize.width(), scaledSize.height()));

cairoSurfaceSetDeviceScale(m_surface.get(), deviceScaleFactor, deviceScaleFactor);
}

WidgetBackingStoreGtkX11::~WidgetBackingStoreGtkX11()
Expand All @@ -72,9 +75,14 @@ void WidgetBackingStoreGtkX11::scroll(const IntRect& scrollRect, const IntSize&
if (targetRect.isEmpty())
return;

targetRect.scale(m_deviceScaleFactor);

IntSize scaledScrollOffset = scrollOffset;
scaledScrollOffset.scale(m_deviceScaleFactor);

cairo_surface_flush(m_surface.get());
XCopyArea(m_display, m_pixmap, m_pixmap, m_gc,
targetRect.x() - scrollOffset.width(), targetRect.y() - scrollOffset.height(),
targetRect.x() - scaledScrollOffset.width(), targetRect.y() - scaledScrollOffset.height(),
targetRect.width(), targetRect.height(),
targetRect.x(), targetRect.y());
cairo_surface_mark_dirty_rectangle(m_surface.get(),
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/platform/gtk/WidgetBackingStoreGtkX11.h
Expand Up @@ -29,8 +29,8 @@ namespace WebCore {
class WidgetBackingStoreGtkX11 : public WidgetBackingStore {

public:
static PassOwnPtr<WidgetBackingStore> create(GtkWidget*, const IntSize&);
WidgetBackingStoreGtkX11(GtkWidget*, const IntSize&);
static PassOwnPtr<WidgetBackingStore> create(GtkWidget*, const IntSize&, float deviceScaleFactor);
WidgetBackingStoreGtkX11(GtkWidget*, const IntSize&, float deviceScaleFactor);
~WidgetBackingStoreGtkX11();
cairo_surface_t* cairoSurface();
void scroll(const IntRect& scrollRect, const IntSize& scrollOffset);
Expand Down
38 changes: 31 additions & 7 deletions Source/WebKit/gtk/WebCoreSupport/ChromeClientGtk.cpp
Expand Up @@ -25,6 +25,7 @@
#include "config.h"
#include "ChromeClientGtk.h"

#include "CairoUtilities.h"
#include "Chrome.h"
#include "Console.h"
#include "DumpRenderTreeSupportGtk.h"
Expand Down Expand Up @@ -97,18 +98,27 @@
#endif
#include "WidgetBackingStoreCairo.h"

#define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)

using namespace WebCore;

namespace WebKit {

static PassOwnPtr<WidgetBackingStore> createBackingStore(GtkWidget* widget, const IntSize& size)
static PassOwnPtr<WidgetBackingStore> createBackingStore(GtkWidget* widget, const IntSize& size, bool scale)
{
float deviceScaleFactor = 1.0;

#if HAVE(GTK_SCALE_FACTOR)
if (scale)
deviceScaleFactor = gtk_widget_get_scale_factor(widget);
#endif

#if PLATFORM(X11) && defined(GDK_WINDOWING_X11)
GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get());
if (GDK_IS_X11_DISPLAY(display))
return WebCore::WidgetBackingStoreGtkX11::create(widget, size);
return WebCore::WidgetBackingStoreGtkX11::create(widget, size, deviceScaleFactor);
#endif
return WebCore::WidgetBackingStoreCairo::create(widget, size);
return WebCore::WidgetBackingStoreCairo::create(widget, size, deviceScaleFactor);
}

ChromeClient::ChromeClient(WebKitWebView* webView)
Expand Down Expand Up @@ -483,7 +493,7 @@ void ChromeClient::widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSi
|| newSize.width() > backingStore->size().width()
|| newSize.height() > backingStore->size().height()) {

OwnPtr<WidgetBackingStore> newBackingStore = createBackingStore(GTK_WIDGET(m_webView), newSize);
OwnPtr<WidgetBackingStore> newBackingStore = createBackingStore(GTK_WIDGET(m_webView), newSize, true);
RefPtr<cairo_t> cr = adoptRef(cairo_create(newBackingStore->cairoSurface()));

clearEverywhereInBackingStore(m_webView, cr.get());
Expand Down Expand Up @@ -518,6 +528,21 @@ void ChromeClient::widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSi
m_repaintSoonSourceId = g_idle_add_full(G_PRIORITY_DEFAULT, reinterpret_cast<GSourceFunc>(repaintEverythingSoonTimeout), this, 0);
}

void ChromeClient::deviceScaleFactorChanged()
{
#if HAVE(GTK_SCALE_FACTOR)
if (m_webView->priv->backingStore) {
int scaleFactor = gtk_widget_get_scale_factor(GTK_WIDGET(m_webView));
float oldScaleFactor = m_webView->priv->backingStore->deviceScaleFactor();

if (scaleFactor != oldScaleFactor) {
m_webView->priv->backingStore = 0;
widgetSizeChanged(IntSize(0, 0), getWebViewRect(m_webView).size());
}
}
#endif
}

static void coalesceRectsIfPossible(const IntRect& clipRect, Vector<IntRect>& rects)
{
const unsigned int cRectThreshold = 10;
Expand Down Expand Up @@ -553,7 +578,6 @@ static void paintWebView(WebKitWebView* webView, Frame* frame, const Region& dir

RefPtr<cairo_t> backingStoreContext = adoptRef(cairo_create(webView->priv->backingStore->cairoSurface()));
GraphicsContext gc(backingStoreContext.get());
gc.applyDeviceScaleFactor(frame->page()->deviceScaleFactor());
for (size_t i = 0; i < rects.size(); i++) {
const IntRect& rect = rects[i];

Expand Down Expand Up @@ -1011,11 +1035,11 @@ void ChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* rootLaye

if (turningOnCompositing) {
m_displayTimer.stop();
m_webView->priv->backingStore = createBackingStore(GTK_WIDGET(m_webView), IntSize(1, 1));
m_webView->priv->backingStore = createBackingStore(GTK_WIDGET(m_webView), IntSize(1, 1), false);
}

if (turningOffCompositing) {
m_webView->priv->backingStore = createBackingStore(GTK_WIDGET(m_webView), getWebViewRect(m_webView).size());
m_webView->priv->backingStore = createBackingStore(GTK_WIDGET(m_webView), getWebViewRect(m_webView).size(), true);
RefPtr<cairo_t> cr = adoptRef(cairo_create(m_webView->priv->backingStore->cairoSurface()));
clearEverywhereInBackingStore(m_webView, cr.get());
}
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/gtk/WebCoreSupport/ChromeClientGtk.h
Expand Up @@ -156,6 +156,7 @@ namespace WebKit {
void paint(Timer<ChromeClient>*);
void forcePaint();
void widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSize);
void deviceScaleFactorChanged();

WebKitWebView* webView() { return m_webView; }

Expand Down
25 changes: 25 additions & 0 deletions Source/WebKit/gtk/webkit/webkitwebview.cpp
Expand Up @@ -130,6 +130,8 @@
#include <gdk/gdkwayland.h>
#endif

#define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)

/**
* SECTION:webkitwebview
* @short_description: The central class of the WebKitGTK+ API
Expand Down Expand Up @@ -281,6 +283,9 @@ G_DEFINE_TYPE_WITH_CODE(WebKitWebView, webkit_web_view, GTK_TYPE_CONTAINER,
static void webkit_web_view_settings_notify(WebKitWebSettings* webSettings, GParamSpec* pspec, WebKitWebView* webView);
static void webkit_web_view_set_window_features(WebKitWebView* webView, WebKitWebWindowFeatures* webWindowFeatures);
static void webkitWebViewDirectionChanged(WebKitWebView*, GtkTextDirection previousDirection, gpointer);
#if HAVE(GTK_SCALE_FACTOR)
static void webkitWebViewNotifyScaleFactor(WebKitWebView* webView, GParamSpec *pspec, gpointer);
#endif

#if ENABLE(CONTEXT_MENUS)
static void PopupMenuPositionFunc(GtkMenu* menu, gint *x, gint *y, gboolean *pushIn, gpointer userData)
Expand Down Expand Up @@ -3851,6 +3856,10 @@ static void webkit_web_view_init(WebKitWebView* webView)
// time of writing this comment), we simply set all the pages to the same group.
priv->corePage->setGroupName(webkitPageGroupName());

#if HAVE(GTK_SCALE_FACTOR)
priv->corePage->setDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webView)));
#endif

// We also add a simple wrapper class to provide the public
// interface for the Web Inspector.
priv->webInspector = adoptGRef(WEBKIT_WEB_INSPECTOR(g_object_new(WEBKIT_TYPE_WEB_INSPECTOR, NULL)));
Expand Down Expand Up @@ -3890,6 +3899,10 @@ static void webkit_web_view_init(WebKitWebView* webView)
#endif

g_signal_connect(webView, "direction-changed", G_CALLBACK(webkitWebViewDirectionChanged), 0);

#if HAVE(GTK_SCALE_FACTOR)
g_signal_connect(webView, "notify::scale-factor", G_CALLBACK(webkitWebViewNotifyScaleFactor), 0);
#endif
}

GtkWidget* webkit_web_view_new(void)
Expand Down Expand Up @@ -5555,6 +5568,18 @@ void webkitWebViewDirectionChanged(WebKitWebView* webView, GtkTextDirection prev
}
}

#if HAVE(GTK_SCALE_FACTOR)
void webkitWebViewNotifyScaleFactor(WebKitWebView* webView, GParamSpec* pspec, gpointer)
{
Page* page = core(webView);

page->setDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webView)));

WebKit::ChromeClient& chromeClient = static_cast<WebKit::ChromeClient&>(page->chrome().client());
chromeClient.deviceScaleFactorChanged();
}
#endif

namespace WebKit {

WebCore::Page* core(WebKitWebView* webView)
Expand Down
18 changes: 18 additions & 0 deletions Source/WebKit2/ChangeLog
@@ -1,3 +1,21 @@
2014-05-29 Owen Taylor <otaylor@redhat.com>

[GTK] Add HighDPI support for non-accelerated compositing contents
https://bugs.webkit.org/show_bug.cgi?id=131562

Reviewed by Anders Carlsson.

Adapted by Michael Kuhn for 2.4 branch.

* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(deviceScaleFactorChanged): Added this callback to pass scale changes to the page proxy.
(webkitWebViewBaseCreateWebPage): Attach the callback to the notify signal.
* UIProcess/WebPageProxy.cpp:
* UIProcess/cairo/BackingStoreCairo.cpp:
(WebKit::WebPageProxy::setCustomDeviceScaleFactor): Do not set a custom device scale factor for cairo when it's not supported.
(WebKit::createBackingStoreForGTK): Pass the scale factor to the WebCore backing store.
(WebKit::BackingStore::incorporateUpdate): Ditto.

2014-11-19 Michael Catanzaro <mcatanzaro@igalia.com>

[GTK] Error in documentation of webkit_print_operation_get_page_setup()
Expand Down

0 comments on commit d860500

Please sign in to comment.