Skip to content

Commit

Permalink
Cherry-pick 278128@main (eb01eca). https://bugs.webkit.org/show_bug.c…
Browse files Browse the repository at this point in the history
…gi?id=247980

    [GTK] Correct scaling for DPI.
    https://bugs.webkit.org/show_bug.cgi?id=247980

    Reviewed by Michael Catanzaro.

    Move the scaling factor formerly in WebKitWebView.cpp (responsive to
    the xft-dpi setting) into WebKitWebViewBase.cpp, and split it into two
    scaling factors. The first, a page scaling factor, uses screenDPI to
    ensure that a length specified by a CSS unit of 1in will appear on the
    screen as one physical inch. The second, a text scaling factor, ensures
    that text specified as 96px in size will have a height on-screen as
    specified by fontDPI (which is primarily driven by the xft-dpi setting),
    in terms of the number of screen pixels taken up.

    The two scaling factors are refreshed when any one of the inputs for
    computing them changes: the GDK_SCALE factor, the xft-dpi setting, or
    the screenDPI of the device it is displayed on (say by being dragged
    to a different monitor). Throughout, at the default zoom level, a CSS
    1in dimension is kept at one physical inch.

    The scale factors are kept internal to WebKitWebViewBase (which helps
    keep GTK dependencies grouped and reduces the total code in WebKitWebView
    enclosed in `#ifdef PLATFORM(GTK)`) but made available to WebKitWebView
    so that its external interfaces can maintain zoom level 1 as the default
    zoom level, and zoom in and out from there.

    So indeed, if a user of WebKitWebView asks for a zoom level of 1.5, a
    length specified in CSS as 1in will then occupy one and a half physical
    inches on screen.

    * Source/WebCore/platform/gtk/PlatformScreenGtk.cpp:
    (WebCore::fontDPI):
    * Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp:
    (webkitWebViewConstructed):
    (webkitWebViewDispose):
    (webkit_web_view_set_zoom_level):
    (webkit_web_view_get_zoom_level):
    * Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp:
    (_WebKitWebViewBasePrivate::_WebKitWebViewBasePrivate):
    (refreshInternalScaling):
    (webkitWebViewBaseUpdateDisplayID):
    (webkitWebViewBaseDispose):
    (webkitWebViewBaseGetScaleFactors):
    (deviceScaleFactorChanged):
    (webkitWebViewBaseCreateWebPage):
    * Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h:

    Canonical link: https://commits.webkit.org/278128@main

Canonical link: https://commits.webkit.org/274313.195@webkitglib/2.44
  • Loading branch information
gwhitney authored and aperezdc committed May 2, 2024
1 parent 95b1c08 commit 9864937
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 29 deletions.
10 changes: 10 additions & 0 deletions Source/WebCore/platform/gtk/PlatformScreenGtk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ bool screenHasInvertedColors()

double fontDPI()
{
#if !USE(GTK4)
// The code in this conditionally-compiled block is needed in order to
// respect the GDK_DPI_SCALE setting that was present in GTK3 as an
// additional font scaling factor.
if (auto* display = gdk_display_get_default()) {
if (auto* screen = gdk_display_get_default_screen(display))
return gdk_screen_get_resolution(screen);
}
#endif

static GtkSettings* gtkSettings = gtk_settings_get_default();
if (gtkSettings) {
int gtkXftDpi;
Expand Down
44 changes: 15 additions & 29 deletions Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
#include <wtf/text/StringBuilder.h>

#if PLATFORM(GTK)
#include "GtkSettingsManager.h"
#include "WebKitFaviconDatabasePrivate.h"
#include "WebKitInputMethodContextImplGtk.h"
#include "WebKitPointerLockPermissionRequest.h"
Expand Down Expand Up @@ -352,8 +351,6 @@ struct _WebKitWebViewPrivate {
CString defaultContentSecurityPolicy;
WebKitWebExtensionMode webExtensionMode;

double textScaleFactor;

bool isWebProcessResponsive;
};

Expand Down Expand Up @@ -894,25 +891,6 @@ static void webkitWebViewConstructed(GObject* object)

priv->backForwardList = adoptGRef(webkitBackForwardListCreate(&getPage(webView).backForwardList()));
priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate());

#if PLATFORM(GTK)
double dpi = GtkSettingsManager::singleton().settingsState().xftDPI.value() / 1024.0;
priv->textScaleFactor = dpi / 96.;
getPage(webView).setTextZoomFactor(priv->textScaleFactor);
GtkSettingsManager::singleton().addObserver([webView](const GtkSettingsState& state) {
if (!state.xftDPI)
return;

double dpi = state.xftDPI.value() / 1024.0;
auto& page = getPage(webView);
auto zoomFactor = page.textZoomFactor() / webView->priv->textScaleFactor;
webView->priv->textScaleFactor = dpi / 96.;
page.setTextZoomFactor(zoomFactor * webView->priv->textScaleFactor);
}, webView);
#else
priv->textScaleFactor = 1;
#endif

priv->isWebProcessResponsive = true;
}

