LCOV - code coverage report
Current view: top level - layout/base - nsLayoutUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 4324 0.1 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsLayoutUtils.h"
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/BasicEvents.h"
      11             : #include "mozilla/ClearOnShutdown.h"
      12             : #include "mozilla/EffectCompositor.h"
      13             : #include "mozilla/EffectSet.h"
      14             : #include "mozilla/EventDispatcher.h"
      15             : #include "mozilla/FloatingPoint.h"
      16             : #include "mozilla/gfx/gfxVars.h"
      17             : #include "mozilla/gfx/PathHelpers.h"
      18             : #include "mozilla/layers/PAPZ.h"
      19             : #include "mozilla/Likely.h"
      20             : #include "mozilla/Maybe.h"
      21             : #include "mozilla/MemoryReporting.h"
      22             : #include "mozilla/dom/ContentChild.h"
      23             : #include "mozilla/ServoStyleSetInlines.h"
      24             : #include "mozilla/StaticPrefs.h"
      25             : #include "mozilla/Unused.h"
      26             : #include "nsCharTraits.h"
      27             : #include "nsDocument.h"
      28             : #include "nsFontMetrics.h"
      29             : #include "nsPresContext.h"
      30             : #include "nsIContent.h"
      31             : #include "nsFrameList.h"
      32             : #include "nsGenericHTMLElement.h"
      33             : #include "nsGkAtoms.h"
      34             : #include "nsAtom.h"
      35             : #include "nsCaret.h"
      36             : #include "nsCSSPseudoElements.h"
      37             : #include "nsCSSAnonBoxes.h"
      38             : #include "nsCSSColorUtils.h"
      39             : #include "nsView.h"
      40             : #include "nsViewManager.h"
      41             : #include "nsPlaceholderFrame.h"
      42             : #include "nsIScrollableFrame.h"
      43             : #include "nsSubDocumentFrame.h"
      44             : #include "nsDisplayList.h"
      45             : #include "nsRegion.h"
      46             : #include "nsCSSFrameConstructor.h"
      47             : #include "nsBlockFrame.h"
      48             : #include "nsBidiPresUtils.h"
      49             : #include "imgIContainer.h"
      50             : #include "ImageOps.h"
      51             : #include "ImageRegion.h"
      52             : #include "gfxRect.h"
      53             : #include "gfxContext.h"
      54             : #include "gfxContext.h"
      55             : #include "nsIInterfaceRequestorUtils.h"
      56             : #include "nsCSSRendering.h"
      57             : #include "nsTextFragment.h"
      58             : #include "nsThemeConstants.h"
      59             : #include "nsPIDOMWindow.h"
      60             : #include "nsIDocShell.h"
      61             : #include "nsIWidget.h"
      62             : #include "gfxMatrix.h"
      63             : #include "gfxPrefs.h"
      64             : #include "gfxTypes.h"
      65             : #include "nsTArray.h"
      66             : #include "mozilla/dom/HTMLCanvasElement.h"
      67             : #include "nsICanvasRenderingContextInternal.h"
      68             : #include "gfxPlatform.h"
      69             : #include <algorithm>
      70             : #include <limits>
      71             : #include "mozilla/dom/AnonymousContent.h"
      72             : #include "mozilla/dom/HTMLBodyElement.h"
      73             : #include "mozilla/dom/HTMLMediaElementBinding.h"
      74             : #include "mozilla/dom/HTMLVideoElement.h"
      75             : #include "mozilla/dom/HTMLImageElement.h"
      76             : #include "mozilla/dom/DOMRect.h"
      77             : #include "mozilla/dom/DOMStringList.h"
      78             : #include "mozilla/dom/KeyframeEffect.h"
      79             : #include "mozilla/layers/APZCCallbackHelper.h"
      80             : #include "imgIRequest.h"
      81             : #include "nsIImageLoadingContent.h"
      82             : #include "nsCOMPtr.h"
      83             : #include "nsCSSProps.h"
      84             : #include "nsListControlFrame.h"
      85             : #include "mozilla/dom/Element.h"
      86             : #include "nsCanvasFrame.h"
      87             : #include "gfxDrawable.h"
      88             : #include "gfxEnv.h"
      89             : #include "gfxUtils.h"
      90             : #include "nsDataHashtable.h"
      91             : #include "nsTableWrapperFrame.h"
      92             : #include "nsTextFrame.h"
      93             : #include "nsFontInflationData.h"
      94             : #include "nsSVGIntegrationUtils.h"
      95             : #include "nsSVGUtils.h"
      96             : #include "SVGImageContext.h"
      97             : #include "SVGTextFrame.h"
      98             : #include "nsStyleStructInlines.h"
      99             : #include "nsStyleTransformMatrix.h"
     100             : #include "nsIFrameInlines.h"
     101             : #include "ImageContainer.h"
     102             : #include "nsComputedDOMStyle.h"
     103             : #include "ActiveLayerTracker.h"
     104             : #include "mozilla/gfx/2D.h"
     105             : #include "gfx2DGlue.h"
     106             : #include "mozilla/LookAndFeel.h"
     107             : #include "UnitTransforms.h"
     108             : #include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
     109             : #include "ClientLayerManager.h"
     110             : #include "nsRefreshDriver.h"
     111             : #include "nsIContentViewer.h"
     112             : #include "LayersLogging.h"
     113             : #include "mozilla/Preferences.h"
     114             : #include "nsFrameSelection.h"
     115             : #include "FrameLayerBuilder.h"
     116             : #include "mozilla/layers/APZUtils.h"    // for apz::CalculatePendingDisplayPort
     117             : #include "mozilla/layers/CompositorBridgeChild.h"
     118             : #include "mozilla/Telemetry.h"
     119             : #include "mozilla/EventDispatcher.h"
     120             : #include "mozilla/StyleAnimationValue.h"
     121             : #include "mozilla/ServoStyleSet.h"
     122             : #include "mozilla/WheelHandlingHelper.h" // for WheelHandlingUtils
     123             : #include "RegionBuilder.h"
     124             : #include "SVGViewportElement.h"
     125             : #include "DisplayItemClip.h"
     126             : #include "mozilla/layers/StackingContextHelper.h"
     127             : #include "mozilla/layers/WebRenderLayerManager.h"
     128             : #include "prenv.h"
     129             : #include "RetainedDisplayListBuilder.h"
     130             : #include "DisplayListChecker.h"
     131             : #include "TextDrawTarget.h"
     132             : #include "nsDeckFrame.h"
     133             : #include "mozilla/dom/InspectorFontFace.h"
     134             : 
     135             : #ifdef MOZ_XUL
     136             : #include "nsXULPopupManager.h"
     137             : #endif
     138             : 
     139             : #include "GeckoProfiler.h"
     140             : #include "nsAnimationManager.h"
     141             : #include "nsTransitionManager.h"
     142             : #include "mozilla/RestyleManager.h"
     143             : #include "LayoutLogging.h"
     144             : 
     145             : // Make sure getpid() works.
     146             : #ifdef XP_WIN
     147             : #include <process.h>
     148             : #define getpid _getpid
     149             : #else
     150             : #include <unistd.h>
     151             : #endif
     152             : 
     153             : using namespace mozilla;
     154             : using namespace mozilla::dom;
     155             : using namespace mozilla::image;
     156             : using namespace mozilla::layers;
     157             : using namespace mozilla::layout;
     158             : using namespace mozilla::gfx;
     159             : using mozilla::dom::HTMLMediaElementBinding::HAVE_NOTHING;
     160             : using mozilla::dom::HTMLMediaElementBinding::HAVE_METADATA;
     161             : 
     162             : #define INTERCHARACTER_RUBY_ENABLED_PREF_NAME "layout.css.ruby.intercharacter.enabled"
     163             : #define CONTENT_SELECT_ENABLED_PREF_NAME "dom.select_popup_in_content.enabled"
     164             : 
     165             : // The time in number of frames that we estimate for a refresh driver
     166             : // to be quiescent
     167             : #define DEFAULT_QUIESCENT_FRAMES 2
     168             : // The time (milliseconds) we estimate is needed between the end of an
     169             : // idle time and the next Tick.
     170             : #define DEFAULT_IDLE_PERIOD_TIME_LIMIT 1.0f
     171             : 
     172             : #ifdef DEBUG
     173             : // TODO: remove, see bug 598468.
     174             : bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
     175             : #endif // DEBUG
     176             : 
     177             : typedef FrameMetrics::ViewID ViewID;
     178             : typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
     179             : 
     180             : /* static */ uint32_t nsLayoutUtils::sFontSizeInflationEmPerLine;
     181             : /* static */ uint32_t nsLayoutUtils::sFontSizeInflationMinTwips;
     182             : /* static */ uint32_t nsLayoutUtils::sFontSizeInflationLineThreshold;
     183             : /* static */ int32_t  nsLayoutUtils::sFontSizeInflationMappingIntercept;
     184             : /* static */ uint32_t nsLayoutUtils::sFontSizeInflationMaxRatio;
     185             : /* static */ bool nsLayoutUtils::sFontSizeInflationForceEnabled;
     186             : /* static */ bool nsLayoutUtils::sFontSizeInflationDisabledInMasterProcess;
     187             : /* static */ uint32_t nsLayoutUtils::sSystemFontScale;
     188             : /* static */ uint32_t nsLayoutUtils::sZoomMaxPercent;
     189             : /* static */ uint32_t nsLayoutUtils::sZoomMinPercent;
     190             : /* static */ bool nsLayoutUtils::sInvalidationDebuggingIsEnabled;
     191             : /* static */ bool nsLayoutUtils::sInterruptibleReflowEnabled;
     192             : /* static */ bool nsLayoutUtils::sSVGTransformBoxEnabled;
     193             : /* static */ uint32_t nsLayoutUtils::sIdlePeriodDeadlineLimit;
     194             : /* static */ uint32_t nsLayoutUtils::sQuiescentFramesBeforeIdlePeriod;
     195             : 
     196             : static ViewID sScrollIdCounter = FrameMetrics::START_SCROLL_ID;
     197             : 
     198             : typedef nsDataHashtable<nsUint64HashKey, nsIContent*> ContentMap;
     199           0 : static ContentMap* sContentMap = nullptr;
     200           0 : static ContentMap& GetContentMap() {
     201           0 :   if (!sContentMap) {
     202             :     sContentMap = new ContentMap();
     203           0 :   }
     204             :   return *sContentMap;
     205             : }
     206             : 
     207             : template<typename TestType>
     208           0 : static bool
     209             : HasMatchingAnimations(EffectSet* aEffects, TestType&& aTest)
     210           0 : {
     211           0 :   for (KeyframeEffect* effect : *aEffects) {
     212           0 :     if (aTest(*effect)) {
     213             :       return true;
     214             :     }
     215             :   }
     216           0 : 
     217             :   return false;
     218             : }
     219             : 
     220             : template<typename TestType>
     221           0 : static bool
     222             : HasMatchingAnimations(const nsIFrame* aFrame, TestType&& aTest)
     223           0 : {
     224           0 :   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
     225             :   if (!effects) {
     226             :     return false;
     227             :   }
     228           0 : 
     229             :   return HasMatchingAnimations(effects, aTest);
     230             : }
     231             : 
     232           0 : bool
     233             : nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
     234             : {
     235           0 :   return HasMatchingAnimations(aFrame,
     236             :     [](KeyframeEffect& aEffect)
     237             :     {
     238             :       // Since |aEffect| is current, it must have an associated Animation
     239           0 :       // so we don't need to null-check the result of GetAnimation().
     240           0 :       return aEffect.IsCurrent() && aEffect.GetAnimation()->AsCSSTransition();
     241           0 :     }
     242             :   );
     243             : }
     244             : 
     245           0 : static bool
     246             : MayHaveAnimationOfProperty(EffectSet* effects, nsCSSPropertyID aProperty)
     247           0 : {
     248             :   MOZ_ASSERT(effects);
     249           0 : 
     250           0 :   if (aProperty == eCSSProperty_transform &&
     251             :       !effects->MayHaveTransformAnimation()) {
     252             :     return false;
     253           0 :   }
     254           0 :   if (aProperty == eCSSProperty_opacity &&
     255             :       !effects->MayHaveOpacityAnimation()) {
     256             :     return false;
     257             :   }
     258           0 : 
     259             :   return true;
     260             : }
     261             : 
     262           0 : static bool
     263             : MayHaveAnimationOfProperty(const nsIFrame* aFrame, nsCSSPropertyID aProperty)
     264             : {
     265           0 :   switch (aProperty) {
     266             :     case eCSSProperty_transform:
     267           0 :       return aFrame->MayHaveTransformAnimation();
     268             :     case eCSSProperty_opacity:
     269           0 :       return aFrame->MayHaveOpacityAnimation();
     270             :     default:
     271           0 :       MOZ_ASSERT_UNREACHABLE("unexpected property");
     272             :       return false;
     273             :   }
     274             : }
     275             : 
     276             : bool
     277           0 : nsLayoutUtils::HasAnimationOfProperty(EffectSet* aEffectSet,
     278             :                                       nsCSSPropertyID aProperty)
     279             : {
     280           0 :   if (!aEffectSet || !MayHaveAnimationOfProperty(aEffectSet, aProperty)) {
     281             :     return false;
     282             :   }
     283             : 
     284           0 :   return HasMatchingAnimations(aEffectSet,
     285           0 :     [&aProperty](KeyframeEffect& aEffect)
     286           0 :     {
     287           0 :       return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
     288           0 :              aEffect.HasAnimationOfProperty(aProperty);
     289           0 :     }
     290           0 :   );
     291             : }
     292             : 
     293             : bool
     294           0 : nsLayoutUtils::HasAnimationOfProperty(const nsIFrame* aFrame,
     295             :                                       nsCSSPropertyID aProperty)
     296             : {
     297           0 :   if (!MayHaveAnimationOfProperty(aFrame, aProperty)) {
     298             :     return false;
     299             :   }
     300             : 
     301           0 :   return HasMatchingAnimations(aFrame,
     302           0 :     [&aProperty](KeyframeEffect& aEffect)
     303           0 :     {
     304           0 :       return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
     305           0 :              aEffect.HasAnimationOfProperty(aProperty);
     306           0 :     }
     307           0 :   );
     308             : 
     309             : }
     310             : 
     311             : bool
     312           0 : nsLayoutUtils::HasEffectiveAnimation(const nsIFrame* aFrame,
     313             :                                      nsCSSPropertyID aProperty)
     314             : {
     315           0 :   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
     316           0 :   if (!effects || !MayHaveAnimationOfProperty(effects, aProperty)) {
     317             :     return false;
     318             :   }
     319             : 
     320             : 
     321           0 :   return HasMatchingAnimations(effects,
     322           0 :     [&aProperty](KeyframeEffect& aEffect)
     323           0 :     {
     324           0 :       return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
     325           0 :              aEffect.HasEffectiveAnimationOfProperty(aProperty);
     326           0 :     }
     327           0 :   );
     328             : }
     329             : 
     330             : static float
     331           0 : GetSuitableScale(float aMaxScale, float aMinScale,
     332             :                  nscoord aVisibleDimension, nscoord aDisplayDimension)
     333             : {
     334           0 :   float displayVisibleRatio = float(aDisplayDimension) /
     335           0 :                               float(aVisibleDimension);
     336             :   // We want to rasterize based on the largest scale used during the
     337             :   // transform animation, unless that would make us rasterize something
     338           0 :   // larger than the screen.  But we never want to go smaller than the
     339             :   // minimum scale over the animation.
     340             :   if (FuzzyEqualsMultiplicative(displayVisibleRatio, aMaxScale, .01f)) {
     341             :     // Using aMaxScale may make us rasterize something a fraction larger than
     342           0 :     // the screen. However, if aMaxScale happens to be the final scale of a
     343             :     // transform animation it is better to use aMaxScale so that for the
     344             :     // fraction of a second before we delayerize the composited texture it has
     345           0 :     // a better chance of being pixel aligned and composited without resampling
     346           0 :     // (avoiding visually clunky delayerization).
     347             :     return aMaxScale;
     348             :   }
     349             :   return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
     350             : }
     351           0 : 
     352             : static inline void
     353             : UpdateMinMaxScale(const nsIFrame* aFrame,
     354             :                   const AnimationValue& aValue,
     355             :                   Size& aMinScale,
     356             :                   Size& aMaxScale)
     357             : {
     358             :   Size size = aValue.GetScaleValue(aFrame);
     359             :   aMaxScale.width = std::max<float>(aMaxScale.width, size.width);
     360           0 :   aMaxScale.height = std::max<float>(aMaxScale.height, size.height);
     361             :   aMinScale.width = std::min<float>(aMinScale.width, size.width);
     362             :   aMinScale.height = std::min<float>(aMinScale.height, size.height);
     363             : }
     364           0 : 
     365             : static void
     366             : GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
     367             :                                       nsTArray<RefPtr<dom::Animation>>& aAnimations,
     368             :                                       Size& aMaxScale,
     369           0 :                                       Size& aMinScale)
     370           0 : {
     371           0 :   for (dom::Animation* anim : aAnimations) {
     372           0 :     // This method is only expected to be passed animations that are running on
     373           0 :     // the compositor and we only pass playing animations to the compositor,
     374           0 :     // which are, by definition, "relevant" animations (animations that are
     375             :     // not yet finished or which are filling forwards).
     376             :     MOZ_ASSERT(anim->IsRelevant());
     377           0 : 
     378             :     dom::KeyframeEffect* effect =
     379             :       anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
     380             :     MOZ_ASSERT(effect, "A playing animation should have a keyframe effect");
     381             :     for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
     382           0 :       const AnimationProperty& prop = effect->Properties()[propIdx];
     383             :       if (prop.mProperty != eCSSProperty_transform) {
     384             :         continue;
     385             :       }
     386             : 
     387           0 :       // We need to factor in the scale of the base style if the base style
     388             :       // will be used on the compositor.
     389             :       AnimationValue baseStyle = effect->BaseStyle(prop.mProperty);
     390           0 :       if (!baseStyle.IsNull()) {
     391           0 :         UpdateMinMaxScale(aFrame, baseStyle, aMinScale, aMaxScale);
     392           0 :       }
     393           0 : 
     394           0 :       for (const AnimationPropertySegment& segment : prop.mSegments) {
     395           0 :         // In case of add or accumulate composite, StyleAnimationValue does
     396             :         // not have a valid value.
     397             :         if (segment.HasReplaceableFromValue()) {
     398             :           UpdateMinMaxScale(aFrame, segment.mFromValue, aMinScale, aMaxScale);
     399             :         }
     400           0 :         if (segment.HasReplaceableToValue()) {
     401           0 :           UpdateMinMaxScale(aFrame, segment.mToValue, aMinScale, aMaxScale);
     402           0 :         }
     403             :       }
     404             :     }
     405           0 :   }
     406             : }
     407             : 
     408           0 : Size
     409           0 : nsLayoutUtils::ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
     410             :                                                 const nsSize& aVisibleSize,
     411           0 :                                                 const nsSize& aDisplaySize)
     412           0 : {
     413             :   Size maxScale(std::numeric_limits<float>::min(),
     414             :                 std::numeric_limits<float>::min());
     415             :   Size minScale(std::numeric_limits<float>::max(),
     416             :                 std::numeric_limits<float>::max());
     417           0 : 
     418             :   nsTArray<RefPtr<dom::Animation>> compositorAnimations =
     419             :     EffectCompositor::GetAnimationsForCompositor(aFrame,
     420           0 :                                                  eCSSProperty_transform);
     421             :   GetMinAndMaxScaleForAnimationProperty(aFrame, compositorAnimations,
     422             :                                         maxScale, minScale);
     423             : 
     424             :   if (maxScale.width == std::numeric_limits<float>::min()) {
     425           0 :     // We didn't encounter a transform
     426             :     return Size(1.0, 1.0);
     427           0 :   }
     428             : 
     429             :   return Size(GetSuitableScale(maxScale.width, minScale.width,
     430             :                                aVisibleSize.width, aDisplaySize.width),
     431           0 :               GetSuitableScale(maxScale.height, minScale.height,
     432             :                                aVisibleSize.height, aDisplaySize.height));
     433           0 : }
     434             : 
     435           0 : bool
     436             : nsLayoutUtils::AreAsyncAnimationsEnabled()
     437           0 : {
     438             :   static bool sAreAsyncAnimationsEnabled;
     439             :   static bool sAsyncPrefCached = false;
     440           0 : 
     441           0 :   if (!sAsyncPrefCached) {
     442             :     sAsyncPrefCached = true;
     443           0 :     Preferences::AddBoolVarCache(&sAreAsyncAnimationsEnabled,
     444             :                                  "layers.offmainthreadcomposition.async-animations");
     445             :   }
     446             : 
     447           0 :   return sAreAsyncAnimationsEnabled &&
     448             :     gfxPlatform::OffMainThreadCompositingEnabled();
     449             : }
     450             : 
     451             : bool
     452           0 : nsLayoutUtils::IsAnimationLoggingEnabled()
     453           0 : {
     454             :   static bool sShouldLog;
     455           0 :   static bool sShouldLogPrefCached;
     456             : 
     457             :   if (!sShouldLogPrefCached) {
     458           0 :     sShouldLogPrefCached = true;
     459           0 :     Preferences::AddBoolVarCache(&sShouldLog,
     460             :                                  "layers.offmainthreadcomposition.log-animations");
     461             :   }
     462             : 
     463           0 :   return sShouldLog;
     464             : }
     465             : 
     466             : bool
     467             : nsLayoutUtils::AreRetainedDisplayListsEnabled()
     468           0 : {
     469           0 :   if (XRE_IsContentProcess()) {
     470             :     return gfxPrefs::LayoutRetainDisplayList();
     471           0 :   } else {
     472             :     return gfxPrefs::LayoutRetainDisplayListChrome();
     473             :   }
     474           0 : }
     475             : 
     476             : bool
     477             : nsLayoutUtils::GPUImageScalingEnabled()
     478           0 : {
     479             :   static bool sGPUImageScalingEnabled;
     480           0 :   static bool sGPUImageScalingPrefInitialised = false;
     481           0 : 
     482             :   if (!sGPUImageScalingPrefInitialised) {
     483           0 :     sGPUImageScalingPrefInitialised = true;
     484             :     sGPUImageScalingEnabled =
     485             :       Preferences::GetBool("layout.gpu-image-scaling.enabled", false);
     486             :   }
     487             : 
     488           0 :   return sGPUImageScalingEnabled;
     489             : }
     490             : 
     491             : bool
     492             : nsLayoutUtils::AnimatedImageLayersEnabled()
     493           0 : {
     494           0 :   static bool sAnimatedImageLayersEnabled;
     495           0 :   static bool sAnimatedImageLayersPrefCached = false;
     496           0 : 
     497             :   if (!sAnimatedImageLayersPrefCached) {
     498             :     sAnimatedImageLayersPrefCached = true;
     499           0 :     Preferences::AddBoolVarCache(&sAnimatedImageLayersEnabled,
     500             :                                  "layout.animated-image-layers.enabled",
     501             :                                  false);
     502             :   }
     503           0 : 
     504             :   return sAnimatedImageLayersEnabled;
     505             : }
     506             : 
     507             : bool
     508           0 : nsLayoutUtils::CSSFiltersEnabled()
     509           0 : {
     510             :   static bool sCSSFiltersEnabled;
     511             :   static bool sCSSFiltersPrefCached = false;
     512           0 : 
     513             :   if (!sCSSFiltersPrefCached) {
     514             :     sCSSFiltersPrefCached = true;
     515           0 :     Preferences::AddBoolVarCache(&sCSSFiltersEnabled,
     516             :                                  "layout.css.filters.enabled",
     517             :                                  false);
     518             :   }
     519           0 : 
     520             :   return sCSSFiltersEnabled;
     521             : }
     522             : 
     523             : bool
     524           0 : nsLayoutUtils::UnsetValueEnabled()
     525           0 : {
     526             :   static bool sUnsetValueEnabled;
     527             :   static bool sUnsetValuePrefCached = false;
     528           0 : 
     529             :   if (!sUnsetValuePrefCached) {
     530             :     sUnsetValuePrefCached = true;
     531           0 :     Preferences::AddBoolVarCache(&sUnsetValueEnabled,
     532             :                                  "layout.css.unset-value.enabled",
     533             :                                  false);
     534             :   }
     535           0 : 
     536             :   return sUnsetValueEnabled;
     537             : }
     538             : 
     539             : bool
     540           0 : nsLayoutUtils::IsInterCharacterRubyEnabled()
     541           0 : {
     542             :   static bool sInterCharacterRubyEnabled;
     543             :   static bool sInterCharacterRubyEnabledPrefCached = false;
     544           0 : 
     545             :   if (!sInterCharacterRubyEnabledPrefCached) {
     546             :     sInterCharacterRubyEnabledPrefCached = true;
     547           0 :     Preferences::AddBoolVarCache(&sInterCharacterRubyEnabled,
     548             :                                  INTERCHARACTER_RUBY_ENABLED_PREF_NAME,
     549             :                                  false);
     550             :   }
     551           0 : 
     552             :   return sInterCharacterRubyEnabled;
     553             : }
     554             : 
     555             : bool
     556           0 : nsLayoutUtils::IsContentSelectEnabled()
     557           0 : {
     558             :   static bool sContentSelectEnabled;
     559             :   static bool sContentSelectEnabledPrefCached = false;
     560           0 : 
     561             :   if (!sContentSelectEnabledPrefCached) {
     562             :     sContentSelectEnabledPrefCached = true;
     563           0 :     Preferences::AddBoolVarCache(&sContentSelectEnabled,
     564             :                                  CONTENT_SELECT_ENABLED_PREF_NAME,
     565             :                                  false);
     566             :   }
     567           0 : 
     568             :   return sContentSelectEnabled;
     569             : }
     570             : 
     571             : void
     572           0 : nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
     573           0 :                                   nsOverflowAreas& aOverflowAreas,
     574             :                                   FrameChildListIDs aSkipChildLists)
     575             : {
     576           0 :   // Iterate over all children except pop-ups.
     577             :   FrameChildListIDs skip = aSkipChildLists |
     578             :       nsIFrame::kSelectPopupList | nsIFrame::kPopupList;
     579           0 :   for (nsIFrame::ChildListIterator childLists(aFrame);
     580             :        !childLists.IsDone(); childLists.Next()) {
     581             :     if (skip.Contains(childLists.CurrentID())) {
     582             :       continue;
     583           0 :     }
     584             : 
     585             :     nsFrameList children = childLists.CurrentList();
     586             :     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
     587             :       nsIFrame* child = e.get();
     588           0 :       nsOverflowAreas childOverflow =
     589           0 :         child->GetOverflowAreas() + child->GetPosition();
     590           0 :       aOverflowAreas.UnionWith(childOverflow);
     591           0 :     }
     592           0 :   }
     593           0 : }
     594             : 
     595             : static void DestroyViewID(void* aObject, nsAtom* aPropertyName,
     596           0 :                           void* aPropertyValue, void* aData)
     597           0 : {
     598           0 :   ViewID* id = static_cast<ViewID*>(aPropertyValue);
     599             :   GetContentMap().Remove(*id);
     600           0 :   delete id;
     601           0 : }
     602             : 
     603             : /**
     604           0 :  * A namespace class for static layout utilities.
     605             :  */
     606           0 : 
     607             : bool
     608             : nsLayoutUtils::FindIDFor(const nsIContent* aContent, ViewID* aOutViewId)
     609           0 : {
     610           0 :   void* scrollIdProperty = aContent->GetProperty(nsGkAtoms::RemoteId);
     611           0 :   if (scrollIdProperty) {
     612           0 :     *aOutViewId = *static_cast<ViewID*>(scrollIdProperty);
     613             :     return true;
     614             :   }
     615             :   return false;
     616             : }
     617             : 
     618             : ViewID
     619           0 : nsLayoutUtils::FindOrCreateIDFor(nsIContent* aContent)
     620             : {
     621           0 :   ViewID scrollId;
     622           0 : 
     623           0 :   if (!FindIDFor(aContent, &scrollId)) {
     624           0 :     scrollId = sScrollIdCounter++;
     625             :     aContent->SetProperty(nsGkAtoms::RemoteId, new ViewID(scrollId),
     626             :                           DestroyViewID);
     627             :     GetContentMap().Put(scrollId, aContent);
     628             :   }
     629             : 
     630           0 :   return scrollId;
     631             : }
     632             : 
     633             : nsIContent*
     634           0 : nsLayoutUtils::FindContentFor(ViewID aId)
     635           0 : {
     636           0 :   MOZ_ASSERT(aId != FrameMetrics::NULL_SCROLL_ID,
     637           0 :              "Cannot find a content element in map for null IDs.");
     638           0 :   nsIContent* content;
     639             :   bool exists = GetContentMap().Get(aId, &content);
     640             : 
     641           0 :   if (exists) {
     642             :     return content;
     643             :   } else {
     644             :     return nullptr;
     645           0 :   }
     646             : }
     647           0 : 
     648             : static nsIFrame*
     649             : GetScrollFrameFromContent(nsIContent* aContent)
     650           0 : {
     651             :   nsIFrame* frame = aContent->GetPrimaryFrame();
     652           0 :   if (aContent->OwnerDoc()->GetRootElement() == aContent) {
     653           0 :     nsIPresShell* presShell = frame ? frame->PresShell() : nullptr;
     654             :     if (!presShell) {
     655             :       presShell = aContent->OwnerDoc()->GetShell();
     656             :     }
     657             :     // We want the scroll frame, the root scroll frame differs from all
     658             :     // others in that the primary frame is not the scroll frame.
     659             :     nsIFrame* rootScrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
     660           0 :     if (rootScrollFrame) {
     661             :       frame = rootScrollFrame;
     662           0 :     }
     663           0 :   }
     664           0 :   return frame;
     665           0 : }
     666           0 : 
     667             : nsIScrollableFrame*
     668             : nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
     669             : {
     670           0 :   nsIContent* content = FindContentFor(aId);
     671           0 :   if (!content) {
     672           0 :     return nullptr;
     673             :   }
     674             : 
     675           0 :   nsIFrame* scrollFrame = GetScrollFrameFromContent(content);
     676             :   return scrollFrame ? scrollFrame->GetScrollTargetFrame() : nullptr;
     677             : }
     678             : 
     679           0 : ViewID
     680             : nsLayoutUtils::FindIDForScrollableFrame(nsIScrollableFrame* aScrollable)
     681           0 : {
     682           0 :   if (!aScrollable) {
     683             :     return FrameMetrics::NULL_SCROLL_ID;
     684             :   }
     685             : 
     686           0 :   nsIFrame* scrollFrame = do_QueryFrame(aScrollable);
     687           0 :   nsIContent* scrollContent = scrollFrame->GetContent();
     688             : 
     689             :   FrameMetrics::ViewID scrollId;
     690             :   if (scrollContent &&
     691           0 :       nsLayoutUtils::FindIDFor(scrollContent, &scrollId)) {
     692             :     return scrollId;
     693           0 :   }
     694           0 : 
     695             :   return FrameMetrics::NULL_SCROLL_ID;
     696             : }
     697           0 : 
     698           0 : static nsRect
     699             : ApplyRectMultiplier(nsRect aRect, float aMultiplier)
     700             : {
     701           0 :   if (aMultiplier == 1.0f) {
     702           0 :     return aRect;
     703           0 :   }
     704             :   float newWidth = aRect.width * aMultiplier;
     705             :   float newHeight = aRect.height * aMultiplier;
     706           0 :   float newX = aRect.x - ((newWidth - aRect.width) / 2.0f);
     707             :   float newY = aRect.y - ((newHeight - aRect.height) / 2.0f);
     708             :   // Rounding doesn't matter too much here, do a round-in
     709             :   return nsRect(ceil(newX), ceil(newY), floor(newWidth), floor(newHeight));
     710           0 : }
     711             : 
     712           0 : bool
     713           0 : nsLayoutUtils::UsesAsyncScrolling(nsIFrame* aFrame)
     714             : {
     715           0 : #ifdef MOZ_WIDGET_ANDROID
     716           0 :   // We always have async scrolling for android
     717           0 :   return true;
     718           0 : #endif
     719             : 
     720           0 :   return AsyncPanZoomEnabled(aFrame);
     721             : }
     722             : 
     723             : bool
     724           0 : nsLayoutUtils::AsyncPanZoomEnabled(nsIFrame* aFrame)
     725             : {
     726             :   // We use this as a shortcut, since if the compositor will never use APZ,
     727             :   // no widget will either.
     728             :   if (!gfxPlatform::AsyncPanZoomEnabled()) {
     729             :     return false;
     730             :   }
     731           0 : 
     732             :   nsIFrame *frame = nsLayoutUtils::GetDisplayRootFrame(aFrame);
     733             :   nsIWidget* widget = frame->GetNearestWidget();
     734             :   if (!widget) {
     735           0 :     return false;
     736             :   }
     737             :   return widget->AsyncPanZoomEnabled();
     738             : }
     739           0 : 
     740             : float
     741             : nsLayoutUtils::GetCurrentAPZResolutionScale(nsIPresShell* aShell) {
     742             :   return aShell ? aShell->GetCumulativeNonRootScaleResolution() : 1.0;
     743           0 : }
     744           0 : 
     745           0 : // Return the maximum displayport size, based on the LayerManager's maximum
     746             : // supported texture size. The result is in app units.
     747             : static nscoord
     748           0 : GetMaxDisplayPortSize(nsIContent* aContent, nsPresContext* aFallbackPrescontext)
     749             : {
     750             :   MOZ_ASSERT(!gfxPrefs::LayersTilesEnabled(), "Do not clamp displayports if tiling is enabled");
     751             : 
     752           0 :   // Pick a safe maximum displayport size for sanity purposes. This is the
     753           0 :   // lowest maximum texture size on tileless-platforms (Windows, D3D10).
     754             :   // If the gfx.max-texture-size pref is set, further restrict the displayport
     755             :   // size to fit within that, because the compositor won't upload stuff larger
     756             :   // than this size.
     757             :   nscoord safeMaximum = aFallbackPrescontext
     758             :       ? aFallbackPrescontext->DevPixelsToAppUnits(
     759           0 :             std::min(8192, gfxPlatform::MaxTextureSize()))
     760             :       : nscoord_MAX;
     761           0 : 
     762             :   nsIFrame* frame = aContent->GetPrimaryFrame();
     763             :   if (!frame) {
     764             :     return safeMaximum;
     765             :   }
     766             :   frame = nsLayoutUtils::GetDisplayRootFrame(frame);
     767             : 
     768             :   nsIWidget* widget = frame->GetNearestWidget();
     769           0 :   if (!widget) {
     770           0 :     return safeMaximum;
     771           0 :   }
     772             :   LayerManager* lm = widget->GetLayerManager();
     773           0 :   if (!lm) {
     774           0 :     return safeMaximum;
     775             :   }
     776             :   nsPresContext* presContext = frame->PresContext();
     777           0 : 
     778             :   int32_t maxSizeInDevPixels = lm->GetMaxTextureSize();
     779           0 :   if (maxSizeInDevPixels < 0 || maxSizeInDevPixels == INT_MAX) {
     780           0 :     return safeMaximum;
     781             :   }
     782             :   maxSizeInDevPixels = std::min(maxSizeInDevPixels, gfxPlatform::MaxTextureSize());
     783           0 :   return presContext->DevPixelsToAppUnits(maxSizeInDevPixels);
     784           0 : }
     785             : 
     786             : static nsRect
     787           0 : GetDisplayPortFromRectData(nsIContent* aContent,
     788             :                            DisplayPortPropertyData* aRectData,
     789           0 :                            float aMultiplier)
     790           0 : {
     791             :   // In the case where the displayport is set as a rect, we assume it is
     792             :   // already aligned and clamped as necessary. The burden to do that is
     793           0 :   // on the setter of the displayport. In practice very few places set the
     794           0 :   // displayport directly as a rect (mostly tests). We still do need to
     795             :   // expand it by the multiplier though.
     796             :   return ApplyRectMultiplier(aRectData->mRect, aMultiplier);
     797             : }
     798           0 : 
     799             : static nsRect
     800             : GetDisplayPortFromMarginsData(nsIContent* aContent,
     801             :                               DisplayPortMarginsPropertyData* aMarginsData,
     802             :                               float aMultiplier)
     803             : {
     804             :   // In the case where the displayport is set via margins, we apply the margins
     805             :   // to a base rect. Then we align the expanded rect based on the alignment
     806             :   // requested, further expand the rect by the multiplier, and finally, clamp it
     807           0 :   // to the size of the scrollable rect.
     808             : 
     809             :   nsRect base;
     810             :   if (nsRect* baseData = static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase))) {
     811           0 :     base = *baseData;
     812             :   } else {
     813             :     // In theory we shouldn't get here, but we do sometimes (see bug 1212136).
     814             :     // Fall through for graceful handling.
     815             :   }
     816             : 
     817             :   nsIFrame* frame = GetScrollFrameFromContent(aContent);
     818             :   if (!frame) {
     819             :     // Turns out we can't really compute it. Oops. We still should return
     820           0 :     // something sane. Note that since we can't clamp the rect without a
     821           0 :     // frame, we don't apply the multiplier either as it can cause the result
     822           0 :     // to leak outside the scrollable area.
     823             :     NS_WARNING("Attempting to get a displayport from a content with no primary frame!");
     824             :     return base;
     825             :   }
     826             : 
     827             :   bool isRoot = false;
     828           0 :   if (aContent->OwnerDoc()->GetRootElement() == aContent) {
     829           0 :     isRoot = true;
     830             :   }
     831             : 
     832             :   nsPoint scrollPos;
     833             :   if (nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame()) {
     834           0 :     scrollPos = scrollableFrame->GetScrollPosition();
     835           0 :   }
     836             : 
     837             :   nsPresContext* presContext = frame->PresContext();
     838           0 :   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
     839           0 : 
     840           0 :   LayoutDeviceToScreenScale2D res(presContext->PresShell()->GetCumulativeResolution()
     841             :                                 * nsLayoutUtils::GetTransformToAncestorScale(frame));
     842             : 
     843           0 :   // Calculate the expanded scrollable rect, which we'll be clamping the
     844           0 :   // displayport to.
     845           0 :   nsRect expandedScrollableRect =
     846             :     nsLayoutUtils::CalculateExpandedScrollableRect(frame);
     847             : 
     848           0 :   // GetTransformToAncestorScale() can return 0. In this case, just return the
     849           0 :   // base rect (clamped to the expanded scrollable rect), as other calculations
     850             :   // would run into divisions by zero.
     851           0 :   if (res == LayoutDeviceToScreenScale2D(0, 0)) {
     852           0 :     // Make sure the displayport remains within the scrollable rect.
     853             :     return base.MoveInsideAndClamp(expandedScrollableRect - scrollPos);
     854             :   }
     855             : 
     856             :   // First convert the base rect to screen pixels
     857           0 :   LayoutDeviceToScreenScale2D parentRes = res;
     858             :   if (isRoot) {
     859             :     // the base rect for root scroll frames is specified in the parent document
     860             :     // coordinate space, so it doesn't include the local resolution.
     861             :     float localRes = presContext->PresShell()->GetResolution();
     862           0 :     parentRes.xScale /= localRes;
     863             :     parentRes.yScale /= localRes;
     864           0 :   }
     865             :   ScreenRect screenRect = LayoutDeviceRect::FromAppUnits(base, auPerDevPixel)
     866             :                         * parentRes;
     867             : 
     868           0 :   // Note on the correctness of applying the alignment in Screen space:
     869           0 :   //   The correct space to apply the alignment in would be Layer space, but
     870             :   //   we don't necessarily know the scale to convert to Layer space at this
     871             :   //   point because Layout may not yet have chosen the resolution at which to
     872           0 :   //   render (it chooses that in FrameLayerBuilder, but this can be called
     873           0 :   //   during display list building). Therefore, we perform the alignment in
     874           0 :   //   Screen space, which basically assumes that Layout chose to render at
     875             :   //   screen resolution; since this is what Layout does most of the time,
     876           0 :   //   this is a good approximation. A proper solution would involve moving
     877           0 :   //   the choosing of the resolution to display-list building time.
     878             :   ScreenSize alignment;
     879             : 
     880             :   if (APZCCallbackHelper::IsDisplayportSuppressed()) {
     881             :     alignment = ScreenSize(1, 1);
     882             :   } else if (gfxPrefs::LayersTilesEnabled()) {
     883             :     // Don't align to tiles if they are too large, because we could expand
     884             :     // the displayport by a lot which can take more paint time. It's a tradeoff
     885             :     // though because if we don't align to tiles we have more waste on upload.
     886             :     IntSize tileSize = gfxVars::TileSize();
     887             :     alignment = ScreenSize(std::min(256, tileSize.width), std::min(256, tileSize.height));
     888             :   } else {
     889           0 :     // If we're not drawing with tiles then we need to be careful about not
     890             :     // hitting the max texture size and we only need 1 draw call per layer
     891           0 :     // so we can align to a smaller multiple.
     892             :     alignment = ScreenSize(128, 128);
     893           0 :   }
     894             : 
     895             :   // Avoid division by zero.
     896             :   if (alignment.width == 0) {
     897           0 :     alignment.width = 128;
     898           0 :   }
     899             :   if (alignment.height == 0) {
     900             :     alignment.height = 128;
     901             :   }
     902             : 
     903             :   if (gfxPrefs::LayersTilesEnabled()) {
     904             :     // Expand the rect by the margins
     905             :     screenRect.Inflate(aMarginsData->mMargins);
     906             :   } else {
     907           0 :     // Calculate the displayport to make sure we fit within the max texture size
     908           0 :     // when not tiling.
     909             :     nscoord maxSizeAppUnits = GetMaxDisplayPortSize(aContent, presContext);
     910           0 :     MOZ_ASSERT(maxSizeAppUnits < nscoord_MAX);
     911           0 : 
     912             :     // The alignment code can round up to 3 tiles, we want to make sure
     913             :     // that the displayport can grow by up to 3 tiles without going
     914           0 :     // over the max texture size.
     915             :     const int MAX_ALIGN_ROUNDING = 3;
     916           0 : 
     917             :     // Find the maximum size in screen pixels.
     918             :     int32_t maxSizeDevPx = presContext->AppUnitsToDevPixels(maxSizeAppUnits);
     919             :     int32_t maxWidthScreenPx = floor(double(maxSizeDevPx) * res.xScale) -
     920           0 :       MAX_ALIGN_ROUNDING * alignment.width;
     921           0 :     int32_t maxHeightScreenPx = floor(double(maxSizeDevPx) * res.yScale) -
     922             :       MAX_ALIGN_ROUNDING * alignment.height;
     923             : 
     924             :     // For each axis, inflate the margins up to the maximum size.
     925             :     const ScreenMargin& margins = aMarginsData->mMargins;
     926           0 :     if (screenRect.height < maxHeightScreenPx) {
     927             :       int32_t budget = maxHeightScreenPx - screenRect.height;
     928             :       // Scale the margins down to fit into the budget if necessary, maintaining
     929           0 :       // their relative ratio.
     930           0 :       float scale = 1.0f;
     931           0 :       if (float(budget) < margins.TopBottom()) {
     932           0 :         scale = float(budget) / margins.TopBottom();
     933           0 :       }
     934             :       float top = margins.top * scale;
     935             :       float bottom = margins.bottom * scale;
     936           0 :       screenRect.y -= top;
     937           0 :       screenRect.height += top + bottom;
     938           0 :     }
     939             :     if (screenRect.width < maxWidthScreenPx) {
     940             :       int32_t budget = maxWidthScreenPx - screenRect.width;
     941           0 :       float scale = 1.0f;
     942           0 :       if (float(budget) < margins.LeftRight()) {
     943           0 :         scale = float(budget) / margins.LeftRight();
     944             :       }
     945           0 :       float left = margins.left * scale;
     946           0 :       float right = margins.right * scale;
     947           0 :       screenRect.x -= left;
     948           0 :       screenRect.width += left + right;
     949             :     }
     950           0 :   }
     951           0 : 
     952           0 :   ScreenPoint scrollPosScreen = LayoutDevicePoint::FromAppUnits(scrollPos, auPerDevPixel)
     953           0 :                               * res;
     954           0 : 
     955             :   // Round-out the display port to the nearest alignment (tiles)
     956           0 :   screenRect += scrollPosScreen;
     957           0 :   float x = alignment.width * floor(screenRect.x / alignment.width);
     958           0 :   float y = alignment.height * floor(screenRect.y / alignment.height);
     959           0 :   float w = alignment.width * ceil(screenRect.width / alignment.width + 1);
     960             :   float h = alignment.height * ceil(screenRect.height / alignment.height + 1);
     961             :   screenRect = ScreenRect(x, y, w, h);
     962             :   screenRect -= scrollPosScreen;
     963           0 : 
     964           0 :   // Convert the aligned rect back into app units.
     965             :   nsRect result = LayoutDeviceRect::ToAppUnits(screenRect / res, auPerDevPixel);
     966             : 
     967           0 :   // If we have non-zero margins, expand the displayport for the low-res buffer
     968           0 :   // if that's what we're drawing. If we have zero margins, we want the
     969           0 :   // displayport to reflect the scrollport.
     970           0 :   if (aMarginsData->mMargins != ScreenMargin()) {
     971           0 :     result = ApplyRectMultiplier(result, aMultiplier);
     972           0 :   }
     973           0 : 
     974             :   // Make sure the displayport remains within the scrollable rect.
     975             :   result = result.MoveInsideAndClamp(expandedScrollableRect - scrollPos);
     976           0 : 
     977             :   return result;
     978             : }
     979             : 
     980             : static bool
     981           0 : HasVisibleAnonymousContents(nsIDocument* aDoc)
     982           0 : {
     983             :   for (RefPtr<AnonymousContent>& ac : aDoc->GetAnonymousContents()) {
     984             :     Element* elem = ac->GetContentNode();
     985             :     // We check to see if the anonymous content node has a frame. If it doesn't,
     986           0 :     // that means that's not visible to the user because e.g. it's display:none.
     987             :     // For now we assume that if it has a frame, it is visible. We might be able
     988           0 :     // to refine this further by adding complexity if it turns out this condition
     989             :     // results in a lot of false positives.
     990             :     if (elem && elem->GetPrimaryFrame()) {
     991             :       return true;
     992           0 :     }
     993             :   }
     994           0 :   return false;
     995           0 : }
     996             : 
     997             : bool
     998             : nsLayoutUtils::ShouldDisableApzForElement(nsIContent* aContent)
     999             : {
    1000             :   if (!aContent) {
    1001           0 :     return false;
    1002           0 :   }
    1003             : 
    1004             :   nsIDocument* doc = aContent->GetComposedDoc();
    1005           0 :   nsIPresShell* rootShell = APZCCallbackHelper::GetRootContentDocumentPresShellForContent(aContent);
    1006             :   if (rootShell) {
    1007             :     if (nsIDocument* rootDoc = rootShell->GetDocument()) {
    1008             :       nsIContent* rootContent = rootShell->GetRootScrollFrame()
    1009           0 :           ? rootShell->GetRootScrollFrame()->GetContent()
    1010             :           : rootDoc->GetDocumentElement();
    1011           0 :       // For the AccessibleCaret: disable APZ on any scrollable subframes that
    1012             :       // are not the root scrollframe of a document, if the document has any
    1013             :       // visible anonymous contents.
    1014             :       // If we find this is triggering in too many scenarios then we might
    1015           0 :       // want to tighten this check further. The main use cases for which we want
    1016           0 :       // to disable APZ as of this writing are listed in bug 1316318.
    1017           0 :       if (aContent != rootContent && HasVisibleAnonymousContents(rootDoc)) {
    1018           0 :         return true;
    1019           0 :       }
    1020           0 :     }
    1021           0 :   }
    1022             : 
    1023             :   if (!doc) {
    1024             :     return false;
    1025             :   }
    1026             :   return gfxPrefs::APZDisableForScrollLinkedEffects() &&
    1027             :          doc->HasScrollLinkedEffect();
    1028           0 : }
    1029             : 
    1030             : static bool
    1031             : GetDisplayPortData(nsIContent* aContent,
    1032             :                    DisplayPortPropertyData** aOutRectData,
    1033             :                    DisplayPortMarginsPropertyData** aOutMarginsData)
    1034           0 : {
    1035             :   MOZ_ASSERT(aOutRectData && aOutMarginsData);
    1036             : 
    1037           0 :   *aOutRectData =
    1038           0 :     static_cast<DisplayPortPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPort));
    1039             :   *aOutMarginsData =
    1040             :     static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
    1041             : 
    1042           0 :   if (!*aOutRectData && !*aOutMarginsData) {
    1043             :     // This content element has no displayport data at all
    1044             :     return false;
    1045             :   }
    1046           0 : 
    1047             :   if (*aOutRectData && *aOutMarginsData) {
    1048           0 :     // choose margins if equal priority
    1049           0 :     if ((*aOutRectData)->mPriority > (*aOutMarginsData)->mPriority) {
    1050           0 :       *aOutMarginsData = nullptr;
    1051           0 :     } else {
    1052             :       *aOutRectData = nullptr;
    1053           0 :     }
    1054             :   }
    1055             : 
    1056             :   NS_ASSERTION((*aOutRectData == nullptr) != (*aOutMarginsData == nullptr),
    1057             :                "Only one of aOutRectData or aOutMarginsData should be set!");
    1058           0 : 
    1059             :   return true;
    1060           0 : }
    1061           0 : 
    1062             : bool
    1063           0 : nsLayoutUtils::IsMissingDisplayPortBaseRect(nsIContent* aContent)
    1064             : {
    1065             :   DisplayPortPropertyData* rectData = nullptr;
    1066             :   DisplayPortMarginsPropertyData* marginsData = nullptr;
    1067           0 : 
    1068             :   if (GetDisplayPortData(aContent, &rectData, &marginsData) && marginsData) {
    1069             :     return !aContent->GetProperty(nsGkAtoms::DisplayPortBase);
    1070             :   }
    1071             : 
    1072             :   return false;
    1073             : }
    1074           0 : 
    1075             : enum class MaxSizeExceededBehaviour {
    1076           0 :   // Ask GetDisplayPortImpl to assert if the calculated displayport exceeds
    1077           0 :   // the maximum allowed size.
    1078             :   eAssert,
    1079           0 :   // Ask GetDisplayPortImpl to pretend like there's no displayport at all, if
    1080           0 :   // the calculated displayport exceeds the maximum allowed size.
    1081             :   eDrop,
    1082             : };
    1083             : 
    1084             : static bool
    1085             : GetDisplayPortImpl(nsIContent* aContent, nsRect* aResult, float aMultiplier,
    1086             :                    MaxSizeExceededBehaviour aBehaviour = MaxSizeExceededBehaviour::eAssert)
    1087             : {
    1088             :   DisplayPortPropertyData* rectData = nullptr;
    1089             :   DisplayPortMarginsPropertyData* marginsData = nullptr;
    1090             : 
    1091             :   if (!GetDisplayPortData(aContent, &rectData, &marginsData)) {
    1092             :     return false;
    1093             :   }
    1094             : 
    1095             :   if (!aResult) {
    1096           0 :     // We have displayport data, but the caller doesn't want the actual
    1097             :     // rect, so we don't need to actually compute it.
    1098             :     return true;
    1099           0 :   }
    1100           0 : 
    1101             :   nsRect result;
    1102           0 :   if (rectData) {
    1103             :     result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
    1104             :   } else if (APZCCallbackHelper::IsDisplayportSuppressed() ||
    1105             :       nsLayoutUtils::ShouldDisableApzForElement(aContent)) {
    1106           0 :     DisplayPortMarginsPropertyData noMargins(ScreenMargin(), 1);
    1107             :     result = GetDisplayPortFromMarginsData(aContent, &noMargins, aMultiplier);
    1108             :   } else {
    1109             :     result = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
    1110             :   }
    1111             : 
    1112           0 :   if (!gfxPrefs::LayersTilesEnabled()) {
    1113           0 :     // Perform the desired error handling if the displayport dimensions
    1114           0 :     // exceeds the maximum allowed size
    1115           0 :     nscoord maxSize = GetMaxDisplayPortSize(aContent, nullptr);
    1116           0 :     if (result.width > maxSize || result.height > maxSize) {
    1117           0 :       switch (aBehaviour) {
    1118           0 :       case MaxSizeExceededBehaviour::eAssert:
    1119             :         NS_ASSERTION(false, "Displayport must be a valid texture size");
    1120           0 :         break;
    1121             :       case MaxSizeExceededBehaviour::eDrop:
    1122             :         return false;
    1123           0 :       }
    1124             :     }
    1125             :   }
    1126           0 : 
    1127           0 :   *aResult = result;
    1128           0 :   return true;
    1129             : }
    1130           0 : 
    1131             : static void
    1132             : TranslateFromScrollPortToScrollFrame(nsIContent* aContent, nsRect* aRect)
    1133             : {
    1134             :   MOZ_ASSERT(aRect);
    1135             :   nsIFrame* frame = GetScrollFrameFromContent(aContent);
    1136             :   nsIScrollableFrame* scrollableFrame = frame ? frame->GetScrollTargetFrame() : nullptr;
    1137             :   if (scrollableFrame) {
    1138           0 :     *aRect += scrollableFrame->GetScrollPortRect().TopLeft();
    1139           0 :   }
    1140             : }
    1141             : 
    1142             : bool
    1143           0 : nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult,
    1144             :   RelativeTo aRelativeTo /* = RelativeTo::ScrollPort */)
    1145           0 : {
    1146           0 :   float multiplier =
    1147           0 :     gfxPrefs::UseLowPrecisionBuffer() ? 1.0f / gfxPrefs::LowPrecisionResolution() : 1.0f;
    1148           0 :   bool usingDisplayPort = GetDisplayPortImpl(aContent, aResult, multiplier);
    1149           0 :   if (aResult && usingDisplayPort && aRelativeTo == RelativeTo::ScrollFrame) {
    1150             :     TranslateFromScrollPortToScrollFrame(aContent, aResult);
    1151           0 :   }
    1152             :   return usingDisplayPort;
    1153             : }
    1154           0 : 
    1155             : bool
    1156             : nsLayoutUtils::HasDisplayPort(nsIContent* aContent) {
    1157             :   return GetDisplayPort(aContent, nullptr);
    1158           0 : }
    1159           0 : 
    1160           0 : /* static */ bool
    1161           0 : nsLayoutUtils::GetDisplayPortForVisibilityTesting(
    1162             :   nsIContent* aContent,
    1163           0 :   nsRect* aResult,
    1164             :   RelativeTo aRelativeTo /* = RelativeTo::ScrollPort */)
    1165             : {
    1166             :   MOZ_ASSERT(aResult);
    1167           0 :   // Since the base rect might not have been updated very recently, it's
    1168           0 :   // possible to end up with an extra-large displayport at this point, if the
    1169             :   // zoom level is changed by a lot. Instead of using the default behaviour of
    1170             :   // asserting, we can just ignore the displayport if that happens, as this
    1171             :   // call site is best-effort.
    1172           0 :   bool usingDisplayPort = GetDisplayPortImpl(aContent, aResult, 1.0f,
    1173             :       MaxSizeExceededBehaviour::eDrop);
    1174             :   if (usingDisplayPort && aRelativeTo == RelativeTo::ScrollFrame) {
    1175             :     TranslateFromScrollPortToScrollFrame(aContent, aResult);
    1176             :   }
    1177           0 :   return usingDisplayPort;
    1178             : }
    1179             : 
    1180             : void
    1181             : nsLayoutUtils::InvalidateForDisplayPortChange(nsIContent* aContent,
    1182             :                                               bool aHadDisplayPort,
    1183             :                                               const nsRect& aOldDisplayPort,
    1184           0 :                                               const nsRect& aNewDisplayPort,
    1185           0 :                                               RepaintMode aRepaintMode)
    1186           0 : {
    1187             :   if (aRepaintMode != RepaintMode::Repaint) {
    1188           0 :     return;
    1189             :   }
    1190             : 
    1191             :   bool changed = !aHadDisplayPort ||
    1192           0 :         !aOldDisplayPort.IsEqualEdges(aNewDisplayPort);
    1193             : 
    1194             :   nsIFrame* frame = GetScrollFrameFromContent(aContent);
    1195             :   if (frame) {
    1196             :     frame = do_QueryFrame(frame->GetScrollTargetFrame());
    1197             :   }
    1198           0 : 
    1199           0 :   if (changed && frame) {
    1200             :     // It is important to call SchedulePaint on the same frame that we set the dirty
    1201             :     // rect properties on so we can find the frame later to remove the properties.
    1202           0 :     frame->SchedulePaint();
    1203           0 : 
    1204             :     if (!nsLayoutUtils::AreRetainedDisplayListsEnabled()) {
    1205           0 :       return;
    1206           0 :     }
    1207           0 : 
    1208             :     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(frame);
    1209             :     RetainedDisplayListBuilder* retainedBuilder =
    1210           0 :       displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
    1211             : 
    1212             :     if (!retainedBuilder) {
    1213           0 :       return;
    1214             :     }
    1215           0 : 
    1216             :     nsRect* rect =
    1217             :       frame->GetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect());
    1218             : 
    1219           0 :     if (!rect) {
    1220             :       rect = new nsRect();
    1221           0 :       frame->SetProperty(nsDisplayListBuilder::DisplayListBuildingDisplayPortRect(), rect);
    1222             :       frame->SetHasOverrideDirtyRegion(true);
    1223           0 : 
    1224             :       nsIFrame* rootFrame = frame->PresContext()->PresShell()->GetRootFrame();
    1225             :       MOZ_ASSERT(rootFrame);
    1226             : 
    1227             :       nsTArray<nsIFrame*>* frames =
    1228           0 :         rootFrame->GetProperty(nsIFrame::OverriddenDirtyRectFrameList());
    1229             : 
    1230           0 :       if (!frames) {
    1231           0 :         frames = new nsTArray<nsIFrame*>();
    1232           0 :         rootFrame->SetProperty(nsIFrame::OverriddenDirtyRectFrameList(), frames);
    1233           0 :       }
    1234             : 
    1235           0 :       frames->AppendElement(frame);
    1236           0 :     }
    1237             : 
    1238             :     if (aHadDisplayPort) {
    1239           0 :       // We only need to build a display list for any new areas added
    1240             :       nsRegion newRegion(aNewDisplayPort);
    1241           0 :       newRegion.SubOut(aOldDisplayPort);
    1242           0 :       rect->UnionRect(*rect, newRegion.GetBounds());
    1243           0 :     } else {
    1244             :       rect->UnionRect(*rect, aNewDisplayPort);
    1245             :     }
    1246           0 :   }
    1247             : }
    1248             : 
    1249           0 : bool
    1250             : nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
    1251           0 :                                      nsIPresShell* aPresShell,
    1252           0 :                                      const ScreenMargin& aMargins,
    1253           0 :                                      uint32_t aPriority,
    1254             :                                      RepaintMode aRepaintMode)
    1255           0 : {
    1256             :   MOZ_ASSERT(aContent);
    1257             :   MOZ_ASSERT(aContent->GetComposedDoc() == aPresShell->GetDocument());
    1258             : 
    1259             :   DisplayPortMarginsPropertyData* currentData =
    1260             :     static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
    1261           0 :   if (currentData && currentData->mPriority > aPriority) {
    1262             :     return false;
    1263             :   }
    1264             : 
    1265             :   nsRect oldDisplayPort;
    1266             :   bool hadDisplayPort = GetHighResolutionDisplayPort(aContent, &oldDisplayPort);
    1267           0 : 
    1268           0 :   aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
    1269             :                         new DisplayPortMarginsPropertyData(
    1270             :                             aMargins, aPriority),
    1271           0 :                         nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
    1272           0 : 
    1273             :   nsRect newDisplayPort;
    1274             :   DebugOnly<bool> hasDisplayPort = GetHighResolutionDisplayPort(aContent, &newDisplayPort);
    1275             :   MOZ_ASSERT(hasDisplayPort);
    1276           0 : 
    1277           0 :   if (gfxPrefs::LayoutUseContainersForRootFrames()) {
    1278             :     nsIFrame* rootScrollFrame = aPresShell->GetRootScrollFrame();
    1279           0 :     if (rootScrollFrame &&
    1280             :         aContent == rootScrollFrame->GetContent() &&
    1281           0 :         nsLayoutUtils::UsesAsyncScrolling(rootScrollFrame))
    1282           0 :     {
    1283             :       // We are setting a root displayport for a document.
    1284           0 :       // If we have APZ, then set a special flag on the pres shell so
    1285           0 :       // that we don't get scrollbars drawn.
    1286           0 :       aPresShell->SetIgnoreViewportScrolling(true);
    1287             :     }
    1288           0 :   }
    1289           0 : 
    1290           0 :   InvalidateForDisplayPortChange(aContent, hadDisplayPort, oldDisplayPort,
    1291           0 :     newDisplayPort, aRepaintMode);
    1292           0 : 
    1293             :   nsIFrame* frame = GetScrollFrameFromContent(aContent);
    1294             :   nsIScrollableFrame* scrollableFrame = frame ? frame->GetScrollTargetFrame() : nullptr;
    1295             :   if (!scrollableFrame) {
    1296             :     return true;
    1297           0 :   }
    1298             : 
    1299             :   scrollableFrame->TriggerDisplayPortExpiration();
    1300             : 
    1301           0 :   // Display port margins changing means that the set of visible frames may
    1302           0 :   // have drastically changed. Check if we should schedule an update.
    1303             :   hadDisplayPort =
    1304           0 :     scrollableFrame->GetDisplayPortAtLastApproximateFrameVisibilityUpdate(&oldDisplayPort);
    1305           0 : 
    1306           0 :   bool needVisibilityUpdate = !hadDisplayPort;
    1307             :   // Check if the total size has changed by a large factor.
    1308             :   if (!needVisibilityUpdate) {
    1309             :     if ((newDisplayPort.width > 2 * oldDisplayPort.width) ||
    1310           0 :         (oldDisplayPort.width > 2 * newDisplayPort.width) ||
    1311             :         (newDisplayPort.height > 2 * oldDisplayPort.height) ||
    1312             :         (oldDisplayPort.height > 2 * newDisplayPort.height)) {
    1313             :       needVisibilityUpdate = true;
    1314             :     }
    1315           0 :   }
    1316             :   // Check if it's moved by a significant amount.
    1317           0 :   if (!needVisibilityUpdate) {
    1318             :     if (nsRect* baseData = static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase))) {
    1319           0 :       nsRect base = *baseData;
    1320           0 :       if ((std::abs(newDisplayPort.X() - oldDisplayPort.X()) > base.width) ||
    1321           0 :           (std::abs(newDisplayPort.XMost() - oldDisplayPort.XMost()) > base.width) ||
    1322           0 :           (std::abs(newDisplayPort.Y() - oldDisplayPort.Y()) > base.height) ||
    1323           0 :           (std::abs(newDisplayPort.YMost() - oldDisplayPort.YMost()) > base.height)) {
    1324           0 :         needVisibilityUpdate = true;
    1325             :       }
    1326             :     }
    1327             :   }
    1328           0 :   if (needVisibilityUpdate) {
    1329           0 :     aPresShell->ScheduleApproximateFrameVisibilityUpdateNow();
    1330           0 :   }
    1331           0 : 
    1332           0 :   return true;
    1333           0 : }
    1334           0 : 
    1335           0 : void
    1336             : nsLayoutUtils::SetDisplayPortBase(nsIContent* aContent, const nsRect& aBase)
    1337             : {
    1338             :   aContent->SetProperty(nsGkAtoms::DisplayPortBase, new nsRect(aBase),
    1339           0 :                         nsINode::DeleteProperty<nsRect>);
    1340           0 : }
    1341             : 
    1342             : void
    1343             : nsLayoutUtils::SetDisplayPortBaseIfNotSet(nsIContent* aContent, const nsRect& aBase)
    1344             : {
    1345             :   if (!aContent->GetProperty(nsGkAtoms::DisplayPortBase)) {
    1346             :     SetDisplayPortBase(aContent, aBase);
    1347           0 :   }
    1348             : }
    1349           0 : 
    1350           0 : bool
    1351           0 : nsLayoutUtils::GetCriticalDisplayPort(nsIContent* aContent, nsRect* aResult)
    1352             : {
    1353             :   if (gfxPrefs::UseLowPrecisionBuffer()) {
    1354           0 :     return GetDisplayPortImpl(aContent, aResult, 1.0f);
    1355             :   }
    1356           0 :   return false;
    1357           0 : }
    1358             : 
    1359           0 : bool
    1360             : nsLayoutUtils::HasCriticalDisplayPort(nsIContent* aContent)
    1361             : {
    1362           0 :   return GetCriticalDisplayPort(aContent, nullptr);
    1363             : }
    1364           0 : 
    1365           0 : bool
    1366             : nsLayoutUtils::GetHighResolutionDisplayPort(nsIContent* aContent, nsRect* aResult)
    1367             : {
    1368             :   if (gfxPrefs::UseLowPrecisionBuffer()) {
    1369             :     return GetCriticalDisplayPort(aContent, aResult);
    1370             :   }
    1371           0 :   return GetDisplayPort(aContent, aResult);
    1372             : }
    1373           0 : 
    1374             : void
    1375             : nsLayoutUtils::RemoveDisplayPort(nsIContent* aContent)
    1376             : {
    1377           0 :   aContent->DeleteProperty(nsGkAtoms::DisplayPort);
    1378             :   aContent->DeleteProperty(nsGkAtoms::DisplayPortMargins);
    1379           0 : }
    1380           0 : 
    1381             : nsContainerFrame*
    1382           0 : nsLayoutUtils::LastContinuationWithChild(nsContainerFrame* aFrame)
    1383             : {
    1384             :   MOZ_ASSERT(aFrame, "NULL frame pointer");
    1385             :   nsIFrame* f = aFrame->LastContinuation();
    1386           0 :   while (!f->PrincipalChildList().FirstChild() && f->GetPrevContinuation()) {
    1387             :     f = f->GetPrevContinuation();
    1388           0 :   }
    1389           0 :   return static_cast<nsContainerFrame*>(f);
    1390           0 : }
    1391             : 
    1392             : //static
    1393           0 : FrameChildListID
    1394             : nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
    1395           0 : {
    1396           0 :   nsIFrame::ChildListID id = nsIFrame::kPrincipalList;
    1397           0 : 
    1398           0 :   MOZ_DIAGNOSTIC_ASSERT(!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
    1399             : 
    1400           0 :   if (aChildFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
    1401             :     nsIFrame* pif = aChildFrame->GetPrevInFlow();
    1402             :     if (pif->GetParent() == aChildFrame->GetParent()) {
    1403             :       id = nsIFrame::kExcessOverflowContainersList;
    1404             :     }
    1405           0 :     else {
    1406             :       id = nsIFrame::kOverflowContainersList;
    1407           0 :     }
    1408             :   } else {
    1409           0 :     LayoutFrameType childType = aChildFrame->Type();
    1410             :     if (LayoutFrameType::MenuPopup == childType) {
    1411           0 :       nsIFrame* parent = aChildFrame->GetParent();
    1412           0 :       MOZ_ASSERT(parent, "nsMenuPopupFrame can't be the root frame");
    1413           0 :       if (parent) {
    1414             :         if (parent->IsPopupSetFrame()) {
    1415             :           id = nsIFrame::kPopupList;
    1416             :         } else {
    1417           0 :           nsIFrame* firstPopup = parent->GetChildList(nsIFrame::kPopupList).FirstChild();
    1418             :           MOZ_ASSERT(!firstPopup || !firstPopup->GetNextSibling(),
    1419             :                      "We assume popupList only has one child, but it has more.");
    1420           0 :           id = firstPopup == aChildFrame
    1421           0 :                  ? nsIFrame::kPopupList
    1422           0 :                  : nsIFrame::kPrincipalList;
    1423           0 :         }
    1424           0 :       } else {
    1425           0 :         id = nsIFrame::kPrincipalList;
    1426             :       }
    1427             :     } else if (LayoutFrameType::TableColGroup == childType) {
    1428           0 :       id = nsIFrame::kColGroupList;
    1429           0 :     } else if (aChildFrame->IsTableCaption()) {
    1430             :       id = nsIFrame::kCaptionList;
    1431             :     } else {
    1432           0 :       id = nsIFrame::kPrincipalList;
    1433             :     }
    1434             :   }
    1435             : 
    1436             : #ifdef DEBUG
    1437             :   // Verify that the frame is actually in that child list or in the
    1438           0 :   // corresponding overflow list.
    1439             :   nsContainerFrame* parent = aChildFrame->GetParent();
    1440           0 :   bool found = parent->GetChildList(id).ContainsFrame(aChildFrame);
    1441             :   if (!found) {
    1442             :     found = parent->GetChildList(nsIFrame::kOverflowList)
    1443           0 :               .ContainsFrame(aChildFrame);
    1444             :     MOZ_ASSERT(found, "not in child list");
    1445             :   }
    1446             : #endif
    1447             : 
    1448             :   return id;
    1449             : }
    1450           0 : 
    1451           0 : static Element*
    1452           0 : GetPseudo(const nsIContent* aContent, nsAtom* aPseudoProperty)
    1453           0 : {
    1454           0 :   MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
    1455           0 :              aPseudoProperty == nsGkAtoms::afterPseudoProperty);
    1456             :   if (!aContent->MayHaveAnonymousChildren()) {
    1457             :     return nullptr;
    1458             :   }
    1459           0 :   return static_cast<Element*>(aContent->GetProperty(aPseudoProperty));
    1460             : }
    1461             : 
    1462             : /*static*/ Element*
    1463           0 : nsLayoutUtils::GetBeforePseudo(const nsIContent* aContent)
    1464             : {
    1465           0 :   return GetPseudo(aContent, nsGkAtoms::beforePseudoProperty);
    1466             : }
    1467           0 : 
    1468             : /*static*/ nsIFrame*
    1469             : nsLayoutUtils::GetBeforeFrame(const nsIContent* aContent)
    1470           0 : {
    1471             :   Element* pseudo = GetBeforePseudo(aContent);
    1472             :   return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
    1473             : }
    1474           0 : 
    1475             : /*static*/ Element*
    1476           0 : nsLayoutUtils::GetAfterPseudo(const nsIContent* aContent)
    1477             : {
    1478             :   return GetPseudo(aContent, nsGkAtoms::afterPseudoProperty);
    1479             : }
    1480           0 : 
    1481             : /*static*/ nsIFrame*
    1482           0 : nsLayoutUtils::GetAfterFrame(const nsIContent* aContent)
    1483           0 : {
    1484             :   Element* pseudo = GetAfterPseudo(aContent);
    1485             :   return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
    1486             : }
    1487           0 : 
    1488             : // static
    1489           0 : nsIFrame*
    1490             : nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame,
    1491             :                                      LayoutFrameType aFrameType,
    1492             :                                      nsIFrame* aStopAt)
    1493           0 : {
    1494             :   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
    1495           0 :     if (frame->Type() == aFrameType) {
    1496           0 :       return frame;
    1497             :     }
    1498             :     if (frame == aStopAt) {
    1499             :       break;
    1500             :     }
    1501           0 :   }
    1502             :   return nullptr;
    1503             : }
    1504             : 
    1505           0 : /* static */ nsIFrame*
    1506           0 : nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
    1507             : {
    1508             :   return GetClosestFrameOfType(aFrame, LayoutFrameType::Page);
    1509           0 : }
    1510             : 
    1511             : // static
    1512             : nsIFrame*
    1513             : nsLayoutUtils::GetStyleFrame(nsIFrame* aFrame)
    1514             : {
    1515             :   if (aFrame->IsTableWrapperFrame()) {
    1516             :     nsIFrame* inner = aFrame->PrincipalChildList().FirstChild();
    1517           0 :     // inner may be null, if aFrame is mid-destruction
    1518             :     return inner;
    1519           0 :   }
    1520             : 
    1521             :   return aFrame;
    1522             : }
    1523             : 
    1524           0 : nsIFrame*
    1525             : nsLayoutUtils::GetStyleFrame(const nsIContent* aContent)
    1526           0 : {
    1527           0 :   nsIFrame *frame = aContent->GetPrimaryFrame();
    1528             :   if (!frame) {
    1529           0 :     return nullptr;
    1530             :   }
    1531             : 
    1532             :   return nsLayoutUtils::GetStyleFrame(frame);
    1533             : }
    1534             : 
    1535             : /* static */ nsIFrame*
    1536           0 : nsLayoutUtils::GetRealPrimaryFrameFor(const nsIContent* aContent)
    1537             : {
    1538           0 :   nsIFrame *frame = aContent->GetPrimaryFrame();
    1539           0 :   if (!frame) {
    1540             :     return nullptr;
    1541             :   }
    1542             : 
    1543           0 :   return nsPlaceholderFrame::GetRealFrameFor(frame);
    1544             : }
    1545             : 
    1546             : nsIFrame*
    1547           0 : nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
    1548             :   NS_ASSERTION(aFrame->IsPlaceholderFrame(), "Must have a placeholder here");
    1549           0 :   if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
    1550           0 :     nsIFrame *outOfFlowFrame =
    1551             :       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
    1552             :     NS_ASSERTION(outOfFlowFrame && outOfFlowFrame->IsFloating(),
    1553             :                  "How did that happen?");
    1554           0 :     return outOfFlowFrame;
    1555             :   }
    1556             : 
    1557             :   return nullptr;
    1558           0 : }
    1559           0 : 
    1560           0 : // static
    1561             : nsIFrame*
    1562           0 : nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
    1563           0 :                                       nsPoint* aExtraOffset)
    1564             : {
    1565             :   nsIFrame* p = aFrame->GetParent();
    1566             :   if (p)
    1567             :     return p;
    1568             : 
    1569             :   nsView* v = aFrame->GetView();
    1570             :   if (!v)
    1571             :     return nullptr;
    1572             :   v = v->GetParent(); // anonymous inner view
    1573           0 :   if (!v)
    1574             :     return nullptr;
    1575             :   if (aExtraOffset) {
    1576           0 :     *aExtraOffset += v->GetPosition();
    1577           0 :   }
    1578             :   v = v->GetParent(); // subdocumentframe's view
    1579             :   return v ? v->GetFrame() : nullptr;
    1580           0 : }
    1581           0 : 
    1582             : // static
    1583           0 : bool
    1584           0 : nsLayoutUtils::IsProperAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
    1585             :                                              nsIFrame* aCommonAncestor)
    1586           0 : {
    1587           0 :   if (aFrame == aAncestorFrame)
    1588             :     return false;
    1589           0 :   return IsAncestorFrameCrossDoc(aAncestorFrame, aFrame, aCommonAncestor);
    1590           0 : }
    1591             : 
    1592             : // static
    1593             : bool
    1594             : nsLayoutUtils::IsAncestorFrameCrossDoc(const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
    1595           0 :                                        const nsIFrame* aCommonAncestor)
    1596             : {
    1597             :   for (const nsIFrame* f = aFrame; f != aCommonAncestor;
    1598           0 :        f = GetCrossDocParentFrame(f)) {
    1599             :     if (f == aAncestorFrame)
    1600           0 :       return true;
    1601             :   }
    1602             :   return aCommonAncestor == aAncestorFrame;
    1603             : }
    1604             : 
    1605           0 : // static
    1606             : bool
    1607             : nsLayoutUtils::IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
    1608           0 :                                      nsIFrame* aCommonAncestor)
    1609             : {
    1610           0 :   if (aFrame == aAncestorFrame)
    1611             :     return false;
    1612             :   for (nsIFrame* f = aFrame; f != aCommonAncestor; f = f->GetParent()) {
    1613           0 :     if (f == aAncestorFrame)
    1614             :       return true;
    1615             :   }
    1616             :   return aCommonAncestor == aAncestorFrame;
    1617             : }
    1618           0 : 
    1619             : // static
    1620             : int32_t
    1621           0 : nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
    1622             :                                      nsIContent* aContent2,
    1623           0 :                                      int32_t aIf1Ancestor,
    1624           0 :                                      int32_t aIf2Ancestor,
    1625             :                                      const nsIContent* aCommonAncestor)
    1626             : {
    1627           0 :   MOZ_ASSERT(aContent1, "aContent1 must not be null");
    1628             :   MOZ_ASSERT(aContent2, "aContent2 must not be null");
    1629             : 
    1630             :   AutoTArray<nsINode*, 32> content1Ancestors;
    1631             :   nsINode* c1;
    1632           0 :   for (c1 = aContent1;
    1633             :        c1 && c1 != aCommonAncestor;
    1634             :        c1 = c1->GetParentOrHostNode()) {
    1635             :     content1Ancestors.AppendElement(c1);
    1636             :   }
    1637             :   if (!c1 && aCommonAncestor) {
    1638           0 :     // So, it turns out aCommonAncestor was not an ancestor of c1. Oops.
    1639           0 :     // Never mind. We can continue as if aCommonAncestor was null.
    1640             :     aCommonAncestor = nullptr;
    1641           0 :   }
    1642             : 
    1643           0 :   AutoTArray<nsINode*, 32> content2Ancestors;
    1644           0 :   nsINode* c2;
    1645           0 :   for (c2 = aContent2;
    1646           0 :        c2 && c2 != aCommonAncestor;
    1647             :        c2 = c2->GetParentOrHostNode()) {
    1648           0 :     content2Ancestors.AppendElement(c2);
    1649             :   }
    1650             :   if (!c2 && aCommonAncestor) {
    1651           0 :     // So, it turns out aCommonAncestor was not an ancestor of c2.
    1652             :     // We need to retry with no common ancestor hint.
    1653             :     return DoCompareTreePosition(aContent1, aContent2,
    1654           0 :                                  aIf1Ancestor, aIf2Ancestor, nullptr);
    1655             :   }
    1656           0 : 
    1657           0 :   int last1 = content1Ancestors.Length() - 1;
    1658           0 :   int last2 = content2Ancestors.Length() - 1;
    1659           0 :   nsINode* content1Ancestor = nullptr;
    1660             :   nsINode* content2Ancestor = nullptr;
    1661           0 :   while (last1 >= 0 && last2 >= 0
    1662             :          && ((content1Ancestor = content1Ancestors.ElementAt(last1)) ==
    1663             :              (content2Ancestor = content2Ancestors.ElementAt(last2)))) {
    1664             :     last1--;
    1665           0 :     last2--;
    1666             :   }
    1667             : 
    1668           0 :   if (last1 < 0) {
    1669           0 :     if (last2 < 0) {
    1670           0 :       NS_ASSERTION(aContent1 == aContent2, "internal error?");
    1671           0 :       return 0;
    1672           0 :     }
    1673           0 :     // aContent1 is an ancestor of aContent2
    1674           0 :     return aIf1Ancestor;
    1675           0 :   }
    1676           0 : 
    1677             :   if (last2 < 0) {
    1678             :     // aContent2 is an ancestor of aContent1
    1679           0 :     return aIf2Ancestor;
    1680           0 :   }
    1681           0 : 
    1682             :   // content1Ancestor != content2Ancestor, so they must be siblings with the same parent
    1683             :   nsINode* parent = content1Ancestor->GetParentOrHostNode();
    1684             : #ifdef DEBUG
    1685             :   // TODO: remove the uglyness, see bug 598468.
    1686             :   NS_ASSERTION(gPreventAssertInCompareTreePosition || parent,
    1687             :                "no common ancestor at all???");
    1688           0 : #endif // DEBUG
    1689             :   if (!parent) { // different documents??
    1690             :     return 0;
    1691             :   }
    1692             : 
    1693             :   int32_t index1 = parent->ComputeIndexOf(content1Ancestor);
    1694           0 :   int32_t index2 = parent->ComputeIndexOf(content2Ancestor);
    1695             :   if (index1 < 0 || index2 < 0) {
    1696             :     // one of them must be anonymous; we can't determine the order
    1697           0 :     return 0;
    1698             :   }
    1699             : 
    1700           0 :   return index1 - index2;
    1701             : }
    1702             : 
    1703             : // static
    1704           0 : nsIFrame*
    1705           0 : nsLayoutUtils::FillAncestors(nsIFrame* aFrame,
    1706           0 :                              nsIFrame* aStopAtAncestor,
    1707             :                              nsTArray<nsIFrame*>* aAncestors)
    1708             : {
    1709             :   while (aFrame && aFrame != aStopAtAncestor) {
    1710             :     aAncestors->AppendElement(aFrame);
    1711           0 :     aFrame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
    1712             :   }
    1713             :   return aFrame;
    1714             : }
    1715             : 
    1716           0 : // Return true if aFrame1 is after aFrame2
    1717             : static bool IsFrameAfter(nsIFrame* aFrame1, nsIFrame* aFrame2)
    1718             : {
    1719             :   nsIFrame* f = aFrame2;
    1720           0 :   do {
    1721           0 :     f = f->GetNextSibling();
    1722           0 :     if (f == aFrame1)
    1723             :       return true;
    1724           0 :   } while (f);
    1725             :   return false;
    1726             : }
    1727             : 
    1728           0 : // static
    1729             : int32_t
    1730           0 : nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
    1731             :                                      nsIFrame* aFrame2,
    1732           0 :                                      int32_t aIf1Ancestor,
    1733           0 :                                      int32_t aIf2Ancestor,
    1734             :                                      nsIFrame* aCommonAncestor)
    1735           0 : {
    1736             :   MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
    1737             :   MOZ_ASSERT(aFrame2, "aFrame2 must not be null");
    1738             : 
    1739             :   AutoTArray<nsIFrame*,20> frame2Ancestors;
    1740             :   nsIFrame* nonCommonAncestor =
    1741           0 :     FillAncestors(aFrame2, aCommonAncestor, &frame2Ancestors);
    1742             : 
    1743             :   return DoCompareTreePosition(aFrame1, aFrame2, frame2Ancestors,
    1744             :                                aIf1Ancestor, aIf2Ancestor,
    1745             :                                nonCommonAncestor ? aCommonAncestor : nullptr);
    1746             : }
    1747           0 : 
    1748           0 : // static
    1749             : int32_t
    1750           0 : nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
    1751             :                                      nsIFrame* aFrame2,
    1752           0 :                                      nsTArray<nsIFrame*>& aFrame2Ancestors,
    1753             :                                      int32_t aIf1Ancestor,
    1754           0 :                                      int32_t aIf2Ancestor,
    1755             :                                      nsIFrame* aCommonAncestor)
    1756           0 : {
    1757             :   MOZ_ASSERT(aFrame1, "aFrame1 must not be null");
    1758             :   MOZ_ASSERT(aFrame2, "aFrame2 must not be null");
    1759             : 
    1760             :   nsPresContext* presContext = aFrame1->PresContext();
    1761           0 :   if (presContext != aFrame2->PresContext()) {
    1762             :     NS_ERROR("no common ancestor at all, different documents");
    1763             :     return 0;
    1764             :   }
    1765             : 
    1766             :   AutoTArray<nsIFrame*,20> frame1Ancestors;
    1767             :   if (aCommonAncestor &&
    1768           0 :       !FillAncestors(aFrame1, aCommonAncestor, &frame1Ancestors)) {
    1769           0 :     // We reached the root of the frame tree ... if aCommonAncestor was set,
    1770             :     // it is wrong
    1771           0 :     return DoCompareTreePosition(aFrame1, aFrame2,
    1772           0 :                                  aIf1Ancestor, aIf2Ancestor, nullptr);
    1773           0 :   }
    1774           0 : 
    1775             :   int32_t last1 = int32_t(frame1Ancestors.Length()) - 1;
    1776             :   int32_t last2 = int32_t(aFrame2Ancestors.Length()) - 1;
    1777           0 :   while (last1 >= 0 && last2 >= 0 &&
    1778           0 :          frame1Ancestors[last1] == aFrame2Ancestors[last2]) {
    1779           0 :     last1--;
    1780             :     last2--;
    1781             :   }
    1782             : 
    1783           0 :   if (last1 < 0) {
    1784             :     if (last2 < 0) {
    1785             :       NS_ASSERTION(aFrame1 == aFrame2, "internal error?");
    1786           0 :       return 0;
    1787           0 :     }
    1788           0 :     // aFrame1 is an ancestor of aFrame2
    1789           0 :     return aIf1Ancestor;
    1790           0 :   }
    1791           0 : 
    1792             :   if (last2 < 0) {
    1793             :     // aFrame2 is an ancestor of aFrame1
    1794           0 :     return aIf2Ancestor;
    1795           0 :   }
    1796           0 : 
    1797             :   nsIFrame* ancestor1 = frame1Ancestors[last1];
    1798             :   nsIFrame* ancestor2 = aFrame2Ancestors[last2];
    1799             :   // Now we should be able to walk sibling chains to find which one is first
    1800             :   if (IsFrameAfter(ancestor2, ancestor1))
    1801             :     return -1;
    1802             :   if (IsFrameAfter(ancestor1, ancestor2))
    1803           0 :     return 1;
    1804             :   NS_WARNING("Frames were in different child lists???");
    1805             :   return 0;
    1806             : }
    1807             : 
    1808           0 : // static
    1809           0 : nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) {
    1810             :   if (!aFrame) {
    1811           0 :     return nullptr;
    1812             :   }
    1813           0 : 
    1814             :   nsIFrame* next;
    1815           0 :   while ((next = aFrame->GetNextSibling()) != nullptr) {
    1816           0 :     aFrame = next;
    1817             :   }
    1818             :   return aFrame;
    1819             : }
    1820           0 : 
    1821           0 : // static
    1822             : nsView*
    1823             : nsLayoutUtils::FindSiblingViewFor(nsView* aParentView, nsIFrame* aFrame) {
    1824             :   nsIFrame* parentViewFrame = aParentView->GetFrame();
    1825             :   nsIContent* parentViewContent = parentViewFrame ? parentViewFrame->GetContent() : nullptr;
    1826           0 :   for (nsView* insertBefore = aParentView->GetFirstChild(); insertBefore;
    1827             :        insertBefore = insertBefore->GetNextSibling()) {
    1828             :     nsIFrame* f = insertBefore->GetFrame();
    1829             :     if (!f) {
    1830             :       // this view could be some anonymous view attached to a meaningful parent
    1831             :       for (nsView* searchView = insertBefore->GetParent(); searchView;
    1832             :            searchView = searchView->GetParent()) {
    1833             :         f = searchView->GetFrame();
    1834           0 :         if (f) {
    1835           0 :           break;
    1836           0 :         }
    1837           0 :       }
    1838             :       NS_ASSERTION(f, "Can't find a frame anywhere!");
    1839           0 :     }
    1840           0 :     if (!f || !aFrame->GetContent() || !f->GetContent() ||
    1841             :         CompareTreePosition(aFrame->GetContent(), f->GetContent(), parentViewContent) > 0) {
    1842           0 :       // aFrame's content is after f's content (or we just don't know),
    1843             :       // so put our view before f's view
    1844           0 :       return insertBefore;
    1845           0 :     }
    1846             :   }
    1847             :   return nullptr;
    1848             : }
    1849           0 : 
    1850             : //static
    1851           0 : nsIScrollableFrame*
    1852           0 : nsLayoutUtils::GetScrollableFrameFor(const nsIFrame *aScrolledFrame)
    1853             : {
    1854             :   nsIFrame *frame = aScrolledFrame->GetParent();
    1855             :   nsIScrollableFrame *sf = do_QueryFrame(frame);
    1856             :   return (sf && sf->GetScrolledFrame() == aScrolledFrame) ? sf : nullptr;
    1857             : }
    1858             : 
    1859             : /* static */ void
    1860             : nsLayoutUtils::SetFixedPositionLayerData(Layer* aLayer,
    1861             :                                          const nsIFrame* aViewportFrame,
    1862             :                                          const nsRect& aAnchorRect,
    1863           0 :                                          const nsIFrame* aFixedPosFrame,
    1864             :                                          nsPresContext* aPresContext,
    1865           0 :                                          const ContainerLayerParameters& aContainerParameters) {
    1866           0 :   // Find out the rect of the viewport frame relative to the reference frame.
    1867           0 :   // This, in conjunction with the container scale, will correspond to the
    1868             :   // coordinate-space of the built layer.
    1869             :   float factor = aPresContext->AppUnitsPerDevPixel();
    1870             :   Rect anchorRect(NSAppUnitsToFloatPixels(aAnchorRect.x, factor) *
    1871           0 :                     aContainerParameters.mXScale,
    1872             :                   NSAppUnitsToFloatPixels(aAnchorRect.y, factor) *
    1873             :                     aContainerParameters.mYScale,
    1874             :                   NSAppUnitsToFloatPixels(aAnchorRect.width, factor) *
    1875             :                     aContainerParameters.mXScale,
    1876             :                   NSAppUnitsToFloatPixels(aAnchorRect.height, factor) *
    1877             :                     aContainerParameters.mYScale);
    1878             :   // Need to transform anchorRect from the container layer's coordinate system
    1879             :   // into aLayer's coordinate system.
    1880           0 :   Matrix transform2d;
    1881           0 :   if (aLayer->GetTransform().Is2D(&transform2d)) {
    1882             :     transform2d.Invert();
    1883           0 :     anchorRect = transform2d.TransformBounds(anchorRect);
    1884             :   } else {
    1885           0 :     NS_ERROR("3D transform found between fixedpos content and its viewport (should never happen)");
    1886           0 :     anchorRect = Rect(0,0,0,0);
    1887           0 :   }
    1888           0 : 
    1889             :   // Work out the anchor point for this fixed position layer. We assume that
    1890             :   // any positioning set (left/top/right/bottom) indicates that the
    1891           0 :   // corresponding side of its container should be the anchor point,
    1892           0 :   // defaulting to top-left.
    1893           0 :   LayerPoint anchor(anchorRect.x, anchorRect.y);
    1894           0 : 
    1895             :   int32_t sides = eSideBitsNone;
    1896           0 :   if (aFixedPosFrame != aViewportFrame) {
    1897           0 :     const nsStylePosition* position = aFixedPosFrame->StylePosition();
    1898             :     if (position->mOffset.GetRightUnit() != eStyleUnit_Auto) {
    1899             :       sides |= eSideBitsRight;
    1900             :       if (position->mOffset.GetLeftUnit() != eStyleUnit_Auto) {
    1901             :         sides |= eSideBitsLeft;
    1902             :         anchor.x = anchorRect.x + anchorRect.width / 2.f;
    1903             :       } else {
    1904           0 :         anchor.x = anchorRect.XMost();
    1905             :       }
    1906           0 :     } else if (position->mOffset.GetLeftUnit() != eStyleUnit_Auto) {
    1907           0 :       sides |= eSideBitsLeft;
    1908           0 :     }
    1909           0 :     if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto) {
    1910           0 :       sides |= eSideBitsBottom;
    1911           0 :       if (position->mOffset.GetTopUnit() != eStyleUnit_Auto) {
    1912           0 :         sides |= eSideBitsTop;
    1913           0 :         anchor.y = anchorRect.y + anchorRect.height / 2.f;
    1914             :       } else {
    1915           0 :         anchor.y = anchorRect.YMost();
    1916             :       }
    1917           0 :     } else if (position->mOffset.GetTopUnit() != eStyleUnit_Auto) {
    1918           0 :       sides |= eSideBitsTop;
    1919             :     }
    1920           0 :   }
    1921           0 : 
    1922           0 :   ViewID id = ScrollIdForRootScrollFrame(aPresContext);
    1923           0 :   aLayer->SetFixedPositionData(id, anchor, sides);
    1924           0 : }
    1925             : 
    1926           0 : FrameMetrics::ViewID
    1927             : nsLayoutUtils::ScrollIdForRootScrollFrame(nsPresContext* aPresContext)
    1928           0 : {
    1929           0 :   ViewID id = FrameMetrics::NULL_SCROLL_ID;
    1930             :   if (nsIFrame* rootScrollFrame = aPresContext->PresShell()->GetRootScrollFrame()) {
    1931             :     if (nsIContent* content = rootScrollFrame->GetContent()) {
    1932             :       id = FindOrCreateIDFor(content);
    1933           0 :     }
    1934           0 :   }
    1935           0 :   return id;
    1936             : }
    1937             : 
    1938           0 : bool
    1939             : nsLayoutUtils::ViewportHasDisplayPort(nsPresContext* aPresContext)
    1940           0 : {
    1941           0 :   nsIFrame* rootScrollFrame =
    1942           0 :     aPresContext->PresShell()->GetRootScrollFrame();
    1943           0 :   return rootScrollFrame &&
    1944             :     nsLayoutUtils::HasDisplayPort(rootScrollFrame->GetContent());
    1945             : }
    1946           0 : 
    1947             : bool
    1948             : nsLayoutUtils::IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame)
    1949             : {
    1950           0 :   // Fixed-pos frames are parented by the viewport frame or the page content frame.
    1951             :   // We'll assume that printing/print preview don't have displayports for their
    1952             :   // pages!
    1953           0 :   nsIFrame* parent = aFrame->GetParent();
    1954           0 :   if (!parent || parent->GetParent() ||
    1955           0 :       aFrame->StyleDisplay()->mPosition != NS_STYLE_POSITION_FIXED) {
    1956             :     return false;
    1957             :   }
    1958             :   return ViewportHasDisplayPort(aFrame->PresContext());
    1959           0 : }
    1960             : 
    1961             : // static
    1962             : nsIScrollableFrame*
    1963             : nsLayoutUtils::GetNearestScrollableFrameForDirection(nsIFrame* aFrame,
    1964           0 :                                                      Direction aDirection)
    1965           0 : {
    1966           0 :   NS_ASSERTION(aFrame, "GetNearestScrollableFrameForDirection expects a non-null frame");
    1967             :   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    1968             :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
    1969           0 :     if (scrollableFrame) {
    1970             :       ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
    1971             :       uint32_t directions = scrollableFrame->GetPerceivedScrollingDirections();
    1972             :       if (aDirection == eVertical ?
    1973             :           (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
    1974           0 :            (directions & nsIScrollableFrame::VERTICAL)) :
    1975             :           (ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
    1976             :            (directions & nsIScrollableFrame::HORIZONTAL)))
    1977           0 :         return scrollableFrame;
    1978           0 :     }
    1979           0 :   }
    1980           0 :   return nullptr;
    1981           0 : }
    1982           0 : 
    1983           0 : // static
    1984           0 : nsIScrollableFrame*
    1985           0 : nsLayoutUtils::GetNearestScrollableFrame(nsIFrame* aFrame, uint32_t aFlags)
    1986           0 : {
    1987           0 :   NS_ASSERTION(aFrame, "GetNearestScrollableFrame expects a non-null frame");
    1988           0 :   for (nsIFrame* f = aFrame; f; f = (aFlags & SCROLLABLE_SAME_DOC) ?
    1989             :        f->GetParent() : nsLayoutUtils::GetCrossDocParentFrame(f)) {
    1990             :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
    1991             :     if (scrollableFrame) {
    1992             :       if (aFlags & SCROLLABLE_ONLY_ASYNC_SCROLLABLE) {
    1993             :         if (scrollableFrame->WantAsyncScroll()) {
    1994             :           return scrollableFrame;
    1995             :         }
    1996           0 :       } else {
    1997             :         ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
    1998           0 :         if ((aFlags & SCROLLABLE_INCLUDE_HIDDEN) ||
    1999           0 :             ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN ||
    2000             :             ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) {
    2001           0 :           return scrollableFrame;
    2002           0 :         }
    2003           0 :       }
    2004           0 :       if (aFlags & SCROLLABLE_ALWAYS_MATCH_ROOT) {
    2005             :         nsIPresShell* ps = f->PresShell();
    2006             :         if (ps->GetRootScrollFrame() == f &&
    2007             :             ps->GetDocument() && ps->GetDocument()->IsRootDisplayDocument()) {
    2008           0 :           return scrollableFrame;
    2009           0 :         }
    2010           0 :       }
    2011             :     }
    2012           0 :     if ((aFlags & SCROLLABLE_FIXEDPOS_FINDS_ROOT) &&
    2013             :         f->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
    2014             :         nsLayoutUtils::IsReallyFixedPos(f)) {
    2015           0 :       return f->PresShell()->GetRootScrollFrameAsScrollable();
    2016           0 :     }
    2017           0 :   }
    2018           0 :   return nullptr;
    2019             : }
    2020             : 
    2021             : // static
    2022             : nsRect
    2023           0 : nsLayoutUtils::GetScrolledRect(nsIFrame* aScrolledFrame,
    2024           0 :                                const nsRect& aScrolledFrameOverflowArea,
    2025           0 :                                const nsSize& aScrollPortSize,
    2026           0 :                                uint8_t aDirection)
    2027             : {
    2028             :   WritingMode wm = aScrolledFrame->GetWritingMode();
    2029             :   // Potentially override the frame's direction to use the direction found
    2030             :   // by ScrollFrameHelper::GetScrolledFrameDir()
    2031             :   wm.SetDirectionFromBidiLevel(aDirection == NS_STYLE_DIRECTION_RTL ? 1 : 0);
    2032             : 
    2033             :   nscoord x1 = aScrolledFrameOverflowArea.x,
    2034           0 :           x2 = aScrolledFrameOverflowArea.XMost(),
    2035             :           y1 = aScrolledFrameOverflowArea.y,
    2036             :           y2 = aScrolledFrameOverflowArea.YMost();
    2037             : 
    2038             :   bool horizontal = !wm.IsVertical();
    2039           0 : 
    2040             :   // Clamp the horizontal start-edge (x1 or x2, depending whether the logical
    2041             :   // axis that corresponds to horizontal progresses from L-R or R-L).
    2042           0 :   // In horizontal writing mode, we need to check IsInlineReversed() to see
    2043             :   // which side to clamp; in vertical mode, it depends on the block direction.
    2044           0 :   if ((horizontal && !wm.IsInlineReversed()) || wm.IsVerticalLR()) {
    2045           0 :     if (x1 < 0) {
    2046           0 :       x1 = 0;
    2047           0 :     }
    2048             :   } else {
    2049           0 :     if (x2 > aScrollPortSize.width) {
    2050             :       x2 = aScrollPortSize.width;
    2051             :     }
    2052             :     // When the scrolled frame chooses a size larger than its available width
    2053             :     // (because its padding alone is larger than the available width), we need
    2054             :     // to keep the start-edge of the scroll frame anchored to the start-edge of
    2055           0 :     // the scrollport.
    2056           0 :     // When the scrolled frame is RTL, this means moving it in our left-based
    2057           0 :     // coordinate system, so we need to compensate for its extra width here by
    2058             :     // effectively repositioning the frame.
    2059             :     nscoord extraWidth =
    2060           0 :       std::max(0, aScrolledFrame->GetSize().width - aScrollPortSize.width);
    2061           0 :     x2 += extraWidth;
    2062             :   }
    2063             : 
    2064             :   // Similarly, clamp the vertical start-edge.
    2065             :   // In horizontal writing mode, the block direction is always top-to-bottom;
    2066             :   // in vertical writing mode, we need to check IsInlineReversed().
    2067             :   if (horizontal || !wm.IsInlineReversed()) {
    2068             :     if (y1 < 0) {
    2069             :       y1 = 0;
    2070             :     }
    2071           0 :   } else {
    2072           0 :     if (y2 > aScrollPortSize.height) {
    2073             :       y2 = aScrollPortSize.height;
    2074             :     }
    2075             :     nscoord extraHeight =
    2076             :       std::max(0, aScrolledFrame->GetSize().height - aScrollPortSize.height);
    2077             :     y2 += extraHeight;
    2078           0 :   }
    2079           0 : 
    2080           0 :   return nsRect(x1, y1, x2 - x1, y2 - y1);
    2081             : }
    2082             : 
    2083           0 : //static
    2084           0 : bool
    2085             : nsLayoutUtils::HasPseudoStyle(nsIContent* aContent,
    2086             :                               ComputedStyle* aComputedStyle,
    2087           0 :                               CSSPseudoElementType aPseudoElement,
    2088           0 :                               nsPresContext* aPresContext)
    2089             : {
    2090             :   MOZ_ASSERT(aPresContext, "Must have a prescontext");
    2091           0 : 
    2092             :   RefPtr<ComputedStyle> pseudoContext;
    2093             :   if (aContent) {
    2094             :     pseudoContext = aPresContext->StyleSet()->
    2095             :       ProbePseudoElementStyle(aContent->AsElement(), aPseudoElement,
    2096           0 :                               aComputedStyle);
    2097             :   }
    2098             :   return pseudoContext != nullptr;
    2099             : }
    2100             : 
    2101           0 : nsPoint
    2102             : nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(Event* aDOMEvent, nsIFrame* aFrame)
    2103           0 : {
    2104           0 :   if (!aDOMEvent)
    2105             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2106           0 :   WidgetEvent* event = aDOMEvent->WidgetEventPtr();
    2107           0 :   if (!event)
    2108             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2109           0 :   return GetEventCoordinatesRelativeTo(event, aFrame);
    2110             : }
    2111             : 
    2112             : nsPoint
    2113           0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
    2114             :                                              nsIFrame* aFrame)
    2115           0 : {
    2116             :   if (!aEvent || (aEvent->mClass != eMouseEventClass &&
    2117           0 :                   aEvent->mClass != eMouseScrollEventClass &&
    2118           0 :                   aEvent->mClass != eWheelEventClass &&
    2119             :                   aEvent->mClass != eDragEventClass &&
    2120           0 :                   aEvent->mClass != eSimpleGestureEventClass &&
    2121             :                   aEvent->mClass != ePointerEventClass &&
    2122             :                   aEvent->mClass != eGestureNotifyEventClass &&
    2123             :                   aEvent->mClass != eTouchEventClass &&
    2124           0 :                   aEvent->mClass != eQueryContentEventClass))
    2125             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2126             : 
    2127           0 :   return GetEventCoordinatesRelativeTo(aEvent,
    2128           0 :            aEvent->AsGUIEvent()->mRefPoint,
    2129           0 :            aFrame);
    2130           0 : }
    2131           0 : 
    2132           0 : nsPoint
    2133           0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
    2134           0 :                                              const LayoutDeviceIntPoint& aPoint,
    2135             :                                              nsIFrame* aFrame)
    2136             : {
    2137             :   if (!aFrame) {
    2138             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2139           0 :   }
    2140           0 : 
    2141             :   nsIWidget* widget = aEvent->AsGUIEvent()->mWidget;
    2142             :   if (!widget) {
    2143             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2144           0 :   }
    2145             : 
    2146             :   return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
    2147             : }
    2148           0 : 
    2149             : nsPoint
    2150             : nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
    2151             :                                              const LayoutDeviceIntPoint& aPoint,
    2152           0 :                                              nsIFrame* aFrame)
    2153           0 : {
    2154             :   if (!aFrame || !aWidget) {
    2155             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2156             :   }
    2157           0 : 
    2158             :   nsView* view = aFrame->GetView();
    2159             :   if (view) {
    2160             :     nsIWidget* frameWidget = view->GetWidget();
    2161           0 :     if (frameWidget && frameWidget == aWidget) {
    2162             :       // Special case this cause it happens a lot.
    2163             :       // This also fixes bug 664707, events in the extra-special case of select
    2164             :       // dropdown popups that are transformed.
    2165           0 :       nsPresContext* presContext = aFrame->PresContext();
    2166             :       nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
    2167             :                  presContext->DevPixelsToAppUnits(aPoint.y));
    2168             :       pt = pt - view->ViewToWidgetOffset();
    2169           0 :       pt = pt.RemoveResolution(GetCurrentAPZResolutionScale(presContext->PresShell()));
    2170           0 :       return pt;
    2171           0 :     }
    2172           0 :   }
    2173             : 
    2174             :   /* If we walk up the frame tree and discover that any of the frames are
    2175             :    * transformed, we need to do extra work to convert from the global
    2176           0 :    * space to the local space.
    2177           0 :    */
    2178           0 :   nsIFrame* rootFrame = aFrame;
    2179           0 :   bool transformFound = false;
    2180           0 :   for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
    2181           0 :     if (f->IsTransformed()) {
    2182             :       transformFound = true;
    2183             :     }
    2184             : 
    2185             :     rootFrame = f;
    2186             :   }
    2187             : 
    2188             :   nsView* rootView = rootFrame->GetView();
    2189             :   if (!rootView) {
    2190             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2191           0 :   }
    2192           0 : 
    2193           0 :   nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
    2194             :                                                aWidget, aPoint, rootView);
    2195             : 
    2196           0 :   if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
    2197             :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2198             :   }
    2199           0 : 
    2200           0 :   // Convert from root document app units to app units of the document aFrame
    2201             :   // is in.
    2202             :   int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
    2203             :   int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
    2204             :   widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD);
    2205           0 :   nsIPresShell* shell = aFrame->PresShell();
    2206             : 
    2207           0 :   // XXX Bug 1224748 - Update nsLayoutUtils functions to correctly handle nsPresShell resolution
    2208             :   widgetToView = widgetToView.RemoveResolution(GetCurrentAPZResolutionScale(shell));
    2209             : 
    2210             :   /* If we encountered a transform, we can't do simple arithmetic to figure
    2211             :    * out how to convert back to aFrame's coordinates and must use the CTM.
    2212             :    */
    2213           0 :   if (transformFound || nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
    2214           0 :     return TransformRootPointToFrame(aFrame, widgetToView);
    2215           0 :   }
    2216           0 : 
    2217             :   /* Otherwise, all coordinate systems are translations of one another,
    2218             :    * so we can just subtract out the difference.
    2219           0 :    */
    2220             :   return widgetToView - aFrame->GetOffsetToCrossDoc(rootFrame);
    2221             : }
    2222             : 
    2223             : nsIFrame*
    2224           0 : nsLayoutUtils::GetPopupFrameForEventCoordinates(nsPresContext* aPresContext,
    2225           0 :                                                 const WidgetEvent* aEvent)
    2226             : {
    2227             : #ifdef MOZ_XUL
    2228             :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    2229             :   if (!pm) {
    2230             :     return nullptr;
    2231           0 :   }
    2232             :   nsTArray<nsIFrame*> popups;
    2233             :   pm->GetVisiblePopups(popups);
    2234             :   uint32_t i;
    2235           0 :   // Search from top to bottom
    2236             :   for (i = 0; i < popups.Length(); i++) {
    2237             :     nsIFrame* popup = popups[i];
    2238             :     if (popup->PresContext()->GetRootPresContext() == aPresContext &&
    2239           0 :         popup->GetScrollableOverflowRect().Contains(
    2240           0 :           GetEventCoordinatesRelativeTo(aEvent, popup))) {
    2241             :       return popup;
    2242             :     }
    2243           0 :   }
    2244           0 : #endif
    2245             :   return nullptr;
    2246             : }
    2247           0 : 
    2248           0 : static void ConstrainToCoordValues(float& aStart, float& aSize)
    2249           0 : {
    2250           0 :   MOZ_ASSERT(aSize >= 0);
    2251           0 : 
    2252             :   // Here we try to make sure that the resulting nsRect will continue to cover
    2253             :   // as much of the area that was covered by the original gfx Rect as possible.
    2254             : 
    2255             :   // We clamp the bounds of the rect to {nscoord_MIN,nscoord_MAX} since
    2256             :   // nsRect::X/Y() and nsRect::XMost/YMost() can't return values outwith this
    2257             :   // range:
    2258             :   float end = aStart + aSize;
    2259           0 :   aStart = clamped(aStart, float(nscoord_MIN), float(nscoord_MAX));
    2260             :   end = clamped(end, float(nscoord_MIN), float(nscoord_MAX));
    2261           0 : 
    2262             :   aSize = end - aStart;
    2263             : 
    2264             :   // We must also clamp aSize to {0,nscoord_MAX} since nsRect::Width/Height()
    2265             :   // can't return a value greater than nscoord_MAX. If aSize is greater than
    2266             :   // nscoord_MAX then we reduce it to nscoord_MAX while keeping the rect
    2267             :   // centered:
    2268             :   if (aSize > nscoord_MAX) {
    2269           0 :     float excess = aSize - nscoord_MAX;
    2270           0 :     excess /= 2;
    2271           0 :     aStart += excess;
    2272             :     aSize = (float)nscoord_MAX;
    2273           0 :   }
    2274             : }
    2275             : 
    2276             : /**
    2277             :  * Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
    2278             :  *
    2279           0 :  * @param aVal The value to constrain (in/out)
    2280           0 :  */
    2281           0 : static void ConstrainToCoordValues(gfxFloat& aVal)
    2282           0 : {
    2283           0 :   if (aVal <= nscoord_MIN)
    2284             :     aVal = nscoord_MIN;
    2285           0 :   else if (aVal >= nscoord_MAX)
    2286             :     aVal = nscoord_MAX;
    2287             : }
    2288             : 
    2289             : static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize)
    2290             : {
    2291             :   gfxFloat max = aStart + aSize;
    2292           0 : 
    2293             :   // Clamp the end points to within nscoord range
    2294           0 :   ConstrainToCoordValues(aStart);
    2295           0 :   ConstrainToCoordValues(max);
    2296           0 : 
    2297           0 :   aSize = max - aStart;
    2298           0 :   // If the width if still greater than the max nscoord, then bring both
    2299             :   // endpoints in by the same amount until it fits.
    2300           0 :   if (aSize > nscoord_MAX) {
    2301             :     gfxFloat excess = aSize - nscoord_MAX;
    2302           0 :     excess /= 2;
    2303             : 
    2304             :     aStart += excess;
    2305           0 :     aSize = nscoord_MAX;
    2306           0 :   } else if (aSize < nscoord_MIN) {
    2307             :     gfxFloat excess = aSize - nscoord_MIN;
    2308           0 :     excess /= 2;
    2309             : 
    2310             :     aStart -= excess;
    2311           0 :     aSize = nscoord_MIN;
    2312           0 :   }
    2313           0 : }
    2314             : 
    2315           0 : nsRect
    2316           0 : nsLayoutUtils::RoundGfxRectToAppRect(const Rect &aRect, float aFactor)
    2317           0 : {
    2318           0 :   /* Get a new Rect whose units are app units by scaling by the specified factor. */
    2319           0 :   Rect scaledRect = aRect;
    2320             :   scaledRect.ScaleRoundOut(aFactor);
    2321           0 : 
    2322           0 :   /* We now need to constrain our results to the max and min values for coords. */
    2323             :   ConstrainToCoordValues(scaledRect.x, scaledRect.width);
    2324           0 :   ConstrainToCoordValues(scaledRect.y, scaledRect.height);
    2325             : 
    2326             :   /* Now typecast everything back.  This is guaranteed to be safe. */
    2327           0 :   return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
    2328             :                 nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
    2329             : }
    2330           0 : 
    2331           0 : nsRect
    2332             : nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
    2333             : {
    2334           0 :   /* Get a new gfxRect whose units are app units by scaling by the specified factor. */
    2335           0 :   gfxRect scaledRect = aRect;
    2336             :   scaledRect.ScaleRoundOut(aFactor);
    2337             : 
    2338           0 :   /* We now need to constrain our results to the max and min values for coords. */
    2339           0 :   ConstrainToCoordValues(scaledRect.x, scaledRect.width);
    2340             :   ConstrainToCoordValues(scaledRect.y, scaledRect.height);
    2341             : 
    2342             :   /* Now typecast everything back.  This is guaranteed to be safe. */
    2343           0 :   return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
    2344             :                 nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
    2345             : }
    2346           0 : 
    2347           0 : 
    2348             : nsRegion
    2349             : nsLayoutUtils::RoundedRectIntersectRect(const nsRect& aRoundedRect,
    2350           0 :                                         const nscoord aRadii[8],
    2351           0 :                                         const nsRect& aContainedRect)
    2352             : {
    2353             :   // rectFullHeight and rectFullWidth together will approximately contain
    2354           0 :   // the total area of the frame minus the rounded corners.
    2355           0 :   nsRect rectFullHeight = aRoundedRect;
    2356             :   nscoord xDiff = std::max(aRadii[eCornerTopLeftX], aRadii[eCornerBottomLeftX]);
    2357             :   rectFullHeight.x += xDiff;
    2358             :   rectFullHeight.width -= std::max(aRadii[eCornerTopRightX],
    2359             :                                    aRadii[eCornerBottomRightX]) + xDiff;
    2360           0 :   nsRect r1;
    2361             :   r1.IntersectRect(rectFullHeight, aContainedRect);
    2362             : 
    2363             :   nsRect rectFullWidth = aRoundedRect;
    2364             :   nscoord yDiff = std::max(aRadii[eCornerTopLeftY], aRadii[eCornerTopRightY]);
    2365             :   rectFullWidth.y += yDiff;
    2366           0 :   rectFullWidth.height -= std::max(aRadii[eCornerBottomLeftY],
    2367           0 :                                    aRadii[eCornerBottomRightY]) + yDiff;
    2368           0 :   nsRect r2;
    2369           0 :   r2.IntersectRect(rectFullWidth, aContainedRect);
    2370           0 : 
    2371           0 :   nsRegion result;
    2372           0 :   result.Or(r1, r2);
    2373             :   return result;
    2374           0 : }
    2375           0 : 
    2376           0 : nsIntRegion
    2377           0 : nsLayoutUtils::RoundedRectIntersectIntRect(const nsIntRect& aRoundedRect,
    2378           0 :                                            const RectCornerRadii& aCornerRadii,
    2379           0 :                                            const nsIntRect& aContainedRect)
    2380           0 : {
    2381             :   // rectFullHeight and rectFullWidth together will approximately contain
    2382           0 :   // the total area of the frame minus the rounded corners.
    2383           0 :   nsIntRect rectFullHeight = aRoundedRect;
    2384           0 :   uint32_t xDiff = std::max(aCornerRadii.TopLeft().width,
    2385             :                             aCornerRadii.BottomLeft().width);
    2386             :   rectFullHeight.x += xDiff;
    2387             :   rectFullHeight.width -= std::max(aCornerRadii.TopRight().width,
    2388           0 :                                    aCornerRadii.BottomRight().width) + xDiff;
    2389             :   nsIntRect r1;
    2390             :   r1.IntersectRect(rectFullHeight, aContainedRect);
    2391             : 
    2392             :   nsIntRect rectFullWidth = aRoundedRect;
    2393             :   uint32_t yDiff = std::max(aCornerRadii.TopLeft().height,
    2394           0 :                             aCornerRadii.TopRight().height);
    2395           0 :   rectFullWidth.y += yDiff;
    2396           0 :   rectFullWidth.height -= std::max(aCornerRadii.BottomLeft().height,
    2397           0 :                                    aCornerRadii.BottomRight().height) + yDiff;
    2398           0 :   nsIntRect r2;
    2399           0 :   r2.IntersectRect(rectFullWidth, aContainedRect);
    2400           0 : 
    2401           0 :   nsIntRegion result;
    2402             :   result.Or(r1, r2);
    2403           0 :   return result;
    2404           0 : }
    2405           0 : 
    2406           0 : // Helper for RoundedRectIntersectsRect.
    2407           0 : static bool
    2408           0 : CheckCorner(nscoord aXOffset, nscoord aYOffset,
    2409           0 :             nscoord aXRadius, nscoord aYRadius)
    2410           0 : {
    2411             :   MOZ_ASSERT(aXOffset > 0 && aYOffset > 0,
    2412           0 :              "must not pass nonpositives to CheckCorner");
    2413           0 :   MOZ_ASSERT(aXRadius >= 0 && aYRadius >= 0,
    2414           0 :              "must not pass negatives to CheckCorner");
    2415             : 
    2416             :   // Avoid floating point math unless we're either (1) within the
    2417             :   // quarter-ellipse area at the rounded corner or (2) outside the
    2418             :   // rounding.
    2419           0 :   if (aXOffset >= aXRadius || aYOffset >= aYRadius)
    2420             :     return true;
    2421             : 
    2422           0 :   // Convert coordinates to a unit circle with (0,0) as the center of
    2423             :   // curvature, and see if we're inside the circle or outside.
    2424           0 :   float scaledX = float(aXRadius - aXOffset) / float(aXRadius);
    2425             :   float scaledY = float(aYRadius - aYOffset) / float(aYRadius);
    2426             :   return scaledX * scaledX + scaledY * scaledY < 1.0f;
    2427             : }
    2428             : 
    2429             : bool
    2430           0 : nsLayoutUtils::RoundedRectIntersectsRect(const nsRect& aRoundedRect,
    2431             :                                          const nscoord aRadii[8],
    2432             :                                          const nsRect& aTestRect)
    2433             : {
    2434             :   if (!aTestRect.Intersects(aRoundedRect))
    2435           0 :     return false;
    2436           0 : 
    2437           0 :   // distances from this edge of aRoundedRect to opposite edge of aTestRect,
    2438             :   // which we know are positive due to the Intersects check above.
    2439             :   nsMargin insets;
    2440             :   insets.top = aTestRect.YMost() - aRoundedRect.y;
    2441           0 :   insets.right = aRoundedRect.XMost() - aTestRect.x;
    2442             :   insets.bottom = aRoundedRect.YMost() - aTestRect.y;
    2443             :   insets.left = aTestRect.XMost() - aRoundedRect.x;
    2444             : 
    2445           0 :   // Check whether the bottom-right corner of aTestRect is inside the
    2446             :   // top left corner of aBounds when rounded by aRadii, etc.  If any
    2447             :   // corner is not, then fail; otherwise succeed.
    2448             :   return CheckCorner(insets.left, insets.top,
    2449             :                      aRadii[eCornerTopLeftX],
    2450           0 :                      aRadii[eCornerTopLeftY]) &&
    2451           0 :          CheckCorner(insets.right, insets.top,
    2452           0 :                      aRadii[eCornerTopRightX],
    2453           0 :                      aRadii[eCornerTopRightY]) &&
    2454           0 :          CheckCorner(insets.right, insets.bottom,
    2455             :                      aRadii[eCornerBottomRightX],
    2456             :                      aRadii[eCornerBottomRightY]) &&
    2457             :          CheckCorner(insets.left, insets.bottom,
    2458             :                      aRadii[eCornerBottomLeftX],
    2459           0 :                      aRadii[eCornerBottomLeftY]);
    2460             : }
    2461           0 : 
    2462           0 : nsRect
    2463             : nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
    2464           0 :                                    const Matrix4x4 &aMatrix, float aFactor)
    2465           0 : {
    2466             :   RectDouble image = RectDouble(NSAppUnitsToDoublePixels(aBounds.x, aFactor),
    2467           0 :                                 NSAppUnitsToDoublePixels(aBounds.y, aFactor),
    2468           0 :                                 NSAppUnitsToDoublePixels(aBounds.width, aFactor),
    2469             :                                 NSAppUnitsToDoublePixels(aBounds.height, aFactor));
    2470             : 
    2471             :   RectDouble maxBounds = RectDouble(double(nscoord_MIN) / aFactor * 0.5,
    2472             :                                     double(nscoord_MIN) / aFactor * 0.5,
    2473             :                                     double(nscoord_MAX) / aFactor,
    2474           0 :                                     double(nscoord_MAX) / aFactor);
    2475             : 
    2476             :   image = aMatrix.TransformAndClipBounds(image, maxBounds);
    2477           0 : 
    2478           0 :   return RoundGfxRectToAppRect(ThebesRect(image), aFactor);
    2479           0 : }
    2480           0 : 
    2481             : nsRect
    2482             : nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
    2483           0 :                                    const Matrix4x4Flagged &aMatrix, float aFactor)
    2484             : {
    2485           0 :   RectDouble image = RectDouble(NSAppUnitsToDoublePixels(aBounds.x, aFactor),
    2486             :                                 NSAppUnitsToDoublePixels(aBounds.y, aFactor),
    2487           0 :                                 NSAppUnitsToDoublePixels(aBounds.width, aFactor),
    2488             :                                 NSAppUnitsToDoublePixels(aBounds.height, aFactor));
    2489           0 : 
    2490             :   RectDouble maxBounds = RectDouble(double(nscoord_MIN) / aFactor * 0.5,
    2491             :                                     double(nscoord_MIN) / aFactor * 0.5,
    2492             :                                     double(nscoord_MAX) / aFactor,
    2493           0 :                                     double(nscoord_MAX) / aFactor);
    2494             : 
    2495             :   image = aMatrix.TransformAndClipBounds(image, maxBounds);
    2496           0 : 
    2497           0 :   return RoundGfxRectToAppRect(ThebesRect(image), aFactor);
    2498           0 : }
    2499           0 : 
    2500             : nsPoint
    2501             : nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
    2502           0 :                                     const Matrix4x4 &aMatrix, float aFactor)
    2503             : {
    2504           0 :   gfxPoint image = gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, aFactor),
    2505             :                             NSAppUnitsToFloatPixels(aPoint.y, aFactor));
    2506           0 :   image = aMatrix.TransformPoint(image);
    2507             :   return nsPoint(NSFloatPixelsToAppUnits(float(image.x), aFactor),
    2508           0 :                  NSFloatPixelsToAppUnits(float(image.y), aFactor));
    2509             : }
    2510             : 
    2511             : void
    2512           0 : nsLayoutUtils::PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin, float aAppUnitsPerPixel, bool aRounded)
    2513             : {
    2514             :   Point3D gfxOrigin =
    2515           0 :     Point3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
    2516           0 :             NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
    2517           0 :             0.0f);
    2518           0 :   if (aRounded) {
    2519           0 :     gfxOrigin.x = NS_round(gfxOrigin.x);
    2520             :     gfxOrigin.y = NS_round(gfxOrigin.y);
    2521             :   }
    2522             :   aTransform.PostTranslate(gfxOrigin);
    2523           0 : }
    2524             : 
    2525             : // We want to this return true for the scroll frame, but not the
    2526           0 : // scrolled frame (which has the same content).
    2527           0 : bool
    2528           0 : nsLayoutUtils::FrameHasDisplayPort(nsIFrame* aFrame, nsIFrame* aScrolledFrame)
    2529           0 : {
    2530           0 :   if (!aFrame->GetContent() || !HasDisplayPort(aFrame->GetContent())) {
    2531           0 :     return false;
    2532             :   }
    2533           0 :   nsIScrollableFrame* sf = do_QueryFrame(aFrame);
    2534           0 :   if (sf) {
    2535             :     if (aScrolledFrame && aScrolledFrame != sf->GetScrolledFrame()) {
    2536             :       return false;
    2537             :     }
    2538             :     return true;
    2539           0 :   }
    2540             :   return false;
    2541           0 : }
    2542             : 
    2543             : Matrix4x4Flagged
    2544           0 : nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame,
    2545           0 :                                       const nsIFrame *aAncestor,
    2546           0 :                                       uint32_t aFlags,
    2547             :                                       nsIFrame** aOutAncestor)
    2548             : {
    2549           0 :   nsIFrame* parent;
    2550             :   Matrix4x4Flagged ctm;
    2551             :   if (aFrame == aAncestor) {
    2552             :     return ctm;
    2553             :   }
    2554             :   ctm = aFrame->GetTransformMatrix(aAncestor, &parent, aFlags);
    2555           0 :   while (parent && parent != aAncestor &&
    2556             :     (!(aFlags & nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
    2557             :       (!parent->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
    2558             :        !parent->IsStackingContext() &&
    2559             :        !FrameHasDisplayPort(parent)))) {
    2560             :     if (!parent->Extend3DContext()) {
    2561           0 :       ctm.ProjectTo2D();
    2562           0 :     }
    2563             :     ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent, aFlags);
    2564             :   }
    2565           0 :   if (aOutAncestor) {
    2566           0 :     *aOutAncestor = parent;
    2567           0 :   }
    2568           0 :   return ctm;
    2569           0 : }
    2570           0 : 
    2571           0 : gfxSize
    2572           0 : nsLayoutUtils::GetTransformToAncestorScale(nsIFrame* aFrame)
    2573             : {
    2574           0 :   Matrix4x4Flagged transform = GetTransformToAncestor(aFrame,
    2575             :       nsLayoutUtils::GetDisplayRootFrame(aFrame));
    2576           0 :   Matrix transform2D;
    2577           0 :   if (transform.Is2D(&transform2D)) {
    2578             :     return ThebesMatrix(transform2D).ScaleFactors(true);
    2579             :   }
    2580             :   return gfxSize(1, 1);
    2581             : }
    2582             : 
    2583           0 : static Matrix4x4Flagged
    2584             : GetTransformToAncestorExcludingAnimated(nsIFrame* aFrame,
    2585             :                                         const nsIFrame* aAncestor)
    2586           0 : {
    2587           0 :   nsIFrame* parent;
    2588           0 :   Matrix4x4Flagged ctm;
    2589           0 :   if (aFrame == aAncestor) {
    2590             :     return ctm;
    2591           0 :   }
    2592             :   if (ActiveLayerTracker::IsScaleSubjectToAnimation(aFrame)) {
    2593             :     return ctm;
    2594             :   }
    2595           0 :   ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
    2596             :   while (parent && parent != aAncestor) {
    2597             :     if (ActiveLayerTracker::IsScaleSubjectToAnimation(parent)) {
    2598             :       return Matrix4x4Flagged();
    2599           0 :     }
    2600           0 :     if (!parent->Extend3DContext()) {
    2601           0 :       ctm.ProjectTo2D();
    2602             :     }
    2603           0 :     ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
    2604           0 :   }
    2605             :   return ctm;
    2606           0 : }
    2607           0 : 
    2608           0 : gfxSize
    2609           0 : nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(nsIFrame* aFrame)
    2610             : {
    2611           0 :   Matrix4x4Flagged transform = GetTransformToAncestorExcludingAnimated(aFrame,
    2612           0 :       nsLayoutUtils::GetDisplayRootFrame(aFrame));
    2613             :   Matrix transform2D;
    2614           0 :   if (transform.Is2D(&transform2D)) {
    2615             :     return ThebesMatrix(transform2D).ScaleFactors(true);
    2616           0 :   }
    2617             :   return gfxSize(1, 1);
    2618             : }
    2619             : 
    2620           0 : nsIFrame*
    2621             : nsLayoutUtils::FindNearestCommonAncestorFrame(nsIFrame* aFrame1, nsIFrame* aFrame2)
    2622             : {
    2623           0 :   AutoTArray<nsIFrame*,100> ancestors1;
    2624           0 :   AutoTArray<nsIFrame*,100> ancestors2;
    2625           0 :   nsIFrame* commonAncestor = nullptr;
    2626           0 :   if (aFrame1->PresContext() == aFrame2->PresContext()) {
    2627             :     commonAncestor = aFrame1->PresShell()->GetRootFrame();
    2628           0 :   }
    2629             :   for (nsIFrame* f = aFrame1; f != commonAncestor;
    2630             :        f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    2631             :     ancestors1.AppendElement(f);
    2632           0 :   }
    2633             :   for (nsIFrame* f = aFrame2; f != commonAncestor;
    2634           0 :        f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    2635           0 :     ancestors2.AppendElement(f);
    2636           0 :   }
    2637           0 :   uint32_t minLengths = std::min(ancestors1.Length(), ancestors2.Length());
    2638           0 :   for (uint32_t i = 1; i <= minLengths; ++i) {
    2639             :     if (ancestors1[ancestors1.Length() - i] == ancestors2[ancestors2.Length() - i]) {
    2640           0 :       commonAncestor = ancestors1[ancestors1.Length() - i];
    2641           0 :     } else {
    2642           0 :       break;
    2643             :     }
    2644           0 :   }
    2645           0 :   return commonAncestor;
    2646           0 : }
    2647             : 
    2648           0 : nsLayoutUtils::TransformResult
    2649           0 : nsLayoutUtils::TransformPoints(nsIFrame* aFromFrame, nsIFrame* aToFrame,
    2650           0 :                                uint32_t aPointCount, CSSPoint* aPoints)
    2651           0 : {
    2652             :   nsIFrame* nearestCommonAncestor = FindNearestCommonAncestorFrame(aFromFrame, aToFrame);
    2653             :   if (!nearestCommonAncestor) {
    2654             :     return NO_COMMON_ANCESTOR;
    2655             :   }
    2656           0 :   Matrix4x4Flagged downToDest = GetTransformToAncestor(aToFrame, nearestCommonAncestor);
    2657             :   if (downToDest.IsSingular()) {
    2658             :     return NONINVERTIBLE_TRANSFORM;
    2659             :   }
    2660           0 :   downToDest.Invert();
    2661             :   Matrix4x4Flagged upToAncestor = GetTransformToAncestor(aFromFrame, nearestCommonAncestor);
    2662             :   CSSToLayoutDeviceScale devPixelsPerCSSPixelFromFrame =
    2663           0 :       aFromFrame->PresContext()->CSSToDevPixelScale();
    2664           0 :   CSSToLayoutDeviceScale devPixelsPerCSSPixelToFrame =
    2665             :       aToFrame->PresContext()->CSSToDevPixelScale();
    2666             :   for (uint32_t i = 0; i < aPointCount; ++i) {
    2667           0 :     LayoutDevicePoint devPixels = aPoints[i] * devPixelsPerCSSPixelFromFrame;
    2668           0 :     // What should the behaviour be if some of the points aren't invertible
    2669             :     // and others are? Just assume all points are for now.
    2670             :     Point toDevPixels = downToDest.ProjectPoint(
    2671           0 :         (upToAncestor.TransformPoint(Point(devPixels.x, devPixels.y)))).As2DPoint();
    2672           0 :     // Divide here so that when the devPixelsPerCSSPixels are the same, we get the correct
    2673             :     // answer instead of some inaccuracy multiplying a number by its reciprocal.
    2674           0 :     aPoints[i] = LayoutDevicePoint(toDevPixels.x, toDevPixels.y) /
    2675             :         devPixelsPerCSSPixelToFrame;
    2676           0 :   }
    2677           0 :   return TRANSFORM_SUCCEEDED;
    2678           0 : }
    2679             : 
    2680             : nsLayoutUtils::TransformResult
    2681           0 : nsLayoutUtils::TransformPoint(nsIFrame* aFromFrame, nsIFrame* aToFrame,
    2682           0 :                               nsPoint& aPoint)
    2683             : {
    2684             :   nsIFrame* nearestCommonAncestor = FindNearestCommonAncestorFrame(aFromFrame, aToFrame);
    2685           0 :   if (!nearestCommonAncestor) {
    2686           0 :     return NO_COMMON_ANCESTOR;
    2687             :   }
    2688             :   Matrix4x4Flagged downToDest = GetTransformToAncestor(aToFrame, nearestCommonAncestor);
    2689             :   if (downToDest.IsSingular()) {
    2690             :     return NONINVERTIBLE_TRANSFORM;
    2691             :   }
    2692           0 :   downToDest.Invert();
    2693             :   Matrix4x4Flagged upToAncestor = GetTransformToAncestor(aFromFrame, nearestCommonAncestor);
    2694             : 
    2695           0 :   float devPixelsPerAppUnitFromFrame =
    2696           0 :     1.0f / aFromFrame->PresContext()->AppUnitsPerDevPixel();
    2697             :   float devPixelsPerAppUnitToFrame =
    2698             :     1.0f / aToFrame->PresContext()->AppUnitsPerDevPixel();
    2699           0 :   Point4D toDevPixels = downToDest.ProjectPoint(
    2700           0 :       upToAncestor.TransformPoint(Point(aPoint.x * devPixelsPerAppUnitFromFrame,
    2701             :                                         aPoint.y * devPixelsPerAppUnitFromFrame)));
    2702             :   if (!toDevPixels.HasPositiveWCoord()) {
    2703           0 :     // Not strictly true, but we failed to get a valid point in this
    2704           0 :     // coordinate space.
    2705             :     return NONINVERTIBLE_TRANSFORM;
    2706             :   }
    2707           0 :   aPoint.x = NSToCoordRound(toDevPixels.x / devPixelsPerAppUnitToFrame);
    2708             :   aPoint.y = NSToCoordRound(toDevPixels.y / devPixelsPerAppUnitToFrame);
    2709           0 :   return TRANSFORM_SUCCEEDED;
    2710             : }
    2711           0 : 
    2712           0 : nsLayoutUtils::TransformResult
    2713           0 : nsLayoutUtils::TransformRect(nsIFrame* aFromFrame, nsIFrame* aToFrame,
    2714             :                              nsRect& aRect)
    2715             : {
    2716             :   nsIFrame* nearestCommonAncestor = FindNearestCommonAncestorFrame(aFromFrame, aToFrame);
    2717             :   if (!nearestCommonAncestor) {
    2718           0 :     return NO_COMMON_ANCESTOR;
    2719           0 :   }
    2720           0 :   Matrix4x4Flagged downToDest = GetTransformToAncestor(aToFrame, nearestCommonAncestor);
    2721             :   if (downToDest.IsSingular()) {
    2722             :     return NONINVERTIBLE_TRANSFORM;
    2723             :   }
    2724           0 :   downToDest.Invert();
    2725             :   Matrix4x4Flagged upToAncestor = GetTransformToAncestor(aFromFrame, nearestCommonAncestor);
    2726             : 
    2727           0 :   float devPixelsPerAppUnitFromFrame =
    2728           0 :     1.0f / aFromFrame->PresContext()->AppUnitsPerDevPixel();
    2729             :   float devPixelsPerAppUnitToFrame =
    2730             :     1.0f / aToFrame->PresContext()->AppUnitsPerDevPixel();
    2731           0 :   gfx::Rect toDevPixels = downToDest.ProjectRectBounds(
    2732           0 :     upToAncestor.ProjectRectBounds(
    2733             :       gfx::Rect(aRect.x * devPixelsPerAppUnitFromFrame,
    2734             :                 aRect.y * devPixelsPerAppUnitFromFrame,
    2735           0 :                 aRect.width * devPixelsPerAppUnitFromFrame,
    2736           0 :                 aRect.height * devPixelsPerAppUnitFromFrame),
    2737             :       Rect(-std::numeric_limits<Float>::max() * 0.5f,
    2738             :            -std::numeric_limits<Float>::max() * 0.5f,
    2739           0 :            std::numeric_limits<Float>::max(),
    2740             :            std::numeric_limits<Float>::max())),
    2741           0 :     Rect(-std::numeric_limits<Float>::max() * devPixelsPerAppUnitFromFrame * 0.5f,
    2742             :          -std::numeric_limits<Float>::max() * devPixelsPerAppUnitFromFrame * 0.5f,
    2743           0 :          std::numeric_limits<Float>::max() * devPixelsPerAppUnitFromFrame,
    2744           0 :          std::numeric_limits<Float>::max() * devPixelsPerAppUnitFromFrame));
    2745           0 :   aRect.x = NSToCoordRound(toDevPixels.x / devPixelsPerAppUnitToFrame);
    2746           0 :   aRect.y = NSToCoordRound(toDevPixels.y / devPixelsPerAppUnitToFrame);
    2747           0 :   aRect.width = NSToCoordRound(toDevPixels.width / devPixelsPerAppUnitToFrame);
    2748           0 :   aRect.height = NSToCoordRound(toDevPixels.height / devPixelsPerAppUnitToFrame);
    2749             :   return TRANSFORM_SUCCEEDED;
    2750             : }
    2751             : 
    2752           0 : nsRect
    2753           0 : nsLayoutUtils::GetRectRelativeToFrame(Element* aElement, nsIFrame* aFrame)
    2754             : {
    2755           0 :   if (!aElement || !aFrame) {
    2756           0 :     return nsRect();
    2757           0 :   }
    2758           0 : 
    2759           0 :   nsIFrame* frame = aElement->GetPrimaryFrame();
    2760           0 :   if (!frame) {
    2761             :     return nsRect();
    2762             :   }
    2763             : 
    2764           0 :   nsRect rect = frame->GetRectRelativeToSelf();
    2765             :   nsLayoutUtils::TransformResult rv =
    2766           0 :     nsLayoutUtils::TransformRect(frame, aFrame, rect);
    2767           0 :   if (rv != nsLayoutUtils::TRANSFORM_SUCCEEDED) {
    2768             :     return nsRect();
    2769             :   }
    2770           0 : 
    2771           0 :   return rect;
    2772           0 : }
    2773             : 
    2774             : bool
    2775           0 : nsLayoutUtils::ContainsPoint(const nsRect& aRect, const nsPoint& aPoint,
    2776             :                              nscoord aInflateSize)
    2777           0 : {
    2778           0 :   nsRect rect = aRect;
    2779           0 :   rect.Inflate(aInflateSize);
    2780             :   return rect.Contains(aPoint);
    2781             : }
    2782           0 : 
    2783             : nsRect
    2784             : nsLayoutUtils::ClampRectToScrollFrames(nsIFrame* aFrame, const nsRect& aRect)
    2785             : {
    2786           0 :   nsIFrame* closestScrollFrame =
    2787             :     nsLayoutUtils::GetClosestFrameOfType(aFrame, LayoutFrameType::Scroll);
    2788             : 
    2789           0 :   nsRect resultRect = aRect;
    2790           0 : 
    2791           0 :   while (closestScrollFrame) {
    2792             :     nsIScrollableFrame* sf = do_QueryFrame(closestScrollFrame);
    2793             : 
    2794             :     nsRect scrollPortRect = sf->GetScrollPortRect();
    2795           0 :     nsLayoutUtils::TransformRect(closestScrollFrame, aFrame, scrollPortRect);
    2796             : 
    2797             :     resultRect = resultRect.Intersect(scrollPortRect);
    2798           0 : 
    2799             :     // Check whether aRect is visible in the scroll frame or not.
    2800           0 :     if (resultRect.IsEmpty()) {
    2801             :       break;
    2802           0 :     }
    2803           0 : 
    2804             :     // Get next ancestor scroll frame.
    2805           0 :     closestScrollFrame = nsLayoutUtils::GetClosestFrameOfType(
    2806           0 :       closestScrollFrame->GetParent(), LayoutFrameType::Scroll);
    2807             :   }
    2808           0 : 
    2809             :   return resultRect;
    2810             : }
    2811           0 : 
    2812             : bool
    2813             : nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame,
    2814             :                                          Matrix4x4Flagged* aTransform)
    2815             : {
    2816             :   // FIXME/bug 796690: we can sometimes compute a transform in these
    2817           0 :   // cases, it just increases complexity considerably.  Punt for now.
    2818             :   if (aFrame->Extend3DContext() || aFrame->HasTransformGetter()) {
    2819             :     return false;
    2820           0 :   }
    2821             : 
    2822             :   nsIFrame* root = nsLayoutUtils::GetDisplayRootFrame(aFrame);
    2823             :   if (root->HasAnyStateBits(NS_FRAME_UPDATE_LAYER_TREE)) {
    2824           0 :     // Content may have been invalidated, so we can't reliably compute
    2825             :     // the "layer transform" in general.
    2826             :     return false;
    2827             :   }
    2828             :   // If the caller doesn't care about the value, early-return to skip
    2829           0 :   // overhead below.
    2830             :   if (!aTransform) {
    2831             :     return true;
    2832             :   }
    2833           0 : 
    2834           0 :   nsDisplayListBuilder builder(root,
    2835             :                                nsDisplayListBuilderMode::TRANSFORM_COMPUTATION,
    2836             :                                false/*don't build caret*/);
    2837             :   builder.BeginFrame();
    2838             :   nsDisplayList list;
    2839             :   nsDisplayTransform* item =
    2840             :     MakeDisplayItem<nsDisplayTransform>(&builder, aFrame, &list, nsRect());
    2841           0 : 
    2842             :   *aTransform = item->GetTransform();
    2843             :   item->Destroy(&builder);
    2844             : 
    2845             :   builder.EndFrame();
    2846             : 
    2847           0 :   return true;
    2848           0 : }
    2849           0 : 
    2850             : static bool
    2851           0 : TransformGfxPointFromAncestor(nsIFrame *aFrame,
    2852             :                               const Point &aPoint,
    2853           0 :                               nsIFrame *aAncestor,
    2854           0 :                               Point* aOut)
    2855             : {
    2856           0 :   Matrix4x4Flagged ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
    2857             :   ctm.Invert();
    2858             :   Point4D point = ctm.ProjectPoint(aPoint);
    2859             :   if (!point.HasPositiveWCoord()) {
    2860             :     return false;
    2861             :   }
    2862           0 :   *aOut = point.As2DPoint();
    2863             :   return true;
    2864             : }
    2865             : 
    2866             : static Rect
    2867           0 : TransformGfxRectToAncestor(nsIFrame *aFrame,
    2868           0 :                            const Rect &aRect,
    2869           0 :                            const nsIFrame *aAncestor,
    2870           0 :                            bool* aPreservesAxisAlignedRectangles = nullptr,
    2871             :                            Maybe<Matrix4x4Flagged>* aMatrixCache = nullptr,
    2872             :                            bool aStopAtStackingContextAndDisplayPort = false,
    2873           0 :                            nsIFrame** aOutAncestor = nullptr)
    2874           0 : {
    2875             :   Matrix4x4Flagged ctm;
    2876             :   if (aMatrixCache && *aMatrixCache) {
    2877             :     // We are given a matrix to use, so use it
    2878           0 :     ctm = aMatrixCache->value();
    2879             :   } else {
    2880             :     // Else, compute it
    2881             :     uint32_t flags = 0;
    2882             :     if (aStopAtStackingContextAndDisplayPort) {
    2883             :       flags |= nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT;
    2884             :     }
    2885             :     ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor, flags, aOutAncestor);
    2886           0 :     if (aMatrixCache) {
    2887           0 :       // and put it in the cache, if provided
    2888             :       *aMatrixCache = Some(ctm);
    2889           0 :     }
    2890             :   }
    2891             :   // Fill out the axis-alignment flag
    2892           0 :   if (aPreservesAxisAlignedRectangles) {
    2893           0 :     Matrix matrix2d;
    2894           0 :     *aPreservesAxisAlignedRectangles =
    2895             :       ctm.Is2D(&matrix2d) && matrix2d.PreservesAxisAlignedRectangles();
    2896           0 :   }
    2897           0 :   const nsIFrame* ancestor = aOutAncestor ? *aOutAncestor : aAncestor;
    2898             :   float factor = ancestor->PresContext()->AppUnitsPerDevPixel();
    2899           0 :   Rect maxBounds = Rect(float(nscoord_MIN) / factor * 0.5,
    2900             :                         float(nscoord_MIN) / factor * 0.5,
    2901             :                         float(nscoord_MAX) / factor,
    2902             :                         float(nscoord_MAX) / factor);
    2903           0 :   return ctm.TransformAndClipBounds(aRect, maxBounds);
    2904           0 : }
    2905           0 : 
    2906           0 : static SVGTextFrame*
    2907             : GetContainingSVGTextFrame(nsIFrame* aFrame)
    2908           0 : {
    2909           0 :   if (!nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
    2910             :     return nullptr;
    2911           0 :   }
    2912             : 
    2913           0 :   return static_cast<SVGTextFrame*>(nsLayoutUtils::GetClosestFrameOfType(
    2914           0 :     aFrame->GetParent(), LayoutFrameType::SVGText));
    2915             : }
    2916             : 
    2917             : nsPoint
    2918           0 : nsLayoutUtils::TransformAncestorPointToFrame(nsIFrame* aFrame,
    2919             :                                              const nsPoint& aPoint,
    2920           0 :                                              nsIFrame* aAncestor)
    2921             : {
    2922             :     SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
    2923             : 
    2924             :     float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
    2925           0 :     Point result(NSAppUnitsToFloatPixels(aPoint.x, factor),
    2926             :                  NSAppUnitsToFloatPixels(aPoint.y, factor));
    2927             : 
    2928             :     if (text) {
    2929           0 :         if (!TransformGfxPointFromAncestor(text, result, aAncestor, &result)) {
    2930             :             return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2931             :         }
    2932             :         result = text->TransformFramePointToTextChild(result, aFrame);
    2933           0 :     } else {
    2934             :         if (!TransformGfxPointFromAncestor(aFrame, result, nullptr, &result)) {
    2935           0 :             return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    2936           0 :         }
    2937           0 :     }
    2938             : 
    2939           0 :     return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
    2940           0 :                    NSFloatPixelsToAppUnits(float(result.y), factor));
    2941             : }
    2942             : 
    2943           0 : nsRect
    2944             : nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
    2945           0 :                                             const nsRect& aRect,
    2946             :                                             const nsIFrame* aAncestor,
    2947             :                                             bool* aPreservesAxisAlignedRectangles /* = nullptr */,
    2948             :                                             Maybe<Matrix4x4Flagged>* aMatrixCache /* = nullptr */,
    2949             :                                             bool aStopAtStackingContextAndDisplayPort /* = false */,
    2950           0 :                                             nsIFrame** aOutAncestor /* = nullptr */)
    2951           0 : {
    2952             :   SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
    2953             : 
    2954             :   float srcAppUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
    2955           0 :   Rect result;
    2956             : 
    2957             :   if (text) {
    2958             :     result = ToRect(text->TransformFrameRectFromTextChild(aRect, aFrame));
    2959             :     result = TransformGfxRectToAncestor(text, result, aAncestor,
    2960             :                                         nullptr, aMatrixCache,
    2961             :                                         aStopAtStackingContextAndDisplayPort, aOutAncestor);
    2962             :     // TransformFrameRectFromTextChild could involve any kind of transform, we
    2963           0 :     // could drill down into it to get an answer out of it but we don't yet.
    2964             :     if (aPreservesAxisAlignedRectangles)
    2965           0 :       *aPreservesAxisAlignedRectangles = false;
    2966           0 :   } else {
    2967             :     result = Rect(NSAppUnitsToFloatPixels(aRect.x, srcAppUnitsPerDevPixel),
    2968           0 :                   NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
    2969           0 :                   NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
    2970             :                   NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
    2971             :     result = TransformGfxRectToAncestor(aFrame, result, aAncestor,
    2972           0 :                                         aPreservesAxisAlignedRectangles, aMatrixCache,
    2973             :                                         aStopAtStackingContextAndDisplayPort, aOutAncestor);
    2974             :   }
    2975           0 : 
    2976           0 :   float destAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
    2977             :   return nsRect(NSFloatPixelsToAppUnits(float(result.x), destAppUnitsPerDevPixel),
    2978           0 :                 NSFloatPixelsToAppUnits(float(result.y), destAppUnitsPerDevPixel),
    2979           0 :                 NSFloatPixelsToAppUnits(float(result.width), destAppUnitsPerDevPixel),
    2980           0 :                 NSFloatPixelsToAppUnits(float(result.height), destAppUnitsPerDevPixel));
    2981           0 : }
    2982             : 
    2983             : static LayoutDeviceIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
    2984           0 :   LayoutDeviceIntPoint offset(0, 0);
    2985             :   while ((aWidget->WindowType() == eWindowType_child ||
    2986             :           aWidget->IsPlugin())) {
    2987           0 :     nsIWidget* parent = aWidget->GetParent();
    2988           0 :     if (!parent) {
    2989           0 :       break;
    2990           0 :     }
    2991           0 :     LayoutDeviceIntRect bounds = aWidget->GetBounds();
    2992             :     offset += bounds.TopLeft();
    2993             :     aWidget = parent;
    2994           0 :   }
    2995           0 :   aRootWidget = aWidget;
    2996           0 :   return offset;
    2997           0 : }
    2998           0 : 
    2999           0 : LayoutDeviceIntPoint
    3000             : nsLayoutUtils::WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) {
    3001             :   nsIWidget* fromRoot;
    3002           0 :   LayoutDeviceIntPoint fromOffset = GetWidgetOffset(aFrom, fromRoot);
    3003           0 :   nsIWidget* toRoot;
    3004           0 :   LayoutDeviceIntPoint toOffset = GetWidgetOffset(aTo, toRoot);
    3005             : 
    3006           0 :   if (fromRoot == toRoot) {
    3007           0 :     return fromOffset - toOffset;
    3008             :   }
    3009             :   return aFrom->WidgetToScreenOffset() - aTo->WidgetToScreenOffset();
    3010             : }
    3011           0 : 
    3012             : nsPoint
    3013           0 : nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
    3014             :                                      nsIWidget* aWidget, const LayoutDeviceIntPoint& aPt,
    3015           0 :                                      nsView* aView)
    3016             : {
    3017           0 :   nsPoint viewOffset;
    3018           0 :   nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
    3019             :   if (!viewWidget) {
    3020           0 :     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    3021             :   }
    3022             : 
    3023             :   LayoutDeviceIntPoint widgetPoint = aPt + WidgetToWidgetOffset(aWidget, viewWidget);
    3024           0 :   nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
    3025             :                          aPresContext->DevPixelsToAppUnits(widgetPoint.y));
    3026             :   return widgetAppUnits - viewOffset;
    3027             : }
    3028           0 : 
    3029           0 : LayoutDeviceIntPoint
    3030           0 : nsLayoutUtils::TranslateViewToWidget(nsPresContext* aPresContext,
    3031             :                                      nsView* aView, nsPoint aPt,
    3032             :                                      nsIWidget* aWidget)
    3033             : {
    3034           0 :   nsPoint viewOffset;
    3035             :   nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
    3036           0 :   if (!viewWidget) {
    3037           0 :     return LayoutDeviceIntPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    3038             :   }
    3039             : 
    3040             :   nsPoint pt = (aPt +
    3041           0 :   viewOffset).ApplyResolution(GetCurrentAPZResolutionScale(aPresContext->PresShell()));
    3042             :   LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x),
    3043             :                                             aPresContext->AppUnitsToDevPixels(pt.y));
    3044             :   return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);
    3045           0 : }
    3046           0 : 
    3047           0 : // Combine aNewBreakType with aOrigBreakType, but limit the break types
    3048           0 : // to StyleClear::Left, Right, Both.
    3049             : StyleClear
    3050             : nsLayoutUtils::CombineBreakType(StyleClear aOrigBreakType,
    3051           0 :                                 StyleClear aNewBreakType)
    3052           0 : {
    3053             :   StyleClear breakType = aOrigBreakType;
    3054           0 :   switch(breakType) {
    3055           0 :     case StyleClear::Left:
    3056             :       if (StyleClear::Right == aNewBreakType ||
    3057             :           StyleClear::Both == aNewBreakType) {
    3058             :         breakType = StyleClear::Both;
    3059             :       }
    3060             :       break;
    3061           0 :     case StyleClear::Right:
    3062             :       if (StyleClear::Left == aNewBreakType ||
    3063             :           StyleClear::Both == aNewBreakType) {
    3064           0 :         breakType = StyleClear::Both;
    3065           0 :       }
    3066             :       break;
    3067           0 :     case StyleClear::None:
    3068           0 :       if (StyleClear::Left == aNewBreakType ||
    3069           0 :           StyleClear::Right == aNewBreakType ||
    3070             :           StyleClear::Both == aNewBreakType) {
    3071             :         breakType = aNewBreakType;
    3072             :       }
    3073           0 :       break;
    3074           0 :     default:
    3075           0 :       break;
    3076             :   }
    3077             :   return breakType;
    3078             : }
    3079           0 : 
    3080           0 : #ifdef MOZ_DUMP_PAINTING
    3081           0 : #include <stdio.h>
    3082           0 : 
    3083             : static bool gDumpEventList = false;
    3084             : 
    3085             : // nsLayoutUtils::PaintFrame() can call itself recursively, so rather than
    3086             : // maintaining a single paint count, we need a stack.
    3087             : StaticAutoPtr<nsTArray<int>> gPaintCountStack;
    3088           0 : 
    3089             : struct AutoNestedPaintCount {
    3090             :   AutoNestedPaintCount() {
    3091             :     gPaintCountStack->AppendElement(0);
    3092             :   }
    3093             :   ~AutoNestedPaintCount() {
    3094             :     gPaintCountStack->RemoveLastElement();
    3095             :   }
    3096             : };
    3097             : 
    3098           0 : #endif
    3099             : 
    3100             : nsIFrame*
    3101           0 : nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt, uint32_t aFlags)
    3102           0 : {
    3103           0 :   AUTO_PROFILER_LABEL("nsLayoutUtils::GetFrameForPoint", LAYOUT);
    3104           0 : 
    3105           0 :   nsresult rv;
    3106           0 :   AutoTArray<nsIFrame*,8> outFrames;
    3107             :   rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames, aFlags);
    3108             :   NS_ENSURE_SUCCESS(rv, nullptr);
    3109             :   return outFrames.Length() ? outFrames.ElementAt(0) : nullptr;
    3110             : }
    3111             : 
    3112           0 : nsresult
    3113             : nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
    3114           0 :                                 nsTArray<nsIFrame*> &aOutFrames,
    3115             :                                 uint32_t aFlags)
    3116             : {
    3117           0 :   AUTO_PROFILER_LABEL("nsLayoutUtils::GetFramesForArea", LAYOUT);
    3118           0 : 
    3119           0 :   nsDisplayListBuilder builder(aFrame,
    3120           0 :                                nsDisplayListBuilderMode::EVENT_DELIVERY,
    3121             :                                false);
    3122             :   builder.BeginFrame();
    3123             :   nsDisplayList list;
    3124           0 : 
    3125             :   if (aFlags & IGNORE_PAINT_SUPPRESSION) {
    3126             :     builder.IgnorePaintSuppression();
    3127             :   }
    3128           0 : 
    3129             :   if (aFlags & IGNORE_ROOT_SCROLL_FRAME) {
    3130             :     nsIFrame* rootScrollFrame = aFrame->PresShell()->GetRootScrollFrame();
    3131             :     if (rootScrollFrame) {
    3132           0 :       builder.SetIgnoreScrollFrame(rootScrollFrame);
    3133           0 :     }
    3134           0 :   }
    3135             :   if (aFlags & IGNORE_CROSS_DOC) {
    3136           0 :     builder.SetDescendIntoSubdocuments(false);
    3137           0 :   }
    3138             : 
    3139             :   builder.SetHitTestIsForVisibility(aFlags & ONLY_VISIBLE);
    3140           0 : 
    3141           0 :   builder.EnterPresShell(aFrame);
    3142           0 : 
    3143           0 :   builder.SetVisibleRect(aRect);
    3144             :   builder.SetDirtyRect(aRect);
    3145             : 
    3146           0 :   aFrame->BuildDisplayListForStackingContext(&builder, &list);
    3147             :   builder.LeavePresShell(aFrame, nullptr);
    3148             : 
    3149             : #ifdef MOZ_DUMP_PAINTING
    3150           0 :   if (gDumpEventList) {
    3151             :     fprintf_stderr(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
    3152           0 : 
    3153             :     std::stringstream ss;
    3154           0 :     nsFrame::PrintDisplayList(&builder, list, ss);
    3155           0 :     print_stderr(ss);
    3156             :   }
    3157           0 : #endif
    3158           0 : 
    3159             :   nsDisplayItem::HitTestState hitTestState;
    3160             :   list.HitTest(&builder, aRect, &hitTestState, &aOutFrames);
    3161           0 :   list.DeleteAll(&builder);
    3162           0 :   builder.EndFrame();
    3163             :   return NS_OK;
    3164           0 : }
    3165           0 : 
    3166           0 : // aScrollFrameAsScrollable must be non-nullptr and queryable to an nsIFrame
    3167             : FrameMetrics
    3168             : nsLayoutUtils::CalculateBasicFrameMetrics(nsIScrollableFrame* aScrollFrame) {
    3169             :   nsIFrame* frame = do_QueryFrame(aScrollFrame);
    3170           0 :   MOZ_ASSERT(frame);
    3171           0 : 
    3172           0 :   // Calculate the metrics necessary for calculating the displayport.
    3173           0 :   // This code has a lot in common with the code in ComputeFrameMetrics();
    3174           0 :   // we may want to refactor this at some point.
    3175             :   FrameMetrics metrics;
    3176             :   nsPresContext* presContext = frame->PresContext();
    3177             :   nsIPresShell* presShell = presContext->PresShell();
    3178             :   CSSToLayoutDeviceScale deviceScale = presContext->CSSToDevPixelScale();
    3179           0 :   float resolution = 1.0f;
    3180           0 :   if (frame == presShell->GetRootScrollFrame()) {
    3181           0 :     // Only the root scrollable frame for a given presShell should pick up
    3182             :     // the presShell's resolution. All the other frames are 1.0.
    3183             :     resolution = presShell->GetResolution();
    3184             :   }
    3185             :   // Note: unlike in ComputeFrameMetrics(), we don't know the full cumulative
    3186           0 :   // resolution including FrameMetrics::mExtraResolution, because layout hasn't
    3187           0 :   // chosen a resolution to paint at yet. However, the display port calculation
    3188           0 :   // divides out mExtraResolution anyways, so we get the correct result by
    3189           0 :   // setting the mCumulativeResolution to everything except the extra resolution
    3190           0 :   // and leaving mExtraResolution at 1.
    3191           0 :   LayoutDeviceToLayerScale2D cumulativeResolution(
    3192             :       presShell->GetCumulativeResolution()
    3193             :     * nsLayoutUtils::GetTransformToAncestorScale(frame));
    3194           0 : 
    3195             :   LayerToParentLayerScale layerToParentLayerScale(1.0f);
    3196             :   metrics.SetDevPixelsPerCSSPixel(deviceScale);
    3197             :   metrics.SetPresShellResolution(resolution);
    3198             :   metrics.SetCumulativeResolution(cumulativeResolution);
    3199             :   metrics.SetZoom(deviceScale * cumulativeResolution * layerToParentLayerScale);
    3200             : 
    3201             :   // Only the size of the composition bounds is relevant to the
    3202             :   // displayport calculation, not its origin.
    3203           0 :   nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(frame);
    3204           0 :   LayoutDeviceToParentLayerScale2D compBoundsScale;
    3205             :   if (frame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
    3206           0 :     if (presContext->GetParentPresContext()) {
    3207           0 :       float res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
    3208           0 :       compBoundsScale = LayoutDeviceToParentLayerScale2D(
    3209           0 :           LayoutDeviceToParentLayerScale(res));
    3210           0 :     }
    3211             :   } else {
    3212             :     compBoundsScale = cumulativeResolution * layerToParentLayerScale;
    3213             :   }
    3214           0 :   metrics.SetCompositionBounds(
    3215           0 :       LayoutDeviceRect::FromAppUnits(nsRect(nsPoint(0, 0), compositionSize),
    3216           0 :                                        presContext->AppUnitsPerDevPixel())
    3217           0 :       * compBoundsScale);
    3218           0 : 
    3219           0 :   metrics.SetRootCompositionSize(
    3220           0 :       nsLayoutUtils::CalculateRootCompositionSize(frame, false, metrics));
    3221             : 
    3222             :   metrics.SetScrollOffset(CSSPoint::FromAppUnits(
    3223           0 :       aScrollFrame->GetScrollPosition()));
    3224             : 
    3225             :   metrics.SetScrollableRect(CSSRect::FromAppUnits(
    3226           0 :       nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrame, nullptr)));
    3227           0 : 
    3228           0 :   return metrics;
    3229             : }
    3230             : 
    3231           0 : bool
    3232             : nsLayoutUtils::CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame,
    3233           0 :                                                  RepaintMode aRepaintMode) {
    3234           0 :   nsIFrame* frame = do_QueryFrame(aScrollFrame);
    3235             :   MOZ_ASSERT(frame);
    3236           0 :   nsIContent* content = frame->GetContent();
    3237           0 :   MOZ_ASSERT(content);
    3238             : 
    3239           0 :   FrameMetrics metrics = CalculateBasicFrameMetrics(aScrollFrame);
    3240             :   ScreenMargin displayportMargins = apz::CalculatePendingDisplayPort(
    3241             :       metrics, ParentLayerPoint(0.0f, 0.0f));
    3242             :   nsIPresShell* presShell = frame->PresContext()->GetPresShell();
    3243           0 :   return nsLayoutUtils::SetDisplayPortMargins(
    3244             :       content, presShell, displayportMargins, 0, aRepaintMode);
    3245           0 : }
    3246           0 : 
    3247           0 : bool
    3248           0 : nsLayoutUtils::MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
    3249             :                                       nsIFrame* aScrollFrame,
    3250           0 :                                       RepaintMode aRepaintMode)
    3251             : {
    3252           0 :   nsIContent* content = aScrollFrame->GetContent();
    3253           0 :   nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
    3254             :   if (!content || !scrollableFrame) {
    3255           0 :     return false;
    3256             :   }
    3257             : 
    3258             :   bool haveDisplayPort = HasDisplayPort(content);
    3259           0 : 
    3260             :   // We perform an optimization where we ensure that at least one
    3261             :   // async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
    3262             :   // If that's not the case yet, and we are async-scrollable, we will get a
    3263           0 :   // displayport.
    3264           0 :   if (aBuilder.IsPaintingToWindow() &&
    3265           0 :       nsLayoutUtils::AsyncPanZoomEnabled(aScrollFrame) &&
    3266             :       !aBuilder.HaveScrollableDisplayPort() &&
    3267             :       scrollableFrame->WantAsyncScroll()) {
    3268             : 
    3269           0 :     // If we don't already have a displayport, calculate and set one.
    3270             :     if (!haveDisplayPort) {
    3271             :       CalculateAndSetDisplayPortMargins(scrollableFrame, aRepaintMode);
    3272             : #ifdef DEBUG
    3273             :       haveDisplayPort = HasDisplayPort(content);
    3274             :       MOZ_ASSERT(haveDisplayPort, "should have a displayport after having just set it");
    3275           0 : #endif
    3276           0 :     }
    3277           0 : 
    3278           0 :     // Record that the we now have a scrollable display port.
    3279             :     aBuilder.SetHaveScrollableDisplayPort();
    3280             :     return true;
    3281           0 :   }
    3282           0 :   return false;
    3283             : }
    3284           0 : 
    3285           0 : nsIScrollableFrame*
    3286             : nsLayoutUtils::GetAsyncScrollableAncestorFrame(nsIFrame* aTarget)
    3287             : {
    3288             :   uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
    3289             :                  | nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE
    3290           0 :                  | nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT;
    3291           0 :   return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags);
    3292             : }
    3293             : 
    3294             : void
    3295             : nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(nsIFrame* aFrame,
    3296             :                                                                   RepaintMode aRepaintMode)
    3297           0 : {
    3298             :   nsIFrame* frame = aFrame;
    3299             :   while (frame) {
    3300             :     frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
    3301           0 :     if (!frame) {
    3302           0 :       break;
    3303             :     }
    3304             :     nsIScrollableFrame* scrollAncestor = GetAsyncScrollableAncestorFrame(frame);
    3305             :     if (!scrollAncestor) {
    3306           0 :       break;
    3307             :     }
    3308             :     frame = do_QueryFrame(scrollAncestor);
    3309           0 :     MOZ_ASSERT(frame);
    3310           0 :     MOZ_ASSERT(scrollAncestor->WantAsyncScroll() ||
    3311           0 :       frame->PresShell()->GetRootScrollFrame() == frame);
    3312           0 :     if (nsLayoutUtils::AsyncPanZoomEnabled(frame) &&
    3313             :         !nsLayoutUtils::HasDisplayPort(frame->GetContent())) {
    3314             :       nsLayoutUtils::SetDisplayPortMargins(
    3315           0 :         frame->GetContent(), frame->PresShell(), ScreenMargin(), 0,
    3316           0 :         aRepaintMode);
    3317             :     }
    3318             :   }
    3319           0 : }
    3320           0 : 
    3321           0 : bool
    3322             : nsLayoutUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
    3323           0 :   nsIFrame* aFrame, nsDisplayListBuilder& aBuilder)
    3324           0 : {
    3325           0 :   nsIScrollableFrame* sf = do_QueryFrame(aFrame);
    3326           0 :   if (sf) {
    3327           0 :     if (MaybeCreateDisplayPort(aBuilder, aFrame, RepaintMode::Repaint)) {
    3328             :       return true;
    3329             :     }
    3330           0 :   }
    3331             :   if (aFrame->IsPlaceholderFrame()) {
    3332             :     nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
    3333           0 :     if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(
    3334             :           placeholder->GetOutOfFlowFrame(), aBuilder)) {
    3335             :       return true;
    3336           0 :     }
    3337           0 :   }
    3338           0 :   if (aFrame->IsSubDocumentFrame()) {
    3339             :     nsIPresShell* presShell =
    3340             :       static_cast<nsSubDocumentFrame*>(aFrame)->GetSubdocumentPresShellForPainting(0);
    3341             :     nsIFrame* root = presShell ? presShell->GetRootFrame() : nullptr;
    3342           0 :     if (root) {
    3343           0 :       if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(root, aBuilder)) {
    3344           0 :         return true;
    3345             :       }
    3346             :     }
    3347             :   }
    3348             :   if (aFrame->IsDeckFrame()) {
    3349           0 :     // only descend the visible card of a decks
    3350             :     nsIFrame* child = static_cast<nsDeckFrame*>(aFrame)->GetSelectedBox();
    3351           0 :     if (child) {
    3352           0 :       return MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder);
    3353           0 :     }
    3354           0 :   }
    3355             : 
    3356             :   for (nsIFrame* child : aFrame->PrincipalChildList()) {
    3357             :     if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder)) {
    3358             :       return true;
    3359           0 :     }
    3360             :   }
    3361           0 : 
    3362           0 :   return false;
    3363           0 : }
    3364             : 
    3365             : void
    3366             : nsLayoutUtils::ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame)
    3367           0 : {
    3368           0 :   nsIFrame* frame = aFrame;
    3369           0 :   while (frame) {
    3370             :     frame = nsLayoutUtils::GetCrossDocParentFrame(frame);
    3371             :     if (!frame) {
    3372             :       break;
    3373           0 :     }
    3374             :     nsIScrollableFrame* scrollAncestor = GetAsyncScrollableAncestorFrame(frame);
    3375             :     if (!scrollAncestor) {
    3376             :       break;
    3377           0 :     }
    3378             :     frame = do_QueryFrame(scrollAncestor);
    3379           0 :     MOZ_ASSERT(frame);
    3380           0 :     if (!frame) {
    3381           0 :       break;
    3382           0 :     }
    3383             :     MOZ_ASSERT(scrollAncestor->WantAsyncScroll() ||
    3384             :       frame->PresShell()->GetRootScrollFrame() == frame);
    3385           0 :     if (nsLayoutUtils::HasDisplayPort(frame->GetContent())) {
    3386           0 :       scrollAncestor->TriggerDisplayPortExpiration();
    3387             :       // Stop after the first trigger. If it failed, there's no point in
    3388             :       // continuing because all the rest of the frames we encounter are going
    3389           0 :       // to be ancestors of |scrollAncestor| which will keep its displayport.
    3390           0 :       // If the trigger succeeded, we stop because when the trigger executes
    3391           0 :       // it will call this function again to trigger the next ancestor up the
    3392             :       // chain.
    3393             :       break;
    3394           0 :     }
    3395             :   }
    3396           0 : }
    3397           0 : 
    3398             : void
    3399             : nsLayoutUtils::AddExtraBackgroundItems(nsDisplayListBuilder& aBuilder,
    3400             :                                        nsDisplayList& aList,
    3401             :                                        nsIFrame* aFrame,
    3402             :                                        const nsRect& aCanvasArea,
    3403             :                                        const nsRegion& aVisibleRegion,
    3404           0 :                                        nscolor aBackstop)
    3405             : {
    3406             :   LayoutFrameType frameType = aFrame->Type();
    3407           0 :   nsPresContext* presContext = aFrame->PresContext();
    3408             :   nsIPresShell* presShell = presContext->PresShell();
    3409             : 
    3410           0 :   // For the viewport frame in print preview/page layout we want to paint
    3411             :   // the grey background behind the page, not the canvas color.
    3412             :   if (frameType == LayoutFrameType::Viewport &&
    3413             :       nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
    3414             :     nsRect bounds = nsRect(aBuilder.ToReferenceFrame(aFrame),
    3415             :                            aFrame->GetSize());
    3416             :     nsDisplayListBuilder::AutoBuildingDisplayList
    3417           0 :       buildingDisplayList(&aBuilder, aFrame, bounds, bounds, false);
    3418           0 :     presShell->AddPrintPreviewBackgroundItem(aBuilder, aList, aFrame, bounds);
    3419           0 :   } else if (frameType != LayoutFrameType::Page) {
    3420             :     // For printing, this function is first called on an nsPageFrame, which
    3421             :     // creates a display list with a PageContent item. The PageContent item's
    3422             :     // paint function calls this function on the nsPageFrame's child which is
    3423           0 :     // an nsPageContentFrame. We only want to add the canvas background color
    3424           0 :     // item once, for the nsPageContentFrame.
    3425           0 : 
    3426           0 :     // Add the canvas background color to the bottom of the list. This
    3427             :     // happens after we've built the list so that AddCanvasBackgroundColorItem
    3428           0 :     // can monkey with the contents if necessary.
    3429           0 :     nsRect canvasArea = aVisibleRegion.GetBounds();
    3430           0 :     canvasArea.IntersectRect(aCanvasArea, canvasArea);
    3431             :     nsDisplayListBuilder::AutoBuildingDisplayList
    3432             :       buildingDisplayList(&aBuilder, aFrame, canvasArea, canvasArea, false);
    3433             :     presShell->AddCanvasBackgroundColorItem(
    3434             :       aBuilder, aList, aFrame, canvasArea, aBackstop);
    3435             :   }
    3436             : }
    3437             : 
    3438             : /**
    3439             :  * Returns a retained display list builder for frame |aFrame|. If there is no
    3440           0 :  * retained display list builder property set for the frame, and if the flag
    3441           0 :  * |aRetainingEnabled| is true, a new retained display list builder is created,
    3442             :  * stored as a property for the frame, and returned.
    3443           0 :  */
    3444             : static RetainedDisplayListBuilder*
    3445           0 : GetOrCreateRetainedDisplayListBuilder(nsIFrame* aFrame, bool aRetainingEnabled,
    3446             :                                       bool aBuildCaret)
    3447           0 : {
    3448             :   RetainedDisplayListBuilder* retainedBuilder =
    3449             :     aFrame->GetProperty(RetainedDisplayListBuilder::Cached());
    3450             : 
    3451             :   if (retainedBuilder) {
    3452             :     return retainedBuilder;
    3453             :   }
    3454             : 
    3455             :   if (aRetainingEnabled) {
    3456           0 :     retainedBuilder =
    3457             :       new RetainedDisplayListBuilder(aFrame, nsDisplayListBuilderMode::PAINTING,
    3458             :                                      aBuildCaret);
    3459             :     aFrame->SetProperty(RetainedDisplayListBuilder::Cached(), retainedBuilder);
    3460           0 :   }
    3461             : 
    3462           0 :   return retainedBuilder;
    3463             : }
    3464             : 
    3465             : nsresult
    3466           0 : nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
    3467           0 :                           const nsRegion& aDirtyRegion, nscolor aBackstop,
    3468             :                           nsDisplayListBuilderMode aBuilderMode,
    3469           0 :                           PaintFrameFlags aFlags)
    3470           0 : {
    3471             :   AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame", GRAPHICS);
    3472             :   typedef RetainedDisplayListBuilder::PartialUpdateResult PartialUpdateResult;
    3473             : 
    3474             : #ifdef MOZ_DUMP_PAINTING
    3475             :   if (!gPaintCountStack) {
    3476             :     gPaintCountStack = new nsTArray<int>();
    3477           0 :     ClearOnShutdown(&gPaintCountStack);
    3478             : 
    3479             :     gPaintCountStack->AppendElement(0);
    3480             :   }
    3481             :   ++gPaintCountStack->LastElement();
    3482           0 :   AutoNestedPaintCount nestedPaintCount;
    3483             : #endif
    3484             : 
    3485             :   if (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) {
    3486           0 :     nsView* view = aFrame->GetView();
    3487           0 :     if (!(view && view->GetWidget() && GetDisplayRootFrame(aFrame) == aFrame)) {
    3488           0 :       aFlags &= ~PaintFrameFlags::PAINT_WIDGET_LAYERS;
    3489             :       NS_ASSERTION(aRenderingContext, "need a rendering context");
    3490           0 :     }
    3491             :   }
    3492           0 : 
    3493           0 :   nsPresContext* presContext = aFrame->PresContext();
    3494             :   nsIPresShell* presShell = presContext->PresShell();
    3495             :   nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
    3496           0 :   if (!rootPresContext) {
    3497           0 :     return NS_OK;
    3498           0 :   }
    3499           0 : 
    3500           0 :   TimeStamp startBuildDisplayList = TimeStamp::Now();
    3501             : 
    3502             :   const bool buildCaret = !(aFlags & PaintFrameFlags::PAINT_HIDE_CARET);
    3503             :   const bool isForPainting = (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) &&
    3504           0 :     aBuilderMode == nsDisplayListBuilderMode::PAINTING;
    3505           0 : 
    3506           0 :   // Only allow retaining for painting when preffed on, and for root frames (since
    3507           0 :   // the modified frame tracking is per-root-frame).
    3508             :   const bool retainingEnabled =
    3509             :     isForPainting && AreRetainedDisplayListsEnabled() && !aFrame->GetParent();
    3510             : 
    3511           0 :   RetainedDisplayListBuilder* retainedBuilder =
    3512             :     GetOrCreateRetainedDisplayListBuilder(aFrame, retainingEnabled, buildCaret);
    3513           0 : 
    3514           0 :   // Only use the retained display list builder if the retaining is currently
    3515           0 :   // enabled. This check is needed because it is possible that the pref has been
    3516             :   // disabled after creating the retained display list builder.
    3517             :   const bool useRetainedBuilder = retainedBuilder && retainingEnabled;
    3518             : 
    3519             :   Maybe<nsDisplayListBuilder> nonRetainedBuilder;
    3520           0 :   Maybe<nsDisplayList> nonRetainedList;
    3521             :   nsDisplayListBuilder* builderPtr = nullptr;
    3522             :   nsDisplayList* listPtr = nullptr;
    3523           0 : 
    3524             :   if (useRetainedBuilder) {
    3525             :     builderPtr = retainedBuilder->Builder();
    3526             :     listPtr = retainedBuilder->List();
    3527             :   } else {
    3528           0 :     nonRetainedBuilder.emplace(aFrame, aBuilderMode, buildCaret);
    3529             :     builderPtr = nonRetainedBuilder.ptr();
    3530           0 :     nonRetainedList.emplace();
    3531           0 :     listPtr = nonRetainedList.ptr();
    3532           0 :   }
    3533           0 : 
    3534             :   // Retained builder exists, but display list retaining is disabled.
    3535           0 :   if (!useRetainedBuilder && retainedBuilder) {
    3536           0 :     // Clear the modified frames lists and frame properties.
    3537           0 :     retainedBuilder->ClearFramesWithProps();
    3538             : 
    3539           0 :     // Clear the retained display list.
    3540           0 :     retainedBuilder->List()->DeleteAll(retainedBuilder->Builder());
    3541           0 :   }
    3542           0 : 
    3543             :   nsDisplayListBuilder& builder = *builderPtr;
    3544             :   nsDisplayList& list = *listPtr;
    3545             : 
    3546           0 :   builder.BeginFrame();
    3547             : 
    3548           0 :   if (aFlags & PaintFrameFlags::PAINT_IN_TRANSFORM) {
    3549             :     builder.SetInTransform(true);
    3550             :   }
    3551           0 :   if (aFlags & PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES) {
    3552             :     builder.SetSyncDecodeImages(true);
    3553             :   }
    3554           0 :   if (aFlags & (PaintFrameFlags::PAINT_WIDGET_LAYERS |
    3555           0 :                 PaintFrameFlags::PAINT_TO_WINDOW)) {
    3556             :     builder.SetPaintingToWindow(true);
    3557           0 :   }
    3558             :   if (aFlags & PaintFrameFlags::PAINT_IGNORE_SUPPRESSION) {
    3559           0 :     builder.IgnorePaintSuppression();
    3560             :   }
    3561             : 
    3562           0 :   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    3563             :   if (rootScrollFrame && !aFrame->GetParent()) {
    3564             :     nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
    3565           0 :     MOZ_ASSERT(rootScrollableFrame);
    3566             :     nsRect displayPortBase = aFrame->GetVisualOverflowRectRelativeToSelf();
    3567             :     nsRect temp = displayPortBase;
    3568             :     Unused << rootScrollableFrame->DecideScrollableLayer(&builder, &displayPortBase, &temp,
    3569           0 :                 /* aSetBase = */ true);
    3570           0 :   }
    3571             : 
    3572             :   nsRegion visibleRegion;
    3573           0 :   if (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) {
    3574           0 :     // This layer tree will be reused, so we'll need to calculate it
    3575           0 :     // for the whole "visible" area of the window
    3576           0 :     //
    3577           0 :     // |ignoreViewportScrolling| and |usingDisplayPort| are persistent
    3578           0 :     // document-rendering state.  We rely on PresShell to flush
    3579           0 :     // retained layers as needed when that persistent state changes.
    3580           0 :     visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf();
    3581             :   } else {
    3582             :     visibleRegion = aDirtyRegion;
    3583           0 :   }
    3584           0 : 
    3585             :   // If the root has embedded plugins, flag the builder so we know we'll need
    3586             :   // to update plugin geometry after painting.
    3587             :   if ((aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) &&
    3588             :       !(aFlags & PaintFrameFlags::PAINT_DOCUMENT_RELATIVE) &&
    3589             :       rootPresContext->NeedToComputePluginGeometryUpdates()) {
    3590             :     builder.SetWillComputePluginGeometry(true);
    3591           0 :   }
    3592             : 
    3593             :   nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
    3594             :   bool ignoreViewportScrolling =
    3595             :     aFrame->GetParent() ? false : presShell->IgnoringViewportScrolling();
    3596             :   if (ignoreViewportScrolling && rootScrollFrame) {
    3597             :     nsIScrollableFrame* rootScrollableFrame =
    3598           0 :       presShell->GetRootScrollFrameAsScrollable();
    3599           0 :     if (aFlags & PaintFrameFlags::PAINT_DOCUMENT_RELATIVE) {
    3600           0 :       // Make visibleRegion and aRenderingContext relative to the
    3601             :       // scrolled frame instead of the root frame.
    3602             :       nsPoint pos = rootScrollableFrame->GetScrollPosition();
    3603             :       visibleRegion.MoveBy(-pos);
    3604           0 :       if (aRenderingContext) {
    3605             :         gfxPoint devPixelOffset =
    3606           0 :           nsLayoutUtils::PointToGfxPoint(pos,
    3607           0 :                                          presContext->AppUnitsPerDevPixel());
    3608             :         aRenderingContext->SetMatrixDouble(
    3609           0 :           aRenderingContext->CurrentMatrixDouble().PreTranslate(devPixelOffset));
    3610           0 :       }
    3611             :     }
    3612             :     builder.SetIgnoreScrollFrame(rootScrollFrame);
    3613           0 : 
    3614           0 :     nsCanvasFrame* canvasFrame =
    3615           0 :       do_QueryFrame(rootScrollableFrame->GetScrolledFrame());
    3616             :     if (canvasFrame) {
    3617             :       // Use UnionRect here to ensure that areas where the scrollbars
    3618           0 :       // were are still filled with the background color.
    3619             :       canvasArea.UnionRect(canvasArea,
    3620           0 :         canvasFrame->CanvasArea() + builder.ToReferenceFrame(canvasFrame));
    3621             :     }
    3622             :   }
    3623           0 : 
    3624             :   builder.ClearHaveScrollableDisplayPort();
    3625             :   if (builder.IsPaintingToWindow()) {
    3626           0 :     MaybeCreateDisplayPortInFirstScrollFrameEncountered(aFrame, builder);
    3627           0 :   }
    3628             : 
    3629             :   nsRect visibleRect = visibleRegion.GetBounds();
    3630             :   PartialUpdateResult updateState = PartialUpdateResult::Failed;
    3631           0 : 
    3632             :   {
    3633             :     AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame:BuildDisplayList",
    3634             :                         GRAPHICS);
    3635           0 :     AUTO_PROFILER_TRACING("Paint", "DisplayList");
    3636           0 : 
    3637           0 :     PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
    3638             :     TimeStamp dlStart = TimeStamp::Now();
    3639             : 
    3640           0 :     {
    3641           0 :       // If a scrollable container layer is created in nsDisplayList::PaintForFrame,
    3642             :       // it will be the scroll parent for display items that are built in the
    3643             :       // BuildDisplayListForStackingContext call below. We need to set the scroll
    3644           0 :       // parent on the display list builder while we build those items, so that they
    3645             :       // can pick up their scroll parent's id.
    3646           0 :       ViewID id = FrameMetrics::NULL_SCROLL_ID;
    3647             :       if (ignoreViewportScrolling && presContext->IsRootContentDocument()) {
    3648           0 :         if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
    3649           0 :           if (nsIContent* content = rootScrollFrame->GetContent()) {
    3650             :             id = nsLayoutUtils::FindOrCreateIDFor(content);
    3651             :           }
    3652             :         }
    3653             :       }
    3654             :       else if (presShell->GetDocument() && presShell->GetDocument()->IsRootDisplayDocument()
    3655             :           && !presShell->GetRootScrollFrame()) {
    3656             :         // In cases where the root document is a XUL document, we want to take
    3657           0 :         // the ViewID from the root element, as that will be the ViewID of the
    3658           0 :         // root APZC in the tree. Skip doing this in cases where we know
    3659           0 :         // nsGfxScrollFrame::BuilDisplayList will do it instead.
    3660           0 :         if (dom::Element* element = presShell->GetDocument()->GetDocumentElement()) {
    3661           0 :           id = nsLayoutUtils::FindOrCreateIDFor(element);
    3662             :         }
    3663             :       }
    3664             : 
    3665           0 :       nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
    3666           0 : 
    3667             :       builder.SetVisibleRect(visibleRect);
    3668             :       builder.SetIsBuilding(true);
    3669             :       builder.SetAncestorHasApzAwareEventHandler(
    3670             :           gfxPlatform::AsyncPanZoomEnabled() &&
    3671           0 :           nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell));
    3672           0 : 
    3673             :       DisplayListChecker beforeMergeChecker;
    3674             :       DisplayListChecker toBeMergedChecker;
    3675             :       DisplayListChecker afterMergeChecker;
    3676           0 : 
    3677             :       // Attempt to do a partial build and merge into the existing list.
    3678           0 :       // This calls BuildDisplayListForStacking context on a subset of the
    3679           0 :       // viewport.
    3680           0 :       if (useRetainedBuilder) {
    3681           0 :         if (gfxPrefs::LayoutVerifyRetainDisplayList()) {
    3682           0 :           beforeMergeChecker.Set(&list, "BM");
    3683             :         }
    3684           0 :         updateState = retainedBuilder->AttemptPartialUpdate(
    3685           0 :           aBackstop, beforeMergeChecker ? &toBeMergedChecker : nullptr);
    3686           0 :         if ((updateState != PartialUpdateResult::Failed) && beforeMergeChecker) {
    3687             :           afterMergeChecker.Set(&list, "AM");
    3688             :         }
    3689             :       }
    3690             : 
    3691           0 :       if ((updateState != PartialUpdateResult::Failed) &&
    3692           0 :           (gfxPrefs::LayoutDisplayListBuildTwice() || afterMergeChecker)) {
    3693           0 :         updateState = PartialUpdateResult::Failed;
    3694             :         if (gfxPrefs::LayersDrawFPS()) {
    3695           0 :           if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
    3696           0 :             if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
    3697           0 :               pt->dl2Ms() = (TimeStamp::Now() - dlStart).ToMilliseconds();
    3698           0 :             }
    3699             :           }
    3700             :         }
    3701             :         dlStart = TimeStamp::Now();
    3702           0 :       }
    3703           0 : 
    3704           0 :       if (updateState == PartialUpdateResult::Failed) {
    3705           0 :         list.DeleteAll(&builder);
    3706           0 :         builder.EnterPresShell(aFrame);
    3707           0 :         builder.SetDirtyRect(visibleRect);
    3708           0 :         builder.ClearRetainedWindowRegions();
    3709             :         aFrame->BuildDisplayListForStackingContext(&builder, &list);
    3710             :         AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
    3711             : 
    3712           0 :         builder.LeavePresShell(aFrame, &list);
    3713             :         updateState = PartialUpdateResult::Updated;
    3714             : 
    3715           0 :         if (afterMergeChecker) {
    3716           0 :           DisplayListChecker nonRetainedChecker(&list, "NR");
    3717           0 :           std::stringstream ss;
    3718           0 :           ss << "**** Differences between retained-after-merged (AM) and "
    3719           0 :              << "non-retained (NR) display lists:";
    3720           0 :           if (!nonRetainedChecker.CompareList(afterMergeChecker, ss)) {
    3721           0 :             ss << "\n\n*** non-retained display items:";
    3722             :             nonRetainedChecker.Dump(ss);
    3723           0 :             ss << "\n\n*** before-merge retained display items:";
    3724           0 :             beforeMergeChecker.Dump(ss);
    3725             :             ss << "\n\n*** to-be-merged retained display items:";
    3726           0 :             toBeMergedChecker.Dump(ss);
    3727           0 :             ss << "\n\n*** after-merge retained display items:";
    3728           0 :             afterMergeChecker.Dump(ss);
    3729             :             fprintf(stderr, "%s\n\n", ss.str().c_str());
    3730           0 : #ifdef DEBUG_FRAME_DUMP
    3731           0 :             fprintf(stderr, "*** Frame tree:\n");
    3732           0 :             aFrame->DumpFrameTree();
    3733           0 : #endif
    3734           0 :           }
    3735           0 :         }
    3736           0 :       }
    3737           0 :     }
    3738           0 : 
    3739           0 :     builder.SetIsBuilding(false);
    3740           0 :     builder.IncrementPresShellPaintCount(presShell);
    3741             : 
    3742           0 :     if (gfxPrefs::LayersDrawFPS()) {
    3743           0 :       if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
    3744             :         if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
    3745             :           pt->dlMs() = (TimeStamp::Now() - dlStart).ToMilliseconds();
    3746             :         }
    3747             :       }
    3748             :     }
    3749             :   }
    3750           0 : 
    3751           0 :   MOZ_ASSERT(updateState != PartialUpdateResult::Failed);
    3752             :   builder.Check();
    3753           0 : 
    3754           0 :   Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,
    3755           0 :                                  startBuildDisplayList);
    3756           0 : 
    3757             :   bool consoleNeedsDisplayList = gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint();
    3758             : #ifdef MOZ_DUMP_PAINTING
    3759             :   FILE* savedDumpFile = gfxUtils::sDumpPaintFile;
    3760             : #endif
    3761             : 
    3762           0 :   UniquePtr<std::stringstream> ss;
    3763           0 :   if (consoleNeedsDisplayList) {
    3764             :     ss = MakeUnique<std::stringstream>();
    3765           0 : #ifdef MOZ_DUMP_PAINTING
    3766           0 :     if (gfxEnv::DumpPaintToFile()) {
    3767             :       nsCString string("dump-");
    3768           0 :       // Include the process ID in the dump file name, to make sure that in an
    3769             :       // e10s setup different processes don't clobber each other's dump files.
    3770           0 :       string.AppendInt(getpid());
    3771             :       for (int paintCount : *gPaintCountStack) {
    3772             :         string.AppendLiteral("-");
    3773           0 :         string.AppendInt(paintCount);
    3774           0 :       }
    3775           0 :       string.AppendLiteral(".html");
    3776             :       gfxUtils::sDumpPaintFile = fopen(string.BeginReading(), "w");
    3777           0 :     } else {
    3778           0 :       gfxUtils::sDumpPaintFile = stderr;
    3779             :     }
    3780             :     if (gfxEnv::DumpPaintToFile()) {
    3781           0 :       *ss << "<html><head><script>\n"
    3782           0 :              "var array = {};\n"
    3783           0 :              "function ViewImage(index) { \n"
    3784           0 :              "  var image = document.getElementById(index);\n"
    3785             :              "  if (image.src) {\n"
    3786           0 :              "    image.removeAttribute('src');\n"
    3787           0 :              "  } else {\n"
    3788             :              "    image.src = array[index];\n"
    3789           0 :              "  }\n"
    3790             :              "}</script></head><body>";
    3791           0 :     }
    3792           0 : #endif
    3793             :     *ss << nsPrintfCString("Painting --- before optimization (dirty %d,%d,%d,%d):\n",
    3794             :             visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height).get();
    3795             :     nsFrame::PrintDisplayList(&builder, list, *ss, gfxEnv::DumpPaintToFile());
    3796             : 
    3797             :     if (gfxEnv::DumpPaint() || gfxEnv::DumpPaintItems()) {
    3798             :       // Flush stream now to avoid reordering dump output relative to
    3799             :       // messages dumped by PaintRoot below.
    3800             :       fprint_stderr(gfxUtils::sDumpPaintFile, *ss);
    3801           0 :       ss = MakeUnique<std::stringstream>();
    3802             :     }
    3803             :   }
    3804           0 : 
    3805           0 :   uint32_t flags = nsDisplayList::PAINT_DEFAULT;
    3806           0 :   if (aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) {
    3807             :     flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
    3808           0 :     if (!(aFlags & PaintFrameFlags::PAINT_DOCUMENT_RELATIVE)) {
    3809             :       nsIWidget *widget = aFrame->GetNearestWidget();
    3810             :       if (widget) {
    3811           0 :         // If we're finished building display list items for painting of the outermost
    3812           0 :         // pres shell, notify the widget about any toolbars we've encountered.
    3813             :         widget->UpdateThemeGeometries(builder.GetThemeGeometries());
    3814             :       }
    3815             :     }
    3816           0 :   }
    3817           0 :   if (aFlags & PaintFrameFlags::PAINT_EXISTING_TRANSACTION) {
    3818           0 :     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
    3819           0 :   }
    3820           0 :   if (aFlags & PaintFrameFlags::PAINT_NO_COMPOSITE) {
    3821           0 :     flags |= nsDisplayList::PAINT_NO_COMPOSITE;
    3822             :   }
    3823             :   if (aFlags & PaintFrameFlags::PAINT_COMPRESSED) {
    3824           0 :     flags |= nsDisplayList::PAINT_COMPRESSED;
    3825             :   }
    3826             :   if (updateState == PartialUpdateResult::NoChange &&
    3827             :       !aRenderingContext) {
    3828           0 :     flags |= nsDisplayList::PAINT_IDENTICAL_DISPLAY_LIST;
    3829           0 :   }
    3830             : 
    3831           0 :   TimeStamp paintStart = TimeStamp::Now();
    3832           0 :   RefPtr<LayerManager> layerManager
    3833             :     = list.PaintRoot(&builder, aRenderingContext, flags);
    3834           0 :   Telemetry::AccumulateTimeDelta(Telemetry::PAINT_RASTERIZE_TIME,
    3835           0 :                                  paintStart);
    3836             : 
    3837           0 :   builder.Check();
    3838           0 : 
    3839             :   if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
    3840             :     TimeStamp now = TimeStamp::Now();
    3841           0 :     float rasterizeTime = (now - paintStart).ToMilliseconds();
    3842             :     uint32_t pixelCount = layerManager->GetAndClearPaintedPixelCount();
    3843           0 :     static std::vector<std::pair<TimeStamp, uint32_t>> history;
    3844           0 :     if (pixelCount) {
    3845           0 :       history.push_back(std::make_pair(now, pixelCount));
    3846             :     }
    3847           0 :     uint32_t paintedInLastSecond = 0;
    3848             :     for (auto i = history.begin(); i != history.end(); i++) {
    3849           0 :       if ((now - i->first).ToMilliseconds() > 1000.0f) {
    3850           0 :         // more than 1000ms ago, don't count it
    3851           0 :         continue;
    3852           0 :       }
    3853           0 :       if (paintedInLastSecond == 0) {
    3854           0 :         // This is the first one in the last 1000ms, so drop everything earlier
    3855           0 :         history.erase(history.begin(), i);
    3856             :         i = history.begin();
    3857           0 :       }
    3858           0 :       paintedInLastSecond += i->second;
    3859           0 :       MOZ_ASSERT(paintedInLastSecond); // all historical pixel counts are > 0
    3860             :     }
    3861             :     printf_stderr("Painted %u pixels in %fms (%u in the last 1000ms)\n",
    3862             :         pixelCount, rasterizeTime, paintedInLastSecond);
    3863           0 :   }
    3864             : 
    3865           0 :   if (consoleNeedsDisplayList) {
    3866           0 :     *ss << "Painting --- after optimization:\n";
    3867             :     nsFrame::PrintDisplayList(&builder, list, *ss, gfxEnv::DumpPaintToFile());
    3868           0 : 
    3869           0 :     *ss << "Painting --- layer tree:\n";
    3870             :     if (layerManager) {
    3871           0 :       FrameLayerBuilder::DumpRetainedLayerTree(layerManager, *ss,
    3872           0 :                                                gfxEnv::DumpPaintToFile());
    3873             :     }
    3874             : 
    3875           0 :     fprint_stderr(gfxUtils::sDumpPaintFile, *ss);
    3876           0 : 
    3877           0 : #ifdef MOZ_DUMP_PAINTING
    3878             :     if (gfxEnv::DumpPaintToFile()) {
    3879           0 :       *ss << "</body></html>";
    3880           0 :     }
    3881           0 :     if (gfxEnv::DumpPaintToFile()) {
    3882           0 :       fclose(gfxUtils::sDumpPaintFile);
    3883             :     }
    3884             :     gfxUtils::sDumpPaintFile = savedDumpFile;
    3885           0 : #endif
    3886             : 
    3887             :     std::stringstream lsStream;
    3888           0 :     nsFrame::PrintDisplayList(&builder, list, lsStream);
    3889           0 :     if (layerManager->GetRoot()) {
    3890             :       layerManager->GetRoot()->SetDisplayListLog(lsStream.str().c_str());
    3891           0 :     }
    3892           0 :   }
    3893             : 
    3894           0 : #ifdef MOZ_DUMP_PAINTING
    3895             :   if (gfxPrefs::DumpClientLayers()) {
    3896             :     std::stringstream ss;
    3897           0 :     FrameLayerBuilder::DumpRetainedLayerTree(layerManager, ss, false);
    3898           0 :     print_stderr(ss);
    3899           0 :   }
    3900           0 : #endif
    3901             : 
    3902             :   // Update the widget's opaque region information. This sets
    3903             :   // glass boundaries on Windows. Also set up the window dragging region
    3904             :   // and plugin clip regions and bounds.
    3905           0 :   if ((aFlags & PaintFrameFlags::PAINT_WIDGET_LAYERS) &&
    3906           0 :       !(aFlags & PaintFrameFlags::PAINT_DOCUMENT_RELATIVE)) {
    3907           0 :     nsIWidget *widget = aFrame->GetNearestWidget();
    3908           0 :     if (widget) {
    3909             :       nsRegion opaqueRegion;
    3910             :       opaqueRegion.And(builder.GetWindowExcludeGlassRegion(), builder.GetWindowOpaqueRegion());
    3911             :       widget->UpdateOpaqueRegion(
    3912             :         LayoutDeviceIntRegion::FromUnknownRegion(
    3913             :           opaqueRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel())));
    3914             : 
    3915           0 :       widget->UpdateWindowDraggingRegion(builder.GetWindowDraggingRegion());
    3916           0 :     }
    3917           0 :   }
    3918           0 : 
    3919           0 :   if (builder.WillComputePluginGeometry()) {
    3920           0 :     // For single process compute and apply plugin geometry updates to plugin
    3921             :     // windows, then request composition. For content processes skip eveything
    3922           0 :     // except requesting composition. Geometry updates were calculated and
    3923           0 :     // shipped to the chrome process in nsDisplayList when the layer
    3924             :     // transaction completed.
    3925           0 :     if (XRE_IsParentProcess()) {
    3926             :       rootPresContext->ComputePluginGeometryUpdates(aFrame, &builder, &list);
    3927             :       // We're not going to get a WillPaintWindow event here if we didn't do
    3928             :       // widget invalidation, so just apply the plugin geometry update here
    3929           0 :       // instead. We could instead have the compositor send back an equivalent
    3930             :       // to WillPaintWindow, but it should be close enough to now not to matter.
    3931             :       if (layerManager && !layerManager->NeedsWidgetInvalidation()) {
    3932             :         rootPresContext->ApplyPluginGeometryUpdates();
    3933             :       }
    3934             :     }
    3935           0 : 
    3936           0 :     // We told the compositor thread not to composite when it received the
    3937             :     // transaction because we wanted to update plugins first. Schedule the
    3938             :     // composite now.
    3939             :     if (layerManager) {
    3940             :       layerManager->ScheduleComposite();
    3941           0 :     }
    3942           0 :   }
    3943             : 
    3944             :   builder.Check();
    3945             : 
    3946             :   {
    3947             :     AUTO_PROFILER_TRACING("Paint", "DisplayListResources");
    3948             : 
    3949           0 :     // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
    3950           0 :     if (!useRetainedBuilder) {
    3951             :       list.DeleteAll(&builder);
    3952             :     }
    3953             : 
    3954           0 :     builder.EndFrame();
    3955             :   }
    3956             :   return NS_OK;
    3957           0 : }
    3958             : 
    3959             : /**
    3960           0 :  * Uses a binary search for find where the cursor falls in the line of text
    3961           0 :  * It also keeps track of the part of the string that has already been measured
    3962             :  * so it doesn't have to keep measuring the same text over and over
    3963             :  *
    3964           0 :  * @param "aBaseWidth" contains the width in twips of the portion
    3965             :  * of the text that has already been measured, and aBaseInx contains
    3966             :  * the index of the text that has already been measured.
    3967             :  *
    3968             :  * @param aTextWidth returns the (in twips) the length of the text that falls
    3969             :  * before the cursor aIndex contains the index of the text where the cursor falls
    3970             :  */
    3971             : bool
    3972             : nsLayoutUtils::BinarySearchForPosition(DrawTarget* aDrawTarget,
    3973             :                                        nsFontMetrics& aFontMetrics,
    3974             :                         const char16_t* aText,
    3975             :                         int32_t    aBaseWidth,
    3976             :                         int32_t    aBaseInx,
    3977             :                         int32_t    aStartInx,
    3978             :                         int32_t    aEndInx,
    3979             :                         int32_t    aCursorPos,
    3980             :                         int32_t&   aIndex,
    3981             :                         int32_t&   aTextWidth)
    3982           0 : {
    3983             :   int32_t range = aEndInx - aStartInx;
    3984             :   if ((range == 1) || (range == 2 && NS_IS_HIGH_SURROGATE(aText[aStartInx]))) {
    3985             :     aIndex   = aStartInx + aBaseInx;
    3986             :     aTextWidth = nsLayoutUtils::AppUnitWidthOfString(aText, aIndex,
    3987             :                                                      aFontMetrics, aDrawTarget);
    3988             :     return true;
    3989             :   }
    3990             : 
    3991             :   int32_t inx = aStartInx + (range / 2);
    3992             : 
    3993           0 :   // Make sure we don't leave a dangling low surrogate
    3994           0 :   if (NS_IS_HIGH_SURROGATE(aText[inx-1]))
    3995           0 :     inx++;
    3996           0 : 
    3997             :   int32_t textWidth = nsLayoutUtils::AppUnitWidthOfString(aText, inx,
    3998           0 :                                                           aFontMetrics,
    3999             :                                                           aDrawTarget);
    4000             : 
    4001           0 :   int32_t fullWidth = aBaseWidth + textWidth;
    4002             :   if (fullWidth == aCursorPos) {
    4003             :     aTextWidth = textWidth;
    4004           0 :     aIndex = inx;
    4005           0 :     return true;
    4006             :   } else if (aCursorPos < fullWidth) {
    4007           0 :     aTextWidth = aBaseWidth;
    4008             :     if (BinarySearchForPosition(aDrawTarget, aFontMetrics, aText, aBaseWidth,
    4009           0 :                                 aBaseInx, aStartInx, inx, aCursorPos, aIndex,
    4010             :                                 aTextWidth)) {
    4011           0 :       return true;
    4012           0 :     }
    4013           0 :   } else {
    4014           0 :     aTextWidth = fullWidth;
    4015           0 :     if (BinarySearchForPosition(aDrawTarget, aFontMetrics, aText, aBaseWidth,
    4016           0 :                                 aBaseInx, inx, aEndInx, aCursorPos, aIndex,
    4017           0 :                                 aTextWidth)) {
    4018           0 :       return true;
    4019             :     }
    4020             :   }
    4021             :   return false;
    4022             : }
    4023             : 
    4024           0 : void
    4025           0 : nsLayoutUtils::AddBoxesForFrame(nsIFrame* aFrame,
    4026             :                                 nsLayoutUtils::BoxCallback* aCallback)
    4027             : {
    4028             :   nsAtom* pseudoType = aFrame->Style()->GetPseudo();
    4029             : 
    4030             :   if (pseudoType == nsCSSAnonBoxes::tableWrapper) {
    4031             :     AddBoxesForFrame(aFrame->PrincipalChildList().FirstChild(), aCallback);
    4032             :     if (aCallback->mIncludeCaptionBoxForTable) {
    4033             :       nsIFrame* kid = aFrame->GetChildList(nsIFrame::kCaptionList).FirstChild();
    4034             :       if (kid) {
    4035           0 :         AddBoxesForFrame(kid, aCallback);
    4036             :       }
    4037             :     }
    4038           0 :   } else if (pseudoType == nsCSSAnonBoxes::mozBlockInsideInlineWrapper ||
    4039             :              pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
    4040           0 :              pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
    4041           0 :     for (nsIFrame* kid : aFrame->PrincipalChildList()) {
    4042           0 :       AddBoxesForFrame(kid, aCallback);
    4043           0 :     }
    4044           0 :   } else {
    4045           0 :     aCallback->AddBox(aFrame);
    4046             :   }
    4047             : }
    4048           0 : 
    4049           0 : void
    4050           0 : nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
    4051           0 : {
    4052           0 :   while (aFrame) {
    4053           0 :     AddBoxesForFrame(aFrame, aCallback);
    4054             :     aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
    4055           0 :   }
    4056             : }
    4057           0 : 
    4058             : nsIFrame*
    4059             : nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame)
    4060           0 : {
    4061             :   while (aFrame) {
    4062           0 :     nsAtom* pseudoType = aFrame->Style()->GetPseudo();
    4063           0 : 
    4064           0 :     if (pseudoType == nsCSSAnonBoxes::tableWrapper) {
    4065             :       nsIFrame* f = GetFirstNonAnonymousFrame(aFrame->PrincipalChildList().FirstChild());
    4066           0 :       if (f) {
    4067             :         return f;
    4068             :       }
    4069           0 :       nsIFrame* kid = aFrame->GetChildList(nsIFrame::kCaptionList).FirstChild();
    4070             :       if (kid) {
    4071           0 :         f = GetFirstNonAnonymousFrame(kid);
    4072           0 :         if (f) {
    4073             :           return f;
    4074           0 :         }
    4075           0 :       }
    4076           0 :     } else if (pseudoType == nsCSSAnonBoxes::mozBlockInsideInlineWrapper ||
    4077             :                pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
    4078             :                pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
    4079           0 :       for (nsIFrame* kid : aFrame->PrincipalChildList()) {
    4080           0 :         nsIFrame* f = GetFirstNonAnonymousFrame(kid);
    4081           0 :         if (f) {
    4082           0 :           return f;
    4083             :         }
    4084             :       }
    4085             :     } else {
    4086           0 :       return aFrame;
    4087           0 :     }
    4088           0 : 
    4089           0 :     aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
    4090           0 :   }
    4091           0 :   return nullptr;
    4092           0 : }
    4093             : 
    4094           0 : struct BoxToRect : public nsLayoutUtils::BoxCallback {
    4095             :   nsIFrame* mRelativeTo;
    4096             :   nsLayoutUtils::RectCallback* mCallback;
    4097             :   uint32_t mFlags;
    4098             : 
    4099           0 :   BoxToRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
    4100             :             uint32_t aFlags)
    4101             :     : mRelativeTo(aRelativeTo), mCallback(aCallback), mFlags(aFlags) {}
    4102             : 
    4103             :   virtual void AddBox(nsIFrame* aFrame) override {
    4104             :     nsRect r;
    4105             :     nsIFrame* outer = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(aFrame, &r);
    4106             :     if (!outer) {
    4107             :       outer = aFrame;
    4108             :       switch (mFlags & nsLayoutUtils::RECTS_WHICH_BOX_MASK) {
    4109             :         case nsLayoutUtils::RECTS_USE_CONTENT_BOX:
    4110             :           r = aFrame->GetContentRectRelativeToSelf();
    4111           0 :           break;
    4112             :         case nsLayoutUtils::RECTS_USE_PADDING_BOX:
    4113           0 :           r = aFrame->GetPaddingRectRelativeToSelf();
    4114           0 :           break;
    4115           0 :         case nsLayoutUtils::RECTS_USE_MARGIN_BOX:
    4116           0 :           r = aFrame->GetMarginRectRelativeToSelf();
    4117           0 :           break;
    4118           0 :         default: // Use the border box
    4119             :           r = aFrame->GetRectRelativeToSelf();
    4120           0 :       }
    4121           0 :     }
    4122             :     if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
    4123           0 :       r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
    4124           0 :     } else {
    4125             :       r += outer->GetOffsetTo(mRelativeTo);
    4126           0 :     }
    4127           0 :     mCallback->AddRect(r);
    4128             :   }
    4129           0 : };
    4130             : 
    4131             : struct MOZ_RAII BoxToRectAndText : public BoxToRect {
    4132           0 :   Sequence<nsString>* mTextList;
    4133           0 : 
    4134             :   BoxToRectAndText(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
    4135           0 :                    Sequence<nsString>* aTextList, uint32_t aFlags)
    4136             :     : BoxToRect(aRelativeTo, aCallback, aFlags), mTextList(aTextList) {}
    4137           0 : 
    4138           0 :   static void AccumulateText(nsIFrame* aFrame, nsAString& aResult) {
    4139             :     MOZ_ASSERT(aFrame);
    4140             : 
    4141             :     // Get all the text in aFrame and child frames, while respecting
    4142             :     // the content offsets in each of the nsTextFrames.
    4143             :     if (aFrame->IsTextFrame()) {
    4144             :       nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
    4145             : 
    4146           0 :       nsIFrame::RenderedText renderedText = textFrame->GetRenderedText(
    4147             :         textFrame->GetContentOffset(),
    4148           0 :         textFrame->GetContentOffset() + textFrame->GetContentLength(),
    4149           0 :         nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
    4150             :         nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
    4151             : 
    4152             :       aResult.Append(renderedText.mString);
    4153           0 :     }
    4154           0 : 
    4155             :     for (nsIFrame* child = aFrame->PrincipalChildList().FirstChild();
    4156             :          child;
    4157           0 :          child = child->GetNextSibling()) {
    4158           0 :       AccumulateText(child, aResult);
    4159             :     }
    4160           0 :   }
    4161             : 
    4162           0 :   virtual void AddBox(nsIFrame* aFrame) override {
    4163             :     BoxToRect::AddBox(aFrame);
    4164             :     if (mTextList) {
    4165           0 :       nsString* textForFrame = mTextList->AppendElement(fallible);
    4166           0 :       if (textForFrame) {
    4167             :         AccumulateText(aFrame, *textForFrame);
    4168           0 :       }
    4169             :     }
    4170           0 :   }
    4171             : };
    4172           0 : 
    4173           0 : void
    4174           0 : nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
    4175           0 :                                  RectCallback* aCallback, uint32_t aFlags)
    4176           0 : {
    4177           0 :   BoxToRect converter(aRelativeTo, aCallback, aFlags);
    4178             :   GetAllInFlowBoxes(aFrame, &converter);
    4179             : }
    4180           0 : 
    4181             : void
    4182             : nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
    4183             :                                          RectCallback* aCallback,
    4184           0 :                                          Sequence<nsString>* aTextList,
    4185             :                                          uint32_t aFlags)
    4186             : {
    4187           0 :   BoxToRectAndText converter(aRelativeTo, aCallback, aTextList, aFlags);
    4188           0 :   GetAllInFlowBoxes(aFrame, &converter);
    4189           0 : }
    4190             : 
    4191             : nsLayoutUtils::RectAccumulator::RectAccumulator() : mSeenFirstRect(false) {}
    4192           0 : 
    4193             : void nsLayoutUtils::RectAccumulator::AddRect(const nsRect& aRect) {
    4194             :   mResultRect.UnionRect(mResultRect, aRect);
    4195             :   if (!mSeenFirstRect) {
    4196             :     mSeenFirstRect = true;
    4197           0 :     mFirstRect = aRect;
    4198           0 :   }
    4199           0 : }
    4200             : 
    4201           0 : nsLayoutUtils::RectListBuilder::RectListBuilder(DOMRectList* aList)
    4202             :   : mRectList(aList)
    4203           0 : {
    4204           0 : }
    4205           0 : 
    4206           0 : void nsLayoutUtils::RectListBuilder::AddRect(const nsRect& aRect) {
    4207           0 :   RefPtr<DOMRect> rect = new DOMRect(mRectList);
    4208             : 
    4209           0 :   rect->SetLayoutRect(aRect);
    4210             :   mRectList->Append(rect);
    4211           0 : }
    4212           0 : 
    4213             : nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame)
    4214           0 : {
    4215             :   return aFrame->PresShell()->GetRootFrame();
    4216           0 : }
    4217           0 : 
    4218             : nsRect
    4219           0 : nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
    4220           0 :                                       uint32_t aFlags) {
    4221           0 :   RectAccumulator accumulator;
    4222             :   GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
    4223           0 :   return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
    4224             :           : accumulator.mResultRect;
    4225           0 : }
    4226             : 
    4227             : nsRect
    4228             : nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
    4229           0 :                                        nsIFrame* aFrame,
    4230             :                                        uint32_t aFlags)
    4231           0 : {
    4232           0 :   const nsStyleText* textStyle = aFrame->StyleText();
    4233           0 :   if (!textStyle->HasTextShadow())
    4234           0 :     return aTextAndDecorationsRect;
    4235             : 
    4236             :   nsRect resultRect = aTextAndDecorationsRect;
    4237             :   int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
    4238           0 :   for (uint32_t i = 0; i < textStyle->mTextShadow->Length(); ++i) {
    4239             :     nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
    4240             :     nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
    4241             :     if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
    4242           0 :       continue;
    4243           0 : 
    4244           0 :     nsRect tmpRect(aTextAndDecorationsRect);
    4245             : 
    4246           0 :     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
    4247           0 :     tmpRect.Inflate(blur);
    4248           0 : 
    4249           0 :     resultRect.UnionRect(resultRect, tmpRect);
    4250           0 :   }
    4251           0 :   return resultRect;
    4252           0 : }
    4253             : 
    4254           0 : enum ObjectDimensionType { eWidth, eHeight };
    4255             : static nscoord
    4256           0 : ComputeMissingDimension(const nsSize& aDefaultObjectSize,
    4257           0 :                         const nsSize& aIntrinsicRatio,
    4258             :                         const Maybe<nscoord>& aSpecifiedWidth,
    4259           0 :                         const Maybe<nscoord>& aSpecifiedHeight,
    4260             :                         ObjectDimensionType aDimensionToCompute)
    4261           0 : {
    4262             :   // The "default sizing algorithm" computes the missing dimension as follows:
    4263             :   // (source: http://dev.w3.org/csswg/css-images-3/#default-sizing )
    4264             : 
    4265             :   // 1. "If the object has an intrinsic aspect ratio, the missing dimension of
    4266           0 :   //     the concrete object size is calculated using the intrinsic aspect
    4267             :   //     ratio and the present dimension."
    4268             :   if (aIntrinsicRatio.width > 0 && aIntrinsicRatio.height > 0) {
    4269             :     // Fill in the missing dimension using the intrinsic aspect ratio.
    4270             :     nscoord knownDimensionSize;
    4271             :     float ratio;
    4272             :     if (aDimensionToCompute == eWidth) {
    4273             :       knownDimensionSize = *aSpecifiedHeight;
    4274             :       ratio = aIntrinsicRatio.width / aIntrinsicRatio.height;
    4275             :     } else {
    4276             :       knownDimensionSize = *aSpecifiedWidth;
    4277             :       ratio = aIntrinsicRatio.height / aIntrinsicRatio.width;
    4278           0 :     }
    4279             :     return NSCoordSaturatingNonnegativeMultiply(knownDimensionSize, ratio);
    4280             :   }
    4281             : 
    4282           0 :   // 2. "Otherwise, if the missing dimension is present in the object’s
    4283           0 :   //     intrinsic dimensions, [...]"
    4284           0 :   // NOTE: *Skipping* this case, because we already know it's not true -- we're
    4285             :   // in this function because the missing dimension is *not* present in
    4286           0 :   // the object's intrinsic dimensions.
    4287           0 : 
    4288             :   // 3. "Otherwise, the missing dimension of the concrete object size is taken
    4289           0 :   //     from the default object size. "
    4290             :   return (aDimensionToCompute == eWidth) ?
    4291             :     aDefaultObjectSize.width : aDefaultObjectSize.height;
    4292             : }
    4293             : 
    4294             : /*
    4295             :  * This computes & returns the concrete object size of replaced content, if
    4296             :  * that content were to be rendered with "object-fit: none".  (Or, if the
    4297             :  * element has neither an intrinsic height nor width, this method returns an
    4298             :  * empty Maybe<> object.)
    4299             :  *
    4300           0 :  * As specced...
    4301             :  *   http://dev.w3.org/csswg/css-images-3/#valdef-object-fit-none
    4302             :  * ..we use "the default sizing algorithm with no specified size,
    4303             :  * and a default object size equal to the replaced element's used width and
    4304             :  * height."
    4305             :  *
    4306             :  * The default sizing algorithm is described here:
    4307             :  *   http://dev.w3.org/csswg/css-images-3/#default-sizing
    4308             :  * Quotes in the function-impl are taken from that ^ spec-text.
    4309             :  *
    4310             :  * Per its final bulleted section: since there's no specified size,
    4311             :  * we run the default sizing algorithm using the object's intrinsic size in
    4312             :  * place of the specified size. But if the object has neither an intrinsic
    4313             :  * height nor an intrinsic width, then we instead return without populating our
    4314             :  * outparam, and we let the caller figure out the size (using a contain
    4315             :  * constraint).
    4316             :  */
    4317             : static Maybe<nsSize>
    4318             : MaybeComputeObjectFitNoneSize(const nsSize& aDefaultObjectSize,
    4319             :                               const IntrinsicSize& aIntrinsicSize,
    4320             :                               const nsSize& aIntrinsicRatio)
    4321             : {
    4322             :   // "If the object has an intrinsic height or width, its size is resolved as
    4323             :   // if its intrinsic dimensions were given as the specified size."
    4324             :   //
    4325             :   // So, first we check if we have an intrinsic height and/or width:
    4326             :   Maybe<nscoord> specifiedWidth;
    4327             :   if (aIntrinsicSize.width.GetUnit() == eStyleUnit_Coord) {
    4328           0 :     specifiedWidth.emplace(aIntrinsicSize.width.GetCoordValue());
    4329             :   }
    4330             : 
    4331             :   Maybe<nscoord> specifiedHeight;
    4332             :   if (aIntrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
    4333             :     specifiedHeight.emplace(aIntrinsicSize.height.GetCoordValue());
    4334             :   }
    4335             : 
    4336           0 :   Maybe<nsSize> noneSize; // (the value we'll return)
    4337           0 :   if (specifiedWidth || specifiedHeight) {
    4338           0 :     // We have at least one specified dimension; use whichever dimension is
    4339             :     // specified, and compute the other one using our intrinsic ratio, or (if
    4340             :     // no valid ratio) using the default object size.
    4341           0 :     noneSize.emplace();
    4342           0 : 
    4343           0 :     noneSize->width = specifiedWidth ?
    4344             :       *specifiedWidth :
    4345             :       ComputeMissingDimension(aDefaultObjectSize, aIntrinsicRatio,
    4346           0 :                               specifiedWidth, specifiedHeight,
    4347           0 :                               eWidth);
    4348             : 
    4349             :     noneSize->height = specifiedHeight ?
    4350             :       *specifiedHeight :
    4351           0 :       ComputeMissingDimension(aDefaultObjectSize, aIntrinsicRatio,
    4352             :                               specifiedWidth, specifiedHeight,
    4353           0 :                               eHeight);
    4354           0 :   }
    4355             :   // [else:] "Otherwise [if there's neither an intrinsic height nor width], its
    4356             :   // size is resolved as a contain constraint against the default object size."
    4357           0 :   // We'll let our caller do that, to share code & avoid redundant
    4358             :   // computations; so, we return w/out populating noneSize.
    4359           0 :   return noneSize;
    4360           0 : }
    4361             : 
    4362             : // Computes the concrete object size to render into, as described at
    4363           0 : // http://dev.w3.org/csswg/css-images-3/#concrete-size-resolution
    4364             : static nsSize
    4365             : ComputeConcreteObjectSize(const nsSize& aConstraintSize,
    4366             :                           const IntrinsicSize& aIntrinsicSize,
    4367             :                           const nsSize& aIntrinsicRatio,
    4368             :                           uint8_t aObjectFit)
    4369           0 : {
    4370             :   // Handle default behavior (filling the container) w/ fast early return.
    4371             :   // (Also: if there's no valid intrinsic ratio, then we have the "fill"
    4372             :   // behavior & just use the constraint size.)
    4373             :   if (MOZ_LIKELY(aObjectFit == NS_STYLE_OBJECT_FIT_FILL) ||
    4374             :       aIntrinsicRatio.width == 0 ||
    4375           0 :       aIntrinsicRatio.height == 0) {
    4376             :     return aConstraintSize;
    4377             :   }
    4378             : 
    4379             :   // The type of constraint to compute (cover/contain), if needed:
    4380             :   Maybe<nsImageRenderer::FitType> fitType;
    4381             : 
    4382             :   Maybe<nsSize> noneSize;
    4383           0 :   if (aObjectFit == NS_STYLE_OBJECT_FIT_NONE ||
    4384           0 :       aObjectFit == NS_STYLE_OBJECT_FIT_SCALE_DOWN) {
    4385           0 :     noneSize = MaybeComputeObjectFitNoneSize(aConstraintSize, aIntrinsicSize,
    4386           0 :                                              aIntrinsicRatio);
    4387             :     if (!noneSize || aObjectFit == NS_STYLE_OBJECT_FIT_SCALE_DOWN) {
    4388             :       // Need to compute a 'CONTAIN' constraint (either for the 'none' size
    4389             :       // itself, or for comparison w/ the 'none' size to resolve 'scale-down'.)
    4390           0 :       fitType.emplace(nsImageRenderer::CONTAIN);
    4391             :     }
    4392           0 :   } else if (aObjectFit == NS_STYLE_OBJECT_FIT_COVER) {
    4393           0 :     fitType.emplace(nsImageRenderer::COVER);
    4394             :   } else if (aObjectFit == NS_STYLE_OBJECT_FIT_CONTAIN) {
    4395           0 :     fitType.emplace(nsImageRenderer::CONTAIN);
    4396           0 :   }
    4397           0 : 
    4398             :   Maybe<nsSize> constrainedSize;
    4399             :   if (fitType) {
    4400           0 :     constrainedSize.emplace(
    4401             :       nsImageRenderer::ComputeConstrainedSize(aConstraintSize,
    4402           0 :                                               aIntrinsicRatio,
    4403           0 :                                               *fitType));
    4404           0 :   }
    4405           0 : 
    4406             :   // Now, we should have all the sizing information that we need.
    4407             :   switch (aObjectFit) {
    4408           0 :     // skipping NS_STYLE_OBJECT_FIT_FILL; we handled it w/ early-return.
    4409           0 :     case NS_STYLE_OBJECT_FIT_CONTAIN:
    4410             :     case NS_STYLE_OBJECT_FIT_COVER:
    4411           0 :       MOZ_ASSERT(constrainedSize);
    4412             :       return *constrainedSize;
    4413           0 : 
    4414             :     case NS_STYLE_OBJECT_FIT_NONE:
    4415             :       if (noneSize) {
    4416             :         return *noneSize;
    4417           0 :       }
    4418             :       MOZ_ASSERT(constrainedSize);
    4419             :       return *constrainedSize;
    4420             : 
    4421           0 :     case NS_STYLE_OBJECT_FIT_SCALE_DOWN:
    4422           0 :       MOZ_ASSERT(constrainedSize);
    4423             :       if (noneSize) {
    4424             :         constrainedSize->width =
    4425           0 :           std::min(constrainedSize->width, noneSize->width);
    4426           0 :         constrainedSize->height =
    4427             :           std::min(constrainedSize->height, noneSize->height);
    4428           0 :       }
    4429           0 :       return *constrainedSize;
    4430             : 
    4431             :     default:
    4432           0 :       MOZ_ASSERT_UNREACHABLE("Unexpected enum value for 'object-fit'");
    4433           0 :       return aConstraintSize; // fall back to (default) 'fill' behavior
    4434           0 :   }
    4435           0 : }
    4436           0 : 
    4437           0 : // (Helper for HasInitialObjectFitAndPosition, to check
    4438             : // each "object-position" coord.)
    4439           0 : static bool
    4440             : IsCoord50Pct(const mozilla::Position::Coord& aCoord)
    4441             : {
    4442           0 :   return (aCoord.mLength == 0 &&
    4443             :           aCoord.mHasPercent &&
    4444             :           aCoord.mPercent == 0.5f);
    4445             : }
    4446             : 
    4447             : // Indicates whether the given nsStylePosition has the initial values
    4448             : // for the "object-fit" and "object-position" properties.
    4449             : static bool
    4450           0 : HasInitialObjectFitAndPosition(const nsStylePosition* aStylePos)
    4451             : {
    4452           0 :   const mozilla::Position& objectPos = aStylePos->mObjectPosition;
    4453           0 : 
    4454           0 :   return aStylePos->mObjectFit == NS_STYLE_OBJECT_FIT_FILL &&
    4455             :     IsCoord50Pct(objectPos.mXPosition) &&
    4456             :     IsCoord50Pct(objectPos.mYPosition);
    4457             : }
    4458             : 
    4459             : /* static */ nsRect
    4460           0 : nsLayoutUtils::ComputeObjectDestRect(const nsRect& aConstraintRect,
    4461             :                                      const IntrinsicSize& aIntrinsicSize,
    4462           0 :                                      const nsSize& aIntrinsicRatio,
    4463             :                                      const nsStylePosition* aStylePos,
    4464           0 :                                      nsPoint* aAnchorPoint)
    4465           0 : {
    4466           0 :   // Step 1: Figure out our "concrete object size"
    4467             :   // (the size of the region we'll actually draw our image's pixels into).
    4468             :   nsSize concreteObjectSize =
    4469             :     ComputeConcreteObjectSize(aConstraintRect.Size(), aIntrinsicSize,
    4470           0 :                               aIntrinsicRatio, aStylePos->mObjectFit);
    4471             : 
    4472             :   // Step 2: Figure out how to align that region in the element's content-box.
    4473             :   nsPoint imageTopLeftPt, imageAnchorPt;
    4474             :   nsImageRenderer::ComputeObjectAnchorPoint(aStylePos->mObjectPosition,
    4475             :                                             aConstraintRect.Size(),
    4476             :                                             concreteObjectSize,
    4477             :                                             &imageTopLeftPt, &imageAnchorPt);
    4478             :   // Right now, we're with respect to aConstraintRect's top-left point.  We add
    4479           0 :   // that point here, to convert to the same broader coordinate space that
    4480           0 :   // aConstraintRect is in.
    4481             :   imageTopLeftPt += aConstraintRect.TopLeft();
    4482             :   imageAnchorPt += aConstraintRect.TopLeft();
    4483           0 : 
    4484           0 :   if (aAnchorPoint) {
    4485           0 :     // Special-case: if our "object-fit" and "object-position" properties have
    4486             :     // their default values ("object-fit: fill; object-position:50% 50%"), then
    4487           0 :     // we'll override the calculated imageAnchorPt, and instead use the
    4488             :     // object's top-left corner.
    4489             :     //
    4490             :     // This special case is partly for backwards compatibility (since
    4491           0 :     // traditionally we've pixel-aligned the top-left corner of e.g. <img>
    4492           0 :     // elements), and partly because ComputeSnappedDrawingParameters produces
    4493             :     // less error if the anchor point is at the top-left corner. So, all other
    4494           0 :     // things being equal, we prefer that code path with less error.
    4495             :     if (HasInitialObjectFitAndPosition(aStylePos)) {
    4496             :       *aAnchorPoint = imageTopLeftPt;
    4497             :     } else {
    4498             :       *aAnchorPoint = imageAnchorPt;
    4499             :     }
    4500             :   }
    4501             :   return nsRect(imageTopLeftPt, concreteObjectSize);
    4502             : }
    4503             : 
    4504             : already_AddRefed<nsFontMetrics>
    4505           0 : nsLayoutUtils::GetFontMetricsForFrame(const nsIFrame* aFrame, float aInflation)
    4506           0 : {
    4507             :   ComputedStyle* computedStyle = aFrame->Style();
    4508           0 :   uint8_t variantWidth = NS_FONT_VARIANT_WIDTH_NORMAL;
    4509             :   if (computedStyle->IsTextCombined()) {
    4510             :     MOZ_ASSERT(aFrame->IsTextFrame());
    4511           0 :     auto textFrame = static_cast<const nsTextFrame*>(aFrame);
    4512             :     auto clusters = textFrame->CountGraphemeClusters();
    4513             :     if (clusters == 2) {
    4514             :       variantWidth = NS_FONT_VARIANT_WIDTH_HALF;
    4515           0 :     } else if (clusters == 3) {
    4516             :       variantWidth = NS_FONT_VARIANT_WIDTH_THIRD;
    4517           0 :     } else if (clusters == 4) {
    4518           0 :       variantWidth = NS_FONT_VARIANT_WIDTH_QUARTER;
    4519           0 :     }
    4520           0 :   }
    4521           0 :   return GetFontMetricsForComputedStyle(computedStyle, aFrame->PresContext(),
    4522           0 :                                         aInflation, variantWidth);
    4523           0 : }
    4524             : 
    4525           0 : already_AddRefed<nsFontMetrics>
    4526             : nsLayoutUtils::GetFontMetricsForComputedStyle(ComputedStyle* aComputedStyle,
    4527           0 :                                               nsPresContext* aPresContext,
    4528           0 :                                               float aInflation,
    4529             :                                               uint8_t aVariantWidth)
    4530             : {
    4531             :   WritingMode wm(aComputedStyle);
    4532           0 :   const nsStyleFont* styleFont = aComputedStyle->StyleFont();
    4533             :   nsFontMetrics::Params params;
    4534             :   params.language = styleFont->mLanguage;
    4535             :   params.explicitLanguage = styleFont->mExplicitLanguage;
    4536           0 :   params.orientation =
    4537             :     wm.IsVertical() && !wm.IsSideways() ? gfxFont::eVertical
    4538             :                                         : gfxFont::eHorizontal;
    4539             :   // pass the user font set object into the device context to
    4540             :   // pass along to CreateFontGroup
    4541           0 :   params.userFontSet = aPresContext->GetUserFontSet();
    4542           0 :   params.textPerf = aPresContext->GetTextPerfMetrics();
    4543           0 : 
    4544           0 :   // When aInflation is 1.0 and we don't require width variant, avoid
    4545           0 :   // making a local copy of the nsFont.
    4546           0 :   // This also avoids running font.size through floats when it is large,
    4547           0 :   // which would be lossy.  Fortunately, in such cases, aInflation is
    4548             :   // guaranteed to be 1.0f.
    4549             :   if (aInflation == 1.0f && aVariantWidth == NS_FONT_VARIANT_WIDTH_NORMAL) {
    4550             :     return aPresContext->DeviceContext()->GetMetricsFor(styleFont->mFont, params);
    4551           0 :   }
    4552           0 : 
    4553             :   nsFont font = styleFont->mFont;
    4554             :   font.size = NSToCoordRound(font.size * aInflation);
    4555             :   font.variantWidth = aVariantWidth;
    4556             :   return aPresContext->DeviceContext()->GetMetricsFor(font, params);
    4557             : }
    4558             : 
    4559           0 : nsIFrame*
    4560           0 : nsLayoutUtils::FindChildContainingDescendant(nsIFrame* aParent, nsIFrame* aDescendantFrame)
    4561             : {
    4562             :   nsIFrame* result = aDescendantFrame;
    4563           0 : 
    4564           0 :   while (result) {
    4565           0 :     nsIFrame* parent = result->GetParent();
    4566           0 :     if (parent == aParent) {
    4567             :       break;
    4568             :     }
    4569             : 
    4570           0 :     // The frame is not an immediate child of aParent so walk up another level
    4571             :     result = parent;
    4572           0 :   }
    4573             : 
    4574           0 :   return result;
    4575           0 : }
    4576           0 : 
    4577             : nsBlockFrame*
    4578             : nsLayoutUtils::GetAsBlock(nsIFrame* aFrame)
    4579             : {
    4580             :   nsBlockFrame* block = do_QueryFrame(aFrame);
    4581             :   return block;
    4582             : }
    4583             : 
    4584           0 : nsBlockFrame*
    4585             : nsLayoutUtils::FindNearestBlockAncestor(nsIFrame* aFrame)
    4586             : {
    4587             :   nsIFrame* nextAncestor;
    4588           0 :   for (nextAncestor = aFrame->GetParent(); nextAncestor;
    4589             :        nextAncestor = nextAncestor->GetParent()) {
    4590           0 :     nsBlockFrame* block = GetAsBlock(nextAncestor);
    4591           0 :     if (block)
    4592             :       return block;
    4593             :   }
    4594             :   return nullptr;
    4595           0 : }
    4596             : 
    4597             : nsIFrame*
    4598           0 : nsLayoutUtils::GetNonGeneratedAncestor(nsIFrame* aFrame)
    4599             : {
    4600           0 :   if (!(aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT))
    4601           0 :     return aFrame;
    4602             : 
    4603             :   nsIFrame* f = aFrame;
    4604             :   do {
    4605             :     f = GetParentOrPlaceholderFor(f);
    4606             :   } while (f->GetStateBits() & NS_FRAME_GENERATED_CONTENT);
    4607             :   return f;
    4608           0 : }
    4609             : 
    4610           0 : nsIFrame*
    4611             : nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame)
    4612             : {
    4613             :   if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
    4614           0 :       && !aFrame->GetPrevInFlow()) {
    4615           0 :     return aFrame->GetProperty(nsIFrame::PlaceholderFrameProperty());
    4616           0 :   }
    4617             :   return aFrame->GetParent();
    4618             : }
    4619             : 
    4620             : nsIFrame*
    4621           0 : nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(nsIFrame* aFrame)
    4622             : {
    4623           0 :   nsIFrame* f = GetParentOrPlaceholderFor(aFrame);
    4624           0 :   if (f)
    4625           0 :     return f;
    4626             :   return GetCrossDocParentFrame(aFrame);
    4627           0 : }
    4628             : 
    4629             : nsIFrame*
    4630             : nsLayoutUtils::GetNextContinuationOrIBSplitSibling(nsIFrame *aFrame)
    4631           0 : {
    4632             :   nsIFrame *result = aFrame->GetNextContinuation();
    4633           0 :   if (result)
    4634           0 :     return result;
    4635             : 
    4636           0 :   if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0) {
    4637             :     // We only store the ib-split sibling annotation with the first
    4638             :     // frame in the continuation chain. Walk back to find that frame now.
    4639             :     aFrame = aFrame->FirstContinuation();
    4640           0 : 
    4641             :     return aFrame->GetProperty(nsIFrame::IBSplitSibling());
    4642           0 :   }
    4643           0 : 
    4644             :   return nullptr;
    4645             : }
    4646           0 : 
    4647             : nsIFrame*
    4648             : nsLayoutUtils::FirstContinuationOrIBSplitSibling(const nsIFrame* aFrame)
    4649           0 : {
    4650             :   nsIFrame* result = aFrame->FirstContinuation();
    4651           0 : 
    4652             :   if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
    4653             :     while (auto* f = result->GetProperty(nsIFrame::IBSplitPrevSibling())) {
    4654             :       result = f;
    4655             :     }
    4656             :   }
    4657             : 
    4658           0 :   return result;
    4659             : }
    4660           0 : 
    4661             : nsIFrame*
    4662           0 : nsLayoutUtils::LastContinuationOrIBSplitSibling(const nsIFrame* aFrame)
    4663           0 : {
    4664             :   nsIFrame* result = aFrame->FirstContinuation();
    4665             : 
    4666             :   if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
    4667             :     while (auto* f = result->GetProperty(nsIFrame::IBSplitSibling())) {
    4668           0 :       result = f;
    4669             :     }
    4670             :   }
    4671             : 
    4672           0 :   return result->LastContinuation();
    4673             : }
    4674           0 : 
    4675             : bool
    4676           0 : nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(nsIFrame *aFrame)
    4677           0 : {
    4678             :   if (aFrame->GetPrevContinuation()) {
    4679             :     return false;
    4680             :   }
    4681             :   if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
    4682           0 :       aFrame->GetProperty(nsIFrame::IBSplitPrevSibling())) {
    4683             :     return false;
    4684             :   }
    4685             : 
    4686           0 :   return true;
    4687             : }
    4688           0 : 
    4689             : bool
    4690             : nsLayoutUtils::IsViewportScrollbarFrame(nsIFrame* aFrame)
    4691           0 : {
    4692           0 :   if (!aFrame)
    4693             :     return false;
    4694             : 
    4695             :   nsIFrame* rootScrollFrame = aFrame->PresShell()->GetRootScrollFrame();
    4696           0 :   if (!rootScrollFrame)
    4697             :     return false;
    4698             : 
    4699             :   nsIScrollableFrame* rootScrollableFrame = do_QueryFrame(rootScrollFrame);
    4700           0 :   NS_ASSERTION(rootScrollableFrame, "The root scorollable frame is null");
    4701             : 
    4702           0 :   if (!IsProperAncestorFrame(rootScrollFrame, aFrame))
    4703             :     return false;
    4704             : 
    4705           0 :   nsIFrame* rootScrolledFrame = rootScrollableFrame->GetScrolledFrame();
    4706           0 :   return !(rootScrolledFrame == aFrame ||
    4707             :            IsProperAncestorFrame(rootScrolledFrame, aFrame));
    4708             : }
    4709           0 : 
    4710           0 : // Use only for widths/heights (or their min/max), since it clamps
    4711             : // negative calc() results to 0.
    4712           0 : static bool GetAbsoluteCoord(const nsStyleCoord& aStyle, nscoord& aResult)
    4713             : {
    4714             :   if (aStyle.IsCalcUnit()) {
    4715           0 :     if (aStyle.CalcHasPercent()) {
    4716           0 :       return false;
    4717           0 :     }
    4718             :     // If it has no percents, we can pass 0 for the percentage basis.
    4719             :     aResult = aStyle.ComputeComputedCalc(0);
    4720             :     if (aResult < 0)
    4721             :       aResult = 0;
    4722           0 :     return true;
    4723             :   }
    4724           0 : 
    4725           0 :   if (eStyleUnit_Coord != aStyle.GetUnit())
    4726             :     return false;
    4727             : 
    4728             :   aResult = aStyle.GetCoordValue();
    4729           0 :   NS_ASSERTION(aResult >= 0, "negative widths not allowed");
    4730           0 :   return true;
    4731           0 : }
    4732             : 
    4733             : static nscoord
    4734             : GetBSizeTakenByBoxSizing(StyleBoxSizing aBoxSizing,
    4735           0 :                          nsIFrame* aFrame,
    4736             :                          bool aHorizontalAxis,
    4737             :                          bool aIgnorePadding);
    4738           0 : 
    4739           0 : // Only call on style coords for which GetAbsoluteCoord returned false.
    4740             : static bool
    4741             : GetPercentBSize(const nsStyleCoord& aStyle,
    4742             :                 nsIFrame* aFrame,
    4743             :                 bool aHorizontalAxis,
    4744             :                 nscoord& aResult)
    4745             : {
    4746             :   if (eStyleUnit_Percent != aStyle.GetUnit() &&
    4747             :       !aStyle.IsCalcUnit())
    4748             :     return false;
    4749             : 
    4750             :   MOZ_ASSERT(!aStyle.IsCalcUnit() || aStyle.CalcHasPercent(),
    4751           0 :              "GetAbsoluteCoord should have handled this");
    4752             : 
    4753             :   // During reflow, nsHTMLScrollFrame::ReflowScrolledFrame uses
    4754             :   // SetComputedHeight on the reflow state for its child to propagate its
    4755             :   // computed height to the scrolled content. So here we skip to the scroll
    4756           0 :   // frame that contains this scrolled content in order to get the same
    4757           0 :   // behavior as layout when computing percentage heights.
    4758             :   nsIFrame *f = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
    4759             :   if (!f) {
    4760           0 :     NS_NOTREACHED("top of frame tree not a containing block");
    4761             :     return false;
    4762             :   }
    4763             : 
    4764             :   WritingMode wm = f->GetWritingMode();
    4765             : 
    4766             :   const nsStylePosition *pos = f->StylePosition();
    4767             :   const nsStyleCoord& bSizeCoord = pos->BSize(wm);
    4768           0 :   nscoord h;
    4769           0 :   if (!GetAbsoluteCoord(bSizeCoord, h) &&
    4770           0 :       !GetPercentBSize(bSizeCoord, f, aHorizontalAxis, h)) {
    4771           0 :     NS_ASSERTION(bSizeCoord.GetUnit() == eStyleUnit_Auto ||
    4772             :                  bSizeCoord.HasPercent(),
    4773             :                  "unknown block-size unit");
    4774           0 :     LayoutFrameType fType = f->Type();
    4775             :     if (fType != LayoutFrameType::Viewport &&
    4776           0 :         fType != LayoutFrameType::Canvas &&
    4777           0 :         fType != LayoutFrameType::PageContent) {
    4778             :       // There's no basis for the percentage height, so it acts like auto.
    4779           0 :       // Should we consider a max-height < min-height pair a basis for
    4780           0 :       // percentage heights?  The spec is somewhat unclear, and not doing
    4781           0 :       // so is simpler and avoids troubling discontinuities in behavior,
    4782             :       // so I'll choose not to. -LDB
    4783             :       return false;
    4784           0 :     }
    4785           0 : 
    4786           0 :     NS_ASSERTION(bSizeCoord.GetUnit() == eStyleUnit_Auto,
    4787             :                  "Unexpected block-size unit for viewport or canvas or page-content");
    4788             :     // For the viewport, canvas, and page-content kids, the percentage
    4789             :     // basis is just the parent block-size.
    4790             :     h = f->BSize(wm);
    4791             :     if (h == NS_UNCONSTRAINEDSIZE) {
    4792             :       // We don't have a percentage basis after all
    4793             :       return false;
    4794             :     }
    4795             :   }
    4796           0 : 
    4797             :   const nsStyleCoord& maxBSizeCoord = pos->MaxBSize(wm);
    4798             : 
    4799             :   nscoord maxh;
    4800           0 :   if (GetAbsoluteCoord(maxBSizeCoord, maxh) ||
    4801           0 :       GetPercentBSize(maxBSizeCoord, f, aHorizontalAxis, maxh)) {
    4802             :     if (maxh < h)
    4803             :       h = maxh;
    4804             :   } else {
    4805             :     NS_ASSERTION(maxBSizeCoord.GetUnit() == eStyleUnit_None ||
    4806             :                  maxBSizeCoord.HasPercent(),
    4807           0 :                  "unknown max block-size unit");
    4808             :   }
    4809             : 
    4810           0 :   const nsStyleCoord& minBSizeCoord = pos->MinBSize(wm);
    4811           0 : 
    4812           0 :   nscoord minh;
    4813           0 :   if (GetAbsoluteCoord(minBSizeCoord, minh) ||
    4814             :       GetPercentBSize(minBSizeCoord, f, aHorizontalAxis, minh)) {
    4815           0 :     if (minh > h)
    4816             :       h = minh;
    4817             :   } else {
    4818             :     NS_ASSERTION(minBSizeCoord.HasPercent() ||
    4819             :                  minBSizeCoord.GetUnit() == eStyleUnit_Auto,
    4820           0 :                  "unknown min block-size unit");
    4821             :   }
    4822             : 
    4823           0 :   // Now adjust h for box-sizing styles on the parent.  We never ignore padding
    4824           0 :   // here.  That could conceivably cause some problems with fieldsets (which are
    4825           0 :   // the one place that wants to ignore padding), but solving that here without
    4826           0 :   // hardcoding a check for f being a fieldset-content frame is a bit of a pain.
    4827             :   nscoord bSizeTakenByBoxSizing =
    4828           0 :     GetBSizeTakenByBoxSizing(pos->mBoxSizing, f, aHorizontalAxis, false);
    4829             :   h = std::max(0, h - bSizeTakenByBoxSizing);
    4830             : 
    4831             :   if (aStyle.IsCalcUnit()) {
    4832             :     aResult = std::max(aStyle.ComputeComputedCalc(h), 0);
    4833             :     return true;
    4834             :   }
    4835             : 
    4836             :   aResult = NSToCoordRound(aStyle.GetPercentValue() * h);
    4837             :   return true;
    4838           0 : }
    4839           0 : 
    4840             : // Return true if aStyle can be resolved to a definite value and if so
    4841           0 : // return that value in aResult.
    4842           0 : static bool
    4843           0 : GetDefiniteSize(const nsStyleCoord&       aStyle,
    4844             :                 nsIFrame*                 aFrame,
    4845             :                 bool                      aIsInlineAxis,
    4846           0 :                 const Maybe<LogicalSize>& aPercentageBasis,
    4847           0 :                 nscoord*                  aResult)
    4848             : {
    4849             :   switch (aStyle.GetUnit()) {
    4850             :     case eStyleUnit_Coord:
    4851             :       *aResult = aStyle.GetCoordValue();
    4852             :       return true;
    4853           0 :     case eStyleUnit_Percent: {
    4854             :       if (aPercentageBasis.isNothing()) {
    4855             :         return false;
    4856             :       }
    4857             :       auto wm = aFrame->GetWritingMode();
    4858             :       nscoord pb = aIsInlineAxis ? aPercentageBasis.value().ISize(wm)
    4859           0 :                                  : aPercentageBasis.value().BSize(wm);
    4860             :       if (pb != NS_UNCONSTRAINEDSIZE) {
    4861           0 :         nscoord p = NSToCoordFloorClamped(pb * aStyle.GetPercentValue());
    4862           0 :         *aResult = std::max(nscoord(0), p);
    4863             :         return true;
    4864           0 :       }
    4865             :       return false;
    4866             :     }
    4867           0 :     case eStyleUnit_Calc: {
    4868           0 :       nsStyleCoord::Calc* calc = aStyle.GetCalcValue();
    4869           0 :       if (calc->mPercent != 0.0f) {
    4870           0 :         if (aPercentageBasis.isNothing()) {
    4871           0 :           return false;
    4872           0 :         }
    4873             :         auto wm = aFrame->GetWritingMode();
    4874             :         nscoord pb = aIsInlineAxis ? aPercentageBasis.value().ISize(wm)
    4875             :                                    : aPercentageBasis.value().BSize(wm);
    4876             :         if (pb == NS_UNCONSTRAINEDSIZE) {
    4877             :           return false;
    4878           0 :         }
    4879           0 :         *aResult = std::max(0, calc->mLength +
    4880           0 :                                NSToCoordFloorClamped(pb * calc->mPercent));
    4881           0 :       } else {
    4882             :         *aResult = std::max(0, calc->mLength);
    4883           0 :       }
    4884           0 :       return true;
    4885           0 :     }
    4886           0 :     default:
    4887             :       return false;
    4888             :   }
    4889           0 : }
    4890           0 : 
    4891             : //
    4892           0 : // NOTE: this function will be replaced by GetDefiniteSizeTakenByBoxSizing (bug 1363918).
    4893             : // Please do not add new uses of this function.
    4894             : //
    4895             : // Get the amount of vertical space taken out of aFrame's content area due to
    4896             : // its borders and paddings given the box-sizing value in aBoxSizing.  We don't
    4897             : // get aBoxSizing from the frame because some callers want to compute this for
    4898             : // specific box-sizing values.  aHorizontalAxis is true if our inline direction
    4899             : // is horisontal and our block direction is vertical.  aIgnorePadding is true if
    4900             : // padding should be ignored.
    4901             : static nscoord
    4902             : GetBSizeTakenByBoxSizing(StyleBoxSizing aBoxSizing,
    4903             :                          nsIFrame* aFrame,
    4904             :                          bool aHorizontalAxis,
    4905             :                          bool aIgnorePadding)
    4906             : {
    4907             :   nscoord bSizeTakenByBoxSizing = 0;
    4908             :   if (aBoxSizing == StyleBoxSizing::Border) {
    4909             :     const nsStyleBorder* styleBorder = aFrame->StyleBorder();
    4910             :     bSizeTakenByBoxSizing +=
    4911             :       aHorizontalAxis ? styleBorder->GetComputedBorder().TopBottom()
    4912           0 :                       : styleBorder->GetComputedBorder().LeftRight();
    4913             :     if (!aIgnorePadding) {
    4914             :       const nsStyleSides& stylePadding =
    4915             :         aFrame->StylePadding()->mPadding;
    4916             :       const nsStyleCoord& paddingStart =
    4917           0 :         stylePadding.Get(aHorizontalAxis ? eSideTop : eSideLeft);
    4918           0 :       const nsStyleCoord& paddingEnd =
    4919           0 :         stylePadding.Get(aHorizontalAxis ? eSideBottom : eSideRight);
    4920           0 :       nscoord pad;
    4921           0 :       // XXXbz Calling GetPercentBSize on padding values looks bogus, since
    4922           0 :       // percent padding is always a percentage of the inline-size of the
    4923           0 :       // containing block.  We should perhaps just treat non-absolute paddings
    4924             :       // here as 0 instead, except that in some cases the width may in fact be
    4925           0 :       // known.  See bug 1231059.
    4926             :       if (GetAbsoluteCoord(paddingStart, pad) ||
    4927           0 :           GetPercentBSize(paddingStart, aFrame, aHorizontalAxis, pad)) {
    4928             :         bSizeTakenByBoxSizing += pad;
    4929           0 :       }
    4930             :       if (GetAbsoluteCoord(paddingEnd, pad) ||
    4931             :           GetPercentBSize(paddingEnd, aFrame, aHorizontalAxis, pad)) {
    4932             :         bSizeTakenByBoxSizing += pad;
    4933             :       }
    4934             :     }
    4935             :   }
    4936           0 :   return bSizeTakenByBoxSizing;
    4937           0 : }
    4938           0 : 
    4939             : // Get the amount of space taken out of aFrame's content area due to its
    4940           0 : // borders and paddings given the box-sizing value in aBoxSizing.  We don't
    4941           0 : // get aBoxSizing from the frame because some callers want to compute this for
    4942           0 : // specific box-sizing values.
    4943             : // aIsInlineAxis is true if we're computing for aFrame's inline axis.
    4944             : // aIgnorePadding is true if padding should be ignored.
    4945             : static nscoord
    4946           0 : GetDefiniteSizeTakenByBoxSizing(StyleBoxSizing aBoxSizing,
    4947             :                                 nsIFrame* aFrame,
    4948             :                                 bool aIsInlineAxis,
    4949             :                                 bool aIgnorePadding,
    4950             :                                 const Maybe<LogicalSize>& aPercentageBasis)
    4951             : {
    4952             :   nscoord sizeTakenByBoxSizing = 0;
    4953             :   if (MOZ_UNLIKELY(aBoxSizing == StyleBoxSizing::Border)) {
    4954             :     const bool isHorizontalAxis =
    4955             :       aIsInlineAxis == !aFrame->GetWritingMode().IsVertical();
    4956           0 :     const nsStyleBorder* styleBorder = aFrame->StyleBorder();
    4957             :     sizeTakenByBoxSizing =
    4958             :       isHorizontalAxis ? styleBorder->GetComputedBorder().LeftRight()
    4959             :                        : styleBorder->GetComputedBorder().TopBottom();
    4960             :     if (!aIgnorePadding) {
    4961             :       const nsStyleSides& stylePadding = aFrame->StylePadding()->mPadding;
    4962           0 :       const nsStyleCoord& pStart =
    4963           0 :         stylePadding.Get(isHorizontalAxis ? eSideLeft : eSideTop);
    4964             :       const nsStyleCoord& pEnd =
    4965           0 :         stylePadding.Get(isHorizontalAxis ? eSideRight : eSideBottom);
    4966           0 :       nscoord pad;
    4967           0 :       // XXXbz Calling GetPercentBSize on padding values looks bogus, since
    4968           0 :       // percent padding is always a percentage of the inline-size of the
    4969           0 :       // containing block.  We should perhaps just treat non-absolute paddings
    4970           0 :       // here as 0 instead, except that in some cases the width may in fact be
    4971           0 :       // known.  See bug 1231059.
    4972             :       if (GetDefiniteSize(pStart, aFrame, aIsInlineAxis, aPercentageBasis, &pad) ||
    4973           0 :           (aPercentageBasis.isNothing() &&
    4974             :            GetPercentBSize(pStart, aFrame, isHorizontalAxis, pad))) {
    4975           0 :         sizeTakenByBoxSizing += pad;
    4976             :       }
    4977             :       if (GetDefiniteSize(pEnd, aFrame, aIsInlineAxis, aPercentageBasis, &pad) ||
    4978             :           (aPercentageBasis.isNothing() &&
    4979             :            GetPercentBSize(pEnd, aFrame, isHorizontalAxis, pad))) {
    4980             :         sizeTakenByBoxSizing += pad;
    4981             :       }
    4982           0 :     }
    4983           0 :   }
    4984           0 :   return sizeTakenByBoxSizing;
    4985           0 : }
    4986             : 
    4987           0 : // Handles only -moz-max-content and -moz-min-content, and
    4988           0 : // -moz-fit-content for min-width and max-width, since the others
    4989           0 : // (-moz-fit-content for width, and -moz-available) have no effect on
    4990           0 : // intrinsic widths.
    4991             : enum eWidthProperty { PROP_WIDTH, PROP_MAX_WIDTH, PROP_MIN_WIDTH };
    4992             : static bool
    4993             : GetIntrinsicCoord(const nsStyleCoord& aStyle,
    4994           0 :                   gfxContext* aRenderingContext,
    4995             :                   nsIFrame* aFrame,
    4996             :                   eWidthProperty aProperty,
    4997             :                   nscoord& aResult)
    4998             : {
    4999             :   MOZ_ASSERT(aProperty == PROP_WIDTH || aProperty == PROP_MAX_WIDTH ||
    5000             :              aProperty == PROP_MIN_WIDTH, "unexpected property");
    5001             : 
    5002             :   if (aStyle.GetUnit() != eStyleUnit_Enumerated)
    5003           0 :     return false;
    5004             :   int32_t val = aStyle.GetIntValue();
    5005             :   NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
    5006             :                val == NS_STYLE_WIDTH_MIN_CONTENT ||
    5007             :                val == NS_STYLE_WIDTH_FIT_CONTENT ||
    5008             :                val == NS_STYLE_WIDTH_AVAILABLE,
    5009           0 :                "unexpected enumerated value for width property");
    5010             :   if (val == NS_STYLE_WIDTH_AVAILABLE)
    5011             :     return false;
    5012           0 :   if (val == NS_STYLE_WIDTH_FIT_CONTENT) {
    5013             :     if (aProperty == PROP_WIDTH)
    5014           0 :       return false; // handle like 'width: auto'
    5015           0 :     if (aProperty == PROP_MAX_WIDTH)
    5016             :       // constrain large 'width' values down to -moz-max-content
    5017             :       val = NS_STYLE_WIDTH_MAX_CONTENT;
    5018             :     else
    5019             :       // constrain small 'width' or 'max-width' values up to -moz-min-content
    5020           0 :       val = NS_STYLE_WIDTH_MIN_CONTENT;
    5021             :   }
    5022           0 : 
    5023           0 :   NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
    5024             :                val == NS_STYLE_WIDTH_MIN_CONTENT,
    5025           0 :                "should have reduced everything remaining to one of these");
    5026             : 
    5027             :   // If aFrame is a container for font size inflation, then shrink
    5028             :   // wrapping inside of it should not apply font size inflation.
    5029             :   AutoMaybeDisableFontInflation an(aFrame);
    5030           0 : 
    5031             :   if (val == NS_STYLE_WIDTH_MAX_CONTENT)
    5032             :     aResult = aFrame->GetPrefISize(aRenderingContext);
    5033           0 :   else
    5034             :     aResult = aFrame->GetMinISize(aRenderingContext);
    5035             :   return true;
    5036             : }
    5037             : 
    5038             : #undef  DEBUG_INTRINSIC_WIDTH
    5039           0 : 
    5040             : #ifdef DEBUG_INTRINSIC_WIDTH
    5041           0 : static int32_t gNoiseIndent = 0;
    5042           0 : #endif
    5043             : 
    5044           0 : // Return true for form controls whose minimum intrinsic inline-size
    5045             : // shrinks to 0 when they have a percentage inline-size (but not
    5046             : // percentage max-inline-size).  (Proper replaced elements, whose
    5047             : // intrinsic minimium inline-size shrinks to 0 for both percentage
    5048             : // inline-size and percentage max-inline-size, are handled elsewhere.)
    5049             : inline static bool
    5050             : FormControlShrinksForPercentISize(nsIFrame* aFrame)
    5051             : {
    5052             :   if (!aFrame->IsFrameOfType(nsIFrame::eReplaced)) {
    5053             :     // Quick test to reject most frames.
    5054             :     return false;
    5055             :   }
    5056             : 
    5057             :   LayoutFrameType fType = aFrame->Type();
    5058             :   if (fType == LayoutFrameType::Meter || fType == LayoutFrameType::Progress) {
    5059             :     // progress and meter do have this shrinking behavior
    5060           0 :     // FIXME: Maybe these should be nsIFormControlFrame?
    5061             :     return true;
    5062           0 :   }
    5063             : 
    5064             :   if (!static_cast<nsIFormControlFrame*>(do_QueryFrame(aFrame))) {
    5065             :     // Not a form control.  This includes fieldsets, which do not
    5066             :     // shrink.
    5067           0 :     return false;
    5068           0 :   }
    5069             : 
    5070             :   if (fType == LayoutFrameType::GfxButtonControl ||
    5071             :       fType == LayoutFrameType::HTMLButtonControl) {
    5072             :     // Buttons don't have this shrinking behavior.  (Note that color
    5073             :     // inputs do, even though they inherit from button, so we can't use
    5074           0 :     // do_QueryFrame here.)
    5075             :     return false;
    5076             :   }
    5077             : 
    5078             :   return true;
    5079             : }
    5080           0 : 
    5081           0 : // https://drafts.csswg.org/css-sizing-3/#percentage-sizing
    5082             : // Return true if the above spec's rule for replaced boxes applies.
    5083             : // XXX bug 1463700 will make this match the spec...
    5084             : static bool
    5085             : IsReplacedBoxResolvedAgainstZero(nsIFrame* aFrame,
    5086             :                                  const nsStyleCoord& aStyleSize,
    5087             :                                  const nsStyleCoord& aStyleMaxSize)
    5088           0 : {
    5089             :   const bool sizeHasPercent = aStyleSize.HasPercent();
    5090             :   return ((sizeHasPercent || aStyleMaxSize.HasPercent()) &&
    5091             :           aFrame->IsFrameOfType(nsIFrame::eReplacedSizing)) ||
    5092             :          (sizeHasPercent &&
    5093             :           FormControlShrinksForPercentISize(aFrame));
    5094             : }
    5095           0 : 
    5096             : /**
    5097             :  * Add aOffsets which describes what to add on outside of the content box
    5098             :  * aContentSize (controlled by 'box-sizing') and apply min/max properties.
    5099           0 :  * We have to account for these properties after getting all the offsets
    5100           0 :  * (margin, border, padding) because percentages do not operate linearly.
    5101           0 :  * Doing this is ok because although percentages aren't handled linearly,
    5102           0 :  * they are handled monotonically.
    5103           0 :  *
    5104             :  * @param aContentSize the content size calculated so far
    5105             :                        (@see IntrinsicForContainer)
    5106             :  * @param aContentMinSize ditto min content size
    5107             :  * @param aStyleSize a 'width' or 'height' property value
    5108             :  * @param aFixedMinSize if aStyleMinSize is a definite size then this points to
    5109             :  *                      the value, otherwise nullptr
    5110             :  * @param aStyleMinSize a 'min-width' or 'min-height' property value
    5111             :  * @param aFixedMaxSize if aStyleMaxSize is a definite size then this points to
    5112             :  *                      the value, otherwise nullptr
    5113             :  * @param aStyleMaxSize a 'max-width' or 'max-height' property value
    5114             :  * @param aFlags same as for IntrinsicForContainer
    5115             :  * @param aContainerWM the container's WM
    5116             :  */
    5117             : static nscoord
    5118             : AddIntrinsicSizeOffset(gfxContext* aRenderingContext,
    5119             :                        nsIFrame* aFrame,
    5120             :                        const nsIFrame::IntrinsicISizeOffsetData& aOffsets,
    5121             :                        nsLayoutUtils::IntrinsicISizeType aType,
    5122             :                        StyleBoxSizing aBoxSizing,
    5123             :                        nscoord aContentSize,
    5124             :                        nscoord aContentMinSize,
    5125             :                        const nsStyleCoord& aStyleSize,
    5126             :                        const nscoord* aFixedMinSize,
    5127             :                        const nsStyleCoord& aStyleMinSize,
    5128           0 :                        const nscoord* aFixedMaxSize,
    5129             :                        const nsStyleCoord& aStyleMaxSize,
    5130             :                        uint32_t aFlags,
    5131             :                        PhysicalAxis aAxis)
    5132             : {
    5133             :   nscoord result = aContentSize;
    5134             :   nscoord min = aContentMinSize;
    5135             :   nscoord coordOutsideSize = 0;
    5136             : 
    5137             :   if (!(aFlags & nsLayoutUtils::IGNORE_PADDING)) {
    5138             :     coordOutsideSize += aOffsets.hPadding;
    5139             :   }
    5140             : 
    5141             :   coordOutsideSize += aOffsets.hBorder;
    5142             : 
    5143           0 :   if (aBoxSizing == StyleBoxSizing::Border) {
    5144           0 :     min += coordOutsideSize;
    5145           0 :     result = NSCoordSaturatingAdd(result, coordOutsideSize);
    5146             : 
    5147           0 :     coordOutsideSize = 0;
    5148           0 :   }
    5149             : 
    5150             :   coordOutsideSize += aOffsets.hMargin;
    5151           0 : 
    5152             :   min += coordOutsideSize;
    5153           0 :   result = NSCoordSaturatingAdd(result, coordOutsideSize);
    5154           0 : 
    5155           0 :   nscoord size;
    5156             :   if (aType == nsLayoutUtils::MIN_ISIZE &&
    5157           0 :       ::IsReplacedBoxResolvedAgainstZero(aFrame, aStyleSize, aStyleMaxSize)) {
    5158             :     // XXX bug 1463700: this doesn't handle calc() according to spec
    5159             :     result = 0; // let |min| handle padding/border/margin
    5160           0 :   } else if (GetAbsoluteCoord(aStyleSize, size) ||
    5161             :              GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame,
    5162           0 :                                PROP_WIDTH, size)) {
    5163           0 :     result = size + coordOutsideSize;
    5164             :   }
    5165             : 
    5166           0 :   nscoord maxSize = aFixedMaxSize ? *aFixedMaxSize : 0;
    5167           0 :   if (aFixedMaxSize ||
    5168             :       GetIntrinsicCoord(aStyleMaxSize, aRenderingContext, aFrame,
    5169             :                         PROP_MAX_WIDTH, maxSize)) {
    5170           0 :     maxSize += coordOutsideSize;
    5171           0 :     if (result > maxSize) {
    5172             :       result = maxSize;
    5173           0 :     }
    5174             :   }
    5175             : 
    5176           0 :   nscoord minSize = aFixedMinSize ? *aFixedMinSize : 0;
    5177           0 :   if (aFixedMinSize ||
    5178           0 :       GetIntrinsicCoord(aStyleMinSize, aRenderingContext, aFrame,
    5179             :                         PROP_MIN_WIDTH, minSize)) {
    5180           0 :     minSize += coordOutsideSize;
    5181           0 :     if (result < minSize) {
    5182           0 :       result = minSize;
    5183             :     }
    5184             :   }
    5185             : 
    5186           0 :   if (result < min) {
    5187           0 :     result = min;
    5188           0 :   }
    5189             : 
    5190           0 :   const nsStyleDisplay* disp = aFrame->StyleDisplay();
    5191           0 :   if (aFrame->IsThemed(disp)) {
    5192           0 :     LayoutDeviceIntSize devSize;
    5193             :     bool canOverride = true;
    5194             :     nsPresContext* pc = aFrame->PresContext();
    5195             :     pc->GetTheme()->GetMinimumWidgetSize(pc, aFrame, disp->mAppearance,
    5196           0 :                                          &devSize, &canOverride);
    5197           0 :     nscoord themeSize =
    5198             :       pc->DevPixelsToAppUnits(aAxis == eAxisVertical ? devSize.height
    5199             :                                                      : devSize.width);
    5200           0 :     // GetMinimumWidgetSize() returns a border-box width.
    5201           0 :     themeSize += aOffsets.hMargin;
    5202           0 :     if (themeSize > result || !canOverride) {
    5203           0 :       result = themeSize;
    5204           0 :     }
    5205           0 :   }
    5206           0 :   return result;
    5207             : }
    5208           0 : 
    5209           0 : static void
    5210             : AddStateBitToAncestors(nsIFrame* aFrame, nsFrameState aBit)
    5211           0 : {
    5212           0 :   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
    5213           0 :     if (f->HasAnyStateBits(aBit)) {
    5214             :       break;
    5215             :     }
    5216           0 :     f->AddStateBits(aBit);
    5217             :   }
    5218             : }
    5219             : 
    5220           0 : /* static */ nscoord
    5221             : nsLayoutUtils::IntrinsicForAxis(PhysicalAxis              aAxis,
    5222           0 :                                 gfxContext*               aRenderingContext,
    5223           0 :                                 nsIFrame*                 aFrame,
    5224             :                                 IntrinsicISizeType        aType,
    5225             :                                 const Maybe<LogicalSize>& aPercentageBasis,
    5226           0 :                                 uint32_t                  aFlags,
    5227             :                                 nscoord                   aMarginBoxMinSizeClamp)
    5228           0 : {
    5229             :   MOZ_ASSERT(aFrame, "null frame");
    5230             :   MOZ_ASSERT(aFrame->GetParent(),
    5231           0 :              "IntrinsicForAxis called on frame not in tree");
    5232             :   MOZ_ASSERT(aType == MIN_ISIZE || aType == PREF_ISIZE, "bad type");
    5233             :   MOZ_ASSERT(aFrame->GetParent()->Type() != LayoutFrameType::GridContainer ||
    5234             :              aPercentageBasis.isSome(),
    5235             :              "grid layout should always pass a percentage basis");
    5236             : 
    5237             :   const bool horizontalAxis = MOZ_LIKELY(aAxis == eAxisHorizontal);
    5238             : #ifdef DEBUG_INTRINSIC_WIDTH
    5239           0 :   nsFrame::IndentBy(stderr, gNoiseIndent);
    5240           0 :   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5241             :   printf_stderr(" %s %s intrinsic size for container:\n",
    5242           0 :                 aType == MIN_ISIZE ? "min" : "pref",
    5243           0 :                 horizontalAxis ? "horizontal" : "vertical");
    5244             : #endif
    5245             : 
    5246             :   // If aFrame is a container for font size inflation, then shrink
    5247           0 :   // wrapping inside of it should not apply font size inflation.
    5248             :   AutoMaybeDisableFontInflation an(aFrame);
    5249             : 
    5250             :   // We want the size this frame will contribute to the parent's inline-size,
    5251             :   // so we work in the parent's writing mode; but if aFrame is orthogonal to
    5252             :   // its parent, we'll need to look at its BSize instead of min/pref-ISize.
    5253             :   const nsStylePosition* stylePos = aFrame->StylePosition();
    5254             :   StyleBoxSizing boxSizing = stylePos->mBoxSizing;
    5255             : 
    5256             :   const nsStyleCoord& styleMinISize =
    5257             :     horizontalAxis ? stylePos->mMinWidth : stylePos->mMinHeight;
    5258           0 :   const nsStyleCoord& styleISize =
    5259             :     (aFlags & MIN_INTRINSIC_ISIZE) ? styleMinISize :
    5260             :     (horizontalAxis ? stylePos->mWidth : stylePos->mHeight);
    5261             :   MOZ_ASSERT(!(aFlags & MIN_INTRINSIC_ISIZE) ||
    5262             :              styleISize.GetUnit() == eStyleUnit_Auto ||
    5263           0 :              styleISize.GetUnit() == eStyleUnit_Enumerated,
    5264           0 :              "should only use MIN_INTRINSIC_ISIZE for intrinsic values");
    5265             :   const nsStyleCoord& styleMaxISize =
    5266             :     horizontalAxis ? stylePos->mMaxWidth : stylePos->mMaxHeight;
    5267           0 : 
    5268             :   // We build up two values starting with the content box, and then
    5269           0 :   // adding padding, border and margin.  The result is normally
    5270           0 :   // |result|.  Then, when we handle 'width', 'min-width', and
    5271           0 :   // 'max-width', we use the results we've been building in |min| as a
    5272             :   // minimum, overriding 'min-width'.  This ensures two things:
    5273             :   //   * that we don't let a value of 'box-sizing' specifying a width
    5274             :   //     smaller than the padding/border inside the box-sizing box give
    5275             :   //     a content width less than zero
    5276           0 :   //   * that we prevent tables from becoming smaller than their
    5277             :   //     intrinsic minimum width
    5278             :   nscoord result = 0, min = 0;
    5279             : 
    5280             :   nscoord maxISize;
    5281             :   bool haveFixedMaxISize = GetAbsoluteCoord(styleMaxISize, maxISize);
    5282             :   nscoord minISize;
    5283             : 
    5284             :   // Treat "min-width: auto" as 0.
    5285             :   bool haveFixedMinISize;
    5286             :   if (eStyleUnit_Auto == styleMinISize.GetUnit()) {
    5287             :     // NOTE: Technically, "auto" is supposed to behave like "min-content" on
    5288           0 :     // flex items. However, we don't need to worry about that here, because
    5289             :     // flex items' min-sizes are intentionally ignored until the flex
    5290             :     // container explicitly considers them during space distribution.
    5291           0 :     minISize = 0;
    5292             :     haveFixedMinISize = true;
    5293             :   } else {
    5294             :     haveFixedMinISize = GetAbsoluteCoord(styleMinISize, minISize);
    5295             :   }
    5296           0 : 
    5297             :   PhysicalAxis ourInlineAxis =
    5298             :     aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
    5299             :   const bool isInlineAxis = aAxis == ourInlineAxis;
    5300             :   // If we have a specified width (or a specified 'min-width' greater
    5301           0 :   // than the specified 'max-width', which works out to the same thing),
    5302           0 :   // don't even bother getting the frame's intrinsic width, because in
    5303             :   // this case GetAbsoluteCoord(styleISize, w) will always succeed, so
    5304           0 :   // we'll never need the intrinsic dimensions.
    5305             :   if (styleISize.GetUnit() == eStyleUnit_Enumerated &&
    5306             :       (styleISize.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
    5307             :        styleISize.GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT)) {
    5308           0 :     // -moz-fit-content and -moz-available enumerated widths compute intrinsic
    5309           0 :     // widths just like auto.
    5310             :     // For -moz-max-content and -moz-min-content, we handle them like
    5311             :     // specified widths, but ignore box-sizing.
    5312             :     boxSizing = StyleBoxSizing::Content;
    5313             :   } else if (!styleISize.ConvertsToLength() &&
    5314             :              !(haveFixedMinISize && haveFixedMaxISize && maxISize <= minISize)) {
    5315           0 : #ifdef DEBUG_INTRINSIC_WIDTH
    5316           0 :     ++gNoiseIndent;
    5317           0 : #endif
    5318             :     if (MOZ_UNLIKELY(!isInlineAxis)) {
    5319             :       IntrinsicSize intrinsicSize = aFrame->GetIntrinsicSize();
    5320             :       const nsStyleCoord intrinsicBCoord =
    5321             :         horizontalAxis ? intrinsicSize.width : intrinsicSize.height;
    5322             :       if (intrinsicBCoord.GetUnit() == eStyleUnit_Coord) {
    5323           0 :         result = intrinsicBCoord.GetCoordValue();
    5324           0 :       } else {
    5325             :         // We don't have an intrinsic bsize and we need aFrame's block-dir size.
    5326             :         if (aFlags & BAIL_IF_REFLOW_NEEDED) {
    5327             :           return NS_INTRINSIC_WIDTH_UNKNOWN;
    5328           0 :         }
    5329           0 :         // XXX Unfortunately, we probably don't know this yet, so this is wrong...
    5330             :         // but it's not clear what we should do. If aFrame's inline size hasn't
    5331           0 :         // been determined yet, we can't necessarily figure out its block size
    5332           0 :         // either. For now, authors who put orthogonal elements into things like
    5333           0 :         // buttons or table cells may have to explicitly provide sizes rather
    5334             :         // than expecting intrinsic sizing to work "perfectly" in underspecified
    5335             :         // cases.
    5336           0 :         result = aFrame->BSize();
    5337           0 :       }
    5338             :     } else {
    5339             :       result = aType == MIN_ISIZE
    5340             :                ? aFrame->GetMinISize(aRenderingContext)
    5341             :                : aFrame->GetPrefISize(aRenderingContext);
    5342             :     }
    5343             : #ifdef DEBUG_INTRINSIC_WIDTH
    5344             :     --gNoiseIndent;
    5345             :     nsFrame::IndentBy(stderr, gNoiseIndent);
    5346           0 :     static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5347             :     printf_stderr(" %s %s intrinsic size from frame is %d.\n",
    5348             :                   aType == MIN_ISIZE ? "min" : "pref",
    5349           0 :                   horizontalAxis ? "horizontal" : "vertical",
    5350           0 :                   result);
    5351           0 : #endif
    5352             : 
    5353             :     // Handle elements with an intrinsic ratio (or size) and a specified
    5354             :     // height, min-height, or max-height.
    5355             :     // NOTE: We treat "min-height:auto" as "0" for the purpose of this code,
    5356             :     // since that's what it means in all cases except for on flex items -- and
    5357             :     // even there, we're supposed to ignore it (i.e. treat it as 0) until the
    5358             :     // flex container explicitly considers it.
    5359             :     const nsStyleCoord& styleBSize =
    5360             :       horizontalAxis ? stylePos->mHeight : stylePos->mWidth;
    5361             :     const nsStyleCoord& styleMinBSize =
    5362             :       horizontalAxis ? stylePos->mMinHeight : stylePos->mMinWidth;
    5363             :     const nsStyleCoord& styleMaxBSize =
    5364             :       horizontalAxis ? stylePos->mMaxHeight : stylePos->mMaxWidth;
    5365             : 
    5366             :     if (styleBSize.GetUnit() != eStyleUnit_Auto ||
    5367             :         !(styleMinBSize.GetUnit() == eStyleUnit_Auto ||
    5368             :           (styleMinBSize.GetUnit() == eStyleUnit_Coord &&
    5369             :            styleMinBSize.GetCoordValue() == 0)) ||
    5370           0 :         styleMaxBSize.GetUnit() != eStyleUnit_None) {
    5371             : 
    5372           0 :       nsSize ratio(aFrame->GetIntrinsicRatio());
    5373             :       nscoord ratioISize = (horizontalAxis ? ratio.width  : ratio.height);
    5374           0 :       nscoord ratioBSize = (horizontalAxis ? ratio.height : ratio.width);
    5375             :       if (ratioBSize != 0) {
    5376           0 :         AddStateBitToAncestors(aFrame,
    5377           0 :             NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE);
    5378           0 : 
    5379           0 :         nscoord bSizeTakenByBoxSizing =
    5380           0 :           GetDefiniteSizeTakenByBoxSizing(boxSizing, aFrame, !isInlineAxis,
    5381             :                                           aFlags & IGNORE_PADDING,
    5382           0 :                                           aPercentageBasis);
    5383           0 :         // NOTE: This is only the minContentSize if we've been passed MIN_INTRINSIC_ISIZE
    5384           0 :         // (which is fine, because this should only be used inside a check for that flag).
    5385           0 :         nscoord minContentSize = result;
    5386             :         nscoord h;
    5387           0 :         if (GetDefiniteSize(styleBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
    5388             :             (aPercentageBasis.isNothing() &&
    5389             :              GetPercentBSize(styleBSize, aFrame, horizontalAxis, h))) {
    5390           0 :           h = std::max(0, h - bSizeTakenByBoxSizing);
    5391           0 :           result = NSCoordMulDiv(h, ratioISize, ratioBSize);
    5392           0 :         }
    5393             : 
    5394             :         if (GetDefiniteSize(styleMaxBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
    5395           0 :             (aPercentageBasis.isNothing() &&
    5396             :              GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) {
    5397           0 :           h = std::max(0, h - bSizeTakenByBoxSizing);
    5398           0 :           nscoord maxISize = NSCoordMulDiv(h, ratioISize, ratioBSize);
    5399           0 :           if (maxISize < result) {
    5400           0 :             result = maxISize;
    5401           0 :           }
    5402             :           if (maxISize < minContentSize) {
    5403             :             minContentSize = maxISize;
    5404           0 :           }
    5405           0 :         }
    5406           0 : 
    5407           0 :         if (GetDefiniteSize(styleMinBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
    5408           0 :             (aPercentageBasis.isNothing() &&
    5409           0 :              GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) {
    5410           0 :           h = std::max(0, h - bSizeTakenByBoxSizing);
    5411             :           nscoord minISize = NSCoordMulDiv(h, ratioISize, ratioBSize);
    5412           0 :           if (minISize > result) {
    5413           0 :             result = minISize;
    5414             :           }
    5415             :           if (minISize > minContentSize) {
    5416             :             minContentSize = minISize;
    5417           0 :           }
    5418           0 :         }
    5419           0 :         if (MOZ_UNLIKELY(aFlags & nsLayoutUtils::MIN_INTRINSIC_ISIZE)) {
    5420           0 :           // This is the 'min-width/height:auto' "transferred size" piece of:
    5421           0 :           // https://www.w3.org/TR/css-flexbox-1/#min-width-automatic-minimum-size
    5422           0 :           // https://drafts.csswg.org/css-grid/#min-size-auto
    5423           0 :           result = std::min(result, minContentSize);
    5424             :         }
    5425           0 :       }
    5426           0 :     }
    5427             :   }
    5428             : 
    5429           0 :   if (aFrame->IsTableFrame()) {
    5430             :     // Tables can't shrink smaller than their intrinsic minimum width,
    5431             :     // no matter what.
    5432             :     min = aFrame->GetMinISize(aRenderingContext);
    5433           0 :   }
    5434             : 
    5435             :   nscoord pmPercentageBasis = NS_UNCONSTRAINEDSIZE;
    5436             :   if (aPercentageBasis.isSome()) {
    5437             :     // The padding/margin percentage basis is the inline-size in the parent's
    5438             :     // writing-mode.
    5439           0 :     auto childWM = aFrame->GetWritingMode();
    5440             :     pmPercentageBasis =
    5441             :       aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ?
    5442           0 :         aPercentageBasis->BSize(childWM) :
    5443             :         aPercentageBasis->ISize(childWM);
    5444             :   }
    5445           0 :   nsIFrame::IntrinsicISizeOffsetData offsets =
    5446           0 :     MOZ_LIKELY(isInlineAxis) ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis)
    5447             :                              : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis);
    5448             :   nscoord contentBoxSize = result;
    5449           0 :   result = AddIntrinsicSizeOffset(aRenderingContext, aFrame, offsets, aType,
    5450           0 :                                   boxSizing, result, min, styleISize,
    5451           0 :                                   haveFixedMinISize ? &minISize : nullptr,
    5452           0 :                                   styleMinISize,
    5453           0 :                                   haveFixedMaxISize ? &maxISize : nullptr,
    5454             :                                   styleMaxISize,
    5455             :                                   aFlags, aAxis);
    5456           0 :   nscoord overflow = result - aMarginBoxMinSizeClamp;
    5457           0 :   if (MOZ_UNLIKELY(overflow > 0)) {
    5458           0 :     nscoord newContentBoxSize = std::max(nscoord(0), contentBoxSize - overflow);
    5459           0 :     result -= contentBoxSize - newContentBoxSize;
    5460             :   }
    5461             : 
    5462             : #ifdef DEBUG_INTRINSIC_WIDTH
    5463             :   nsFrame::IndentBy(stderr, gNoiseIndent);
    5464             :   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5465             :   printf_stderr(" %s %s intrinsic size for container is %d twips.\n",
    5466           0 :                 aType == MIN_ISIZE ? "min" : "pref",
    5467           0 :                 horizontalAxis ? "horizontal" : "vertical",
    5468           0 :                 result);
    5469           0 : #endif
    5470             : 
    5471             :   return result;
    5472             : }
    5473             : 
    5474             : /* static */ nscoord
    5475             : nsLayoutUtils::IntrinsicForContainer(gfxContext* aRenderingContext,
    5476             :                                      nsIFrame* aFrame,
    5477             :                                      IntrinsicISizeType aType,
    5478             :                                      uint32_t aFlags)
    5479             : {
    5480             :   MOZ_ASSERT(aFrame && aFrame->GetParent());
    5481           0 :   // We want the size aFrame will contribute to its parent's inline-size.
    5482             :   PhysicalAxis axis =
    5483             :     aFrame->GetParent()->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
    5484             :   return IntrinsicForAxis(axis, aRenderingContext, aFrame, aType, Nothing(), aFlags);
    5485           0 : }
    5486             : 
    5487             : /* static */ nscoord
    5488             : nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis       aAxis,
    5489             :                                           gfxContext*        aRC,
    5490           0 :                                           nsIFrame*          aFrame,
    5491             :                                           IntrinsicISizeType aType,
    5492             :                                           const LogicalSize& aPercentageBasis,
    5493           0 :                                           uint32_t           aFlags)
    5494           0 : {
    5495             :   MOZ_ASSERT(aFrame);
    5496             :   MOZ_ASSERT(aFrame->IsFlexOrGridItem(),
    5497             :              "only grid/flex items have this behavior currently");
    5498           0 : 
    5499             : #ifdef DEBUG_INTRINSIC_WIDTH
    5500             :   nsFrame::IndentBy(stderr, gNoiseIndent);
    5501             :   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5502             :   printf_stderr(" %s min-isize for %s WM:\n",
    5503             :                 aType == MIN_ISIZE ? "min" : "pref",
    5504             :                 aWM.IsVertical() ? "vertical" : "horizontal");
    5505           0 : #endif
    5506           0 : 
    5507             :   // Note: this method is only meant for grid/flex items.
    5508             :   const nsStylePosition* const stylePos = aFrame->StylePosition();
    5509             :   const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth
    5510             :                                                        : &stylePos->mMinHeight;
    5511             :   nscoord minSize;
    5512             :   nscoord* fixedMinSize = nullptr;
    5513             :   auto minSizeUnit = style->GetUnit();
    5514             :   if (minSizeUnit == eStyleUnit_Auto) {
    5515             :     if (aFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) {
    5516             :       style = aAxis == eAxisHorizontal ? &stylePos->mWidth
    5517             :                                        : &stylePos->mHeight;
    5518           0 :       if (GetAbsoluteCoord(*style, minSize)) {
    5519           0 :         // We have a definite width/height.  This is the "specified size" in:
    5520           0 :         // https://drafts.csswg.org/css-grid/#min-size-auto
    5521             :         fixedMinSize = &minSize;
    5522           0 :       } else if (::IsReplacedBoxResolvedAgainstZero(aFrame, *style,
    5523           0 :                      eAxisHorizontal ? stylePos->mMaxWidth
    5524           0 :                                      : stylePos->mMaxHeight)) {
    5525           0 :         // XXX bug 1463700: this doesn't handle calc() according to spec
    5526           0 :         minSize = 0;
    5527             :         fixedMinSize = &minSize;
    5528           0 :       }
    5529             :       // fall through - the caller will have to deal with "transferred size"
    5530             :     } else {
    5531             :       // min-[width|height]:auto with overflow != visible computes to zero.
    5532           0 :       minSize = 0;
    5533             :       fixedMinSize = &minSize;
    5534             :     }
    5535             :   } else if (GetAbsoluteCoord(*style, minSize)) {
    5536           0 :     fixedMinSize = &minSize;
    5537           0 :   } else if (minSizeUnit != eStyleUnit_Enumerated) {
    5538             :     MOZ_ASSERT(style->HasPercent());
    5539             :     minSize = 0;
    5540             :     fixedMinSize = &minSize;
    5541             :   }
    5542           0 : 
    5543           0 :   if (!fixedMinSize) {
    5544             :     // Let the caller deal with the "content size" cases.
    5545           0 : #ifdef DEBUG_INTRINSIC_WIDTH
    5546             :     nsFrame::IndentBy(stderr, gNoiseIndent);
    5547           0 :     static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5548           0 :     printf_stderr(" %s min-isize is indefinite.\n",
    5549           0 :                   aType == MIN_ISIZE ? "min" : "pref");
    5550           0 : #endif
    5551             :     return NS_UNCONSTRAINEDSIZE;
    5552             :   }
    5553           0 : 
    5554             :   // If aFrame is a container for font size inflation, then shrink
    5555             :   // wrapping inside of it should not apply font size inflation.
    5556             :   AutoMaybeDisableFontInflation an(aFrame);
    5557             : 
    5558             :   // The padding/margin percentage basis is the inline-size in the parent's
    5559             :   // writing-mode.
    5560             :   auto childWM = aFrame->GetWritingMode();
    5561             :   nscoord pmPercentageBasis =
    5562             :     aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ?
    5563             :       aPercentageBasis.BSize(childWM) :
    5564             :       aPercentageBasis.ISize(childWM);
    5565             :   PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline);
    5566           0 :   nsIFrame::IntrinsicISizeOffsetData offsets =
    5567             :     ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis)
    5568             :                            : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis);
    5569             :   nscoord result = 0;
    5570           0 :   nscoord min = 0;
    5571             :   const nsStyleCoord& maxISize =
    5572           0 :     aAxis == eAxisHorizontal ? stylePos->mMaxWidth : stylePos->mMaxHeight;
    5573             :   result = AddIntrinsicSizeOffset(aRC, aFrame, offsets, aType,
    5574           0 :                                   stylePos->mBoxSizing,
    5575           0 :                                   result, min, *style, fixedMinSize,
    5576             :                                   *style, nullptr, maxISize, aFlags, aAxis);
    5577           0 : 
    5578           0 : #ifdef DEBUG_INTRINSIC_WIDTH
    5579           0 :   nsFrame::IndentBy(stderr, gNoiseIndent);
    5580           0 :   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
    5581             :   printf_stderr(" %s min-isize is %d twips.\n",
    5582           0 :          aType == MIN_ISIZE ? "min" : "pref", result);
    5583             : #endif
    5584           0 : 
    5585             :   return result;
    5586           0 : }
    5587             : 
    5588             : /* static */ nscoord
    5589             : nsLayoutUtils::ComputeCBDependentValue(nscoord aPercentBasis,
    5590             :                                        const nsStyleCoord& aCoord)
    5591             : {
    5592             :   NS_WARNING_ASSERTION(
    5593             :     aPercentBasis != NS_UNCONSTRAINEDSIZE,
    5594             :     "have unconstrained width or height; this should only result from very "
    5595             :     "large sizes, not attempts at intrinsic size calculation");
    5596             : 
    5597             :   if (aCoord.IsCoordPercentCalcUnit()) {
    5598             :     return aCoord.ComputeCoordPercentCalc(aPercentBasis);
    5599           0 :   }
    5600             :   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
    5601             :                aCoord.GetUnit() == eStyleUnit_Auto,
    5602           0 :                "unexpected width value");
    5603             :   return 0;
    5604             : }
    5605             : 
    5606             : /* static */ nscoord
    5607           0 : nsLayoutUtils::ComputeBSizeDependentValue(
    5608           0 :                  nscoord              aContainingBlockBSize,
    5609             :                  const nsStyleCoord&  aCoord)
    5610           0 : {
    5611             :   // XXXldb Some callers explicitly check aContainingBlockBSize
    5612             :   // against NS_AUTOHEIGHT *and* unit against eStyleUnit_Percent or
    5613             :   // calc()s containing percents before calling this function.
    5614             :   // However, it would be much more likely to catch problems without
    5615             :   // the unit conditions.
    5616             :   // XXXldb Many callers pass a non-'auto' containing block height when
    5617           0 :   // according to CSS2.1 they should be passing 'auto'.
    5618             :   MOZ_ASSERT(NS_AUTOHEIGHT != aContainingBlockBSize ||
    5619             :              !aCoord.HasPercent(),
    5620             :              "unexpected containing block block-size");
    5621             : 
    5622             :   if (aCoord.IsCoordPercentCalcUnit()) {
    5623             :     return aCoord.ComputeCoordPercentCalc(aContainingBlockBSize);
    5624             :   }
    5625             : 
    5626             :   NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
    5627             :                aCoord.GetUnit() == eStyleUnit_Auto,
    5628           0 :                "unexpected block-size value");
    5629             :   return 0;
    5630             : }
    5631             : 
    5632           0 : /* static */ void
    5633           0 : nsLayoutUtils::MarkDescendantsDirty(nsIFrame *aSubtreeRoot)
    5634             : {
    5635             :   AutoTArray<nsIFrame*, 4> subtrees;
    5636           0 :   subtrees.AppendElement(aSubtreeRoot);
    5637             : 
    5638             :   // dirty descendants, iterating over subtrees that may include
    5639             :   // additional subtrees associated with placeholders
    5640             :   do {
    5641             :     nsIFrame *subtreeRoot = subtrees.PopLastElement();
    5642             : 
    5643           0 :     // Mark all descendants dirty (using an nsTArray stack rather than
    5644             :     // recursion).
    5645           0 :     // Note that ReflowInput::InitResizeFlags has some similar
    5646           0 :     // code; see comments there for how and why it differs.
    5647             :     AutoTArray<nsIFrame*, 32> stack;
    5648             :     stack.AppendElement(subtreeRoot);
    5649             : 
    5650           0 :     do {
    5651           0 :       nsIFrame *f = stack.PopLastElement();
    5652             : 
    5653             :       f->MarkIntrinsicISizesDirty();
    5654             : 
    5655             :       if (f->IsPlaceholderFrame()) {
    5656             :         nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
    5657           0 :         if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
    5658           0 :           // We have another distinct subtree we need to mark.
    5659             :           subtrees.AppendElement(oof);
    5660           0 :         }
    5661           0 :       }
    5662             : 
    5663           0 :       nsIFrame::ChildListIterator lists(f);
    5664             :       for (; !lists.IsDone(); lists.Next()) {
    5665           0 :         nsFrameList::Enumerator childFrames(lists.CurrentList());
    5666           0 :         for (; !childFrames.AtEnd(); childFrames.Next()) {
    5667           0 :           nsIFrame* kid = childFrames.get();
    5668             :           stack.AppendElement(kid);
    5669           0 :         }
    5670             :       }
    5671             :     } while (stack.Length() != 0);
    5672             :   } while (subtrees.Length() != 0);
    5673           0 : }
    5674           0 : 
    5675           0 : /* static */
    5676           0 : void
    5677           0 : nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame)
    5678           0 : {
    5679             :   AutoTArray<nsIFrame*, 32> stack;
    5680             :   stack.AppendElement(aFrame);
    5681           0 : 
    5682           0 :   do {
    5683           0 :     nsIFrame* f = stack.PopLastElement();
    5684             : 
    5685             :     if (!f->HasAnyStateBits(
    5686             :         NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
    5687           0 :       continue;
    5688             :     }
    5689           0 :     f->MarkIntrinsicISizesDirty();
    5690           0 : 
    5691             :     for (nsIFrame::ChildListIterator lists(f); !lists.IsDone(); lists.Next()) {
    5692           0 :       for (nsIFrame* kid : lists.CurrentList()) {
    5693           0 :         stack.AppendElement(kid);
    5694             :       }
    5695           0 :     }
    5696             :   } while (stack.Length() != 0);
    5697             : }
    5698             : 
    5699           0 : nsSize
    5700             : nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(nscoord minWidth, nscoord minHeight,
    5701           0 :                                                       nscoord maxWidth, nscoord maxHeight,
    5702           0 :                                                       nscoord tentWidth, nscoord tentHeight)
    5703           0 : {
    5704             :   // Now apply min/max-width/height - CSS 2.1 sections 10.4 and 10.7:
    5705             : 
    5706           0 :   if (minWidth > maxWidth)
    5707           0 :     maxWidth = minWidth;
    5708             :   if (minHeight > maxHeight)
    5709             :     maxHeight = minHeight;
    5710           0 : 
    5711             :   nscoord heightAtMaxWidth, heightAtMinWidth,
    5712             :           widthAtMaxHeight, widthAtMinHeight;
    5713             : 
    5714             :   if (tentWidth > 0) {
    5715             :     heightAtMaxWidth = NSCoordMulDiv(maxWidth, tentHeight, tentWidth);
    5716           0 :     if (heightAtMaxWidth < minHeight)
    5717           0 :       heightAtMaxWidth = minHeight;
    5718           0 :     heightAtMinWidth = NSCoordMulDiv(minWidth, tentHeight, tentWidth);
    5719           0 :     if (heightAtMinWidth > maxHeight)
    5720             :       heightAtMinWidth = maxHeight;
    5721             :   } else {
    5722             :     heightAtMaxWidth = heightAtMinWidth = NS_CSS_MINMAX(tentHeight, minHeight, maxHeight);
    5723             :   }
    5724           0 : 
    5725           0 :   if (tentHeight > 0) {
    5726           0 :     widthAtMaxHeight = NSCoordMulDiv(maxHeight, tentWidth, tentHeight);
    5727           0 :     if (widthAtMaxHeight < minWidth)
    5728           0 :       widthAtMaxHeight = minWidth;
    5729           0 :     widthAtMinHeight = NSCoordMulDiv(minHeight, tentWidth, tentHeight);
    5730           0 :     if (widthAtMinHeight > maxWidth)
    5731             :       widthAtMinHeight = maxWidth;
    5732             :   } else {
    5733             :     widthAtMaxHeight = widthAtMinHeight = NS_CSS_MINMAX(tentWidth, minWidth, maxWidth);
    5734             :   }
    5735           0 : 
    5736           0 :   // The table at http://www.w3.org/TR/CSS21/visudet.html#min-max-widths :
    5737           0 : 
    5738           0 :   nscoord width, height;
    5739           0 : 
    5740           0 :   if (tentWidth > maxWidth) {
    5741           0 :     if (tentHeight > maxHeight) {
    5742             :       if (int64_t(maxWidth) * int64_t(tentHeight) <=
    5743             :           int64_t(maxHeight) * int64_t(tentWidth)) {
    5744             :         width = maxWidth;
    5745             :         height = heightAtMaxWidth;
    5746             :       } else {
    5747             :         width = widthAtMaxHeight;
    5748             :         height = maxHeight;
    5749             :       }
    5750           0 :     } else {
    5751           0 :       // This also covers "(w > max-width) and (h < min-height)" since in
    5752           0 :       // that case (max-width/w < 1), and with (h < min-height):
    5753           0 :       //   max(max-width * h/w, min-height) == min-height
    5754             :       width = maxWidth;
    5755             :       height = heightAtMaxWidth;
    5756             :     }
    5757           0 :   } else if (tentWidth < minWidth) {
    5758           0 :     if (tentHeight < minHeight) {
    5759             :       if (int64_t(minWidth) * int64_t(tentHeight) <=
    5760             :           int64_t(minHeight) * int64_t(tentWidth)) {
    5761             :         width = widthAtMinHeight;
    5762             :         height = minHeight;
    5763             :       } else {
    5764             :         width = minWidth;
    5765             :         height = heightAtMinWidth;
    5766             :       }
    5767           0 :     } else {
    5768           0 :       // This also covers "(w < min-width) and (h > max-height)" since in
    5769           0 :       // that case (min-width/w > 1), and with (h > max-height):
    5770           0 :       //   min(min-width * h/w, max-height) == max-height
    5771             :       width = minWidth;
    5772             :       height = heightAtMinWidth;
    5773             :     }
    5774           0 :   } else {
    5775           0 :     if (tentHeight > maxHeight) {
    5776             :       width = widthAtMaxHeight;
    5777             :       height = maxHeight;
    5778             :     } else if (tentHeight < minHeight) {
    5779             :       width = widthAtMinHeight;
    5780             :       height = minHeight;
    5781             :     } else {
    5782             :       width = tentWidth;
    5783             :       height = tentHeight;
    5784             :     }
    5785           0 :   }
    5786             : 
    5787             :   return nsSize(width, height);
    5788           0 : }
    5789             : 
    5790             : /* static */ nscoord
    5791             : nsLayoutUtils::MinISizeFromInline(nsIFrame* aFrame,
    5792           0 :                                   gfxContext* aRenderingContext)
    5793           0 : {
    5794             :   NS_ASSERTION(!aFrame->IsContainerForFontSizeInflation(),
    5795             :                "should not be container for font size inflation");
    5796             : 
    5797           0 :   nsIFrame::InlineMinISizeData data;
    5798             :   DISPLAY_MIN_WIDTH(aFrame, data.mPrevLines);
    5799             :   aFrame->AddInlineMinISize(aRenderingContext, &data);
    5800             :   data.ForceBreak();
    5801           0 :   return data.mPrevLines;
    5802             : }
    5803             : 
    5804           0 : /* static */ nscoord
    5805             : nsLayoutUtils::PrefISizeFromInline(nsIFrame* aFrame,
    5806             :                                    gfxContext* aRenderingContext)
    5807           0 : {
    5808           0 :   NS_ASSERTION(!aFrame->IsContainerForFontSizeInflation(),
    5809           0 :                "should not be container for font size inflation");
    5810           0 : 
    5811           0 :   nsIFrame::InlinePrefISizeData data;
    5812             :   DISPLAY_PREF_WIDTH(aFrame, data.mPrevLines);
    5813             :   aFrame->AddInlinePrefISize(aRenderingContext, &data);
    5814             :   data.ForceBreak();
    5815           0 :   return data.mPrevLines;
    5816             : }
    5817             : 
    5818           0 : static nscolor
    5819             : DarkenColor(nscolor aColor)
    5820             : {
    5821           0 :   uint16_t  hue, sat, value;
    5822           0 :   uint8_t alpha;
    5823           0 : 
    5824           0 :   // convert the RBG to HSV so we can get the lightness (which is the v)
    5825           0 :   NS_RGB2HSV(aColor, hue, sat, value, alpha);
    5826             : 
    5827             :   // The goal here is to send white to black while letting colored
    5828             :   // stuff stay colored... So we adopt the following approach.
    5829           0 :   // Something with sat = 0 should end up with value = 0.  Something
    5830             :   // with a high sat can end up with a high value and it's ok.... At
    5831             :   // the same time, we don't want to make things lighter.  Do
    5832             :   // something simple, since it seems to work.
    5833             :   if (value > sat) {
    5834             :     value = sat;
    5835           0 :     // convert this color back into the RGB color space.
    5836             :     NS_HSV2RGB(aColor, hue, sat, value, alpha);
    5837             :   }
    5838             :   return aColor;
    5839             : }
    5840             : 
    5841             : // Check whether we should darken text/decoration colors. We need to do this if
    5842             : // background images and colors are being suppressed, because that means
    5843           0 : // light text will not be visible against the (presumed light-colored) background.
    5844           0 : static bool
    5845             : ShouldDarkenColors(nsPresContext* aPresContext)
    5846           0 : {
    5847             :   return !aPresContext->GetBackgroundColorDraw() &&
    5848           0 :          !aPresContext->GetBackgroundImageDraw();
    5849             : }
    5850             : 
    5851             : nscolor
    5852             : nsLayoutUtils::DarkenColorIfNeeded(nsIFrame* aFrame, nscolor aColor)
    5853             : {
    5854             :   if (ShouldDarkenColors(aFrame->PresContext())) {
    5855           0 :     return DarkenColor(aColor);
    5856             :   }
    5857           0 :   return aColor;
    5858           0 : }
    5859             : 
    5860             : gfxFloat
    5861             : nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
    5862           0 :                                    nscoord aY, nscoord aAscent)
    5863             : {
    5864           0 :   gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
    5865           0 :   gfxFloat baseline = gfxFloat(aY) + aAscent;
    5866             :   gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
    5867             :   if (!aContext->UserToDevicePixelSnapped(putativeRect, true))
    5868             :     return baseline;
    5869             :   return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
    5870             : }
    5871           0 : 
    5872             : gfxFloat
    5873             : nsLayoutUtils::GetSnappedBaselineX(nsIFrame* aFrame, gfxContext* aContext,
    5874           0 :                                    nscoord aX, nscoord aAscent)
    5875           0 : {
    5876           0 :   gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
    5877           0 :   gfxFloat baseline = gfxFloat(aX) + aAscent;
    5878             :   gfxRect putativeRect(baseline / appUnitsPerDevUnit, 0, 1, 1);
    5879           0 :   if (!aContext->UserToDevicePixelSnapped(putativeRect, true)) {
    5880             :     return baseline;
    5881             :   }
    5882             :   return aContext->DeviceToUser(putativeRect.TopLeft()).x * appUnitsPerDevUnit;
    5883           0 : }
    5884             : 
    5885             : // Hard limit substring lengths to 8000 characters ... this lets us statically
    5886           0 : // size the cluster buffer array in FindSafeLength
    5887           0 : #define MAX_GFX_TEXT_BUF_SIZE 8000
    5888           0 : 
    5889           0 : static int32_t FindSafeLength(const char16_t *aString, uint32_t aLength,
    5890             :                               uint32_t aMaxChunkLength)
    5891             : {
    5892           0 :   if (aLength <= aMaxChunkLength)
    5893             :     return aLength;
    5894             : 
    5895             :   int32_t len = aMaxChunkLength;
    5896             : 
    5897             :   // Ensure that we don't break inside a surrogate pair
    5898             :   while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
    5899           0 :     len--;
    5900             :   }
    5901             :   if (len == 0) {
    5902           0 :     // We don't want our caller to go into an infinite loop, so don't
    5903           0 :     // return zero. It's hard to imagine how we could actually get here
    5904             :     // unless there are languages that allow clusters of arbitrary size.
    5905           0 :     // If there are and someone feeds us a 500+ character cluster, too
    5906             :     // bad.
    5907             :     return aMaxChunkLength;
    5908           0 :   }
    5909           0 :   return len;
    5910             : }
    5911           0 : 
    5912             : static int32_t GetMaxChunkLength(nsFontMetrics& aFontMetrics)
    5913             : {
    5914             :   return std::min(aFontMetrics.GetMaxStringLength(), MAX_GFX_TEXT_BUF_SIZE);
    5915             : }
    5916             : 
    5917           0 : nscoord
    5918             : nsLayoutUtils::AppUnitWidthOfString(const char16_t *aString,
    5919             :                                     uint32_t aLength,
    5920             :                                     nsFontMetrics& aFontMetrics,
    5921             :                                     DrawTarget* aDrawTarget)
    5922           0 : {
    5923             :   uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
    5924           0 :   nscoord width = 0;
    5925             :   while (aLength > 0) {
    5926             :     int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
    5927             :     width += aFontMetrics.GetWidth(aString, len, aDrawTarget);
    5928           0 :     aLength -= len;
    5929             :     aString += len;
    5930             :   }
    5931             :   return width;
    5932             : }
    5933           0 : 
    5934           0 : nscoord
    5935           0 : nsLayoutUtils::AppUnitWidthOfStringBidi(const char16_t* aString,
    5936           0 :                                         uint32_t aLength,
    5937           0 :                                         const nsIFrame* aFrame,
    5938           0 :                                         nsFontMetrics& aFontMetrics,
    5939           0 :                                         gfxContext& aContext)
    5940             : {
    5941           0 :   nsPresContext* presContext = aFrame->PresContext();
    5942             :   if (presContext->BidiEnabled()) {
    5943             :     nsBidiLevel level =
    5944             :       nsBidiPresUtils::BidiLevelFromStyle(aFrame->Style());
    5945           0 :     return nsBidiPresUtils::MeasureTextWidth(aString, aLength, level,
    5946             :                                              presContext, aContext,
    5947             :                                              aFontMetrics);
    5948             :   }
    5949             :   aFontMetrics.SetTextRunRTL(false);
    5950             :   aFontMetrics.SetVertical(aFrame->GetWritingMode().IsVertical());
    5951           0 :   aFontMetrics.SetTextOrientation(aFrame->StyleVisibility()->mTextOrientation);
    5952           0 :   return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
    5953             :                                              aContext.GetDrawTarget());
    5954           0 : }
    5955           0 : 
    5956             : bool
    5957           0 : nsLayoutUtils::StringWidthIsGreaterThan(const nsString& aString,
    5958             :                                         nsFontMetrics& aFontMetrics,
    5959           0 :                                         DrawTarget* aDrawTarget,
    5960           0 :                                         nscoord aWidth)
    5961           0 : {
    5962           0 :   const char16_t *string = aString.get();
    5963           0 :   uint32_t length = aString.Length();
    5964             :   uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
    5965             :   nscoord width = 0;
    5966             :   while (length > 0) {
    5967           0 :     int32_t len = FindSafeLength(string, length, maxChunkLength);
    5968             :     width += aFontMetrics.GetWidth(string, len, aDrawTarget);
    5969             :     if (width > aWidth) {
    5970             :       return true;
    5971             :     }
    5972           0 :     length -= len;
    5973           0 :     string += len;
    5974           0 :   }
    5975           0 :   return false;
    5976           0 : }
    5977           0 : 
    5978           0 : nsBoundingMetrics
    5979           0 : nsLayoutUtils::AppUnitBoundsOfString(const char16_t* aString,
    5980             :                                      uint32_t aLength,
    5981             :                                      nsFontMetrics& aFontMetrics,
    5982           0 :                                      DrawTarget* aDrawTarget)
    5983           0 : {
    5984             :   uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
    5985             :   int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
    5986             :   // Assign directly in the first iteration. This ensures that
    5987             :   // negative ascent/descent can be returned and the left bearing
    5988             :   // is properly initialized.
    5989           0 :   nsBoundingMetrics totalMetrics =
    5990             :     aFontMetrics.GetBoundingMetrics(aString, len, aDrawTarget);
    5991             :   aLength -= len;
    5992             :   aString += len;
    5993             : 
    5994           0 :   while (aLength > 0) {
    5995           0 :     len = FindSafeLength(aString, aLength, maxChunkLength);
    5996             :     nsBoundingMetrics metrics =
    5997             :       aFontMetrics.GetBoundingMetrics(aString, len, aDrawTarget);
    5998             :     totalMetrics += metrics;
    5999             :     aLength -= len;
    6000           0 :     aString += len;
    6001           0 :   }
    6002           0 :   return totalMetrics;
    6003             : }
    6004           0 : 
    6005           0 : void
    6006             : nsLayoutUtils::DrawString(const nsIFrame*     aFrame,
    6007           0 :                           nsFontMetrics&      aFontMetrics,
    6008           0 :                           gfxContext*         aContext,
    6009           0 :                           const char16_t*     aString,
    6010           0 :                           int32_t             aLength,
    6011             :                           nsPoint             aPoint,
    6012           0 :                           ComputedStyle*      aComputedStyle,
    6013             :                           DrawStringFlags     aFlags)
    6014             : {
    6015             :   nsresult rv = NS_ERROR_FAILURE;
    6016           0 : 
    6017             :   // If caller didn't pass a style, use the frame's.
    6018             :   if (!aComputedStyle) {
    6019             :     aComputedStyle = aFrame->Style();
    6020             :   }
    6021             : 
    6022             :   if (aFlags & DrawStringFlags::eForceHorizontal) {
    6023             :     aFontMetrics.SetVertical(false);
    6024             :   } else {
    6025           0 :     aFontMetrics.SetVertical(WritingMode(aComputedStyle).IsVertical());
    6026             :   }
    6027             : 
    6028           0 :   aFontMetrics.SetTextOrientation(
    6029           0 :     aComputedStyle->StyleVisibility()->mTextOrientation);
    6030             : 
    6031             :   nsPresContext* presContext = aFrame->PresContext();
    6032           0 :   if (presContext->BidiEnabled()) {
    6033             :     nsBidiLevel level =
    6034             :       nsBidiPresUtils::BidiLevelFromStyle(aComputedStyle);
    6035           0 :     rv = nsBidiPresUtils::RenderText(aString, aLength, level,
    6036             :                                      presContext, *aContext,
    6037             :                                      aContext->GetDrawTarget(), aFontMetrics,
    6038           0 :                                      aPoint.x, aPoint.y);
    6039           0 :   }
    6040             :   if (NS_FAILED(rv))
    6041           0 :   {
    6042           0 :     aFontMetrics.SetTextRunRTL(false);
    6043             :     DrawUniDirString(aString, aLength, aPoint, aFontMetrics, *aContext);
    6044           0 :   }
    6045           0 : }
    6046             : 
    6047             : void
    6048           0 : nsLayoutUtils::DrawUniDirString(const char16_t* aString,
    6049             :                                 uint32_t aLength,
    6050           0 :                                 const nsPoint& aPoint,
    6051             :                                 nsFontMetrics& aFontMetrics,
    6052           0 :                                 gfxContext& aContext)
    6053           0 : {
    6054             :   nscoord x = aPoint.x;
    6055           0 :   nscoord y = aPoint.y;
    6056             : 
    6057             :   uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
    6058           0 :   if (aLength <= maxChunkLength) {
    6059             :     aFontMetrics.DrawString(aString, aLength, x, y, &aContext,
    6060             :                             aContext.GetDrawTarget());
    6061             :     return;
    6062             :   }
    6063             : 
    6064           0 :   bool isRTL = aFontMetrics.GetTextRunRTL();
    6065           0 : 
    6066             :   // If we're drawing right to left, we must start at the end.
    6067           0 :   if (isRTL) {
    6068           0 :     x += nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
    6069           0 :                                              aContext.GetDrawTarget());
    6070           0 :   }
    6071           0 : 
    6072             :   while (aLength > 0) {
    6073             :     int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
    6074           0 :     nscoord width = aFontMetrics.GetWidth(aString, len, aContext.GetDrawTarget());
    6075             :     if (isRTL) {
    6076             :       x -= width;
    6077           0 :     }
    6078           0 :     aFontMetrics.DrawString(aString, len, x, y, &aContext,
    6079             :                             aContext.GetDrawTarget());
    6080             :     if (!isRTL) {
    6081             :       x += width;
    6082           0 :     }
    6083           0 :     aLength -= len;
    6084           0 :     aString += len;
    6085           0 :   }
    6086           0 : }
    6087             : 
    6088           0 : /* static */ void
    6089           0 : nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
    6090           0 :                                gfxContext* aContext,
    6091           0 :                                const nsRect& aTextRect,
    6092             :                                const nsRect& aDirtyRect,
    6093           0 :                                const nscolor& aForegroundColor,
    6094           0 :                                TextShadowCallback aCallback,
    6095             :                                void* aCallbackData)
    6096             : {
    6097             :   const nsStyleText* textStyle = aFrame->StyleText();
    6098             :   if (!textStyle->HasTextShadow())
    6099           0 :     return;
    6100             : 
    6101             :   // Text shadow happens with the last value being painted at the back,
    6102             :   // ie. it is painted first.
    6103             :   gfxContext* aDestCtx = aContext;
    6104             :   for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
    6105             :     nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1);
    6106             :     nsPoint shadowOffset(shadowDetails->mXOffset,
    6107           0 :                          shadowDetails->mYOffset);
    6108           0 :     nscoord blurRadius = std::max(shadowDetails->mRadius, 0);
    6109             : 
    6110             :     nsRect shadowRect(aTextRect);
    6111             :     shadowRect.MoveBy(shadowOffset);
    6112             : 
    6113           0 :     nsPresContext* presCtx = aFrame->PresContext();
    6114           0 :     nsContextBoxBlur contextBoxBlur;
    6115           0 : 
    6116             :     nscolor shadowColor;
    6117           0 :     if (shadowDetails->mHasColor)
    6118           0 :       shadowColor = shadowDetails->mColor;
    6119             :     else
    6120           0 :       shadowColor = aForegroundColor;
    6121           0 : 
    6122             :     // Webrender just needs the shadow details
    6123           0 :     if (auto* textDrawer = aContext->GetTextDrawer()) {
    6124           0 :       wr::Shadow wrShadow;
    6125             : 
    6126             :       wrShadow.offset = {
    6127           0 :         presCtx->AppUnitsToFloatDevPixels(shadowDetails->mXOffset),
    6128           0 :         presCtx->AppUnitsToFloatDevPixels(shadowDetails->mYOffset)
    6129             :       };
    6130           0 : 
    6131             :       wrShadow.blur_radius = presCtx->AppUnitsToFloatDevPixels(shadowDetails->mRadius);
    6132             :       wrShadow.color = wr::ToColorF(ToDeviceColor(shadowColor));
    6133           0 : 
    6134             :       textDrawer->AppendShadow(wrShadow);
    6135             :       return;
    6136             :     }
    6137           0 : 
    6138           0 :     gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
    6139           0 :                                                     presCtx->AppUnitsPerDevPixel(),
    6140             :                                                     aDestCtx, aDirtyRect, nullptr,
    6141           0 :                                                     nsContextBoxBlur::DISABLE_HARDWARE_ACCELERATION_BLUR);
    6142           0 :     if (!shadowContext)
    6143             :       continue;
    6144           0 : 
    6145             :     
    6146             : 
    6147             :     aDestCtx->Save();
    6148           0 :     aDestCtx->NewPath();
    6149             :     aDestCtx->SetColor(Color::FromABGR(shadowColor));
    6150             : 
    6151           0 :     // The callback will draw whatever we want to blur as a shadow.
    6152           0 :     aCallback(shadowContext, shadowOffset, shadowColor, aCallbackData);
    6153           0 : 
    6154             :     contextBoxBlur.DoPaint();
    6155             :     aDestCtx->Restore();
    6156             :   }
    6157           0 : }
    6158           0 : 
    6159           0 : /* static */ nscoord
    6160             : nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
    6161             :                                        nscoord        aLineHeight,
    6162           0 :                                        bool           aIsInverted)
    6163             : {
    6164           0 :   nscoord fontAscent = aIsInverted ? aFontMetrics->MaxDescent()
    6165           0 :                                    : aFontMetrics->MaxAscent();
    6166             :   nscoord fontHeight = aFontMetrics->MaxHeight();
    6167             : 
    6168             :   nscoord leading = aLineHeight - fontHeight;
    6169             :   return fontAscent + leading/2;
    6170           0 : }
    6171             : 
    6172             : 
    6173             : /* static */ bool
    6174           0 : nsLayoutUtils::GetFirstLineBaseline(WritingMode aWritingMode,
    6175           0 :                                     const nsIFrame* aFrame, nscoord* aResult)
    6176           0 : {
    6177             :   LinePosition position;
    6178           0 :   if (!GetFirstLinePosition(aWritingMode, aFrame, &position))
    6179           0 :     return false;
    6180             :   *aResult = position.mBaseline;
    6181             :   return true;
    6182             : }
    6183             : 
    6184           0 : /* static */ bool
    6185             : nsLayoutUtils::GetFirstLinePosition(WritingMode aWM,
    6186             :                                     const nsIFrame* aFrame,
    6187             :                                     LinePosition* aResult)
    6188           0 : {
    6189             :   const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
    6190           0 :   if (!block) {
    6191           0 :     // For the first-line baseline we also have to check for a table, and if
    6192             :     // so, use the baseline of its first row.
    6193             :     LayoutFrameType fType = aFrame->Type();
    6194             :     if (fType == LayoutFrameType::TableWrapper ||
    6195           0 :         fType == LayoutFrameType::FlexContainer ||
    6196             :         fType == LayoutFrameType::GridContainer) {
    6197             :       if ((fType == LayoutFrameType::GridContainer &&
    6198             :            aFrame->HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) ||
    6199           0 :           (fType == LayoutFrameType::FlexContainer &&
    6200           0 :            aFrame->HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) ||
    6201             :           (fType == LayoutFrameType::TableWrapper &&
    6202             :            static_cast<const nsTableWrapperFrame*>(aFrame)->GetRowCount() == 0)) {
    6203           0 :         // empty grid/flex/table container
    6204           0 :         aResult->mBStart = 0;
    6205           0 :         aResult->mBaseline = aFrame->SynthesizeBaselineBOffsetFromBorderBox(aWM,
    6206             :                                        BaselineSharingGroup::eFirst);
    6207           0 :         aResult->mBEnd = aFrame->BSize(aWM);
    6208           0 :         return true;
    6209           0 :       }
    6210           0 :       aResult->mBStart = 0;
    6211           0 :       aResult->mBaseline = aFrame->GetLogicalBaseline(aWM);
    6212           0 :       // This is what we want for the list bullet caller; not sure if
    6213             :       // other future callers will want the same.
    6214           0 :       aResult->mBEnd = aFrame->BSize(aWM);
    6215           0 :       return true;
    6216             :     }
    6217           0 : 
    6218           0 :     // For first-line baselines, we have to consider scroll frames.
    6219             :     if (fType == LayoutFrameType::Scroll) {
    6220           0 :       nsIScrollableFrame *sFrame = do_QueryFrame(const_cast<nsIFrame*>(aFrame));
    6221           0 :       if (!sFrame) {
    6222             :         NS_NOTREACHED("not scroll frame");
    6223             :       }
    6224           0 :       LinePosition kidPosition;
    6225           0 :       if (GetFirstLinePosition(aWM,
    6226             :                                sFrame->GetScrolledFrame(), &kidPosition)) {
    6227             :         // Consider only the border and padding that contributes to the
    6228             :         // kid's position, not the scrolling, so we get the initial
    6229           0 :         // position.
    6230           0 :         *aResult = kidPosition +
    6231           0 :           aFrame->GetLogicalUsedBorderAndPadding(aWM).BStart(aWM);
    6232           0 :         return true;
    6233             :       }
    6234             :       return false;
    6235           0 :     }
    6236           0 : 
    6237             :     if (fType == LayoutFrameType::FieldSet) {
    6238             :       LinePosition kidPosition;
    6239             :       nsIFrame* kid = aFrame->PrincipalChildList().FirstChild();
    6240             :       // kid might be a legend frame here, but that's ok.
    6241           0 :       if (GetFirstLinePosition(aWM, kid, &kidPosition)) {
    6242           0 :         *aResult = kidPosition +
    6243             :           kid->GetLogicalNormalPosition(aWM, aFrame->GetSize()).B(aWM);
    6244             :         return true;
    6245             :       }
    6246             :       return false;
    6247           0 :     }
    6248             : 
    6249           0 :     // No baseline.
    6250             :     return false;
    6251           0 :   }
    6252             : 
    6253           0 :   for (nsBlockFrame::ConstLineIterator line = block->LinesBegin(),
    6254           0 :                                        line_end = block->LinesEnd();
    6255             :        line != line_end; ++line) {
    6256             :     if (line->IsBlock()) {
    6257             :       nsIFrame *kid = line->mFirstChild;
    6258             :       LinePosition kidPosition;
    6259             :       if (GetFirstLinePosition(aWM, kid, &kidPosition)) {
    6260             :         //XXX Not sure if this is the correct value to use for container
    6261             :         //    width here. It will only be used in vertical-rl layout,
    6262             :         //    which we don't have full support and testing for yet.
    6263           0 :         const nsSize& containerSize = line->mContainerSize;
    6264           0 :         *aResult = kidPosition +
    6265             :                    kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
    6266           0 :         return true;
    6267           0 :       }
    6268             :     } else {
    6269           0 :       // XXX Is this the right test?  We have some bogus empty lines
    6270             :       // floating around, but IsEmpty is perhaps too weak.
    6271             :       if (line->BSize() != 0 || !line->IsEmpty()) {
    6272             :         nscoord bStart = line->BStart();
    6273           0 :         aResult->mBStart = bStart;
    6274             :         aResult->mBaseline = bStart + line->GetLogicalAscent();
    6275           0 :         aResult->mBEnd = bStart + line->BSize();
    6276           0 :         return true;
    6277             :       }
    6278             :     }
    6279             :   }
    6280             :   return false;
    6281           0 : }
    6282           0 : 
    6283           0 : /* static */ bool
    6284           0 : nsLayoutUtils::GetLastLineBaseline(WritingMode aWM,
    6285           0 :                                    const nsIFrame* aFrame, nscoord* aResult)
    6286           0 : {
    6287             :   const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
    6288             :   if (!block)
    6289             :     // No baseline.  (We intentionally don't descend into scroll frames.)
    6290           0 :     return false;
    6291             : 
    6292             :   for (nsBlockFrame::ConstReverseLineIterator line = block->LinesRBegin(),
    6293             :                                               line_end = block->LinesREnd();
    6294           0 :        line != line_end; ++line) {
    6295             :     if (line->IsBlock()) {
    6296             :       nsIFrame *kid = line->mFirstChild;
    6297           0 :       nscoord kidBaseline;
    6298           0 :       const nsSize& containerSize = line->mContainerSize;
    6299             :       if (GetLastLineBaseline(aWM, kid, &kidBaseline)) {
    6300             :         // Ignore relative positioning for baseline calculations
    6301             :         *aResult = kidBaseline +
    6302           0 :           kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
    6303           0 :         return true;
    6304             :       } else if (kid->IsScrollFrame()) {
    6305           0 :         // Defer to nsFrame::GetLogicalBaseline (which synthesizes a baseline
    6306           0 :         // from the margin-box).
    6307             :         kidBaseline = kid->GetLogicalBaseline(aWM);
    6308           0 :         *aResult = kidBaseline +
    6309           0 :           kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
    6310             :         return true;
    6311           0 :       }
    6312           0 :     } else {
    6313           0 :       // XXX Is this the right test?  We have some bogus empty lines
    6314           0 :       // floating around, but IsEmpty is perhaps too weak.
    6315             :       if (line->BSize() != 0 || !line->IsEmpty()) {
    6316             :         *aResult = line->BStart() + line->GetLogicalAscent();
    6317           0 :         return true;
    6318           0 :       }
    6319           0 :     }
    6320           0 :   }
    6321             :   return false;
    6322             : }
    6323             : 
    6324             : static nscoord
    6325           0 : CalculateBlockContentBEnd(WritingMode aWM, nsBlockFrame* aFrame)
    6326           0 : {
    6327           0 :   MOZ_ASSERT(aFrame, "null ptr");
    6328             : 
    6329             :   nscoord contentBEnd = 0;
    6330             : 
    6331           0 :   for (nsBlockFrame::LineIterator line = aFrame->LinesBegin(),
    6332             :                                   line_end = aFrame->LinesEnd();
    6333             :        line != line_end; ++line) {
    6334             :     if (line->IsBlock()) {
    6335           0 :       nsIFrame* child = line->mFirstChild;
    6336             :       const nsSize& containerSize = line->mContainerSize;
    6337           0 :       nscoord offset =
    6338             :         child->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
    6339           0 :       contentBEnd =
    6340             :         std::max(contentBEnd,
    6341           0 :                  nsLayoutUtils::CalculateContentBEnd(aWM, child) + offset);
    6342           0 :     }
    6343             :     else {
    6344           0 :       contentBEnd = std::max(contentBEnd, line->BEnd());
    6345           0 :     }
    6346           0 :   }
    6347             :   return contentBEnd;
    6348           0 : }
    6349           0 : 
    6350           0 : /* static */ nscoord
    6351           0 : nsLayoutUtils::CalculateContentBEnd(WritingMode aWM, nsIFrame* aFrame)
    6352             : {
    6353             :   MOZ_ASSERT(aFrame, "null ptr");
    6354           0 : 
    6355             :   nscoord contentBEnd = aFrame->BSize(aWM);
    6356             : 
    6357           0 :   // We want scrollable overflow rather than visual because this
    6358             :   // calculation is intended to affect layout.
    6359             :   LogicalSize overflowSize(aWM, aFrame->GetScrollableOverflowRect().Size());
    6360             :   if (overflowSize.BSize(aWM) > contentBEnd) {
    6361           0 :     nsIFrame::ChildListIDs skip(nsIFrame::kOverflowList |
    6362             :                                 nsIFrame::kExcessOverflowContainersList |
    6363           0 :                                 nsIFrame::kOverflowOutOfFlowList);
    6364             :     nsBlockFrame* blockFrame = GetAsBlock(aFrame);
    6365           0 :     if (blockFrame) {
    6366             :       contentBEnd =
    6367             :         std::max(contentBEnd, CalculateBlockContentBEnd(aWM, blockFrame));
    6368             :       skip |= nsIFrame::kPrincipalList;
    6369           0 :     }
    6370           0 :     nsIFrame::ChildListIterator lists(aFrame);
    6371           0 :     for (; !lists.IsDone(); lists.Next()) {
    6372             :       if (!skip.Contains(lists.CurrentID())) {
    6373           0 :         nsFrameList::Enumerator childFrames(lists.CurrentList());
    6374           0 :         for (; !childFrames.AtEnd(); childFrames.Next()) {
    6375           0 :           nsIFrame* child = childFrames.get();
    6376           0 :           nscoord offset =
    6377           0 :             child->GetLogicalNormalPosition(aWM,
    6378           0 :                                             aFrame->GetSize()).B(aWM);
    6379             :           contentBEnd = std::max(contentBEnd,
    6380           0 :                                  CalculateContentBEnd(aWM, child) + offset);
    6381           0 :         }
    6382           0 :       }
    6383           0 :     }
    6384           0 :   }
    6385           0 :   return contentBEnd;
    6386             : }
    6387           0 : 
    6388           0 : /* static */ nsIFrame*
    6389           0 : nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame)
    6390           0 : {
    6391             :   nsIFrame* layer;
    6392             :   for (layer = aFrame; layer; layer = layer->GetParent()) {
    6393             :     if (layer->IsAbsPosContainingBlock() ||
    6394             :         (layer->GetParent() && layer->GetParent()->IsScrollFrame()))
    6395           0 :       break;
    6396             :   }
    6397             :   if (layer)
    6398             :     return layer;
    6399           0 :   return aFrame->PresShell()->GetRootFrame();
    6400             : }
    6401             : 
    6402           0 : SamplingFilter
    6403           0 : nsLayoutUtils::GetSamplingFilterForFrame(nsIFrame* aForFrame)
    6404           0 : {
    6405             :   SamplingFilter defaultFilter = SamplingFilter::GOOD;
    6406             :   ComputedStyle *sc;
    6407           0 :   if (nsCSSRendering::IsCanvasFrame(aForFrame)) {
    6408             :     nsCSSRendering::FindBackground(aForFrame, &sc);
    6409           0 :   } else {
    6410             :     sc = aForFrame->Style();
    6411             :   }
    6412             : 
    6413           0 :   switch (sc->StyleVisibility()->mImageRendering) {
    6414             :   case NS_STYLE_IMAGE_RENDERING_OPTIMIZESPEED:
    6415           0 :     return SamplingFilter::POINT;
    6416             :   case NS_STYLE_IMAGE_RENDERING_OPTIMIZEQUALITY:
    6417           0 :     return SamplingFilter::LINEAR;
    6418           0 :   case NS_STYLE_IMAGE_RENDERING_CRISPEDGES:
    6419             :     return SamplingFilter::POINT;
    6420           0 :   default:
    6421             :     return defaultFilter;
    6422             :   }
    6423           0 : }
    6424             : 
    6425             : /**
    6426             :  * Given an image being drawn into an appunit coordinate system, and
    6427           0 :  * a point in that coordinate system, map the point back into image
    6428             :  * pixel space.
    6429             :  * @param aSize the size of the image, in pixels
    6430             :  * @param aDest the rectangle that the image is being mapped into
    6431           0 :  * @param aPt a point in the same coordinate system as the rectangle
    6432             :  */
    6433             : static gfxPoint
    6434             : MapToFloatImagePixels(const gfxSize& aSize,
    6435             :                       const gfxRect& aDest, const gfxPoint& aPt)
    6436             : {
    6437             :   return gfxPoint(((aPt.x - aDest.X())*aSize.width)/aDest.Width(),
    6438             :                   ((aPt.y - aDest.Y())*aSize.height)/aDest.Height());
    6439             : }
    6440             : 
    6441             : /**
    6442             :  * Given an image being drawn into an pixel-based coordinate system, and
    6443             :  * a point in image space, map the point into the pixel-based coordinate
    6444           0 :  * system.
    6445             :  * @param aSize the size of the image, in pixels
    6446             :  * @param aDest the rectangle that the image is being mapped into
    6447           0 :  * @param aPt a point in image space
    6448           0 :  */
    6449             : static gfxPoint
    6450             : MapToFloatUserPixels(const gfxSize& aSize,
    6451             :                      const gfxRect& aDest, const gfxPoint& aPt)
    6452             : {
    6453             :   return gfxPoint(aPt.x*aDest.Width()/aSize.width + aDest.X(),
    6454             :                   aPt.y*aDest.Height()/aSize.height + aDest.Y());
    6455             : }
    6456             : 
    6457             : /* static */ gfxRect
    6458             : nsLayoutUtils::RectToGfxRect(const nsRect& aRect, int32_t aAppUnitsPerDevPixel)
    6459             : {
    6460           0 :   return gfxRect(gfxFloat(aRect.x) / aAppUnitsPerDevPixel,
    6461             :                  gfxFloat(aRect.y) / aAppUnitsPerDevPixel,
    6462             :                  gfxFloat(aRect.width) / aAppUnitsPerDevPixel,
    6463           0 :                  gfxFloat(aRect.height) / aAppUnitsPerDevPixel);
    6464           0 : }
    6465             : 
    6466             : struct SnappedImageDrawingParameters {
    6467             :   // A transform from image space to device space.
    6468           0 :   gfxMatrix imageSpaceToDeviceSpace;
    6469             :   // The size at which the image should be drawn (which may not be its
    6470           0 :   // intrinsic size due to, for example, HQ scaling).
    6471           0 :   nsIntSize size;
    6472           0 :   // The region in tiled image space which will be drawn, with an associated
    6473           0 :   // region to which sampling should be restricted.
    6474             :   ImageRegion region;
    6475             :   // The default viewport size for SVG images, which we use unless a different
    6476             :   // one has been explicitly specified. This is the same as |size| except that
    6477             :   // it does not take into account any transformation on the gfxContext we're
    6478             :   // drawing to - for example, CSS transforms are not taken into account.
    6479             :   CSSIntSize svgViewportSize;
    6480             :   // Whether there's anything to draw at all.
    6481             :   bool shouldDraw;
    6482             : 
    6483             :   SnappedImageDrawingParameters()
    6484             :    : region(ImageRegion::Empty())
    6485             :    , shouldDraw(false)
    6486             :   {}
    6487             : 
    6488             :   SnappedImageDrawingParameters(const gfxMatrix&   aImageSpaceToDeviceSpace,
    6489             :                                 const nsIntSize&   aSize,
    6490             :                                 const ImageRegion& aRegion,
    6491             :                                 const CSSIntSize&  aSVGViewportSize)
    6492             :    : imageSpaceToDeviceSpace(aImageSpaceToDeviceSpace)
    6493           0 :    , size(aSize)
    6494           0 :    , region(aRegion)
    6495           0 :    , svgViewportSize(aSVGViewportSize)
    6496           0 :    , shouldDraw(true)
    6497             :   {}
    6498           0 : };
    6499             : 
    6500             : /**
    6501             :  * Given two axis-aligned rectangles, returns the transformation that maps the
    6502           0 :  * first onto the second.
    6503             :  *
    6504             :  * @param aFrom The rect to be transformed.
    6505             :  * @param aTo The rect that aFrom should be mapped onto by the transformation.
    6506           0 :  */
    6507           0 : static gfxMatrix
    6508             : TransformBetweenRects(const gfxRect& aFrom, const gfxRect& aTo)
    6509             : {
    6510             :   gfxSize scale(aTo.width / aFrom.width,
    6511             :                 aTo.height / aFrom.height);
    6512             :   gfxPoint translation(aTo.x - aFrom.x * scale.width,
    6513             :                        aTo.y - aFrom.y * scale.height);
    6514             :   return gfxMatrix(scale.width, 0, 0, scale.height,
    6515             :                    translation.x, translation.y);
    6516             : }
    6517             : 
    6518           0 : static nsRect
    6519             : TileNearRect(const nsRect& aAnyTile, const nsRect& aTargetRect)
    6520           0 : {
    6521           0 :   nsPoint distance = aTargetRect.TopLeft() - aAnyTile.TopLeft();
    6522           0 :   return aAnyTile + nsPoint(distance.x / aAnyTile.width * aAnyTile.width,
    6523           0 :                             distance.y / aAnyTile.height * aAnyTile.height);
    6524             : }
    6525           0 : 
    6526             : static gfxFloat
    6527             : StableRound(gfxFloat aValue)
    6528             : {
    6529           0 :   // Values slightly less than 0.5 should round up like 0.5 would; we're
    6530             :   // assuming they were meant to be 0.5.
    6531           0 :   return floor(aValue + 0.5001);
    6532           0 : }
    6533           0 : 
    6534             : static gfxPoint
    6535             : StableRound(const gfxPoint& aPoint)
    6536             : {
    6537           0 :   return gfxPoint(StableRound(aPoint.x), StableRound(aPoint.y));
    6538             : }
    6539             : 
    6540             : /**
    6541           0 :  * Given a set of input parameters, compute certain output parameters
    6542             :  * for drawing an image with the image snapping algorithm.
    6543             :  * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
    6544             :  *
    6545           0 :  *  @see nsLayoutUtils::DrawImage() for the descriptions of input parameters
    6546             :  */
    6547           0 : static SnappedImageDrawingParameters
    6548             : ComputeSnappedImageDrawingParameters(gfxContext*     aCtx,
    6549             :                                      int32_t         aAppUnitsPerDevPixel,
    6550             :                                      const nsRect    aDest,
    6551             :                                      const nsRect    aFill,
    6552             :                                      const nsPoint   aAnchor,
    6553             :                                      const nsRect    aDirty,
    6554             :                                      imgIContainer*  aImage,
    6555             :                                      const SamplingFilter aSamplingFilter,
    6556             :                                      uint32_t        aImageFlags,
    6557             :                                      ExtendMode      aExtendMode)
    6558           0 : {
    6559             :   if (aDest.IsEmpty() || aFill.IsEmpty())
    6560             :     return SnappedImageDrawingParameters();
    6561             : 
    6562             :   // Avoid unnecessarily large offsets.
    6563             :   bool doTile = !aDest.Contains(aFill);
    6564             :   nsRect appUnitDest = doTile ? TileNearRect(aDest, aFill.Intersect(aDirty))
    6565             :                               : aDest;
    6566             :   nsPoint anchor = aAnchor + (appUnitDest.TopLeft() - aDest.TopLeft());
    6567             : 
    6568             :   gfxRect devPixelDest =
    6569           0 :     nsLayoutUtils::RectToGfxRect(appUnitDest, aAppUnitsPerDevPixel);
    6570           0 :   gfxRect devPixelFill =
    6571             :     nsLayoutUtils::RectToGfxRect(aFill, aAppUnitsPerDevPixel);
    6572             :   gfxRect devPixelDirty =
    6573           0 :     nsLayoutUtils::RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
    6574           0 : 
    6575           0 :   gfxMatrix currentMatrix = aCtx->CurrentMatrixDouble();
    6576           0 :   gfxRect fill = devPixelFill;
    6577             :   gfxRect dest = devPixelDest;
    6578             :   bool didSnap;
    6579           0 :   // Snap even if we have a scale in the context. But don't snap if
    6580             :   // we have something that's not translation+scale, or if the scale flips in
    6581           0 :   // the X or Y direction, because snapped image drawing can't handle that yet.
    6582             :   // Any changes to this algorithm will need to be reflected in
    6583           0 :   // ComputeImageContainerDrawingParameters.
    6584             :   if (!currentMatrix.HasNonAxisAlignedTransform() &&
    6585           0 :       currentMatrix._11 > 0.0 && currentMatrix._22 > 0.0 &&
    6586           0 :       aCtx->UserToDevicePixelSnapped(fill, true) &&
    6587           0 :       aCtx->UserToDevicePixelSnapped(dest, true)) {
    6588             :     // We snapped. On this code path, |fill| and |dest| take into account
    6589             :     // currentMatrix's transform.
    6590             :     didSnap = true;
    6591             :   } else {
    6592             :     // We didn't snap. On this code path, |fill| and |dest| do not take into
    6593             :     // account currentMatrix's transform.
    6594           0 :     didSnap = false;
    6595           0 :     fill = devPixelFill;
    6596           0 :     dest = devPixelDest;
    6597           0 :   }
    6598             : 
    6599             :   // If we snapped above, |dest| already takes into account |currentMatrix|'s scale
    6600             :   // and has integer coordinates. If not, we need these properties to compute
    6601             :   // the optimal drawn image size, so compute |snappedDestSize| here.
    6602             :   gfxSize snappedDestSize = dest.Size();
    6603             :   gfxSize scaleFactors = currentMatrix.ScaleFactors(true);
    6604           0 :   if (!didSnap) {
    6605           0 :     snappedDestSize.Scale(scaleFactors.width, scaleFactors.height);
    6606           0 :     snappedDestSize.width = NS_round(snappedDestSize.width);
    6607             :     snappedDestSize.height = NS_round(snappedDestSize.height);
    6608             :   }
    6609             : 
    6610             :   // We need to be sure that this is at least one pixel in width and height,
    6611             :   // or we'll end up drawing nothing even if we have a nonempty fill.
    6612           0 :   snappedDestSize.width = std::max(snappedDestSize.width, 1.0);
    6613           0 :   snappedDestSize.height = std::max(snappedDestSize.height, 1.0);
    6614           0 : 
    6615           0 :   // Bail if we're not going to end up drawing anything.
    6616           0 :   if (fill.IsEmpty()) {
    6617           0 :     return SnappedImageDrawingParameters();
    6618             :   }
    6619             : 
    6620             :   nsIntSize intImageSize =
    6621             :     aImage->OptimalImageSizeForDest(snappedDestSize,
    6622           0 :                                     imgIContainer::FRAME_CURRENT,
    6623           0 :                                     aSamplingFilter, aImageFlags);
    6624             : 
    6625             :   nsIntSize svgViewportSize;
    6626           0 :   if (scaleFactors.width == 1.0 && scaleFactors.height == 1.0) {
    6627           0 :     // intImageSize is scaled by currentMatrix. But since there are no scale
    6628             :     // factors in currentMatrix, it is safe to assign intImageSize to
    6629             :     // svgViewportSize directly.
    6630             :     svgViewportSize = intImageSize;
    6631             :   } else {
    6632             :     // We should not take into account any transformation of currentMatrix
    6633           0 :     // when computing svg viewport size. Since currentMatrix contains scale
    6634             :     // factors, we need to recompute SVG viewport by unscaled devPixelDest.
    6635           0 :     svgViewportSize = aImage->OptimalImageSizeForDest(devPixelDest.Size(),
    6636           0 :                                                       imgIContainer::FRAME_CURRENT,
    6637             :                                                       aSamplingFilter,
    6638             :                                                       aImageFlags);
    6639             :   }
    6640           0 : 
    6641             :   gfxSize imageSize(intImageSize.width, intImageSize.height);
    6642             : 
    6643             :   // Compute the set of pixels that would be sampled by an ideal rendering
    6644             :   gfxPoint subimageTopLeft =
    6645           0 :     MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.TopLeft());
    6646             :   gfxPoint subimageBottomRight =
    6647             :     MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.BottomRight());
    6648           0 :   gfxRect subimage;
    6649             :   subimage.MoveTo(NSToIntFloor(subimageTopLeft.x),
    6650             :                   NSToIntFloor(subimageTopLeft.y));
    6651           0 :   subimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - subimage.x,
    6652             :                   NSToIntCeil(subimageBottomRight.y) - subimage.y);
    6653             : 
    6654             :   if (subimage.IsEmpty()) {
    6655           0 :     // Bail if the subimage is empty (we're not going to be drawing anything).
    6656             :     return SnappedImageDrawingParameters();
    6657           0 :   }
    6658           0 : 
    6659           0 :   gfxMatrix transform;
    6660           0 :   gfxMatrix invTransform;
    6661           0 : 
    6662           0 :   bool anchorAtUpperLeft = anchor.x == appUnitDest.x &&
    6663             :                            anchor.y == appUnitDest.y;
    6664           0 :   bool exactlyOneImageCopy = aFill.IsEqualEdges(appUnitDest);
    6665             :   if (anchorAtUpperLeft && exactlyOneImageCopy) {
    6666           0 :     // The simple case: we can ignore the anchor point and compute the
    6667             :     // transformation from the sampled region (the subimage) to the fill rect.
    6668             :     // This approach is preferable when it works since it tends to produce
    6669           0 :     // less numerical error.
    6670           0 :     transform = TransformBetweenRects(subimage, fill);
    6671             :     invTransform = TransformBetweenRects(fill, subimage);
    6672           0 :   } else {
    6673           0 :     // The more complicated case: we compute the transformation from the
    6674           0 :     // image rect positioned at the image space anchor point to the dest rect
    6675           0 :     // positioned at the device space anchor point.
    6676             : 
    6677             :     // Compute the anchor point in both device space and image space.  This
    6678             :     // code assumes that pixel-based devices have one pixel per device unit!
    6679             :     gfxPoint anchorPoint(gfxFloat(anchor.x)/aAppUnitsPerDevPixel,
    6680           0 :                          gfxFloat(anchor.y)/aAppUnitsPerDevPixel);
    6681           0 :     gfxPoint imageSpaceAnchorPoint =
    6682             :       MapToFloatImagePixels(imageSize, devPixelDest, anchorPoint);
    6683             : 
    6684             :     if (didSnap) {
    6685             :       imageSpaceAnchorPoint = StableRound(imageSpaceAnchorPoint);
    6686             :       anchorPoint = imageSpaceAnchorPoint;
    6687             :       anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
    6688             :       anchorPoint = currentMatrix.TransformPoint(anchorPoint);
    6689           0 :       anchorPoint = StableRound(anchorPoint);
    6690           0 :     }
    6691             : 
    6692           0 :     // Compute an unsnapped version of the dest rect's size. We continue to
    6693             :     // follow the pattern that we take |currentMatrix| into account only if
    6694           0 :     // |didSnap| is true.
    6695           0 :     gfxSize unsnappedDestSize
    6696           0 :       = didSnap ? devPixelDest.Size() * currentMatrix.ScaleFactors(true)
    6697           0 :                 : devPixelDest.Size();
    6698           0 : 
    6699           0 :     gfxRect anchoredDestRect(anchorPoint, unsnappedDestSize);
    6700             :     gfxRect anchoredImageRect(imageSpaceAnchorPoint, imageSize);
    6701             : 
    6702             :     // Calculate anchoredDestRect with snapped fill rect when the devPixelFill rect
    6703             :     // corresponds to just a single tile in that direction
    6704             :     if (fill.Width() != devPixelFill.Width() &&
    6705             :         devPixelDest.x == devPixelFill.x &&
    6706           0 :         devPixelDest.XMost() == devPixelFill.XMost()) {
    6707           0 :       anchoredDestRect.width = fill.width;
    6708             :     }
    6709           0 :     if (fill.Height() != devPixelFill.Height() &&
    6710           0 :         devPixelDest.y == devPixelFill.y &&
    6711             :         devPixelDest.YMost() == devPixelFill.YMost()) {
    6712             :       anchoredDestRect.height = fill.height;
    6713             :     }
    6714           0 : 
    6715           0 :     transform = TransformBetweenRects(anchoredImageRect, anchoredDestRect);
    6716           0 :     invTransform = TransformBetweenRects(anchoredDestRect, anchoredImageRect);
    6717           0 :   }
    6718             : 
    6719           0 :   // If the transform is not a straight translation by integers, then
    6720           0 :   // filtering will occur, and restricting the fill rect to the dirty rect
    6721           0 :   // would change the values computed for edge pixels, which we can't allow.
    6722           0 :   // Also, if 'didSnap' is false then rounding out 'devPixelDirty' might not
    6723             :   // produce pixel-aligned coordinates, which would also break the values
    6724             :   // computed for edge pixels.
    6725           0 :   if (didSnap && !invTransform.HasNonIntegerTranslation()) {
    6726           0 :     // This form of Transform is safe to call since non-axis-aligned
    6727             :     // transforms wouldn't be snapped.
    6728             :     devPixelDirty = currentMatrix.TransformRect(devPixelDirty);
    6729             :     devPixelDirty.RoundOut();
    6730             :     fill = fill.Intersect(devPixelDirty);
    6731             :   }
    6732             :   if (fill.IsEmpty())
    6733             :     return SnappedImageDrawingParameters();
    6734             : 
    6735           0 :   gfxRect imageSpaceFill(didSnap ? invTransform.TransformRect(fill)
    6736             :                                  : invTransform.TransformBounds(fill));
    6737             : 
    6738           0 :   // If we didn't snap, we need to post-multiply the matrix on the context to
    6739           0 :   // get the final matrix we'll draw with, because we didn't take it into
    6740           0 :   // account when computing the matrices above.
    6741             :   if (!didSnap) {
    6742           0 :     transform = transform * currentMatrix;
    6743           0 :   }
    6744             : 
    6745             :   ExtendMode extendMode = (aImageFlags & imgIContainer::FLAG_CLAMP)
    6746           0 :                           ? ExtendMode::CLAMP
    6747             :                           : aExtendMode;
    6748             :   // We were passed in the default extend mode but need to tile.
    6749             :   if (extendMode == ExtendMode::CLAMP && doTile) {
    6750             :     MOZ_ASSERT(!(aImageFlags & imgIContainer::FLAG_CLAMP));
    6751           0 :     extendMode = ExtendMode::REPEAT;
    6752           0 :   }
    6753             : 
    6754             :   ImageRegion region =
    6755           0 :     ImageRegion::CreateWithSamplingRestriction(imageSpaceFill, subimage, extendMode);
    6756           0 : 
    6757           0 :   return SnappedImageDrawingParameters(transform, intImageSize,
    6758             :                                        region,
    6759           0 :                                        CSSIntSize(svgViewportSize.width,
    6760           0 :                                                   svgViewportSize.height));
    6761             : }
    6762             : 
    6763             : static ImgDrawResult
    6764             : DrawImageInternal(gfxContext&            aContext,
    6765           0 :                   nsPresContext*         aPresContext,
    6766             :                   imgIContainer*         aImage,
    6767             :                   const SamplingFilter   aSamplingFilter,
    6768             :                   const nsRect&          aDest,
    6769           0 :                   const nsRect&          aFill,
    6770           0 :                   const nsPoint&         aAnchor,
    6771             :                   const nsRect&          aDirty,
    6772             :                   const Maybe<SVGImageContext>& aSVGContext,
    6773             :                   uint32_t               aImageFlags,
    6774           0 :                   ExtendMode             aExtendMode = ExtendMode::CLAMP,
    6775             :                   float                  aOpacity = 1.0)
    6776             : {
    6777             :   ImgDrawResult result = ImgDrawResult::SUCCESS;
    6778             : 
    6779             :   aImageFlags |= imgIContainer::FLAG_ASYNC_NOTIFY;
    6780             : 
    6781             :   if (aPresContext->Type() == nsPresContext::eContext_Print) {
    6782             :     // We want vector images to be passed on as vector commands, not a raster
    6783             :     // image.
    6784             :     aImageFlags |= imgIContainer::FLAG_BYPASS_SURFACE_CACHE;
    6785             :   }
    6786             :   if (aDest.Contains(aFill)) {
    6787           0 :     aImageFlags |= imgIContainer::FLAG_CLAMP;
    6788             :   }
    6789           0 :   int32_t appUnitsPerDevPixel =
    6790             :    aPresContext->AppUnitsPerDevPixel();
    6791           0 : 
    6792             :   SnappedImageDrawingParameters params =
    6793             :     ComputeSnappedImageDrawingParameters(&aContext, appUnitsPerDevPixel, aDest,
    6794           0 :                                          aFill, aAnchor, aDirty, aImage,
    6795             :                                          aSamplingFilter, aImageFlags, aExtendMode);
    6796           0 : 
    6797           0 :   if (!params.shouldDraw) {
    6798             :     return result;
    6799             :   }
    6800           0 : 
    6801             :   {
    6802             :     gfxContextMatrixAutoSaveRestore contextMatrixRestorer(&aContext);
    6803             : 
    6804             :     aContext.SetMatrixDouble(params.imageSpaceToDeviceSpace);
    6805           0 : 
    6806             :     Maybe<SVGImageContext> fallbackContext;
    6807           0 :     if (!aSVGContext) {
    6808             :       // Use the default viewport.
    6809             :       fallbackContext.emplace(Some(params.svgViewportSize));
    6810             :     }
    6811             : 
    6812           0 :     result = aImage->Draw(&aContext, params.size, params.region,
    6813             :                           imgIContainer::FRAME_CURRENT, aSamplingFilter,
    6814           0 :                           aSVGContext ? aSVGContext : fallbackContext,
    6815             :                           aImageFlags, aOpacity);
    6816           0 : 
    6817           0 :   }
    6818             : 
    6819           0 :   return result;
    6820             : }
    6821             : 
    6822           0 : /* static */ ImgDrawResult
    6823             : nsLayoutUtils::DrawSingleUnscaledImage(gfxContext&          aContext,
    6824           0 :                                        nsPresContext*       aPresContext,
    6825           0 :                                        imgIContainer*       aImage,
    6826             :                                        const SamplingFilter aSamplingFilter,
    6827             :                                        const nsPoint&       aDest,
    6828             :                                        const nsRect*        aDirty,
    6829           0 :                                        const Maybe<SVGImageContext>& aSVGContext,
    6830             :                                        uint32_t             aImageFlags,
    6831             :                                        const nsRect*        aSourceArea)
    6832             : {
    6833           0 :   CSSIntSize imageSize;
    6834             :   aImage->GetWidth(&imageSize.width);
    6835             :   aImage->GetHeight(&imageSize.height);
    6836             :   if (imageSize.width < 1 || imageSize.height < 1) {
    6837             :     NS_WARNING("Image width or height is non-positive");
    6838             :     return ImgDrawResult::TEMPORARY_ERROR;
    6839             :   }
    6840             : 
    6841             :   nsSize size(CSSPixel::ToAppUnits(imageSize));
    6842             :   nsRect source;
    6843           0 :   if (aSourceArea) {
    6844           0 :     source = *aSourceArea;
    6845           0 :   } else {
    6846           0 :     source.SizeTo(size);
    6847           0 :   }
    6848           0 : 
    6849             :   nsRect dest(aDest - source.TopLeft(), size);
    6850             :   nsRect fill(aDest, source.Size());
    6851           0 :   // Ensure that only a single image tile is drawn. If aSourceArea extends
    6852           0 :   // outside the image bounds, we want to honor the aSourceArea-to-aDest
    6853           0 :   // translation but we don't want to actually tile the image.
    6854           0 :   fill.IntersectRect(fill, dest);
    6855             :   return DrawImageInternal(aContext, aPresContext,
    6856             :                            aImage, aSamplingFilter,
    6857             :                            dest, fill, aDest, aDirty ? *aDirty : dest,
    6858             :                            aSVGContext, aImageFlags);
    6859           0 : }
    6860           0 : 
    6861             : /* static */ ImgDrawResult
    6862             : nsLayoutUtils::DrawSingleImage(gfxContext&            aContext,
    6863             :                                nsPresContext*         aPresContext,
    6864           0 :                                imgIContainer*         aImage,
    6865           0 :                                const SamplingFilter   aSamplingFilter,
    6866             :                                const nsRect&          aDest,
    6867             :                                const nsRect&          aDirty,
    6868           0 :                                const Maybe<SVGImageContext>& aSVGContext,
    6869             :                                uint32_t               aImageFlags,
    6870             :                                const nsPoint*         aAnchorPoint,
    6871             :                                const nsRect*          aSourceArea)
    6872           0 : {
    6873             :   nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
    6874             :   CSSIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
    6875             :   if (pixelImageSize.width < 1 || pixelImageSize.height < 1) {
    6876             :     NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0,
    6877             :                  "Image width or height is negative");
    6878             :     return ImgDrawResult::SUCCESS;  // no point in drawing a zero size image
    6879             :   }
    6880             : 
    6881             :   nsSize imageSize(CSSPixel::ToAppUnits(pixelImageSize));
    6882             :   nsRect source;
    6883           0 :   nsCOMPtr<imgIContainer> image;
    6884           0 :   if (aSourceArea) {
    6885           0 :     source = *aSourceArea;
    6886           0 :     nsIntRect subRect(source.x, source.y, source.width, source.height);
    6887             :     subRect.ScaleInverseRoundOut(appUnitsPerCSSPixel);
    6888             :     image = ImageOps::Clip(aImage, subRect);
    6889             : 
    6890             :     nsRect imageRect;
    6891           0 :     imageRect.SizeTo(imageSize);
    6892           0 :     nsRect clippedSource = imageRect.Intersect(source);
    6893           0 : 
    6894           0 :     source -= clippedSource.TopLeft();
    6895           0 :     imageSize = clippedSource.Size();
    6896           0 :   } else {
    6897           0 :     source.SizeTo(imageSize);
    6898           0 :     image = aImage;
    6899             :   }
    6900           0 : 
    6901           0 :   nsRect dest = GetWholeImageDestination(imageSize, source, aDest);
    6902           0 : 
    6903             :   // Ensure that only a single image tile is drawn. If aSourceArea extends
    6904           0 :   // outside the image bounds, we want to honor the aSourceArea-to-aDest
    6905           0 :   // transform but we don't want to actually tile the image.
    6906             :   nsRect fill;
    6907           0 :   fill.IntersectRect(aDest, dest);
    6908           0 :   return DrawImageInternal(aContext, aPresContext, image,
    6909             :                            aSamplingFilter, dest, fill,
    6910             :                            aAnchorPoint ? *aAnchorPoint : fill.TopLeft(),
    6911           0 :                            aDirty, aSVGContext, aImageFlags);
    6912             : }
    6913             : 
    6914             : /* static */ void
    6915             : nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
    6916           0 :                                      CSSIntSize&    aImageSize, /*outparam*/
    6917           0 :                                      nsSize&        aIntrinsicRatio, /*outparam*/
    6918           0 :                                      bool&          aGotWidth,  /*outparam*/
    6919             :                                      bool&          aGotHeight  /*outparam*/)
    6920           0 : {
    6921           0 :   aGotWidth  = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width));
    6922             :   aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height));
    6923             :   bool gotRatio = NS_SUCCEEDED(aImage->GetIntrinsicRatio(&aIntrinsicRatio));
    6924             : 
    6925           0 :   if (!(aGotWidth && aGotHeight) && !gotRatio) {
    6926             :     // We hit an error (say, because the image failed to load or couldn't be
    6927             :     // decoded) and should return zero size.
    6928             :     aGotWidth = aGotHeight = true;
    6929             :     aImageSize = CSSIntSize(0, 0);
    6930             :     aIntrinsicRatio = nsSize(0, 0);
    6931           0 :   }
    6932           0 : }
    6933           0 : 
    6934             : /* static */ CSSIntSize
    6935           0 : nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage,
    6936             :                                                  const nsSize&  aFallbackSize)
    6937             : {
    6938           0 :   CSSIntSize imageSize;
    6939           0 :   nsSize imageRatio;
    6940           0 :   bool gotHeight, gotWidth;
    6941             :   ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight);
    6942           0 : 
    6943             :   // If we didn't get both width and height, try to compute them using the
    6944             :   // intrinsic ratio of the image.
    6945           0 :   if (gotWidth != gotHeight) {
    6946             :     if (!gotWidth) {
    6947             :       if (imageRatio.height != 0) {
    6948           0 :         imageSize.width =
    6949           0 :           NSCoordSaturatingNonnegativeMultiply(imageSize.height,
    6950             :                                                float(imageRatio.width) /
    6951           0 :                                                float(imageRatio.height));
    6952             :         gotWidth = true;
    6953             :       }
    6954             :     } else {
    6955           0 :       if (imageRatio.width != 0) {
    6956           0 :         imageSize.height =
    6957           0 :           NSCoordSaturatingNonnegativeMultiply(imageSize.width,
    6958           0 :                                                float(imageRatio.height) /
    6959           0 :                                                float(imageRatio.width));
    6960           0 :         gotHeight = true;
    6961           0 :       }
    6962           0 :     }
    6963             :   }
    6964             : 
    6965           0 :   // If we still don't have a width or height, just use the fallback size the
    6966           0 :   // caller provided.
    6967           0 :   if (!gotWidth) {
    6968           0 :     imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aFallbackSize.width);
    6969           0 :   }
    6970           0 :   if (!gotHeight) {
    6971             :     imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aFallbackSize.height);
    6972             :   }
    6973             : 
    6974             :   return imageSize;
    6975             : }
    6976             : 
    6977           0 : /* static */ IntSize
    6978           0 : nsLayoutUtils::ComputeImageContainerDrawingParameters(imgIContainer*            aImage,
    6979             :                                                       nsIFrame*                 aForFrame,
    6980           0 :                                                       const LayoutDeviceRect&   aDestRect,
    6981           0 :                                                       const StackingContextHelper& aSc,
    6982             :                                                       uint32_t                  aFlags,
    6983             :                                                       Maybe<SVGImageContext>&   aSVGContext)
    6984           0 : {
    6985             :   MOZ_ASSERT(aImage);
    6986             :   MOZ_ASSERT(aForFrame);
    6987             : 
    6988           0 :   gfx::Size scaleFactors = aSc.GetInheritedScale();
    6989             :   SamplingFilter samplingFilter =
    6990             :     nsLayoutUtils::GetSamplingFilterForFrame(aForFrame);
    6991             : 
    6992             :   // Compute our SVG context parameters, if any. Don't replace the viewport
    6993             :   // size if it was already set, prefer what the caller gave.
    6994             :   SVGImageContext::MaybeStoreContextPaint(aSVGContext, aForFrame, aImage);
    6995           0 :   if ((scaleFactors.width != 1.0 || scaleFactors.height != 1.0) &&
    6996           0 :       aImage->GetType() == imgIContainer::TYPE_VECTOR &&
    6997             :       (!aSVGContext || !aSVGContext->GetViewportSize())) {
    6998           0 :     gfxSize gfxDestSize(aDestRect.Width(), aDestRect.Height());
    6999             :     IntSize viewportSize =
    7000           0 :       aImage->OptimalImageSizeForDest(gfxDestSize,
    7001             :                                       imgIContainer::FRAME_CURRENT,
    7002             :                                       samplingFilter, aFlags);
    7003             : 
    7004           0 :     CSSIntSize cssViewportSize(viewportSize.width, viewportSize.height);
    7005           0 :     if (!aSVGContext) {
    7006           0 :       aSVGContext.emplace(Some(cssViewportSize));
    7007           0 :     } else {
    7008           0 :       aSVGContext->SetViewportSize(Some(cssViewportSize));
    7009             :     }
    7010             :   }
    7011             : 
    7012           0 :   // Attempt to snap pixels, the same as ComputeSnappedImageDrawingParameters.
    7013             :   // Any changes to the algorithm here will need to be reflected there.
    7014           0 :   bool snapped = false;
    7015           0 :   gfxSize gfxLayerSize;
    7016           0 :   const gfx::Matrix& itm = aSc.GetInheritedTransform();
    7017             :   if (!itm.HasNonAxisAlignedTransform() &&
    7018           0 :       itm._11 > 0.0 &&
    7019             :       itm._22 > 0.0) {
    7020             :     gfxRect rect(gfxPoint(aDestRect.X(), aDestRect.Y()),
    7021             :                  gfxSize(aDestRect.Width(), aDestRect.Height()));
    7022             : 
    7023             :     gfxPoint p1 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopLeft())));
    7024           0 :     gfxPoint p2 = ThebesPoint(itm.TransformPoint(ToPoint(rect.TopRight())));
    7025           0 :     gfxPoint p3 = ThebesPoint(itm.TransformPoint(ToPoint(rect.BottomRight())));
    7026           0 : 
    7027           0 :     if (p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y)) {
    7028           0 :       p1.Round();
    7029           0 :       p3.Round();
    7030           0 : 
    7031           0 :       rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y)));
    7032             :       rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(),
    7033           0 :                           std::max(p1.y, p3.y) - rect.Y()));
    7034           0 : 
    7035           0 :       // An empty size is unacceptable so we ensure our suggested size is at
    7036             :       // least 1 pixel wide/tall.
    7037           0 :       gfxLayerSize = gfxSize(std::max(rect.Width(), 1.0),
    7038           0 :                              std::max(rect.Height(), 1.0));
    7039           0 :       snapped = true;
    7040             :     }
    7041           0 :   }
    7042           0 : 
    7043           0 :   if (!snapped) {
    7044             :     // Compute our size in layer pixels.
    7045             :     const LayerIntSize layerSize =
    7046             :       RoundedToInt(LayerSize(aDestRect.Width() * scaleFactors.width,
    7047           0 :                              aDestRect.Height() * scaleFactors.height));
    7048           0 : 
    7049           0 :     // An empty size is unacceptable so we ensure our suggested size is at least
    7050             :     // 1 pixel wide/tall.
    7051             :     gfxLayerSize = gfxSize(std::max(layerSize.width, 1),
    7052             :                            std::max(layerSize.height, 1));
    7053           0 :   }
    7054             : 
    7055             :   return aImage->OptimalImageSizeForDest(gfxLayerSize,
    7056           0 :                                          imgIContainer::FRAME_CURRENT,
    7057           0 :                                          samplingFilter, aFlags);
    7058             : }
    7059             : 
    7060             : /* static */ nsPoint
    7061           0 : nsLayoutUtils::GetBackgroundFirstTilePos(const nsPoint& aDest,
    7062           0 :                                          const nsPoint& aFill,
    7063             :                                          const nsSize& aRepeatSize)
    7064             : {
    7065             :   return nsPoint(NSToIntFloor(float(aFill.x - aDest.x) / aRepeatSize.width) * aRepeatSize.width,
    7066             :                  NSToIntFloor(float(aFill.y - aDest.y) / aRepeatSize.height) * aRepeatSize.height) +
    7067           0 :          aDest;
    7068             : }
    7069             : 
    7070             : /* static */ ImgDrawResult
    7071           0 : nsLayoutUtils::DrawBackgroundImage(gfxContext&         aContext,
    7072             :                                    nsIFrame*           aForFrame,
    7073             :                                    nsPresContext*      aPresContext,
    7074             :                                    imgIContainer*      aImage,
    7075           0 :                                    const CSSIntSize&   aImageSize,
    7076           0 :                                    SamplingFilter      aSamplingFilter,
    7077           0 :                                    const nsRect&       aDest,
    7078             :                                    const nsRect&       aFill,
    7079             :                                    const nsSize&       aRepeatSize,
    7080             :                                    const nsPoint&      aAnchor,
    7081           0 :                                    const nsRect&       aDirty,
    7082             :                                    uint32_t            aImageFlags,
    7083             :                                    ExtendMode          aExtendMode,
    7084             :                                    float               aOpacity)
    7085             : {
    7086             :   AUTO_PROFILER_LABEL("nsLayoutUtils::DrawBackgroundImage", GRAPHICS);
    7087             : 
    7088             :   Maybe<SVGImageContext> svgContext(Some(SVGImageContext(Some(aImageSize))));
    7089             :   SVGImageContext::MaybeStoreContextPaint(svgContext, aForFrame, aImage);
    7090             : 
    7091             :   /* Fast path when there is no need for image spacing */
    7092             :   if (aRepeatSize.width == aDest.width && aRepeatSize.height == aDest.height) {
    7093             :     return DrawImageInternal(aContext, aPresContext, aImage,
    7094             :                              aSamplingFilter, aDest, aFill, aAnchor,
    7095             :                              aDirty, svgContext, aImageFlags, aExtendMode,
    7096           0 :                              aOpacity);
    7097             :   }
    7098           0 : 
    7099           0 :   nsPoint firstTilePos = GetBackgroundFirstTilePos(aDest.TopLeft(), aFill.TopLeft(), aRepeatSize);
    7100             :   for (int32_t i = firstTilePos.x; i < aFill.XMost(); i += aRepeatSize.width) {
    7101             :     for (int32_t j = firstTilePos.y; j < aFill.YMost(); j += aRepeatSize.height) {
    7102           0 :       nsRect dest(i, j, aDest.width, aDest.height);
    7103             :       ImgDrawResult result = DrawImageInternal(aContext, aPresContext, aImage, aSamplingFilter,
    7104             :                                             dest, dest, aAnchor, aDirty, svgContext,
    7105             :                                             aImageFlags, ExtendMode::CLAMP,
    7106           0 :                                             aOpacity);
    7107             :       if (result != ImgDrawResult::SUCCESS) {
    7108             :         return result;
    7109           0 :       }
    7110           0 :     }
    7111           0 :   }
    7112           0 : 
    7113             :   return ImgDrawResult::SUCCESS;
    7114             : }
    7115             : 
    7116           0 : /* static */ ImgDrawResult
    7117           0 : nsLayoutUtils::DrawImage(gfxContext&         aContext,
    7118           0 :                          ComputedStyle*     aComputedStyle,
    7119             :                          nsPresContext*      aPresContext,
    7120             :                          imgIContainer*      aImage,
    7121             :                          const SamplingFilter aSamplingFilter,
    7122             :                          const nsRect&       aDest,
    7123             :                          const nsRect&       aFill,
    7124             :                          const nsPoint&      aAnchor,
    7125             :                          const nsRect&       aDirty,
    7126             :                          uint32_t            aImageFlags,
    7127           0 :                          float               aOpacity)
    7128             : {
    7129             :   Maybe<SVGImageContext> svgContext;
    7130             :   SVGImageContext::MaybeStoreContextPaint(svgContext, aComputedStyle, aImage);
    7131             : 
    7132             :   return DrawImageInternal(aContext, aPresContext, aImage,
    7133             :                            aSamplingFilter, aDest, aFill, aAnchor,
    7134             :                            aDirty,
    7135             :                            svgContext,
    7136             :                            aImageFlags, ExtendMode::CLAMP,
    7137             :                            aOpacity);
    7138             : }
    7139           0 : 
    7140           0 : /* static */ nsRect
    7141             : nsLayoutUtils::GetWholeImageDestination(const nsSize& aWholeImageSize,
    7142             :                                         const nsRect& aImageSourceArea,
    7143             :                                         const nsRect& aDestArea)
    7144             : {
    7145             :   double scaleX = double(aDestArea.width)/aImageSourceArea.width;
    7146             :   double scaleY = double(aDestArea.height)/aImageSourceArea.height;
    7147           0 :   nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
    7148             :   nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY);
    7149             :   nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*scaleX);
    7150             :   nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*scaleY);
    7151           0 :   return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY),
    7152             :                 nsSize(wholeSizeX, wholeSizeY));
    7153             : }
    7154             : 
    7155           0 : /* static */ already_AddRefed<imgIContainer>
    7156           0 : nsLayoutUtils::OrientImage(imgIContainer* aContainer,
    7157           0 :                            const nsStyleImageOrientation& aOrientation)
    7158           0 : {
    7159           0 :   MOZ_ASSERT(aContainer, "Should have an image container");
    7160           0 :   nsCOMPtr<imgIContainer> img(aContainer);
    7161           0 : 
    7162           0 :   if (aOrientation.IsFromImage()) {
    7163             :     img = ImageOps::Orient(img, img->GetOrientation());
    7164             :   } else if (!aOrientation.IsDefault()) {
    7165             :     Angle angle = aOrientation.Angle();
    7166           0 :     Flip flip  = aOrientation.IsFlipped() ? Flip::Horizontal
    7167             :                                           : Flip::Unflipped;
    7168             :     img = ImageOps::Orient(img, Orientation(angle, flip));
    7169           0 :   }
    7170           0 : 
    7171             :   return img.forget();
    7172           0 : }
    7173           0 : 
    7174           0 : static bool NonZeroStyleCoord(const nsStyleCoord& aCoord)
    7175           0 : {
    7176           0 :   if (aCoord.IsCoordPercentCalcUnit()) {
    7177           0 :     // Since negative results are clamped to 0, check > 0.
    7178           0 :     return aCoord.ComputeCoordPercentCalc(nscoord_MAX) > 0 ||
    7179             :            aCoord.ComputeCoordPercentCalc(0) > 0;
    7180             :   }
    7181           0 : 
    7182             :   return true;
    7183             : }
    7184           0 : 
    7185             : /* static */ bool
    7186           0 : nsLayoutUtils::HasNonZeroCorner(const nsStyleCorners& aCorners)
    7187             : {
    7188           0 :   NS_FOR_CSS_HALF_CORNERS(corner) {
    7189           0 :     if (NonZeroStyleCoord(aCorners.Get(corner)))
    7190             :       return true;
    7191             :   }
    7192             :   return false;
    7193             : }
    7194             : 
    7195             : // aCorner is a "full corner" value, i.e. eCornerTopLeft etc.
    7196           0 : static bool IsCornerAdjacentToSide(uint8_t aCorner, Side aSide)
    7197             : {
    7198           0 :   static_assert((int)eSideTop == eCornerTopLeft, "Check for Full Corner");
    7199           0 :   static_assert((int)eSideRight == eCornerTopRight, "Check for Full Corner");
    7200             :   static_assert((int)eSideBottom == eCornerBottomRight, "Check for Full Corner");
    7201             :   static_assert((int)eSideLeft == eCornerBottomLeft, "Check for Full Corner");
    7202             :   static_assert((int)eSideTop == ((eCornerTopRight - 1)&3), "Check for Full Corner");
    7203             :   static_assert((int)eSideRight == ((eCornerBottomRight - 1)&3), "Check for Full Corner");
    7204             :   static_assert((int)eSideBottom == ((eCornerBottomLeft - 1)&3), "Check for Full Corner");
    7205             :   static_assert((int)eSideLeft == ((eCornerTopLeft - 1)&3), "Check for Full Corner");
    7206           0 : 
    7207             :   return aSide == aCorner || aSide == ((aCorner - 1)&3);
    7208             : }
    7209             : 
    7210             : /* static */ bool
    7211             : nsLayoutUtils::HasNonZeroCornerOnSide(const nsStyleCorners& aCorners,
    7212             :                                       Side aSide)
    7213             : {
    7214             :   static_assert(eCornerTopLeftX/2 == eCornerTopLeft, "Check for Non Zero on side");
    7215             :   static_assert(eCornerTopLeftY/2 == eCornerTopLeft, "Check for Non Zero on side");
    7216             :   static_assert(eCornerTopRightX/2 == eCornerTopRight, "Check for Non Zero on side");
    7217           0 :   static_assert(eCornerTopRightY/2 == eCornerTopRight, "Check for Non Zero on side");
    7218             :   static_assert(eCornerBottomRightX/2 == eCornerBottomRight, "Check for Non Zero on side");
    7219             :   static_assert(eCornerBottomRightY/2 == eCornerBottomRight, "Check for Non Zero on side");
    7220             :   static_assert(eCornerBottomLeftX/2 == eCornerBottomLeft, "Check for Non Zero on side");
    7221           0 :   static_assert(eCornerBottomLeftY/2 == eCornerBottomLeft, "Check for Non Zero on side");
    7222             : 
    7223             :   NS_FOR_CSS_HALF_CORNERS(corner) {
    7224             :     // corner is a "half corner" value, so dividing by two gives us a
    7225             :     // "full corner" value.
    7226             :     if (NonZeroStyleCoord(aCorners.Get(corner)) &&
    7227             :         IsCornerAdjacentToSide(corner/2, aSide))
    7228             :       return true;
    7229             :   }
    7230             :   return false;
    7231             : }
    7232             : 
    7233           0 : /* static */ nsTransparencyMode
    7234             : nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame,
    7235             :                                     nsIFrame* aCSSRootFrame) {
    7236           0 :   if (aCSSRootFrame->StyleEffects()->mOpacity < 1.0f)
    7237           0 :     return eTransparencyTransparent;
    7238             : 
    7239             :   if (HasNonZeroCorner(aCSSRootFrame->StyleBorder()->mBorderRadius))
    7240             :     return eTransparencyTransparent;
    7241             : 
    7242             :   if (aCSSRootFrame->StyleDisplay()->mAppearance == NS_THEME_WIN_GLASS)
    7243             :     return eTransparencyGlass;
    7244           0 : 
    7245             :   if (aCSSRootFrame->StyleDisplay()->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS)
    7246           0 :     return eTransparencyBorderlessGlass;
    7247             : 
    7248             :   nsITheme::Transparency transparency;
    7249           0 :   if (aCSSRootFrame->IsThemed(&transparency))
    7250             :     return transparency == nsITheme::eTransparent
    7251             :          ? eTransparencyTransparent
    7252           0 :          : eTransparencyOpaque;
    7253             : 
    7254             :   // We need an uninitialized window to be treated as opaque because
    7255           0 :   // doing otherwise breaks window display effects on some platforms,
    7256             :   // specifically Vista. (bug 450322)
    7257             :   if (aBackgroundFrame->IsViewportFrame() &&
    7258             :       !aBackgroundFrame->PrincipalChildList().FirstChild()) {
    7259           0 :     return eTransparencyOpaque;
    7260           0 :   }
    7261           0 : 
    7262             :   ComputedStyle* bgSC;
    7263             :   if (!nsCSSRendering::FindBackground(aBackgroundFrame, &bgSC)) {
    7264             :     return eTransparencyTransparent;
    7265             :   }
    7266             :   const nsStyleBackground* bg = bgSC->StyleBackground();
    7267           0 :   if (NS_GET_A(bg->BackgroundColor(bgSC)) < 255 ||
    7268           0 :       // bottom layer's clip is used for the color
    7269             :       bg->BottomLayer().mClip != StyleGeometryBox::BorderBox)
    7270             :     return eTransparencyTransparent;
    7271             :   return eTransparencyOpaque;
    7272             : }
    7273           0 : 
    7274             : static bool IsPopupFrame(nsIFrame* aFrame)
    7275             : {
    7276           0 :   // aFrame is a popup it's the list control frame dropdown for a combobox.
    7277           0 :   LayoutFrameType frameType = aFrame->Type();
    7278             :   if (!nsLayoutUtils::IsContentSelectEnabled() &&
    7279           0 :       frameType == LayoutFrameType::ListControl) {
    7280             :     nsListControlFrame* lcf = static_cast<nsListControlFrame*>(aFrame);
    7281           0 :     return lcf->IsInDropDownMode();
    7282             :   }
    7283             : 
    7284           0 :   // ... or if it's a XUL menupopup frame.
    7285             :   return frameType == LayoutFrameType::MenuPopup;
    7286             : }
    7287           0 : 
    7288           0 : /* static */ bool
    7289             : nsLayoutUtils::IsPopup(nsIFrame* aFrame)
    7290           0 : {
    7291           0 :   // Optimization: the frame can't possibly be a popup if it has no view.
    7292             :   if (!aFrame->HasView()) {
    7293             :     NS_ASSERTION(!IsPopupFrame(aFrame), "popup frame must have a view");
    7294             :     return false;
    7295           0 :   }
    7296             :   return IsPopupFrame(aFrame);
    7297             : }
    7298             : 
    7299           0 : /* static */ nsIFrame*
    7300             : nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
    7301             : {
    7302           0 :   // We could use GetRootPresContext() here if the
    7303           0 :   // NS_FRAME_IN_POPUP frame bit is set.
    7304             :   nsIFrame* f = aFrame;
    7305             :   for (;;) {
    7306           0 :     if (!f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
    7307             :       f = f->PresShell()->GetRootFrame();
    7308             :       if (!f) {
    7309             :         return aFrame;
    7310           0 :       }
    7311             :     } else if (IsPopup(f)) {
    7312             :       return f;
    7313             :     }
    7314           0 :     nsIFrame* parent = GetCrossDocParentFrame(f);
    7315             :     if (!parent)
    7316           0 :       return f;
    7317           0 :     f = parent;
    7318           0 :   }
    7319             : }
    7320             : 
    7321           0 : /* static */ nsIFrame*
    7322             : nsLayoutUtils::GetReferenceFrame(nsIFrame* aFrame)
    7323             : {
    7324           0 :   nsIFrame *f = aFrame;
    7325           0 :   for (;;) {
    7326             :     const nsStyleDisplay* disp = f->StyleDisplay();
    7327             :     if (f->IsTransformed(disp) || f->IsPreserve3DLeaf(disp) || IsPopup(f)) {
    7328             :       return f;
    7329             :     }
    7330             :     nsIFrame* parent = GetCrossDocParentFrame(f);
    7331             :     if (!parent) {
    7332           0 :       return f;
    7333             :     }
    7334           0 :     f = parent;
    7335             :   }
    7336           0 : }
    7337           0 : 
    7338             : /* static */ gfx::ShapedTextFlags
    7339             : nsLayoutUtils::GetTextRunFlagsForStyle(ComputedStyle* aComputedStyle,
    7340           0 :                                        nsPresContext* aPresContext,
    7341           0 :                                        const nsStyleFont* aStyleFont,
    7342             :                                        const nsStyleText* aStyleText,
    7343             :                                        nscoord aLetterSpacing)
    7344             : {
    7345             :   gfx::ShapedTextFlags result = gfx::ShapedTextFlags();
    7346             :   if (aLetterSpacing != 0 ||
    7347             :       aStyleText->mTextJustify == StyleTextJustify::InterCharacter) {
    7348             :     result |= gfx::ShapedTextFlags::TEXT_DISABLE_OPTIONAL_LIGATURES;
    7349           0 :   }
    7350             :   if (aStyleText->mControlCharacterVisibility == NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN) {
    7351             :     result |= gfx::ShapedTextFlags::TEXT_HIDE_CONTROL_CHARACTERS;
    7352             :   }
    7353             :   switch (aComputedStyle->StyleText()->mTextRendering) {
    7354             :   case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
    7355           0 :     result |= gfx::ShapedTextFlags::TEXT_OPTIMIZE_SPEED;
    7356           0 :     break;
    7357           0 :   case NS_STYLE_TEXT_RENDERING_AUTO:
    7358             :     if (aStyleFont->mFont.size < aPresContext->GetAutoQualityMinFontSize()) {
    7359             :       result |= gfx::ShapedTextFlags::TEXT_OPTIMIZE_SPEED;
    7360           0 :     }
    7361             :     break;
    7362             :   default:
    7363           0 :     break;
    7364             :   }
    7365             :   return result | GetTextRunOrientFlagsForStyle(aComputedStyle);
    7366             : }
    7367             : 
    7368           0 : /* static */ gfx::ShapedTextFlags
    7369             : nsLayoutUtils::GetTextRunOrientFlagsForStyle(ComputedStyle* aComputedStyle)
    7370             : {
    7371             :   uint8_t writingMode = aComputedStyle->StyleVisibility()->mWritingMode;
    7372             :   switch (writingMode) {
    7373             :   case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
    7374             :     return gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL;
    7375           0 : 
    7376             :   case NS_STYLE_WRITING_MODE_VERTICAL_LR:
    7377             :   case NS_STYLE_WRITING_MODE_VERTICAL_RL:
    7378             :     switch (aComputedStyle->StyleVisibility()->mTextOrientation) {
    7379           0 :     case NS_STYLE_TEXT_ORIENTATION_MIXED:
    7380             :       return gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED;
    7381           0 :     case NS_STYLE_TEXT_ORIENTATION_UPRIGHT:
    7382           0 :       return gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
    7383             :     case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS:
    7384             :       return gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
    7385             :     default:
    7386             :       NS_NOTREACHED("unknown text-orientation");
    7387             :       return gfx::ShapedTextFlags();
    7388           0 :     }
    7389             : 
    7390             :   case NS_STYLE_WRITING_MODE_SIDEWAYS_LR:
    7391             :     return gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
    7392           0 : 
    7393             :   case NS_STYLE_WRITING_MODE_SIDEWAYS_RL:
    7394           0 :     return gfx::ShapedTextFlags::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
    7395             : 
    7396           0 :   default:
    7397           0 :     NS_NOTREACHED("unknown writing-mode");
    7398             :     return gfx::ShapedTextFlags();
    7399             :   }
    7400             : }
    7401           0 : 
    7402             : /* static */ void
    7403             : nsLayoutUtils::GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
    7404           0 :                                        nsRect* aHStrip, nsRect* aVStrip) {
    7405             :   NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(),
    7406             :                "expected rects at the same position");
    7407           0 :   nsRect unionRect(aR1.x, aR1.y, std::max(aR1.width, aR2.width),
    7408           0 :                    std::max(aR1.height, aR2.height));
    7409             :   nscoord VStripStart = std::min(aR1.width, aR2.width);
    7410             :   nscoord HStripStart = std::min(aR1.height, aR2.height);
    7411             :   *aVStrip = unionRect;
    7412             :   aVStrip->x += VStripStart;
    7413           0 :   aVStrip->width -= VStripStart;
    7414             :   *aHStrip = unionRect;
    7415           0 :   aHStrip->y += HStripStart;
    7416             :   aHStrip->height -= HStripStart;
    7417           0 : }
    7418           0 : 
    7419           0 : nsDeviceContext*
    7420           0 : nsLayoutUtils::GetDeviceContextForScreenInfo(nsPIDOMWindowOuter* aWindow)
    7421           0 : {
    7422           0 :   if (!aWindow) {
    7423           0 :     return nullptr;
    7424           0 :   }
    7425           0 : 
    7426           0 :   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
    7427           0 :   while (docShell) {
    7428             :     // Now make sure our size is up to date.  That will mean that the device
    7429             :     // context does the right thing on multi-monitor systems when we return it to
    7430           0 :     // the caller.  It will also make sure that our prescontext has been created,
    7431             :     // if we're supposed to have one.
    7432           0 :     nsCOMPtr<nsPIDOMWindowOuter> win = docShell->GetWindow();
    7433             :     if (!win) {
    7434             :       // No reason to go on
    7435             :       return nullptr;
    7436           0 :     }
    7437           0 : 
    7438             :     win->EnsureSizeAndPositionUpToDate();
    7439             : 
    7440             :     RefPtr<nsPresContext> presContext;
    7441             :     docShell->GetPresContext(getter_AddRefs(presContext));
    7442           0 :     if (presContext) {
    7443           0 :       nsDeviceContext* context = presContext->DeviceContext();
    7444             :       if (context) {
    7445           0 :         return context;
    7446             :       }
    7447             :     }
    7448           0 : 
    7449             :     nsCOMPtr<nsIDocShellTreeItem> parentItem;
    7450           0 :     docShell->GetParent(getter_AddRefs(parentItem));
    7451           0 :     docShell = do_QueryInterface(parentItem);
    7452           0 :   }
    7453           0 : 
    7454           0 :   return nullptr;
    7455           0 : }
    7456             : 
    7457             : /* static */ bool
    7458             : nsLayoutUtils::IsReallyFixedPos(const nsIFrame* aFrame)
    7459           0 : {
    7460           0 :   MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED,
    7461           0 :              "IsReallyFixedPos called on non-'position:fixed' frame");
    7462             :   return MayBeReallyFixedPos(aFrame);
    7463             : }
    7464             : 
    7465             : 
    7466             : /* static */ bool
    7467             : nsLayoutUtils::MayBeReallyFixedPos(const nsIFrame* aFrame)
    7468           0 : {
    7469             :   MOZ_ASSERT(aFrame->GetParent(),
    7470           0 :              "MayBeReallyFixedPos called on frame not in tree");
    7471             :   LayoutFrameType parentType = aFrame->GetParent()->Type();
    7472           0 :   return parentType == LayoutFrameType::Viewport ||
    7473             :          parentType == LayoutFrameType::PageContent;
    7474             : }
    7475             : 
    7476             : nsLayoutUtils::SurfaceFromElementResult
    7477           0 : nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas,
    7478             :                                           uint32_t aSurfaceFlags,
    7479           0 :                                           RefPtr<DrawTarget>& aTarget)
    7480             : {
    7481           0 :   SurfaceFromElementResult result;
    7482           0 : 
    7483           0 :   nsIntSize size = aOffscreenCanvas->GetWidthHeight();
    7484             : 
    7485             :   result.mSourceSurface = aOffscreenCanvas->GetSurfaceSnapshot(&result.mAlphaType);
    7486             :   if (!result.mSourceSurface) {
    7487           0 :     // If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
    7488             :     // draw nothing, so return an empty surface.
    7489             :     result.mAlphaType = gfxAlphaType::Opaque;
    7490             :     RefPtr<DrawTarget> ref =
    7491           0 :       aTarget ? aTarget
    7492             :               : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
    7493           0 :     RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
    7494             :                                                          SurfaceFormat::B8G8R8A8);
    7495           0 :     if (dt) {
    7496           0 :       result.mSourceSurface = dt->Snapshot();
    7497             :     }
    7498             :   } else if (aTarget) {
    7499           0 :     RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
    7500             :     if (opt) {
    7501             :       result.mSourceSurface = opt;
    7502           0 :     }
    7503           0 :   }
    7504           0 : 
    7505           0 :   result.mHasSize = true;
    7506           0 :   result.mSize = size;
    7507             :   result.mIsWriteOnly = aOffscreenCanvas->IsWriteOnly();
    7508           0 : 
    7509           0 :   return result;
    7510           0 : }
    7511           0 : 
    7512             : nsLayoutUtils::SurfaceFromElementResult
    7513             : nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement,
    7514             :                                   uint32_t aSurfaceFlags,
    7515           0 :                                   RefPtr<DrawTarget>& aTarget)
    7516           0 : {
    7517           0 :   SurfaceFromElementResult result;
    7518             :   nsresult rv;
    7519           0 : 
    7520             :   nsCOMPtr<imgIRequest> imgRequest;
    7521             :   rv = aElement->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    7522             :                             getter_AddRefs(imgRequest));
    7523           0 :   if (NS_FAILED(rv)) {
    7524             :     return result;
    7525             :   }
    7526             : 
    7527           0 :   if (!imgRequest) {
    7528             :     // There's no image request. This is either because a request for
    7529             :     // a non-empty URI failed, or the URI is the empty string.
    7530           0 :     nsCOMPtr<nsIURI> currentURI;
    7531           0 :     aElement->GetCurrentURI(getter_AddRefs(currentURI));
    7532           0 :     if (!currentURI) {
    7533           0 :       // Treat the empty URI as available instead of broken state.
    7534             :       result.mHasSize = true;
    7535             :     }
    7536             :     return result;
    7537           0 :   }
    7538             : 
    7539             :   uint32_t status;
    7540           0 :   imgRequest->GetImageStatus(&status);
    7541           0 :   result.mHasSize = status & imgIRequest::STATUS_SIZE_AVAILABLE;
    7542           0 :   if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
    7543             :     // Spec says to use GetComplete, but that only works on
    7544           0 :     // HTMLImageElement, and we support all sorts of other stuff
    7545             :     // here.  Do this for now pending spec clarification.
    7546             :     result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
    7547             :     return result;
    7548             :   }
    7549             : 
    7550           0 :   nsCOMPtr<nsIPrincipal> principal;
    7551           0 :   rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
    7552           0 :   if (NS_FAILED(rv)) {
    7553             :     return result;
    7554             :   }
    7555             : 
    7556           0 :   nsCOMPtr<imgIContainer> imgContainer;
    7557           0 :   rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
    7558             :   if (NS_FAILED(rv)) {
    7559             :     return result;
    7560           0 :   }
    7561           0 : 
    7562           0 :   uint32_t noRasterize = aSurfaceFlags & SFE_NO_RASTERIZING_VECTORS;
    7563             : 
    7564             :   uint32_t whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME_IF_IMAGE)
    7565             :                         ? (uint32_t) imgIContainer::FRAME_FIRST
    7566           0 :                         : (uint32_t) imgIContainer::FRAME_CURRENT;
    7567           0 :   uint32_t frameFlags = imgIContainer::FLAG_SYNC_DECODE
    7568           0 :                       | imgIContainer::FLAG_ASYNC_NOTIFY;
    7569             :   if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
    7570             :     frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
    7571             :   if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
    7572           0 :     frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
    7573             :   }
    7574           0 : 
    7575           0 :   int32_t imgWidth, imgHeight;
    7576           0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    7577             :   HTMLImageElement* element = HTMLImageElement::FromNodeOrNull(content);
    7578           0 :   if (aSurfaceFlags & SFE_USE_ELEMENT_SIZE_IF_VECTOR &&
    7579           0 :       element &&
    7580           0 :       imgContainer->GetType() == imgIContainer::TYPE_VECTOR) {
    7581           0 :     // We're holding a strong ref to "element" via "content".
    7582           0 :     imgWidth = MOZ_KnownLive(element)->Width();
    7583             :     imgHeight = MOZ_KnownLive(element)->Height();
    7584             :   } else {
    7585             :     rv = imgContainer->GetWidth(&imgWidth);
    7586           0 :     nsresult rv2 = imgContainer->GetHeight(&imgHeight);
    7587           0 :     if (NS_FAILED(rv) || NS_FAILED(rv2))
    7588           0 :       return result;
    7589           0 :   }
    7590           0 :   result.mSize = IntSize(imgWidth, imgHeight);
    7591             : 
    7592           0 :   if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
    7593           0 :     if (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) {
    7594             :       frameFlags |= imgIContainer::FLAG_WANT_DATA_SURFACE;
    7595           0 :     }
    7596           0 :     result.mSourceSurface = imgContainer->GetFrameAtSize(result.mSize, whichFrame, frameFlags);
    7597           0 :     if (!result.mSourceSurface) {
    7598             :       return result;
    7599             :     }
    7600           0 :     // The surface we return is likely to be cached. We don't want to have to
    7601             :     // convert to a surface that's compatible with aTarget each time it's used
    7602           0 :     // (that would result in terrible performance), so we convert once here
    7603           0 :     // upfront if aTarget is specified.
    7604           0 :     if (aTarget) {
    7605             :       RefPtr<SourceSurface> optSurface =
    7606           0 :         aTarget->OptimizeSourceSurface(result.mSourceSurface);
    7607           0 :       if (optSurface) {
    7608             :         result.mSourceSurface = optSurface;
    7609             :       }
    7610             :     }
    7611             : 
    7612             :     const auto& format = result.mSourceSurface->GetFormat();
    7613             :     if (IsOpaque(format)) {
    7614           0 :       result.mAlphaType = gfxAlphaType::Opaque;
    7615             :     } else if (frameFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA) {
    7616           0 :       result.mAlphaType = gfxAlphaType::NonPremult;
    7617           0 :     } else {
    7618           0 :       result.mAlphaType = gfxAlphaType::Premult;
    7619             :     }
    7620             :   } else {
    7621             :     result.mDrawInfo.mImgContainer = imgContainer;
    7622           0 :     result.mDrawInfo.mWhichFrame = whichFrame;
    7623           0 :     result.mDrawInfo.mDrawingFlags = frameFlags;
    7624           0 :   }
    7625           0 : 
    7626           0 :   int32_t corsmode;
    7627             :   if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
    7628           0 :     result.mCORSUsed = (corsmode != imgIRequest::CORS_NONE);
    7629             :   }
    7630             : 
    7631           0 :   result.mPrincipal = principal.forget();
    7632           0 :   // no images, including SVG images, can load content from another domain.
    7633           0 :   result.mIsWriteOnly = false;
    7634             :   result.mImageRequest = imgRequest.forget();
    7635             :   return result;
    7636             : }
    7637           0 : 
    7638           0 : nsLayoutUtils::SurfaceFromElementResult
    7639             : nsLayoutUtils::SurfaceFromElement(HTMLImageElement *aElement,
    7640             :                                   uint32_t aSurfaceFlags,
    7641           0 :                                   RefPtr<DrawTarget>& aTarget)
    7642             : {
    7643           0 :   return SurfaceFromElement(static_cast<nsIImageLoadingContent*>(aElement),
    7644           0 :                             aSurfaceFlags, aTarget);
    7645           0 : }
    7646             : 
    7647             : nsLayoutUtils::SurfaceFromElementResult
    7648             : nsLayoutUtils::SurfaceFromElement(HTMLCanvasElement* aElement,
    7649           0 :                                   uint32_t aSurfaceFlags,
    7650             :                                   RefPtr<DrawTarget>& aTarget)
    7651             : {
    7652             :   SurfaceFromElementResult result;
    7653             : 
    7654           0 :   IntSize size = aElement->GetSize();
    7655             : 
    7656             :   result.mSourceSurface = aElement->GetSurfaceSnapshot(&result.mAlphaType);
    7657             :   if (!result.mSourceSurface) {
    7658           0 :     // If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
    7659             :     // draw nothing, so return an empty surface.
    7660             :     result.mAlphaType = gfxAlphaType::Opaque;
    7661             :     RefPtr<DrawTarget> ref =
    7662           0 :       aTarget ? aTarget
    7663             :               : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
    7664           0 :     RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
    7665             :                                                         SurfaceFormat::B8G8R8A8);
    7666           0 :     if (dt) {
    7667           0 :       result.mSourceSurface = dt->Snapshot();
    7668             :     }
    7669             :   } else if (aTarget) {
    7670           0 :     RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
    7671             :     if (opt) {
    7672             :       result.mSourceSurface = opt;
    7673           0 :     }
    7674           0 :   }
    7675           0 : 
    7676           0 :   // Ensure that any future changes to the canvas trigger proper invalidation,
    7677           0 :   // in case this is being used by -moz-element()
    7678             :   aElement->MarkContextClean();
    7679           0 : 
    7680           0 :   result.mHasSize = true;
    7681           0 :   result.mSize = size;
    7682           0 :   result.mPrincipal = aElement->NodePrincipal();
    7683             :   result.mIsWriteOnly = aElement->IsWriteOnly();
    7684             : 
    7685             :   return result;
    7686             : }
    7687             : 
    7688           0 : nsLayoutUtils::SurfaceFromElementResult
    7689             : nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
    7690           0 :                                   uint32_t aSurfaceFlags,
    7691           0 :                                   RefPtr<DrawTarget>& aTarget)
    7692           0 : {
    7693           0 :   SurfaceFromElementResult result;
    7694             :   result.mAlphaType = gfxAlphaType::Opaque; // Assume opaque.
    7695           0 : 
    7696             :   if (aElement->ContainsRestrictedContent()) {
    7697             :     return result;
    7698             :   }
    7699           0 : 
    7700             :   uint16_t readyState = aElement->ReadyState();
    7701             :   if (readyState == HAVE_NOTHING ||
    7702             :       readyState == HAVE_METADATA) {
    7703           0 :     result.mIsStillLoading = true;
    7704           0 :     return result;
    7705             :   }
    7706           0 : 
    7707             :   // If it doesn't have a principal, just bail
    7708             :   nsCOMPtr<nsIPrincipal> principal = aElement->GetCurrentVideoPrincipal();
    7709             :   if (!principal)
    7710           0 :     return result;
    7711           0 : 
    7712             :   result.mLayersImage = aElement->GetCurrentImage();
    7713           0 :   if (!result.mLayersImage)
    7714           0 :     return result;
    7715             : 
    7716             :   if (aTarget) {
    7717             :     // They gave us a DrawTarget to optimize for, so even though we have a layers::Image,
    7718           0 :     // we should unconditionally grab a SourceSurface and try to optimize it.
    7719           0 :     result.mSourceSurface = result.mLayersImage->GetAsSourceSurface();
    7720             :     if (!result.mSourceSurface)
    7721             :       return result;
    7722           0 : 
    7723           0 :     RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
    7724             :     if (opt) {
    7725             :       result.mSourceSurface = opt;
    7726           0 :     }
    7727             :   }
    7728             : 
    7729           0 :   result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
    7730           0 :   result.mHasSize = true;
    7731           0 :   result.mSize = result.mLayersImage->GetSize();
    7732             :   result.mPrincipal = principal.forget();
    7733           0 :   result.mIsWriteOnly = false;
    7734           0 : 
    7735           0 :   return result;
    7736             : }
    7737             : 
    7738             : nsLayoutUtils::SurfaceFromElementResult
    7739           0 : nsLayoutUtils::SurfaceFromElement(dom::Element* aElement,
    7740           0 :                                   uint32_t aSurfaceFlags,
    7741           0 :                                   RefPtr<DrawTarget>& aTarget)
    7742           0 : {
    7743           0 :   // If it's a <canvas>, we may be able to just grab its internal surface
    7744             :   if (HTMLCanvasElement* canvas =
    7745           0 :         HTMLCanvasElement::FromNodeOrNull(aElement)) {
    7746             :     return SurfaceFromElement(canvas, aSurfaceFlags, aTarget);
    7747             :   }
    7748             : 
    7749           0 :   // Maybe it's <video>?
    7750             :   if (HTMLVideoElement* video =
    7751             :         HTMLVideoElement::FromNodeOrNull(aElement)) {
    7752             :     return SurfaceFromElement(video, aSurfaceFlags, aTarget);
    7753             :   }
    7754           0 : 
    7755           0 :   // Finally, check if it's a normal image
    7756           0 :   nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
    7757             : 
    7758             :   if (!imageLoader) {
    7759             :     return SurfaceFromElementResult();
    7760           0 :   }
    7761           0 : 
    7762           0 :   return SurfaceFromElement(imageLoader, aSurfaceFlags, aTarget);
    7763             : }
    7764             : 
    7765             : /* static */
    7766           0 : Element*
    7767             : nsLayoutUtils::GetEditableRootContentByContentEditable(nsIDocument* aDocument)
    7768           0 : {
    7769           0 :   // If the document is in designMode we should return nullptr.
    7770             :   if (!aDocument || aDocument->HasFlag(NODE_IS_EDITABLE)) {
    7771             :     return nullptr;
    7772           0 :   }
    7773             : 
    7774             :   // contenteditable only works with HTML document.
    7775             :   // XXXbz should this test IsHTMLOrXHTML(), or just IsHTML()?
    7776             :   if (!aDocument->IsHTMLOrXHTML()) {
    7777           0 :     return nullptr;
    7778             :   }
    7779             : 
    7780           0 :   Element* rootElement = aDocument->GetRootElement();
    7781             :   if (rootElement && rootElement->IsEditable()) {
    7782             :     return rootElement;
    7783             :   }
    7784             : 
    7785             :   // If there is no editable root element, check its <body> element.
    7786           0 :   // Note that the body element could be <frameset> element.
    7787             :   Element* bodyElement = aDocument->GetBody();
    7788             :   if (bodyElement && bodyElement->IsEditable()) {
    7789             :     return bodyElement;
    7790           0 :   }
    7791           0 :   return nullptr;
    7792             : }
    7793             : 
    7794             : #ifdef DEBUG
    7795             : /* static */ void
    7796             : nsLayoutUtils::AssertNoDuplicateContinuations(nsIFrame* aContainer,
    7797           0 :                                               const nsFrameList& aFrameList)
    7798           0 : {
    7799             :   for (nsIFrame* f : aFrameList) {
    7800             :     // Check only later continuations of f; we deal with checking the
    7801           0 :     // earlier continuations when we hit those earlier continuations in
    7802             :     // the frame list.
    7803             :     for (nsIFrame *c = f; (c = c->GetNextInFlow());) {
    7804             :       NS_ASSERTION(c->GetParent() != aContainer ||
    7805             :                    !aFrameList.ContainsFrame(c),
    7806           0 :                    "Two continuations of the same frame in the same "
    7807             :                    "frame list");
    7808             :     }
    7809           0 :   }
    7810             : }
    7811             : 
    7812             : // Is one of aFrame's ancestors a letter frame?
    7813           0 : static bool
    7814           0 : IsInLetterFrame(nsIFrame *aFrame)
    7815             : {
    7816             :   for (nsIFrame *f = aFrame->GetParent(); f; f = f->GetParent()) {
    7817             :     if (f->IsLetterFrame()) {
    7818             :       return true;
    7819             :     }
    7820           0 :   }
    7821             :   return false;
    7822             : }
    7823             : 
    7824           0 : /* static */ void
    7825             : nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot)
    7826           0 : {
    7827           0 :   NS_ASSERTION(aSubtreeRoot->GetPrevInFlow(),
    7828             :                "frame tree not empty, but caller reported complete status");
    7829             : 
    7830             :   // Also assert that text frames map no text.
    7831             :   int32_t start, end;
    7832             :   nsresult rv = aSubtreeRoot->GetOffsets(start, end);
    7833             :   NS_ASSERTION(NS_SUCCEEDED(rv), "GetOffsets failed");
    7834             :   // In some cases involving :first-letter, we'll partially unlink a
    7835           0 :   // continuation in the middle of a continuation chain from its
    7836             :   // previous and next continuations before destroying it, presumably so
    7837           0 :   // that we don't also destroy the later continuations.  Once we've
    7838             :   // done this, GetOffsets returns incorrect values.
    7839             :   // For examples, see list of tests in
    7840             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=619021#c29
    7841             :   NS_ASSERTION(start == end || IsInLetterFrame(aSubtreeRoot),
    7842           0 :                "frame tree not empty, but caller reported complete status");
    7843           0 : 
    7844             :   nsIFrame::ChildListIterator lists(aSubtreeRoot);
    7845             :   for (; !lists.IsDone(); lists.Next()) {
    7846             :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    7847             :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    7848             :       nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(childFrames.get());
    7849             :     }
    7850             :   }
    7851           0 : }
    7852             : #endif
    7853             : 
    7854           0 : static void
    7855           0 : GetFontFacesForFramesInner(nsIFrame* aFrame,
    7856           0 :                            nsLayoutUtils::UsedFontFaceTable& aFontFaces,
    7857           0 :                            uint32_t aMaxRanges,
    7858           0 :                            bool aSkipCollapsedWhitespace)
    7859             : {
    7860             :   MOZ_ASSERT(aFrame, "NULL frame pointer");
    7861           0 : 
    7862             :   if (aFrame->IsTextFrame()) {
    7863             :     if (!aFrame->GetPrevContinuation()) {
    7864             :       nsLayoutUtils::GetFontFacesForText(aFrame, 0, INT32_MAX, true,
    7865           0 :                                          aFontFaces, aMaxRanges,
    7866             :                                          aSkipCollapsedWhitespace);
    7867             :     }
    7868             :     return;
    7869             :   }
    7870           0 : 
    7871             :   nsIFrame::ChildListID childLists[] = { nsIFrame::kPrincipalList,
    7872           0 :                                          nsIFrame::kPopupList };
    7873           0 :   for (size_t i = 0; i < ArrayLength(childLists); ++i) {
    7874           0 :     nsFrameList children(aFrame->GetChildList(childLists[i]));
    7875             :     for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
    7876           0 :       nsIFrame* child = e.get();
    7877             :       child = nsPlaceholderFrame::GetRealFrameFor(child);
    7878           0 :       GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges,
    7879             :                                  aSkipCollapsedWhitespace);
    7880             :     }
    7881             :   }
    7882           0 : }
    7883           0 : 
    7884           0 : /* static */ nsresult
    7885           0 : nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame,
    7886           0 :                                      UsedFontFaceTable& aFontFaces,
    7887           0 :                                      uint32_t aMaxRanges,
    7888           0 :                                      bool aSkipCollapsedWhitespace)
    7889           0 : {
    7890             :   MOZ_ASSERT(aFrame, "NULL frame pointer");
    7891             : 
    7892             :   while (aFrame) {
    7893             :     GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges,
    7894             :                                aSkipCollapsedWhitespace);
    7895           0 :     aFrame = GetNextContinuationOrIBSplitSibling(aFrame);
    7896             :   }
    7897             : 
    7898             :   return NS_OK;
    7899             : }
    7900           0 : 
    7901             : static void
    7902           0 : AddFontsFromTextRun(gfxTextRun* aTextRun,
    7903           0 :                     nsTextFrame* aFrame,
    7904           0 :                     gfxSkipCharsIterator& aSkipIter,
    7905           0 :                     const gfxTextRun::Range& aRange,
    7906             :                     nsLayoutUtils::UsedFontFaceTable& aFontFaces,
    7907             :                     uint32_t aMaxRanges)
    7908           0 : {
    7909             :   gfxTextRun::GlyphRunIterator glyphRuns(aTextRun, aRange);
    7910             :   nsIContent* content = aFrame->GetContent();
    7911             :   int32_t contentLimit = aFrame->GetContentOffset() +
    7912           0 :                          aFrame->GetInFlowContentLength();
    7913             :   while (glyphRuns.NextRun()) {
    7914             :     gfxFontEntry *fe = glyphRuns.GetGlyphRun()->mFont->GetFontEntry();
    7915             :     // if we have already listed this face, just make sure the match type is
    7916             :     // recorded
    7917             :     InspectorFontFace* fontFace = aFontFaces.Get(fe);
    7918             :     if (fontFace) {
    7919           0 :       fontFace->AddMatchType(glyphRuns.GetGlyphRun()->mMatchType);
    7920           0 :     } else {
    7921           0 :       // A new font entry we haven't seen before
    7922           0 :       fontFace = new InspectorFontFace(fe, aTextRun->GetFontGroup(),
    7923           0 :                                        glyphRuns.GetGlyphRun()->mMatchType);
    7924           0 :       aFontFaces.Put(fe, fontFace);
    7925             :     }
    7926             : 
    7927           0 :     // Add this glyph run to the fontFace's list of ranges, unless we have
    7928           0 :     // already collected as many as wanted.
    7929           0 :     if (fontFace->RangeCount() < aMaxRanges) {
    7930             :       int32_t start =
    7931             :         aSkipIter.ConvertSkippedToOriginal(glyphRuns.GetStringStart());
    7932           0 :       int32_t end =
    7933           0 :         aSkipIter.ConvertSkippedToOriginal(glyphRuns.GetStringEnd());
    7934           0 : 
    7935             :       // Mapping back from textrun offsets ("skipped" offsets that reflect the
    7936             :       // text after whitespace collapsing, etc) to DOM content offsets in the
    7937             :       // original text is ambiguous, because many original characters can
    7938             :       // map to a single skipped offset. aSkipIter.ConvertSkippedToOriginal()
    7939           0 :       // will return an "original" offset that corresponds to the *end* of
    7940             :       // a collapsed run of characters in this case; but that might extend
    7941           0 :       // beyond the current content node if the textrun mapped multiple nodes.
    7942             :       // So we clamp the end offset to keep it valid for the content node
    7943           0 :       // that corresponds to the current textframe.
    7944             :       end = std::min(end, contentLimit);
    7945             : 
    7946             :       if (end > start) {
    7947             :         RefPtr<nsRange> range;
    7948             :         if (NS_FAILED(nsRange::CreateRange(content, start, content, end,
    7949             :                                            getter_AddRefs(range)))) {
    7950             :           NS_WARNING("failed to create range");
    7951             :         } else {
    7952             :           fontFace->AddRange(range);
    7953             :         }
    7954           0 :       }
    7955             :     }
    7956           0 :   }
    7957           0 : }
    7958           0 : 
    7959             : /* static */ void
    7960           0 : nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame,
    7961             :                                    int32_t aStartOffset,
    7962           0 :                                    int32_t aEndOffset,
    7963             :                                    bool aFollowContinuations,
    7964             :                                    UsedFontFaceTable& aFontFaces,
    7965             :                                    uint32_t aMaxRanges,
    7966             :                                    bool aSkipCollapsedWhitespace)
    7967           0 : {
    7968             :   MOZ_ASSERT(aFrame, "NULL frame pointer");
    7969             : 
    7970           0 :   if (!aFrame->IsTextFrame()) {
    7971             :     return;
    7972             :   }
    7973             : 
    7974             :   if (!aFrame->StyleVisibility()->IsVisible()) {
    7975             :     return;
    7976             :   }
    7977             : 
    7978           0 :   nsTextFrame* curr = static_cast<nsTextFrame*>(aFrame);
    7979             :   do {
    7980           0 :     int32_t fstart = std::max(curr->GetContentOffset(), aStartOffset);
    7981             :     int32_t fend = std::min(curr->GetContentEnd(), aEndOffset);
    7982             :     if (fstart >= fend) {
    7983             :       curr = static_cast<nsTextFrame*>(curr->GetNextContinuation());
    7984           0 :       continue;
    7985             :     }
    7986             : 
    7987             :     // curr is overlapping with the offset we want
    7988             :     gfxSkipCharsIterator iter = curr->EnsureTextRun(nsTextFrame::eInflated);
    7989             :     gfxTextRun* textRun = curr->GetTextRun(nsTextFrame::eInflated);
    7990           0 :     if (!textRun) {
    7991           0 :       NS_WARNING("failed to get textRun, low memory?");
    7992           0 :       return;
    7993           0 :     }
    7994           0 : 
    7995             :     // include continuations in the range that share the same textrun
    7996             :     nsTextFrame* next = nullptr;
    7997             :     if (aFollowContinuations && fend < aEndOffset) {
    7998           0 :       next = static_cast<nsTextFrame*>(curr->GetNextContinuation());
    7999           0 :       while (next && next->GetTextRun(nsTextFrame::eInflated) == textRun) {
    8000           0 :         fend = std::min(next->GetContentEnd(), aEndOffset);
    8001           0 :         next = fend < aEndOffset ?
    8002           0 :           static_cast<nsTextFrame*>(next->GetNextContinuation()) : nullptr;
    8003             :       }
    8004             :     }
    8005             : 
    8006           0 :     if (!aSkipCollapsedWhitespace ||
    8007           0 :         (curr->HasAnyNoncollapsedCharacters() &&
    8008           0 :          curr->HasNonSuppressedText())) {
    8009           0 :       gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart),
    8010           0 :                               iter.ConvertOriginalToSkipped(fend));
    8011           0 :       AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges);
    8012             :     }
    8013             : 
    8014             :     curr = next;
    8015             :   } while (aFollowContinuations && curr);
    8016           0 : }
    8017           0 : 
    8018           0 : /* static */
    8019             : size_t
    8020           0 : nsLayoutUtils::SizeOfTextRunsForFrames(nsIFrame* aFrame,
    8021           0 :                                        MallocSizeOf aMallocSizeOf,
    8022             :                                        bool clear)
    8023             : {
    8024           0 :   MOZ_ASSERT(aFrame, "NULL frame pointer");
    8025           0 : 
    8026             :   size_t total = 0;
    8027             : 
    8028             :   if (aFrame->IsTextFrame()) {
    8029             :     nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
    8030           0 :     for (uint32_t i = 0; i < 2; ++i) {
    8031             :       gfxTextRun *run = textFrame->GetTextRun(
    8032             :         (i != 0) ? nsTextFrame::eInflated : nsTextFrame::eNotInflated);
    8033             :       if (run) {
    8034           0 :         if (clear) {
    8035             :           run->ResetSizeOfAccountingFlags();
    8036           0 :         } else {
    8037             :           total += run->MaybeSizeOfIncludingThis(aMallocSizeOf);
    8038           0 :         }
    8039             :       }
    8040           0 :     }
    8041           0 :     return total;
    8042           0 :   }
    8043           0 : 
    8044           0 :   AutoTArray<nsIFrame::ChildList,4> childListArray;
    8045             :   aFrame->GetChildLists(&childListArray);
    8046             : 
    8047           0 :   for (nsIFrame::ChildListArrayIterator childLists(childListArray);
    8048             :        !childLists.IsDone(); childLists.Next()) {
    8049             :     for (nsFrameList::Enumerator e(childLists.CurrentList());
    8050             :          !e.AtEnd(); e.Next()) {
    8051             :       total += SizeOfTextRunsForFrames(e.get(), aMallocSizeOf, clear);
    8052             :     }
    8053             :   }
    8054           0 :   return total;
    8055           0 : }
    8056             : 
    8057           0 : /* static */
    8058           0 : void
    8059           0 : nsLayoutUtils::Initialize()
    8060           0 : {
    8061           0 :   Preferences::AddUintVarCache(&sFontSizeInflationMaxRatio,
    8062             :                                "font.size.inflation.maxRatio");
    8063             :   Preferences::AddUintVarCache(&sFontSizeInflationEmPerLine,
    8064           0 :                                "font.size.inflation.emPerLine");
    8065             :   Preferences::AddUintVarCache(&sFontSizeInflationMinTwips,
    8066             :                                "font.size.inflation.minTwips");
    8067             :   Preferences::AddUintVarCache(&sFontSizeInflationLineThreshold,
    8068             :                                "font.size.inflation.lineThreshold");
    8069           0 :   Preferences::AddIntVarCache(&sFontSizeInflationMappingIntercept,
    8070             :                               "font.size.inflation.mappingIntercept");
    8071             :   Preferences::AddBoolVarCache(&sFontSizeInflationForceEnabled,
    8072           0 :                                "font.size.inflation.forceEnabled");
    8073             :   Preferences::AddBoolVarCache(&sFontSizeInflationDisabledInMasterProcess,
    8074           0 :                                "font.size.inflation.disabledInMasterProcess");
    8075             :   Preferences::AddUintVarCache(&sSystemFontScale,
    8076           0 :                                "font.size.systemFontScale", 100);
    8077             :   Preferences::AddUintVarCache(&sZoomMaxPercent,
    8078           0 :                                "zoom.maxPercent", 300);
    8079             :   Preferences::AddUintVarCache(&sZoomMinPercent,
    8080           0 :                                "zoom.minPercent", 30);
    8081             :   Preferences::AddBoolVarCache(&sInvalidationDebuggingIsEnabled,
    8082           0 :                                "nglayout.debug.invalidation");
    8083             :   Preferences::AddBoolVarCache(&sInterruptibleReflowEnabled,
    8084           0 :                                "layout.interruptible-reflow.enabled");
    8085             :   Preferences::AddBoolVarCache(&sSVGTransformBoxEnabled,
    8086           0 :                                "svg.transform-box.enabled");
    8087             :   Preferences::AddUintVarCache(&sIdlePeriodDeadlineLimit,
    8088           0 :                                "layout.idle_period.time_limit",
    8089             :                                DEFAULT_IDLE_PERIOD_TIME_LIMIT);
    8090           0 :   Preferences::AddUintVarCache(&sQuiescentFramesBeforeIdlePeriod,
    8091             :                                "layout.idle_period.required_quiescent_frames",
    8092           0 :                                DEFAULT_QUIESCENT_FRAMES);
    8093             : 
    8094           0 :   nsComputedDOMStyle::RegisterPrefChangeCallbacks();
    8095             : }
    8096           0 : 
    8097             : /* static */
    8098             : void
    8099           0 : nsLayoutUtils::Shutdown()
    8100             : {
    8101             :   if (sContentMap) {
    8102           0 :     delete sContentMap;
    8103             :     sContentMap = nullptr;
    8104           0 :   }
    8105           0 : 
    8106             :   nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
    8107             : 
    8108             :   // so the cached initial quotes array doesn't appear to be a leak
    8109           0 :   nsStyleList::Shutdown();
    8110             : }
    8111           0 : 
    8112           0 : /* static */
    8113           0 : void
    8114             : nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
    8115             :                                     imgIRequest* aRequest,
    8116           0 :                                     bool* aRequestRegistered)
    8117             : {
    8118             :   if (!aPresContext) {
    8119           0 :     return;
    8120           0 :   }
    8121             : 
    8122             :   if (aRequestRegistered && *aRequestRegistered) {
    8123             :     // Our request is already registered with the refresh driver, so
    8124           0 :     // no need to register it again.
    8125             :     return;
    8126             :   }
    8127             : 
    8128           0 :   if (aRequest) {
    8129             :     if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
    8130             :       NS_WARNING("Unable to add image request");
    8131             :       return;
    8132           0 :     }
    8133             : 
    8134             :     if (aRequestRegistered) {
    8135             :       *aRequestRegistered = true;
    8136             :     }
    8137             :   }
    8138           0 : }
    8139           0 : 
    8140           0 : /* static */
    8141           0 : void
    8142             : nsLayoutUtils::RegisterImageRequestIfAnimated(nsPresContext* aPresContext,
    8143             :                                               imgIRequest* aRequest,
    8144           0 :                                               bool* aRequestRegistered)
    8145           0 : {
    8146             :   if (!aPresContext) {
    8147             :     return;
    8148             :   }
    8149             : 
    8150             :   if (aRequestRegistered && *aRequestRegistered) {
    8151             :     // Our request is already registered with the refresh driver, so
    8152           0 :     // no need to register it again.
    8153             :     return;
    8154             :   }
    8155             : 
    8156           0 :   if (aRequest) {
    8157             :     nsCOMPtr<imgIContainer> image;
    8158             :     if (NS_SUCCEEDED(aRequest->GetImage(getter_AddRefs(image)))) {
    8159             :       // Check to verify that the image is animated. If so, then add it to the
    8160           0 :       // list of images tracked by the refresh driver.
    8161             :       bool isAnimated = false;
    8162             :       nsresult rv = image->GetAnimated(&isAnimated);
    8163             :       if (NS_SUCCEEDED(rv) && isAnimated) {
    8164             :         if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
    8165             :           NS_WARNING("Unable to add image request");
    8166           0 :           return;
    8167           0 :         }
    8168           0 : 
    8169             :         if (aRequestRegistered) {
    8170             :           *aRequestRegistered = true;
    8171           0 :         }
    8172           0 :       }
    8173           0 :     }
    8174           0 :   }
    8175           0 : }
    8176           0 : 
    8177             : /* static */
    8178             : void
    8179           0 : nsLayoutUtils::DeregisterImageRequest(nsPresContext* aPresContext,
    8180           0 :                                       imgIRequest* aRequest,
    8181             :                                       bool* aRequestRegistered)
    8182             : {
    8183             :   if (!aPresContext) {
    8184             :     return;
    8185             :   }
    8186             : 
    8187             :   // Deregister our imgIRequest with the refresh driver to
    8188             :   // complete tear-down, but only if it has been registered
    8189           0 :   if (aRequestRegistered && !*aRequestRegistered) {
    8190             :     return;
    8191             :   }
    8192             : 
    8193           0 :   if (aRequest) {
    8194             :     nsCOMPtr<imgIContainer> image;
    8195             :     if (NS_SUCCEEDED(aRequest->GetImage(getter_AddRefs(image)))) {
    8196             :       aPresContext->RefreshDriver()->RemoveImageRequest(aRequest);
    8197             : 
    8198             :       if (aRequestRegistered) {
    8199           0 :         *aRequestRegistered = false;
    8200             :       }
    8201             :     }
    8202             :   }
    8203           0 : }
    8204           0 : 
    8205           0 : /* static */
    8206           0 : void
    8207             : nsLayoutUtils::PostRestyleEvent(Element* aElement,
    8208           0 :                                 nsRestyleHint aRestyleHint,
    8209           0 :                                 nsChangeHint aMinChangeHint)
    8210             : {
    8211             :   nsIDocument* doc = aElement->GetComposedDoc();
    8212             :   if (doc) {
    8213             :     RefPtr<nsPresContext> presContext = doc->GetPresContext();
    8214             :     if (presContext) {
    8215             :       presContext->RestyleManager()->PostRestyleEvent(
    8216             :         aElement, aRestyleHint, aMinChangeHint);
    8217           0 :     }
    8218             :   }
    8219             : }
    8220             : 
    8221           0 : nsSetAttrRunnable::nsSetAttrRunnable(Element* aElement,
    8222           0 :                                      nsAtom* aAttrName,
    8223           0 :                                      const nsAString& aValue)
    8224           0 :   : mozilla::Runnable("nsSetAttrRunnable")
    8225           0 :   , mElement(aElement)
    8226           0 :   , mAttrName(aAttrName)
    8227             :   , mValue(aValue)
    8228             : {
    8229           0 :   NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
    8230             : }
    8231           0 : 
    8232             : nsSetAttrRunnable::nsSetAttrRunnable(Element* aElement,
    8233           0 :                                      nsAtom* aAttrName,
    8234             :                                      int32_t aValue)
    8235             :   : mozilla::Runnable("nsSetAttrRunnable")
    8236             :   , mElement(aElement)
    8237           0 :   , mAttrName(aAttrName)
    8238             : {
    8239           0 :   NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
    8240           0 :   mValue.AppendInt(aValue);
    8241             : }
    8242           0 : 
    8243             : NS_IMETHODIMP
    8244           0 : nsSetAttrRunnable::Run()
    8245             : {
    8246             :   return mElement->SetAttr(kNameSpaceID_None, mAttrName, mValue, true);
    8247           0 : }
    8248             : 
    8249           0 : nsUnsetAttrRunnable::nsUnsetAttrRunnable(Element* aElement,
    8250           0 :                                          nsAtom* aAttrName)
    8251           0 :   : mozilla::Runnable("nsUnsetAttrRunnable")
    8252             :   , mElement(aElement)
    8253             :   , mAttrName(aAttrName)
    8254           0 : {
    8255             :   NS_ASSERTION(aElement && aAttrName, "Missing stuff, prepare to crash");
    8256           0 : }
    8257             : 
    8258             : NS_IMETHODIMP
    8259           0 : nsUnsetAttrRunnable::Run()
    8260           0 : {
    8261             :   return mElement->UnsetAttr(kNameSpaceID_None, mAttrName, true);
    8262             : }
    8263           0 : 
    8264             : /**
    8265           0 :  * Compute the minimum font size inside of a container with the given
    8266           0 :  * width, such that **when the user zooms the container to fill the full
    8267             :  * width of the device**, the fonts satisfy our minima.
    8268             :  */
    8269           0 : static nscoord
    8270             : MinimumFontSizeFor(nsPresContext* aPresContext, WritingMode aWritingMode,
    8271           0 :                    nscoord aContainerISize)
    8272             : {
    8273             :   nsIPresShell* presShell = aPresContext->PresShell();
    8274             : 
    8275             :   uint32_t emPerLine = presShell->FontSizeInflationEmPerLine();
    8276             :   uint32_t minTwips = presShell->FontSizeInflationMinTwips();
    8277             :   if (emPerLine == 0 && minTwips == 0) {
    8278             :     return 0;
    8279             :   }
    8280           0 : 
    8281             :   // Clamp the container width to the device dimensions
    8282             :   nscoord iFrameISize = aWritingMode.IsVertical()
    8283           0 :     ? aPresContext->GetVisibleArea().height
    8284             :     : aPresContext->GetVisibleArea().width;
    8285           0 :   nscoord effectiveContainerISize = std::min(iFrameISize, aContainerISize);
    8286           0 : 
    8287           0 :   nscoord byLine = 0, byInch = 0;
    8288             :   if (emPerLine != 0) {
    8289             :     byLine = effectiveContainerISize / emPerLine;
    8290             :   }
    8291             :   if (minTwips != 0) {
    8292           0 :     // REVIEW: Is this giving us app units and sizes *not* counting
    8293           0 :     // viewport scaling?
    8294           0 :     gfxSize screenSize = aPresContext->ScreenSizeInchesForFontInflation();
    8295           0 :     float deviceISizeInches = aWritingMode.IsVertical()
    8296             :       ? screenSize.height : screenSize.width;
    8297           0 :     byInch = NSToCoordRound(effectiveContainerISize /
    8298           0 :                             (deviceISizeInches * 1440 /
    8299           0 :                              minTwips ));
    8300             :   }
    8301           0 :   return std::max(byLine, byInch);
    8302             : }
    8303             : 
    8304           0 : /* static */ float
    8305           0 : nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame,
    8306           0 :                                       nscoord aMinFontSize)
    8307           0 : {
    8308           0 :   // Note that line heights should be inflated by the same ratio as the
    8309             :   // font size of the same text; thus we operate only on the font size
    8310             :   // even when we're scaling a line height.
    8311           0 :   nscoord styleFontSize = aFrame->StyleFont()->mFont.size;
    8312             :   if (styleFontSize <= 0) {
    8313             :     // Never scale zero font size.
    8314             :     return 1.0;
    8315           0 :   }
    8316             : 
    8317             :   if (aMinFontSize <= 0) {
    8318             :     // No need to scale.
    8319             :     return 1.0;
    8320             :   }
    8321           0 : 
    8322           0 :   // If between this current frame and its font inflation container there is a
    8323             :   // non-inline element with fixed width or height, then we should not inflate
    8324             :   // fonts for this frame.
    8325             :   for (const nsIFrame* f = aFrame;
    8326             :        f && !f->IsContainerForFontSizeInflation();
    8327           0 :        f = f->GetParent()) {
    8328             :     nsIContent* content = f->GetContent();
    8329             :     LayoutFrameType fType = f->Type();
    8330             :     nsIFrame* parent = f->GetParent();
    8331             :     // Also, if there is more than one frame corresponding to a single
    8332             :     // content node, we want the outermost one.
    8333             :     if (!(parent && parent->GetContent() == content) &&
    8334             :         // ignore width/height on inlines since they don't apply
    8335           0 :         fType != LayoutFrameType::Inline &&
    8336           0 :         // ignore width on radios and checkboxes since we enlarge them and
    8337             :         // they have width/height in ua.css
    8338           0 :         fType != LayoutFrameType::CheckboxRadio) {
    8339           0 :       // ruby annotations should have the same inflation as its
    8340           0 :       // grandparent, which is the ruby frame contains the annotation.
    8341             :       if (fType == LayoutFrameType::RubyText) {
    8342             :         MOZ_ASSERT(parent && parent->IsRubyTextContainerFrame());
    8343           0 :         nsIFrame* grandparent = parent->GetParent();
    8344             :         MOZ_ASSERT(grandparent && grandparent->IsRubyFrame());
    8345           0 :         return FontSizeInflationFor(grandparent);
    8346             :       }
    8347             :       nsStyleCoord stylePosWidth = f->StylePosition()->mWidth;
    8348           0 :       nsStyleCoord stylePosHeight = f->StylePosition()->mHeight;
    8349             :       if (stylePosWidth.GetUnit() != eStyleUnit_Auto ||
    8350             :           stylePosHeight.GetUnit() != eStyleUnit_Auto) {
    8351           0 : 
    8352           0 :         return 1.0;
    8353           0 :       }
    8354           0 :     }
    8355           0 :   }
    8356             : 
    8357           0 :   int32_t interceptParam = nsLayoutUtils::FontSizeInflationMappingIntercept();
    8358           0 :   float maxRatio = (float)nsLayoutUtils::FontSizeInflationMaxRatio() / 100.0f;
    8359           0 : 
    8360           0 :   float ratio = float(styleFontSize) / float(aMinFontSize);
    8361             :   float inflationRatio;
    8362           0 : 
    8363             :   // Given a minimum inflated font size m, a specified font size s, we want to
    8364             :   // find the inflated font size i and then return the ratio of i to s (i/s).
    8365             :   if (interceptParam >= 0) {
    8366             :     // Since the mapping intercept parameter P is greater than zero, we use it
    8367           0 :     // to determine the point where our mapping function intersects the i=s
    8368           0 :     // line. This means that we have an equation of the form:
    8369             :     //
    8370           0 :     // i = m + s·(P/2)/(1 + P/2), if s <= (1 + P/2)·m
    8371             :     // i = s, if s >= (1 + P/2)·m
    8372             : 
    8373             :     float intercept = 1 + float(interceptParam)/2.0f;
    8374             :     if (ratio >= intercept) {
    8375           0 :       // If we're already at 1+P/2 or more times the minimum, don't scale.
    8376             :       return 1.0;
    8377             :     }
    8378             : 
    8379             :     // The point (intercept, intercept) is where the part of the i vs. s graph
    8380             :     // that's not slope 1 meets the i=s line.  (This part of the
    8381             :     // graph is a line from (0, m), to that point). We calculate the
    8382             :     // intersection point to be ((1+P/2)m, (1+P/2)m), where P is the
    8383           0 :     // intercept parameter above. We then need to return i/s.
    8384           0 :     inflationRatio = (1.0f + (ratio * (intercept - 1) / intercept)) / ratio;
    8385             :   } else {
    8386             :     // This is the case where P is negative. We essentially want to implement
    8387             :     // the case for P=infinity here, so we make i = s + m, which means that
    8388             :     // i/s = s/s + m/s = 1 + 1/ratio
    8389             :     inflationRatio = 1 + 1.0f / ratio;
    8390             :   }
    8391             : 
    8392             :   if (maxRatio > 1.0 && inflationRatio > maxRatio) {
    8393             :     return maxRatio;
    8394           0 :   } else {
    8395             :     return inflationRatio;
    8396             :   }
    8397             : }
    8398             : 
    8399           0 : static bool
    8400             : ShouldInflateFontsForContainer(const nsIFrame *aFrame)
    8401             : {
    8402           0 :   // We only want to inflate fonts for text that is in a place
    8403             :   // with room to expand.  The question is what the best heuristic for
    8404             :   // that is...
    8405           0 :   // For now, we're going to use NS_FRAME_IN_CONSTRAINED_BSIZE, which
    8406             :   // indicates whether the frame is inside something with a constrained
    8407             :   // block-size (propagating down the tree), but the propagation stops when
    8408             :   // we hit overflow-y [or -x, for vertical mode]: scroll or auto.
    8409             :   const nsStyleText* styleText = aFrame->StyleText();
    8410           0 : 
    8411             :   return styleText->mTextSizeAdjust != NS_STYLE_TEXT_SIZE_ADJUST_NONE &&
    8412             :          !(aFrame->GetStateBits() & NS_FRAME_IN_CONSTRAINED_BSIZE) &&
    8413             :          // We also want to disable font inflation for containers that have
    8414             :          // preformatted text.
    8415             :          // MathML cells need special treatment. See bug 1002526 comment 56.
    8416             :          (styleText->WhiteSpaceCanWrap(aFrame) ||
    8417             :           aFrame->IsFrameOfType(nsIFrame::eMathML));
    8418             : }
    8419           0 : 
    8420             : nscoord
    8421           0 : nsLayoutUtils::InflationMinFontSizeFor(const nsIFrame *aFrame)
    8422           0 : {
    8423             :   nsPresContext *presContext = aFrame->PresContext();
    8424             :   if (!FontSizeInflationEnabled(presContext) ||
    8425             :       presContext->mInflationDisabledForShrinkWrap) {
    8426           0 :     return 0;
    8427           0 :   }
    8428             : 
    8429             :   for (const nsIFrame *f = aFrame; f; f = f->GetParent()) {
    8430             :     if (f->IsContainerForFontSizeInflation()) {
    8431           0 :       if (!ShouldInflateFontsForContainer(f)) {
    8432             :         return 0;
    8433           0 :       }
    8434           0 : 
    8435           0 :       nsFontInflationData *data =
    8436             :         nsFontInflationData::FindFontInflationDataFor(aFrame);
    8437             :       // FIXME: The need to null-check here is sort of a bug, and might
    8438             :       // lead to incorrect results.
    8439           0 :       if (!data || !data->InflationEnabled()) {
    8440           0 :         return 0;
    8441           0 :       }
    8442             : 
    8443             :       return MinimumFontSizeFor(aFrame->PresContext(),
    8444             :                                 aFrame->GetWritingMode(),
    8445             :                                 data->EffectiveISize());
    8446           0 :     }
    8447             :   }
    8448             : 
    8449           0 :   MOZ_ASSERT(false, "root should always be container");
    8450             : 
    8451             :   return 0;
    8452             : }
    8453           0 : 
    8454             : float
    8455           0 : nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame)
    8456             : {
    8457             :   if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
    8458             :     const nsIFrame* container = aFrame;
    8459           0 :     while (!container->IsSVGTextFrame()) {
    8460             :       container = container->GetParent();
    8461             :     }
    8462             :     NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
    8463             :     return
    8464             :       static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
    8465           0 :   }
    8466             : 
    8467           0 :   if (!FontSizeInflationEnabled(aFrame->PresContext())) {
    8468             :     return 1.0f;
    8469           0 :   }
    8470           0 : 
    8471             :   return FontSizeInflationInner(aFrame, InflationMinFontSizeFor(aFrame));
    8472           0 : }
    8473             : 
    8474           0 : /* static */ bool
    8475             : nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
    8476             : {
    8477           0 :   nsIPresShell* presShell = aPresContext->GetPresShell();
    8478             : 
    8479             :   if (!presShell) {
    8480             :     return false;
    8481           0 :   }
    8482             : 
    8483             :   return presShell->FontSizeInflationEnabled();
    8484             : }
    8485           0 : 
    8486             : /* static */ nsRect
    8487           0 : nsLayoutUtils::GetBoxShadowRectForFrame(nsIFrame* aFrame,
    8488             :                                         const nsSize& aFrameSize)
    8489           0 : {
    8490             :   nsCSSShadowArray* boxShadows = aFrame->StyleEffects()->mBoxShadow;
    8491             :   if (!boxShadows) {
    8492             :     return nsRect();
    8493           0 :   }
    8494             : 
    8495             :   nsRect inputRect(nsPoint(0, 0), aFrameSize);
    8496             : 
    8497           0 :   // According to the CSS spec, box-shadow should be based on the border box.
    8498             :   // However, that looks broken when the background extends outside the border
    8499             :   // box, as can be the case with native theming.  To fix that we expand the
    8500           0 :   // area that we shadow to include the bounds of any native theme drawing.
    8501           0 :   const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
    8502           0 :   nsITheme::Transparency transparency;
    8503             :   if (aFrame->IsThemed(styleDisplay, &transparency)) {
    8504             :     // For opaque (rectangular) theme widgets we can take the generic
    8505           0 :     // border-box path with border-radius disabled.
    8506             :     if (transparency != nsITheme::eOpaque) {
    8507             :       nsPresContext *presContext = aFrame->PresContext();
    8508             :       presContext->GetTheme()->
    8509             :         GetWidgetOverflow(presContext->DeviceContext(), aFrame,
    8510             :                           styleDisplay->mAppearance, &inputRect);
    8511           0 :     }
    8512             :   }
    8513           0 : 
    8514             :   nsRect shadows;
    8515             :   int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
    8516           0 :   for (uint32_t i = 0; i < boxShadows->Length(); ++i) {
    8517           0 :     nsRect tmpRect = inputRect;
    8518           0 :     nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
    8519           0 : 
    8520           0 :     // inset shadows are never painted outside the frame
    8521             :     if (shadow->mInset)
    8522             :       continue;
    8523             : 
    8524           0 :     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
    8525           0 :     tmpRect.Inflate(shadow->mSpread);
    8526           0 :     tmpRect.Inflate(
    8527           0 :       nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
    8528           0 :     shadows.UnionRect(shadows, tmpRect);
    8529             :   }
    8530             :   return shadows;
    8531           0 : }
    8532           0 : 
    8533             : /* static */ bool
    8534           0 : nsLayoutUtils::GetContentViewerSize(nsPresContext* aPresContext,
    8535           0 :                                     LayoutDeviceIntSize& aOutSize)
    8536             : {
    8537           0 :   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
    8538           0 :   if (!docShell) {
    8539             :     return false;
    8540           0 :   }
    8541             : 
    8542             :   nsCOMPtr<nsIContentViewer> cv;
    8543             :   docShell->GetContentViewer(getter_AddRefs(cv));
    8544           0 :   if (!cv) {
    8545             :     return false;
    8546             :   }
    8547           0 : 
    8548           0 :   nsIntRect bounds;
    8549             :   cv->GetBounds(bounds);
    8550             :   aOutSize = LayoutDeviceIntRect::FromUnknownRect(bounds).Size();
    8551             :   return true;
    8552           0 : }
    8553           0 : 
    8554           0 : static bool
    8555             : UpdateCompositionBoundsForRCDRSF(ParentLayerRect& aCompBounds,
    8556             :                                  nsPresContext* aPresContext,
    8557             :                                  bool aScaleContentViewerSize)
    8558           0 : {
    8559           0 :   nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
    8560           0 :   if (!rootFrame) {
    8561           0 :     return false;
    8562             :   }
    8563             : 
    8564             : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
    8565           0 :   nsIWidget* widget = rootFrame->GetNearestWidget();
    8566             : #else
    8567             :   nsView* view = rootFrame->GetView();
    8568             :   nsIWidget* widget = view ? view->GetWidget() : nullptr;
    8569           0 : #endif
    8570           0 : 
    8571             :   if (widget) {
    8572             :     LayoutDeviceIntRect widgetBounds = widget->GetBounds();
    8573             :     widgetBounds.MoveTo(0, 0);
    8574             :     aCompBounds = ParentLayerRect(
    8575             :       ViewAs<ParentLayerPixel>(
    8576             :         widgetBounds,
    8577           0 :         PixelCastJustification::LayoutDeviceIsParentLayerForRCDRSF));
    8578           0 :     return true;
    8579             :   }
    8580             : 
    8581           0 :   LayoutDeviceIntSize contentSize;
    8582           0 :   if (nsLayoutUtils::GetContentViewerSize(aPresContext, contentSize)) {
    8583           0 :     LayoutDeviceToParentLayerScale scale;
    8584           0 :     if (aScaleContentViewerSize && aPresContext->GetParentPresContext()) {
    8585           0 :       scale = LayoutDeviceToParentLayerScale(
    8586             :         aPresContext->GetParentPresContext()->PresShell()->GetCumulativeResolution());
    8587             :     }
    8588             :     aCompBounds.SizeTo(contentSize * scale);
    8589             :     return true;
    8590             :   }
    8591           0 : 
    8592           0 :   return false;
    8593           0 : }
    8594           0 : 
    8595           0 : /* static */ nsMargin
    8596           0 : nsLayoutUtils::ScrollbarAreaToExcludeFromCompositionBoundsFor(nsIFrame* aScrollFrame)
    8597             : {
    8598           0 :   if (!aScrollFrame || !aScrollFrame->GetScrollTargetFrame()) {
    8599             :     return nsMargin();
    8600             :   }
    8601             :   nsPresContext* presContext = aScrollFrame->PresContext();
    8602             :   nsIPresShell* presShell = presContext->GetPresShell();
    8603             :   if (!presShell) {
    8604             :     return nsMargin();
    8605             :   }
    8606           0 :   bool isRootScrollFrame = aScrollFrame == presShell->GetRootScrollFrame();
    8607             :   bool isRootContentDocRootScrollFrame = isRootScrollFrame
    8608           0 :                                       && presContext->IsRootContentDocument();
    8609             :   if (!isRootContentDocRootScrollFrame) {
    8610             :     return nsMargin();
    8611           0 :   }
    8612           0 :   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
    8613           0 :     return nsMargin();
    8614             :   }
    8615             :   nsIScrollableFrame* scrollableFrame = aScrollFrame->GetScrollTargetFrame();
    8616           0 :   if (!scrollableFrame) {
    8617             :     return nsMargin();
    8618           0 :   }
    8619           0 :   return scrollableFrame->GetActualScrollbarSizes();
    8620             : }
    8621             : 
    8622           0 : /* static */ nsSize
    8623             : nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame, bool aSubtractScrollbars)
    8624             : {
    8625           0 :   // If we have a scrollable frame, restrict the composition bounds to its
    8626           0 :   // scroll port. The scroll port excludes the frame borders and the scroll
    8627             :   // bars, which we don't want to be part of the composition bounds.
    8628             :   nsIScrollableFrame* scrollableFrame = aFrame->GetScrollTargetFrame();
    8629           0 :   nsRect rect = scrollableFrame ? scrollableFrame->GetScrollPortRect() : aFrame->GetRect();
    8630             :   nsSize size = rect.Size();
    8631             : 
    8632             :   nsPresContext* presContext = aFrame->PresContext();
    8633           0 :   nsIPresShell* presShell = presContext->PresShell();
    8634             : 
    8635             :   bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
    8636             :                                       && aFrame == presShell->GetRootScrollFrame();
    8637             :   if (isRootContentDocRootScrollFrame) {
    8638           0 :     ParentLayerRect compBounds;
    8639           0 :     if (UpdateCompositionBoundsForRCDRSF(compBounds, presContext, false)) {
    8640           0 :       int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
    8641             :       size = nsSize(compBounds.width * auPerDevPixel, compBounds.height * auPerDevPixel);
    8642           0 :     }
    8643           0 :   }
    8644             : 
    8645           0 :   if (aSubtractScrollbars) {
    8646           0 :     nsMargin margins = ScrollbarAreaToExcludeFromCompositionBoundsFor(aFrame);
    8647           0 :     size.width -= margins.LeftRight();
    8648           0 :     size.height -= margins.TopBottom();
    8649           0 :   }
    8650           0 : 
    8651           0 :   return size;
    8652             : }
    8653             : 
    8654             : /* static */ CSSSize
    8655           0 : nsLayoutUtils::CalculateRootCompositionSize(nsIFrame* aFrame,
    8656           0 :                                             bool aIsRootContentDocRootScrollFrame,
    8657           0 :                                             const FrameMetrics& aMetrics)
    8658           0 : {
    8659             : 
    8660             :   if (aIsRootContentDocRootScrollFrame) {
    8661           0 :     return ViewAs<LayerPixel>(aMetrics.GetCompositionBounds().Size(),
    8662             :                               PixelCastJustification::ParentLayerToLayerForRootComposition)
    8663             :            * LayerToScreenScale(1.0f)
    8664             :            / aMetrics.DisplayportPixelsPerCSSPixel();
    8665           0 :   }
    8666             :   nsPresContext* presContext = aFrame->PresContext();
    8667             :   ScreenSize rootCompositionSize;
    8668             :   nsPresContext* rootPresContext =
    8669             :     presContext->GetToplevelContentDocumentPresContext();
    8670           0 :   if (!rootPresContext) {
    8671           0 :     rootPresContext = presContext->GetRootPresContext();
    8672             :   }
    8673           0 :   nsIPresShell* rootPresShell = nullptr;
    8674           0 :   if (rootPresContext) {
    8675             :     rootPresShell = rootPresContext->PresShell();
    8676           0 :     if (nsIFrame* rootFrame = rootPresShell->GetRootFrame()) {
    8677           0 :       LayoutDeviceToLayerScale2D cumulativeResolution(
    8678             :         rootPresShell->GetCumulativeResolution()
    8679           0 :       * nsLayoutUtils::GetTransformToAncestorScale(rootFrame));
    8680           0 :       ParentLayerRect compBounds;
    8681           0 :       if (UpdateCompositionBoundsForRCDRSF(compBounds, rootPresContext, true)) {
    8682             :         rootCompositionSize = ViewAs<ScreenPixel>(compBounds.Size(),
    8683           0 :             PixelCastJustification::ScreenIsParentLayerForRoot);
    8684           0 :       } else {
    8685           0 :         int32_t rootAUPerDevPixel = rootPresContext->AppUnitsPerDevPixel();
    8686           0 :         LayerSize frameSize =
    8687             :           (LayoutDeviceRect::FromAppUnits(rootFrame->GetRect(), rootAUPerDevPixel)
    8688           0 :            * cumulativeResolution).Size();
    8689           0 :         rootCompositionSize = frameSize * LayerToScreenScale(1.0f);
    8690           0 :       }
    8691           0 :     }
    8692           0 :   } else {
    8693           0 :     nsIWidget* widget = aFrame->GetNearestWidget();
    8694             :     LayoutDeviceIntRect widgetBounds = widget->GetBounds();
    8695           0 :     rootCompositionSize = ScreenSize(
    8696             :       ViewAs<ScreenPixel>(widgetBounds.Size(),
    8697           0 :                           PixelCastJustification::LayoutDeviceIsScreenForBounds));
    8698           0 :   }
    8699           0 : 
    8700             :   // Adjust composition size for the size of scroll bars.
    8701             :   nsIFrame* rootRootScrollFrame = rootPresShell ? rootPresShell->GetRootScrollFrame() : nullptr;
    8702             :   nsMargin scrollbarMargins = ScrollbarAreaToExcludeFromCompositionBoundsFor(rootRootScrollFrame);
    8703           0 :   LayoutDeviceMargin margins = LayoutDeviceMargin::FromAppUnits(scrollbarMargins,
    8704           0 :     rootPresContext->AppUnitsPerDevPixel());
    8705           0 :   // Scrollbars are not subject to resolution scaling, so LD pixels = layer pixels for them.
    8706           0 :   rootCompositionSize.width -= margins.LeftRight();
    8707             :   rootCompositionSize.height -= margins.TopBottom();
    8708             : 
    8709             :   return rootCompositionSize / aMetrics.DisplayportPixelsPerCSSPixel();
    8710             : }
    8711           0 : 
    8712           0 : /* static */ nsRect
    8713             : nsLayoutUtils::CalculateScrollableRectForFrame(nsIScrollableFrame* aScrollableFrame, nsIFrame* aRootFrame)
    8714           0 : {
    8715             :   nsRect contentBounds;
    8716           0 :   if (aScrollableFrame) {
    8717           0 :     contentBounds = aScrollableFrame->GetScrollRange();
    8718             : 
    8719           0 :     nsPoint scrollPosition = aScrollableFrame->GetScrollPosition();
    8720             :     if (aScrollableFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
    8721             :       contentBounds.y = scrollPosition.y;
    8722             :       contentBounds.height = 0;
    8723           0 :     }
    8724             :     if (aScrollableFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
    8725           0 :       contentBounds.x = scrollPosition.x;
    8726           0 :       contentBounds.width = 0;
    8727           0 :     }
    8728             : 
    8729           0 :     contentBounds.width += aScrollableFrame->GetScrollPortRect().width;
    8730           0 :     contentBounds.height += aScrollableFrame->GetScrollPortRect().height;
    8731           0 :   } else {
    8732           0 :     contentBounds = aRootFrame->GetRect();
    8733             :   }
    8734           0 :   return contentBounds;
    8735           0 : }
    8736           0 : 
    8737             : /* static */ nsRect
    8738             : nsLayoutUtils::CalculateExpandedScrollableRect(nsIFrame* aFrame)
    8739           0 : {
    8740           0 :   nsRect scrollableRect =
    8741             :     CalculateScrollableRectForFrame(aFrame->GetScrollTargetFrame(),
    8742           0 :                                     aFrame->PresShell()->GetRootFrame());
    8743             :   nsSize compSize = CalculateCompositionSizeForFrame(aFrame);
    8744           0 : 
    8745             :   if (aFrame == aFrame->PresShell()->GetRootScrollFrame()) {
    8746             :     // the composition size for the root scroll frame does not include the
    8747             :     // local resolution, so we adjust.
    8748           0 :     float res = aFrame->PresShell()->GetResolution();
    8749             :     compSize.width = NSToCoordRound(compSize.width / res);
    8750             :     compSize.height = NSToCoordRound(compSize.height / res);
    8751           0 :   }
    8752           0 : 
    8753           0 :   if (scrollableRect.width < compSize.width) {
    8754             :     scrollableRect.x = std::max(0,
    8755           0 :                                 scrollableRect.x - (compSize.width - scrollableRect.width));
    8756             :     scrollableRect.width = compSize.width;
    8757             :   }
    8758           0 : 
    8759           0 :   if (scrollableRect.height < compSize.height) {
    8760           0 :     scrollableRect.y = std::max(0,
    8761             :                                 scrollableRect.y - (compSize.height - scrollableRect.height));
    8762             :     scrollableRect.height = compSize.height;
    8763           0 :   }
    8764           0 :   return scrollableRect;
    8765           0 : }
    8766           0 : 
    8767             : /* static */ void
    8768             : nsLayoutUtils::DoLogTestDataForPaint(LayerManager* aManager,
    8769           0 :                                      ViewID aScrollId,
    8770           0 :                                      const std::string& aKey,
    8771           0 :                                      const std::string& aValue)
    8772           0 : {
    8773             :   MOZ_ASSERT(nsLayoutUtils::IsAPZTestLoggingEnabled(), "don't call me");
    8774           0 :   if (ClientLayerManager* mgr = aManager->AsClientLayerManager()) {
    8775             :     mgr->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
    8776             :   } else if (WebRenderLayerManager* wrlm = aManager->AsWebRenderLayerManager()) {
    8777             :     wrlm->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
    8778           0 :   }
    8779             : }
    8780             : 
    8781             : /* static */ bool
    8782             : nsLayoutUtils::IsAPZTestLoggingEnabled()
    8783           0 : {
    8784           0 :   return gfxPrefs::APZTestLoggingEnabled();
    8785           0 : }
    8786           0 : 
    8787           0 : ////////////////////////////////////////
    8788             : // SurfaceFromElementResult
    8789           0 : 
    8790             : nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
    8791             :   // Use safe default values here
    8792           0 :   : mIsWriteOnly(true)
    8793             :   , mIsStillLoading(false)
    8794           0 :   , mHasSize(false)
    8795             :   , mCORSUsed(false)
    8796             :   , mAlphaType(gfxAlphaType::Opaque)
    8797             : {
    8798             : }
    8799             : 
    8800           0 : const RefPtr<mozilla::gfx::SourceSurface>&
    8801             : nsLayoutUtils::SurfaceFromElementResult::GetSourceSurface()
    8802             : {
    8803             :   if (!mSourceSurface && mLayersImage) {
    8804             :     mSourceSurface = mLayersImage->GetAsSourceSurface();
    8805             :   }
    8806           0 : 
    8807             :   return mSourceSurface;
    8808           0 : }
    8809             : 
    8810             : ////////////////////////////////////////
    8811           0 : 
    8812             : bool
    8813           0 : nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
    8814           0 : {
    8815             :   return GetAsBlock(aFrame) && !aFrame->IsBlockWrapper();
    8816             : }
    8817           0 : 
    8818             : bool
    8819             : nsLayoutUtils::NeedsPrintPreviewBackground(nsPresContext* aPresContext)
    8820             : {
    8821             :   return aPresContext->IsRootPaginatedDocument() &&
    8822             :     (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
    8823           0 :      aPresContext->Type() == nsPresContext::eContext_PageLayout);
    8824             : }
    8825           0 : 
    8826             : AutoMaybeDisableFontInflation::AutoMaybeDisableFontInflation(nsIFrame *aFrame)
    8827             : {
    8828             :   // FIXME: Now that inflation calculations are based on the flow
    8829           0 :   // root's NCA's (nearest common ancestor of its inflatable
    8830             :   // descendants) width, we could probably disable inflation in
    8831           0 :   // fewer cases than we currently do.
    8832           0 :   // MathML cells need special treatment. See bug 1002526 comment 56.
    8833           0 :   if (aFrame->IsContainerForFontSizeInflation() &&
    8834             :       !aFrame->IsFrameOfType(nsIFrame::eMathML)) {
    8835             :     mPresContext = aFrame->PresContext();
    8836           0 :     mOldValue = mPresContext->mInflationDisabledForShrinkWrap;
    8837             :     mPresContext->mInflationDisabledForShrinkWrap = true;
    8838             :   } else {
    8839             :     // indicate we have nothing to restore
    8840             :     mPresContext = nullptr;
    8841             :   }
    8842             : }
    8843           0 : 
    8844           0 : AutoMaybeDisableFontInflation::~AutoMaybeDisableFontInflation()
    8845           0 : {
    8846           0 :   if (mPresContext) {
    8847           0 :     mPresContext->mInflationDisabledForShrinkWrap = mOldValue;
    8848             :   }
    8849             : }
    8850           0 : 
    8851             : namespace mozilla {
    8852           0 : 
    8853             : Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel)
    8854           0 : {
    8855             :   // Note that by making aAppUnitsPerPixel a double we're doing floating-point
    8856           0 :   // division using a larger type and avoiding rounding error.
    8857           0 :   return Rect(Float(aRect.x / aAppUnitsPerPixel),
    8858             :               Float(aRect.y / aAppUnitsPerPixel),
    8859           0 :               Float(aRect.width / aAppUnitsPerPixel),
    8860             :               Float(aRect.height / aAppUnitsPerPixel));
    8861             : }
    8862             : 
    8863           0 : Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel,
    8864             :                          const gfx::DrawTarget& aSnapDT)
    8865             : {
    8866             :   // Note that by making aAppUnitsPerPixel a double we're doing floating-point
    8867           0 :   // division using a larger type and avoiding rounding error.
    8868           0 :   Rect rect(Float(aRect.x / aAppUnitsPerPixel),
    8869           0 :             Float(aRect.y / aAppUnitsPerPixel),
    8870           0 :             Float(aRect.width / aAppUnitsPerPixel),
    8871             :             Float(aRect.height / aAppUnitsPerPixel));
    8872             :   MaybeSnapToDevicePixels(rect, aSnapDT, true);
    8873           0 :   return rect;
    8874             : }
    8875             : // Similar to a snapped rect, except an axis is left unsnapped if the snapping
    8876             : // process results in a length of 0.
    8877             : Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel,
    8878           0 :                                  const gfx::DrawTarget& aSnapDT)
    8879           0 : {
    8880           0 :   // Note that by making aAppUnitsPerPixel a double we're doing floating-point
    8881           0 :   // division using a larger type and avoiding rounding error.
    8882           0 :   Rect rect(Float(aRect.x / aAppUnitsPerPixel),
    8883           0 :             Float(aRect.y / aAppUnitsPerPixel),
    8884             :             Float(aRect.width / aAppUnitsPerPixel),
    8885             :             Float(aRect.height / aAppUnitsPerPixel));
    8886             :   MaybeSnapToDevicePixels(rect, aSnapDT, true, false);
    8887           0 :   return rect;
    8888             : }
    8889             : 
    8890             : void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2,
    8891             :                             int32_t aAppUnitsPerDevPixel,
    8892           0 :                             DrawTarget& aDrawTarget,
    8893           0 :                             const Pattern& aPattern,
    8894           0 :                             const StrokeOptions& aStrokeOptions,
    8895           0 :                             const DrawOptions& aDrawOptions)
    8896           0 : {
    8897           0 :   Point p1 = NSPointToPoint(aP1, aAppUnitsPerDevPixel);
    8898             :   Point p2 = NSPointToPoint(aP2, aAppUnitsPerDevPixel);
    8899             :   SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget,
    8900           0 :                                     aStrokeOptions.mLineWidth);
    8901             :   aDrawTarget.StrokeLine(p1, p2, aPattern, aStrokeOptions, aDrawOptions);
    8902             : }
    8903             : 
    8904             : namespace layout {
    8905             : 
    8906             : void
    8907           0 : MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager,
    8908           0 :                                  nsPresContext* aPresContext)
    8909             : {
    8910           0 :   auto backendType = aManager->GetBackendType();
    8911           0 :   if (backendType == LayersBackend::LAYERS_CLIENT ||
    8912           0 :       backendType == LayersBackend::LAYERS_WR) {
    8913             :     aManager->SetTransactionIdAllocator(aPresContext->RefreshDriver());
    8914             :   }
    8915             : }
    8916             : 
    8917           0 : } // namespace layout
    8918             : } // namespace mozilla
    8919             : 
    8920           0 : /* static */ bool
    8921           0 : nsLayoutUtils::IsOutlineStyleAutoEnabled()
    8922             : {
    8923           0 :   static bool sOutlineStyleAutoEnabled;
    8924             :   static bool sOutlineStyleAutoPrefCached = false;
    8925           0 : 
    8926             :   if (!sOutlineStyleAutoPrefCached) {
    8927             :     sOutlineStyleAutoPrefCached = true;
    8928             :     Preferences::AddBoolVarCache(&sOutlineStyleAutoEnabled,
    8929             :                                  "layout.css.outline-style-auto.enabled",
    8930             :                                  false);
    8931           0 :   }
    8932             :   return sOutlineStyleAutoEnabled;
    8933             : }
    8934             : 
    8935             : /* static */ void
    8936           0 : nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
    8937           0 :                                        ReflowOutput& aMetrics,
    8938             :                                        const LogicalMargin& aFramePadding,
    8939             :                                        WritingMode aLineWM,
    8940           0 :                                        WritingMode aFrameWM)
    8941             : {
    8942           0 :   RefPtr<nsFontMetrics> fm =
    8943             :     nsLayoutUtils::GetInflatedFontMetricsForFrame(aFrame);
    8944             : 
    8945             :   if (fm) {
    8946           0 :     // Compute final height of the frame.
    8947             :     //
    8948             :     // Do things the standard css2 way -- though it's hard to find it
    8949             :     // in the css2 spec! It's actually found in the css1 spec section
    8950             :     // 4.4 (you will have to read between the lines to really see
    8951             :     // it).
    8952             :     //
    8953           0 :     // The height of our box is the sum of our font size plus the top
    8954             :     // and bottom border and padding. The height of children do not
    8955           0 :     // affect our height.
    8956             :     aMetrics.SetBlockStartAscent(aLineWM.IsLineInverted() ? fm->MaxDescent()
    8957             :                                                           : fm->MaxAscent());
    8958             :     aMetrics.BSize(aLineWM) = fm->MaxHeight();
    8959             :   } else {
    8960             :     NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
    8961             :     aMetrics.SetBlockStartAscent(aMetrics.BSize(aLineWM) = 0);
    8962             :   }
    8963             :   aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
    8964             :                                aFramePadding.BStart(aFrameWM));
    8965             :   aMetrics.BSize(aLineWM) += aFramePadding.BStartEnd(aFrameWM);
    8966           0 : }
    8967           0 : 
    8968           0 : /* static */ bool
    8969             : nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell)
    8970           0 : {
    8971           0 :   if (nsIDocument* doc = aShell->GetDocument()) {
    8972             :     WidgetEvent event(true, eVoidEvent);
    8973           0 :     nsTArray<EventTarget*> targets;
    8974           0 :     nsresult rv = EventDispatcher::Dispatch(doc, nullptr, &event, nullptr,
    8975           0 :         nullptr, nullptr, &targets);
    8976           0 :     NS_ENSURE_SUCCESS(rv, false);
    8977             :     for (size_t i = 0; i < targets.Length(); i++) {
    8978             :       if (targets[i]->IsApzAware()) {
    8979           0 :         return true;
    8980             :       }
    8981           0 :     }
    8982           0 :   }
    8983           0 :   return false;
    8984             : }
    8985           0 : 
    8986           0 : static void
    8987           0 : MaybeReflowForInflationScreenSizeChange(nsPresContext *aPresContext)
    8988           0 : {
    8989             :   if (aPresContext) {
    8990             :     nsIPresShell* presShell = aPresContext->GetPresShell();
    8991             :     const bool fontInflationWasEnabled = presShell->FontSizeInflationEnabled();
    8992             :     presShell->RecomputeFontSizeInflationEnabled();
    8993             :     bool changed = false;
    8994             :     if (presShell->FontSizeInflationEnabled() &&
    8995             :         presShell->FontSizeInflationMinTwips() != 0) {
    8996             :       aPresContext->ScreenSizeInchesForFontInflation(&changed);
    8997           0 :     }
    8998             : 
    8999           0 :     changed = changed ||
    9000           0 :       fontInflationWasEnabled != presShell->FontSizeInflationEnabled();
    9001           0 :     if (changed) {
    9002           0 :       nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
    9003           0 :       if (docShell) {
    9004           0 :         nsCOMPtr<nsIContentViewer> cv;
    9005             :         docShell->GetContentViewer(getter_AddRefs(cv));
    9006           0 :         if (cv) {
    9007             :           nsTArray<nsCOMPtr<nsIContentViewer> > array;
    9008             :           cv->AppendSubtree(array);
    9009           0 :           for (uint32_t i = 0, iEnd = array.Length(); i < iEnd; ++i) {
    9010             :             nsCOMPtr<nsIPresShell> shell;
    9011           0 :             nsCOMPtr<nsIContentViewer> cv = array[i];
    9012           0 :             cv->GetPresShell(getter_AddRefs(shell));
    9013           0 :             if (shell) {
    9014           0 :               nsIFrame *rootFrame = shell->GetRootFrame();
    9015           0 :               if (rootFrame) {
    9016           0 :                 shell->FrameNeedsReflow(rootFrame,
    9017           0 :                                         nsIPresShell::eStyleChange,
    9018           0 :                                         NS_FRAME_IS_DIRTY);
    9019           0 :               }
    9020           0 :             }
    9021           0 :           }
    9022           0 :         }
    9023           0 :       }
    9024           0 :     }
    9025           0 :   }
    9026           0 : }
    9027             : 
    9028           0 : /* static */ void
    9029             : nsLayoutUtils::SetScrollPositionClampingScrollPortSize(nsIPresShell* aPresShell, CSSSize aSize)
    9030             : {
    9031             :   MOZ_ASSERT(aSize.width >= 0.0 && aSize.height >= 0.0);
    9032             : 
    9033             :   aPresShell->SetScrollPositionClampingScrollPortSize(
    9034             :     nsPresContext::CSSPixelsToAppUnits(aSize.width),
    9035             :     nsPresContext::CSSPixelsToAppUnits(aSize.height));
    9036           0 : 
    9037             :   // When the "font.size.inflation.minTwips" preference is set, the
    9038             :   // layout depends on the size of the screen.  Since when the size
    9039           0 :   // of the screen changes, the scroll position clamping scroll port
    9040             :   // size also changes, we hook in the needed updates here rather
    9041           0 :   // than adding a separate notification just for this change.
    9042             :   nsPresContext* presContext = aPresShell->GetPresContext();
    9043           0 :   MaybeReflowForInflationScreenSizeChange(presContext);
    9044             : }
    9045           0 : 
    9046             : /* static */ bool
    9047             : nsLayoutUtils::CanScrollOriginClobberApz(nsAtom* aScrollOrigin)
    9048             : {
    9049             :   return aScrollOrigin != nullptr
    9050             :       && aScrollOrigin != nsGkAtoms::apz
    9051             :       && aScrollOrigin != nsGkAtoms::restore;
    9052           0 : }
    9053           0 : 
    9054           0 : /* static */ ScrollMetadata
    9055             : nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame,
    9056             :                                      nsIFrame* aScrollFrame,
    9057           0 :                                      nsIContent* aContent,
    9058             :                                      const nsIFrame* aReferenceFrame,
    9059             :                                      LayerManager* aLayerManager,
    9060           0 :                                      ViewID aScrollParentId,
    9061           0 :                                      const nsRect& aViewport,
    9062             :                                      const Maybe<nsRect>& aClipRect,
    9063             :                                      bool aIsRootContent,
    9064             :                                      const ContainerLayerParameters& aContainerParameters)
    9065           0 : {
    9066             :   nsPresContext* presContext = aForFrame->PresContext();
    9067             :   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
    9068             : 
    9069             :   nsIPresShell* presShell = presContext->GetPresShell();
    9070             :   ScrollMetadata metadata;
    9071             :   FrameMetrics& metrics = metadata.GetMetrics();
    9072             :   metrics.SetViewport(CSSRect::FromAppUnits(aViewport));
    9073             : 
    9074             :   ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
    9075             :   if (aContent) {
    9076           0 :     if (void* paintRequestTime = aContent->GetProperty(nsGkAtoms::paintRequestTime)) {
    9077           0 :       metrics.SetPaintRequestTime(*static_cast<TimeStamp*>(paintRequestTime));
    9078             :       aContent->DeleteProperty(nsGkAtoms::paintRequestTime);
    9079           0 :     }
    9080           0 :     scrollId = nsLayoutUtils::FindOrCreateIDFor(aContent);
    9081           0 :     nsRect dp;
    9082           0 :     if (nsLayoutUtils::GetDisplayPort(aContent, &dp)) {
    9083             :       metrics.SetDisplayPort(CSSRect::FromAppUnits(dp));
    9084           0 :       if (IsAPZTestLoggingEnabled()) {
    9085           0 :         LogTestDataForPaint(aLayerManager, scrollId, "displayport",
    9086           0 :                             metrics.GetDisplayPort());
    9087           0 :       }
    9088           0 :     }
    9089             :     if (nsLayoutUtils::GetCriticalDisplayPort(aContent, &dp)) {
    9090           0 :       metrics.SetCriticalDisplayPort(CSSRect::FromAppUnits(dp));
    9091           0 :       if (IsAPZTestLoggingEnabled()) {
    9092           0 :         LogTestDataForPaint(aLayerManager, scrollId, "criticalDisplayport",
    9093           0 :                             metrics.GetCriticalDisplayPort());
    9094           0 :       }
    9095           0 :     }
    9096           0 :     DisplayPortMarginsPropertyData* marginsData =
    9097             :         static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
    9098             :     if (marginsData) {
    9099           0 :       metrics.SetDisplayPortMargins(marginsData->mMargins);
    9100           0 :     }
    9101           0 :   }
    9102           0 : 
    9103           0 :   nsIScrollableFrame* scrollableFrame = nullptr;
    9104             :   if (aScrollFrame)
    9105             :     scrollableFrame = aScrollFrame->GetScrollTargetFrame();
    9106             : 
    9107           0 :   metrics.SetScrollableRect(CSSRect::FromAppUnits(
    9108           0 :     nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame, aForFrame)));
    9109           0 : 
    9110             :   if (scrollableFrame) {
    9111             :     nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
    9112             :     metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
    9113           0 : 
    9114           0 :     nsPoint smoothScrollPosition = scrollableFrame->LastScrollDestination();
    9115           0 :     metrics.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition));
    9116             : 
    9117           0 :     // If the frame was scrolled since the last layers update, and by something
    9118           0 :     // that is higher priority than APZ, we want to tell the APZ to update
    9119             :     // its scroll offset. We want to distinguish the case where the scroll offset
    9120           0 :     // was "restored" because in that case the restored scroll position should
    9121           0 :     // not overwrite a user-driven scroll.
    9122           0 :     if (scrollableFrame->LastScrollOrigin() == nsGkAtoms::restore) {
    9123             :       metrics.SetScrollOffsetRestored(scrollableFrame->CurrentScrollGeneration());
    9124           0 :     } else if (CanScrollOriginClobberApz(scrollableFrame->LastScrollOrigin())) {
    9125           0 :       metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
    9126             :     }
    9127             :     scrollableFrame->AllowScrollOriginDowngrade();
    9128             : 
    9129             :     nsAtom* lastSmoothScrollOrigin = scrollableFrame->LastSmoothScrollOrigin();
    9130             :     if (lastSmoothScrollOrigin) {
    9131             :       metrics.SetSmoothScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
    9132           0 :     }
    9133           0 : 
    9134           0 :     nsSize lineScrollAmount = scrollableFrame->GetLineScrollAmount();
    9135           0 :     LayoutDeviceIntSize lineScrollAmountInDevPixels =
    9136             :       LayoutDeviceIntSize::FromAppUnitsRounded(lineScrollAmount, presContext->AppUnitsPerDevPixel());
    9137           0 :     metadata.SetLineScrollAmount(lineScrollAmountInDevPixels);
    9138             : 
    9139           0 :     nsSize pageScrollAmount = scrollableFrame->GetPageScrollAmount();
    9140           0 :     LayoutDeviceIntSize pageScrollAmountInDevPixels =
    9141           0 :       LayoutDeviceIntSize::FromAppUnitsRounded(pageScrollAmount, presContext->AppUnitsPerDevPixel());
    9142             :     metadata.SetPageScrollAmount(pageScrollAmountInDevPixels);
    9143             : 
    9144           0 :     if (aScrollFrame->GetParent()) {
    9145             :       metadata.SetDisregardedDirection(
    9146           0 :         WheelHandlingUtils::GetDisregardedWheelScrollDirection(
    9147           0 :           aScrollFrame->GetParent()));
    9148             :     }
    9149           0 : 
    9150             :     metadata.SetUsesContainerScrolling(scrollableFrame->UsesContainerScrolling());
    9151           0 : 
    9152           0 :     metadata.SetSnapInfo(scrollableFrame->GetScrollSnapInfo());
    9153             : 
    9154           0 :     ScrollbarStyles scrollbarStyles = scrollableFrame->GetScrollbarStyles();
    9155             :     metadata.SetOverscrollBehavior(OverscrollBehaviorInfo::FromStyleConstants(
    9156           0 :         scrollbarStyles.mOverscrollBehaviorX,
    9157           0 :         scrollbarStyles.mOverscrollBehaviorY));
    9158             :   }
    9159             : 
    9160           0 :   // If we have the scrollparent being the same as the scroll id, the
    9161             :   // compositor-side code could get into an infinite loop while building the
    9162           0 :   // overscroll handoff chain.
    9163             :   MOZ_ASSERT(aScrollParentId == FrameMetrics::NULL_SCROLL_ID || scrollId != aScrollParentId);
    9164           0 :   metrics.SetScrollId(scrollId);
    9165           0 :   metrics.SetIsRootContent(aIsRootContent);
    9166             :   metadata.SetScrollParentId(aScrollParentId);
    9167           0 : 
    9168             :   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    9169             :   bool isRootScrollFrame = aScrollFrame == rootScrollFrame;
    9170             :   nsIDocument* document = presShell->GetDocument();
    9171             : 
    9172             :   if (scrollId != FrameMetrics::NULL_SCROLL_ID && !presContext->GetParentPresContext()) {
    9173           0 :     if ((aScrollFrame && isRootScrollFrame)) {
    9174           0 :       metadata.SetIsLayersIdRoot(true);
    9175           0 :     } else {
    9176           0 :       MOZ_ASSERT(document, "A non-root-scroll frame must be in a document");
    9177             :       if (aContent == document->GetDocumentElement()) {
    9178           0 :         metadata.SetIsLayersIdRoot(true);
    9179           0 :       }
    9180           0 :     }
    9181             :   }
    9182           0 : 
    9183           0 :   // Get whether the root content is RTL(E.g. it's true either if
    9184             :   // "writing-mode: vertical-rl", or if
    9185             :   // "writing-mode: horizontal-tb; direction: rtl;" in CSS).
    9186           0 :   // For the concept of this and the reason why we need to get this kind of
    9187           0 :   // information, see the definition of |mIsAutoDirRootContentRTL| in struct
    9188             :   // |ScrollMetadata|.
    9189             :   Element* bodyElement = document ? document->GetBodyElement() : nullptr;
    9190             :   nsIFrame* primaryFrame = bodyElement ? bodyElement->GetPrimaryFrame() :
    9191             :                                            rootScrollFrame;
    9192             :   if (!primaryFrame) {
    9193             :     primaryFrame = rootScrollFrame;
    9194             :   }
    9195             :   if (primaryFrame) {
    9196             :     WritingMode writingModeOfRootScrollFrame =
    9197             :                   primaryFrame->GetWritingMode();
    9198             :     WritingMode::BlockDir blockDirOfRootScrollFrame =
    9199           0 :                             writingModeOfRootScrollFrame.GetBlockDir();
    9200           0 :     WritingMode::InlineDir inlineDirOfRootScrollFrame =
    9201           0 :                              writingModeOfRootScrollFrame.GetInlineDir();
    9202           0 :     if (blockDirOfRootScrollFrame == WritingMode::BlockDir::eBlockRL ||
    9203           0 :         (blockDirOfRootScrollFrame == WritingMode::BlockDir::eBlockTB &&
    9204             :           inlineDirOfRootScrollFrame == WritingMode::InlineDir::eInlineRTL)) {
    9205           0 :       metadata.SetIsAutoDirRootContentRTL(true);
    9206             :     }
    9207           0 :   }
    9208             : 
    9209           0 :   // Only the root scrollable frame for a given presShell should pick up
    9210             :   // the presShell's resolution. All the other frames are 1.0.
    9211           0 :   if (isRootScrollFrame) {
    9212           0 :     metrics.SetPresShellResolution(presShell->GetResolution());
    9213           0 :   } else {
    9214           0 :     metrics.SetPresShellResolution(1.0f);
    9215             :   }
    9216             :   // The cumulative resolution is the resolution at which the scroll frame's
    9217             :   // content is actually rendered. It includes the pres shell resolutions of
    9218             :   // all the pres shells from here up to the root, as well as any css-driven
    9219             :   // resolution. We don't need to compute it as it's already stored in the
    9220             :   // container parameters.
    9221           0 :   metrics.SetCumulativeResolution(aContainerParameters.Scale());
    9222           0 : 
    9223             :   LayoutDeviceToScreenScale2D resolutionToScreen(
    9224           0 :       presShell->GetCumulativeResolution()
    9225             :     * nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame ? aScrollFrame : aForFrame));
    9226             :   metrics.SetExtraResolution(metrics.GetCumulativeResolution() / resolutionToScreen);
    9227             : 
    9228             :   metrics.SetDevPixelsPerCSSPixel(presContext->CSSToDevPixelScale());
    9229             : 
    9230             :   // Initially, AsyncPanZoomController should render the content to the screen
    9231           0 :   // at the painted resolution.
    9232             :   const LayerToParentLayerScale layerToParentLayerScale(1.0f);
    9233             :   metrics.SetZoom(metrics.GetCumulativeResolution() * metrics.GetDevPixelsPerCSSPixel()
    9234           0 :                   * layerToParentLayerScale);
    9235           0 : 
    9236           0 :   // Calculate the composition bounds as the size of the scroll frame and
    9237             :   // its origin relative to the reference frame.
    9238           0 :   // If aScrollFrame is null, we are in a document without a root scroll frame,
    9239             :   // so it's a xul document. In this case, use the size of the viewport frame.
    9240             :   nsIFrame* frameForCompositionBoundsCalculation = aScrollFrame ? aScrollFrame : aForFrame;
    9241             :   nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame),
    9242           0 :                            frameForCompositionBoundsCalculation->GetSize());
    9243           0 :   if (scrollableFrame) {
    9244           0 :     // If we have a scrollable frame, restrict the composition bounds to its
    9245             :     // scroll port. The scroll port excludes the frame borders and the scroll
    9246             :     // bars, which we don't want to be part of the composition bounds.
    9247             :     nsRect scrollPort = scrollableFrame->GetScrollPortRect();
    9248             :     compositionBounds = nsRect(compositionBounds.TopLeft() + scrollPort.TopLeft(),
    9249             :                                scrollPort.Size());
    9250           0 :   }
    9251           0 :   ParentLayerRect frameBounds = LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
    9252           0 :                               * metrics.GetCumulativeResolution()
    9253           0 :                               * layerToParentLayerScale;
    9254             : 
    9255             :   if (aClipRect) {
    9256             :     ParentLayerRect rect = LayoutDeviceRect::FromAppUnits(*aClipRect, auPerDevPixel)
    9257           0 :                          * metrics.GetCumulativeResolution()
    9258           0 :                          * layerToParentLayerScale;
    9259           0 :     metadata.SetScrollClip(Some(LayerClip(RoundedToInt(rect))));
    9260             :   }
    9261           0 : 
    9262           0 :   // For the root scroll frame of the root content document (RCD-RSF), the above calculation
    9263           0 :   // will yield the size of the viewport frame as the composition bounds, which
    9264             :   // doesn't actually correspond to what is visible when
    9265           0 :   // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
    9266           0 :   // the prescontext that the viewport frame is reflowed into. In that case if our
    9267           0 :   // document has a widget then the widget's bounds will correspond to what is
    9268           0 :   // visible. If we don't have a widget the root view's bounds correspond to what
    9269           0 :   // would be visible because they don't get modified by setCSSViewport.
    9270             :   bool isRootContentDocRootScrollFrame = isRootScrollFrame
    9271             :                                       && presContext->IsRootContentDocument();
    9272             :   if (isRootContentDocRootScrollFrame) {
    9273             :     UpdateCompositionBoundsForRCDRSF(frameBounds, presContext, true);
    9274             :   }
    9275             : 
    9276             :   nsMargin sizes = ScrollbarAreaToExcludeFromCompositionBoundsFor(aScrollFrame);
    9277             :   // Scrollbars are not subject to resolution scaling, so LD pixels = layer pixels for them.
    9278             :   ParentLayerMargin boundMargins = LayoutDeviceMargin::FromAppUnits(sizes, auPerDevPixel)
    9279             :     * LayoutDeviceToParentLayerScale(1.0f);
    9280             :   frameBounds.Deflate(boundMargins);
    9281           0 : 
    9282           0 :   metrics.SetCompositionBounds(frameBounds);
    9283           0 : 
    9284             :   metrics.SetRootCompositionSize(
    9285             :     nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame ? aScrollFrame : aForFrame,
    9286           0 :                                                 isRootContentDocRootScrollFrame, metrics));
    9287             : 
    9288           0 :   if (gfxPrefs::APZPrintTree() || gfxPrefs::APZTestLoggingEnabled()) {
    9289           0 :     if (nsIContent* content = frameForCompositionBoundsCalculation->GetContent()) {
    9290           0 :       nsAutoString contentDescription;
    9291             :       if (content->IsElement()) {
    9292           0 :         content->AsElement()->Describe(contentDescription);
    9293             :       } else {
    9294             :         contentDescription.AssignLiteral("(not an element)");
    9295           0 :       }
    9296           0 :       metadata.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription));
    9297             :       if (IsAPZTestLoggingEnabled()) {
    9298           0 :         LogTestDataForPaint(aLayerManager, scrollId, "contentDescription",
    9299           0 :                             metadata.GetContentDescription().get());
    9300           0 :       }
    9301           0 :     }
    9302           0 :   }
    9303             : 
    9304           0 :   metrics.SetPresShellId(presShell->GetPresShellId());
    9305             : 
    9306           0 :   // If the scroll frame's content is marked 'scrollgrab', record this
    9307           0 :   // in the FrameMetrics so APZ knows to provide the scroll grabbing
    9308           0 :   // behaviour.
    9309           0 :   if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) {
    9310             :     metadata.SetHasScrollgrab(true);
    9311             :   }
    9312             : 
    9313             :   // Also compute and set the background color.
    9314           0 :   // This is needed for APZ overscrolling support.
    9315             :   if (aScrollFrame) {
    9316             :     if (isRootScrollFrame) {
    9317             :       metadata.SetBackgroundColor(Color::FromABGR(
    9318             :         presShell->GetCanvasBackground()));
    9319           0 :     } else {
    9320             :       ComputedStyle* backgroundStyle;
    9321             :       if (nsCSSRendering::FindBackground(aScrollFrame, &backgroundStyle)) {
    9322             :         nscolor backgroundColor = backgroundStyle->
    9323             :           StyleBackground()->BackgroundColor(backgroundStyle);
    9324             :         metadata.SetBackgroundColor(Color::FromABGR(backgroundColor));
    9325           0 :       }
    9326           0 :     }
    9327           0 :   }
    9328           0 : 
    9329             :   if (ShouldDisableApzForElement(aContent)) {
    9330             :     metadata.SetForceDisableApz(true);
    9331           0 :   }
    9332             : 
    9333           0 :   return metadata;
    9334           0 : }
    9335             : 
    9336             : /*static*/ Maybe<ScrollMetadata>
    9337             : nsLayoutUtils::GetRootMetadata(nsDisplayListBuilder* aBuilder,
    9338             :                                LayerManager* aLayerManager,
    9339           0 :                                const ContainerLayerParameters& aContainerParameters,
    9340             :                                const std::function<bool(ViewID& aScrollId)>& aCallback)
    9341             : {
    9342             :   nsIFrame* frame = aBuilder->RootReferenceFrame();
    9343           0 :   nsPresContext* presContext = frame->PresContext();
    9344             :   nsIPresShell* presShell = presContext->PresShell();
    9345             :   nsIDocument* document = presShell->GetDocument();
    9346             : 
    9347           0 :   // If we're using containerless scrolling, there is still one case where we
    9348             :   // want the root container layer to have metrics. If the parent process is
    9349             :   // using XUL windows, there is no root scrollframe, and without explicitly
    9350             :   // creating metrics there will be no guaranteed top-level APZC.
    9351             :   bool addMetrics = gfxPrefs::LayoutUseContainersForRootFrames() ||
    9352           0 :       (XRE_IsParentProcess() && !presShell->GetRootScrollFrame());
    9353           0 : 
    9354           0 :   // Add metrics if there are none in the layer tree with the id (create an id
    9355           0 :   // if there isn't one already) of the root scroll frame/root content.
    9356             :   bool ensureMetricsForRootId =
    9357             :     nsLayoutUtils::AsyncPanZoomEnabled(frame) &&
    9358             :     !gfxPrefs::LayoutUseContainersForRootFrames() &&
    9359             :     aBuilder->IsPaintingToWindow() &&
    9360             :     !presContext->GetParentPresContext();
    9361           0 : 
    9362           0 :   nsIContent* content = nullptr;
    9363             :   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    9364             :   if (rootScrollFrame) {
    9365             :     content = rootScrollFrame->GetContent();
    9366             :   } else {
    9367           0 :     // If there is no root scroll frame, pick the document element instead.
    9368           0 :     // The only case we don't want to do this is in non-APZ fennec, where
    9369           0 :     // we want the root xul document to get a null scroll id so that the root
    9370           0 :     // content document gets the first non-null scroll id.
    9371             :     content = document->GetDocumentElement();
    9372           0 :   }
    9373           0 : 
    9374           0 :   if (ensureMetricsForRootId && content) {
    9375           0 :     ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
    9376             :     if (aCallback(scrollId)) {
    9377             :       ensureMetricsForRootId = false;
    9378             :     }
    9379             :   }
    9380             : 
    9381           0 :   if (addMetrics || ensureMetricsForRootId) {
    9382             :     bool isRootContent = presContext->IsRootContentDocument();
    9383             : 
    9384           0 :     nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize());
    9385           0 :     return Some(nsLayoutUtils::ComputeScrollMetadata(frame,
    9386           0 :                            rootScrollFrame, content,
    9387           0 :                            aBuilder->FindReferenceFrameFor(frame),
    9388             :                            aLayerManager, FrameMetrics::NULL_SCROLL_ID, viewport, Nothing(),
    9389             :                            isRootContent, aContainerParameters));
    9390             :   }
    9391           0 : 
    9392           0 :   return Nothing();
    9393             : }
    9394           0 : 
    9395           0 : /* static */ bool
    9396             : nsLayoutUtils::ContainsMetricsWithId(const Layer* aLayer, const ViewID& aScrollId)
    9397             : {
    9398             :   for (uint32_t i = aLayer->GetScrollMetadataCount(); i > 0; i--) {
    9399           0 :     if (aLayer->GetFrameMetrics(i-1).GetScrollId() == aScrollId) {
    9400             :       return true;
    9401             :     }
    9402             :   }
    9403             :   for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
    9404             :     if (ContainsMetricsWithId(child, aScrollId)) {
    9405             :       return true;
    9406           0 :     }
    9407             :   }
    9408           0 :   return false;
    9409           0 : }
    9410             : 
    9411             : /* static */ uint32_t
    9412             : nsLayoutUtils::GetTouchActionFromFrame(nsIFrame* aFrame)
    9413           0 : {
    9414           0 :   // If aFrame is null then return default value
    9415             :   if (!aFrame) {
    9416             :     return NS_STYLE_TOUCH_ACTION_AUTO;
    9417             :   }
    9418             : 
    9419             :   // The touch-action CSS property applies to: all elements except:
    9420             :   // non-replaced inline elements, table rows, row groups, table columns, and column groups
    9421             :   bool isNonReplacedInlineElement = aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
    9422           0 :   if (isNonReplacedInlineElement) {
    9423             :     return NS_STYLE_TOUCH_ACTION_AUTO;
    9424             :   }
    9425           0 : 
    9426             :   const nsStyleDisplay* disp = aFrame->StyleDisplay();
    9427             :   bool isTableElement = disp->IsInnerTableStyle() &&
    9428             :     disp->mDisplay != StyleDisplay::TableCell &&
    9429             :     disp->mDisplay != StyleDisplay::TableCaption;
    9430             :   if (isTableElement) {
    9431           0 :     return NS_STYLE_TOUCH_ACTION_AUTO;
    9432           0 :   }
    9433             : 
    9434             :   return disp->mTouchAction;
    9435             : }
    9436           0 : 
    9437           0 : /* static */  void
    9438           0 : nsLayoutUtils::TransformToAncestorAndCombineRegions(
    9439           0 :   const nsRegion& aRegion,
    9440           0 :   nsIFrame* aFrame,
    9441             :   const nsIFrame* aAncestorFrame,
    9442             :   nsRegion* aPreciseTargetDest,
    9443             :   nsRegion* aImpreciseTargetDest,
    9444           0 :   Maybe<Matrix4x4Flagged>* aMatrixCache,
    9445             :   const DisplayItemClip* aClip)
    9446             : {
    9447             :   if (aRegion.IsEmpty()) {
    9448           0 :     return;
    9449             :   }
    9450             :   bool isPrecise;
    9451             :   RegionBuilder<nsRegion> transformedRegion;
    9452             :   for (nsRegion::RectIterator it = aRegion.RectIter(); !it.Done(); it.Next()) {
    9453             :     nsRect transformed = TransformFrameRectToAncestor(
    9454             :       aFrame, it.Get(), aAncestorFrame, &isPrecise, aMatrixCache);
    9455             :     if (aClip) {
    9456             :       transformed = aClip->ApplyNonRoundedIntersection(transformed);
    9457           0 :       if (aClip->GetRoundedRectCount() > 0) {
    9458           0 :         isPrecise = false;
    9459             :       }
    9460             :     }
    9461           0 :     transformedRegion.OrWith(transformed);
    9462           0 :   }
    9463             :   nsRegion* dest = isPrecise ? aPreciseTargetDest : aImpreciseTargetDest;
    9464           0 :   dest->OrWith(transformedRegion.ToRegion());
    9465           0 : }
    9466           0 : 
    9467           0 : /* static */ bool
    9468           0 : nsLayoutUtils::ShouldUseNoScriptSheet(nsIDocument* aDocument)
    9469             : {
    9470             :   // also handle the case where print is done from print preview
    9471           0 :   // see bug #342439 for more details
    9472             :   if (aDocument->IsStaticDocument()) {
    9473           0 :     aDocument = aDocument->GetOriginalDocument();
    9474           0 :   }
    9475             :   return aDocument->IsScriptEnabled();
    9476             : }
    9477             : 
    9478           0 : /* static */ bool
    9479             : nsLayoutUtils::ShouldUseNoFramesSheet(nsIDocument* aDocument)
    9480             : {
    9481             :   bool allowSubframes = true;
    9482           0 :   nsIDocShell* docShell = aDocument->GetDocShell();
    9483           0 :   if (docShell) {
    9484             :     docShell->GetAllowSubframes(&allowSubframes);
    9485           0 :   }
    9486             :   return !allowSubframes;
    9487             : }
    9488             : 
    9489           0 : /* static */ void
    9490             : nsLayoutUtils::GetFrameTextContent(nsIFrame* aFrame, nsAString& aResult)
    9491           0 : {
    9492           0 :   aResult.Truncate();
    9493           0 :   AppendFrameTextContent(aFrame, aResult);
    9494           0 : }
    9495             : 
    9496           0 : /* static */ void
    9497             : nsLayoutUtils::AppendFrameTextContent(nsIFrame* aFrame, nsAString& aResult)
    9498             : {
    9499             :   if (aFrame->IsTextFrame()) {
    9500           0 :     auto textFrame = static_cast<nsTextFrame*>(aFrame);
    9501             :     auto offset = textFrame->GetContentOffset();
    9502           0 :     auto length = textFrame->GetContentLength();
    9503           0 :     textFrame->GetContent()->
    9504           0 :       GetText()->AppendTo(aResult, offset, length);
    9505             :   } else {
    9506             :     for (nsIFrame* child : aFrame->PrincipalChildList()) {
    9507           0 :       AppendFrameTextContent(child, aResult);
    9508             :     }
    9509           0 :   }
    9510           0 : }
    9511           0 : 
    9512           0 : /* static */
    9513           0 : nsRect
    9514           0 : nsLayoutUtils::GetSelectionBoundingRect(Selection* aSel)
    9515             : {
    9516           0 :   nsRect res;
    9517           0 :   // Bounding client rect may be empty after calling GetBoundingClientRect
    9518             :   // when range is collapsed. So we get caret's rect when range is
    9519             :   // collapsed.
    9520           0 :   if (aSel->IsCollapsed()) {
    9521             :     nsIFrame* frame = nsCaret::GetGeometry(aSel, &res);
    9522             :     if (frame) {
    9523             :       nsIFrame* relativeTo = GetContainingBlockForClientRect(frame);
    9524           0 :       res = TransformFrameRectToAncestor(frame, res, relativeTo);
    9525             :     }
    9526           0 :   } else {
    9527             :     int32_t rangeCount = aSel->RangeCount();
    9528             :     RectAccumulator accumulator;
    9529             :     for (int32_t idx = 0; idx < rangeCount; ++idx) {
    9530           0 :       nsRange* range = aSel->GetRangeAt(idx);
    9531           0 :       nsRange::CollectClientRectsAndText(&accumulator, nullptr, range,
    9532           0 :                                          range->GetStartContainer(),
    9533           0 :                                          range->StartOffset(),
    9534           0 :                                          range->GetEndContainer(),
    9535             :                                          range->EndOffset(),
    9536             :                                          true, false);
    9537           0 :     }
    9538           0 :     res = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect :
    9539           0 :       accumulator.mResultRect;
    9540           0 :   }
    9541           0 : 
    9542             :   return res;
    9543             : }
    9544             : 
    9545             : /* static */ nsBlockFrame*
    9546           0 : nsLayoutUtils::GetFloatContainingBlock(nsIFrame* aFrame)
    9547             : {
    9548           0 :   nsIFrame* ancestor = aFrame->GetParent();
    9549             :   while (ancestor && !ancestor->IsFloatContainingBlock()) {
    9550             :     ancestor = ancestor->GetParent();
    9551             :   }
    9552           0 :   MOZ_ASSERT(!ancestor || GetAsBlock(ancestor),
    9553             :              "Float containing block can only be block frame");
    9554             :   return static_cast<nsBlockFrame*>(ancestor);
    9555             : }
    9556           0 : 
    9557             : // The implementation of this calculation is adapted from
    9558           0 : // Element::GetBoundingClientRect().
    9559           0 : /* static */ CSSRect
    9560           0 : nsLayoutUtils::GetBoundingContentRect(const nsIContent* aContent,
    9561             :                                       const nsIScrollableFrame* aRootScrollFrame) {
    9562           0 :   CSSRect result;
    9563             :   if (nsIFrame* frame = aContent->GetPrimaryFrame()) {
    9564           0 :     nsIFrame* relativeTo = aRootScrollFrame->GetScrolledFrame();
    9565             :     result = CSSRect::FromAppUnits(
    9566             :         nsLayoutUtils::GetAllInFlowRectsUnion(
    9567             :             frame,
    9568             :             relativeTo,
    9569             :             nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS));
    9570           0 : 
    9571             :     // If the element is contained in a scrollable frame that is not
    9572           0 :     // the root scroll frame, make sure to clip the result so that it is
    9573           0 :     // not larger than the containing scrollable frame's bounds.
    9574           0 :     nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetNearestScrollableFrame(frame);
    9575             :     if (scrollFrame && scrollFrame != aRootScrollFrame) {
    9576           0 :       nsIFrame* subFrame = do_QueryFrame(scrollFrame);
    9577             :       MOZ_ASSERT(subFrame);
    9578             :       // Get the bounds of the scroll frame in the same coordinate space
    9579           0 :       // as |result|.
    9580             :       CSSRect subFrameRect = CSSRect::FromAppUnits(
    9581             :           nsLayoutUtils::TransformFrameRectToAncestor(
    9582             :               subFrame,
    9583             :               subFrame->GetRectRelativeToSelf(),
    9584           0 :               relativeTo));
    9585           0 : 
    9586           0 :       result = subFrameRect.Intersect(result);
    9587           0 :     }
    9588             :   }
    9589             :   return result;
    9590             : }
    9591           0 : 
    9592             : static already_AddRefed<nsIPresShell>
    9593           0 : GetPresShell(const nsIContent* aContent)
    9594           0 : {
    9595             :   nsCOMPtr<nsIPresShell> result;
    9596           0 :   if (nsIDocument* doc = aContent->GetComposedDoc()) {
    9597             :     result = doc->GetShell();
    9598             :   }
    9599           0 :   return result.forget();
    9600             : }
    9601             : 
    9602             : static void UpdateDisplayPortMarginsForPendingMetrics(FrameMetrics& aMetrics) {
    9603           0 :   nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
    9604             :   if (!content) {
    9605           0 :     return;
    9606           0 :   }
    9607           0 : 
    9608             :   nsCOMPtr<nsIPresShell> shell = GetPresShell(content);
    9609           0 :   if (!shell) {
    9610             :     return;
    9611             :   }
    9612           0 : 
    9613           0 :   MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
    9614           0 : 
    9615           0 :   if (gfxPrefs::APZAllowZooming() && aMetrics.IsRootContent()) {
    9616             :     // See APZCCallbackHelper::UpdateRootFrame for details.
    9617             :     float presShellResolution = shell->GetResolution();
    9618           0 :     if (presShellResolution != aMetrics.GetPresShellResolution()) {
    9619           0 :       return;
    9620           0 :     }
    9621             :   }
    9622             : 
    9623           0 :   nsIScrollableFrame* frame = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
    9624             : 
    9625           0 :   if (!frame) {
    9626             :     return;
    9627           0 :   }
    9628           0 : 
    9629             :   if (APZCCallbackHelper::IsScrollInProgress(frame)) {
    9630             :     // If these conditions are true, then the UpdateFrame
    9631             :     // message may be ignored by the main-thread, so we
    9632             :     // shouldn't update the displayport based on it.
    9633           0 :     return;
    9634             :   }
    9635           0 : 
    9636             :   DisplayPortMarginsPropertyData* currentData =
    9637             :     static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
    9638             :   if (!currentData) {
    9639           0 :     return;
    9640             :   }
    9641             : 
    9642             :   CSSPoint frameScrollOffset = CSSPoint::FromAppUnits(frame->GetScrollPosition());
    9643             :   APZCCallbackHelper::AdjustDisplayPortForScrollDelta(aMetrics, frameScrollOffset);
    9644             : 
    9645             :   nsLayoutUtils::SetDisplayPortMargins(content, shell,
    9646             :                                        aMetrics.GetDisplayPortMargins(), 0);
    9647           0 : }
    9648           0 : 
    9649             : /* static */ void
    9650             : nsLayoutUtils::UpdateDisplayPortMarginsFromPendingMessages()
    9651             : {
    9652           0 :   if (XRE_IsContentProcess() &&
    9653           0 :       mozilla::layers::CompositorBridgeChild::Get() &&
    9654             :       mozilla::layers::CompositorBridgeChild::Get()->GetIPCChannel()) {
    9655           0 :     CompositorBridgeChild::Get()->GetIPCChannel()->PeekMessages(
    9656           0 :       [](const IPC::Message& aMsg) -> bool {
    9657             :         if (aMsg.type() == mozilla::layers::PAPZ::Msg_RequestContentRepaint__ID) {
    9658             :           PickleIterator iter(aMsg);
    9659             :           FrameMetrics frame;
    9660           0 :           if (!IPC::ReadParam(&aMsg, &iter, &frame)) {
    9661             :             MOZ_ASSERT(false);
    9662           0 :             return true;
    9663           0 :           }
    9664           0 : 
    9665           0 :           UpdateDisplayPortMarginsForPendingMetrics(frame);
    9666           0 :         }
    9667           0 :         return true;
    9668           0 :       });
    9669           0 :   }
    9670           0 : }
    9671           0 : 
    9672             : /* static */ bool
    9673             : nsLayoutUtils::IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
    9674             : {
    9675           0 :   for (nsIFrame* f = aForFrame; f != aTopFrame; f = f->GetParent()) {
    9676             :     if (f->IsTransformed()) {
    9677             :       return true;
    9678           0 :     }
    9679             :   }
    9680           0 :   return false;
    9681             : }
    9682             : 
    9683           0 : /*static*/ CSSPoint
    9684             : nsLayoutUtils::GetCumulativeApzCallbackTransform(nsIFrame* aFrame)
    9685           0 : {
    9686           0 :   CSSPoint delta;
    9687             :   if (!aFrame) {
    9688             :     return delta;
    9689             :   }
    9690             :   nsIFrame* frame = aFrame;
    9691             :   nsCOMPtr<nsIContent> content = frame->GetContent();
    9692             :   nsCOMPtr<nsIContent> lastContent;
    9693             :   while (frame) {
    9694           0 :     if (content && (content != lastContent)) {
    9695             :       void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
    9696           0 :       if (property) {
    9697           0 :         delta += *static_cast<CSSPoint*>(property);
    9698           0 :       }
    9699             :     }
    9700           0 :     frame = GetCrossDocParentFrame(frame);
    9701           0 :     lastContent = content;
    9702           0 :     content = frame ? frame->GetContent() : nullptr;
    9703           0 :   }
    9704           0 :   return delta;
    9705           0 : }
    9706           0 : 
    9707           0 : /* static */ nsRect
    9708             : nsLayoutUtils::ComputePartialPrerenderArea(const nsRect& aDirtyRect,
    9709             :                                            const nsRect& aOverflow,
    9710           0 :                                            const nsSize& aPrerenderSize)
    9711           0 : {
    9712           0 :   // Simple calculation for now: center the pre-render area on the dirty rect,
    9713             :   // and clamp to the overflow area. Later we can do more advanced things like
    9714           0 :   // redistributing from one axis to another, or from one side to another.
    9715             :   nscoord xExcess = std::max(aPrerenderSize.width - aDirtyRect.width, 0);
    9716             :   nscoord yExcess = std::max(aPrerenderSize.height - aDirtyRect.height, 0);
    9717             :   nsRect result = aDirtyRect;
    9718           0 :   result.Inflate(xExcess / 2, yExcess / 2);
    9719             :   return result.MoveInsideAndClamp(aOverflow);
    9720             : }
    9721             : 
    9722             : static
    9723             : bool
    9724             : LineHasNonEmptyContentWorker(nsIFrame* aFrame)
    9725           0 : {
    9726           0 :   // Look for non-empty frames, but ignore inline and br frames.
    9727           0 :   // For inline frames, descend into the children, if any.
    9728           0 :   if (aFrame->IsInlineFrame()) {
    9729           0 :     for (nsIFrame* child : aFrame->PrincipalChildList()) {
    9730             :       if (LineHasNonEmptyContentWorker(child)) {
    9731             :         return true;
    9732             :       }
    9733             :     }
    9734           0 :   } else {
    9735             :     if (!aFrame->IsBrFrame() && !aFrame->IsEmpty()) {
    9736             :       return true;
    9737             :     }
    9738           0 :   }
    9739           0 :   return false;
    9740           0 : }
    9741           0 : 
    9742             : static
    9743             : bool
    9744             : LineHasNonEmptyContent(nsLineBox* aLine)
    9745           0 : {
    9746             :   int32_t count = aLine->GetChildCount();
    9747             :   for (nsIFrame* frame = aLine->mFirstChild; count > 0;
    9748             :        --count, frame = frame->GetNextSibling()) {
    9749             :     if (LineHasNonEmptyContentWorker(frame)) {
    9750             :       return true;
    9751             :     }
    9752             :   }
    9753             :   return false;
    9754           0 : }
    9755             : 
    9756           0 : /* static */ bool
    9757           0 : nsLayoutUtils::IsInvisibleBreak(nsINode* aNode, nsIFrame** aNextLineFrame)
    9758             : {
    9759           0 :   if (aNextLineFrame) {
    9760             :     *aNextLineFrame = nullptr;
    9761             :   }
    9762             : 
    9763             :   if (!aNode->IsElement() || !aNode->IsEditable()) {
    9764             :     return false;
    9765             :   }
    9766             :   nsIFrame* frame = aNode->AsElement()->GetPrimaryFrame();
    9767           0 :   if (!frame || !frame->IsBrFrame()) {
    9768             :     return false;
    9769           0 :   }
    9770           0 : 
    9771             :   nsContainerFrame* f = frame->GetParent();
    9772             :   while (f && f->IsFrameOfType(nsBox::eLineParticipant)) {
    9773           0 :     f = f->GetParent();
    9774             :   }
    9775             :   nsBlockFrame* blockAncestor = do_QueryFrame(f);
    9776           0 :   if (!blockAncestor) {
    9777           0 :     // The container frame doesn't support line breaking.
    9778             :     return false;
    9779             :   }
    9780             : 
    9781           0 :   bool valid = false;
    9782           0 :   nsBlockInFlowLineIterator iter(blockAncestor, frame, &valid);
    9783           0 :   if (!valid) {
    9784             :     return false;
    9785           0 :   }
    9786           0 : 
    9787             :   bool lineNonEmpty = LineHasNonEmptyContent(iter.GetLine());
    9788             :   if (!lineNonEmpty) {
    9789             :     return false;
    9790             :   }
    9791           0 : 
    9792           0 :   while (iter.Next()) {
    9793           0 :     auto currentLine = iter.GetLine();
    9794             :     // Completely skip empty lines.
    9795             :     if (!currentLine->IsEmpty()) {
    9796             :       // If we come across an inline line, the BR has caused a visible line break.
    9797           0 :       if (currentLine->IsInline()) {
    9798           0 :         if (aNextLineFrame) {
    9799             :           *aNextLineFrame = currentLine->mFirstChild;
    9800             :         }
    9801             :         return false;
    9802           0 :       }
    9803           0 :       break;
    9804             :     }
    9805           0 :   }
    9806             : 
    9807           0 :   return lineNonEmpty;
    9808           0 : }
    9809           0 : 
    9810             : static nsRect
    9811           0 : ComputeSVGReferenceRect(nsIFrame* aFrame,
    9812             :                         StyleGeometryBox aGeometryBox)
    9813           0 : {
    9814             :   MOZ_ASSERT(aFrame->GetContent()->IsSVGElement());
    9815             :   nsRect r;
    9816             : 
    9817             :   // For SVG elements without associated CSS layout box, the used value for
    9818             :   // content-box, padding-box, border-box and margin-box is fill-box.
    9819             :   switch (aGeometryBox) {
    9820             :     case StyleGeometryBox::StrokeBox: {
    9821           0 :       // XXX Bug 1299876
    9822             :       // The size of srtoke-box is not correct if this graphic element has
    9823             :       // specific stroke-linejoin or stroke-linecap.
    9824           0 :       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
    9825           0 :                 nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke);
    9826             :       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
    9827             :                                          nsPresContext::AppUnitsPerCSSPixel());
    9828             :       break;
    9829           0 :     }
    9830             :     case StyleGeometryBox::ViewBox: {
    9831             :       nsIContent* content = aFrame->GetContent();
    9832             :       nsSVGElement* element = static_cast<nsSVGElement*>(content);
    9833             :       SVGViewportElement* svgElement = element->GetCtx();
    9834             :       MOZ_ASSERT(svgElement);
    9835           0 : 
    9836           0 :       if (svgElement && svgElement->HasViewBoxRect()) {
    9837             :         // If a ‘viewBox‘ attribute is specified for the SVG viewport creating
    9838             :         // element:
    9839             :         // 1. The reference box is positioned at the origin of the coordinate
    9840             :         //    system established by the ‘viewBox‘ attribute.
    9841           0 :         // 2. The dimension of the reference box is set to the width and height
    9842           0 :         //    values of the ‘viewBox‘ attribute.
    9843           0 :         nsSVGViewBox* viewBox = svgElement->GetViewBox();
    9844           0 :         const nsSVGViewBoxRect& value = viewBox->GetAnimValue();
    9845             :         r = nsRect(nsPresContext::CSSPixelsToAppUnits(value.x),
    9846           0 :                    nsPresContext::CSSPixelsToAppUnits(value.y),
    9847             :                    nsPresContext::CSSPixelsToAppUnits(value.width),
    9848             :                    nsPresContext::CSSPixelsToAppUnits(value.height));
    9849             :       } else {
    9850             :         // No viewBox is specified, uses the nearest SVG viewport as reference
    9851             :         // box.
    9852             :         svgFloatSize viewportSize = svgElement->GetViewportSize();
    9853           0 :         r = nsRect(0, 0,
    9854           0 :                    nsPresContext::CSSPixelsToAppUnits(viewportSize.width),
    9855           0 :                    nsPresContext::CSSPixelsToAppUnits(viewportSize.height));
    9856           0 :       }
    9857           0 : 
    9858           0 :       break;
    9859             :     }
    9860             :     case StyleGeometryBox::NoBox:
    9861             :     case StyleGeometryBox::BorderBox:
    9862           0 :     case StyleGeometryBox::ContentBox:
    9863           0 :     case StyleGeometryBox::PaddingBox:
    9864             :     case StyleGeometryBox::MarginBox:
    9865             :     case StyleGeometryBox::FillBox: {
    9866             :       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
    9867             :                                          nsSVGUtils::eBBoxIncludeFill);
    9868             :       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
    9869             :                                          nsPresContext::AppUnitsPerCSSPixel());
    9870             :       break;
    9871             :     }
    9872             :     default:{
    9873             :       MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type");
    9874             :       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
    9875             :                                          nsSVGUtils::eBBoxIncludeFill);
    9876             :       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
    9877           0 :                                          nsPresContext::AppUnitsPerCSSPixel());
    9878           0 :       break;
    9879             :     }
    9880             :   }
    9881             : 
    9882             :   return r;
    9883           0 : }
    9884             : 
    9885             : static nsRect
    9886             : ComputeHTMLReferenceRect(nsIFrame* aFrame,
    9887             :                          StyleGeometryBox aGeometryBox)
    9888             : {
    9889             :   nsRect r;
    9890             : 
    9891             :   // For elements with associated CSS layout box, the used value for fill-box,
    9892           0 :   // stroke-box and view-box is border-box.
    9893             :   switch (aGeometryBox) {
    9894             :     case StyleGeometryBox::ContentBox:
    9895             :       r = aFrame->GetContentRectRelativeToSelf();
    9896           0 :       break;
    9897             :     case StyleGeometryBox::PaddingBox:
    9898             :       r = aFrame->GetPaddingRectRelativeToSelf();
    9899           0 :       break;
    9900             :     case StyleGeometryBox::MarginBox:
    9901             :       r = aFrame->GetMarginRectRelativeToSelf();
    9902             :       break;
    9903           0 :     case StyleGeometryBox::NoBox:
    9904             :     case StyleGeometryBox::BorderBox:
    9905           0 :     case StyleGeometryBox::FillBox:
    9906           0 :     case StyleGeometryBox::StrokeBox:
    9907             :     case StyleGeometryBox::ViewBox:
    9908           0 :       r = aFrame->GetRectRelativeToSelf();
    9909           0 :       break;
    9910             :     default:
    9911           0 :       MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type");
    9912           0 :       r = aFrame->GetRectRelativeToSelf();
    9913             :       break;
    9914             :   }
    9915             : 
    9916             :   return r;
    9917             : }
    9918           0 : 
    9919           0 : /* static */ nsRect
    9920             : nsLayoutUtils::ComputeGeometryBox(nsIFrame* aFrame,
    9921           0 :                                   StyleGeometryBox aGeometryBox)
    9922             : {
    9923             :   // We use ComputeSVGReferenceRect for all SVG elements, except <svg>
    9924             :   // element, which does have an associated CSS layout box. In this case we
    9925             :   // should still use ComputeHTMLReferenceRect for region computing.
    9926           0 :   nsRect r = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)
    9927             :              ? ComputeSVGReferenceRect(aFrame, aGeometryBox)
    9928             :              : ComputeHTMLReferenceRect(aFrame, aGeometryBox);
    9929             : 
    9930           0 :   return r;
    9931             : }
    9932             : 
    9933             : /* static */ nsPoint
    9934             : nsLayoutUtils::ComputeOffsetToUserSpace(nsDisplayListBuilder* aBuilder,
    9935             :                                         nsIFrame* aFrame)
    9936           0 : {
    9937             :   nsPoint offsetToBoundingBox = aBuilder->ToReferenceFrame(aFrame) -
    9938           0 :                          nsSVGIntegrationUtils::GetOffsetToBoundingBox(aFrame);
    9939             :   if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
    9940           0 :     // Snap the offset if the reference frame is not a SVG frame, since other
    9941             :     // frames will be snapped to pixel when rendering.
    9942             :     offsetToBoundingBox = nsPoint(
    9943             :       aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
    9944           0 :       aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
    9945             :   }
    9946             : 
    9947           0 :   // During SVG painting, the offset computed here is applied to the gfxContext
    9948           0 :   // "ctx" used to paint the mask. After applying only "offsetToBoundingBox",
    9949           0 :   // "ctx" would have its origin at the top left corner of frame's bounding box
    9950             :   // (over all continuations).
    9951             :   // However, SVG painting needs the origin to be located at the origin of the
    9952           0 :   // SVG frame's "user space", i.e. the space in which, for example, the
    9953             :   // frame's BBox lives.
    9954             :   // SVG geometry frames and foreignObject frames apply their own offsets, so
    9955             :   // their position is relative to their user space. So for these frame types,
    9956             :   // if we want "ctx" to be in user space, we first need to subtract the
    9957             :   // frame's position so that SVG painting can later add it again and the
    9958             :   // frame is painted in the right place.
    9959             :   gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame);
    9960             :   nsPoint toUserSpace =
    9961             :     nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
    9962             :             nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
    9963             : 
    9964             :   return (offsetToBoundingBox - toUserSpace);
    9965             : }
    9966             : 
    9967             : /* static */ uint8_t
    9968             : nsLayoutUtils::ControlCharVisibilityDefault()
    9969           0 : {
    9970             :   return StaticPrefs::layout_css_control_characters_visible()
    9971           0 :     ? NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE
    9972           0 :     : NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
    9973             : }
    9974           0 : 
    9975             : /* static */
    9976             : already_AddRefed<nsFontMetrics>
    9977             : nsLayoutUtils::GetMetricsFor(nsPresContext* aPresContext,
    9978           0 :                              bool aIsVertical,
    9979             :                              const nsStyleFont* aStyleFont,
    9980          35 :                              nscoord aFontSize,
    9981             :                              bool aUseUserFontSet,
    9982           0 :                              FlushUserFontSet aFlushUserFontSet)
    9983             : {
    9984             :   nsFont font = aStyleFont->mFont;
    9985             :   font.size = aFontSize;
    9986             :   gfxFont::Orientation orientation
    9987           0 :     = aIsVertical ? gfxFont::eVertical : gfxFont::eHorizontal;
    9988             :   nsFontMetrics::Params params;
    9989             :   params.language = aStyleFont->mLanguage;
    9990             :   params.explicitLanguage = aStyleFont->mExplicitLanguage;
    9991             :   params.orientation = orientation;
    9992             :   params.userFontSet = aUseUserFontSet
    9993             :     ? aPresContext->GetUserFontSet(aFlushUserFontSet == FlushUserFontSet::Yes)
    9994           0 :     : nullptr;
    9995           0 :   params.textPerf = aPresContext->GetTextPerfMetrics();
    9996             :   return aPresContext->DeviceContext()->GetMetricsFor(font, params);
    9997           0 : }
    9998           0 : 
    9999           0 : /* static */ void
   10000           0 : nsLayoutUtils::FixupNoneGeneric(nsFont* aFont,
   10001           0 :                                 const nsPresContext* aPresContext,
   10002           0 :                                 uint8_t aGenericFontID,
   10003           0 :                                 const nsFont* aDefaultVariableFont)
   10004             : {
   10005           0 :   bool useDocumentFonts =
   10006           0 :     aPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
   10007             :   if (aGenericFontID == kGenericFont_NONE ||
   10008             :       (!useDocumentFonts && (aGenericFontID == kGenericFont_cursive ||
   10009             :                              aGenericFontID == kGenericFont_fantasy))) {
   10010           0 :     FontFamilyType defaultGeneric =
   10011             :       aDefaultVariableFont->fontlist.GetDefaultFontType();
   10012             :     MOZ_ASSERT(aDefaultVariableFont->fontlist.IsEmpty() &&
   10013             :                (defaultGeneric == eFamily_serif ||
   10014             :                 defaultGeneric == eFamily_sans_serif));
   10015             :     if (defaultGeneric != eFamily_none) {
   10016           0 :       if (useDocumentFonts) {
   10017           0 :         aFont->fontlist.SetDefaultFontType(defaultGeneric);
   10018           0 :       } else {
   10019           0 :         // Either prioritize the first generic in the list,
   10020             :         // or (if there isn't one) prepend the default variable font.
   10021           0 :         if (!aFont->fontlist.PrioritizeFirstGeneric()) {
   10022           0 :           aFont->fontlist.PrependGeneric(defaultGeneric);
   10023             :         }
   10024             :       }
   10025           0 :     }
   10026           0 :   } else {
   10027           0 :     aFont->fontlist.SetDefaultFontType(eFamily_none);
   10028             :   }
   10029             : }
   10030             : 
   10031           0 : /* static */ void
   10032           0 : nsLayoutUtils::ApplyMinFontSize(nsStyleFont* aFont,
   10033             :                                 const nsPresContext* aPresContext,
   10034             :                                 nscoord aMinFontSize)
   10035             : {
   10036             :   nscoord fontSize = aFont->mSize;
   10037           0 : 
   10038             :   // enforce the user' specified minimum font-size on the value that we expose
   10039           0 :   // (but don't change font-size:0, since that would unhide hidden text)
   10040             :   if (fontSize > 0) {
   10041             :     if (aMinFontSize < 0) {
   10042           0 :       aMinFontSize = 0;
   10043             :     } else {
   10044             :       aMinFontSize = (aMinFontSize * aFont->mMinFontSizeRatio) / 100;
   10045             :     }
   10046           0 :     if (fontSize < aMinFontSize && !aPresContext->IsChrome()) {
   10047             :       // override the minimum font-size constraint
   10048             :       fontSize = aMinFontSize;
   10049             :     }
   10050           0 :   }
   10051           0 :   aFont->mFont.size = fontSize;
   10052             : }
   10053             : 
   10054           0 : /* static */ void
   10055             : nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID,
   10056           0 :                                  const nsPresContext* aPresContext,
   10057             :                                  const nsFont* aDefaultVariableFont)
   10058           0 : {
   10059             :   gfxFontStyle fontStyle;
   10060             :   float devPerCSS =
   10061           0 :     (float)nsPresContext::AppUnitsPerCSSPixel() /
   10062           0 :     aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   10063             :   nsAutoString systemFontName;
   10064             :   if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) {
   10065           0 :     systemFontName.Trim("\"'");
   10066             :     aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName);
   10067             :     aSystemFont->fontlist.SetDefaultFontType(eFamily_none);
   10068             :     aSystemFont->style = fontStyle.style;
   10069           0 :     aSystemFont->systemFont = fontStyle.systemFont;
   10070             :     aSystemFont->weight = fontStyle.weight;
   10071           0 :     aSystemFont->stretch = fontStyle.stretch;
   10072           0 :     aSystemFont->size =
   10073           0 :       NSFloatPixelsToAppUnits(fontStyle.size,
   10074           0 :                               aPresContext->DeviceContext()->
   10075           0 :                                 AppUnitsPerDevPixelAtUnitFullZoom());
   10076           0 :     //aSystemFont->langGroup = fontStyle.langGroup;
   10077           0 :     aSystemFont->sizeAdjust = fontStyle.sizeAdjust;
   10078           0 : 
   10079           0 : #ifdef XP_WIN
   10080           0 :     // XXXldb This platform-specific stuff should be in the
   10081           0 :     // LookAndFeel implementation, not here.
   10082           0 :     // XXXzw Should we even still *have* this code?  It looks to be making
   10083           0 :     // old, probably obsolete assumptions.
   10084             : 
   10085           0 :     if (aFontID == LookAndFeel::eFont_Field ||
   10086             :         aFontID == LookAndFeel::eFont_Button ||
   10087           0 :         aFontID == LookAndFeel::eFont_List) {
   10088             :       // As far as I can tell the system default fonts and sizes
   10089             :       // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
   10090             :       // all pre-determined and cannot be changed by either the control panel
   10091             :       // or programmatically.
   10092             :       // Fields (text fields)
   10093             :       // Button and Selects (listboxes/comboboxes)
   10094             :       //    We use whatever font is defined by the system. Which it appears
   10095             :       //    (and the assumption is) it is always a proportional font. Then we
   10096             :       //    always use 2 points smaller than what the browser has defined as
   10097             :       //    the default proportional font.
   10098             :       // Assumption: system defined font is proportional
   10099             :       aSystemFont->size =
   10100             :         std::max(aDefaultVariableFont->size -
   10101             :                  nsPresContext::CSSPointsToAppUnits(2), 0);
   10102             :     }
   10103             : #endif
   10104             :   }
   10105             : }
   10106             : 
   10107             : static inline void
   10108             : AssertValidFontTag(const nsString& aString)
   10109             : {
   10110             :   // To be valid as a font feature tag, a string MUST be:
   10111             :   MOZ_ASSERT(aString.Length() == 4 &&              // (1) exactly 4 chars long
   10112             :              NS_IsAscii(aString.BeginReading()) && // (2) entirely ASCII
   10113             :              isprint(aString[0]) &&                // (3) all printable chars
   10114             :              isprint(aString[1]) &&
   10115           0 :              isprint(aString[2]) &&
   10116             :              isprint(aString[3]));
   10117             : }
   10118           0 : 
   10119             : /* static */ void
   10120             : nsLayoutUtils::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
   10121           0 :                                    nsTArray<gfxFontFeature>& aFeatureSettings)
   10122             : {
   10123             :   aFeatureSettings.Clear();
   10124             :   for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
   10125             :     gfxFontFeature feat;
   10126             : 
   10127           0 :     MOZ_ASSERT(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
   10128             :                "unexpected value unit");
   10129             : 
   10130           0 :     // tag is a 4-byte ASCII sequence
   10131             :     nsAutoString tag;
   10132             :     p->mXValue.GetStringValue(tag);
   10133           0 :     AssertValidFontTag(tag);
   10134           0 :     if (tag.Length() != 4) {
   10135             :       continue;
   10136             :     }
   10137           0 :     // parsing validates that these are ASCII chars
   10138             :     // tags are always big-endian
   10139             :     feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
   10140             : 
   10141           0 :     // value
   10142           0 :     NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
   10143           0 :                  "should have found an integer unit");
   10144           0 :     feat.mValue = p->mYValue.GetIntValue();
   10145           0 : 
   10146             :     aFeatureSettings.AppendElement(feat);
   10147             :   }
   10148             : }
   10149           0 : 
   10150             : /* static */ void
   10151             : nsLayoutUtils::ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
   10152           0 :                                      nsTArray<gfxFontVariation>& aVariationSettings)
   10153             : {
   10154           0 :   aVariationSettings.Clear();
   10155             :   for (const nsCSSValuePairList* p = aVariationsList; p; p = p->mNext) {
   10156           0 :     gfxFontVariation var;
   10157             : 
   10158           0 :     MOZ_ASSERT(aVariationsList->mXValue.GetUnit() == eCSSUnit_String,
   10159             :                "unexpected value unit");
   10160             : 
   10161           0 :     // tag is a 4-byte ASCII sequence
   10162             :     nsAutoString tag;
   10163             :     p->mXValue.GetStringValue(tag);
   10164           0 :     AssertValidFontTag(tag);
   10165           0 :     if (tag.Length() != 4) {
   10166             :       continue;
   10167             :     }
   10168           0 :     // parsing validates that these are ASCII chars
   10169             :     // tags are always big-endian
   10170             :     var.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
   10171             : 
   10172           0 :     // value
   10173           0 :     NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Number,
   10174           0 :                  "should have found a number unit");
   10175           0 :     var.mValue = p->mYValue.GetFloatValue();
   10176           0 : 
   10177             :     aVariationSettings.AppendElement(var);
   10178             :   }
   10179             : }
   10180           0 : 
   10181             : /* static */ uint32_t
   10182             : nsLayoutUtils::ParseFontLanguageOverride(const nsAString& aLangTag)
   10183           0 : {
   10184             :   if (!aLangTag.Length() || aLangTag.Length() > 4) {
   10185           0 :     return NO_FONT_LANGUAGE_OVERRIDE;
   10186             :   }
   10187           0 :   uint32_t index, result = 0;
   10188             :   for (index = 0; index < aLangTag.Length(); ++index) {
   10189           0 :     char16_t ch = aLangTag[index];
   10190             :     if (!nsCRT::IsAscii(ch)) { // valid tags are pure ASCII
   10191             :       return NO_FONT_LANGUAGE_OVERRIDE;
   10192           0 :     }
   10193             :     result = (result << 8) + ch;
   10194           0 :   }
   10195             :   while (index++ < 4) {
   10196             :     result = (result << 8) + 0x20;
   10197             :   }
   10198           0 :   return result;
   10199           0 : }
   10200           0 : 
   10201             : /* static */ ComputedStyle*
   10202             : nsLayoutUtils::StyleForScrollbar(nsIFrame* aScrollbarPart)
   10203           0 : {
   10204             :   // Get the closest non-native-anonymous content node, which should be
   10205           0 :   // the originating element of the scrollbar part. In theory we could
   10206           0 :   // have an XBL binding attached to NAC element, and that binding
   10207             :   // creates a scrollable element. It's unlikely we want to control the
   10208             :   // style of scrollbars from inside the binding, so that case is not
   10209             :   // considered below.
   10210             :   nsIContent* content = aScrollbarPart->GetContent();
   10211             :   // Note that the content may be a normal element with scrollbar part
   10212           0 :   // value specified for its -moz-appearance, so don't rely on it being
   10213             :   // a native anonymous.
   10214             :   MOZ_ASSERT(content, "No content for the scrollbar part?");
   10215             :   while (content && content->IsInNativeAnonymousSubtree()) {
   10216             :     content = content->GetParent();
   10217             :   }
   10218             :   MOZ_ASSERT(content, "Native anonymous element with no originating node?");
   10219             :   // Use the style from the primary frame of the content.
   10220           0 :   // Note: it is important to use the primary frame rather than an
   10221             :   // ancestor frame of the scrollbar part for the correct handling of
   10222             :   // viewport scrollbar. The content of the scroll frame of the viewport
   10223             :   // is the root element, but its style inherits from the viewport.
   10224           0 :   // Since we need to use the style of root element for the viewport
   10225           0 :   // scrollbar, we have to get the style from the primary frame.
   10226           0 :   if (nsIFrame* primaryFrame = content->GetPrimaryFrame()) {
   10227             :     return primaryFrame->Style();
   10228           0 :   }
   10229             :   // If the element doesn't have primary frame, get the computed style
   10230             :   // from the element directly. This can happen on viewport, because
   10231             :   // the scrollbar of viewport may be shown when the root element has
   10232             :   // > display: none; overflow: scroll;
   10233             :   nsPresContext* pc = aScrollbarPart->PresContext();
   10234             :   MOZ_ASSERT(content == pc->Document()->GetRootElement(),
   10235             :              "Root element is the only case for this fallback "
   10236           0 :              "path to be triggered");
   10237           0 :   RefPtr<ComputedStyle> style =
   10238             :     pc->StyleSet()->ResolveServoStyle(content->AsElement());
   10239             :   // Dropping the strong reference is fine because the style should be
   10240             :   // held strongly by the element.
   10241             :   return style.get();
   10242             : }

Generated by: LCOV version 1.13-14-ga5dd952