Bug 1460874 - Part 9: Expose font size/inflation options via GeckoRuntimeSettings. r=geckoview-reviewers,snorp
☠☠ backed out by cd616c3e3eea ☠ ☠
authorJan Henning <jh+bugzilla@buttercookie.de>
Wed, 13 Feb 2019 20:10:57 +0000
changeset 459052 9fc145133f20
parent 459051 17fbff3da236
child 459053 2020cb134d1f
push id111913
push usershindli@mozilla.com
push dateThu, 14 Feb 2019 05:01:59 +0000
treeherdermozilla-inbound@a0752d7e8073 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgeckoview-reviewers, snorp
bugs1460874
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1460874 - Part 9: Expose font size/inflation options via GeckoRuntimeSettings. r=geckoview-reviewers,snorp Some callers might prefer to manually set the font size in analogy to WebView's WebSettings.setTextZoom(), respectively allow their users to do so. Subsequently, we're also going to switch the GeckoFontScaleListener to operate on those settings. Because the effects of font inflation are more difficult to quantify than a plain text zoom, we just check that operating the runtime setting sets the corresponding Gecko pref. Besides, there already are further platform (ref)tests checking the actual operation of font inflation itself. Differential Revision: https://phabricator.services.mozilla.com/D17749
mobile/android/geckoview/api.txt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -208,42 +208,48 @@ package org.mozilla.geckoview {
   @android.support.annotation.AnyThread public final class GeckoRuntimeSettings extends org.mozilla.geckoview.RuntimeSettings {
     method @android.support.annotation.NonNull public java.lang.String[] getArguments();
     method public boolean getConsoleOutputEnabled();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.ContentBlocking.Settings getContentBlocking();
     method @android.support.annotation.Nullable public java.lang.Class<?> getCrashHandler();
     method @android.support.annotation.Nullable public java.lang.Float getDisplayDensityOverride();
     method @android.support.annotation.Nullable public java.lang.Integer getDisplayDpiOverride();
     method @android.support.annotation.NonNull public android.os.Bundle getExtras();
+    method public boolean getFontInflationEnabled();
+    method public float getFontSizeFactor();
     method public boolean getJavaScriptEnabled();
     method @android.support.annotation.Nullable public java.lang.String[] getLocales();
     method public boolean getPauseForDebuggerEnabled();
     method public boolean getRemoteDebuggingEnabled();
     method @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoRuntime getRuntime();
     method @android.support.annotation.Nullable public android.graphics.Rect getScreenSizeOverride();
     method public boolean getUseContentProcessHint();
     method public boolean getUseMaxScreenDepth();
     method public boolean getWebFontsEnabled();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setConsoleOutputEnabled(boolean);
+    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setFontInflationEnabled(boolean);
+    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setFontSizeFactor(float);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setJavaScriptEnabled(boolean);
     method public void setLocales(@android.support.annotation.Nullable java.lang.String[]);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setRemoteDebuggingEnabled(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings setWebFontsEnabled(boolean);
     field public static final android.os.Parcelable.Creator<org.mozilla.geckoview.GeckoRuntimeSettings> CREATOR;
   }
 
   @android.support.annotation.AnyThread public static final class GeckoRuntimeSettings.Builder extends org.mozilla.geckoview.RuntimeSettings.Builder<Settings extends org.mozilla.geckoview.RuntimeSettings> {
     ctor public Builder();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder arguments(@android.support.annotation.NonNull java.lang.String[]);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder consoleOutput(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder contentBlocking(@android.support.annotation.NonNull org.mozilla.geckoview.ContentBlocking.Settings);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder crashHandler(java.lang.Class<?>);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder displayDensityOverride(float);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder displayDpiOverride(int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder extras(@android.support.annotation.NonNull android.os.Bundle);
+    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder fontInflation(boolean);
+    method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder fontSizeFactor(float);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder javaScriptEnabled(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder locales(java.lang.String[]);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder pauseForDebugger(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder remoteDebuggingEnabled(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder screenSizeOverride(int, int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder useContentProcessHint(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder useMaxScreenDepth(boolean);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoRuntimeSettings.Builder webFontsEnabled(boolean);
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/RuntimeSettingsTest.kt
@@ -0,0 +1,89 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.geckoview.test
+
+import android.support.test.filters.MediumTest
+import android.support.test.runner.AndroidJUnit4
+import org.hamcrest.Matchers.*
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDevToolsAPI
+import kotlin.math.roundToInt
+
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+@ReuseSession(false)
+class RuntimeSettingsTest : BaseSessionTest() {
+
+    @WithDevToolsAPI
+    @Test fun fontSize() {
+        val settings = sessionRule.runtime.settings
+        settings.fontSizeFactor = 1.0f
+        sessionRule.session.loadTestPath(HELLO_HTML_PATH)
+        sessionRule.waitForPageStop()
+
+        val fontSizeJs = "parseFloat(window.getComputedStyle(document.querySelector('p')).fontSize)"
+        val initialFontSize = sessionRule.session.evaluateJS(fontSizeJs) as Double
+
+        val textSizeFactor = 2.0f
+        settings.fontSizeFactor = textSizeFactor
+        sessionRule.session.reload()
+        sessionRule.waitForPageStop()
+        var fontSize = sessionRule.session.evaluateJS(fontSizeJs) as Double
+        val expectedFontSize = initialFontSize * textSizeFactor
+        assertThat("old text size ${initialFontSize}px, new size should be ${expectedFontSize}px",
+                fontSize, closeTo(expectedFontSize, 0.1))
+
+        settings.fontSizeFactor = 1.0f
+        sessionRule.session.reload()
+        sessionRule.waitForPageStop()
+        fontSize = sessionRule.session.evaluateJS(fontSizeJs) as Double
+        assertThat("text size should be ${initialFontSize}px again",
+                fontSize, closeTo(initialFontSize, 0.1))
+    }
+
+    @WithDevToolsAPI
+    @Test fun fontInflation() {
+        val baseFontInflationMinTwips = 120
+        val settings = sessionRule.runtime.settings
+
+        settings.fontInflationEnabled = false;
+        settings.fontSizeFactor = 1.0f
+        val fontInflationPrefJs = "Services.prefs.getIntPref('font.size.inflation.minTwips')"
+        var prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("Gecko font inflation pref should be turned off",
+                prefValue, `is`(0))
+
+        settings.fontInflationEnabled = true;
+        prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("Gecko font inflation pref should be turned on",
+                prefValue, `is`(baseFontInflationMinTwips))
+
+        settings.fontSizeFactor = 2.0f
+        prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("Gecko font inflation pref should scale with increased font size factor",
+                prefValue, greaterThan(baseFontInflationMinTwips))
+
+        settings.fontSizeFactor = 0.5f
+        prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("Gecko font inflation pref should scale with decreased font size factor",
+                prefValue, lessThan(baseFontInflationMinTwips))
+
+        settings.fontSizeFactor = 0.0f
+        prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("setting font size factor to 0 turns off font inflation",
+                prefValue, `is`(0))
+        assertThat("GeckoRuntimeSettings returns new font inflation state, too",
+                settings.fontInflationEnabled, `is`(false))
+
+        settings.fontSizeFactor = 1.0f
+        prefValue = (sessionRule.evaluateChromeJS(fontInflationPrefJs) as Double).roundToInt()
+        assertThat("Gecko font inflation pref remains turned off",
+                prefValue, `is`(0))
+        assertThat("GeckoRuntimeSettings remains turned off",
+                settings.fontInflationEnabled, `is`(false))
+    }
+}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -150,16 +150,53 @@ public final class GeckoRuntimeSettings 
          * @return The builder instance.
          */
         public @NonNull Builder consoleOutput(boolean enabled) {
             getSettings().mConsoleOutput.set(enabled);
             return this;
         }
 
         /**
+         * Set a font size factor that will operate as a global text zoom. All font sizes will be
+         * multiplied by this factor.
+         *
+         * <p>The default factor is 1.0.
+         *
+         * @param fontSizeFactor The factor to be used for scaling all text. Setting a value of 0
+         *                       disables both this feature and
+         *                       {@link Builder#fontInflation font inflation}.
+         * @return The builder instance.
+         */
+        public @NonNull Builder fontSizeFactor(float fontSizeFactor) {
+            getSettings().setFontSizeFactor(fontSizeFactor);
+            return this;
+        }
+
+        /**
+         * Set whether or not font inflation for non mobile-friendly pages should be enabled. The
+         * default value of this setting is <code>false</code>.
+         *
+         * <p>When enabled, font sizes will be increased on all pages that are lacking a
+         * &lt;meta&gt; viewport tag and have been loaded in a session using
+         * {@link GeckoSessionSettings#VIEWPORT_MODE_MOBILE}. To improve readability, the font
+         * inflation logic will attempt to increase font sizes for the main text content of the page
+         * only.
+         *
+         * <p>The magnitude of font inflation applied depends on the
+         * {@link Builder#fontSizeFactor font size factor} currently in use.
+         *
+         * @param enabled A flag determining whether or not font inflation should be enabled.
+         * @return The builder instance.
+         */
+        public @NonNull Builder fontInflation(boolean enabled) {
+            getSettings().setFontInflationEnabled(enabled);
+            return this;
+        }
+
+        /**
          * Set the display density override.
          *
          * @param density The display density value to use for overriding the system default.
          * @return The builder instance.
          */
         public @NonNull Builder displayDensityOverride(float density) {
             getSettings().mDisplayDensityOverride = density;
             return this;
@@ -259,16 +296,20 @@ public final class GeckoRuntimeSettings 
     /* package */ final Pref<Boolean> mJavaScript = new Pref<Boolean>(
         "javascript.enabled", true);
     /* package */ final Pref<Boolean> mRemoteDebugging = new Pref<Boolean>(
         "devtools.debugger.remote-enabled", false);
     /* package */ final Pref<Integer> mWebFonts = new Pref<Integer>(
         "browser.display.use_document_fonts", 1);
     /* package */ final Pref<Boolean> mConsoleOutput = new Pref<Boolean>(
         "geckoview.console.enabled", false);
+    /* package */ final Pref<Integer> mFontSizeFactor = new Pref<>(
+        "font.size.systemFontScale", 100);
+    /* package */ final Pref<Integer> mFontInflationMinTwips = new Pref<>(
+        "font.size.inflation.minTwips", 0);
 
     /* package */ boolean mDebugPause;
     /* package */ boolean mUseMaxScreenDepth;
     /* package */ float mDisplayDensityOverride = -1.0f;
     /* package */ int mDisplayDpiOverride;
     /* package */ int mScreenWidthOverride;
     /* package */ int mScreenHeightOverride;
     /* package */ Class<? extends Service> mCrashHandler;
@@ -520,16 +561,87 @@ public final class GeckoRuntimeSettings 
      * Get whether or not web console messages are sent to logcat.
      *
      * @return True if console output is enabled.
      */
     public boolean getConsoleOutputEnabled() {
         return mConsoleOutput.get();
     }
 
+    private static int FONT_INFLATION_BASE_VALUE = 120;
+
+    /**
+     * Set a font size factor that will operate as a global text zoom. All font sizes will be
+     * multiplied by this factor.
+     *
+     * <p>The default factor is 1.0.
+     *
+     * <p>Currently, any changes only take effect after a reload of the session.
+     *
+     * @param fontSizeFactor The factor to be used for scaling all text. Setting a value of 0
+     *                       disables both this feature and
+     *                       {@link GeckoRuntimeSettings#setFontInflationEnabled font inflation}.
+     * @return This GeckoRuntimeSettings instance.
+     */
+    public @NonNull GeckoRuntimeSettings setFontSizeFactor(float fontSizeFactor) {
+        if (fontSizeFactor < 0) {
+            throw new IllegalArgumentException("fontSizeFactor cannot be < 0");
+        }
+
+        final int fontSizePercentage = Math.round(fontSizeFactor * 100);
+        mFontSizeFactor.commit(Math.round(fontSizePercentage));
+        if (getFontInflationEnabled()) {
+            final int scaledFontInflation = Math.round(FONT_INFLATION_BASE_VALUE * fontSizeFactor);
+            mFontInflationMinTwips.commit(scaledFontInflation);
+        }
+        return this;
+    }
+
+    /**
+     * Gets the currently applied font size factor.
+     *
+     * @return The currently applied font size factor.
+     */
+    public float getFontSizeFactor() {
+        return mFontSizeFactor.get() / 100f;
+    }
+
+    /**
+     * Set whether or not font inflation for non mobile-friendly pages should be enabled. The
+     * default value of this setting is <code>false</code>.
+     *
+     * <p>When enabled, font sizes will be increased on all pages that are lacking a &lt;meta&gt;
+     * viewport tag and have been loaded in a session using
+     * {@link GeckoSessionSettings#VIEWPORT_MODE_MOBILE}. To improve readability, the font inflation
+     * logic will attempt to increase font sizes for the main text content of the page only.
+     *
+     * <p>The magnitude of font inflation applied depends on the
+     * {@link GeckoRuntimeSettings#setFontSizeFactor font size factor} currently in use.
+     *
+     * <p>Currently, any changes only take effect after a reload of the session.
+     *
+     * @param enabled A flag determining whether or not font inflation should be enabled.
+     * @return This GeckoRuntimeSettings instance.
+     */
+    public @NonNull GeckoRuntimeSettings setFontInflationEnabled(boolean enabled) {
+        final int minTwips =
+                enabled ? Math.round(FONT_INFLATION_BASE_VALUE * getFontSizeFactor()) : 0;
+        mFontInflationMinTwips.commit(minTwips);
+        return this;
+    }
+
+    /**
+     * Get whether or not font inflation for non mobile-friendly pages is currently enabled.
+     *
+     * @return True if font inflation is enabled.
+     */
+    public boolean getFontInflationEnabled() {
+        return mFontInflationMinTwips.get() > 0;
+    }
+
     @Override // Parcelable
     public void writeToParcel(Parcel out, int flags) {
         super.writeToParcel(out, flags);
 
         ParcelableUtils.writeBoolean(out, mUseContentProcess);
         out.writeStringArray(mArgs);
         mExtras.writeToParcel(out, flags);
         ParcelableUtils.writeBoolean(out, mDebugPause);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
@@ -4,16 +4,19 @@ title: API Changelog
 description: GeckoView API Changelog.
 nav_exclude: true
 exclude: true
 ---
 
 <h1> GeckoView API Changelog. </h1>
 
 ## v67
+- Added GeckoRuntimeSettings for setting a font size scaling factor, and for
+  enabling font inflation for non-mobile-friendly pages.
+
 - Change `ContentBlocking.AT_ALL` and `ContentBlocking.SB_ALL` values to mirror
   the actual constants they encompass.
 
 - Added nested `ContentBlocking` runtime settings.
 
 - Added `RuntimeSettings` base class to support nested settings.
 
 - Added `baseUri` to [`ContentDelegate.ContextElement`][65.21] and changed
@@ -123,9 +126,9 @@ exclude: true
 [65.23]: ../GeckoSession.FinderResult.html
 
 - Update [`CrashReporter#sendCrashReport`][65.24] to return the crash ID as a
   [`GeckoResult<String>`][65.25].
 
 [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: ../GeckoResult.html
 
-[api-version]: 1a31e792d4802cb18219b7ac5281a63a89a1df75
+[api-version]: 1f30cea0011654a414fd9bad35dd340ffc56c6e2