Expand Down Expand Up @@ -1137,10 +1115,6 @@ static void webkitWebViewDispose(GObject* object)
webView->priv->view->close();
#endif

#if PLATFORM(GTK)
GtkSettingsManager::singleton().removeObserver(webView);
#endif

G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
}

Expand Down Expand Up @@ -3912,11 +3886,17 @@ void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel)
if (webkit_web_view_get_zoom_level(webView) == zoomLevel)
return;

#if PLATFORM(GTK)
auto [pageScale, textScale] = webkitWebViewBaseGetScaleFactors(WEBKIT_WEB_VIEW_BASE(webView));
#else
const double pageScale = 1.0, textScale = 1.0;
#endif

auto& page = getPage(webView);
if (webkit_settings_get_zoom_text_only(webView->priv->settings.get()))
page.setTextZoomFactor(zoomLevel * webView->priv->textScaleFactor);
page.setTextZoomFactor(zoomLevel * textScale);
else
page.setPageZoomFactor(zoomLevel);
page.setPageZoomFactor(zoomLevel * pageScale);
g_object_notify_by_pspec(G_OBJECT(webView), sObjProperties[PROP_ZOOM_LEVEL]);
}

Expand All @@ -3935,9 +3915,15 @@ gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView)
{
g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1);

#if PLATFORM(GTK)
auto [pageScale, textScale] = webkitWebViewBaseGetScaleFactors(WEBKIT_WEB_VIEW_BASE(webView));
#else
const double pageScale = 1.0, textScale = 1.0;
#endif

auto& page = getPage(webView);
gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webView->priv->settings.get());
return zoomTextOnly ? page.textZoomFactor() / webView->priv->textScaleFactor : page.pageZoomFactor();
return zoomTextOnly ? page.textZoomFactor() / textScale : page.pageZoomFactor() / pageScale;
}

