From 51044f283faade0d3314eab0fafb2776189aec76 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Fri, 1 Jun 2018 15:35:32 +1000 Subject: [PATCH] Bug 1423017 - Add a telemetry for out-of-reach overflowing on root. r=botond MozReview-Commit-ID: 2CyZTVBFP59 --HG-- extra : rebase_source : 69792750af013f33ca9efd01c1d19013b0b26456 --- dom/base/nsDocument.cpp | 68 ++++++++++++++++++++ dom/base/nsIDocument.h | 37 ++++++++++- layout/generic/nsGfxScrollFrame.cpp | 35 ++++++++-- toolkit/components/telemetry/Histograms.json | 9 +++ 4 files changed, 143 insertions(+), 6 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index c02e8396454e..db45faab1f68 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1497,6 +1497,7 @@ nsIDocument::nsIDocument() mStackRefCnt(0), mUpdateNestLevel(0), mViewportType(Unknown), + mViewportOverflowType(ViewportOverflowType::NoOverflow), mSubDocuments(nullptr), mHeaderData(nullptr), mFlashClassification(FlashClassification::Unclassified), @@ -3690,6 +3691,7 @@ nsIDocument::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) aHeaderField == nsGkAtoms::viewport_width || aHeaderField == nsGkAtoms::viewport_user_scalable) { mViewportType = Unknown; + mViewportOverflowType = ViewportOverflowType::NoOverflow; } // Referrer policy spec says to ignore any empty referrer policies. @@ -7237,6 +7239,7 @@ nsIDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode); mViewportType = Specified; + mViewportOverflowType = ViewportOverflowType::NoOverflow; MOZ_FALLTHROUGH; } case Specified: @@ -7318,6 +7321,54 @@ nsIDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) } } +void +nsIDocument::UpdateViewportOverflowType(nscoord aScrolledWidth, + nscoord aScrollportWidth) +{ +#ifdef DEBUG + MOZ_ASSERT(mPresShell); + nsPresContext* pc = GetPresContext(); + MOZ_ASSERT(pc->GetViewportScrollbarStylesOverride().mHorizontal == + NS_STYLE_OVERFLOW_HIDDEN, + "Should only be called when viewport has overflow-x: hidden"); + MOZ_ASSERT(aScrolledWidth > aScrollportWidth, + "Should only be called when viewport is overflowed"); + MOZ_ASSERT(IsTopLevelContentDocument(), + "Should only be called for top-level content document"); +#endif // DEBUG + + if (!gfxPrefs::MetaViewportEnabled() || + (GetWindow() && GetWindow()->IsDesktopModeViewport())) { + mViewportOverflowType = ViewportOverflowType::Desktop; + return; + } + + static const LayoutDeviceToScreenScale + kBlinkDefaultMinScale = LayoutDeviceToScreenScale(0.25f); + LayoutDeviceToScreenScale minScale; + if (mViewportType == DisplayWidthHeight) { + minScale = kBlinkDefaultMinScale; + } else { + MOZ_ASSERT(mViewportType == Specified, + "Viewport information should have been initialized"); + if (mScaleMinFloat == kViewportMinScale) { + minScale = kBlinkDefaultMinScale; + } else { + minScale = mScaleMinFloat; + } + } + + // If the content has overflowed with minimum scale applied, don't + // change it, otherwise update the overflow type. + if (mViewportOverflowType != ViewportOverflowType::MinScaleSize) { + if (aScrolledWidth * minScale.scale < aScrollportWidth) { + mViewportOverflowType = ViewportOverflowType::ButNotMinScaleSize; + } else { + mViewportOverflowType = ViewportOverflowType::MinScaleSize; + } + } +} + EventListenerManager* nsDocument::GetOrCreateListenerManager() { @@ -12132,6 +12183,23 @@ nsIDocument::ReportUseCounters(UseCounterReportKind aKind) } } } + + if (IsTopLevelContentDocument() && !IsResourceDoc()) { + using mozilla::Telemetry::LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE; + LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE label; + switch (mViewportOverflowType) { +#define CASE_OVERFLOW_TYPE(t_) \ + case ViewportOverflowType::t_: \ + label = LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE::t_; \ + break; + CASE_OVERFLOW_TYPE(NoOverflow) + CASE_OVERFLOW_TYPE(Desktop) + CASE_OVERFLOW_TYPE(ButNotMinScaleSize) + CASE_OVERFLOW_TYPE(MinScaleSize) +#undef CASE_OVERFLOW_TYPE + } + Telemetry::AccumulateCategorical(label); + } } void diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index d6ce44e13fa2..e34411c96885 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -1199,6 +1199,17 @@ public: */ nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize); + /** + * It updates the viewport overflow type with the given two widths + * and the viewport setting of the document. + * This should only be called when there is out-of-reach overflow + * happens on the viewport, i.e. the viewport should be using + * `overflow: hidden`. And it should only be called on a top level + * content document. + */ + void UpdateViewportOverflowType(nscoord aScrolledWidth, + nscoord aScrollportWidth); + /** * True iff this doc will ignore manual character encoding overrides. */ @@ -4271,7 +4282,7 @@ protected: // Our update nesting level uint32_t mUpdateNestLevel; - enum ViewportType { + enum ViewportType : uint8_t { DisplayWidthHeight, Specified, Unknown @@ -4279,6 +4290,30 @@ protected: ViewportType mViewportType; + // Enum for how content in this document overflows viewport causing + // out-of-reach issue. Currently it only takes horizontal overflow + // into consideration. This enum and the corresponding field is only + // set and read on a top level content document. + enum class ViewportOverflowType : uint8_t { + // Viewport doesn't have out-of-reach overflow content, either + // because the content doesn't overflow, or the viewport doesn't + // have "overflow: hidden". + NoOverflow, + + // All following items indicates that the content overflows the + // scroll port which causing out-of-reach content. + + // Meta viewport is disabled or the document is in desktop mode. + Desktop, + // The content does not overflow the minimum-scale size. When there + // is no minimum scale specified, the default value used by Blink, + // 0.25, is used for this matter. + ButNotMinScaleSize, + // The content overflows the minimum-scale size. + MinScaleSize, + }; + ViewportOverflowType mViewportOverflowType; + PLDHashTable* mSubDocuments; nsDocHeaderData* mHeaderData; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index f872d9762950..7066031ebfcc 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -395,12 +395,12 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, std::max(0, compositionSize.height - hScrollbarDesiredHeight)); } - if (!aForce) { - nsRect scrolledRect = - mHelper.GetUnsnappedScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(), - scrollPortSize); - nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1); + nsRect scrolledRect = + mHelper.GetUnsnappedScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(), + scrollPortSize); + nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1); + if (!aForce) { // If the style is HIDDEN then we already know that aAssumeHScroll is false if (aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) { bool wantHScrollbar = @@ -426,6 +426,31 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, } } + do { + if (!mHelper.mIsRoot) { + break; + } + // Check whether there is actually any overflow. + nscoord scrolledWidth = scrolledRect.width + oneDevPixel; + if (scrolledWidth <= scrollPortSize.width) { + break; + } + // Viewport scrollbar style is used below instead of aState->mStyles + // because the latter can be affected by various factors, while we + // only care about what the page itself specifies. + nsPresContext* pc = PresContext(); + ScrollbarStyles styles = pc->GetViewportScrollbarStylesOverride(); + if (styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) { + break; + } + // Only top level content document is considered. + nsIDocument* doc = pc->Document(); + if (!doc->IsTopLevelContentDocument()) { + break; + } + doc->UpdateViewportOverflowType(scrolledWidth, scrollPortSize.width); + } while (false); + nscoord vScrollbarActualWidth = aState->mInsideBorderSize.width - scrollPortSize.width; aState->mShowHScrollbar = aAssumeHScroll; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 003e4507e2fe..026ed42acdbd 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -13804,5 +13804,14 @@ "high": 50, "n_buckets": 20, "description": "Total number of doc groups per tab group, including docgroups fully in bfcache. Collected at the point when the top level document of the tab group is unloaded." + }, + "HIDDEN_VIEWPORT_OVERFLOW_TYPE": { + "record_in_processes": ["content"], + "alert_emails": ["xquan@mozilla.com", "botond@mozilla.com"], + "bug_numbers": [1423013, 1423017], + "expires_in_version": "65", + "kind": "categorical", + "labels": ["NoOverflow", "Desktop", "ButNotMinScaleSize", "MinScaleSize"], + "description": "How common are different types of out-of-reach viewport overflow?" } }