LCOV - code coverage report
Current view: top level - layout/base - nsLayoutUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1975 4390 45.0 %
Date: 2017-07-14 16:53:18 Functions: 207 343 60.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13