/**
Expand Down
71 changes: 71 additions & 0 deletions Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "DrawingAreaProxyCoordinatedGraphics.h"
#include "DropTarget.h"
#include "EditorState.h"
#include "GtkSettingsManager.h"
#include "InputMethodFilter.h"
#include "KeyAutoRepeatHandler.h"
#include "KeyBindingTranslator.h"
Expand Down Expand Up @@ -245,6 +246,8 @@ typedef HashMap<uint32_t, GRefPtr<GdkEvent>> TouchEventsMap;
struct _WebKitWebViewBasePrivate {
_WebKitWebViewBasePrivate()
: updateActivityStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateActivityStateTimerFired)
, pageScaleFactor(1.0)
, textScaleFactor(1.0)
#if GTK_CHECK_VERSION(3, 24, 0)
, releaseEmojiChooserTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::releaseEmojiChooserTimerFired)
#endif
Expand Down Expand Up @@ -340,6 +343,8 @@ struct _WebKitWebViewBasePrivate {
RunLoop::Timer updateActivityStateTimer;

PlatformDisplayID displayID;
double pageScaleFactor; // Corrects length of absolute units
double textScaleFactor; // Respects GTK font-specific scaling

#if ENABLE(FULLSCREEN_API)
WebFullScreenManagerProxy::FullscreenState fullScreenState;
Expand Down Expand Up @@ -425,6 +430,45 @@ webkitWebViewBaseAccessibleInterfaceInit(GtkAccessibleInterface* iface)
}
#endif

static void refreshInternalScaling(WebKitWebViewBase* self)
{
auto* page = webkitWebViewBaseGetPage(self);

// Gather the data needed to determine the ideal scale factors
auto displayID = self->priv->displayID;
if (!displayID)
displayID = primaryScreenDisplayID();
// Sadly, seems to be necessary always to collect the screen
// properties, in case the device rescaled since the last time.
ScreenManager::singleton().collectScreenProperties();
auto* data = WebCore::screenData(displayID);
double screenDPI = data ? data->dpi : 96.;
double fontDPI = WebCore::fontDPI();

// Compute the new ideal scale factors
// The following computation should cause a CSS unit of 1in appear
// as 1 actual physical inch on the current display:
double newPageScale = screenDPI / 96.;
// And the following computation should make a 96px font take up the
// specified number of device pixels on the screen:
double newTextScale = fontDPI / screenDPI;
// Note that if the font DPI does not equal the screen DPI, then a 1em
// length with respect to a 96px font will not actually measure 1in at
// default zoom, as specified by the CSS standard; but we presume it is
// better to respect the environment's specific font size request.

// Finally, adjust the page and text zooms as needed, and update
// the internal scale factors. Don't bother with changes under one percent.
if (std::abs(newPageScale / self->priv->pageScaleFactor - 1) > 0.01) {
page->setPageZoomFactor(page->pageZoomFactor() * newPageScale / self->priv->pageScaleFactor);
self->priv->pageScaleFactor = newPageScale;
}
if (std::abs(newTextScale / self->priv->textScaleFactor - 1) > 0.01) {
page->setTextZoomFactor(page->textZoomFactor() * newTextScale / self->priv->textScaleFactor);
self->priv->textScaleFactor = newTextScale;
}
}

static void webkitWebViewBaseUpdateDisplayID(WebKitWebViewBase* webViewBase, GdkMonitor* monitor)
{
if (!monitor)
Expand All @@ -435,6 +479,7 @@ static void webkitWebViewBaseUpdateDisplayID(WebKitWebViewBase* webViewBase, Gdk
return;

webViewBase->priv->displayID = displayID;
refreshInternalScaling(webViewBase);
if (webViewBase->priv->pageProxy)
webViewBase->priv->pageProxy->windowScreenDidChange(displayID);
}
Expand Down Expand Up @@ -846,6 +891,7 @@ static void webkitWebViewBaseDispose(GObject* gobject)
webkitWebViewAccessibleSetWebView(WEBKIT_WEB_VIEW_ACCESSIBLE(webView->priv->accessible.get()), nullptr);
#endif

GtkSettingsManager::singleton().removeObserver(webView);
webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr);
#if GTK_CHECK_VERSION(3, 24, 0)
webkitWebViewBaseCompleteEmojiChooserRequest(webView, emptyString());
Expand Down Expand Up @@ -2556,9 +2602,27 @@ WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
return webkitWebViewBase->priv->pageProxy.get();
}

WebKitWebViewBaseScaleFactors webkitWebViewBaseGetScaleFactors(WebKitWebViewBase* webkitWebViewBase)
{
auto* priv = webkitWebViewBase->priv;
return WebKitWebViewBaseScaleFactors { priv->pageScaleFactor, priv->textScaleFactor };
}

static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase)
{
auto page = webkitWebViewBase->priv->pageProxy;
auto initialScaleFactor = page->deviceScaleFactor();
webkitWebViewBase->priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
auto scaleRatio = initialScaleFactor / page->deviceScaleFactor();
// Re-collecting the screenDPIs and refreshing the scaling was not working
// reliably. Maybe there is some kind of race condition with whatever
// updates the screen DPI. So instead, update the scaling directly.
if (std::abs(scaleRatio - 1) > 0.01) {
page->setPageZoomFactor(page->pageZoomFactor() * scaleRatio);
webkitWebViewBase->priv->pageScaleFactor *= scaleRatio;
page->setTextZoomFactor(page->textZoomFactor() / scaleRatio);
webkitWebViewBase->priv->textScaleFactor /= scaleRatio;
}
}

void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<API::PageConfiguration>&& configuration)
Expand All @@ -2580,8 +2644,15 @@ void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<AP
if (priv->displayID)
priv->pageProxy->windowScreenDidChange(priv->displayID);

refreshInternalScaling(webkitWebViewBase);
// We attach this here, because changes in scale factor are passed directly to the page proxy.
g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr);
// Also watch for changes to xft-dpi
GtkSettingsManager::singleton().addObserver([webkitWebViewBase](const GtkSettingsState& state) {
if (!state.xftDPI)
return;
refreshInternalScaling(webkitWebViewBase);
}, webkitWebViewBase);
}

void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
Expand Down
4 changes: 4 additions & 0 deletions Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@

WebKitWebViewBase* webkitWebViewBaseCreate(const API::PageConfiguration&);
WebKit::WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase*);
struct WebKitWebViewBaseScaleFactors {
double pageScale, textScale;
};
WebKitWebViewBaseScaleFactors webkitWebViewBaseGetScaleFactors(WebKitWebViewBase*);
void webkitWebViewBaseCreateWebPage(WebKitWebViewBase*, Ref<API::PageConfiguration>&&);
void webkitWebViewBaseSetTooltipText(WebKitWebViewBase*, const char*);
void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase*, const WebCore::IntRect&);
Expand Down

0 comments on commit 9864937

Please sign in to comment.