Bug 1328868 - Part 2 - Apply the system font scale as an additional text zoom factor to all pages that are not font inflated. r?tnikkel
We want to use a similar model as Chrome on Android does for scaling our display of web content, that is use font inflation for desktop pages and plain text zooming for everything else.
Since we don't want to simply clobber any text zoom that might have been set by the user/front-end code, we allow setting and storing the system font scale separately on the PresContext. We then calculate the effective text zoom value as the product of the system font scale and the current text zoom value.
Any function that is using the PresContext's TextZoom value for layouting/rendering is switched over to this new EffectiveTextZoom value, whereas functions that are interested in the text zoom as actually set by the user/front-end (e.g. the nsDocumentViewer, or the code responsible for copying text and full zoom settings into the new PresContext on page navigation) continue using the plain TextZoom value.
As long as font inflation is enabled in principle (e.g. font.size.inflation.minTwips != 0), every page starts out as eligible for font inflation until the relevant meta viewport tags marking the page as "mobile friendly" have been detected. Since the PresShell caches the font inflation state and only recalculates it when necessary, we make use of that and set the PresContext's system font scale as necessary whenever the font inflation state has been refreshed.
MozReview-Commit-ID: 2InyE04wKAW
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -376,17 +376,17 @@ ValueFromStringHelper(nsCSSPropertyID aP
InvertSign(aStyleAnimValue);
}
if (aPropID == eCSSProperty_font_size) {
// Divide out text-zoom, since SVG is supposed to ignore it
MOZ_ASSERT(aStyleAnimValue.GetUnit() == StyleAnimationValue::eUnit_Coord,
"'font-size' value with unexpected style unit");
aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
- aPresContext->TextZoom());
+ aPresContext->EffectiveTextZoom());
}
return true;
}
// static
void
nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
Element* aTargetElement,
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -299,18 +299,18 @@ float
SVGContentUtils::GetFontSize(nsStyleContext *aStyleContext)
{
MOZ_ASSERT(aStyleContext, "NULL style context in GetFontSize");
nsPresContext *presContext = aStyleContext->PresContext();
MOZ_ASSERT(presContext, "NULL pres context in GetFontSize");
nscoord fontSize = aStyleContext->StyleFont()->mSize;
- return nsPresContext::AppUnitsToFloatCSSPixels(fontSize) /
- presContext->TextZoom();
+ return nsPresContext::AppUnitsToFloatCSSPixels(fontSize) /
+ presContext->EffectiveTextZoom();
}
float
SVGContentUtils::GetFontXHeight(Element *aElement)
{
if (!aElement)
return 1.0f;
@@ -347,17 +347,17 @@ SVGContentUtils::GetFontXHeight(nsStyleC
if (!fontMetrics) {
// ReportToConsole
NS_WARNING("no FontMetrics in GetFontXHeight()");
return 1.0f;
}
nscoord xHeight = fontMetrics->XHeight();
return nsPresContext::AppUnitsToFloatCSSPixels(xHeight) /
- presContext->TextZoom();
+ presContext->EffectiveTextZoom();
}
nsresult
SVGContentUtils::ReportToConsole(nsIDocument* doc,
const char* aWarning,
const char16_t **aParams,
uint32_t aParamsLength)
{
return nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -802,18 +802,18 @@ nsIPresShell::nsIPresShell()
, mNeedThrottledAnimationFlush(true)
, mPresShellId(0)
, mFontSizeInflationEmPerLine(0)
, mFontSizeInflationMinTwips(0)
, mFontSizeInflationLineThreshold(0)
, mFontSizeInflationForceEnabled(false)
, mFontSizeInflationDisabledInMasterProcess(false)
, mFontSizeInflationEnabled(false)
+ , mFontSizeInflationEnabledIsDirty(false)
, mPaintingIsFrozen(false)
- , mFontSizeInflationEnabledIsDirty(false)
, mIsNeverPainting(false)
, mInFlush(false)
{}
PresShell::PresShell()
: mCaretEnabled(false)
#ifdef DEBUG
, mInVerifyReflow(false)
@@ -11023,39 +11023,43 @@ PresShell::SetupFontInflation()
NotifyFontSizeInflationEnabledIsDirty();
}
void
nsIPresShell::RecomputeFontSizeInflationEnabled()
{
mFontSizeInflationEnabledIsDirty = false;
-
+ mFontSizeInflationEnabled = DetermineFontSizeInflationState();
+
+ HandleSystemFontScale();
+}
+
+bool
+nsIPresShell::DetermineFontSizeInflationState()
+{
MOZ_ASSERT(mPresContext, "our pres context should not be null");
if ((FontSizeInflationEmPerLine() == 0 &&
FontSizeInflationMinTwips() == 0) || mPresContext->IsChrome()) {
- mFontSizeInflationEnabled = false;
- return;
+ return false;
}
// Force-enabling font inflation always trumps the heuristics here.
if (!FontSizeInflationForceEnabled()) {
if (TabChild* tab = TabChild::GetFrom(this)) {
// We're in a child process. Cancel inflation if we're not
// async-pan zoomed.
if (!tab->AsyncPanZoomEnabled()) {
- mFontSizeInflationEnabled = false;
- return;
+ return false;
}
} else if (XRE_IsParentProcess()) {
// We're in the master process. Cancel inflation if it's been
// explicitly disabled.
if (FontSizeInflationDisabledInMasterProcess()) {
- mFontSizeInflationEnabled = false;
- return;
+ return false;
}
}
}
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
@@ -11070,49 +11074,64 @@ nsIPresShell::RecomputeFontSizeInflation
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult rv;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
if (!NS_SUCCEEDED(rv)) {
- mFontSizeInflationEnabled = false;
- return;
+ return false;
}
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
if (screen) {
int32_t screenLeft, screenTop, screenWidth, screenHeight;
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
nsViewportInfo vInf =
GetDocument()->GetViewportInfo(ScreenIntSize(screenWidth, screenHeight));
if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) {
- mFontSizeInflationEnabled = false;
- return;
- }
- }
-
- mFontSizeInflationEnabled = true;
+ return false;
+ }
+ }
+
+ return true;
}
bool
nsIPresShell::FontSizeInflationEnabled()
{
if (mFontSizeInflationEnabledIsDirty) {
RecomputeFontSizeInflationEnabled();
}
return mFontSizeInflationEnabled;
}
void
+nsIPresShell::HandleSystemFontScale()
+{
+ float fontScale = nsLayoutUtils::SystemFontScale();
+ if (fontScale == 0.0f) {
+ return;
+ }
+
+ MOZ_ASSERT(mDocument && mPresContext, "our document and pres context should not be null");
+
+ if (!mFontSizeInflationEnabled && !mDocument->IsSyntheticDocument()) {
+ mPresContext->SetSystemFontScale(fontScale);
+ } else {
+ mPresContext->SetSystemFontScale(1.0f);
+ }
+}
+
+void
PresShell::PausePainting()
{
if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
return;
mPaintingIsFrozen = true;
GetPresContext()->RefreshDriver()->Freeze();
}
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1703,16 +1703,27 @@ protected:
/**
* Do computations necessary to determine if font size inflation is enabled.
* This value is cached after computation, as the computation is somewhat
* expensive.
*/
void RecomputeFontSizeInflationEnabled();
+ /**
+ * Does the actual work of figuring out the current state of font size inflation.
+ */
+ bool DetermineFontSizeInflationState();
+
+ /**
+ * Apply the system font scale from the corresponding pref to the PresContext,
+ * taking into account the current state of font size inflation.
+ */
+ void HandleSystemFontScale();
+
void RecordAlloc(void* aPtr) {
#ifdef DEBUG
MOZ_ASSERT(!mAllocatedPointers.Contains(aPtr));
mAllocatedPointers.PutEntry(aPtr);
#endif
}
void RecordFree(void* aPtr) {
@@ -1910,21 +1921,22 @@ protected:
// Cached font inflation values. This is done to prevent changing of font
// inflation until a page is reloaded.
uint32_t mFontSizeInflationEmPerLine;
uint32_t mFontSizeInflationMinTwips;
uint32_t mFontSizeInflationLineThreshold;
bool mFontSizeInflationForceEnabled;
bool mFontSizeInflationDisabledInMasterProcess;
bool mFontSizeInflationEnabled;
- bool mPaintingIsFrozen;
// Dirty bit indicating that mFontSizeInflationEnabled needs to be recomputed.
bool mFontSizeInflationEnabledIsDirty;
+ bool mPaintingIsFrozen;
+
// If a document belongs to an invisible DocShell, this flag must be set
// to true, so we can avoid any paint calls for widget related to this
// presshell.
bool mIsNeverPainting;
// Whether we're currently under a FlushPendingNotifications.
// This is used to handle flush reentry correctly.
bool mInFlush;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -205,17 +205,19 @@ nsPresContext::nsPresContext(nsIDocument
: mType(aType),
mShell(nullptr),
mDocument(aDocument),
mMedium(aType == eContext_Galley ? nsGkAtoms::screen : nsGkAtoms::print),
mMediaEmulated(mMedium),
mLinkHandler(nullptr),
mInflationDisabledForShrinkWrap(false),
mBaseMinFontSize(0),
+ mSystemFontScale(1.0),
mTextZoom(1.0),
+ mEffectiveTextZoom(1.0),
mFullZoom(1.0),
mOverrideDPPX(0.0),
mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)),
mCurAppUnitsPerDevPixel(0),
mAutoQualityMinFontSizePixelsPref(0),
mPageSize(-1, -1),
mPageScale(0.0),
mPPScale(1.0f),
@@ -1314,16 +1316,39 @@ nsPresContext::GetContentLanguage() cons
return NS_Atomize(language);
// NOTE: This does *not* count as an explicit language; in other
// words, it doesn't trigger language-specific hyphenation.
}
return nullptr;
}
void
+nsPresContext::UpdateEffectiveTextZoom()
+{
+ float newZoom = mSystemFontScale * mTextZoom;
+ float minZoom = nsLayoutUtils::MinZoom();
+ float maxZoom = nsLayoutUtils::MaxZoom();
+
+ if (newZoom < minZoom) {
+ newZoom = minZoom;
+ } else if (newZoom > maxZoom) {
+ newZoom = maxZoom;
+ }
+
+ mEffectiveTextZoom = newZoom;
+
+ if (HasCachedStyleData()) {
+ // Media queries could have changed, since we changed the meaning
+ // of 'em' units in them.
+ MediaFeatureValuesChanged(eRestyle_ForceDescendants,
+ NS_STYLE_HINT_REFLOW);
+ }
+}
+
+void
nsPresContext::SetFullZoom(float aZoom)
{
if (!mShell || mFullZoom == aZoom) {
return;
}
// Re-fetch the view manager's window dimensions in case there's a deferred
// resize which hasn't affected our mVisibleArea yet
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -530,31 +530,64 @@ public:
float GetPrintPreviewScale() { return mPPScale; }
void SetPrintPreviewScale(float aScale) { mPPScale = aScale; }
nsDeviceContext* DeviceContext() const { return mDeviceContext; }
mozilla::EventStateManager* EventStateManager() { return mEventManager; }
nsIAtom* GetLanguageFromCharset() const { return mLanguage; }
already_AddRefed<nsIAtom> GetContentLanguage() const;
+ /**
+ * Get/set a text zoom factor that is applied on top of the normal text zoom
+ * set by the front-end/user.
+ */
+ float GetSystemFontScale() const { return mSystemFontScale; }
+ void SetSystemFontScale(float aFontScale) {
+ MOZ_ASSERT(aFontScale > 0.0f, "invalid font scale");
+ if (aFontScale == mSystemFontScale || IsPrintingOrPrintPreview()) {
+ return;
+ }
+
+ mSystemFontScale = aFontScale;
+ UpdateEffectiveTextZoom();
+ }
+
+ /**
+ * Get/set the text zoom factor in use.
+ * This value should be used if you're interested in the pure text zoom value
+ * controlled by the front-end, e.g. when transferring zoom levels to a new
+ * document.
+ * Code that wants to use this value for layouting and rendering purposes
+ * should consider using EffectiveTextZoom() instead, so as to take the system
+ * font scale into account as well.
+ */
float TextZoom() const { return mTextZoom; }
void SetTextZoom(float aZoom) {
MOZ_ASSERT(aZoom > 0.0f, "invalid zoom factor");
if (aZoom == mTextZoom)
return;
mTextZoom = aZoom;
- if (HasCachedStyleData()) {
- // Media queries could have changed, since we changed the meaning
- // of 'em' units in them.
- MediaFeatureValuesChanged(eRestyle_ForceDescendants,
- NS_STYLE_HINT_REFLOW);
- }
+ UpdateEffectiveTextZoom();
}
+protected:
+ void UpdateEffectiveTextZoom();
+
+public:
+ /**
+ * Corresponds to the product of text zoom and system font scale, limited
+ * by zoom.maxPercent and minPercent.
+ * As the system font scale is automatically set by the PresShell, code that
+ * e.g. wants to transfer zoom levels to a new document should use TextZoom()
+ * instead, which corresponds to the text zoom level that was actually set by
+ * the front-end/user.
+ */
+ float EffectiveTextZoom() const { return mEffectiveTextZoom; }
+
/**
* Get the minimum font size for the specified language. If aLanguage
* is nullptr, then the document's language is used. This combines
* the language-specific global preference with the per-presentation
* base minimum font size.
*/
int32_t MinFontSize(nsIAtom *aLanguage) const {
const LangGroupFontPrefs *prefs = GetFontPrefsForLang(aLanguage);
@@ -926,16 +959,17 @@ public:
}
gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
bool IsDynamic() { return (mType == eContext_PageLayout || mType == eContext_Galley); }
bool IsScreen() { return (mMedium == nsGkAtoms::screen ||
mType == eContext_PageLayout ||
mType == eContext_PrintPreview); }
+ bool IsPrintingOrPrintPreview() { return (mType == eContext_Print || mType == eContext_PrintPreview); }
// Is this presentation in a chrome docshell?
bool IsChrome() const { return mIsChrome; }
bool IsChromeOriginImage() const { return mIsChromeOriginImage; }
void UpdateIsChrome();
// Public API for native theme code to get style internals.
bool HasAuthorSpecifiedRules(const nsIFrame *aFrame,
@@ -1295,17 +1329,19 @@ public:
bool mInflationDisabledForShrinkWrap;
protected:
mozilla::WeakPtr<nsDocShell> mContainer;
// Base minimum font size, independent of the language-specific global preference. Defaults to 0
int32_t mBaseMinFontSize;
+ float mSystemFontScale; // Internal text zoom factor, defaults to 1.0
float mTextZoom; // Text zoom, defaults to 1.0
+ float mEffectiveTextZoom; // Text zoom * system font scale
float mFullZoom; // Page zoom, defaults to 1.0
float mOverrideDPPX; // DPPX overrided, defaults to 0.0
gfxSize mLastFontInflationScreenSize;
int32_t mCurAppUnitsPerDevPixel;
int32_t mAutoQualityMinFontSizePixelsPref;
nsCOMPtr<nsITheme> mTheme;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5409,17 +5409,17 @@ nsComputedDOMStyle::GetLineHeightCoord(n
blockHeight, 1.0f);
// CalcLineHeight uses font->mFont.size, but we want to use
// font->mSize as the font size. Adjust for that. Also adjust for
// the text zoom, if any.
const nsStyleFont* font = StyleFont();
float fCoord = float(aCoord);
if (font->mAllowZoom) {
- fCoord /= mPresShell->GetPresContext()->TextZoom();
+ fCoord /= mPresShell->GetPresContext()->EffectiveTextZoom();
}
if (font->mFont.size != font->mSize) {
fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
}
aCoord = NSToCoordRound(fCoord);
return true;
}
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -195,25 +195,25 @@ nsStyleFont::CalcDifference(const nsStyl
return nsChangeHint(0);
}
/* static */ nscoord
nsStyleFont::ZoomText(const nsPresContext* aPresContext, nscoord aSize)
{
// aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
// The caller is expected deal with that.
- return NSToCoordTruncClamped(float(aSize) * aPresContext->TextZoom());
+ return NSToCoordTruncClamped(float(aSize) * aPresContext->EffectiveTextZoom());
}
/* static */ nscoord
nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
{
// aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
// The caller is expected deal with that.
- return NSToCoordTruncClamped(float(aSize) / aPresContext->TextZoom());
+ return NSToCoordTruncClamped(float(aSize) / aPresContext->EffectiveTextZoom());
}
/* static */ already_AddRefed<nsIAtom>
nsStyleFont::GetLanguage(const nsPresContext* aPresContext)
{
RefPtr<nsIAtom> language = aPresContext->GetContentLanguage();
if (!language) {
// we didn't find a (usable) Content-Language, so we fall back