layout/base/nsLayoutUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/nsLayoutUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,6597 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "nsLayoutUtils.h"
    1.11 +
    1.12 +#include "mozilla/ArrayUtils.h"
    1.13 +#include "mozilla/BasicEvents.h"
    1.14 +#include "mozilla/MemoryReporting.h"
    1.15 +#include "nsPresContext.h"
    1.16 +#include "nsIContent.h"
    1.17 +#include "nsIDOMHTMLDocument.h"
    1.18 +#include "nsIDOMHTMLElement.h"
    1.19 +#include "nsFrameList.h"
    1.20 +#include "nsGkAtoms.h"
    1.21 +#include "nsIAtom.h"
    1.22 +#include "nsCSSPseudoElements.h"
    1.23 +#include "nsCSSAnonBoxes.h"
    1.24 +#include "nsCSSColorUtils.h"
    1.25 +#include "nsView.h"
    1.26 +#include "nsPlaceholderFrame.h"
    1.27 +#include "nsIScrollableFrame.h"
    1.28 +#include "nsIDOMEvent.h"
    1.29 +#include "nsDisplayList.h"
    1.30 +#include "nsRegion.h"
    1.31 +#include "nsFrameManager.h"
    1.32 +#include "nsBlockFrame.h"
    1.33 +#include "nsBidiPresUtils.h"
    1.34 +#include "imgIContainer.h"
    1.35 +#include "ImageOps.h"
    1.36 +#include "gfxRect.h"
    1.37 +#include "gfxContext.h"
    1.38 +#include "nsRenderingContext.h"
    1.39 +#include "nsIInterfaceRequestorUtils.h"
    1.40 +#include "nsCSSRendering.h"
    1.41 +#include "nsThemeConstants.h"
    1.42 +#include "nsPIDOMWindow.h"
    1.43 +#include "nsIDocShell.h"
    1.44 +#include "nsIWidget.h"
    1.45 +#include "gfxMatrix.h"
    1.46 +#include "gfxPoint3D.h"
    1.47 +#include "gfxPrefs.h"
    1.48 +#include "gfxTypes.h"
    1.49 +#include "nsTArray.h"
    1.50 +#include "mozilla/dom/HTMLCanvasElement.h"
    1.51 +#include "nsICanvasRenderingContextInternal.h"
    1.52 +#include "gfxPlatform.h"
    1.53 +#include <algorithm>
    1.54 +#include "mozilla/dom/HTMLVideoElement.h"
    1.55 +#include "mozilla/dom/HTMLImageElement.h"
    1.56 +#include "mozilla/dom/DOMRect.h"
    1.57 +#include "imgIRequest.h"
    1.58 +#include "nsIImageLoadingContent.h"
    1.59 +#include "nsCOMPtr.h"
    1.60 +#include "nsCSSProps.h"
    1.61 +#include "nsListControlFrame.h"
    1.62 +#include "mozilla/dom/Element.h"
    1.63 +#include "nsCanvasFrame.h"
    1.64 +#include "gfxDrawable.h"
    1.65 +#include "gfxUtils.h"
    1.66 +#include "nsDataHashtable.h"
    1.67 +#include "nsTextFrame.h"
    1.68 +#include "nsFontFaceList.h"
    1.69 +#include "nsFontInflationData.h"
    1.70 +#include "nsSVGUtils.h"
    1.71 +#include "SVGTextFrame.h"
    1.72 +#include "nsStyleStructInlines.h"
    1.73 +#include "nsStyleTransformMatrix.h"
    1.74 +#include "nsIFrameInlines.h"
    1.75 +#include "ImageContainer.h"
    1.76 +#include "nsComputedDOMStyle.h"
    1.77 +#include "ActiveLayerTracker.h"
    1.78 +#include "mozilla/gfx/2D.h"
    1.79 +#include "gfx2DGlue.h"
    1.80 +#include "mozilla/LookAndFeel.h"
    1.81 +#include "UnitTransforms.h"
    1.82 +#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
    1.83 +
    1.84 +#include "mozilla/Preferences.h"
    1.85 +
    1.86 +#include "mozilla/LookAndFeel.h"
    1.87 +
    1.88 +#ifdef MOZ_XUL
    1.89 +#include "nsXULPopupManager.h"
    1.90 +#endif
    1.91 +
    1.92 +#include "GeckoProfiler.h"
    1.93 +#include "nsAnimationManager.h"
    1.94 +#include "nsTransitionManager.h"
    1.95 +#include "RestyleManager.h"
    1.96 +
    1.97 +// Additional includes used on B2G by code in GetOrMaybeCreateDisplayPort().
    1.98 +#ifdef MOZ_WIDGET_GONK
    1.99 +#include "mozilla/layers/AsyncPanZoomController.h"
   1.100 +#endif
   1.101 +
   1.102 +using namespace mozilla;
   1.103 +using namespace mozilla::css;
   1.104 +using namespace mozilla::dom;
   1.105 +using namespace mozilla::layers;
   1.106 +using namespace mozilla::layout;
   1.107 +using namespace mozilla::gfx;
   1.108 +
   1.109 +using mozilla::image::Angle;
   1.110 +using mozilla::image::Flip;
   1.111 +using mozilla::image::ImageOps;
   1.112 +using mozilla::image::Orientation;
   1.113 +
   1.114 +#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
   1.115 +#define STICKY_ENABLED_PREF_NAME "layout.css.sticky.enabled"
   1.116 +#define TEXT_ALIGN_TRUE_ENABLED_PREF_NAME "layout.css.text-align-true-value.enabled"
   1.117 +
   1.118 +#ifdef DEBUG
   1.119 +// TODO: remove, see bug 598468.
   1.120 +bool nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
   1.121 +#endif // DEBUG
   1.122 +
   1.123 +typedef FrameMetrics::ViewID ViewID;
   1.124 +
   1.125 +/* static */ uint32_t nsLayoutUtils::sFontSizeInflationEmPerLine;
   1.126 +/* static */ uint32_t nsLayoutUtils::sFontSizeInflationMinTwips;
   1.127 +/* static */ uint32_t nsLayoutUtils::sFontSizeInflationLineThreshold;
   1.128 +/* static */ int32_t  nsLayoutUtils::sFontSizeInflationMappingIntercept;
   1.129 +/* static */ uint32_t nsLayoutUtils::sFontSizeInflationMaxRatio;
   1.130 +/* static */ bool nsLayoutUtils::sFontSizeInflationForceEnabled;
   1.131 +/* static */ bool nsLayoutUtils::sFontSizeInflationDisabledInMasterProcess;
   1.132 +/* static */ bool nsLayoutUtils::sInvalidationDebuggingIsEnabled;
   1.133 +/* static */ bool nsLayoutUtils::sCSSVariablesEnabled;
   1.134 +/* static */ bool nsLayoutUtils::sInterruptibleReflowEnabled;
   1.135 +
   1.136 +static ViewID sScrollIdCounter = FrameMetrics::START_SCROLL_ID;
   1.137 +
   1.138 +typedef nsDataHashtable<nsUint64HashKey, nsIContent*> ContentMap;
   1.139 +static ContentMap* sContentMap = nullptr;
   1.140 +static ContentMap& GetContentMap() {
   1.141 +  if (!sContentMap) {
   1.142 +    sContentMap = new ContentMap();
   1.143 +  }
   1.144 +  return *sContentMap;
   1.145 +}
   1.146 +
   1.147 +// When the pref "layout.css.grid.enabled" changes, this function is invoked
   1.148 +// to let us update kDisplayKTable, to selectively disable or restore the
   1.149 +// entries for "grid" and "inline-grid" in that table.
   1.150 +static void
   1.151 +GridEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
   1.152 +{
   1.153 +  MOZ_ASSERT(strncmp(aPrefName, GRID_ENABLED_PREF_NAME,
   1.154 +                     ArrayLength(GRID_ENABLED_PREF_NAME)) == 0,
   1.155 +             "We only registered this callback for a single pref, so it "
   1.156 +             "should only be called for that pref");
   1.157 +
   1.158 +  static int32_t sIndexOfGridInDisplayTable;
   1.159 +  static int32_t sIndexOfInlineGridInDisplayTable;
   1.160 +  static bool sAreGridKeywordIndicesInitialized; // initialized to false
   1.161 +
   1.162 +  bool isGridEnabled =
   1.163 +    Preferences::GetBool(GRID_ENABLED_PREF_NAME, false);
   1.164 +  if (!sAreGridKeywordIndicesInitialized) {
   1.165 +    // First run: find the position of "grid" and "inline-grid" in
   1.166 +    // kDisplayKTable.
   1.167 +    sIndexOfGridInDisplayTable =
   1.168 +      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_grid,
   1.169 +                                     nsCSSProps::kDisplayKTable);
   1.170 +    MOZ_ASSERT(sIndexOfGridInDisplayTable >= 0,
   1.171 +               "Couldn't find grid in kDisplayKTable");
   1.172 +    sIndexOfInlineGridInDisplayTable =
   1.173 +      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_grid,
   1.174 +                                     nsCSSProps::kDisplayKTable);
   1.175 +    MOZ_ASSERT(sIndexOfInlineGridInDisplayTable >= 0,
   1.176 +               "Couldn't find inline-grid in kDisplayKTable");
   1.177 +    sAreGridKeywordIndicesInitialized = true;
   1.178 +  }
   1.179 +
   1.180 +  // OK -- now, stomp on or restore the "grid" entries in kDisplayKTable,
   1.181 +  // depending on whether the grid pref is enabled vs. disabled.
   1.182 +  if (sIndexOfGridInDisplayTable >= 0) {
   1.183 +    nsCSSProps::kDisplayKTable[sIndexOfGridInDisplayTable] =
   1.184 +      isGridEnabled ? eCSSKeyword_grid : eCSSKeyword_UNKNOWN;
   1.185 +  }
   1.186 +  if (sIndexOfInlineGridInDisplayTable >= 0) {
   1.187 +    nsCSSProps::kDisplayKTable[sIndexOfInlineGridInDisplayTable] =
   1.188 +      isGridEnabled ? eCSSKeyword_inline_grid : eCSSKeyword_UNKNOWN;
   1.189 +  }
   1.190 +}
   1.191 +
   1.192 +// When the pref "layout.css.sticky.enabled" changes, this function is invoked
   1.193 +// to let us update kPositionKTable, to selectively disable or restore the
   1.194 +// entry for "sticky" in that table.
   1.195 +static void
   1.196 +StickyEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
   1.197 +{
   1.198 +  MOZ_ASSERT(strncmp(aPrefName, STICKY_ENABLED_PREF_NAME,
   1.199 +                     ArrayLength(STICKY_ENABLED_PREF_NAME)) == 0,
   1.200 +             "We only registered this callback for a single pref, so it "
   1.201 +             "should only be called for that pref");
   1.202 +
   1.203 +  static int32_t sIndexOfStickyInPositionTable;
   1.204 +  static bool sIsStickyKeywordIndexInitialized; // initialized to false
   1.205 +
   1.206 +  bool isStickyEnabled =
   1.207 +    Preferences::GetBool(STICKY_ENABLED_PREF_NAME, false);
   1.208 +
   1.209 +  if (!sIsStickyKeywordIndexInitialized) {
   1.210 +    // First run: find the position of "sticky" in kPositionKTable.
   1.211 +    sIndexOfStickyInPositionTable =
   1.212 +      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_sticky,
   1.213 +                                     nsCSSProps::kPositionKTable);
   1.214 +    MOZ_ASSERT(sIndexOfStickyInPositionTable >= 0,
   1.215 +               "Couldn't find sticky in kPositionKTable");
   1.216 +    sIsStickyKeywordIndexInitialized = true;
   1.217 +  }
   1.218 +
   1.219 +  // OK -- now, stomp on or restore the "sticky" entry in kPositionKTable,
   1.220 +  // depending on whether the sticky pref is enabled vs. disabled.
   1.221 +  nsCSSProps::kPositionKTable[sIndexOfStickyInPositionTable] =
   1.222 +    isStickyEnabled ? eCSSKeyword_sticky : eCSSKeyword_UNKNOWN;
   1.223 +}
   1.224 +
   1.225 +// When the pref "layout.css.text-align-true-value.enabled" changes, this
   1.226 +// function is called to let us update kTextAlignKTable & kTextAlignLastKTable,
   1.227 +// to selectively disable or restore the entries for "true" in those tables.
   1.228 +static void
   1.229 +TextAlignTrueEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
   1.230 +{
   1.231 +  NS_ASSERTION(strcmp(aPrefName, TEXT_ALIGN_TRUE_ENABLED_PREF_NAME) == 0,
   1.232 +               "Did you misspell " TEXT_ALIGN_TRUE_ENABLED_PREF_NAME " ?");
   1.233 +
   1.234 +  static bool sIsInitialized;
   1.235 +  static int32_t sIndexOfTrueInTextAlignTable;
   1.236 +  static int32_t sIndexOfTrueInTextAlignLastTable;
   1.237 +  bool isTextAlignTrueEnabled =
   1.238 +    Preferences::GetBool(TEXT_ALIGN_TRUE_ENABLED_PREF_NAME, false);
   1.239 +
   1.240 +  if (!sIsInitialized) {
   1.241 +    // First run: find the position of "true" in kTextAlignKTable.
   1.242 +    sIndexOfTrueInTextAlignTable =
   1.243 +      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_true,
   1.244 +                                     nsCSSProps::kTextAlignKTable);
   1.245 +    // First run: find the position of "true" in kTextAlignLastKTable.
   1.246 +    sIndexOfTrueInTextAlignLastTable =
   1.247 +      nsCSSProps::FindIndexOfKeyword(eCSSKeyword_true,
   1.248 +                                     nsCSSProps::kTextAlignLastKTable);
   1.249 +    sIsInitialized = true;
   1.250 +  }
   1.251 +
   1.252 +  // OK -- now, stomp on or restore the "true" entry in the keyword tables,
   1.253 +  // depending on whether the pref is enabled vs. disabled.
   1.254 +  MOZ_ASSERT(sIndexOfTrueInTextAlignTable >= 0);
   1.255 +  nsCSSProps::kTextAlignKTable[sIndexOfTrueInTextAlignTable] =
   1.256 +    isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
   1.257 +  MOZ_ASSERT(sIndexOfTrueInTextAlignLastTable >= 0);
   1.258 +  nsCSSProps::kTextAlignLastKTable[sIndexOfTrueInTextAlignLastTable] =
   1.259 +    isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
   1.260 +}
   1.261 +
   1.262 +template <class AnimationsOrTransitions>
   1.263 +static AnimationsOrTransitions*
   1.264 +HasAnimationOrTransitionForCompositor(nsIContent* aContent,
   1.265 +                                      nsIAtom* aAnimationProperty,
   1.266 +                                      nsCSSProperty aProperty)
   1.267 +{
   1.268 +  AnimationsOrTransitions* animations =
   1.269 +    static_cast<AnimationsOrTransitions*>(aContent->GetProperty(aAnimationProperty));
   1.270 +  if (animations) {
   1.271 +    bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
   1.272 +    if (propertyMatches &&
   1.273 +        animations->CanPerformOnCompositorThread(
   1.274 +          CommonElementAnimationData::CanAnimate_AllowPartial)) {
   1.275 +      return animations;
   1.276 +    }
   1.277 +  }
   1.278 +
   1.279 +  return nullptr;
   1.280 +}
   1.281 +
   1.282 +bool
   1.283 +nsLayoutUtils::HasAnimationsForCompositor(nsIContent* aContent,
   1.284 +                                          nsCSSProperty aProperty)
   1.285 +{
   1.286 +  if (!aContent->MayHaveAnimations())
   1.287 +    return false;
   1.288 +  return HasAnimationOrTransitionForCompositor<ElementAnimations>
   1.289 +            (aContent, nsGkAtoms::animationsProperty, aProperty) ||
   1.290 +         HasAnimationOrTransitionForCompositor<ElementTransitions>
   1.291 +            (aContent, nsGkAtoms::transitionsProperty, aProperty);
   1.292 +}
   1.293 +
   1.294 +template <class AnimationsOrTransitions>
   1.295 +AnimationsOrTransitions*
   1.296 +mozilla::HasAnimationOrTransition(nsIContent* aContent,
   1.297 +                         nsIAtom* aAnimationProperty,
   1.298 +                         nsCSSProperty aProperty)
   1.299 +{
   1.300 +  AnimationsOrTransitions* animations =
   1.301 +    static_cast<AnimationsOrTransitions*>(aContent->GetProperty(aAnimationProperty));
   1.302 +  if (animations) {
   1.303 +    bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
   1.304 +    if (propertyMatches) {
   1.305 +      return animations;
   1.306 +    }
   1.307 +  }
   1.308 +
   1.309 +  return nullptr;
   1.310 +}
   1.311 +
   1.312 +template ElementAnimations*
   1.313 +mozilla::HasAnimationOrTransition<ElementAnimations>(nsIContent* aContent,
   1.314 +                         nsIAtom* aAnimationProperty,
   1.315 +                         nsCSSProperty aProperty);
   1.316 +
   1.317 +template ElementTransitions*
   1.318 +mozilla::HasAnimationOrTransition<ElementTransitions>(nsIContent* aContent,
   1.319 +                         nsIAtom* aAnimationProperty,
   1.320 +                         nsCSSProperty aProperty);
   1.321 +
   1.322 +
   1.323 +bool
   1.324 +nsLayoutUtils::HasAnimations(nsIContent* aContent,
   1.325 +                             nsCSSProperty aProperty)
   1.326 +{
   1.327 +  if (!aContent->MayHaveAnimations())
   1.328 +    return false;
   1.329 +  return HasAnimationOrTransition<ElementAnimations>
   1.330 +            (aContent, nsGkAtoms::animationsProperty, aProperty) ||
   1.331 +         HasAnimationOrTransition<ElementTransitions>
   1.332 +            (aContent, nsGkAtoms::transitionsProperty, aProperty);
   1.333 +}
   1.334 +
   1.335 +static gfxSize
   1.336 +GetScaleForValue(const nsStyleAnimation::Value& aValue,
   1.337 +                 nsIFrame* aFrame)
   1.338 +{
   1.339 +  if (!aFrame) {
   1.340 +    NS_WARNING("No frame.");
   1.341 +    return gfxSize();
   1.342 +  }
   1.343 +  if (aValue.GetUnit() != nsStyleAnimation::eUnit_Transform) {
   1.344 +    NS_WARNING("Expected a transform.");
   1.345 +    return gfxSize();
   1.346 +  }
   1.347 +
   1.348 +  nsCSSValueSharedList* list = aValue.GetCSSValueSharedListValue();
   1.349 +  MOZ_ASSERT(list->mHead);
   1.350 +
   1.351 +  if (list->mHead->mValue.GetUnit() == eCSSUnit_None) {
   1.352 +    // There is an animation, but no actual transform yet.
   1.353 +    return gfxSize();
   1.354 +  }
   1.355 +
   1.356 +  nsRect frameBounds = aFrame->GetRect();
   1.357 +  bool dontCare;
   1.358 +  gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
   1.359 +                            list->mHead,
   1.360 +                            aFrame->StyleContext(),
   1.361 +                            aFrame->PresContext(), dontCare, frameBounds,
   1.362 +                            aFrame->PresContext()->AppUnitsPerDevPixel());
   1.363 +
   1.364 +  gfxMatrix transform2d;
   1.365 +  bool canDraw2D = transform.CanDraw2D(&transform2d);
   1.366 +  if (!canDraw2D) {
   1.367 +    return gfxSize();
   1.368 +  }
   1.369 +
   1.370 +  return transform2d.ScaleFactors(true);
   1.371 +}
   1.372 +
   1.373 +float
   1.374 +GetSuitableScale(float aMaxScale, float aMinScale)
   1.375 +{
   1.376 +  // If the minimum scale >= 1.0f, use it; if the maximum <= 1.0f, use it;
   1.377 +  // otherwise use 1.0f.
   1.378 +  if (aMinScale >= 1.0f) {
   1.379 +    return aMinScale;
   1.380 +  }
   1.381 +  else if (aMaxScale <= 1.0f) {
   1.382 +    return aMaxScale;
   1.383 +  }
   1.384 +
   1.385 +  return 1.0f;
   1.386 +}
   1.387 +
   1.388 +gfxSize
   1.389 +nsLayoutUtils::ComputeSuitableScaleForAnimation(nsIContent* aContent)
   1.390 +{
   1.391 +  gfxSize maxScale(1.0f, 1.0f);
   1.392 +  gfxSize minScale(1.0f, 1.0f);
   1.393 +
   1.394 +  ElementAnimations* animations = HasAnimationOrTransitionForCompositor<ElementAnimations>
   1.395 +    (aContent, nsGkAtoms::animationsProperty, eCSSProperty_transform);
   1.396 +  if (animations) {
   1.397 +    for (uint32_t animIdx = animations->mAnimations.Length(); animIdx-- != 0; ) {
   1.398 +      mozilla::StyleAnimation& anim = animations->mAnimations[animIdx];
   1.399 +      for (uint32_t propIdx = anim.mProperties.Length(); propIdx-- != 0; ) {
   1.400 +        AnimationProperty& prop = anim.mProperties[propIdx];
   1.401 +        if (prop.mProperty == eCSSProperty_transform) {
   1.402 +          for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
   1.403 +            AnimationPropertySegment& segment = prop.mSegments[segIdx];
   1.404 +            gfxSize from = GetScaleForValue(segment.mFromValue,
   1.405 +                                            aContent->GetPrimaryFrame());
   1.406 +            maxScale.width = std::max<float>(maxScale.width, from.width);
   1.407 +            maxScale.height = std::max<float>(maxScale.height, from.height);
   1.408 +            minScale.width = std::min<float>(minScale.width, from.width);
   1.409 +            minScale.height = std::min<float>(minScale.height, from.height);
   1.410 +            gfxSize to = GetScaleForValue(segment.mToValue,
   1.411 +                                          aContent->GetPrimaryFrame());
   1.412 +            maxScale.width = std::max<float>(maxScale.width, to.width);
   1.413 +            maxScale.height = std::max<float>(maxScale.height, to.height);
   1.414 +            minScale.width = std::min<float>(minScale.width, to.width);
   1.415 +            minScale.height = std::min<float>(minScale.height, to.height);
   1.416 +          }
   1.417 +        }
   1.418 +      }
   1.419 +    }
   1.420 +  }
   1.421 +
   1.422 +  ElementTransitions* transitions = HasAnimationOrTransitionForCompositor<ElementTransitions>
   1.423 +    (aContent, nsGkAtoms::transitionsProperty, eCSSProperty_transform);
   1.424 +  if (transitions) {
   1.425 +    for (uint32_t i = 0, i_end = transitions->mPropertyTransitions.Length();
   1.426 +         i < i_end; ++i){
   1.427 +      ElementPropertyTransition &pt = transitions->mPropertyTransitions[i];
   1.428 +      if (pt.IsRemovedSentinel()) {
   1.429 +        continue;
   1.430 +      }
   1.431 +      MOZ_ASSERT(pt.mProperties.Length() == 1,
   1.432 +        "Should have one animation property for a transition");
   1.433 +      MOZ_ASSERT(pt.mProperties[0].mSegments.Length() == 1,
   1.434 +        "Animation property should have one segment for a transition");
   1.435 +      const AnimationPropertySegment& segment = pt.mProperties[0].mSegments[0];
   1.436 +
   1.437 +      if (pt.mProperties[0].mProperty == eCSSProperty_transform) {
   1.438 +        gfxSize start = GetScaleForValue(segment.mFromValue,
   1.439 +                                         aContent->GetPrimaryFrame());
   1.440 +        maxScale.width = std::max<float>(maxScale.width, start.width);
   1.441 +        maxScale.height = std::max<float>(maxScale.height, start.height);
   1.442 +        minScale.width = std::min<float>(minScale.width, start.width);
   1.443 +        minScale.height = std::min<float>(minScale.height, start.height);
   1.444 +        gfxSize end = GetScaleForValue(segment.mToValue,
   1.445 +                                       aContent->GetPrimaryFrame());
   1.446 +        maxScale.width = std::max<float>(maxScale.width, end.width);
   1.447 +        maxScale.height = std::max<float>(maxScale.height, end.height);
   1.448 +        minScale.width = std::min<float>(minScale.width, end.width);
   1.449 +        minScale.height = std::min<float>(minScale.height, end.height);
   1.450 +      }
   1.451 +    }
   1.452 +  }
   1.453 +
   1.454 +  return gfxSize(GetSuitableScale(maxScale.width, minScale.width),
   1.455 +      GetSuitableScale(maxScale.height, minScale.height));
   1.456 +}
   1.457 +
   1.458 +bool
   1.459 +nsLayoutUtils::AreAsyncAnimationsEnabled()
   1.460 +{
   1.461 +  static bool sAreAsyncAnimationsEnabled;
   1.462 +  static bool sAsyncPrefCached = false;
   1.463 +
   1.464 +  if (!sAsyncPrefCached) {
   1.465 +    sAsyncPrefCached = true;
   1.466 +    Preferences::AddBoolVarCache(&sAreAsyncAnimationsEnabled,
   1.467 +                                 "layers.offmainthreadcomposition.async-animations");
   1.468 +  }
   1.469 +
   1.470 +  return sAreAsyncAnimationsEnabled &&
   1.471 +    gfxPlatform::OffMainThreadCompositingEnabled();
   1.472 +}
   1.473 +
   1.474 +bool
   1.475 +nsLayoutUtils::IsAnimationLoggingEnabled()
   1.476 +{
   1.477 +  static bool sShouldLog;
   1.478 +  static bool sShouldLogPrefCached;
   1.479 +
   1.480 +  if (!sShouldLogPrefCached) {
   1.481 +    sShouldLogPrefCached = true;
   1.482 +    Preferences::AddBoolVarCache(&sShouldLog,
   1.483 +                                 "layers.offmainthreadcomposition.log-animations");
   1.484 +  }
   1.485 +
   1.486 +  return sShouldLog;
   1.487 +}
   1.488 +
   1.489 +bool
   1.490 +nsLayoutUtils::UseBackgroundNearestFiltering()
   1.491 +{
   1.492 +  static bool sUseBackgroundNearestFilteringEnabled;
   1.493 +  static bool sUseBackgroundNearestFilteringPrefInitialised = false;
   1.494 +
   1.495 +  if (!sUseBackgroundNearestFilteringPrefInitialised) {
   1.496 +    sUseBackgroundNearestFilteringPrefInitialised = true;
   1.497 +    sUseBackgroundNearestFilteringEnabled =
   1.498 +      Preferences::GetBool("gfx.filter.nearest.force-enabled", false);
   1.499 +  }
   1.500 +
   1.501 +  return sUseBackgroundNearestFilteringEnabled;
   1.502 +}
   1.503 +
   1.504 +bool
   1.505 +nsLayoutUtils::GPUImageScalingEnabled()
   1.506 +{
   1.507 +  static bool sGPUImageScalingEnabled;
   1.508 +  static bool sGPUImageScalingPrefInitialised = false;
   1.509 +
   1.510 +  if (!sGPUImageScalingPrefInitialised) {
   1.511 +    sGPUImageScalingPrefInitialised = true;
   1.512 +    sGPUImageScalingEnabled =
   1.513 +      Preferences::GetBool("layout.gpu-image-scaling.enabled", false);
   1.514 +  }
   1.515 +
   1.516 +  return sGPUImageScalingEnabled;
   1.517 +}
   1.518 +
   1.519 +bool
   1.520 +nsLayoutUtils::AnimatedImageLayersEnabled()
   1.521 +{
   1.522 +  static bool sAnimatedImageLayersEnabled;
   1.523 +  static bool sAnimatedImageLayersPrefCached = false;
   1.524 +
   1.525 +  if (!sAnimatedImageLayersPrefCached) {
   1.526 +    sAnimatedImageLayersPrefCached = true;
   1.527 +    Preferences::AddBoolVarCache(&sAnimatedImageLayersEnabled,
   1.528 +                                 "layout.animated-image-layers.enabled",
   1.529 +                                 false);
   1.530 +  }
   1.531 +
   1.532 +  return sAnimatedImageLayersEnabled;
   1.533 +}
   1.534 +
   1.535 +bool
   1.536 +nsLayoutUtils::CSSFiltersEnabled()
   1.537 +{
   1.538 +  static bool sCSSFiltersEnabled;
   1.539 +  static bool sCSSFiltersPrefCached = false;
   1.540 +
   1.541 +  if (!sCSSFiltersPrefCached) {
   1.542 +    sCSSFiltersPrefCached = true;
   1.543 +    Preferences::AddBoolVarCache(&sCSSFiltersEnabled,
   1.544 +                                 "layout.css.filters.enabled",
   1.545 +                                 false);
   1.546 +  }
   1.547 +
   1.548 +  return sCSSFiltersEnabled;
   1.549 +}
   1.550 +
   1.551 +bool
   1.552 +nsLayoutUtils::UnsetValueEnabled()
   1.553 +{
   1.554 +  static bool sUnsetValueEnabled;
   1.555 +  static bool sUnsetValuePrefCached = false;
   1.556 +
   1.557 +  if (!sUnsetValuePrefCached) {
   1.558 +    sUnsetValuePrefCached = true;
   1.559 +    Preferences::AddBoolVarCache(&sUnsetValueEnabled,
   1.560 +                                 "layout.css.unset-value.enabled",
   1.561 +                                 false);
   1.562 +  }
   1.563 +
   1.564 +  return sUnsetValueEnabled;
   1.565 +}
   1.566 +
   1.567 +bool
   1.568 +nsLayoutUtils::IsTextAlignTrueValueEnabled()
   1.569 +{
   1.570 +  static bool sTextAlignTrueValueEnabled;
   1.571 +  static bool sTextAlignTrueValueEnabledPrefCached = false;
   1.572 +
   1.573 +  if (!sTextAlignTrueValueEnabledPrefCached) {
   1.574 +    sTextAlignTrueValueEnabledPrefCached = true;
   1.575 +    Preferences::AddBoolVarCache(&sTextAlignTrueValueEnabled,
   1.576 +                                 TEXT_ALIGN_TRUE_ENABLED_PREF_NAME,
   1.577 +                                 false);
   1.578 +  }
   1.579 +
   1.580 +  return sTextAlignTrueValueEnabled;
   1.581 +}
   1.582 +
   1.583 +void
   1.584 +nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
   1.585 +                                  nsOverflowAreas& aOverflowAreas,
   1.586 +                                  FrameChildListIDs aSkipChildLists)
   1.587 +{
   1.588 +  // Iterate over all children except pop-ups.
   1.589 +  FrameChildListIDs skip = aSkipChildLists |
   1.590 +      nsIFrame::kSelectPopupList | nsIFrame::kPopupList;
   1.591 +  for (nsIFrame::ChildListIterator childLists(aFrame);
   1.592 +       !childLists.IsDone(); childLists.Next()) {
   1.593 +    if (skip.Contains(childLists.CurrentID())) {
   1.594 +      continue;
   1.595 +    }
   1.596 +
   1.597 +    nsFrameList children = childLists.CurrentList();
   1.598 +    for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
   1.599 +      nsIFrame* child = e.get();
   1.600 +      nsOverflowAreas childOverflow =
   1.601 +        child->GetOverflowAreas() + child->GetPosition();
   1.602 +      aOverflowAreas.UnionWith(childOverflow);
   1.603 +    }
   1.604 +  }
   1.605 +}
   1.606 +
   1.607 +static void DestroyViewID(void* aObject, nsIAtom* aPropertyName,
   1.608 +                          void* aPropertyValue, void* aData)
   1.609 +{
   1.610 +  ViewID* id = static_cast<ViewID*>(aPropertyValue);
   1.611 +  GetContentMap().Remove(*id);
   1.612 +  delete id;
   1.613 +}
   1.614 +
   1.615 +/**
   1.616 + * A namespace class for static layout utilities.
   1.617 + */
   1.618 +
   1.619 +bool
   1.620 +nsLayoutUtils::FindIDFor(const nsIContent* aContent, ViewID* aOutViewId)
   1.621 +{
   1.622 +  void* scrollIdProperty = aContent->GetProperty(nsGkAtoms::RemoteId);
   1.623 +  if (scrollIdProperty) {
   1.624 +    *aOutViewId = *static_cast<ViewID*>(scrollIdProperty);
   1.625 +    return true;
   1.626 +  }
   1.627 +  return false;
   1.628 +}
   1.629 +
   1.630 +ViewID
   1.631 +nsLayoutUtils::FindOrCreateIDFor(nsIContent* aContent)
   1.632 +{
   1.633 +  ViewID scrollId;
   1.634 +
   1.635 +  if (!FindIDFor(aContent, &scrollId)) {
   1.636 +    scrollId = sScrollIdCounter++;
   1.637 +    aContent->SetProperty(nsGkAtoms::RemoteId, new ViewID(scrollId),
   1.638 +                          DestroyViewID);
   1.639 +    GetContentMap().Put(scrollId, aContent);
   1.640 +  }
   1.641 +
   1.642 +  return scrollId;
   1.643 +}
   1.644 +
   1.645 +nsIContent*
   1.646 +nsLayoutUtils::FindContentFor(ViewID aId)
   1.647 +{
   1.648 +  NS_ABORT_IF_FALSE(aId != FrameMetrics::NULL_SCROLL_ID,
   1.649 +                    "Cannot find a content element in map for null IDs.");
   1.650 +  nsIContent* content;
   1.651 +  bool exists = GetContentMap().Get(aId, &content);
   1.652 +
   1.653 +  if (exists) {
   1.654 +    return content;
   1.655 +  } else {
   1.656 +    return nullptr;
   1.657 +  }
   1.658 +}
   1.659 +
   1.660 +nsIScrollableFrame*
   1.661 +nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
   1.662 +{
   1.663 +  nsIContent* content = FindContentFor(aId);
   1.664 +  if (!content) {
   1.665 +    return nullptr;
   1.666 +  }
   1.667 +
   1.668 +  nsIFrame* scrolledFrame = content->GetPrimaryFrame();
   1.669 +  if (scrolledFrame && content->OwnerDoc()->GetRootElement() == content) {
   1.670 +    // The content is the root element of a subdocument, so return the root scrollable
   1.671 +    // for the subdocument.
   1.672 +    scrolledFrame = scrolledFrame->PresContext()->PresShell()->GetRootScrollFrame();
   1.673 +  }
   1.674 +  return scrolledFrame ? scrolledFrame->GetScrollTargetFrame() : nullptr;
   1.675 +}
   1.676 +
   1.677 +bool
   1.678 +nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
   1.679 +{
   1.680 +  DisplayPortPropertyData* rectData =
   1.681 +    static_cast<DisplayPortPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPort));
   1.682 +  DisplayPortMarginsPropertyData* marginsData =
   1.683 +    static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
   1.684 +  if (!rectData && !marginsData) {
   1.685 +    return false;
   1.686 +  }
   1.687 +
   1.688 +  if (aResult) {
   1.689 +    if (rectData && marginsData) {
   1.690 +      // choose margins if equal priority
   1.691 +      if (rectData->mPriority > marginsData->mPriority) {
   1.692 +        marginsData = nullptr;
   1.693 +      } else {
   1.694 +        rectData = nullptr;
   1.695 +      }
   1.696 +    }
   1.697 +
   1.698 +    if (rectData) {
   1.699 +      *aResult = rectData->mRect;
   1.700 +    } else {
   1.701 +      nsRect* baseData =
   1.702 +        static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase));
   1.703 +      nsRect base;
   1.704 +      if (baseData) {
   1.705 +        base = *baseData;
   1.706 +      }
   1.707 +
   1.708 +      nsIFrame* frame = aContent->GetPrimaryFrame();
   1.709 +      if (frame) {
   1.710 +        bool isRoot = false;
   1.711 +        if (aContent->OwnerDoc()->GetRootElement() == aContent) {
   1.712 +          // We want the scroll frame, the root scroll frame differs from all
   1.713 +          // others in that the primary frame is not the scroll frame.
   1.714 +          frame = frame->PresContext()->PresShell()->GetRootScrollFrame();
   1.715 +          isRoot = true;
   1.716 +        }
   1.717 +
   1.718 +        // first convert the base rect to layer pixels
   1.719 +        nsPresContext* presContext = frame->PresContext();
   1.720 +        int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
   1.721 +        gfxSize res = presContext->PresShell()->GetCumulativeResolution();
   1.722 +        gfxSize parentRes = res;
   1.723 +        if (isRoot) {
   1.724 +          // the base rect for root scroll frames is specified in the parent document
   1.725 +          // coordinate space, so it doesn't include the local resolution.
   1.726 +          gfxSize localRes = presContext->PresShell()->GetResolution();
   1.727 +          parentRes.width /= localRes.width;
   1.728 +          parentRes.height /= localRes.height;
   1.729 +        }
   1.730 +        LayerRect rect;
   1.731 +        rect.x = parentRes.width * NSAppUnitsToFloatPixels(base.x, auPerDevPixel);
   1.732 +        rect.y = parentRes.height * NSAppUnitsToFloatPixels(base.y, auPerDevPixel);
   1.733 +        rect.width =
   1.734 +          parentRes.width * NSAppUnitsToFloatPixels(base.width, auPerDevPixel);
   1.735 +        rect.height =
   1.736 +          parentRes.height * NSAppUnitsToFloatPixels(base.height, auPerDevPixel);
   1.737 +
   1.738 +        rect.Inflate(marginsData->mMargins);
   1.739 +
   1.740 +        nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame();
   1.741 +        nsPoint scrollPos(
   1.742 +          scrollableFrame ? scrollableFrame->GetScrollPosition() : nsPoint(0,0));
   1.743 +        if (marginsData->mAlignmentX > 0 || marginsData->mAlignmentY > 0) {
   1.744 +          // Avoid division by zero.
   1.745 +          if (marginsData->mAlignmentX == 0) {
   1.746 +            marginsData->mAlignmentX = 1;
   1.747 +          }
   1.748 +          if (marginsData->mAlignmentY == 0) {
   1.749 +            marginsData->mAlignmentY = 1;
   1.750 +          }
   1.751 +
   1.752 +          LayerPoint scrollPosLayer(
   1.753 +            res.width * NSAppUnitsToFloatPixels(scrollPos.x, auPerDevPixel),
   1.754 +            res.height * NSAppUnitsToFloatPixels(scrollPos.y, auPerDevPixel));
   1.755 +          rect += scrollPosLayer;
   1.756 +
   1.757 +          // Inflate the rectangle by 1 so that we always push to the next tile
   1.758 +          // boundary. This is desirable to stop from having a rectangle with a
   1.759 +          // moving origin occasionally being smaller when it coincidentally lines
   1.760 +          // up to tile boundaries.
   1.761 +          rect.Inflate(1);
   1.762 +
   1.763 +          float left =
   1.764 +            marginsData->mAlignmentX * floor(rect.x / marginsData->mAlignmentX);
   1.765 +          float top =
   1.766 +            marginsData->mAlignmentY * floor(rect.y / marginsData->mAlignmentY);
   1.767 +          float right =
   1.768 +            marginsData->mAlignmentX * ceil(rect.XMost() / marginsData->mAlignmentX);
   1.769 +          float bottom =
   1.770 +            marginsData->mAlignmentY * ceil(rect.YMost() / marginsData->mAlignmentY);
   1.771 +          rect = LayerRect(left, top, right - left, bottom - top);
   1.772 +          rect -= scrollPosLayer;
   1.773 +        }
   1.774 +
   1.775 +        nsRect result;
   1.776 +        result.x = NSFloatPixelsToAppUnits(rect.x / res.width, auPerDevPixel);
   1.777 +        result.y = NSFloatPixelsToAppUnits(rect.y / res.height, auPerDevPixel);
   1.778 +        result.width =
   1.779 +          NSFloatPixelsToAppUnits(rect.width / res.width, auPerDevPixel);
   1.780 +        result.height =
   1.781 +          NSFloatPixelsToAppUnits(rect.height / res.height, auPerDevPixel);
   1.782 +
   1.783 +        // Finally, clamp the display port to the expanded scrollable rect.
   1.784 +        nsRect expandedScrollableRect = CalculateExpandedScrollableRect(frame);
   1.785 +        result = expandedScrollableRect.Intersect(result + scrollPos) - scrollPos;
   1.786 +
   1.787 +        *aResult = result;
   1.788 +      }
   1.789 +    }
   1.790 +  }
   1.791 +
   1.792 +  return true;
   1.793 +}
   1.794 +
   1.795 +void
   1.796 +nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
   1.797 +                                     nsIPresShell* aPresShell,
   1.798 +                                     const LayerMargin& aMargins,
   1.799 +                                     uint32_t aAlignmentX,
   1.800 +                                     uint32_t aAlignmentY,
   1.801 +                                     uint32_t aPriority,
   1.802 +                                     RepaintMode aRepaintMode)
   1.803 +{
   1.804 +  DisplayPortMarginsPropertyData* currentData =
   1.805 +    static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
   1.806 +  if (currentData && currentData->mPriority > aPriority) {
   1.807 +    return;
   1.808 +  }
   1.809 +
   1.810 +  aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
   1.811 +                        new DisplayPortMarginsPropertyData(
   1.812 +                            aMargins, aAlignmentX, aAlignmentY, aPriority),
   1.813 +                        nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
   1.814 +
   1.815 +  nsIFrame* rootScrollFrame = aPresShell->GetRootScrollFrame();
   1.816 +  if (rootScrollFrame && aContent == rootScrollFrame->GetContent()) {
   1.817 +    // We are setting a root displayport for a document.
   1.818 +    // The pres shell needs a special flag set.
   1.819 +    aPresShell->SetIgnoreViewportScrolling(true);
   1.820 +  }
   1.821 +
   1.822 +  if (aRepaintMode == RepaintMode::Repaint) {
   1.823 +    nsIFrame* rootFrame = aPresShell->FrameManager()->GetRootFrame();
   1.824 +    if (rootFrame) {
   1.825 +      rootFrame->SchedulePaint();
   1.826 +    }
   1.827 +  }
   1.828 +}
   1.829 +
   1.830 +void
   1.831 +nsLayoutUtils::SetDisplayPortBase(nsIContent* aContent, const nsRect& aBase)
   1.832 +{
   1.833 +  aContent->SetProperty(nsGkAtoms::DisplayPortBase, new nsRect(aBase),
   1.834 +                        nsINode::DeleteProperty<nsRect>);
   1.835 +}
   1.836 +
   1.837 +void
   1.838 +nsLayoutUtils::SetDisplayPortBaseIfNotSet(nsIContent* aContent, const nsRect& aBase)
   1.839 +{
   1.840 +  if (!aContent->GetProperty(nsGkAtoms::DisplayPortBase)) {
   1.841 +    SetDisplayPortBase(aContent, aBase);
   1.842 +  }
   1.843 +}
   1.844 +
   1.845 +bool
   1.846 +nsLayoutUtils::GetCriticalDisplayPort(nsIContent* aContent, nsRect* aResult)
   1.847 +{
   1.848 +  void* property = aContent->GetProperty(nsGkAtoms::CriticalDisplayPort);
   1.849 +  if (!property) {
   1.850 +    return false;
   1.851 +  }
   1.852 +
   1.853 +  if (aResult) {
   1.854 +    *aResult = *static_cast<nsRect*>(property);
   1.855 +  }
   1.856 +  return true;
   1.857 +}
   1.858 +
   1.859 +nsIFrame*
   1.860 +nsLayoutUtils::LastContinuationWithChild(nsIFrame* aFrame)
   1.861 +{
   1.862 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
   1.863 +  aFrame = aFrame->LastContinuation();
   1.864 +  while (!aFrame->GetFirstPrincipalChild() &&
   1.865 +         aFrame->GetPrevContinuation()) {
   1.866 +    aFrame = aFrame->GetPrevContinuation();
   1.867 +  }
   1.868 +  return aFrame;
   1.869 +}
   1.870 +
   1.871 +/**
   1.872 + * GetFirstChildFrame returns the first "real" child frame of a
   1.873 + * given frame.  It will descend down into pseudo-frames (unless the
   1.874 + * pseudo-frame is the :before generated frame).
   1.875 + * @param aFrame the frame
   1.876 + * @param aFrame the frame's content node
   1.877 + */
   1.878 +static nsIFrame*
   1.879 +GetFirstChildFrame(nsIFrame*       aFrame,
   1.880 +                   nsIContent*     aContent)
   1.881 +{
   1.882 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
   1.883 +
   1.884 +  // Get the first child frame
   1.885 +  nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
   1.886 +
   1.887 +  // If the child frame is a pseudo-frame, then return its first child.
   1.888 +  // Note that the frame we create for the generated content is also a
   1.889 +  // pseudo-frame and so don't drill down in that case
   1.890 +  if (childFrame &&
   1.891 +      childFrame->IsPseudoFrame(aContent) &&
   1.892 +      !childFrame->IsGeneratedContentFrame()) {
   1.893 +    return GetFirstChildFrame(childFrame, aContent);
   1.894 +  }
   1.895 +
   1.896 +  return childFrame;
   1.897 +}
   1.898 +
   1.899 +/**
   1.900 + * GetLastChildFrame returns the last "real" child frame of a
   1.901 + * given frame.  It will descend down into pseudo-frames (unless the
   1.902 + * pseudo-frame is the :after generated frame).
   1.903 + * @param aFrame the frame
   1.904 + * @param aFrame the frame's content node
   1.905 + */
   1.906 +static nsIFrame*
   1.907 +GetLastChildFrame(nsIFrame*       aFrame,
   1.908 +                  nsIContent*     aContent)
   1.909 +{
   1.910 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
   1.911 +
   1.912 +  // Get the last continuation frame that's a parent
   1.913 +  nsIFrame* lastParentContinuation =
   1.914 +    nsLayoutUtils::LastContinuationWithChild(aFrame);
   1.915 +  nsIFrame* lastChildFrame =
   1.916 +    lastParentContinuation->GetLastChild(nsIFrame::kPrincipalList);
   1.917 +  if (lastChildFrame) {
   1.918 +    // Get the frame's first continuation. This matters in case the frame has
   1.919 +    // been continued across multiple lines or split by BiDi resolution.
   1.920 +    lastChildFrame = lastChildFrame->FirstContinuation();
   1.921 +
   1.922 +    // If the last child frame is a pseudo-frame, then return its last child.
   1.923 +    // Note that the frame we create for the generated content is also a
   1.924 +    // pseudo-frame and so don't drill down in that case
   1.925 +    if (lastChildFrame &&
   1.926 +        lastChildFrame->IsPseudoFrame(aContent) &&
   1.927 +        !lastChildFrame->IsGeneratedContentFrame()) {
   1.928 +      return GetLastChildFrame(lastChildFrame, aContent);
   1.929 +    }
   1.930 +
   1.931 +    return lastChildFrame;
   1.932 +  }
   1.933 +
   1.934 +  return nullptr;
   1.935 +}
   1.936 +
   1.937 +//static
   1.938 +FrameChildListID
   1.939 +nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
   1.940 +{
   1.941 +  nsIFrame::ChildListID id = nsIFrame::kPrincipalList;
   1.942 +
   1.943 +  if (aChildFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
   1.944 +    nsIFrame* pif = aChildFrame->GetPrevInFlow();
   1.945 +    if (pif->GetParent() == aChildFrame->GetParent()) {
   1.946 +      id = nsIFrame::kExcessOverflowContainersList;
   1.947 +    }
   1.948 +    else {
   1.949 +      id = nsIFrame::kOverflowContainersList;
   1.950 +    }
   1.951 +  }
   1.952 +  // See if the frame is moved out of the flow
   1.953 +  else if (aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
   1.954 +    // Look at the style information to tell
   1.955 +    const nsStyleDisplay* disp = aChildFrame->StyleDisplay();
   1.956 +
   1.957 +    if (NS_STYLE_POSITION_ABSOLUTE == disp->mPosition) {
   1.958 +      id = nsIFrame::kAbsoluteList;
   1.959 +    } else if (NS_STYLE_POSITION_FIXED == disp->mPosition) {
   1.960 +      if (nsLayoutUtils::IsReallyFixedPos(aChildFrame)) {
   1.961 +        id = nsIFrame::kFixedList;
   1.962 +      } else {
   1.963 +        id = nsIFrame::kAbsoluteList;
   1.964 +      }
   1.965 +#ifdef MOZ_XUL
   1.966 +    } else if (NS_STYLE_DISPLAY_POPUP == disp->mDisplay) {
   1.967 +      // Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
   1.968 +#ifdef DEBUG
   1.969 +      nsIFrame* parent = aChildFrame->GetParent();
   1.970 +      NS_ASSERTION(parent && parent->GetType() == nsGkAtoms::popupSetFrame,
   1.971 +                   "Unexpected parent");
   1.972 +#endif // DEBUG
   1.973 +
   1.974 +      id = nsIFrame::kPopupList;
   1.975 +#endif // MOZ_XUL
   1.976 +    } else {
   1.977 +      NS_ASSERTION(aChildFrame->IsFloating(), "not a floated frame");
   1.978 +      id = nsIFrame::kFloatList;
   1.979 +    }
   1.980 +
   1.981 +  } else {
   1.982 +    nsIAtom* childType = aChildFrame->GetType();
   1.983 +    if (nsGkAtoms::menuPopupFrame == childType) {
   1.984 +      nsIFrame* parent = aChildFrame->GetParent();
   1.985 +      MOZ_ASSERT(parent, "nsMenuPopupFrame can't be the root frame");
   1.986 +      if (parent) {
   1.987 +        if (parent->GetType() == nsGkAtoms::popupSetFrame) {
   1.988 +          id = nsIFrame::kPopupList;
   1.989 +        } else {
   1.990 +          nsIFrame* firstPopup = parent->GetFirstChild(nsIFrame::kPopupList);
   1.991 +          MOZ_ASSERT(!firstPopup || !firstPopup->GetNextSibling(),
   1.992 +                     "We assume popupList only has one child, but it has more.");
   1.993 +          id = firstPopup == aChildFrame
   1.994 +                 ? nsIFrame::kPopupList
   1.995 +                 : nsIFrame::kPrincipalList;
   1.996 +        }
   1.997 +      } else {
   1.998 +        id = nsIFrame::kPrincipalList;
   1.999 +      }
  1.1000 +    } else if (nsGkAtoms::tableColGroupFrame == childType) {
  1.1001 +      id = nsIFrame::kColGroupList;
  1.1002 +    } else if (nsGkAtoms::tableCaptionFrame == childType) {
  1.1003 +      id = nsIFrame::kCaptionList;
  1.1004 +    } else {
  1.1005 +      id = nsIFrame::kPrincipalList;
  1.1006 +    }
  1.1007 +  }
  1.1008 +
  1.1009 +#ifdef DEBUG
  1.1010 +  // Verify that the frame is actually in that child list or in the
  1.1011 +  // corresponding overflow list.
  1.1012 +  nsIFrame* parent = aChildFrame->GetParent();
  1.1013 +  bool found = parent->GetChildList(id).ContainsFrame(aChildFrame);
  1.1014 +  if (!found) {
  1.1015 +    if (!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
  1.1016 +      found = parent->GetChildList(nsIFrame::kOverflowList)
  1.1017 +                .ContainsFrame(aChildFrame);
  1.1018 +    }
  1.1019 +    else if (aChildFrame->IsFloating()) {
  1.1020 +      found = parent->GetChildList(nsIFrame::kOverflowOutOfFlowList)
  1.1021 +                .ContainsFrame(aChildFrame);
  1.1022 +      if (!found) {
  1.1023 +        found = parent->GetChildList(nsIFrame::kPushedFloatsList)
  1.1024 +                  .ContainsFrame(aChildFrame);
  1.1025 +      }
  1.1026 +    }
  1.1027 +    // else it's positioned and should have been on the 'id' child list.
  1.1028 +    NS_POSTCONDITION(found, "not in child list");
  1.1029 +  }
  1.1030 +#endif
  1.1031 +
  1.1032 +  return id;
  1.1033 +}
  1.1034 +
  1.1035 +// static
  1.1036 +nsIFrame*
  1.1037 +nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
  1.1038 +{
  1.1039 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.1040 +  NS_ASSERTION(!aFrame->GetPrevContinuation(),
  1.1041 +               "aFrame must be first continuation");
  1.1042 +
  1.1043 +  nsIFrame* cif = aFrame->GetContentInsertionFrame();
  1.1044 +  nsIFrame* firstFrame = GetFirstChildFrame(cif, aFrame->GetContent());
  1.1045 +
  1.1046 +  if (firstFrame && IsGeneratedContentFor(nullptr, firstFrame,
  1.1047 +                                          nsCSSPseudoElements::before)) {
  1.1048 +    return firstFrame;
  1.1049 +  }
  1.1050 +
  1.1051 +  return nullptr;
  1.1052 +}
  1.1053 +
  1.1054 +// static
  1.1055 +nsIFrame*
  1.1056 +nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
  1.1057 +{
  1.1058 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.1059 +
  1.1060 +  nsIFrame* cif = aFrame->GetContentInsertionFrame();
  1.1061 +  nsIFrame* lastFrame = GetLastChildFrame(cif, aFrame->GetContent());
  1.1062 +
  1.1063 +  if (lastFrame && IsGeneratedContentFor(nullptr, lastFrame,
  1.1064 +                                         nsCSSPseudoElements::after)) {
  1.1065 +    return lastFrame;
  1.1066 +  }
  1.1067 +
  1.1068 +  return nullptr;
  1.1069 +}
  1.1070 +
  1.1071 +// static
  1.1072 +nsIFrame*
  1.1073 +nsLayoutUtils::GetClosestFrameOfType(nsIFrame* aFrame, nsIAtom* aFrameType)
  1.1074 +{
  1.1075 +  for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
  1.1076 +    if (frame->GetType() == aFrameType) {
  1.1077 +      return frame;
  1.1078 +    }
  1.1079 +  }
  1.1080 +  return nullptr;
  1.1081 +}
  1.1082 +
  1.1083 +// static
  1.1084 +nsIFrame*
  1.1085 +nsLayoutUtils::GetStyleFrame(nsIFrame* aFrame)
  1.1086 +{
  1.1087 +  if (aFrame->GetType() == nsGkAtoms::tableOuterFrame) {
  1.1088 +    nsIFrame* inner = aFrame->GetFirstPrincipalChild();
  1.1089 +    NS_ASSERTION(inner, "Outer table must have an inner");
  1.1090 +    return inner;
  1.1091 +  }
  1.1092 +
  1.1093 +  return aFrame;
  1.1094 +}
  1.1095 +
  1.1096 +nsIFrame*
  1.1097 +nsLayoutUtils::GetStyleFrame(const nsIContent* aContent)
  1.1098 +{
  1.1099 +  nsIFrame *frame = aContent->GetPrimaryFrame();
  1.1100 +  if (!frame) {
  1.1101 +    return nullptr;
  1.1102 +  }
  1.1103 +
  1.1104 +  return nsLayoutUtils::GetStyleFrame(frame);
  1.1105 +}
  1.1106 +
  1.1107 +nsIFrame*
  1.1108 +nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
  1.1109 +  NS_ASSERTION(nsGkAtoms::placeholderFrame == aFrame->GetType(),
  1.1110 +               "Must have a placeholder here");
  1.1111 +  if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
  1.1112 +    nsIFrame *outOfFlowFrame =
  1.1113 +      nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
  1.1114 +    NS_ASSERTION(outOfFlowFrame->IsFloating(),
  1.1115 +                 "How did that happen?");
  1.1116 +    return outOfFlowFrame;
  1.1117 +  }
  1.1118 +
  1.1119 +  return nullptr;
  1.1120 +}
  1.1121 +
  1.1122 +// static
  1.1123 +bool
  1.1124 +nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
  1.1125 +                                     nsIFrame* aFrame,
  1.1126 +                                     nsIAtom* aPseudoElement)
  1.1127 +{
  1.1128 +  NS_PRECONDITION(aFrame, "Must have a frame");
  1.1129 +  NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
  1.1130 +
  1.1131 +  if (!aFrame->IsGeneratedContentFrame()) {
  1.1132 +    return false;
  1.1133 +  }
  1.1134 +  nsIFrame* parent = aFrame->GetParent();
  1.1135 +  NS_ASSERTION(parent, "Generated content can't be root frame");
  1.1136 +  if (parent->IsGeneratedContentFrame()) {
  1.1137 +    // Not the root of the generated content
  1.1138 +    return false;
  1.1139 +  }
  1.1140 +
  1.1141 +  if (aContent && parent->GetContent() != aContent) {
  1.1142 +    return false;
  1.1143 +  }
  1.1144 +
  1.1145 +  return (aFrame->GetContent()->Tag() == nsGkAtoms::mozgeneratedcontentbefore) ==
  1.1146 +    (aPseudoElement == nsCSSPseudoElements::before);
  1.1147 +}
  1.1148 +
  1.1149 +// static
  1.1150 +nsIFrame*
  1.1151 +nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
  1.1152 +                                      nsPoint* aExtraOffset)
  1.1153 +{
  1.1154 +  nsIFrame* p = aFrame->GetParent();
  1.1155 +  if (p)
  1.1156 +    return p;
  1.1157 +
  1.1158 +  nsView* v = aFrame->GetView();
  1.1159 +  if (!v)
  1.1160 +    return nullptr;
  1.1161 +  v = v->GetParent(); // anonymous inner view
  1.1162 +  if (!v)
  1.1163 +    return nullptr;
  1.1164 +  if (aExtraOffset) {
  1.1165 +    *aExtraOffset += v->GetPosition();
  1.1166 +  }
  1.1167 +  v = v->GetParent(); // subdocumentframe's view
  1.1168 +  return v ? v->GetFrame() : nullptr;
  1.1169 +}
  1.1170 +
  1.1171 +// static
  1.1172 +bool
  1.1173 +nsLayoutUtils::IsProperAncestorFrameCrossDoc(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
  1.1174 +                                             nsIFrame* aCommonAncestor)
  1.1175 +{
  1.1176 +  if (aFrame == aAncestorFrame)
  1.1177 +    return false;
  1.1178 +  return IsAncestorFrameCrossDoc(aAncestorFrame, aFrame, aCommonAncestor);
  1.1179 +}
  1.1180 +
  1.1181 +// static
  1.1182 +bool
  1.1183 +nsLayoutUtils::IsAncestorFrameCrossDoc(const nsIFrame* aAncestorFrame, const nsIFrame* aFrame,
  1.1184 +                                       const nsIFrame* aCommonAncestor)
  1.1185 +{
  1.1186 +  for (const nsIFrame* f = aFrame; f != aCommonAncestor;
  1.1187 +       f = GetCrossDocParentFrame(f)) {
  1.1188 +    if (f == aAncestorFrame)
  1.1189 +      return true;
  1.1190 +  }
  1.1191 +  return aCommonAncestor == aAncestorFrame;
  1.1192 +}
  1.1193 +
  1.1194 +// static
  1.1195 +bool
  1.1196 +nsLayoutUtils::IsProperAncestorFrame(nsIFrame* aAncestorFrame, nsIFrame* aFrame,
  1.1197 +                                     nsIFrame* aCommonAncestor)
  1.1198 +{
  1.1199 +  if (aFrame == aAncestorFrame)
  1.1200 +    return false;
  1.1201 +  for (nsIFrame* f = aFrame; f != aCommonAncestor; f = f->GetParent()) {
  1.1202 +    if (f == aAncestorFrame)
  1.1203 +      return true;
  1.1204 +  }
  1.1205 +  return aCommonAncestor == aAncestorFrame;
  1.1206 +}
  1.1207 +
  1.1208 +// static
  1.1209 +int32_t
  1.1210 +nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
  1.1211 +                                     nsIContent* aContent2,
  1.1212 +                                     int32_t aIf1Ancestor,
  1.1213 +                                     int32_t aIf2Ancestor,
  1.1214 +                                     const nsIContent* aCommonAncestor)
  1.1215 +{
  1.1216 +  NS_PRECONDITION(aContent1, "aContent1 must not be null");
  1.1217 +  NS_PRECONDITION(aContent2, "aContent2 must not be null");
  1.1218 +
  1.1219 +  nsAutoTArray<nsINode*, 32> content1Ancestors;
  1.1220 +  nsINode* c1;
  1.1221 +  for (c1 = aContent1; c1 && c1 != aCommonAncestor; c1 = c1->GetParentNode()) {
  1.1222 +    content1Ancestors.AppendElement(c1);
  1.1223 +  }
  1.1224 +  if (!c1 && aCommonAncestor) {
  1.1225 +    // So, it turns out aCommonAncestor was not an ancestor of c1. Oops.
  1.1226 +    // Never mind. We can continue as if aCommonAncestor was null.
  1.1227 +    aCommonAncestor = nullptr;
  1.1228 +  }
  1.1229 +
  1.1230 +  nsAutoTArray<nsINode*, 32> content2Ancestors;
  1.1231 +  nsINode* c2;
  1.1232 +  for (c2 = aContent2; c2 && c2 != aCommonAncestor; c2 = c2->GetParentNode()) {
  1.1233 +    content2Ancestors.AppendElement(c2);
  1.1234 +  }
  1.1235 +  if (!c2 && aCommonAncestor) {
  1.1236 +    // So, it turns out aCommonAncestor was not an ancestor of c2.
  1.1237 +    // We need to retry with no common ancestor hint.
  1.1238 +    return DoCompareTreePosition(aContent1, aContent2,
  1.1239 +                                 aIf1Ancestor, aIf2Ancestor, nullptr);
  1.1240 +  }
  1.1241 +
  1.1242 +  int last1 = content1Ancestors.Length() - 1;
  1.1243 +  int last2 = content2Ancestors.Length() - 1;
  1.1244 +  nsINode* content1Ancestor = nullptr;
  1.1245 +  nsINode* content2Ancestor = nullptr;
  1.1246 +  while (last1 >= 0 && last2 >= 0
  1.1247 +         && ((content1Ancestor = content1Ancestors.ElementAt(last1)) ==
  1.1248 +             (content2Ancestor = content2Ancestors.ElementAt(last2)))) {
  1.1249 +    last1--;
  1.1250 +    last2--;
  1.1251 +  }
  1.1252 +
  1.1253 +  if (last1 < 0) {
  1.1254 +    if (last2 < 0) {
  1.1255 +      NS_ASSERTION(aContent1 == aContent2, "internal error?");
  1.1256 +      return 0;
  1.1257 +    }
  1.1258 +    // aContent1 is an ancestor of aContent2
  1.1259 +    return aIf1Ancestor;
  1.1260 +  }
  1.1261 +
  1.1262 +  if (last2 < 0) {
  1.1263 +    // aContent2 is an ancestor of aContent1
  1.1264 +    return aIf2Ancestor;
  1.1265 +  }
  1.1266 +
  1.1267 +  // content1Ancestor != content2Ancestor, so they must be siblings with the same parent
  1.1268 +  nsINode* parent = content1Ancestor->GetParentNode();
  1.1269 +#ifdef DEBUG
  1.1270 +  // TODO: remove the uglyness, see bug 598468.
  1.1271 +  NS_ASSERTION(gPreventAssertInCompareTreePosition || parent,
  1.1272 +               "no common ancestor at all???");
  1.1273 +#endif // DEBUG
  1.1274 +  if (!parent) { // different documents??
  1.1275 +    return 0;
  1.1276 +  }
  1.1277 +
  1.1278 +  int32_t index1 = parent->IndexOf(content1Ancestor);
  1.1279 +  int32_t index2 = parent->IndexOf(content2Ancestor);
  1.1280 +  if (index1 < 0 || index2 < 0) {
  1.1281 +    // one of them must be anonymous; we can't determine the order
  1.1282 +    return 0;
  1.1283 +  }
  1.1284 +
  1.1285 +  return index1 - index2;
  1.1286 +}
  1.1287 +
  1.1288 +// static
  1.1289 +nsIFrame*
  1.1290 +nsLayoutUtils::FillAncestors(nsIFrame* aFrame,
  1.1291 +                             nsIFrame* aStopAtAncestor,
  1.1292 +                             nsTArray<nsIFrame*>* aAncestors)
  1.1293 +{
  1.1294 +  while (aFrame && aFrame != aStopAtAncestor) {
  1.1295 +    aAncestors->AppendElement(aFrame);
  1.1296 +    aFrame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
  1.1297 +  }
  1.1298 +  return aFrame;
  1.1299 +}
  1.1300 +
  1.1301 +// Return true if aFrame1 is after aFrame2
  1.1302 +static bool IsFrameAfter(nsIFrame* aFrame1, nsIFrame* aFrame2)
  1.1303 +{
  1.1304 +  nsIFrame* f = aFrame2;
  1.1305 +  do {
  1.1306 +    f = f->GetNextSibling();
  1.1307 +    if (f == aFrame1)
  1.1308 +      return true;
  1.1309 +  } while (f);
  1.1310 +  return false;
  1.1311 +}
  1.1312 +
  1.1313 +// static
  1.1314 +int32_t
  1.1315 +nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
  1.1316 +                                     nsIFrame* aFrame2,
  1.1317 +                                     int32_t aIf1Ancestor,
  1.1318 +                                     int32_t aIf2Ancestor,
  1.1319 +                                     nsIFrame* aCommonAncestor)
  1.1320 +{
  1.1321 +  NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
  1.1322 +  NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
  1.1323 +
  1.1324 +  nsAutoTArray<nsIFrame*,20> frame2Ancestors;
  1.1325 +  nsIFrame* nonCommonAncestor =
  1.1326 +    FillAncestors(aFrame2, aCommonAncestor, &frame2Ancestors);
  1.1327 +
  1.1328 +  return DoCompareTreePosition(aFrame1, aFrame2, frame2Ancestors,
  1.1329 +                               aIf1Ancestor, aIf2Ancestor,
  1.1330 +                               nonCommonAncestor ? aCommonAncestor : nullptr);
  1.1331 +}
  1.1332 +
  1.1333 +// static
  1.1334 +int32_t
  1.1335 +nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
  1.1336 +                                     nsIFrame* aFrame2,
  1.1337 +                                     nsTArray<nsIFrame*>& aFrame2Ancestors,
  1.1338 +                                     int32_t aIf1Ancestor,
  1.1339 +                                     int32_t aIf2Ancestor,
  1.1340 +                                     nsIFrame* aCommonAncestor)
  1.1341 +{
  1.1342 +  NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
  1.1343 +  NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
  1.1344 +
  1.1345 +  nsPresContext* presContext = aFrame1->PresContext();
  1.1346 +  if (presContext != aFrame2->PresContext()) {
  1.1347 +    NS_ERROR("no common ancestor at all, different documents");
  1.1348 +    return 0;
  1.1349 +  }
  1.1350 +
  1.1351 +  nsAutoTArray<nsIFrame*,20> frame1Ancestors;
  1.1352 +  if (aCommonAncestor &&
  1.1353 +      !FillAncestors(aFrame1, aCommonAncestor, &frame1Ancestors)) {
  1.1354 +    // We reached the root of the frame tree ... if aCommonAncestor was set,
  1.1355 +    // it is wrong
  1.1356 +    return DoCompareTreePosition(aFrame1, aFrame2,
  1.1357 +                                 aIf1Ancestor, aIf2Ancestor, nullptr);
  1.1358 +  }
  1.1359 +
  1.1360 +  int32_t last1 = int32_t(frame1Ancestors.Length()) - 1;
  1.1361 +  int32_t last2 = int32_t(aFrame2Ancestors.Length()) - 1;
  1.1362 +  while (last1 >= 0 && last2 >= 0 &&
  1.1363 +         frame1Ancestors[last1] == aFrame2Ancestors[last2]) {
  1.1364 +    last1--;
  1.1365 +    last2--;
  1.1366 +  }
  1.1367 +
  1.1368 +  if (last1 < 0) {
  1.1369 +    if (last2 < 0) {
  1.1370 +      NS_ASSERTION(aFrame1 == aFrame2, "internal error?");
  1.1371 +      return 0;
  1.1372 +    }
  1.1373 +    // aFrame1 is an ancestor of aFrame2
  1.1374 +    return aIf1Ancestor;
  1.1375 +  }
  1.1376 +
  1.1377 +  if (last2 < 0) {
  1.1378 +    // aFrame2 is an ancestor of aFrame1
  1.1379 +    return aIf2Ancestor;
  1.1380 +  }
  1.1381 +
  1.1382 +  nsIFrame* ancestor1 = frame1Ancestors[last1];
  1.1383 +  nsIFrame* ancestor2 = aFrame2Ancestors[last2];
  1.1384 +  // Now we should be able to walk sibling chains to find which one is first
  1.1385 +  if (IsFrameAfter(ancestor2, ancestor1))
  1.1386 +    return -1;
  1.1387 +  if (IsFrameAfter(ancestor1, ancestor2))
  1.1388 +    return 1;
  1.1389 +  NS_WARNING("Frames were in different child lists???");
  1.1390 +  return 0;
  1.1391 +}
  1.1392 +
  1.1393 +// static
  1.1394 +nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) {
  1.1395 +  if (!aFrame) {
  1.1396 +    return nullptr;
  1.1397 +  }
  1.1398 +
  1.1399 +  nsIFrame* next;
  1.1400 +  while ((next = aFrame->GetNextSibling()) != nullptr) {
  1.1401 +    aFrame = next;
  1.1402 +  }
  1.1403 +  return aFrame;
  1.1404 +}
  1.1405 +
  1.1406 +// static
  1.1407 +nsView*
  1.1408 +nsLayoutUtils::FindSiblingViewFor(nsView* aParentView, nsIFrame* aFrame) {
  1.1409 +  nsIFrame* parentViewFrame = aParentView->GetFrame();
  1.1410 +  nsIContent* parentViewContent = parentViewFrame ? parentViewFrame->GetContent() : nullptr;
  1.1411 +  for (nsView* insertBefore = aParentView->GetFirstChild(); insertBefore;
  1.1412 +       insertBefore = insertBefore->GetNextSibling()) {
  1.1413 +    nsIFrame* f = insertBefore->GetFrame();
  1.1414 +    if (!f) {
  1.1415 +      // this view could be some anonymous view attached to a meaningful parent
  1.1416 +      for (nsView* searchView = insertBefore->GetParent(); searchView;
  1.1417 +           searchView = searchView->GetParent()) {
  1.1418 +        f = searchView->GetFrame();
  1.1419 +        if (f) {
  1.1420 +          break;
  1.1421 +        }
  1.1422 +      }
  1.1423 +      NS_ASSERTION(f, "Can't find a frame anywhere!");
  1.1424 +    }
  1.1425 +    if (!f || !aFrame->GetContent() || !f->GetContent() ||
  1.1426 +        CompareTreePosition(aFrame->GetContent(), f->GetContent(), parentViewContent) > 0) {
  1.1427 +      // aFrame's content is after f's content (or we just don't know),
  1.1428 +      // so put our view before f's view
  1.1429 +      return insertBefore;
  1.1430 +    }
  1.1431 +  }
  1.1432 +  return nullptr;
  1.1433 +}
  1.1434 +
  1.1435 +//static
  1.1436 +nsIScrollableFrame*
  1.1437 +nsLayoutUtils::GetScrollableFrameFor(const nsIFrame *aScrolledFrame)
  1.1438 +{
  1.1439 +  nsIFrame *frame = aScrolledFrame->GetParent();
  1.1440 +  nsIScrollableFrame *sf = do_QueryFrame(frame);
  1.1441 +  return sf;
  1.1442 +}
  1.1443 +
  1.1444 +/* static */ void
  1.1445 +nsLayoutUtils::SetFixedPositionLayerData(Layer* aLayer,
  1.1446 +                                         const nsIFrame* aViewportFrame,
  1.1447 +                                         const nsRect& aAnchorRect,
  1.1448 +                                         const nsIFrame* aFixedPosFrame,
  1.1449 +                                         nsPresContext* aPresContext,
  1.1450 +                                         const ContainerLayerParameters& aContainerParameters) {
  1.1451 +  // Find out the rect of the viewport frame relative to the reference frame.
  1.1452 +  // This, in conjunction with the container scale, will correspond to the
  1.1453 +  // coordinate-space of the built layer.
  1.1454 +  float factor = aPresContext->AppUnitsPerDevPixel();
  1.1455 +  Rect anchorRect(NSAppUnitsToFloatPixels(aAnchorRect.x, factor) *
  1.1456 +                    aContainerParameters.mXScale,
  1.1457 +                  NSAppUnitsToFloatPixels(aAnchorRect.y, factor) *
  1.1458 +                    aContainerParameters.mYScale,
  1.1459 +                  NSAppUnitsToFloatPixels(aAnchorRect.width, factor) *
  1.1460 +                    aContainerParameters.mXScale,
  1.1461 +                  NSAppUnitsToFloatPixels(aAnchorRect.height, factor) *
  1.1462 +                    aContainerParameters.mYScale);
  1.1463 +  // Need to transform anchorRect from the container layer's coordinate system
  1.1464 +  // into aLayer's coordinate system.
  1.1465 +  Matrix transform2d;
  1.1466 +  if (aLayer->GetTransform().Is2D(&transform2d)) {
  1.1467 +    transform2d.Invert();
  1.1468 +    anchorRect = transform2d.TransformBounds(anchorRect);
  1.1469 +  } else {
  1.1470 +    NS_ERROR("3D transform found between fixedpos content and its viewport (should never happen)");
  1.1471 +    anchorRect = Rect(0,0,0,0);
  1.1472 +  }
  1.1473 +
  1.1474 +  // Work out the anchor point for this fixed position layer. We assume that
  1.1475 +  // any positioning set (left/top/right/bottom) indicates that the
  1.1476 +  // corresponding side of its container should be the anchor point,
  1.1477 +  // defaulting to top-left.
  1.1478 +  LayerPoint anchor(anchorRect.x, anchorRect.y);
  1.1479 +  // Make sure the layer is aware of any fixed position margins that have
  1.1480 +  // been set.
  1.1481 +  nsMargin fixedMargins = aPresContext->PresShell()->GetContentDocumentFixedPositionMargins();
  1.1482 +  LayerMargin fixedLayerMargins(NSAppUnitsToFloatPixels(fixedMargins.top, factor) *
  1.1483 +                                  aContainerParameters.mYScale,
  1.1484 +                                NSAppUnitsToFloatPixels(fixedMargins.right, factor) *
  1.1485 +                                  aContainerParameters.mXScale,
  1.1486 +                                NSAppUnitsToFloatPixels(fixedMargins.bottom, factor) *
  1.1487 +                                  aContainerParameters.mYScale,
  1.1488 +                                NSAppUnitsToFloatPixels(fixedMargins.left, factor) *
  1.1489 +                                  aContainerParameters.mXScale);
  1.1490 +
  1.1491 +  if (aFixedPosFrame != aViewportFrame) {
  1.1492 +    const nsStylePosition* position = aFixedPosFrame->StylePosition();
  1.1493 +    if (position->mOffset.GetRightUnit() != eStyleUnit_Auto) {
  1.1494 +      if (position->mOffset.GetLeftUnit() != eStyleUnit_Auto) {
  1.1495 +        anchor.x = anchorRect.x + anchorRect.width / 2.f;
  1.1496 +      } else {
  1.1497 +        anchor.x = anchorRect.XMost();
  1.1498 +      }
  1.1499 +    }
  1.1500 +    if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto) {
  1.1501 +      if (position->mOffset.GetTopUnit() != eStyleUnit_Auto) {
  1.1502 +        anchor.y = anchorRect.y + anchorRect.height / 2.f;
  1.1503 +      } else {
  1.1504 +        anchor.y = anchorRect.YMost();
  1.1505 +      }
  1.1506 +    }
  1.1507 +
  1.1508 +    // If the frame is auto-positioned on either axis, set the top/left layer
  1.1509 +    // margins to -1, to indicate to the compositor that this layer is
  1.1510 +    // unaffected by fixed margins.
  1.1511 +    if (position->mOffset.GetLeftUnit() == eStyleUnit_Auto &&
  1.1512 +        position->mOffset.GetRightUnit() == eStyleUnit_Auto) {
  1.1513 +      fixedLayerMargins.left = -1;
  1.1514 +    }
  1.1515 +    if (position->mOffset.GetTopUnit() == eStyleUnit_Auto &&
  1.1516 +        position->mOffset.GetBottomUnit() == eStyleUnit_Auto) {
  1.1517 +      fixedLayerMargins.top = -1;
  1.1518 +    }
  1.1519 +  }
  1.1520 +
  1.1521 +  aLayer->SetFixedPositionAnchor(anchor);
  1.1522 +  aLayer->SetFixedPositionMargins(fixedLayerMargins);
  1.1523 +}
  1.1524 +
  1.1525 +bool
  1.1526 +nsLayoutUtils::ViewportHasDisplayPort(nsPresContext* aPresContext, nsRect* aDisplayPort)
  1.1527 +{
  1.1528 +  nsIFrame* rootScrollFrame =
  1.1529 +    aPresContext->PresShell()->GetRootScrollFrame();
  1.1530 +  return rootScrollFrame &&
  1.1531 +    nsLayoutUtils::GetDisplayPort(rootScrollFrame->GetContent(), aDisplayPort);
  1.1532 +}
  1.1533 +
  1.1534 +bool
  1.1535 +nsLayoutUtils::IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame, nsRect* aDisplayPort)
  1.1536 +{
  1.1537 +  // Fixed-pos frames are parented by the viewport frame or the page content frame.
  1.1538 +  // We'll assume that printing/print preview don't have displayports for their
  1.1539 +  // pages!
  1.1540 +  nsIFrame* parent = aFrame->GetParent();
  1.1541 +  if (!parent || parent->GetParent() ||
  1.1542 +      aFrame->StyleDisplay()->mPosition != NS_STYLE_POSITION_FIXED) {
  1.1543 +    return false;
  1.1544 +  }
  1.1545 +  return ViewportHasDisplayPort(aFrame->PresContext(), aDisplayPort);
  1.1546 +}
  1.1547 +
  1.1548 +static nsIFrame*
  1.1549 +GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
  1.1550 +                                const nsIFrame* aStopAtAncestor)
  1.1551 +{
  1.1552 +  nsIFrame* f = aFrame;
  1.1553 +  nsIFrame* stickyFrame = nullptr;
  1.1554 +  while (f != aStopAtAncestor) {
  1.1555 +    if (nsLayoutUtils::IsPopup(f))
  1.1556 +      break;
  1.1557 +    if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
  1.1558 +      break;
  1.1559 +    if (!f->GetParent() &&
  1.1560 +        nsLayoutUtils::ViewportHasDisplayPort(f->PresContext())) {
  1.1561 +      // Viewport frames in a display port need to be animated geometry roots
  1.1562 +      // for background-attachment:fixed elements.
  1.1563 +      break;
  1.1564 +    }
  1.1565 +    nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
  1.1566 +    if (!parent)
  1.1567 +      break;
  1.1568 +    nsIAtom* parentType = parent->GetType();
  1.1569 +#ifdef ANDROID
  1.1570 +    // Treat the slider thumb as being as an active scrolled root
  1.1571 +    // on mobile so that it can move without repainting.
  1.1572 +    if (parentType == nsGkAtoms::sliderFrame)
  1.1573 +      break;
  1.1574 +#endif
  1.1575 +    // Sticky frames are active if their nearest scrollable frame
  1.1576 +    // is also active, just keep a record of sticky frames that we
  1.1577 +    // encounter for now.
  1.1578 +    if (f->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
  1.1579 +        !stickyFrame) {
  1.1580 +      stickyFrame = f;
  1.1581 +    }
  1.1582 +    if (parentType == nsGkAtoms::scrollFrame) {
  1.1583 +      nsIScrollableFrame* sf = do_QueryFrame(parent);
  1.1584 +      if (sf->IsScrollingActive() && sf->GetScrolledFrame() == f) {
  1.1585 +        // If we found a sticky frame inside this active scroll frame,
  1.1586 +        // then use that. Otherwise use the scroll frame.
  1.1587 +        if (stickyFrame) {
  1.1588 +          return stickyFrame;
  1.1589 +        }
  1.1590 +        return f;
  1.1591 +      } else {
  1.1592 +        stickyFrame = nullptr;
  1.1593 +      }
  1.1594 +    }
  1.1595 +    // Fixed-pos frames are parented by the viewport frame, which has no parent
  1.1596 +    if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
  1.1597 +      return f;
  1.1598 +    }
  1.1599 +    f = parent;
  1.1600 +  }
  1.1601 +  return f;
  1.1602 +}
  1.1603 +
  1.1604 +nsIFrame*
  1.1605 +nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
  1.1606 +                                          nsDisplayListBuilder* aBuilder)
  1.1607 +{
  1.1608 +  nsIFrame* f = aItem->Frame();
  1.1609 +  if (aItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER) {
  1.1610 +    nsDisplayScrollLayer* scrollLayerItem =
  1.1611 +      static_cast<nsDisplayScrollLayer*>(aItem);
  1.1612 +    nsIFrame* scrolledFrame = scrollLayerItem->GetScrolledFrame();
  1.1613 +    return GetAnimatedGeometryRootForFrame(scrolledFrame,
  1.1614 +        aBuilder->FindReferenceFrameFor(scrolledFrame));
  1.1615 +  }
  1.1616 +  if (aItem->ShouldFixToViewport(aBuilder)) {
  1.1617 +    // Make its active scrolled root be the active scrolled root of
  1.1618 +    // the enclosing viewport, since it shouldn't be scrolled by scrolled
  1.1619 +    // frames in its document. InvalidateFixedBackgroundFramesFromList in
  1.1620 +    // nsGfxScrollFrame will not repaint this item when scrolling occurs.
  1.1621 +    nsIFrame* viewportFrame =
  1.1622 +      nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame);
  1.1623 +    NS_ASSERTION(viewportFrame, "no viewport???");
  1.1624 +    return GetAnimatedGeometryRootForFrame(viewportFrame,
  1.1625 +        aBuilder->FindReferenceFrameFor(viewportFrame));
  1.1626 +  }
  1.1627 +  return GetAnimatedGeometryRootForFrame(f, aItem->ReferenceFrame());
  1.1628 +}
  1.1629 +
  1.1630 +// static
  1.1631 +nsIScrollableFrame*
  1.1632 +nsLayoutUtils::GetNearestScrollableFrameForDirection(nsIFrame* aFrame,
  1.1633 +                                                     Direction aDirection)
  1.1634 +{
  1.1635 +  NS_ASSERTION(aFrame, "GetNearestScrollableFrameForDirection expects a non-null frame");
  1.1636 +  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  1.1637 +    nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
  1.1638 +    if (scrollableFrame) {
  1.1639 +      ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
  1.1640 +      uint32_t directions = scrollableFrame->GetPerceivedScrollingDirections();
  1.1641 +      if (aDirection == eVertical ?
  1.1642 +          (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN &&
  1.1643 +           (directions & nsIScrollableFrame::VERTICAL)) :
  1.1644 +          (ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN &&
  1.1645 +           (directions & nsIScrollableFrame::HORIZONTAL)))
  1.1646 +        return scrollableFrame;
  1.1647 +    }
  1.1648 +  }
  1.1649 +  return nullptr;
  1.1650 +}
  1.1651 +
  1.1652 +// static
  1.1653 +nsIScrollableFrame*
  1.1654 +nsLayoutUtils::GetNearestScrollableFrame(nsIFrame* aFrame, uint32_t aFlags)
  1.1655 +{
  1.1656 +  NS_ASSERTION(aFrame, "GetNearestScrollableFrame expects a non-null frame");
  1.1657 +  for (nsIFrame* f = aFrame; f; f = (aFlags & SCROLLABLE_SAME_DOC) ?
  1.1658 +       f->GetParent() : nsLayoutUtils::GetCrossDocParentFrame(f)) {
  1.1659 +    nsIScrollableFrame* scrollableFrame = do_QueryFrame(f);
  1.1660 +    if (scrollableFrame) {
  1.1661 +      ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
  1.1662 +      if ((aFlags & SCROLLABLE_INCLUDE_HIDDEN) ||
  1.1663 +          ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN ||
  1.1664 +          ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN)
  1.1665 +        return scrollableFrame;
  1.1666 +    }
  1.1667 +  }
  1.1668 +  return nullptr;
  1.1669 +}
  1.1670 +
  1.1671 +// static
  1.1672 +nsRect
  1.1673 +nsLayoutUtils::GetScrolledRect(nsIFrame* aScrolledFrame,
  1.1674 +                               const nsRect& aScrolledFrameOverflowArea,
  1.1675 +                               const nsSize& aScrollPortSize,
  1.1676 +                               uint8_t aDirection)
  1.1677 +{
  1.1678 +  nscoord x1 = aScrolledFrameOverflowArea.x,
  1.1679 +          x2 = aScrolledFrameOverflowArea.XMost(),
  1.1680 +          y1 = aScrolledFrameOverflowArea.y,
  1.1681 +          y2 = aScrolledFrameOverflowArea.YMost();
  1.1682 +  if (y1 < 0) {
  1.1683 +    y1 = 0;
  1.1684 +  }
  1.1685 +  if (aDirection != NS_STYLE_DIRECTION_RTL) {
  1.1686 +    if (x1 < 0) {
  1.1687 +      x1 = 0;
  1.1688 +    }
  1.1689 +  } else {
  1.1690 +    if (x2 > aScrollPortSize.width) {
  1.1691 +      x2 = aScrollPortSize.width;
  1.1692 +    }
  1.1693 +    // When the scrolled frame chooses a size larger than its available width (because
  1.1694 +    // its padding alone is larger than the available width), we need to keep the
  1.1695 +    // start-edge of the scroll frame anchored to the start-edge of the scrollport.
  1.1696 +    // When the scrolled frame is RTL, this means moving it in our left-based
  1.1697 +    // coordinate system, so we need to compensate for its extra width here by
  1.1698 +    // effectively repositioning the frame.
  1.1699 +    nscoord extraWidth = std::max(0, aScrolledFrame->GetSize().width - aScrollPortSize.width);
  1.1700 +    x2 += extraWidth;
  1.1701 +  }
  1.1702 +  return nsRect(x1, y1, x2 - x1, y2 - y1);
  1.1703 +}
  1.1704 +
  1.1705 +//static
  1.1706 +bool
  1.1707 +nsLayoutUtils::HasPseudoStyle(nsIContent* aContent,
  1.1708 +                              nsStyleContext* aStyleContext,
  1.1709 +                              nsCSSPseudoElements::Type aPseudoElement,
  1.1710 +                              nsPresContext* aPresContext)
  1.1711 +{
  1.1712 +  NS_PRECONDITION(aPresContext, "Must have a prescontext");
  1.1713 +
  1.1714 +  nsRefPtr<nsStyleContext> pseudoContext;
  1.1715 +  if (aContent) {
  1.1716 +    pseudoContext = aPresContext->StyleSet()->
  1.1717 +      ProbePseudoElementStyle(aContent->AsElement(), aPseudoElement,
  1.1718 +                              aStyleContext);
  1.1719 +  }
  1.1720 +  return pseudoContext != nullptr;
  1.1721 +}
  1.1722 +
  1.1723 +nsPoint
  1.1724 +nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(nsIDOMEvent* aDOMEvent, nsIFrame* aFrame)
  1.1725 +{
  1.1726 +  if (!aDOMEvent)
  1.1727 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1728 +  WidgetEvent* event = aDOMEvent->GetInternalNSEvent();
  1.1729 +  if (!event)
  1.1730 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1731 +  return GetEventCoordinatesRelativeTo(event, aFrame);
  1.1732 +}
  1.1733 +
  1.1734 +nsPoint
  1.1735 +nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
  1.1736 +                                             nsIFrame* aFrame)
  1.1737 +{
  1.1738 +  if (!aEvent || (aEvent->eventStructType != NS_MOUSE_EVENT &&
  1.1739 +                  aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
  1.1740 +                  aEvent->eventStructType != NS_WHEEL_EVENT &&
  1.1741 +                  aEvent->eventStructType != NS_DRAG_EVENT &&
  1.1742 +                  aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
  1.1743 +                  aEvent->eventStructType != NS_POINTER_EVENT &&
  1.1744 +                  aEvent->eventStructType != NS_GESTURENOTIFY_EVENT &&
  1.1745 +                  aEvent->eventStructType != NS_TOUCH_EVENT &&
  1.1746 +                  aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
  1.1747 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1748 +
  1.1749 +  return GetEventCoordinatesRelativeTo(aEvent,
  1.1750 +           LayoutDeviceIntPoint::ToUntyped(aEvent->AsGUIEvent()->refPoint),
  1.1751 +           aFrame);
  1.1752 +}
  1.1753 +
  1.1754 +nsPoint
  1.1755 +nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
  1.1756 +                                             const nsIntPoint aPoint,
  1.1757 +                                             nsIFrame* aFrame)
  1.1758 +{
  1.1759 +  if (!aFrame) {
  1.1760 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1761 +  }
  1.1762 +
  1.1763 +  nsIWidget* widget = aEvent->AsGUIEvent()->widget;
  1.1764 +  if (!widget) {
  1.1765 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1766 +  }
  1.1767 +
  1.1768 +  return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
  1.1769 +}
  1.1770 +
  1.1771 +nsPoint
  1.1772 +nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
  1.1773 +                                             const nsIntPoint aPoint,
  1.1774 +                                             nsIFrame* aFrame)
  1.1775 +{
  1.1776 +  if (!aFrame || !aWidget) {
  1.1777 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1778 +  }
  1.1779 +
  1.1780 +  nsView* view = aFrame->GetView();
  1.1781 +  if (view) {
  1.1782 +    nsIWidget* frameWidget = view->GetWidget();
  1.1783 +    if (frameWidget && frameWidget == aWidget) {
  1.1784 +      // Special case this cause it happens a lot.
  1.1785 +      // This also fixes bug 664707, events in the extra-special case of select
  1.1786 +      // dropdown popups that are transformed.
  1.1787 +      nsPresContext* presContext = aFrame->PresContext();
  1.1788 +      nsPoint pt(presContext->DevPixelsToAppUnits(aPoint.x),
  1.1789 +                 presContext->DevPixelsToAppUnits(aPoint.y));
  1.1790 +      return pt - view->ViewToWidgetOffset();
  1.1791 +    }
  1.1792 +  }
  1.1793 +
  1.1794 +  /* If we walk up the frame tree and discover that any of the frames are
  1.1795 +   * transformed, we need to do extra work to convert from the global
  1.1796 +   * space to the local space.
  1.1797 +   */
  1.1798 +  nsIFrame* rootFrame = aFrame;
  1.1799 +  bool transformFound = false;
  1.1800 +  for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
  1.1801 +    if (f->IsTransformed()) {
  1.1802 +      transformFound = true;
  1.1803 +    }
  1.1804 +
  1.1805 +    rootFrame = f;
  1.1806 +  }
  1.1807 +
  1.1808 +  nsView* rootView = rootFrame->GetView();
  1.1809 +  if (!rootView) {
  1.1810 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1811 +  }
  1.1812 +
  1.1813 +  nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
  1.1814 +                                               aWidget, aPoint, rootView);
  1.1815 +
  1.1816 +  if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
  1.1817 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.1818 +  }
  1.1819 +
  1.1820 +  // Convert from root document app units to app units of the document aFrame
  1.1821 +  // is in.
  1.1822 +  int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
  1.1823 +  int32_t localAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.1824 +  widgetToView = widgetToView.ConvertAppUnits(rootAPD, localAPD);
  1.1825 +
  1.1826 +  /* If we encountered a transform, we can't do simple arithmetic to figure
  1.1827 +   * out how to convert back to aFrame's coordinates and must use the CTM.
  1.1828 +   */
  1.1829 +  if (transformFound || aFrame->IsSVGText()) {
  1.1830 +    return TransformRootPointToFrame(aFrame, widgetToView);
  1.1831 +  }
  1.1832 +
  1.1833 +  /* Otherwise, all coordinate systems are translations of one another,
  1.1834 +   * so we can just subtract out the difference.
  1.1835 +   */
  1.1836 +  return widgetToView - aFrame->GetOffsetToCrossDoc(rootFrame);
  1.1837 +}
  1.1838 +
  1.1839 +nsIFrame*
  1.1840 +nsLayoutUtils::GetPopupFrameForEventCoordinates(nsPresContext* aPresContext,
  1.1841 +                                                const WidgetEvent* aEvent)
  1.1842 +{
  1.1843 +#ifdef MOZ_XUL
  1.1844 +  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1.1845 +  if (!pm) {
  1.1846 +    return nullptr;
  1.1847 +  }
  1.1848 +  nsTArray<nsIFrame*> popups;
  1.1849 +  pm->GetVisiblePopups(popups);
  1.1850 +  uint32_t i;
  1.1851 +  // Search from top to bottom
  1.1852 +  for (i = 0; i < popups.Length(); i++) {
  1.1853 +    nsIFrame* popup = popups[i];
  1.1854 +    if (popup->PresContext()->GetRootPresContext() == aPresContext &&
  1.1855 +        popup->GetScrollableOverflowRect().Contains(
  1.1856 +          GetEventCoordinatesRelativeTo(aEvent, popup))) {
  1.1857 +      return popup;
  1.1858 +    }
  1.1859 +  }
  1.1860 +#endif
  1.1861 +  return nullptr;
  1.1862 +}
  1.1863 +
  1.1864 +gfx3DMatrix
  1.1865 +nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
  1.1866 +                                 const gfx3DMatrix &aMatrix)
  1.1867 +{
  1.1868 +  gfx3DMatrix result = aMatrix;
  1.1869 +
  1.1870 +  /* Translate to the origin before aMatrix */
  1.1871 +  result.Translate(-aOrigin);
  1.1872 +
  1.1873 +  /* Translate back into position after aMatrix */
  1.1874 +  result.TranslatePost(aOrigin);
  1.1875 +
  1.1876 +  return result; 
  1.1877 +}
  1.1878 +
  1.1879 +static void ConstrainToCoordValues(float& aStart, float& aSize)
  1.1880 +{
  1.1881 +  MOZ_ASSERT(aSize >= 0);
  1.1882 +
  1.1883 +  // Here we try to make sure that the resulting nsRect will continue to cover
  1.1884 +  // as much of the area that was covered by the original gfx Rect as possible.
  1.1885 +
  1.1886 +  // We clamp the bounds of the rect to {nscoord_MIN,nscoord_MAX} since
  1.1887 +  // nsRect::X/Y() and nsRect::XMost/YMost() can't return values outwith this
  1.1888 +  // range:
  1.1889 +  float end = aStart + aSize;
  1.1890 +  aStart = clamped(aStart, float(nscoord_MIN), float(nscoord_MAX));
  1.1891 +  end = clamped(end, float(nscoord_MIN), float(nscoord_MAX));
  1.1892 +
  1.1893 +  aSize = end - aStart;
  1.1894 +
  1.1895 +  // We must also clamp aSize to {0,nscoord_MAX} since nsRect::Width/Height()
  1.1896 +  // can't return a value greater than nscoord_MAX. If aSize is greater than
  1.1897 +  // nscoord_MAX then we reduce it to nscoord_MAX while keeping the rect
  1.1898 +  // centered:
  1.1899 +  if (aSize > nscoord_MAX) {
  1.1900 +    float excess = aSize - nscoord_MAX;
  1.1901 +    excess /= 2;
  1.1902 +    aStart += excess;
  1.1903 +    aSize = nscoord_MAX;
  1.1904 +  }
  1.1905 +}
  1.1906 +
  1.1907 +/**
  1.1908 + * Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
  1.1909 + *
  1.1910 + * @param aVal The value to constrain (in/out)
  1.1911 + */
  1.1912 +static void ConstrainToCoordValues(gfxFloat& aVal)
  1.1913 +{
  1.1914 +  if (aVal <= nscoord_MIN)
  1.1915 +    aVal = nscoord_MIN;
  1.1916 +  else if (aVal >= nscoord_MAX)
  1.1917 +    aVal = nscoord_MAX;
  1.1918 +}
  1.1919 +
  1.1920 +static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize)
  1.1921 +{
  1.1922 +  gfxFloat max = aStart + aSize;
  1.1923 +
  1.1924 +  // Clamp the end points to within nscoord range
  1.1925 +  ConstrainToCoordValues(aStart);
  1.1926 +  ConstrainToCoordValues(max);
  1.1927 +
  1.1928 +  aSize = max - aStart;
  1.1929 +  // If the width if still greater than the max nscoord, then bring both
  1.1930 +  // endpoints in by the same amount until it fits.
  1.1931 +  if (aSize > nscoord_MAX) {
  1.1932 +    gfxFloat excess = aSize - nscoord_MAX;
  1.1933 +    excess /= 2;
  1.1934 +
  1.1935 +    aStart += excess;
  1.1936 +    aSize = nscoord_MAX;
  1.1937 +  } else if (aSize < nscoord_MIN) {
  1.1938 +    gfxFloat excess = aSize - nscoord_MIN;
  1.1939 +    excess /= 2;
  1.1940 +
  1.1941 +    aStart -= excess;
  1.1942 +    aSize = nscoord_MIN;
  1.1943 +  }
  1.1944 +}
  1.1945 +
  1.1946 +nsRect
  1.1947 +nsLayoutUtils::RoundGfxRectToAppRect(const Rect &aRect, float aFactor)
  1.1948 +{
  1.1949 +  /* Get a new Rect whose units are app units by scaling by the specified factor. */
  1.1950 +  Rect scaledRect = aRect;
  1.1951 +  scaledRect.ScaleRoundOut(aFactor);
  1.1952 +
  1.1953 +  /* We now need to constrain our results to the max and min values for coords. */
  1.1954 +  ConstrainToCoordValues(scaledRect.x, scaledRect.width);
  1.1955 +  ConstrainToCoordValues(scaledRect.y, scaledRect.height);
  1.1956 +
  1.1957 +  /* Now typecast everything back.  This is guaranteed to be safe. */
  1.1958 +  return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
  1.1959 +                nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
  1.1960 +}
  1.1961 +
  1.1962 +nsRect
  1.1963 +nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
  1.1964 +{
  1.1965 +  /* Get a new gfxRect whose units are app units by scaling by the specified factor. */
  1.1966 +  gfxRect scaledRect = aRect;
  1.1967 +  scaledRect.ScaleRoundOut(aFactor);
  1.1968 +
  1.1969 +  /* We now need to constrain our results to the max and min values for coords. */
  1.1970 +  ConstrainToCoordValues(scaledRect.x, scaledRect.width);
  1.1971 +  ConstrainToCoordValues(scaledRect.y, scaledRect.height);
  1.1972 +
  1.1973 +  /* Now typecast everything back.  This is guaranteed to be safe. */
  1.1974 +  return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
  1.1975 +                nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
  1.1976 +}
  1.1977 +
  1.1978 +
  1.1979 +nsRegion
  1.1980 +nsLayoutUtils::RoundedRectIntersectRect(const nsRect& aRoundedRect,
  1.1981 +                                        const nscoord aRadii[8],
  1.1982 +                                        const nsRect& aContainedRect)
  1.1983 +{
  1.1984 +  // rectFullHeight and rectFullWidth together will approximately contain
  1.1985 +  // the total area of the frame minus the rounded corners.
  1.1986 +  nsRect rectFullHeight = aRoundedRect;
  1.1987 +  nscoord xDiff = std::max(aRadii[NS_CORNER_TOP_LEFT_X], aRadii[NS_CORNER_BOTTOM_LEFT_X]);
  1.1988 +  rectFullHeight.x += xDiff;
  1.1989 +  rectFullHeight.width -= std::max(aRadii[NS_CORNER_TOP_RIGHT_X],
  1.1990 +                                 aRadii[NS_CORNER_BOTTOM_RIGHT_X]) + xDiff;
  1.1991 +  nsRect r1;
  1.1992 +  r1.IntersectRect(rectFullHeight, aContainedRect);
  1.1993 +
  1.1994 +  nsRect rectFullWidth = aRoundedRect;
  1.1995 +  nscoord yDiff = std::max(aRadii[NS_CORNER_TOP_LEFT_Y], aRadii[NS_CORNER_TOP_RIGHT_Y]);
  1.1996 +  rectFullWidth.y += yDiff;
  1.1997 +  rectFullWidth.height -= std::max(aRadii[NS_CORNER_BOTTOM_LEFT_Y],
  1.1998 +                                 aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) + yDiff;
  1.1999 +  nsRect r2;
  1.2000 +  r2.IntersectRect(rectFullWidth, aContainedRect);
  1.2001 +
  1.2002 +  nsRegion result;
  1.2003 +  result.Or(r1, r2);
  1.2004 +  return result;
  1.2005 +}
  1.2006 +
  1.2007 +// Helper for RoundedRectIntersectsRect.
  1.2008 +static bool
  1.2009 +CheckCorner(nscoord aXOffset, nscoord aYOffset,
  1.2010 +            nscoord aXRadius, nscoord aYRadius)
  1.2011 +{
  1.2012 +  NS_ABORT_IF_FALSE(aXOffset > 0 && aYOffset > 0,
  1.2013 +                    "must not pass nonpositives to CheckCorner");
  1.2014 +  NS_ABORT_IF_FALSE(aXRadius >= 0 && aYRadius >= 0,
  1.2015 +                    "must not pass negatives to CheckCorner");
  1.2016 +
  1.2017 +  // Avoid floating point math unless we're either (1) within the
  1.2018 +  // quarter-ellipse area at the rounded corner or (2) outside the
  1.2019 +  // rounding.
  1.2020 +  if (aXOffset >= aXRadius || aYOffset >= aYRadius)
  1.2021 +    return true;
  1.2022 +
  1.2023 +  // Convert coordinates to a unit circle with (0,0) as the center of
  1.2024 +  // curvature, and see if we're inside the circle or outside.
  1.2025 +  float scaledX = float(aXRadius - aXOffset) / float(aXRadius);
  1.2026 +  float scaledY = float(aYRadius - aYOffset) / float(aYRadius);
  1.2027 +  return scaledX * scaledX + scaledY * scaledY < 1.0f;
  1.2028 +}
  1.2029 +
  1.2030 +bool
  1.2031 +nsLayoutUtils::RoundedRectIntersectsRect(const nsRect& aRoundedRect,
  1.2032 +                                         const nscoord aRadii[8],
  1.2033 +                                         const nsRect& aTestRect)
  1.2034 +{
  1.2035 +  if (!aTestRect.Intersects(aRoundedRect))
  1.2036 +    return false;
  1.2037 +
  1.2038 +  // distances from this edge of aRoundedRect to opposite edge of aTestRect,
  1.2039 +  // which we know are positive due to the Intersects check above.
  1.2040 +  nsMargin insets;
  1.2041 +  insets.top = aTestRect.YMost() - aRoundedRect.y;
  1.2042 +  insets.right = aRoundedRect.XMost() - aTestRect.x;
  1.2043 +  insets.bottom = aRoundedRect.YMost() - aTestRect.y;
  1.2044 +  insets.left = aTestRect.XMost() - aRoundedRect.x;
  1.2045 +
  1.2046 +  // Check whether the bottom-right corner of aTestRect is inside the
  1.2047 +  // top left corner of aBounds when rounded by aRadii, etc.  If any
  1.2048 +  // corner is not, then fail; otherwise succeed.
  1.2049 +  return CheckCorner(insets.left, insets.top,
  1.2050 +                     aRadii[NS_CORNER_TOP_LEFT_X],
  1.2051 +                     aRadii[NS_CORNER_TOP_LEFT_Y]) &&
  1.2052 +         CheckCorner(insets.right, insets.top,
  1.2053 +                     aRadii[NS_CORNER_TOP_RIGHT_X],
  1.2054 +                     aRadii[NS_CORNER_TOP_RIGHT_Y]) &&
  1.2055 +         CheckCorner(insets.right, insets.bottom,
  1.2056 +                     aRadii[NS_CORNER_BOTTOM_RIGHT_X],
  1.2057 +                     aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) &&
  1.2058 +         CheckCorner(insets.left, insets.bottom,
  1.2059 +                     aRadii[NS_CORNER_BOTTOM_LEFT_X],
  1.2060 +                     aRadii[NS_CORNER_BOTTOM_LEFT_Y]);
  1.2061 +}
  1.2062 +
  1.2063 +nsRect
  1.2064 +nsLayoutUtils::MatrixTransformRectOut(const nsRect &aBounds,
  1.2065 +                                      const gfx3DMatrix &aMatrix, float aFactor)
  1.2066 +{
  1.2067 +  nsRect outside = aBounds;
  1.2068 +  outside.ScaleRoundOut(1/aFactor);
  1.2069 +  gfxRect image = aMatrix.TransformBounds(gfxRect(outside.x,
  1.2070 +                                                  outside.y,
  1.2071 +                                                  outside.width,
  1.2072 +                                                  outside.height));
  1.2073 +  return RoundGfxRectToAppRect(image, aFactor);
  1.2074 +}
  1.2075 +
  1.2076 +nsRect
  1.2077 +nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
  1.2078 +                                   const gfx3DMatrix &aMatrix, float aFactor)
  1.2079 +{
  1.2080 +  gfxRect image = aMatrix.TransformBounds(gfxRect(NSAppUnitsToDoublePixels(aBounds.x, aFactor),
  1.2081 +                                                  NSAppUnitsToDoublePixels(aBounds.y, aFactor),
  1.2082 +                                                  NSAppUnitsToDoublePixels(aBounds.width, aFactor),
  1.2083 +                                                  NSAppUnitsToDoublePixels(aBounds.height, aFactor)));
  1.2084 +
  1.2085 +  return RoundGfxRectToAppRect(image, aFactor);
  1.2086 +}
  1.2087 +
  1.2088 +nsPoint
  1.2089 +nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
  1.2090 +                                    const gfx3DMatrix &aMatrix, float aFactor)
  1.2091 +{
  1.2092 +  gfxPoint image = aMatrix.Transform(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, aFactor),
  1.2093 +                                              NSAppUnitsToFloatPixels(aPoint.y, aFactor)));
  1.2094 +  return nsPoint(NSFloatPixelsToAppUnits(float(image.x), aFactor),
  1.2095 +                 NSFloatPixelsToAppUnits(float(image.y), aFactor));
  1.2096 +}
  1.2097 +
  1.2098 +gfx3DMatrix
  1.2099 +nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame, const nsIFrame *aAncestor)
  1.2100 +{
  1.2101 +  nsIFrame* parent;
  1.2102 +  gfx3DMatrix ctm;
  1.2103 +  if (aFrame == aAncestor) {
  1.2104 +    return ctm;
  1.2105 +  }
  1.2106 +  ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
  1.2107 +  while (parent && parent != aAncestor) {
  1.2108 +    if (!parent->Preserves3DChildren()) {
  1.2109 +      ctm.ProjectTo2D();
  1.2110 +    }
  1.2111 +    ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
  1.2112 +  }
  1.2113 +  return ctm;
  1.2114 +}
  1.2115 +
  1.2116 +static nsIFrame*
  1.2117 +FindNearestCommonAncestorFrame(nsIFrame* aFrame1, nsIFrame* aFrame2)
  1.2118 +{
  1.2119 +  nsAutoTArray<nsIFrame*,100> ancestors1;
  1.2120 +  nsAutoTArray<nsIFrame*,100> ancestors2;
  1.2121 +  nsIFrame* commonAncestor = nullptr;
  1.2122 +  if (aFrame1->PresContext() == aFrame2->PresContext()) {
  1.2123 +    commonAncestor = aFrame1->PresContext()->PresShell()->GetRootFrame();
  1.2124 +  }
  1.2125 +  for (nsIFrame* f = aFrame1; f != commonAncestor;
  1.2126 +       f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  1.2127 +    ancestors1.AppendElement(f);
  1.2128 +  }
  1.2129 +  for (nsIFrame* f = aFrame2; f != commonAncestor;
  1.2130 +       f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  1.2131 +    ancestors2.AppendElement(f);
  1.2132 +  }
  1.2133 +  uint32_t minLengths = std::min(ancestors1.Length(), ancestors2.Length());
  1.2134 +  for (uint32_t i = 1; i <= minLengths; ++i) {
  1.2135 +    if (ancestors1[ancestors1.Length() - i] == ancestors2[ancestors2.Length() - i]) {
  1.2136 +      commonAncestor = ancestors1[ancestors1.Length() - i];
  1.2137 +    } else {
  1.2138 +      break;
  1.2139 +    }
  1.2140 +  }
  1.2141 +  return commonAncestor;
  1.2142 +}
  1.2143 +
  1.2144 +nsLayoutUtils::TransformResult
  1.2145 +nsLayoutUtils::TransformPoints(nsIFrame* aFromFrame, nsIFrame* aToFrame,
  1.2146 +                               uint32_t aPointCount, CSSPoint* aPoints)
  1.2147 +{
  1.2148 +  nsIFrame* nearestCommonAncestor = FindNearestCommonAncestorFrame(aFromFrame, aToFrame);
  1.2149 +  if (!nearestCommonAncestor) {
  1.2150 +    return NO_COMMON_ANCESTOR;
  1.2151 +  }
  1.2152 +  gfx3DMatrix downToDest = GetTransformToAncestor(aToFrame, nearestCommonAncestor);
  1.2153 +  if (downToDest.IsSingular()) {
  1.2154 +    return NONINVERTIBLE_TRANSFORM;
  1.2155 +  }
  1.2156 +  downToDest.Invert();
  1.2157 +  gfx3DMatrix upToAncestor = GetTransformToAncestor(aFromFrame, nearestCommonAncestor);
  1.2158 +  CSSToLayoutDeviceScale devPixelsPerCSSPixelFromFrame(
  1.2159 +    double(nsPresContext::AppUnitsPerCSSPixel())/
  1.2160 +      aFromFrame->PresContext()->AppUnitsPerDevPixel());
  1.2161 +  CSSToLayoutDeviceScale devPixelsPerCSSPixelToFrame(
  1.2162 +    double(nsPresContext::AppUnitsPerCSSPixel())/
  1.2163 +      aToFrame->PresContext()->AppUnitsPerDevPixel());
  1.2164 +  for (uint32_t i = 0; i < aPointCount; ++i) {
  1.2165 +    LayoutDevicePoint devPixels = aPoints[i] * devPixelsPerCSSPixelFromFrame;
  1.2166 +    gfxPoint toDevPixels = downToDest.ProjectPoint(
  1.2167 +        upToAncestor.ProjectPoint(gfxPoint(devPixels.x, devPixels.y)));
  1.2168 +    // Divide here so that when the devPixelsPerCSSPixels are the same, we get the correct
  1.2169 +    // answer instead of some inaccuracy multiplying a number by its reciprocal.
  1.2170 +    aPoints[i] = LayoutDevicePoint(toDevPixels.x, toDevPixels.y) /
  1.2171 +        devPixelsPerCSSPixelToFrame;
  1.2172 +  }
  1.2173 +  return TRANSFORM_SUCCEEDED;
  1.2174 +}
  1.2175 +
  1.2176 +bool
  1.2177 +nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame,
  1.2178 +                                         gfx3DMatrix* aTransform)
  1.2179 +{
  1.2180 +  // FIXME/bug 796690: we can sometimes compute a transform in these
  1.2181 +  // cases, it just increases complexity considerably.  Punt for now.
  1.2182 +  if (aFrame->Preserves3DChildren() || aFrame->HasTransformGetter()) {
  1.2183 +    return false;
  1.2184 +  }
  1.2185 +
  1.2186 +  nsIFrame* root = nsLayoutUtils::GetDisplayRootFrame(aFrame);
  1.2187 +  if (root->HasAnyStateBits(NS_FRAME_UPDATE_LAYER_TREE)) {
  1.2188 +    // Content may have been invalidated, so we can't reliably compute
  1.2189 +    // the "layer transform" in general.
  1.2190 +    return false;
  1.2191 +  }
  1.2192 +  // If the caller doesn't care about the value, early-return to skip
  1.2193 +  // overhead below.
  1.2194 +  if (!aTransform) {
  1.2195 +    return true;
  1.2196 +  }
  1.2197 +
  1.2198 +  nsDisplayListBuilder builder(root, nsDisplayListBuilder::OTHER,
  1.2199 +                               false/*don't build caret*/);
  1.2200 +  nsDisplayList list;  
  1.2201 +  nsDisplayTransform* item =
  1.2202 +    new (&builder) nsDisplayTransform(&builder, aFrame, &list);
  1.2203 +
  1.2204 +  *aTransform =
  1.2205 +    item->GetTransform();
  1.2206 +  item->~nsDisplayTransform();
  1.2207 +
  1.2208 +  return true;
  1.2209 +}
  1.2210 +
  1.2211 +static bool
  1.2212 +TransformGfxPointFromAncestor(nsIFrame *aFrame,
  1.2213 +                              const gfxPoint &aPoint,
  1.2214 +                              nsIFrame *aAncestor,
  1.2215 +                              gfxPoint* aOut)
  1.2216 +{
  1.2217 +  gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
  1.2218 +
  1.2219 +  float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.2220 +  nsRect childBounds = aFrame->GetVisualOverflowRectRelativeToSelf();
  1.2221 +  gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
  1.2222 +                         NSAppUnitsToFloatPixels(childBounds.y, factor),
  1.2223 +                         NSAppUnitsToFloatPixels(childBounds.width, factor),
  1.2224 +                         NSAppUnitsToFloatPixels(childBounds.height, factor));
  1.2225 +  return ctm.UntransformPoint(aPoint, childGfxBounds, aOut);
  1.2226 +}
  1.2227 +
  1.2228 +static gfxRect
  1.2229 +TransformGfxRectToAncestor(nsIFrame *aFrame,
  1.2230 +                           const gfxRect &aRect,
  1.2231 +                           const nsIFrame *aAncestor,
  1.2232 +                           bool* aPreservesAxisAlignedRectangles = nullptr)
  1.2233 +{
  1.2234 +  gfx3DMatrix ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
  1.2235 +  if (aPreservesAxisAlignedRectangles) {
  1.2236 +    gfxMatrix matrix2d;
  1.2237 +    *aPreservesAxisAlignedRectangles =
  1.2238 +      ctm.Is2D(&matrix2d) && matrix2d.PreservesAxisAlignedRectangles();
  1.2239 +  }
  1.2240 +  return ctm.TransformBounds(aRect);
  1.2241 +}
  1.2242 +
  1.2243 +static SVGTextFrame*
  1.2244 +GetContainingSVGTextFrame(nsIFrame* aFrame)
  1.2245 +{
  1.2246 +  if (!aFrame->IsSVGText()) {
  1.2247 +    return nullptr;
  1.2248 +  }
  1.2249 +
  1.2250 +  return static_cast<SVGTextFrame*>
  1.2251 +    (nsLayoutUtils::GetClosestFrameOfType(aFrame->GetParent(),
  1.2252 +                                          nsGkAtoms::svgTextFrame));
  1.2253 +}
  1.2254 +
  1.2255 +nsPoint
  1.2256 +nsLayoutUtils::TransformAncestorPointToFrame(nsIFrame* aFrame,
  1.2257 +                                             const nsPoint& aPoint,
  1.2258 +                                             nsIFrame* aAncestor)
  1.2259 +{
  1.2260 +    SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
  1.2261 +
  1.2262 +    float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.2263 +    gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor),
  1.2264 +                    NSAppUnitsToFloatPixels(aPoint.y, factor));
  1.2265 +
  1.2266 +    if (text) {
  1.2267 +        if (!TransformGfxPointFromAncestor(text, result, aAncestor, &result)) {
  1.2268 +            return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.2269 +        }
  1.2270 +        result = text->TransformFramePointToTextChild(result, aFrame);
  1.2271 +    } else {
  1.2272 +        if (!TransformGfxPointFromAncestor(aFrame, result, nullptr, &result)) {
  1.2273 +            return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.2274 +        }
  1.2275 +    }
  1.2276 +
  1.2277 +    return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
  1.2278 +                   NSFloatPixelsToAppUnits(float(result.y), factor));
  1.2279 +}
  1.2280 +
  1.2281 +nsRect
  1.2282 +nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
  1.2283 +                                            const nsRect& aRect,
  1.2284 +                                            const nsIFrame* aAncestor,
  1.2285 +                                            bool* aPreservesAxisAlignedRectangles /* = nullptr */)
  1.2286 +{
  1.2287 +  SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
  1.2288 +
  1.2289 +  float srcAppUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.2290 +  gfxRect result;
  1.2291 +
  1.2292 +  if (text) {
  1.2293 +    result = text->TransformFrameRectFromTextChild(aRect, aFrame);
  1.2294 +    result = TransformGfxRectToAncestor(text, result, aAncestor);
  1.2295 +    // TransformFrameRectFromTextChild could involve any kind of transform, we
  1.2296 +    // could drill down into it to get an answer out of it but we don't yet.
  1.2297 +    if (aPreservesAxisAlignedRectangles)
  1.2298 +      *aPreservesAxisAlignedRectangles = false;
  1.2299 +  } else {
  1.2300 +    result = gfxRect(NSAppUnitsToFloatPixels(aRect.x, srcAppUnitsPerDevPixel),
  1.2301 +                     NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
  1.2302 +                     NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
  1.2303 +                     NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
  1.2304 +    result = TransformGfxRectToAncestor(aFrame, result, aAncestor, aPreservesAxisAlignedRectangles);
  1.2305 +  }
  1.2306 +
  1.2307 +  float destAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
  1.2308 +  return nsRect(NSFloatPixelsToAppUnits(float(result.x), destAppUnitsPerDevPixel),
  1.2309 +                NSFloatPixelsToAppUnits(float(result.y), destAppUnitsPerDevPixel),
  1.2310 +                NSFloatPixelsToAppUnits(float(result.width), destAppUnitsPerDevPixel),
  1.2311 +                NSFloatPixelsToAppUnits(float(result.height), destAppUnitsPerDevPixel));
  1.2312 +}
  1.2313 +
  1.2314 +static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
  1.2315 +  nsIntPoint offset(0, 0);
  1.2316 +  nsIWidget* parent = aWidget->GetParent();
  1.2317 +  while (parent) {
  1.2318 +    nsIntRect bounds;
  1.2319 +    aWidget->GetBounds(bounds);
  1.2320 +    offset += bounds.TopLeft();
  1.2321 +    aWidget = parent;
  1.2322 +    parent = aWidget->GetParent();
  1.2323 +  }
  1.2324 +  aRootWidget = aWidget;
  1.2325 +  return offset;
  1.2326 +}
  1.2327 +
  1.2328 +nsPoint
  1.2329 +nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
  1.2330 +                                     nsIWidget* aWidget, nsIntPoint aPt,
  1.2331 +                                     nsView* aView)
  1.2332 +{
  1.2333 +  nsPoint viewOffset;
  1.2334 +  nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset);
  1.2335 +  if (!viewWidget) {
  1.2336 +    return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
  1.2337 +  }
  1.2338 +
  1.2339 +  nsIWidget* fromRoot;
  1.2340 +  nsIntPoint fromOffset = GetWidgetOffset(aWidget, fromRoot);
  1.2341 +  nsIWidget* toRoot;
  1.2342 +  nsIntPoint toOffset = GetWidgetOffset(viewWidget, toRoot);
  1.2343 +
  1.2344 +  nsIntPoint widgetPoint;
  1.2345 +  if (fromRoot == toRoot) {
  1.2346 +    widgetPoint = aPt + fromOffset - toOffset;
  1.2347 +  } else {
  1.2348 +    nsIntPoint screenPoint = aWidget->WidgetToScreenOffset();
  1.2349 +    widgetPoint = aPt + screenPoint - viewWidget->WidgetToScreenOffset();
  1.2350 +  }
  1.2351 +
  1.2352 +  nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
  1.2353 +                         aPresContext->DevPixelsToAppUnits(widgetPoint.y));
  1.2354 +  return widgetAppUnits - viewOffset;
  1.2355 +}
  1.2356 +
  1.2357 +// Combine aNewBreakType with aOrigBreakType, but limit the break types
  1.2358 +// to NS_STYLE_CLEAR_LEFT, RIGHT, BOTH.
  1.2359 +uint8_t
  1.2360 +nsLayoutUtils::CombineBreakType(uint8_t aOrigBreakType,
  1.2361 +                                uint8_t aNewBreakType)
  1.2362 +{
  1.2363 +  uint8_t breakType = aOrigBreakType;
  1.2364 +  switch(breakType) {
  1.2365 +  case NS_STYLE_CLEAR_LEFT:
  1.2366 +    if (NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
  1.2367 +        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
  1.2368 +      breakType = NS_STYLE_CLEAR_BOTH;
  1.2369 +    }
  1.2370 +    break;
  1.2371 +  case NS_STYLE_CLEAR_RIGHT:
  1.2372 +    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
  1.2373 +        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
  1.2374 +      breakType = NS_STYLE_CLEAR_BOTH;
  1.2375 +    }
  1.2376 +    break;
  1.2377 +  case NS_STYLE_CLEAR_NONE:
  1.2378 +    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
  1.2379 +        NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
  1.2380 +        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
  1.2381 +      breakType = aNewBreakType;
  1.2382 +    }
  1.2383 +  }
  1.2384 +  return breakType;
  1.2385 +}
  1.2386 +
  1.2387 +#ifdef MOZ_DUMP_PAINTING
  1.2388 +#include <stdio.h>
  1.2389 +
  1.2390 +static bool gDumpEventList = false;
  1.2391 +int gPaintCount = 0;
  1.2392 +#endif
  1.2393 +
  1.2394 +nsresult
  1.2395 +nsLayoutUtils::GetRemoteContentIds(nsIFrame* aFrame,
  1.2396 +                                   const nsRect& aTarget,
  1.2397 +                                   nsTArray<ViewID> &aOutIDs,
  1.2398 +                                   bool aIgnoreRootScrollFrame)
  1.2399 +{
  1.2400 +  nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY,
  1.2401 +                               false);
  1.2402 +  nsDisplayList list;
  1.2403 +
  1.2404 +  if (aIgnoreRootScrollFrame) {
  1.2405 +    nsIFrame* rootScrollFrame =
  1.2406 +      aFrame->PresContext()->PresShell()->GetRootScrollFrame();
  1.2407 +    if (rootScrollFrame) {
  1.2408 +      builder.SetIgnoreScrollFrame(rootScrollFrame);
  1.2409 +    }
  1.2410 +  }
  1.2411 +
  1.2412 +  builder.EnterPresShell(aFrame, aTarget);
  1.2413 +  aFrame->BuildDisplayListForStackingContext(&builder, aTarget, &list);
  1.2414 +  builder.LeavePresShell(aFrame, aTarget);
  1.2415 +
  1.2416 +  nsAutoTArray<nsIFrame*,8> outFrames;
  1.2417 +  nsDisplayItem::HitTestState hitTestState(&aOutIDs);
  1.2418 +  list.HitTest(&builder, aTarget, &hitTestState, &outFrames);
  1.2419 +  list.DeleteAll();
  1.2420 +
  1.2421 +  return NS_OK;
  1.2422 +}
  1.2423 +
  1.2424 +nsIFrame*
  1.2425 +nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt, uint32_t aFlags)
  1.2426 +{
  1.2427 +  PROFILER_LABEL("nsLayoutUtils", "GetFrameForPoint");
  1.2428 +  nsresult rv;
  1.2429 +  nsAutoTArray<nsIFrame*,8> outFrames;
  1.2430 +  rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames, aFlags);
  1.2431 +  NS_ENSURE_SUCCESS(rv, nullptr);
  1.2432 +  return outFrames.Length() ? outFrames.ElementAt(0) : nullptr;
  1.2433 +}
  1.2434 +
  1.2435 +nsresult
  1.2436 +nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
  1.2437 +                                nsTArray<nsIFrame*> &aOutFrames,
  1.2438 +                                uint32_t aFlags)
  1.2439 +{
  1.2440 +  PROFILER_LABEL("nsLayoutUtils","GetFramesForArea");
  1.2441 +  nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::EVENT_DELIVERY,
  1.2442 +                               false);
  1.2443 +  nsDisplayList list;
  1.2444 +  nsRect target(aRect);
  1.2445 +
  1.2446 +  if (aFlags & IGNORE_PAINT_SUPPRESSION) {
  1.2447 +    builder.IgnorePaintSuppression();
  1.2448 +  }
  1.2449 +
  1.2450 +  if (aFlags & IGNORE_ROOT_SCROLL_FRAME) {
  1.2451 +    nsIFrame* rootScrollFrame =
  1.2452 +      aFrame->PresContext()->PresShell()->GetRootScrollFrame();
  1.2453 +    if (rootScrollFrame) {
  1.2454 +      builder.SetIgnoreScrollFrame(rootScrollFrame);
  1.2455 +    }
  1.2456 +  }
  1.2457 +  if (aFlags & IGNORE_CROSS_DOC) {
  1.2458 +    builder.SetDescendIntoSubdocuments(false);
  1.2459 +  }
  1.2460 +
  1.2461 +  builder.EnterPresShell(aFrame, target);
  1.2462 +  aFrame->BuildDisplayListForStackingContext(&builder, target, &list);
  1.2463 +  builder.LeavePresShell(aFrame, target);
  1.2464 +
  1.2465 +#ifdef MOZ_DUMP_PAINTING
  1.2466 +  if (gDumpEventList) {
  1.2467 +    fprintf_stderr(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
  1.2468 +    nsFrame::PrintDisplayList(&builder, list);
  1.2469 +  }
  1.2470 +#endif
  1.2471 +
  1.2472 +  nsDisplayItem::HitTestState hitTestState;
  1.2473 +  list.HitTest(&builder, target, &hitTestState, &aOutFrames);
  1.2474 +  list.DeleteAll();
  1.2475 +  return NS_OK;
  1.2476 +}
  1.2477 +
  1.2478 +// This function is only used on B2G, and some compilers complain about
  1.2479 +// unused static functions, so we need to #ifdef it.
  1.2480 +#ifdef MOZ_WIDGET_GONK
  1.2481 +// aScrollFrame and aScrollFrameAsScrollable must be non-nullptr
  1.2482 +static FrameMetrics
  1.2483 +CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
  1.2484 +                                    nsIScrollableFrame* aScrollFrameAsScrollable) {
  1.2485 +  // Calculate the metrics necessary for calculating the displayport.
  1.2486 +  // This code has a lot in common with the code in RecordFrameMetrics();
  1.2487 +  // we may want to refactor this at some point.
  1.2488 +  FrameMetrics metrics;
  1.2489 +  nsPresContext* presContext = aScrollFrame->PresContext();
  1.2490 +  nsIPresShell* presShell = presContext->PresShell();
  1.2491 +  CSSToLayoutDeviceScale deviceScale(float(nsPresContext::AppUnitsPerCSSPixel())
  1.2492 +                                     / presContext->AppUnitsPerDevPixel());
  1.2493 +  ParentLayerToLayerScale resolution(presShell->GetResolution().width);
  1.2494 +  LayoutDeviceToLayerScale cumulativeResolution(presShell->GetCumulativeResolution().width);
  1.2495 +
  1.2496 +  metrics.mDevPixelsPerCSSPixel = deviceScale;
  1.2497 +  metrics.mResolution = resolution;
  1.2498 +  metrics.mCumulativeResolution = cumulativeResolution;
  1.2499 +  metrics.SetZoom(deviceScale * cumulativeResolution * LayerToScreenScale(1));
  1.2500 +
  1.2501 +  // Only the size of the composition bounds is relevant to the
  1.2502 +  // displayport calculation, not its origin.
  1.2503 +  nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(aScrollFrame);
  1.2504 +  metrics.mCompositionBounds
  1.2505 +      = RoundedToInt(LayoutDeviceRect::FromAppUnits(nsRect(nsPoint(0, 0), compositionSize),
  1.2506 +                                                    presContext->AppUnitsPerDevPixel())
  1.2507 +                     * (cumulativeResolution / resolution));
  1.2508 +
  1.2509 +  // This function is used for setting a display port for subframes, so
  1.2510 +  // aScrollFrame will not be the root content document's root scroll frame.
  1.2511 +  metrics.SetRootCompositionSize(
  1.2512 +      nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame, false, metrics));
  1.2513 +
  1.2514 +  metrics.SetScrollOffset(CSSPoint::FromAppUnits(
  1.2515 +      aScrollFrameAsScrollable->GetScrollPosition()));
  1.2516 +
  1.2517 +  metrics.mScrollableRect = CSSRect::FromAppUnits(
  1.2518 +      nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrameAsScrollable, nullptr));
  1.2519 +
  1.2520 +  return metrics;
  1.2521 +}
  1.2522 +#endif
  1.2523 +
  1.2524 +bool
  1.2525 +nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
  1.2526 +                                           nsIFrame* aScrollFrame,
  1.2527 +                                           nsRect aDisplayPortBase,
  1.2528 +                                           nsRect* aOutDisplayport) {
  1.2529 +  nsIContent* content = aScrollFrame->GetContent();
  1.2530 +  nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
  1.2531 +  if (!content || !scrollableFrame) {
  1.2532 +    return false;
  1.2533 +  }
  1.2534 +
  1.2535 +  // Set the base rect. Note that this will not influence 'haveDisplayPort',
  1.2536 +  // which is based on either the whole rect or margins being set, but it
  1.2537 +  // will affect what is returned in 'aOutDisplayPort' if margins are set.
  1.2538 +  SetDisplayPortBase(content, aDisplayPortBase);
  1.2539 +
  1.2540 +  bool haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
  1.2541 +
  1.2542 +#ifdef MOZ_WIDGET_GONK
  1.2543 +  // On B2G, we perform an optimization where we ensure that at least one
  1.2544 +  // async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
  1.2545 +  // If that's not the case yet, and we are async-scrollable, we will get a
  1.2546 +  // displayport.
  1.2547 +  // Note: we only do this in processes where we do subframe scrolling to
  1.2548 +  //       begin with (i.e., not in the parent process on B2G).
  1.2549 +  if (WantSubAPZC() &&
  1.2550 +      !aBuilder.HaveScrollableDisplayPort() &&
  1.2551 +      scrollableFrame->WantAsyncScroll()) {
  1.2552 +
  1.2553 +    // If we don't already have a displayport, calculate and set one.
  1.2554 +    if (!haveDisplayPort) {
  1.2555 +      FrameMetrics metrics = CalculateFrameMetricsForDisplayPort(aScrollFrame, scrollableFrame);
  1.2556 +      LayerMargin displayportMargins = AsyncPanZoomController::CalculatePendingDisplayPort(
  1.2557 +          metrics, ScreenPoint(0.0f, 0.0f), 0.0);
  1.2558 +      nsIPresShell* presShell = aScrollFrame->PresContext()->GetPresShell();
  1.2559 +      gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled()
  1.2560 +          ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) :
  1.2561 +            gfx::IntSize(0, 0);
  1.2562 +      nsLayoutUtils::SetDisplayPortMargins(
  1.2563 +          content, presShell, displayportMargins, alignment.width,
  1.2564 +          alignment.height, 0, nsLayoutUtils::RepaintMode::DoNotRepaint);
  1.2565 +      haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
  1.2566 +      NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it");
  1.2567 +    }
  1.2568 +
  1.2569 +    // Record that the we now have a scrollable display port.
  1.2570 +    aBuilder.SetHaveScrollableDisplayPort();
  1.2571 +  }
  1.2572 +#endif
  1.2573 +
  1.2574 +  return haveDisplayPort;
  1.2575 +}
  1.2576 +
  1.2577 +nsresult
  1.2578 +nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
  1.2579 +                          const nsRegion& aDirtyRegion, nscolor aBackstop,
  1.2580 +                          uint32_t aFlags)
  1.2581 +{
  1.2582 +  PROFILER_LABEL("nsLayoutUtils","PaintFrame");
  1.2583 +  if (aFlags & PAINT_WIDGET_LAYERS) {
  1.2584 +    nsView* view = aFrame->GetView();
  1.2585 +    if (!(view && view->GetWidget() && GetDisplayRootFrame(aFrame) == aFrame)) {
  1.2586 +      aFlags &= ~PAINT_WIDGET_LAYERS;
  1.2587 +      NS_ASSERTION(aRenderingContext, "need a rendering context");
  1.2588 +    }
  1.2589 +  }
  1.2590 +
  1.2591 +  nsPresContext* presContext = aFrame->PresContext();
  1.2592 +  nsIPresShell* presShell = presContext->PresShell();
  1.2593 +  nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
  1.2594 +  if (!rootPresContext) {
  1.2595 +    return NS_OK;
  1.2596 +  }
  1.2597 +
  1.2598 +  nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
  1.2599 +                           !(aFlags & PAINT_HIDE_CARET));
  1.2600 +
  1.2601 +  nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
  1.2602 +  bool usingDisplayPort = false;
  1.2603 +  nsRect displayport;
  1.2604 +  if (rootScrollFrame && !aFrame->GetParent()) {
  1.2605 +    nsRect displayportBase(
  1.2606 +        nsPoint(0,0),
  1.2607 +        nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame));
  1.2608 +    usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
  1.2609 +        builder, rootScrollFrame, displayportBase, &displayport);
  1.2610 +  }
  1.2611 +
  1.2612 +  nsRegion visibleRegion;
  1.2613 +  if (aFlags & PAINT_WIDGET_LAYERS) {
  1.2614 +    // This layer tree will be reused, so we'll need to calculate it
  1.2615 +    // for the whole "visible" area of the window
  1.2616 +    // 
  1.2617 +    // |ignoreViewportScrolling| and |usingDisplayPort| are persistent
  1.2618 +    // document-rendering state.  We rely on PresShell to flush
  1.2619 +    // retained layers as needed when that persistent state changes.
  1.2620 +    if (!usingDisplayPort) {
  1.2621 +      visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf();
  1.2622 +    } else {
  1.2623 +      visibleRegion = displayport;
  1.2624 +    }
  1.2625 +  } else {
  1.2626 +    visibleRegion = aDirtyRegion;
  1.2627 +  }
  1.2628 +
  1.2629 +  // If we're going to display something different from what we'd normally
  1.2630 +  // paint in a window then we will flush out any retained layer trees before
  1.2631 +  // *and after* we draw.
  1.2632 +  bool willFlushRetainedLayers = (aFlags & PAINT_HIDE_CARET) != 0;
  1.2633 +
  1.2634 +  nsDisplayList list;
  1.2635 +  if (aFlags & PAINT_IN_TRANSFORM) {
  1.2636 +    builder.SetInTransform(true);
  1.2637 +  }
  1.2638 +  if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
  1.2639 +    builder.SetSyncDecodeImages(true);
  1.2640 +  }
  1.2641 +  if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
  1.2642 +    builder.SetPaintingToWindow(true);
  1.2643 +  }
  1.2644 +  if (aFlags & PAINT_IGNORE_SUPPRESSION) {
  1.2645 +    builder.IgnorePaintSuppression();
  1.2646 +  }
  1.2647 +  // Windowed plugins aren't allowed in popups
  1.2648 +  if ((aFlags & PAINT_WIDGET_LAYERS) &&
  1.2649 +      !willFlushRetainedLayers &&
  1.2650 +      !(aFlags & PAINT_DOCUMENT_RELATIVE) &&
  1.2651 +      rootPresContext->NeedToComputePluginGeometryUpdates()) {
  1.2652 +    builder.SetWillComputePluginGeometry(true);
  1.2653 +  }
  1.2654 +  nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
  1.2655 +
  1.2656 +  bool ignoreViewportScrolling =
  1.2657 +    aFrame->GetParent() ? false : presShell->IgnoringViewportScrolling();
  1.2658 +  if (ignoreViewportScrolling && rootScrollFrame) {
  1.2659 +    nsIScrollableFrame* rootScrollableFrame =
  1.2660 +      presShell->GetRootScrollFrameAsScrollable();
  1.2661 +    if (aFlags & PAINT_DOCUMENT_RELATIVE) {
  1.2662 +      // Make visibleRegion and aRenderingContext relative to the
  1.2663 +      // scrolled frame instead of the root frame.
  1.2664 +      nsPoint pos = rootScrollableFrame->GetScrollPosition();
  1.2665 +      visibleRegion.MoveBy(-pos);
  1.2666 +      if (aRenderingContext) {
  1.2667 +        aRenderingContext->Translate(pos);
  1.2668 +      }
  1.2669 +    }
  1.2670 +    builder.SetIgnoreScrollFrame(rootScrollFrame);
  1.2671 +
  1.2672 +    nsCanvasFrame* canvasFrame =
  1.2673 +      do_QueryFrame(rootScrollableFrame->GetScrolledFrame());
  1.2674 +    if (canvasFrame) {
  1.2675 +      // Use UnionRect here to ensure that areas where the scrollbars
  1.2676 +      // were are still filled with the background color.
  1.2677 +      canvasArea.UnionRect(canvasArea,
  1.2678 +        canvasFrame->CanvasArea() + builder.ToReferenceFrame(canvasFrame));
  1.2679 +    }
  1.2680 +  }
  1.2681 +
  1.2682 +  nsRect dirtyRect = visibleRegion.GetBounds();
  1.2683 +  builder.EnterPresShell(aFrame, dirtyRect);
  1.2684 +  {
  1.2685 +    PROFILER_LABEL("nsLayoutUtils","PaintFrame::BuildDisplayList");
  1.2686 +    aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
  1.2687 +  }
  1.2688 +  const bool paintAllContinuations = aFlags & PAINT_ALL_CONTINUATIONS;
  1.2689 +  NS_ASSERTION(!paintAllContinuations || !aFrame->GetPrevContinuation(),
  1.2690 +               "If painting all continuations, the frame must be "
  1.2691 +               "first-continuation");
  1.2692 +
  1.2693 +  nsIAtom* frameType = aFrame->GetType();
  1.2694 +
  1.2695 +  if (paintAllContinuations) {
  1.2696 +    nsIFrame* currentFrame = aFrame;
  1.2697 +    while ((currentFrame = currentFrame->GetNextContinuation()) != nullptr) {
  1.2698 +      PROFILER_LABEL("nsLayoutUtils","PaintFrame::ContinuationsBuildDisplayList");
  1.2699 +      nsRect frameDirty = dirtyRect - builder.ToReferenceFrame(currentFrame);
  1.2700 +      currentFrame->BuildDisplayListForStackingContext(&builder,
  1.2701 +                                                       frameDirty, &list);
  1.2702 +    }
  1.2703 +  }
  1.2704 +
  1.2705 +  // For the viewport frame in print preview/page layout we want to paint
  1.2706 +  // the grey background behind the page, not the canvas color.
  1.2707 +  if (frameType == nsGkAtoms::viewportFrame && 
  1.2708 +      nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
  1.2709 +    nsRect bounds = nsRect(builder.ToReferenceFrame(aFrame),
  1.2710 +                           aFrame->GetSize());
  1.2711 +    presShell->AddPrintPreviewBackgroundItem(builder, list, aFrame, bounds);
  1.2712 +  } else if (frameType != nsGkAtoms::pageFrame) {
  1.2713 +    // For printing, this function is first called on an nsPageFrame, which
  1.2714 +    // creates a display list with a PageContent item. The PageContent item's
  1.2715 +    // paint function calls this function on the nsPageFrame's child which is
  1.2716 +    // an nsPageContentFrame. We only want to add the canvas background color
  1.2717 +    // item once, for the nsPageContentFrame.
  1.2718 +
  1.2719 +    // Add the canvas background color to the bottom of the list. This
  1.2720 +    // happens after we've built the list so that AddCanvasBackgroundColorItem
  1.2721 +    // can monkey with the contents if necessary.
  1.2722 +    canvasArea.IntersectRect(canvasArea, visibleRegion.GetBounds());
  1.2723 +    presShell->AddCanvasBackgroundColorItem(
  1.2724 +           builder, list, aFrame, canvasArea, aBackstop);
  1.2725 +
  1.2726 +    // If the passed in backstop color makes us draw something different from
  1.2727 +    // normal, we need to flush layers.
  1.2728 +    if ((aFlags & PAINT_WIDGET_LAYERS) && !willFlushRetainedLayers) {
  1.2729 +      nsView* view = aFrame->GetView();
  1.2730 +      if (view) {
  1.2731 +        nscolor backstop = presShell->ComputeBackstopColor(view);
  1.2732 +        // The PresShell's canvas background color doesn't get updated until
  1.2733 +        // EnterPresShell, so this check has to be done after that.
  1.2734 +        nscolor canvasColor = presShell->GetCanvasBackground();
  1.2735 +        if (NS_ComposeColors(aBackstop, canvasColor) !=
  1.2736 +            NS_ComposeColors(backstop, canvasColor)) {
  1.2737 +          willFlushRetainedLayers = true;
  1.2738 +        }
  1.2739 +      }
  1.2740 +    }
  1.2741 +  }
  1.2742 +
  1.2743 +  builder.LeavePresShell(aFrame, dirtyRect);
  1.2744 +
  1.2745 +  if (builder.GetHadToIgnorePaintSuppression()) {
  1.2746 +    willFlushRetainedLayers = true;
  1.2747 +  }
  1.2748 +
  1.2749 +#ifdef MOZ_DUMP_PAINTING
  1.2750 +  FILE* savedDumpFile = gfxUtils::sDumpPaintFile;
  1.2751 +  if (gfxUtils::sDumpPaintList || gfxUtils::sDumpPainting) {
  1.2752 +    if (gfxUtils::sDumpPaintingToFile) {
  1.2753 +      nsCString string("dump-");
  1.2754 +      string.AppendInt(gPaintCount);
  1.2755 +      string.Append(".html");
  1.2756 +      gfxUtils::sDumpPaintFile = fopen(string.BeginReading(), "w");
  1.2757 +    } else {
  1.2758 +      gfxUtils::sDumpPaintFile = stderr;
  1.2759 +    }
  1.2760 +    if (gfxUtils::sDumpPaintingToFile) {
  1.2761 +      fprintf_stderr(gfxUtils::sDumpPaintFile, "<html><head><script>var array = {}; function ViewImage(index) { window.location = array[index]; }</script></head><body>");
  1.2762 +    }
  1.2763 +    fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
  1.2764 +            dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
  1.2765 +    nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile, gfxUtils::sDumpPaintingToFile);
  1.2766 +    if (gfxUtils::sDumpPaintingToFile) {
  1.2767 +      fprintf_stderr(gfxUtils::sDumpPaintFile, "<script>");
  1.2768 +    }
  1.2769 +  }
  1.2770 +#endif
  1.2771 +
  1.2772 +  list.ComputeVisibilityForRoot(&builder, &visibleRegion,
  1.2773 +                                usingDisplayPort ? rootScrollFrame : nullptr);
  1.2774 +
  1.2775 +  uint32_t flags = nsDisplayList::PAINT_DEFAULT;
  1.2776 +  if (aFlags & PAINT_WIDGET_LAYERS) {
  1.2777 +    flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS;
  1.2778 +    if (willFlushRetainedLayers) {
  1.2779 +      // The caller wanted to paint from retained layers, but set up
  1.2780 +      // the paint in such a way that we can't use them.  We're going
  1.2781 +      // to display something different from what we'd normally paint
  1.2782 +      // in a window, so make sure we flush out any retained layer
  1.2783 +      // trees before *and after* we draw.  Callers should be fixed to
  1.2784 +      // not do this.
  1.2785 +      NS_WARNING("Flushing retained layers!");
  1.2786 +      flags |= nsDisplayList::PAINT_FLUSH_LAYERS;
  1.2787 +    } else if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) {
  1.2788 +      nsIWidget *widget = aFrame->GetNearestWidget();
  1.2789 +      if (widget) {
  1.2790 +        builder.SetFinalTransparentRegion(visibleRegion);
  1.2791 +        // If we're finished building display list items for painting of the outermost
  1.2792 +        // pres shell, notify the widget about any toolbars we've encountered.
  1.2793 +        widget->UpdateThemeGeometries(builder.GetThemeGeometries());
  1.2794 +      }
  1.2795 +    }
  1.2796 +  }
  1.2797 +  if (aFlags & PAINT_EXISTING_TRANSACTION) {
  1.2798 +    flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
  1.2799 +  }
  1.2800 +  if (aFlags & PAINT_NO_COMPOSITE) {
  1.2801 +    flags |= nsDisplayList::PAINT_NO_COMPOSITE;
  1.2802 +  }
  1.2803 +  if (aFlags & PAINT_COMPRESSED) {
  1.2804 +    flags |= nsDisplayList::PAINT_COMPRESSED;
  1.2805 +  }
  1.2806 +
  1.2807 +  list.PaintRoot(&builder, aRenderingContext, flags);
  1.2808 +
  1.2809 +#ifdef MOZ_DUMP_PAINTING
  1.2810 +  if (gfxUtils::sDumpPaintList || gfxUtils::sDumpPainting) {
  1.2811 +    if (gfxUtils::sDumpPaintingToFile) {
  1.2812 +      fprintf_stderr(gfxUtils::sDumpPaintFile, "</script>");
  1.2813 +    }
  1.2814 +    fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- after optimization:\n");
  1.2815 +    nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile, gfxUtils::sDumpPaintingToFile);
  1.2816 +
  1.2817 +    fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- retained layer tree:\n");
  1.2818 +    nsIWidget* widget = aFrame->GetNearestWidget();
  1.2819 +    if (widget) {
  1.2820 +      nsRefPtr<LayerManager> layerManager = widget->GetLayerManager();
  1.2821 +      if (layerManager) {
  1.2822 +        FrameLayerBuilder::DumpRetainedLayerTree(layerManager, gfxUtils::sDumpPaintFile,
  1.2823 +                                                 gfxUtils::sDumpPaintingToFile);
  1.2824 +      }
  1.2825 +    }
  1.2826 +    if (gfxUtils::sDumpPaintingToFile) {
  1.2827 +      fprintf(gfxUtils::sDumpPaintFile, "</body></html>");
  1.2828 +      fclose(gfxUtils::sDumpPaintFile);
  1.2829 +    }
  1.2830 +    gfxUtils::sDumpPaintFile = savedDumpFile;
  1.2831 +    gPaintCount++;
  1.2832 +  }
  1.2833 +#endif
  1.2834 +
  1.2835 +  // Update the widget's opaque region information. This sets
  1.2836 +  // glass boundaries on Windows. Also set up plugin clip regions and bounds.
  1.2837 +  if ((aFlags & PAINT_WIDGET_LAYERS) &&
  1.2838 +      !willFlushRetainedLayers &&
  1.2839 +      !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
  1.2840 +    nsIWidget *widget = aFrame->GetNearestWidget();
  1.2841 +    if (widget) {
  1.2842 +      nsRegion excludedRegion = builder.GetExcludedGlassRegion();
  1.2843 +      excludedRegion.Sub(excludedRegion, visibleRegion);
  1.2844 +      nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel()));
  1.2845 +      widget->UpdateOpaqueRegion(windowRegion);
  1.2846 +    }
  1.2847 +  }
  1.2848 +
  1.2849 +  if (builder.WillComputePluginGeometry()) {
  1.2850 +    nsRefPtr<LayerManager> layerManager;
  1.2851 +    nsIWidget* widget = aFrame->GetNearestWidget();
  1.2852 +    if (widget) {
  1.2853 +      layerManager = widget->GetLayerManager();
  1.2854 +    }
  1.2855 +
  1.2856 +    rootPresContext->ComputePluginGeometryUpdates(aFrame, &builder, &list);
  1.2857 +
  1.2858 +    // We're not going to get a WillPaintWindow event here if we didn't do
  1.2859 +    // widget invalidation, so just apply the plugin geometry update here instead.
  1.2860 +    // We could instead have the compositor send back an equivalent to WillPaintWindow,
  1.2861 +    // but it should be close enough to now not to matter.
  1.2862 +    if (layerManager && !layerManager->NeedsWidgetInvalidation()) {
  1.2863 +      rootPresContext->ApplyPluginGeometryUpdates();
  1.2864 +    }
  1.2865 +
  1.2866 +    // We told the compositor thread not to composite when it received the transaction because
  1.2867 +    // we wanted to update plugins first. Schedule the composite now.
  1.2868 +    if (layerManager) {
  1.2869 +      layerManager->Composite();
  1.2870 +    }
  1.2871 +  }
  1.2872 +
  1.2873 +
  1.2874 +  // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
  1.2875 +  list.DeleteAll();
  1.2876 +  return NS_OK;
  1.2877 +}
  1.2878 +
  1.2879 +/**
  1.2880 + * Uses a binary search for find where the cursor falls in the line of text
  1.2881 + * It also keeps track of the part of the string that has already been measured
  1.2882 + * so it doesn't have to keep measuring the same text over and over
  1.2883 + *
  1.2884 + * @param "aBaseWidth" contains the width in twips of the portion
  1.2885 + * of the text that has already been measured, and aBaseInx contains
  1.2886 + * the index of the text that has already been measured.
  1.2887 + *
  1.2888 + * @param aTextWidth returns the (in twips) the length of the text that falls
  1.2889 + * before the cursor aIndex contains the index of the text where the cursor falls
  1.2890 + */
  1.2891 +bool
  1.2892 +nsLayoutUtils::BinarySearchForPosition(nsRenderingContext* aRendContext,
  1.2893 +                        const char16_t* aText,
  1.2894 +                        int32_t    aBaseWidth,
  1.2895 +                        int32_t    aBaseInx,
  1.2896 +                        int32_t    aStartInx,
  1.2897 +                        int32_t    aEndInx,
  1.2898 +                        int32_t    aCursorPos,
  1.2899 +                        int32_t&   aIndex,
  1.2900 +                        int32_t&   aTextWidth)
  1.2901 +{
  1.2902 +  int32_t range = aEndInx - aStartInx;
  1.2903 +  if ((range == 1) || (range == 2 && NS_IS_HIGH_SURROGATE(aText[aStartInx]))) {
  1.2904 +    aIndex   = aStartInx + aBaseInx;
  1.2905 +    aTextWidth = aRendContext->GetWidth(aText, aIndex);
  1.2906 +    return true;
  1.2907 +  }
  1.2908 +
  1.2909 +  int32_t inx = aStartInx + (range / 2);
  1.2910 +
  1.2911 +  // Make sure we don't leave a dangling low surrogate
  1.2912 +  if (NS_IS_HIGH_SURROGATE(aText[inx-1]))
  1.2913 +    inx++;
  1.2914 +
  1.2915 +  int32_t textWidth = aRendContext->GetWidth(aText, inx);
  1.2916 +
  1.2917 +  int32_t fullWidth = aBaseWidth + textWidth;
  1.2918 +  if (fullWidth == aCursorPos) {
  1.2919 +    aTextWidth = textWidth;
  1.2920 +    aIndex = inx;
  1.2921 +    return true;
  1.2922 +  } else if (aCursorPos < fullWidth) {
  1.2923 +    aTextWidth = aBaseWidth;
  1.2924 +    if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) {
  1.2925 +      return true;
  1.2926 +    }
  1.2927 +  } else {
  1.2928 +    aTextWidth = fullWidth;
  1.2929 +    if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, inx, aEndInx, aCursorPos, aIndex, aTextWidth)) {
  1.2930 +      return true;
  1.2931 +    }
  1.2932 +  }
  1.2933 +  return false;
  1.2934 +}
  1.2935 +
  1.2936 +static void
  1.2937 +AddBoxesForFrame(nsIFrame* aFrame,
  1.2938 +                 nsLayoutUtils::BoxCallback* aCallback)
  1.2939 +{
  1.2940 +  nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
  1.2941 +
  1.2942 +  if (pseudoType == nsCSSAnonBoxes::tableOuter) {
  1.2943 +    AddBoxesForFrame(aFrame->GetFirstPrincipalChild(), aCallback);
  1.2944 +    nsIFrame* kid = aFrame->GetFirstChild(nsIFrame::kCaptionList);
  1.2945 +    if (kid) {
  1.2946 +      AddBoxesForFrame(kid, aCallback);
  1.2947 +    }
  1.2948 +  } else if (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
  1.2949 +             pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
  1.2950 +             pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
  1.2951 +             pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
  1.2952 +    for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
  1.2953 +      AddBoxesForFrame(kid, aCallback);
  1.2954 +    }
  1.2955 +  } else {
  1.2956 +    aCallback->AddBox(aFrame);
  1.2957 +  }
  1.2958 +}
  1.2959 +
  1.2960 +void
  1.2961 +nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
  1.2962 +{
  1.2963 +  while (aFrame) {
  1.2964 +    AddBoxesForFrame(aFrame, aCallback);
  1.2965 +    aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
  1.2966 +  }
  1.2967 +}
  1.2968 +
  1.2969 +nsIFrame*
  1.2970 +nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame)
  1.2971 +{
  1.2972 +  while (aFrame) {
  1.2973 +    nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
  1.2974 +
  1.2975 +    if (pseudoType == nsCSSAnonBoxes::tableOuter) {
  1.2976 +      nsIFrame* f = GetFirstNonAnonymousFrame(aFrame->GetFirstPrincipalChild());
  1.2977 +      if (f) {
  1.2978 +        return f;
  1.2979 +      }
  1.2980 +      nsIFrame* kid = aFrame->GetFirstChild(nsIFrame::kCaptionList);
  1.2981 +      if (kid) {
  1.2982 +        f = GetFirstNonAnonymousFrame(kid);
  1.2983 +        if (f) {
  1.2984 +          return f;
  1.2985 +        }
  1.2986 +      }
  1.2987 +    } else if (pseudoType == nsCSSAnonBoxes::mozAnonymousBlock ||
  1.2988 +               pseudoType == nsCSSAnonBoxes::mozAnonymousPositionedBlock ||
  1.2989 +               pseudoType == nsCSSAnonBoxes::mozMathMLAnonymousBlock ||
  1.2990 +               pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
  1.2991 +      for (nsIFrame* kid = aFrame->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
  1.2992 +        nsIFrame* f = GetFirstNonAnonymousFrame(kid);
  1.2993 +        if (f) {
  1.2994 +          return f;
  1.2995 +        }
  1.2996 +      }
  1.2997 +    } else {
  1.2998 +      return aFrame;
  1.2999 +    }
  1.3000 +
  1.3001 +    aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
  1.3002 +  }
  1.3003 +  return nullptr;
  1.3004 +}
  1.3005 +
  1.3006 +struct BoxToRect : public nsLayoutUtils::BoxCallback {
  1.3007 +  nsIFrame* mRelativeTo;
  1.3008 +  nsLayoutUtils::RectCallback* mCallback;
  1.3009 +  uint32_t mFlags;
  1.3010 +
  1.3011 +  BoxToRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
  1.3012 +            uint32_t aFlags)
  1.3013 +    : mRelativeTo(aRelativeTo), mCallback(aCallback), mFlags(aFlags) {}
  1.3014 +
  1.3015 +  virtual void AddBox(nsIFrame* aFrame) MOZ_OVERRIDE {
  1.3016 +    nsRect r;
  1.3017 +    nsIFrame* outer = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(aFrame, &r);
  1.3018 +    if (!outer) {
  1.3019 +      outer = aFrame;
  1.3020 +      switch (mFlags & nsLayoutUtils::RECTS_WHICH_BOX_MASK) {
  1.3021 +        case nsLayoutUtils::RECTS_USE_CONTENT_BOX:
  1.3022 +          r = aFrame->GetContentRectRelativeToSelf();
  1.3023 +          break;
  1.3024 +        case nsLayoutUtils::RECTS_USE_PADDING_BOX:
  1.3025 +          r = aFrame->GetPaddingRectRelativeToSelf();
  1.3026 +          break;
  1.3027 +        case nsLayoutUtils::RECTS_USE_MARGIN_BOX:
  1.3028 +          r = aFrame->GetMarginRectRelativeToSelf();
  1.3029 +          break;
  1.3030 +        default: // Use the border box
  1.3031 +          r = aFrame->GetRectRelativeToSelf();
  1.3032 +      }
  1.3033 +    }
  1.3034 +    if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
  1.3035 +      r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
  1.3036 +    } else {
  1.3037 +      r += outer->GetOffsetTo(mRelativeTo);
  1.3038 +    }
  1.3039 +    mCallback->AddRect(r);
  1.3040 +  }
  1.3041 +};
  1.3042 +
  1.3043 +void
  1.3044 +nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
  1.3045 +                                 RectCallback* aCallback, uint32_t aFlags)
  1.3046 +{
  1.3047 +  BoxToRect converter(aRelativeTo, aCallback, aFlags);
  1.3048 +  GetAllInFlowBoxes(aFrame, &converter);
  1.3049 +}
  1.3050 +
  1.3051 +nsLayoutUtils::RectAccumulator::RectAccumulator() : mSeenFirstRect(false) {}
  1.3052 +
  1.3053 +void nsLayoutUtils::RectAccumulator::AddRect(const nsRect& aRect) {
  1.3054 +  mResultRect.UnionRect(mResultRect, aRect);
  1.3055 +  if (!mSeenFirstRect) {
  1.3056 +    mSeenFirstRect = true;
  1.3057 +    mFirstRect = aRect;
  1.3058 +  }
  1.3059 +}
  1.3060 +
  1.3061 +nsLayoutUtils::RectListBuilder::RectListBuilder(DOMRectList* aList)
  1.3062 +  : mRectList(aList)
  1.3063 +{
  1.3064 +}
  1.3065 +
  1.3066 +void nsLayoutUtils::RectListBuilder::AddRect(const nsRect& aRect) {
  1.3067 +  nsRefPtr<DOMRect> rect = new DOMRect(mRectList);
  1.3068 +
  1.3069 +  rect->SetLayoutRect(aRect);
  1.3070 +  mRectList->Append(rect);
  1.3071 +}
  1.3072 +
  1.3073 +nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame)
  1.3074 +{
  1.3075 +  return aFrame->PresContext()->PresShell()->GetRootFrame();
  1.3076 +}
  1.3077 +
  1.3078 +nsRect
  1.3079 +nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
  1.3080 +                                      uint32_t aFlags) {
  1.3081 +  RectAccumulator accumulator;
  1.3082 +  GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
  1.3083 +  return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
  1.3084 +          : accumulator.mResultRect;
  1.3085 +}
  1.3086 +
  1.3087 +nsRect
  1.3088 +nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
  1.3089 +                                       nsIFrame* aFrame,
  1.3090 +                                       uint32_t aFlags)
  1.3091 +{
  1.3092 +  const nsStyleText* textStyle = aFrame->StyleText();
  1.3093 +  if (!textStyle->HasTextShadow())
  1.3094 +    return aTextAndDecorationsRect;
  1.3095 +
  1.3096 +  nsRect resultRect = aTextAndDecorationsRect;
  1.3097 +  int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.3098 +  for (uint32_t i = 0; i < textStyle->mTextShadow->Length(); ++i) {
  1.3099 +    nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
  1.3100 +    nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
  1.3101 +    if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
  1.3102 +      continue;
  1.3103 +
  1.3104 +    nsRect tmpRect(aTextAndDecorationsRect);
  1.3105 +
  1.3106 +    tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
  1.3107 +    tmpRect.Inflate(blur);
  1.3108 +
  1.3109 +    resultRect.UnionRect(resultRect, tmpRect);
  1.3110 +  }
  1.3111 +  return resultRect;
  1.3112 +}
  1.3113 +
  1.3114 +nsresult
  1.3115 +nsLayoutUtils::GetFontMetricsForFrame(const nsIFrame* aFrame,
  1.3116 +                                      nsFontMetrics** aFontMetrics,
  1.3117 +                                      float aInflation)
  1.3118 +{
  1.3119 +  return nsLayoutUtils::GetFontMetricsForStyleContext(aFrame->StyleContext(),
  1.3120 +                                                      aFontMetrics,
  1.3121 +                                                      aInflation);
  1.3122 +}
  1.3123 +
  1.3124 +nsresult
  1.3125 +nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
  1.3126 +                                             nsFontMetrics** aFontMetrics,
  1.3127 +                                             float aInflation)
  1.3128 +{
  1.3129 +  // pass the user font set object into the device context to pass along to CreateFontGroup
  1.3130 +  nsPresContext* pc = aStyleContext->PresContext();
  1.3131 +  gfxUserFontSet* fs = pc->GetUserFontSet();
  1.3132 +  gfxTextPerfMetrics* tp = pc->GetTextPerfMetrics();
  1.3133 +
  1.3134 +  nsFont font = aStyleContext->StyleFont()->mFont;
  1.3135 +  // We need to not run font.size through floats when it's large since
  1.3136 +  // doing so would be lossy.  Fortunately, in such cases, aInflation is
  1.3137 +  // guaranteed to be 1.0f.
  1.3138 +  if (aInflation != 1.0f) {
  1.3139 +    font.size = NSToCoordRound(font.size * aInflation);
  1.3140 +  }
  1.3141 +  return pc->DeviceContext()->GetMetricsFor(
  1.3142 +                  font, aStyleContext->StyleFont()->mLanguage,
  1.3143 +                  fs, tp, *aFontMetrics);
  1.3144 +}
  1.3145 +
  1.3146 +nsIFrame*
  1.3147 +nsLayoutUtils::FindChildContainingDescendant(nsIFrame* aParent, nsIFrame* aDescendantFrame)
  1.3148 +{
  1.3149 +  nsIFrame* result = aDescendantFrame;
  1.3150 +
  1.3151 +  while (result) {
  1.3152 +    nsIFrame* parent = result->GetParent();
  1.3153 +    if (parent == aParent) {
  1.3154 +      break;
  1.3155 +    }
  1.3156 +
  1.3157 +    // The frame is not an immediate child of aParent so walk up another level
  1.3158 +    result = parent;
  1.3159 +  }
  1.3160 +
  1.3161 +  return result;
  1.3162 +}
  1.3163 +
  1.3164 +nsBlockFrame*
  1.3165 +nsLayoutUtils::GetAsBlock(nsIFrame* aFrame)
  1.3166 +{
  1.3167 +  nsBlockFrame* block = do_QueryFrame(aFrame);
  1.3168 +  return block;
  1.3169 +}
  1.3170 +
  1.3171 +nsBlockFrame*
  1.3172 +nsLayoutUtils::FindNearestBlockAncestor(nsIFrame* aFrame)
  1.3173 +{
  1.3174 +  nsIFrame* nextAncestor;
  1.3175 +  for (nextAncestor = aFrame->GetParent(); nextAncestor;
  1.3176 +       nextAncestor = nextAncestor->GetParent()) {
  1.3177 +    nsBlockFrame* block = GetAsBlock(nextAncestor);
  1.3178 +    if (block)
  1.3179 +      return block;
  1.3180 +  }
  1.3181 +  return nullptr;
  1.3182 +}
  1.3183 +
  1.3184 +nsIFrame*
  1.3185 +nsLayoutUtils::GetNonGeneratedAncestor(nsIFrame* aFrame)
  1.3186 +{
  1.3187 +  if (!(aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT))
  1.3188 +    return aFrame;
  1.3189 +
  1.3190 +  nsIFrame* f = aFrame;
  1.3191 +  do {
  1.3192 +    f = GetParentOrPlaceholderFor(f);
  1.3193 +  } while (f->GetStateBits() & NS_FRAME_GENERATED_CONTENT);
  1.3194 +  return f;
  1.3195 +}
  1.3196 +
  1.3197 +nsIFrame*
  1.3198 +nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame)
  1.3199 +{
  1.3200 +  if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
  1.3201 +      && !aFrame->GetPrevInFlow()) {
  1.3202 +    return aFrame->PresContext()->PresShell()->FrameManager()->
  1.3203 +      GetPlaceholderFrameFor(aFrame);
  1.3204 +  }
  1.3205 +  return aFrame->GetParent();
  1.3206 +}
  1.3207 +
  1.3208 +nsIFrame*
  1.3209 +nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(nsIFrame* aFrame)
  1.3210 +{
  1.3211 +  nsIFrame* f = GetParentOrPlaceholderFor(aFrame);
  1.3212 +  if (f)
  1.3213 +    return f;
  1.3214 +  return GetCrossDocParentFrame(aFrame);
  1.3215 +}
  1.3216 +
  1.3217 +nsIFrame*
  1.3218 +nsLayoutUtils::GetNextContinuationOrIBSplitSibling(nsIFrame *aFrame)
  1.3219 +{
  1.3220 +  nsIFrame *result = aFrame->GetNextContinuation();
  1.3221 +  if (result)
  1.3222 +    return result;
  1.3223 +
  1.3224 +  if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) != 0) {
  1.3225 +    // We only store the ib-split sibling annotation with the first
  1.3226 +    // frame in the continuation chain. Walk back to find that frame now.
  1.3227 +    aFrame = aFrame->FirstContinuation();
  1.3228 +
  1.3229 +    void* value = aFrame->Properties().Get(nsIFrame::IBSplitSibling());
  1.3230 +    return static_cast<nsIFrame*>(value);
  1.3231 +  }
  1.3232 +
  1.3233 +  return nullptr;
  1.3234 +}
  1.3235 +
  1.3236 +nsIFrame*
  1.3237 +nsLayoutUtils::FirstContinuationOrIBSplitSibling(nsIFrame *aFrame)
  1.3238 +{
  1.3239 +  nsIFrame *result = aFrame->FirstContinuation();
  1.3240 +  if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
  1.3241 +    while (true) {
  1.3242 +      nsIFrame *f = static_cast<nsIFrame*>
  1.3243 +        (result->Properties().Get(nsIFrame::IBSplitPrevSibling()));
  1.3244 +      if (!f)
  1.3245 +        break;
  1.3246 +      result = f;
  1.3247 +    }
  1.3248 +  }
  1.3249 +
  1.3250 +  return result;
  1.3251 +}
  1.3252 +
  1.3253 +bool
  1.3254 +nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(nsIFrame *aFrame)
  1.3255 +{
  1.3256 +  if (aFrame->GetPrevContinuation()) {
  1.3257 +    return false;
  1.3258 +  }
  1.3259 +  if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
  1.3260 +      aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling())) {
  1.3261 +    return false;
  1.3262 +  }
  1.3263 +
  1.3264 +  return true;
  1.3265 +}
  1.3266 +
  1.3267 +bool
  1.3268 +nsLayoutUtils::IsViewportScrollbarFrame(nsIFrame* aFrame)
  1.3269 +{
  1.3270 +  if (!aFrame)
  1.3271 +    return false;
  1.3272 +
  1.3273 +  nsIFrame* rootScrollFrame =
  1.3274 +    aFrame->PresContext()->PresShell()->GetRootScrollFrame();
  1.3275 +  if (!rootScrollFrame)
  1.3276 +    return false;
  1.3277 +
  1.3278 +  nsIScrollableFrame* rootScrollableFrame = do_QueryFrame(rootScrollFrame);
  1.3279 +  NS_ASSERTION(rootScrollableFrame, "The root scorollable frame is null");
  1.3280 +
  1.3281 +  if (!IsProperAncestorFrame(rootScrollFrame, aFrame))
  1.3282 +    return false;
  1.3283 +
  1.3284 +  nsIFrame* rootScrolledFrame = rootScrollableFrame->GetScrolledFrame();
  1.3285 +  return !(rootScrolledFrame == aFrame ||
  1.3286 +           IsProperAncestorFrame(rootScrolledFrame, aFrame));
  1.3287 +}
  1.3288 +
  1.3289 +static nscoord AddPercents(nsLayoutUtils::IntrinsicWidthType aType,
  1.3290 +                           nscoord aCurrent, float aPercent)
  1.3291 +{
  1.3292 +  nscoord result = aCurrent;
  1.3293 +  if (aPercent > 0.0f && aType == nsLayoutUtils::PREF_WIDTH) {
  1.3294 +    // XXX Should we also consider percentages for min widths, up to a
  1.3295 +    // limit?
  1.3296 +    if (aPercent >= 1.0f)
  1.3297 +      result = nscoord_MAX;
  1.3298 +    else
  1.3299 +      result = NSToCoordRound(float(result) / (1.0f - aPercent));
  1.3300 +  }
  1.3301 +  return result;
  1.3302 +}
  1.3303 +
  1.3304 +// Use only for widths/heights (or their min/max), since it clamps
  1.3305 +// negative calc() results to 0.
  1.3306 +static bool GetAbsoluteCoord(const nsStyleCoord& aStyle, nscoord& aResult)
  1.3307 +{
  1.3308 +  if (aStyle.IsCalcUnit()) {
  1.3309 +    if (aStyle.CalcHasPercent()) {
  1.3310 +      return false;
  1.3311 +    }
  1.3312 +    // If it has no percents, we can pass 0 for the percentage basis.
  1.3313 +    aResult = nsRuleNode::ComputeComputedCalc(aStyle, 0);
  1.3314 +    if (aResult < 0)
  1.3315 +      aResult = 0;
  1.3316 +    return true;
  1.3317 +  }
  1.3318 +
  1.3319 +  if (eStyleUnit_Coord != aStyle.GetUnit())
  1.3320 +    return false;
  1.3321 +
  1.3322 +  aResult = aStyle.GetCoordValue();
  1.3323 +  NS_ASSERTION(aResult >= 0, "negative widths not allowed");
  1.3324 +  return true;
  1.3325 +}
  1.3326 +
  1.3327 +// Only call on style coords for which GetAbsoluteCoord returned false.
  1.3328 +static bool
  1.3329 +GetPercentHeight(const nsStyleCoord& aStyle,
  1.3330 +                 nsIFrame* aFrame,
  1.3331 +                 nscoord& aResult)
  1.3332 +{
  1.3333 +  if (eStyleUnit_Percent != aStyle.GetUnit() &&
  1.3334 +      !aStyle.IsCalcUnit())
  1.3335 +    return false;
  1.3336 +
  1.3337 +  MOZ_ASSERT(!aStyle.IsCalcUnit() || aStyle.CalcHasPercent(),
  1.3338 +             "GetAbsoluteCoord should have handled this");
  1.3339 +
  1.3340 +  nsIFrame *f = aFrame->GetContainingBlock();
  1.3341 +  if (!f) {
  1.3342 +    NS_NOTREACHED("top of frame tree not a containing block");
  1.3343 +    return false;
  1.3344 +  }
  1.3345 +
  1.3346 +  // During reflow, nsHTMLScrollFrame::ReflowScrolledFrame uses
  1.3347 +  // SetComputedHeight on the reflow state for its child to propagate its
  1.3348 +  // computed height to the scrolled content. So here we skip to the scroll
  1.3349 +  // frame that contains this scrolled content in order to get the same
  1.3350 +  // behavior as layout when computing percentage heights.
  1.3351 +  if (f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
  1.3352 +    f = f->GetParent();
  1.3353 +  }
  1.3354 +
  1.3355 +  const nsStylePosition *pos = f->StylePosition();
  1.3356 +  nscoord h;
  1.3357 +  if (!GetAbsoluteCoord(pos->mHeight, h) &&
  1.3358 +      !GetPercentHeight(pos->mHeight, f, h)) {
  1.3359 +    NS_ASSERTION(pos->mHeight.GetUnit() == eStyleUnit_Auto ||
  1.3360 +                 pos->mHeight.HasPercent(),
  1.3361 +                 "unknown height unit");
  1.3362 +    nsIAtom* fType = f->GetType();
  1.3363 +    if (fType != nsGkAtoms::viewportFrame && fType != nsGkAtoms::canvasFrame &&
  1.3364 +        fType != nsGkAtoms::pageContentFrame) {
  1.3365 +      // There's no basis for the percentage height, so it acts like auto.
  1.3366 +      // Should we consider a max-height < min-height pair a basis for
  1.3367 +      // percentage heights?  The spec is somewhat unclear, and not doing
  1.3368 +      // so is simpler and avoids troubling discontinuities in behavior,
  1.3369 +      // so I'll choose not to. -LDB
  1.3370 +      return false;
  1.3371 +    }
  1.3372 +
  1.3373 +    NS_ASSERTION(pos->mHeight.GetUnit() == eStyleUnit_Auto,
  1.3374 +                 "Unexpected height unit for viewport or canvas or page-content");
  1.3375 +    // For the viewport, canvas, and page-content kids, the percentage
  1.3376 +    // basis is just the parent height.
  1.3377 +    h = f->GetSize().height;
  1.3378 +    if (h == NS_UNCONSTRAINEDSIZE) {
  1.3379 +      // We don't have a percentage basis after all
  1.3380 +      return false;
  1.3381 +    }
  1.3382 +  }
  1.3383 +
  1.3384 +  nscoord maxh;
  1.3385 +  if (GetAbsoluteCoord(pos->mMaxHeight, maxh) ||
  1.3386 +      GetPercentHeight(pos->mMaxHeight, f, maxh)) {
  1.3387 +    if (maxh < h)
  1.3388 +      h = maxh;
  1.3389 +  } else {
  1.3390 +    NS_ASSERTION(pos->mMaxHeight.GetUnit() == eStyleUnit_None ||
  1.3391 +                 pos->mMaxHeight.HasPercent(),
  1.3392 +                 "unknown max-height unit");
  1.3393 +  }
  1.3394 +
  1.3395 +  nscoord minh;
  1.3396 +  if (GetAbsoluteCoord(pos->mMinHeight, minh) ||
  1.3397 +      GetPercentHeight(pos->mMinHeight, f, minh)) {
  1.3398 +    if (minh > h)
  1.3399 +      h = minh;
  1.3400 +  } else {
  1.3401 +    NS_ASSERTION(pos->mMinHeight.HasPercent(),
  1.3402 +                 "unknown min-height unit");
  1.3403 +  }
  1.3404 +
  1.3405 +  if (aStyle.IsCalcUnit()) {
  1.3406 +    aResult = std::max(nsRuleNode::ComputeComputedCalc(aStyle, h), 0);
  1.3407 +    return true;
  1.3408 +  }
  1.3409 +
  1.3410 +  aResult = NSToCoordRound(aStyle.GetPercentValue() * h);
  1.3411 +  return true;
  1.3412 +}
  1.3413 +
  1.3414 +// Handles only -moz-max-content and -moz-min-content, and
  1.3415 +// -moz-fit-content for min-width and max-width, since the others
  1.3416 +// (-moz-fit-content for width, and -moz-available) have no effect on
  1.3417 +// intrinsic widths.
  1.3418 +enum eWidthProperty { PROP_WIDTH, PROP_MAX_WIDTH, PROP_MIN_WIDTH };
  1.3419 +static bool
  1.3420 +GetIntrinsicCoord(const nsStyleCoord& aStyle,
  1.3421 +                  nsRenderingContext* aRenderingContext,
  1.3422 +                  nsIFrame* aFrame,
  1.3423 +                  eWidthProperty aProperty,
  1.3424 +                  nscoord& aResult)
  1.3425 +{
  1.3426 +  NS_PRECONDITION(aProperty == PROP_WIDTH || aProperty == PROP_MAX_WIDTH ||
  1.3427 +                  aProperty == PROP_MIN_WIDTH, "unexpected property");
  1.3428 +  if (aStyle.GetUnit() != eStyleUnit_Enumerated)
  1.3429 +    return false;
  1.3430 +  int32_t val = aStyle.GetIntValue();
  1.3431 +  NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
  1.3432 +               val == NS_STYLE_WIDTH_MIN_CONTENT ||
  1.3433 +               val == NS_STYLE_WIDTH_FIT_CONTENT ||
  1.3434 +               val == NS_STYLE_WIDTH_AVAILABLE,
  1.3435 +               "unexpected enumerated value for width property");
  1.3436 +  if (val == NS_STYLE_WIDTH_AVAILABLE)
  1.3437 +    return false;
  1.3438 +  if (val == NS_STYLE_WIDTH_FIT_CONTENT) {
  1.3439 +    if (aProperty == PROP_WIDTH)
  1.3440 +      return false; // handle like 'width: auto'
  1.3441 +    if (aProperty == PROP_MAX_WIDTH)
  1.3442 +      // constrain large 'width' values down to -moz-max-content
  1.3443 +      val = NS_STYLE_WIDTH_MAX_CONTENT;
  1.3444 +    else
  1.3445 +      // constrain small 'width' or 'max-width' values up to -moz-min-content
  1.3446 +      val = NS_STYLE_WIDTH_MIN_CONTENT;
  1.3447 +  }
  1.3448 +
  1.3449 +  NS_ASSERTION(val == NS_STYLE_WIDTH_MAX_CONTENT ||
  1.3450 +               val == NS_STYLE_WIDTH_MIN_CONTENT,
  1.3451 +               "should have reduced everything remaining to one of these");
  1.3452 +
  1.3453 +  // If aFrame is a container for font size inflation, then shrink
  1.3454 +  // wrapping inside of it should not apply font size inflation.
  1.3455 +  AutoMaybeDisableFontInflation an(aFrame);
  1.3456 +
  1.3457 +  if (val == NS_STYLE_WIDTH_MAX_CONTENT)
  1.3458 +    aResult = aFrame->GetPrefWidth(aRenderingContext);
  1.3459 +  else
  1.3460 +    aResult = aFrame->GetMinWidth(aRenderingContext);
  1.3461 +  return true;
  1.3462 +}
  1.3463 +
  1.3464 +#undef  DEBUG_INTRINSIC_WIDTH
  1.3465 +
  1.3466 +#ifdef DEBUG_INTRINSIC_WIDTH
  1.3467 +static int32_t gNoiseIndent = 0;
  1.3468 +#endif
  1.3469 +
  1.3470 +/* static */ nscoord
  1.3471 +nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext,
  1.3472 +                                     nsIFrame *aFrame,
  1.3473 +                                     IntrinsicWidthType aType,
  1.3474 +                                     uint32_t aFlags)
  1.3475 +{
  1.3476 +  NS_PRECONDITION(aFrame, "null frame");
  1.3477 +  NS_PRECONDITION(aType == MIN_WIDTH || aType == PREF_WIDTH, "bad type");
  1.3478 +
  1.3479 +#ifdef DEBUG_INTRINSIC_WIDTH
  1.3480 +  nsFrame::IndentBy(stderr, gNoiseIndent);
  1.3481 +  static_cast<nsFrame*>(aFrame)->ListTag(stderr);
  1.3482 +  printf_stderr(" %s intrinsic width for container:\n",
  1.3483 +         aType == MIN_WIDTH ? "min" : "pref");
  1.3484 +#endif
  1.3485 +
  1.3486 +  // If aFrame is a container for font size inflation, then shrink
  1.3487 +  // wrapping inside of it should not apply font size inflation.
  1.3488 +  AutoMaybeDisableFontInflation an(aFrame);
  1.3489 +
  1.3490 +  nsIFrame::IntrinsicWidthOffsetData offsets =
  1.3491 +    aFrame->IntrinsicWidthOffsets(aRenderingContext);
  1.3492 +
  1.3493 +  const nsStylePosition *stylePos = aFrame->StylePosition();
  1.3494 +  uint8_t boxSizing = stylePos->mBoxSizing;
  1.3495 +  const nsStyleCoord &styleWidth = stylePos->mWidth;
  1.3496 +  const nsStyleCoord &styleMinWidth = stylePos->mMinWidth;
  1.3497 +  const nsStyleCoord &styleMaxWidth = stylePos->mMaxWidth;
  1.3498 +
  1.3499 +  // We build up two values starting with the content box, and then
  1.3500 +  // adding padding, border and margin.  The result is normally
  1.3501 +  // |result|.  Then, when we handle 'width', 'min-width', and
  1.3502 +  // 'max-width', we use the results we've been building in |min| as a
  1.3503 +  // minimum, overriding 'min-width'.  This ensures two things:
  1.3504 +  //   * that we don't let a value of 'box-sizing' specifying a width
  1.3505 +  //     smaller than the padding/border inside the box-sizing box give
  1.3506 +  //     a content width less than zero
  1.3507 +  //   * that we prevent tables from becoming smaller than their
  1.3508 +  //     intrinsic minimum width
  1.3509 +  nscoord result = 0, min = 0;
  1.3510 +
  1.3511 +  nscoord maxw;
  1.3512 +  bool haveFixedMaxWidth = GetAbsoluteCoord(styleMaxWidth, maxw);
  1.3513 +  nscoord minw;
  1.3514 +  bool haveFixedMinWidth = GetAbsoluteCoord(styleMinWidth, minw);
  1.3515 +
  1.3516 +  // If we have a specified width (or a specified 'min-width' greater
  1.3517 +  // than the specified 'max-width', which works out to the same thing),
  1.3518 +  // don't even bother getting the frame's intrinsic width, because in
  1.3519 +  // this case GetAbsoluteCoord(styleWidth, w) will always succeed, so
  1.3520 +  // we'll never need the intrinsic dimensions.
  1.3521 +  if (styleWidth.GetUnit() == eStyleUnit_Enumerated &&
  1.3522 +      (styleWidth.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
  1.3523 +       styleWidth.GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT)) {
  1.3524 +    // -moz-fit-content and -moz-available enumerated widths compute intrinsic
  1.3525 +    // widths just like auto.
  1.3526 +    // For -moz-max-content and -moz-min-content, we handle them like
  1.3527 +    // specified widths, but ignore box-sizing.
  1.3528 +    boxSizing = NS_STYLE_BOX_SIZING_CONTENT;
  1.3529 +  } else if (!styleWidth.ConvertsToLength() &&
  1.3530 +             !(haveFixedMinWidth && haveFixedMaxWidth && maxw <= minw)) {
  1.3531 +#ifdef DEBUG_INTRINSIC_WIDTH
  1.3532 +    ++gNoiseIndent;
  1.3533 +#endif
  1.3534 +    if (aType == MIN_WIDTH)
  1.3535 +      result = aFrame->GetMinWidth(aRenderingContext);
  1.3536 +    else
  1.3537 +      result = aFrame->GetPrefWidth(aRenderingContext);
  1.3538 +#ifdef DEBUG_INTRINSIC_WIDTH
  1.3539 +    --gNoiseIndent;
  1.3540 +    nsFrame::IndentBy(stderr, gNoiseIndent);
  1.3541 +    static_cast<nsFrame*>(aFrame)->ListTag(stderr);
  1.3542 +    printf_stderr(" %s intrinsic width from frame is %d.\n",
  1.3543 +           aType == MIN_WIDTH ? "min" : "pref", result);
  1.3544 +#endif
  1.3545 +
  1.3546 +    // Handle elements with an intrinsic ratio (or size) and a specified
  1.3547 +    // height, min-height, or max-height.
  1.3548 +    const nsStyleCoord &styleHeight = stylePos->mHeight;
  1.3549 +    const nsStyleCoord &styleMinHeight = stylePos->mMinHeight;
  1.3550 +    const nsStyleCoord &styleMaxHeight = stylePos->mMaxHeight;
  1.3551 +    if (styleHeight.GetUnit() != eStyleUnit_Auto ||
  1.3552 +        !(styleMinHeight.GetUnit() == eStyleUnit_Coord &&
  1.3553 +          styleMinHeight.GetCoordValue() == 0) ||
  1.3554 +        styleMaxHeight.GetUnit() != eStyleUnit_None) {
  1.3555 +
  1.3556 +      nsSize ratio = aFrame->GetIntrinsicRatio();
  1.3557 +
  1.3558 +      if (ratio.height != 0) {
  1.3559 +        nscoord heightTakenByBoxSizing = 0;
  1.3560 +        switch (boxSizing) {
  1.3561 +        case NS_STYLE_BOX_SIZING_BORDER: {
  1.3562 +          const nsStyleBorder* styleBorder = aFrame->StyleBorder();
  1.3563 +          heightTakenByBoxSizing +=
  1.3564 +            styleBorder->GetComputedBorder().TopBottom();
  1.3565 +          // fall through
  1.3566 +        }
  1.3567 +        case NS_STYLE_BOX_SIZING_PADDING: {
  1.3568 +          if (!(aFlags & IGNORE_PADDING)) {
  1.3569 +            const nsStylePadding* stylePadding = aFrame->StylePadding();
  1.3570 +            nscoord pad;
  1.3571 +            if (GetAbsoluteCoord(stylePadding->mPadding.GetTop(), pad) ||
  1.3572 +                GetPercentHeight(stylePadding->mPadding.GetTop(), aFrame, pad)) {
  1.3573 +              heightTakenByBoxSizing += pad;
  1.3574 +            }
  1.3575 +            if (GetAbsoluteCoord(stylePadding->mPadding.GetBottom(), pad) ||
  1.3576 +                GetPercentHeight(stylePadding->mPadding.GetBottom(), aFrame, pad)) {
  1.3577 +              heightTakenByBoxSizing += pad;
  1.3578 +            }
  1.3579 +          }
  1.3580 +          // fall through
  1.3581 +        }
  1.3582 +        case NS_STYLE_BOX_SIZING_CONTENT:
  1.3583 +        default:
  1.3584 +          break;
  1.3585 +        }
  1.3586 +
  1.3587 +        nscoord h;
  1.3588 +        if (GetAbsoluteCoord(styleHeight, h) ||
  1.3589 +            GetPercentHeight(styleHeight, aFrame, h)) {
  1.3590 +          h = std::max(0, h - heightTakenByBoxSizing);
  1.3591 +          result =
  1.3592 +            NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
  1.3593 +        }
  1.3594 +
  1.3595 +        if (GetAbsoluteCoord(styleMaxHeight, h) ||
  1.3596 +            GetPercentHeight(styleMaxHeight, aFrame, h)) {
  1.3597 +          h = std::max(0, h - heightTakenByBoxSizing);
  1.3598 +          nscoord maxWidth =
  1.3599 +            NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
  1.3600 +          if (maxWidth < result)
  1.3601 +            result = maxWidth;
  1.3602 +        }
  1.3603 +
  1.3604 +        if (GetAbsoluteCoord(styleMinHeight, h) ||
  1.3605 +            GetPercentHeight(styleMinHeight, aFrame, h)) {
  1.3606 +          h = std::max(0, h - heightTakenByBoxSizing);
  1.3607 +          nscoord minWidth =
  1.3608 +            NSToCoordRound(h * (float(ratio.width) / float(ratio.height)));
  1.3609 +          if (minWidth > result)
  1.3610 +            result = minWidth;
  1.3611 +        }
  1.3612 +      }
  1.3613 +    }
  1.3614 +  }
  1.3615 +
  1.3616 +  if (aFrame->GetType() == nsGkAtoms::tableFrame) {
  1.3617 +    // Tables can't shrink smaller than their intrinsic minimum width,
  1.3618 +    // no matter what.
  1.3619 +    min = aFrame->GetMinWidth(aRenderingContext);
  1.3620 +  }
  1.3621 +
  1.3622 +  // We also need to track what has been added on outside of the box
  1.3623 +  // (controlled by 'box-sizing') where 'width', 'min-width' and
  1.3624 +  // 'max-width' are applied.  We have to account for these properties
  1.3625 +  // after getting all the offsets (margin, border, padding) because
  1.3626 +  // percentages do not operate linearly.
  1.3627 +  // Doing this is ok because although percentages aren't handled
  1.3628 +  // linearly, they are handled monotonically.
  1.3629 +  nscoord coordOutsideWidth = 0;
  1.3630 +  float pctOutsideWidth = 0;
  1.3631 +  float pctTotal = 0.0f;
  1.3632 +
  1.3633 +  if (!(aFlags & IGNORE_PADDING)) {
  1.3634 +    coordOutsideWidth += offsets.hPadding;
  1.3635 +    pctOutsideWidth += offsets.hPctPadding;
  1.3636 +
  1.3637 +    if (boxSizing == NS_STYLE_BOX_SIZING_PADDING) {
  1.3638 +      min += coordOutsideWidth;
  1.3639 +      result = NSCoordSaturatingAdd(result, coordOutsideWidth);
  1.3640 +      pctTotal += pctOutsideWidth;
  1.3641 +
  1.3642 +      coordOutsideWidth = 0;
  1.3643 +      pctOutsideWidth = 0.0f;
  1.3644 +    }
  1.3645 +  }
  1.3646 +
  1.3647 +  coordOutsideWidth += offsets.hBorder;
  1.3648 +
  1.3649 +  if (boxSizing == NS_STYLE_BOX_SIZING_BORDER) {
  1.3650 +    min += coordOutsideWidth;
  1.3651 +    result = NSCoordSaturatingAdd(result, coordOutsideWidth);
  1.3652 +    pctTotal += pctOutsideWidth;
  1.3653 +
  1.3654 +    coordOutsideWidth = 0;
  1.3655 +    pctOutsideWidth = 0.0f;
  1.3656 +  }
  1.3657 +
  1.3658 +  coordOutsideWidth += offsets.hMargin;
  1.3659 +  pctOutsideWidth += offsets.hPctMargin;
  1.3660 +
  1.3661 +  min += coordOutsideWidth;
  1.3662 +  result = NSCoordSaturatingAdd(result, coordOutsideWidth);
  1.3663 +  pctTotal += pctOutsideWidth;
  1.3664 +
  1.3665 +  nscoord w;
  1.3666 +  if (GetAbsoluteCoord(styleWidth, w) ||
  1.3667 +      GetIntrinsicCoord(styleWidth, aRenderingContext, aFrame,
  1.3668 +                        PROP_WIDTH, w)) {
  1.3669 +    result = AddPercents(aType, w + coordOutsideWidth, pctOutsideWidth);
  1.3670 +  }
  1.3671 +  else if (aType == MIN_WIDTH &&
  1.3672 +           // The only cases of coord-percent-calc() units that
  1.3673 +           // GetAbsoluteCoord didn't handle are percent and calc()s
  1.3674 +           // containing percent.
  1.3675 +           styleWidth.IsCoordPercentCalcUnit() &&
  1.3676 +           aFrame->IsFrameOfType(nsIFrame::eReplaced)) {
  1.3677 +    // A percentage width on replaced elements means they can shrink to 0.
  1.3678 +    result = 0; // let |min| handle padding/border/margin
  1.3679 +  }
  1.3680 +  else {
  1.3681 +    // NOTE: We could really do a lot better for percents and for some
  1.3682 +    // cases of calc() containing percent (certainly including any where
  1.3683 +    // the coefficient on the percent is positive and there are no max()
  1.3684 +    // expressions).  However, doing better for percents wouldn't be
  1.3685 +    // backwards compatible.
  1.3686 +    result = AddPercents(aType, result, pctTotal);
  1.3687 +  }
  1.3688 +
  1.3689 +  if (haveFixedMaxWidth ||
  1.3690 +      GetIntrinsicCoord(styleMaxWidth, aRenderingContext, aFrame,
  1.3691 +                        PROP_MAX_WIDTH, maxw)) {
  1.3692 +    maxw = AddPercents(aType, maxw + coordOutsideWidth, pctOutsideWidth);
  1.3693 +    if (result > maxw)
  1.3694 +      result = maxw;
  1.3695 +  }
  1.3696 +
  1.3697 +  if (haveFixedMinWidth ||
  1.3698 +      GetIntrinsicCoord(styleMinWidth, aRenderingContext, aFrame,
  1.3699 +                        PROP_MIN_WIDTH, minw)) {
  1.3700 +    minw = AddPercents(aType, minw + coordOutsideWidth, pctOutsideWidth);
  1.3701 +    if (result < minw)
  1.3702 +      result = minw;
  1.3703 +  }
  1.3704 +
  1.3705 +  min = AddPercents(aType, min, pctTotal);
  1.3706 +  if (result < min)
  1.3707 +    result = min;
  1.3708 +
  1.3709 +  const nsStyleDisplay *disp = aFrame->StyleDisplay();
  1.3710 +  if (aFrame->IsThemed(disp)) {
  1.3711 +    nsIntSize size(0, 0);
  1.3712 +    bool canOverride = true;
  1.3713 +    nsPresContext *presContext = aFrame->PresContext();
  1.3714 +    presContext->GetTheme()->
  1.3715 +      GetMinimumWidgetSize(aRenderingContext, aFrame, disp->mAppearance,
  1.3716 +                           &size, &canOverride);
  1.3717 +
  1.3718 +    nscoord themeWidth = presContext->DevPixelsToAppUnits(size.width);
  1.3719 +
  1.3720 +    // GMWS() returns a border-box width
  1.3721 +    themeWidth += offsets.hMargin;
  1.3722 +    themeWidth = AddPercents(aType, themeWidth, offsets.hPctMargin);
  1.3723 +
  1.3724 +    if (themeWidth > result || !canOverride)
  1.3725 +      result = themeWidth;
  1.3726 +  }
  1.3727 +
  1.3728 +#ifdef DEBUG_INTRINSIC_WIDTH
  1.3729 +  nsFrame::IndentBy(stderr, gNoiseIndent);
  1.3730 +  static_cast<nsFrame*>(aFrame)->ListTag(stderr);
  1.3731 +  printf_stderr(" %s intrinsic width for container is %d twips.\n",
  1.3732 +         aType == MIN_WIDTH ? "min" : "pref", result);
  1.3733 +#endif
  1.3734 +
  1.3735 +  return result;
  1.3736 +}
  1.3737 +
  1.3738 +/* static */ nscoord
  1.3739 +nsLayoutUtils::ComputeCBDependentValue(nscoord aPercentBasis,
  1.3740 +                                       const nsStyleCoord& aCoord)
  1.3741 +{
  1.3742 +  NS_WARN_IF_FALSE(aPercentBasis != NS_UNCONSTRAINEDSIZE,
  1.3743 +                   "have unconstrained width or height; this should only "
  1.3744 +                   "result from very large sizes, not attempts at intrinsic "
  1.3745 +                   "size calculation");
  1.3746 +
  1.3747 +  if (aCoord.IsCoordPercentCalcUnit()) {
  1.3748 +    return nsRuleNode::ComputeCoordPercentCalc(aCoord, aPercentBasis);
  1.3749 +  }
  1.3750 +  NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
  1.3751 +               aCoord.GetUnit() == eStyleUnit_Auto,
  1.3752 +               "unexpected width value");
  1.3753 +  return 0;
  1.3754 +}
  1.3755 +
  1.3756 +/* static */ nscoord
  1.3757 +nsLayoutUtils::ComputeWidthValue(
  1.3758 +                 nsRenderingContext* aRenderingContext,
  1.3759 +                 nsIFrame*            aFrame,
  1.3760 +                 nscoord              aContainingBlockWidth,
  1.3761 +                 nscoord              aContentEdgeToBoxSizing,
  1.3762 +                 nscoord              aBoxSizingToMarginEdge,
  1.3763 +                 const nsStyleCoord&  aCoord)
  1.3764 +{
  1.3765 +  NS_PRECONDITION(aFrame, "non-null frame expected");
  1.3766 +  NS_PRECONDITION(aRenderingContext, "non-null rendering context expected");
  1.3767 +  NS_WARN_IF_FALSE(aContainingBlockWidth != NS_UNCONSTRAINEDSIZE,
  1.3768 +                   "have unconstrained width; this should only result from "
  1.3769 +                   "very large sizes, not attempts at intrinsic width "
  1.3770 +                   "calculation");
  1.3771 +  NS_PRECONDITION(aContainingBlockWidth >= 0,
  1.3772 +                  "width less than zero");
  1.3773 +
  1.3774 +  nscoord result;
  1.3775 +  if (aCoord.IsCoordPercentCalcUnit()) {
  1.3776 +    result = nsRuleNode::ComputeCoordPercentCalc(aCoord, 
  1.3777 +                                                 aContainingBlockWidth);
  1.3778 +    // The result of a calc() expression might be less than 0; we
  1.3779 +    // should clamp at runtime (below).  (Percentages and coords that
  1.3780 +    // are less than 0 have already been dropped by the parser.)
  1.3781 +    result -= aContentEdgeToBoxSizing;
  1.3782 +  } else {
  1.3783 +    MOZ_ASSERT(eStyleUnit_Enumerated == aCoord.GetUnit());
  1.3784 +    // If aFrame is a container for font size inflation, then shrink
  1.3785 +    // wrapping inside of it should not apply font size inflation.
  1.3786 +    AutoMaybeDisableFontInflation an(aFrame);
  1.3787 +
  1.3788 +    int32_t val = aCoord.GetIntValue();
  1.3789 +    switch (val) {
  1.3790 +      case NS_STYLE_WIDTH_MAX_CONTENT:
  1.3791 +        result = aFrame->GetPrefWidth(aRenderingContext);
  1.3792 +        NS_ASSERTION(result >= 0, "width less than zero");
  1.3793 +        break;
  1.3794 +      case NS_STYLE_WIDTH_MIN_CONTENT:
  1.3795 +        result = aFrame->GetMinWidth(aRenderingContext);
  1.3796 +        NS_ASSERTION(result >= 0, "width less than zero");
  1.3797 +        break;
  1.3798 +      case NS_STYLE_WIDTH_FIT_CONTENT:
  1.3799 +        {
  1.3800 +          nscoord pref = aFrame->GetPrefWidth(aRenderingContext),
  1.3801 +                   min = aFrame->GetMinWidth(aRenderingContext),
  1.3802 +                  fill = aContainingBlockWidth -
  1.3803 +                         (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
  1.3804 +          result = std::max(min, std::min(pref, fill));
  1.3805 +          NS_ASSERTION(result >= 0, "width less than zero");
  1.3806 +        }
  1.3807 +        break;
  1.3808 +      case NS_STYLE_WIDTH_AVAILABLE:
  1.3809 +        result = aContainingBlockWidth -
  1.3810 +                 (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
  1.3811 +    }
  1.3812 +  }
  1.3813 +
  1.3814 +  return std::max(0, result);
  1.3815 +}
  1.3816 +
  1.3817 +/* static */ nscoord
  1.3818 +nsLayoutUtils::ComputeHeightDependentValue(
  1.3819 +                 nscoord              aContainingBlockHeight,
  1.3820 +                 const nsStyleCoord&  aCoord)
  1.3821 +{
  1.3822 +  // XXXldb Some callers explicitly check aContainingBlockHeight
  1.3823 +  // against NS_AUTOHEIGHT *and* unit against eStyleUnit_Percent or
  1.3824 +  // calc()s containing percents before calling this function.
  1.3825 +  // However, it would be much more likely to catch problems without
  1.3826 +  // the unit conditions.
  1.3827 +  // XXXldb Many callers pass a non-'auto' containing block height when
  1.3828 +  // according to CSS2.1 they should be passing 'auto'.
  1.3829 +  NS_PRECONDITION(NS_AUTOHEIGHT != aContainingBlockHeight ||
  1.3830 +                  !aCoord.HasPercent(),
  1.3831 +                  "unexpected containing block height");
  1.3832 +
  1.3833 +  if (aCoord.IsCoordPercentCalcUnit()) {
  1.3834 +    return nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockHeight);
  1.3835 +  }
  1.3836 +
  1.3837 +  NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
  1.3838 +               aCoord.GetUnit() == eStyleUnit_Auto,
  1.3839 +               "unexpected height value");
  1.3840 +  return 0;
  1.3841 +}
  1.3842 +
  1.3843 +/* static */ void
  1.3844 +nsLayoutUtils::MarkDescendantsDirty(nsIFrame *aSubtreeRoot)
  1.3845 +{
  1.3846 +  nsAutoTArray<nsIFrame*, 4> subtrees;
  1.3847 +  subtrees.AppendElement(aSubtreeRoot);
  1.3848 +
  1.3849 +  // dirty descendants, iterating over subtrees that may include
  1.3850 +  // additional subtrees associated with placeholders
  1.3851 +  do {
  1.3852 +    nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
  1.3853 +    subtrees.RemoveElementAt(subtrees.Length() - 1);
  1.3854 +
  1.3855 +    // Mark all descendants dirty (using an nsTArray stack rather than
  1.3856 +    // recursion).
  1.3857 +    // Note that nsHTMLReflowState::InitResizeFlags has some similar
  1.3858 +    // code; see comments there for how and why it differs.
  1.3859 +    nsAutoTArray<nsIFrame*, 32> stack;
  1.3860 +    stack.AppendElement(subtreeRoot);
  1.3861 +
  1.3862 +    do {
  1.3863 +      nsIFrame *f = stack.ElementAt(stack.Length() - 1);
  1.3864 +      stack.RemoveElementAt(stack.Length() - 1);
  1.3865 +
  1.3866 +      f->MarkIntrinsicWidthsDirty();
  1.3867 +
  1.3868 +      if (f->GetType() == nsGkAtoms::placeholderFrame) {
  1.3869 +        nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
  1.3870 +        if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
  1.3871 +          // We have another distinct subtree we need to mark.
  1.3872 +          subtrees.AppendElement(oof);
  1.3873 +        }
  1.3874 +      }
  1.3875 +
  1.3876 +      nsIFrame::ChildListIterator lists(f);
  1.3877 +      for (; !lists.IsDone(); lists.Next()) {
  1.3878 +        nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.3879 +        for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.3880 +          nsIFrame* kid = childFrames.get();
  1.3881 +          stack.AppendElement(kid);
  1.3882 +        }
  1.3883 +      }
  1.3884 +    } while (stack.Length() != 0);
  1.3885 +  } while (subtrees.Length() != 0);
  1.3886 +}
  1.3887 +
  1.3888 +#define MULDIV(a,b,c) (nscoord(int64_t(a) * int64_t(b) / int64_t(c)))
  1.3889 +
  1.3890 +/* static */ nsSize
  1.3891 +nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
  1.3892 +                   nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
  1.3893 +                   const IntrinsicSize& aIntrinsicSize,
  1.3894 +                   nsSize aIntrinsicRatio, nsSize aCBSize,
  1.3895 +                   nsSize aMargin, nsSize aBorder, nsSize aPadding)
  1.3896 +{
  1.3897 +  const nsStylePosition* stylePos = aFrame->StylePosition();
  1.3898 +
  1.3899 +  // If we're a flex item, we'll compute our size a bit differently.
  1.3900 +  const nsStyleCoord* widthStyleCoord = &(stylePos->mWidth);
  1.3901 +  const nsStyleCoord* heightStyleCoord = &(stylePos->mHeight);
  1.3902 +
  1.3903 +  bool isFlexItem = aFrame->IsFlexItem();
  1.3904 +  bool isHorizontalFlexItem = false;
  1.3905 +
  1.3906 +  if (isFlexItem) {
  1.3907 +    // Flex items use their "flex-basis" property in place of their main-size
  1.3908 +    // property (e.g. "width") for sizing purposes, *unless* they have
  1.3909 +    // "flex-basis:auto", in which case they use their main-size property after
  1.3910 +    // all.
  1.3911 +    uint32_t flexDirection =
  1.3912 +      aFrame->GetParent()->StylePosition()->mFlexDirection;
  1.3913 +    isHorizontalFlexItem =
  1.3914 +      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
  1.3915 +      flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
  1.3916 +
  1.3917 +    // NOTE: The logic here should match the similar chunk for determining
  1.3918 +    // widthStyleCoord and heightStyleCoord in nsFrame::ComputeSize().
  1.3919 +    const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
  1.3920 +    if (flexBasis->GetUnit() != eStyleUnit_Auto) {
  1.3921 +      if (isHorizontalFlexItem) {
  1.3922 +        widthStyleCoord = flexBasis;
  1.3923 +      } else {
  1.3924 +        // One caveat for vertical flex items: We don't support enumerated
  1.3925 +        // values (e.g. "max-content") for height properties yet. So, if our
  1.3926 +        // computed flex-basis is an enumerated value, we'll just behave as if
  1.3927 +        // it were "auto", which means "use the main-size property after all"
  1.3928 +        // (which is "height", in this case).
  1.3929 +        // NOTE: Once we support intrinsic sizing keywords for "height",
  1.3930 +        // we should remove this check.
  1.3931 +        if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
  1.3932 +          heightStyleCoord = flexBasis;
  1.3933 +        }
  1.3934 +      }
  1.3935 +    }
  1.3936 +  }
  1.3937 +
  1.3938 +  // Handle intrinsic sizes and their interaction with
  1.3939 +  // {min-,max-,}{width,height} according to the rules in
  1.3940 +  // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
  1.3941 +
  1.3942 +  // Note: throughout the following section of the function, I avoid
  1.3943 +  // a * (b / c) because of its reduced accuracy relative to a * b / c
  1.3944 +  // or (a * b) / c (which are equivalent).
  1.3945 +
  1.3946 +  const bool isAutoWidth = widthStyleCoord->GetUnit() == eStyleUnit_Auto;
  1.3947 +  const bool isAutoHeight = IsAutoHeight(*heightStyleCoord, aCBSize.height);
  1.3948 +
  1.3949 +  nsSize boxSizingAdjust(0,0);
  1.3950 +  switch (stylePos->mBoxSizing) {
  1.3951 +    case NS_STYLE_BOX_SIZING_BORDER:
  1.3952 +      boxSizingAdjust += aBorder;
  1.3953 +      // fall through
  1.3954 +    case NS_STYLE_BOX_SIZING_PADDING:
  1.3955 +      boxSizingAdjust += aPadding;
  1.3956 +  }
  1.3957 +  nscoord boxSizingToMarginEdgeWidth =
  1.3958 +    aMargin.width + aBorder.width + aPadding.width - boxSizingAdjust.width;
  1.3959 +
  1.3960 +  nscoord width, minWidth, maxWidth, height, minHeight, maxHeight;
  1.3961 +
  1.3962 +  if (!isAutoWidth) {
  1.3963 +    width = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
  1.3964 +              aFrame, aCBSize.width, boxSizingAdjust.width,
  1.3965 +              boxSizingToMarginEdgeWidth, *widthStyleCoord);
  1.3966 +  }
  1.3967 +
  1.3968 +  if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None &&
  1.3969 +      !(isFlexItem && isHorizontalFlexItem)) {
  1.3970 +    maxWidth = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
  1.3971 +                 aFrame, aCBSize.width, boxSizingAdjust.width,
  1.3972 +                 boxSizingToMarginEdgeWidth, stylePos->mMaxWidth);
  1.3973 +  } else {
  1.3974 +    // NOTE: Flex items ignore their min & max sizing properties in their
  1.3975 +    // flex container's main-axis.  (Those properties get applied later in
  1.3976 +    // the flexbox algorithm.)
  1.3977 +    maxWidth = nscoord_MAX;
  1.3978 +  }
  1.3979 +
  1.3980 +  if (!(isFlexItem && isHorizontalFlexItem)) {
  1.3981 +    minWidth = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
  1.3982 +                 aFrame, aCBSize.width, boxSizingAdjust.width,
  1.3983 +                 boxSizingToMarginEdgeWidth, stylePos->mMinWidth);
  1.3984 +  } else {
  1.3985 +    // NOTE: Flex items ignore their min & max sizing properties in their
  1.3986 +    // flex container's main-axis.  (Those properties get applied later in
  1.3987 +    // the flexbox algorithm.)
  1.3988 +    minWidth = 0;
  1.3989 +  }
  1.3990 +
  1.3991 +  if (!isAutoHeight) {
  1.3992 +    height = nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.3993 +                boxSizingAdjust.height, 
  1.3994 +                *heightStyleCoord);
  1.3995 +  }
  1.3996 +
  1.3997 +  if (!IsAutoHeight(stylePos->mMaxHeight, aCBSize.height) &&
  1.3998 +      !(isFlexItem && !isHorizontalFlexItem)) {
  1.3999 +    maxHeight = nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.4000 +                  boxSizingAdjust.height, 
  1.4001 +                  stylePos->mMaxHeight);
  1.4002 +  } else {
  1.4003 +    maxHeight = nscoord_MAX;
  1.4004 +  }
  1.4005 +
  1.4006 +  if (!IsAutoHeight(stylePos->mMinHeight, aCBSize.height) &&
  1.4007 +      !(isFlexItem && !isHorizontalFlexItem)) {
  1.4008 +    minHeight = nsLayoutUtils::ComputeHeightValue(aCBSize.height, 
  1.4009 +                  boxSizingAdjust.height,
  1.4010 +                  stylePos->mMinHeight);
  1.4011 +  } else {
  1.4012 +    minHeight = 0;
  1.4013 +  }
  1.4014 +
  1.4015 +  // Resolve percentage intrinsic width/height as necessary:
  1.4016 +
  1.4017 +  NS_ASSERTION(aCBSize.width != NS_UNCONSTRAINEDSIZE,
  1.4018 +               "Our containing block must not have unconstrained width!");
  1.4019 +
  1.4020 +  bool hasIntrinsicWidth, hasIntrinsicHeight;
  1.4021 +  nscoord intrinsicWidth, intrinsicHeight;
  1.4022 +
  1.4023 +  if (aIntrinsicSize.width.GetUnit() == eStyleUnit_Coord) {
  1.4024 +    hasIntrinsicWidth = true;
  1.4025 +    intrinsicWidth = aIntrinsicSize.width.GetCoordValue();
  1.4026 +    if (intrinsicWidth < 0)
  1.4027 +      intrinsicWidth = 0;
  1.4028 +  } else {
  1.4029 +    NS_ASSERTION(aIntrinsicSize.width.GetUnit() == eStyleUnit_None,
  1.4030 +                 "unexpected unit");
  1.4031 +    hasIntrinsicWidth = false;
  1.4032 +    intrinsicWidth = 0;
  1.4033 +  }
  1.4034 +
  1.4035 +  if (aIntrinsicSize.height.GetUnit() == eStyleUnit_Coord) {
  1.4036 +    hasIntrinsicHeight = true;
  1.4037 +    intrinsicHeight = aIntrinsicSize.height.GetCoordValue();
  1.4038 +    if (intrinsicHeight < 0)
  1.4039 +      intrinsicHeight = 0;
  1.4040 +  } else {
  1.4041 +    NS_ASSERTION(aIntrinsicSize.height.GetUnit() == eStyleUnit_None,
  1.4042 +                 "unexpected unit");
  1.4043 +    hasIntrinsicHeight = false;
  1.4044 +    intrinsicHeight = 0;
  1.4045 +  }
  1.4046 +
  1.4047 +  NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0,
  1.4048 +               "Intrinsic ratio has a negative component!");
  1.4049 +
  1.4050 +  // Now calculate the used values for width and height:
  1.4051 +
  1.4052 +  if (isAutoWidth) {
  1.4053 +    if (isAutoHeight) {
  1.4054 +
  1.4055 +      // 'auto' width, 'auto' height
  1.4056 +
  1.4057 +      // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2:
  1.4058 +
  1.4059 +      nscoord tentWidth, tentHeight;
  1.4060 +
  1.4061 +      if (hasIntrinsicWidth) {
  1.4062 +        tentWidth = intrinsicWidth;
  1.4063 +      } else if (hasIntrinsicHeight && aIntrinsicRatio.height > 0) {
  1.4064 +        tentWidth = MULDIV(intrinsicHeight, aIntrinsicRatio.width, aIntrinsicRatio.height);
  1.4065 +      } else if (aIntrinsicRatio.width > 0) {
  1.4066 +        tentWidth = aCBSize.width - boxSizingToMarginEdgeWidth; // XXX scrollbar?
  1.4067 +        if (tentWidth < 0) tentWidth = 0;
  1.4068 +      } else {
  1.4069 +        tentWidth = nsPresContext::CSSPixelsToAppUnits(300);
  1.4070 +      }
  1.4071 +
  1.4072 +      if (hasIntrinsicHeight) {
  1.4073 +        tentHeight = intrinsicHeight;
  1.4074 +      } else if (aIntrinsicRatio.width > 0) {
  1.4075 +        tentHeight = MULDIV(tentWidth, aIntrinsicRatio.height, aIntrinsicRatio.width);
  1.4076 +      } else {
  1.4077 +        tentHeight = nsPresContext::CSSPixelsToAppUnits(150);
  1.4078 +      }
  1.4079 +
  1.4080 +      return ComputeAutoSizeWithIntrinsicDimensions(minWidth, minHeight,
  1.4081 +                                                    maxWidth, maxHeight,
  1.4082 +                                                    tentWidth, tentHeight);
  1.4083 +    } else {
  1.4084 +
  1.4085 +      // 'auto' width, non-'auto' height
  1.4086 +      height = NS_CSS_MINMAX(height, minHeight, maxHeight);
  1.4087 +      if (aIntrinsicRatio.height > 0) {
  1.4088 +        width = MULDIV(height, aIntrinsicRatio.width, aIntrinsicRatio.height);
  1.4089 +      } else if (hasIntrinsicWidth) {
  1.4090 +        width = intrinsicWidth;
  1.4091 +      } else {
  1.4092 +        width = nsPresContext::CSSPixelsToAppUnits(300);
  1.4093 +      }
  1.4094 +      width = NS_CSS_MINMAX(width, minWidth, maxWidth);
  1.4095 +
  1.4096 +    }
  1.4097 +  } else {
  1.4098 +    if (isAutoHeight) {
  1.4099 +
  1.4100 +      // non-'auto' width, 'auto' height
  1.4101 +      width = NS_CSS_MINMAX(width, minWidth, maxWidth);
  1.4102 +      if (aIntrinsicRatio.width > 0) {
  1.4103 +        height = MULDIV(width, aIntrinsicRatio.height, aIntrinsicRatio.width);
  1.4104 +      } else if (hasIntrinsicHeight) {
  1.4105 +        height = intrinsicHeight;
  1.4106 +      } else {
  1.4107 +        height = nsPresContext::CSSPixelsToAppUnits(150);
  1.4108 +      }
  1.4109 +      height = NS_CSS_MINMAX(height, minHeight, maxHeight);
  1.4110 +
  1.4111 +    } else {
  1.4112 +
  1.4113 +      // non-'auto' width, non-'auto' height
  1.4114 +      width = NS_CSS_MINMAX(width, minWidth, maxWidth);
  1.4115 +      height = NS_CSS_MINMAX(height, minHeight, maxHeight);
  1.4116 +
  1.4117 +    }
  1.4118 +  }
  1.4119 +
  1.4120 +  return nsSize(width, height);
  1.4121 +}
  1.4122 +
  1.4123 +nsSize
  1.4124 +nsLayoutUtils::ComputeAutoSizeWithIntrinsicDimensions(nscoord minWidth, nscoord minHeight,
  1.4125 +                                                      nscoord maxWidth, nscoord maxHeight,
  1.4126 +                                                      nscoord tentWidth, nscoord tentHeight)
  1.4127 +{
  1.4128 +  // Now apply min/max-width/height - CSS 2.1 sections 10.4 and 10.7:
  1.4129 +
  1.4130 +  if (minWidth > maxWidth)
  1.4131 +    maxWidth = minWidth;
  1.4132 +  if (minHeight > maxHeight)
  1.4133 +    maxHeight = minHeight;
  1.4134 +
  1.4135 +  nscoord heightAtMaxWidth, heightAtMinWidth,
  1.4136 +          widthAtMaxHeight, widthAtMinHeight;
  1.4137 +
  1.4138 +  if (tentWidth > 0) {
  1.4139 +    heightAtMaxWidth = MULDIV(maxWidth, tentHeight, tentWidth);
  1.4140 +    if (heightAtMaxWidth < minHeight)
  1.4141 +      heightAtMaxWidth = minHeight;
  1.4142 +    heightAtMinWidth = MULDIV(minWidth, tentHeight, tentWidth);
  1.4143 +    if (heightAtMinWidth > maxHeight)
  1.4144 +      heightAtMinWidth = maxHeight;
  1.4145 +  } else {
  1.4146 +    heightAtMaxWidth = heightAtMinWidth = NS_CSS_MINMAX(tentHeight, minHeight, maxHeight);
  1.4147 +  }
  1.4148 +
  1.4149 +  if (tentHeight > 0) {
  1.4150 +    widthAtMaxHeight = MULDIV(maxHeight, tentWidth, tentHeight);
  1.4151 +    if (widthAtMaxHeight < minWidth)
  1.4152 +      widthAtMaxHeight = minWidth;
  1.4153 +    widthAtMinHeight = MULDIV(minHeight, tentWidth, tentHeight);
  1.4154 +    if (widthAtMinHeight > maxWidth)
  1.4155 +      widthAtMinHeight = maxWidth;
  1.4156 +  } else {
  1.4157 +    widthAtMaxHeight = widthAtMinHeight = NS_CSS_MINMAX(tentWidth, minWidth, maxWidth);
  1.4158 +  }
  1.4159 +
  1.4160 +  // The table at http://www.w3.org/TR/CSS21/visudet.html#min-max-widths :
  1.4161 +
  1.4162 +  nscoord width, height;
  1.4163 +
  1.4164 +  if (tentWidth > maxWidth) {
  1.4165 +    if (tentHeight > maxHeight) {
  1.4166 +      if (int64_t(maxWidth) * int64_t(tentHeight) <=
  1.4167 +          int64_t(maxHeight) * int64_t(tentWidth)) {
  1.4168 +        width = maxWidth;
  1.4169 +        height = heightAtMaxWidth;
  1.4170 +      } else {
  1.4171 +        width = widthAtMaxHeight;
  1.4172 +        height = maxHeight;
  1.4173 +      }
  1.4174 +    } else {
  1.4175 +      // This also covers "(w > max-width) and (h < min-height)" since in
  1.4176 +      // that case (max-width/w < 1), and with (h < min-height):
  1.4177 +      //   max(max-width * h/w, min-height) == min-height
  1.4178 +      width = maxWidth;
  1.4179 +      height = heightAtMaxWidth;
  1.4180 +    }
  1.4181 +  } else if (tentWidth < minWidth) {
  1.4182 +    if (tentHeight < minHeight) {
  1.4183 +      if (int64_t(minWidth) * int64_t(tentHeight) <=
  1.4184 +          int64_t(minHeight) * int64_t(tentWidth)) {
  1.4185 +        width = widthAtMinHeight;
  1.4186 +        height = minHeight;
  1.4187 +      } else {
  1.4188 +        width = minWidth;
  1.4189 +        height = heightAtMinWidth;
  1.4190 +      }
  1.4191 +    } else {
  1.4192 +      // This also covers "(w < min-width) and (h > max-height)" since in
  1.4193 +      // that case (min-width/w > 1), and with (h > max-height):
  1.4194 +      //   min(min-width * h/w, max-height) == max-height
  1.4195 +      width = minWidth;
  1.4196 +      height = heightAtMinWidth;
  1.4197 +    }
  1.4198 +  } else {
  1.4199 +    if (tentHeight > maxHeight) {
  1.4200 +      width = widthAtMaxHeight;
  1.4201 +      height = maxHeight;
  1.4202 +    } else if (tentHeight < minHeight) {
  1.4203 +      width = widthAtMinHeight;
  1.4204 +      height = minHeight;
  1.4205 +    } else {
  1.4206 +      width = tentWidth;
  1.4207 +      height = tentHeight;
  1.4208 +    }
  1.4209 +  }
  1.4210 +
  1.4211 +  return nsSize(width, height);
  1.4212 +}
  1.4213 +
  1.4214 +/* static */ nscoord
  1.4215 +nsLayoutUtils::MinWidthFromInline(nsIFrame* aFrame,
  1.4216 +                                  nsRenderingContext* aRenderingContext)
  1.4217 +{
  1.4218 +  NS_ASSERTION(!aFrame->IsContainerForFontSizeInflation(),
  1.4219 +               "should not be container for font size inflation");
  1.4220 +
  1.4221 +  nsIFrame::InlineMinWidthData data;
  1.4222 +  DISPLAY_MIN_WIDTH(aFrame, data.prevLines);
  1.4223 +  aFrame->AddInlineMinWidth(aRenderingContext, &data);
  1.4224 +  data.ForceBreak(aRenderingContext);
  1.4225 +  return data.prevLines;
  1.4226 +}
  1.4227 +
  1.4228 +/* static */ nscoord
  1.4229 +nsLayoutUtils::PrefWidthFromInline(nsIFrame* aFrame,
  1.4230 +                                   nsRenderingContext* aRenderingContext)
  1.4231 +{
  1.4232 +  NS_ASSERTION(!aFrame->IsContainerForFontSizeInflation(),
  1.4233 +               "should not be container for font size inflation");
  1.4234 +
  1.4235 +  nsIFrame::InlinePrefWidthData data;
  1.4236 +  DISPLAY_PREF_WIDTH(aFrame, data.prevLines);
  1.4237 +  aFrame->AddInlinePrefWidth(aRenderingContext, &data);
  1.4238 +  data.ForceBreak(aRenderingContext);
  1.4239 +  return data.prevLines;
  1.4240 +}
  1.4241 +
  1.4242 +static nscolor
  1.4243 +DarkenColor(nscolor aColor)
  1.4244 +{
  1.4245 +  uint16_t  hue, sat, value;
  1.4246 +  uint8_t alpha;
  1.4247 +
  1.4248 +  // convert the RBG to HSV so we can get the lightness (which is the v)
  1.4249 +  NS_RGB2HSV(aColor, hue, sat, value, alpha);
  1.4250 +
  1.4251 +  // The goal here is to send white to black while letting colored
  1.4252 +  // stuff stay colored... So we adopt the following approach.
  1.4253 +  // Something with sat = 0 should end up with value = 0.  Something
  1.4254 +  // with a high sat can end up with a high value and it's ok.... At
  1.4255 +  // the same time, we don't want to make things lighter.  Do
  1.4256 +  // something simple, since it seems to work.
  1.4257 +  if (value > sat) {
  1.4258 +    value = sat;
  1.4259 +    // convert this color back into the RGB color space.
  1.4260 +    NS_HSV2RGB(aColor, hue, sat, value, alpha);
  1.4261 +  }
  1.4262 +  return aColor;
  1.4263 +}
  1.4264 +
  1.4265 +// Check whether we should darken text/decoration colors. We need to do this if
  1.4266 +// background images and colors are being suppressed, because that means
  1.4267 +// light text will not be visible against the (presumed light-colored) background.
  1.4268 +static bool
  1.4269 +ShouldDarkenColors(nsPresContext* aPresContext)
  1.4270 +{
  1.4271 +  return !aPresContext->GetBackgroundColorDraw() &&
  1.4272 +         !aPresContext->GetBackgroundImageDraw();
  1.4273 +}
  1.4274 +
  1.4275 +nscolor
  1.4276 +nsLayoutUtils::GetColor(nsIFrame* aFrame, nsCSSProperty aProperty)
  1.4277 +{
  1.4278 +  if (aProperty == eCSSProperty_color)
  1.4279 +  {
  1.4280 +    nscolor nativeColor = NS_RGB(0, 0, 0);
  1.4281 +    if (GetNativeTextColor(aFrame, nativeColor))
  1.4282 +      return nativeColor;
  1.4283 +  }
  1.4284 +
  1.4285 +  nscolor color = aFrame->GetVisitedDependentColor(aProperty);
  1.4286 +  if (ShouldDarkenColors(aFrame->PresContext())) {
  1.4287 +    color = DarkenColor(color);
  1.4288 +  }
  1.4289 +
  1.4290 +  return color;
  1.4291 +}
  1.4292 +
  1.4293 +bool
  1.4294 +nsLayoutUtils::GetNativeTextColor(nsIFrame* aFrame, nscolor& aColor)
  1.4295 +{
  1.4296 +  nsPresContext *presContext = aFrame->PresContext();
  1.4297 +  if (!presContext->IsChrome()) {
  1.4298 +    // If native appearance was used to draw the background of the containing
  1.4299 +    // frame, return a contrasting native foreground color instead of the
  1.4300 +    // color from the element's style.  This avoids a problem where black
  1.4301 +    // text was displayed on a black background when a Windows theme such as
  1.4302 +    // "High Contrast Black" was used.  The background is drawn inside
  1.4303 +    // nsNativeThemeWin::ClassicDrawWidgetBackground().
  1.4304 +    //
  1.4305 +    // Because both the background color and this foreground color are used
  1.4306 +    // directly without exposing the colors via CSS computed styles, the
  1.4307 +    // native colors are not leaked to content.
  1.4308 +    nsIFrame* bgFrame =
  1.4309 +                    nsCSSRendering::FindNonTransparentBackgroundFrame(aFrame);
  1.4310 +    if (bgFrame) {
  1.4311 +      const nsStyleDisplay* displayData = bgFrame->StyleDisplay();
  1.4312 +      uint8_t widgetType = displayData->mAppearance;
  1.4313 +      nsITheme *theme = presContext->GetTheme();
  1.4314 +      if (theme && widgetType && theme->ThemeSupportsWidget(presContext,
  1.4315 +                                                            bgFrame,
  1.4316 +                                                            widgetType)) {
  1.4317 +        bool isDisabled = false;
  1.4318 +        nsIContent* frameContent = bgFrame->GetContent();
  1.4319 +        if (frameContent && frameContent->IsElement()) {
  1.4320 +          EventStates es = frameContent->AsElement()->State();
  1.4321 +          isDisabled = es.HasState(NS_EVENT_STATE_DISABLED); 
  1.4322 +        } 
  1.4323 +
  1.4324 +        if (NS_SUCCEEDED(LookAndFeel::GetColorForNativeAppearance(widgetType,
  1.4325 +                                                       isDisabled, &aColor))) {
  1.4326 +            return true;
  1.4327 +        }
  1.4328 +      }
  1.4329 +    }
  1.4330 +  }
  1.4331 +
  1.4332 +  return false;
  1.4333 +}
  1.4334 +
  1.4335 +gfxFloat
  1.4336 +nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
  1.4337 +                                   nscoord aY, nscoord aAscent)
  1.4338 +{
  1.4339 +  gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.4340 +  gfxFloat baseline = gfxFloat(aY) + aAscent;
  1.4341 +  gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
  1.4342 +  if (!aContext->UserToDevicePixelSnapped(putativeRect, true))
  1.4343 +    return baseline;
  1.4344 +  return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
  1.4345 +}
  1.4346 +
  1.4347 +void
  1.4348 +nsLayoutUtils::DrawString(const nsIFrame*       aFrame,
  1.4349 +                          nsRenderingContext*   aContext,
  1.4350 +                          const char16_t*      aString,
  1.4351 +                          int32_t               aLength,
  1.4352 +                          nsPoint               aPoint,
  1.4353 +                          nsStyleContext*       aStyleContext)
  1.4354 +{
  1.4355 +  nsresult rv = NS_ERROR_FAILURE;
  1.4356 +  nsPresContext* presContext = aFrame->PresContext();
  1.4357 +  if (presContext->BidiEnabled()) {
  1.4358 +    nsBidiLevel level =
  1.4359 +      nsBidiPresUtils::BidiLevelFromStyle(aStyleContext ?
  1.4360 +                                          aStyleContext : aFrame->StyleContext());
  1.4361 +    rv = nsBidiPresUtils::RenderText(aString, aLength, level,
  1.4362 +                                     presContext, *aContext, *aContext,
  1.4363 +                                     aPoint.x, aPoint.y);
  1.4364 +  }
  1.4365 +  if (NS_FAILED(rv))
  1.4366 +  {
  1.4367 +    aContext->SetTextRunRTL(false);
  1.4368 +    aContext->DrawString(aString, aLength, aPoint.x, aPoint.y);
  1.4369 +  }
  1.4370 +}
  1.4371 +
  1.4372 +nscoord
  1.4373 +nsLayoutUtils::GetStringWidth(const nsIFrame*      aFrame,
  1.4374 +                              nsRenderingContext* aContext,
  1.4375 +                              const char16_t*     aString,
  1.4376 +                              int32_t              aLength)
  1.4377 +{
  1.4378 +  nsPresContext* presContext = aFrame->PresContext();
  1.4379 +  if (presContext->BidiEnabled()) {
  1.4380 +    nsBidiLevel level =
  1.4381 +      nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext());
  1.4382 +    return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
  1.4383 +                                             level, presContext, *aContext);
  1.4384 +  }
  1.4385 +  aContext->SetTextRunRTL(false);
  1.4386 +  return aContext->GetWidth(aString, aLength);
  1.4387 +}
  1.4388 +
  1.4389 +/* static */ void
  1.4390 +nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
  1.4391 +                               nsRenderingContext* aContext,
  1.4392 +                               const nsRect& aTextRect,
  1.4393 +                               const nsRect& aDirtyRect,
  1.4394 +                               const nscolor& aForegroundColor,
  1.4395 +                               TextShadowCallback aCallback,
  1.4396 +                               void* aCallbackData)
  1.4397 +{
  1.4398 +  const nsStyleText* textStyle = aFrame->StyleText();
  1.4399 +  if (!textStyle->HasTextShadow())
  1.4400 +    return;
  1.4401 +
  1.4402 +  // Text shadow happens with the last value being painted at the back,
  1.4403 +  // ie. it is painted first.
  1.4404 +  gfxContext* aDestCtx = aContext->ThebesContext();
  1.4405 +  for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
  1.4406 +    nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1);
  1.4407 +    nsPoint shadowOffset(shadowDetails->mXOffset,
  1.4408 +                         shadowDetails->mYOffset);
  1.4409 +    nscoord blurRadius = std::max(shadowDetails->mRadius, 0);
  1.4410 +
  1.4411 +    nsRect shadowRect(aTextRect);
  1.4412 +    shadowRect.MoveBy(shadowOffset);
  1.4413 +
  1.4414 +    nsPresContext* presCtx = aFrame->PresContext();
  1.4415 +    nsContextBoxBlur contextBoxBlur;
  1.4416 +    gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
  1.4417 +                                                    presCtx->AppUnitsPerDevPixel(),
  1.4418 +                                                    aDestCtx, aDirtyRect, nullptr);
  1.4419 +    if (!shadowContext)
  1.4420 +      continue;
  1.4421 +
  1.4422 +    nscolor shadowColor;
  1.4423 +    if (shadowDetails->mHasColor)
  1.4424 +      shadowColor = shadowDetails->mColor;
  1.4425 +    else
  1.4426 +      shadowColor = aForegroundColor;
  1.4427 +
  1.4428 +    // Conjure an nsRenderingContext from a gfxContext for drawing the text
  1.4429 +    // to blur.
  1.4430 +    nsRefPtr<nsRenderingContext> renderingContext = new nsRenderingContext();
  1.4431 +    renderingContext->Init(presCtx->DeviceContext(), shadowContext);
  1.4432 +
  1.4433 +    aDestCtx->Save();
  1.4434 +    aDestCtx->NewPath();
  1.4435 +    aDestCtx->SetColor(gfxRGBA(shadowColor));
  1.4436 +
  1.4437 +    // The callback will draw whatever we want to blur as a shadow.
  1.4438 +    aCallback(renderingContext, shadowOffset, shadowColor, aCallbackData);
  1.4439 +
  1.4440 +    contextBoxBlur.DoPaint();
  1.4441 +    aDestCtx->Restore();
  1.4442 +  }
  1.4443 +}
  1.4444 +
  1.4445 +/* static */ nscoord
  1.4446 +nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
  1.4447 +                                       nscoord         aLineHeight)
  1.4448 +{
  1.4449 +  nscoord fontAscent = aFontMetrics->MaxAscent();
  1.4450 +  nscoord fontHeight = aFontMetrics->MaxHeight();
  1.4451 +
  1.4452 +  nscoord leading = aLineHeight - fontHeight;
  1.4453 +  return fontAscent + leading/2;
  1.4454 +}
  1.4455 +
  1.4456 +
  1.4457 +/* static */ bool
  1.4458 +nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
  1.4459 +{
  1.4460 +  LinePosition position;
  1.4461 +  if (!GetFirstLinePosition(aFrame, &position))
  1.4462 +    return false;
  1.4463 +  *aResult = position.mBaseline;
  1.4464 +  return true;
  1.4465 +}
  1.4466 +
  1.4467 +/* static */ bool
  1.4468 +nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
  1.4469 +                                    LinePosition* aResult)
  1.4470 +{
  1.4471 +  const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
  1.4472 +  if (!block) {
  1.4473 +    // For the first-line baseline we also have to check for a table, and if
  1.4474 +    // so, use the baseline of its first row.
  1.4475 +    nsIAtom* fType = aFrame->GetType();
  1.4476 +    if (fType == nsGkAtoms::tableOuterFrame) {
  1.4477 +      aResult->mTop = 0;
  1.4478 +      aResult->mBaseline = aFrame->GetBaseline();
  1.4479 +      // This is what we want for the list bullet caller; not sure if
  1.4480 +      // other future callers will want the same.
  1.4481 +      aResult->mBottom = aFrame->GetSize().height;
  1.4482 +      return true;
  1.4483 +    }
  1.4484 +
  1.4485 +    // For first-line baselines, we have to consider scroll frames.
  1.4486 +    if (fType == nsGkAtoms::scrollFrame) {
  1.4487 +      nsIScrollableFrame *sFrame = do_QueryFrame(const_cast<nsIFrame*>(aFrame));
  1.4488 +      if (!sFrame) {
  1.4489 +        NS_NOTREACHED("not scroll frame");
  1.4490 +      }
  1.4491 +      LinePosition kidPosition;
  1.4492 +      if (GetFirstLinePosition(sFrame->GetScrolledFrame(), &kidPosition)) {
  1.4493 +        // Consider only the border and padding that contributes to the
  1.4494 +        // kid's position, not the scrolling, so we get the initial
  1.4495 +        // position.
  1.4496 +        *aResult = kidPosition + aFrame->GetUsedBorderAndPadding().top;
  1.4497 +        return true;
  1.4498 +      }
  1.4499 +      return false;
  1.4500 +    }
  1.4501 +
  1.4502 +    if (fType == nsGkAtoms::fieldSetFrame) {
  1.4503 +      LinePosition kidPosition;
  1.4504 +      nsIFrame* kid = aFrame->GetFirstPrincipalChild();
  1.4505 +      // kid might be a legend frame here, but that's ok.
  1.4506 +      if (GetFirstLinePosition(kid, &kidPosition)) {
  1.4507 +        *aResult = kidPosition + kid->GetNormalPosition().y;
  1.4508 +        return true;
  1.4509 +      }
  1.4510 +      return false;
  1.4511 +    }
  1.4512 +
  1.4513 +    // No baseline.
  1.4514 +    return false;
  1.4515 +  }
  1.4516 +
  1.4517 +  for (nsBlockFrame::const_line_iterator line = block->begin_lines(),
  1.4518 +                                     line_end = block->end_lines();
  1.4519 +       line != line_end; ++line) {
  1.4520 +    if (line->IsBlock()) {
  1.4521 +      nsIFrame *kid = line->mFirstChild;
  1.4522 +      LinePosition kidPosition;
  1.4523 +      if (GetFirstLinePosition(kid, &kidPosition)) {
  1.4524 +        *aResult = kidPosition + kid->GetNormalPosition().y;
  1.4525 +        return true;
  1.4526 +      }
  1.4527 +    } else {
  1.4528 +      // XXX Is this the right test?  We have some bogus empty lines
  1.4529 +      // floating around, but IsEmpty is perhaps too weak.
  1.4530 +      if (line->BSize() != 0 || !line->IsEmpty()) {
  1.4531 +        nscoord top = line->BStart();
  1.4532 +        aResult->mTop = top;
  1.4533 +        aResult->mBaseline = top + line->GetAscent();
  1.4534 +        aResult->mBottom = top + line->BSize();
  1.4535 +        return true;
  1.4536 +      }
  1.4537 +    }
  1.4538 +  }
  1.4539 +  return false;
  1.4540 +}
  1.4541 +
  1.4542 +/* static */ bool
  1.4543 +nsLayoutUtils::GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
  1.4544 +{
  1.4545 +  const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
  1.4546 +  if (!block)
  1.4547 +    // No baseline.  (We intentionally don't descend into scroll frames.)
  1.4548 +    return false;
  1.4549 +
  1.4550 +  for (nsBlockFrame::const_reverse_line_iterator line = block->rbegin_lines(),
  1.4551 +                                             line_end = block->rend_lines();
  1.4552 +       line != line_end; ++line) {
  1.4553 +    if (line->IsBlock()) {
  1.4554 +      nsIFrame *kid = line->mFirstChild;
  1.4555 +      nscoord kidBaseline;
  1.4556 +      if (GetLastLineBaseline(kid, &kidBaseline)) {
  1.4557 +        // Ignore relative positioning for baseline calculations
  1.4558 +        *aResult = kidBaseline + kid->GetNormalPosition().y;
  1.4559 +        return true;
  1.4560 +      } else if (kid->GetType() == nsGkAtoms::scrollFrame) {
  1.4561 +        // Use the bottom of the scroll frame.
  1.4562 +        // XXX CSS2.1 really doesn't say what to do here.
  1.4563 +        *aResult = kid->GetNormalPosition().y + kid->GetRect().height;
  1.4564 +        return true;
  1.4565 +      }
  1.4566 +    } else {
  1.4567 +      // XXX Is this the right test?  We have some bogus empty lines
  1.4568 +      // floating around, but IsEmpty is perhaps too weak.
  1.4569 +      if (line->BSize() != 0 || !line->IsEmpty()) {
  1.4570 +        *aResult = line->BStart() + line->GetAscent();
  1.4571 +        return true;
  1.4572 +      }
  1.4573 +    }
  1.4574 +  }
  1.4575 +  return false;
  1.4576 +}
  1.4577 +
  1.4578 +static nscoord
  1.4579 +CalculateBlockContentBottom(nsBlockFrame* aFrame)
  1.4580 +{
  1.4581 +  NS_PRECONDITION(aFrame, "null ptr");
  1.4582 +
  1.4583 +  nscoord contentBottom = 0;
  1.4584 +
  1.4585 +  for (nsBlockFrame::line_iterator line = aFrame->begin_lines(),
  1.4586 +                                   line_end = aFrame->end_lines();
  1.4587 +       line != line_end; ++line) {
  1.4588 +    if (line->IsBlock()) {
  1.4589 +      nsIFrame* child = line->mFirstChild;
  1.4590 +      nscoord offset = child->GetNormalPosition().y;
  1.4591 +      contentBottom = std::max(contentBottom,
  1.4592 +                        nsLayoutUtils::CalculateContentBottom(child) + offset);
  1.4593 +    }
  1.4594 +    else {
  1.4595 +      contentBottom = std::max(contentBottom, line->BEnd());
  1.4596 +    }
  1.4597 +  }
  1.4598 +  return contentBottom;
  1.4599 +}
  1.4600 +
  1.4601 +/* static */ nscoord
  1.4602 +nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
  1.4603 +{
  1.4604 +  NS_PRECONDITION(aFrame, "null ptr");
  1.4605 +
  1.4606 +  nscoord contentBottom = aFrame->GetRect().height;
  1.4607 +
  1.4608 +  // We want scrollable overflow rather than visual because this
  1.4609 +  // calculation is intended to affect layout.
  1.4610 +  if (aFrame->GetScrollableOverflowRect().height > contentBottom) {
  1.4611 +    nsIFrame::ChildListIDs skip(nsIFrame::kOverflowList |
  1.4612 +                                nsIFrame::kExcessOverflowContainersList |
  1.4613 +                                nsIFrame::kOverflowOutOfFlowList);
  1.4614 +    nsBlockFrame* blockFrame = GetAsBlock(aFrame);
  1.4615 +    if (blockFrame) {
  1.4616 +      contentBottom =
  1.4617 +        std::max(contentBottom, CalculateBlockContentBottom(blockFrame));
  1.4618 +      skip |= nsIFrame::kPrincipalList;
  1.4619 +    }
  1.4620 +    nsIFrame::ChildListIterator lists(aFrame);
  1.4621 +    for (; !lists.IsDone(); lists.Next()) {
  1.4622 +      if (!skip.Contains(lists.CurrentID())) {
  1.4623 +        nsFrameList::Enumerator childFrames(lists.CurrentList()); 
  1.4624 +        for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.4625 +          nsIFrame* child = childFrames.get();
  1.4626 +          nscoord offset = child->GetNormalPosition().y;
  1.4627 +          contentBottom = std::max(contentBottom,
  1.4628 +                                 CalculateContentBottom(child) + offset);
  1.4629 +        }
  1.4630 +      }
  1.4631 +    }
  1.4632 +  }
  1.4633 +  return contentBottom;
  1.4634 +}
  1.4635 +
  1.4636 +/* static */ nsIFrame*
  1.4637 +nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame)
  1.4638 +{
  1.4639 +  nsIFrame* layer;
  1.4640 +  for (layer = aFrame; layer; layer = layer->GetParent()) {
  1.4641 +    if (layer->IsPositioned() ||
  1.4642 +        (layer->GetParent() &&
  1.4643 +          layer->GetParent()->GetType() == nsGkAtoms::scrollFrame))
  1.4644 +      break;
  1.4645 +  }
  1.4646 +  if (layer)
  1.4647 +    return layer;
  1.4648 +  return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
  1.4649 +}
  1.4650 +
  1.4651 +GraphicsFilter
  1.4652 +nsLayoutUtils::GetGraphicsFilterForFrame(nsIFrame* aForFrame)
  1.4653 +{
  1.4654 +  GraphicsFilter defaultFilter = GraphicsFilter::FILTER_GOOD;
  1.4655 +  nsStyleContext *sc;
  1.4656 +  if (nsCSSRendering::IsCanvasFrame(aForFrame)) {
  1.4657 +    nsCSSRendering::FindBackground(aForFrame, &sc);
  1.4658 +  } else {
  1.4659 +    sc = aForFrame->StyleContext();
  1.4660 +  }
  1.4661 +
  1.4662 +  switch (sc->StyleSVG()->mImageRendering) {
  1.4663 +  case NS_STYLE_IMAGE_RENDERING_OPTIMIZESPEED:
  1.4664 +    return GraphicsFilter::FILTER_FAST;
  1.4665 +  case NS_STYLE_IMAGE_RENDERING_OPTIMIZEQUALITY:
  1.4666 +    return GraphicsFilter::FILTER_BEST;
  1.4667 +  case NS_STYLE_IMAGE_RENDERING_CRISPEDGES:
  1.4668 +    return GraphicsFilter::FILTER_NEAREST;
  1.4669 +  default:
  1.4670 +    return defaultFilter;
  1.4671 +  }
  1.4672 +}
  1.4673 +
  1.4674 +/**
  1.4675 + * Given an image being drawn into an appunit coordinate system, and
  1.4676 + * a point in that coordinate system, map the point back into image
  1.4677 + * pixel space.
  1.4678 + * @param aSize the size of the image, in pixels
  1.4679 + * @param aDest the rectangle that the image is being mapped into
  1.4680 + * @param aPt a point in the same coordinate system as the rectangle
  1.4681 + */
  1.4682 +static gfxPoint
  1.4683 +MapToFloatImagePixels(const gfxSize& aSize,
  1.4684 +                      const gfxRect& aDest, const gfxPoint& aPt)
  1.4685 +{
  1.4686 +  return gfxPoint(((aPt.x - aDest.X())*aSize.width)/aDest.Width(),
  1.4687 +                  ((aPt.y - aDest.Y())*aSize.height)/aDest.Height());
  1.4688 +}
  1.4689 +
  1.4690 +/**
  1.4691 + * Given an image being drawn into an pixel-based coordinate system, and
  1.4692 + * a point in image space, map the point into the pixel-based coordinate
  1.4693 + * system.
  1.4694 + * @param aSize the size of the image, in pixels
  1.4695 + * @param aDest the rectangle that the image is being mapped into
  1.4696 + * @param aPt a point in image space
  1.4697 + */
  1.4698 +static gfxPoint
  1.4699 +MapToFloatUserPixels(const gfxSize& aSize,
  1.4700 +                     const gfxRect& aDest, const gfxPoint& aPt)
  1.4701 +{
  1.4702 +  return gfxPoint(aPt.x*aDest.Width()/aSize.width + aDest.X(),
  1.4703 +                  aPt.y*aDest.Height()/aSize.height + aDest.Y());
  1.4704 +}
  1.4705 +
  1.4706 +/* static */ gfxRect
  1.4707 +nsLayoutUtils::RectToGfxRect(const nsRect& aRect, int32_t aAppUnitsPerDevPixel)
  1.4708 +{
  1.4709 +  return gfxRect(gfxFloat(aRect.x) / aAppUnitsPerDevPixel,
  1.4710 +                 gfxFloat(aRect.y) / aAppUnitsPerDevPixel,
  1.4711 +                 gfxFloat(aRect.width) / aAppUnitsPerDevPixel,
  1.4712 +                 gfxFloat(aRect.height) / aAppUnitsPerDevPixel);
  1.4713 +}
  1.4714 +
  1.4715 +struct SnappedImageDrawingParameters {
  1.4716 +  // A transform from either device space or user space (depending on mResetCTM)
  1.4717 +  // to image space
  1.4718 +  gfxMatrix mUserSpaceToImageSpace;
  1.4719 +  // A device-space, pixel-aligned rectangle to fill
  1.4720 +  gfxRect mFillRect;
  1.4721 +  // A pixel rectangle in tiled image space outside of which gfx should not
  1.4722 +  // sample (using EXTEND_PAD as necessary)
  1.4723 +  nsIntRect mSubimage;
  1.4724 +  // Whether there's anything to draw at all
  1.4725 +  bool mShouldDraw;
  1.4726 +  // true iff the CTM of the rendering context needs to be reset to the
  1.4727 +  // identity matrix before drawing
  1.4728 +  bool mResetCTM;
  1.4729 +
  1.4730 +  SnappedImageDrawingParameters()
  1.4731 +   : mShouldDraw(false)
  1.4732 +   , mResetCTM(false)
  1.4733 +  {}
  1.4734 +
  1.4735 +  SnappedImageDrawingParameters(const gfxMatrix& aUserSpaceToImageSpace,
  1.4736 +                                const gfxRect&   aFillRect,
  1.4737 +                                const nsIntRect& aSubimage,
  1.4738 +                                bool             aResetCTM)
  1.4739 +   : mUserSpaceToImageSpace(aUserSpaceToImageSpace)
  1.4740 +   , mFillRect(aFillRect)
  1.4741 +   , mSubimage(aSubimage)
  1.4742 +   , mShouldDraw(true)
  1.4743 +   , mResetCTM(aResetCTM)
  1.4744 +  {}
  1.4745 +};
  1.4746 +
  1.4747 +/**
  1.4748 + * Given a set of input parameters, compute certain output parameters
  1.4749 + * for drawing an image with the image snapping algorithm.
  1.4750 + * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
  1.4751 + *
  1.4752 + *  @see nsLayoutUtils::DrawImage() for the descriptions of input parameters
  1.4753 + */
  1.4754 +static SnappedImageDrawingParameters
  1.4755 +ComputeSnappedImageDrawingParameters(gfxContext*     aCtx,
  1.4756 +                                     int32_t         aAppUnitsPerDevPixel,
  1.4757 +                                     const nsRect    aDest,
  1.4758 +                                     const nsRect    aFill,
  1.4759 +                                     const nsPoint   aAnchor,
  1.4760 +                                     const nsRect    aDirty,
  1.4761 +                                     const nsIntSize aImageSize)
  1.4762 +
  1.4763 +{
  1.4764 +  if (aDest.IsEmpty() || aFill.IsEmpty() || !aImageSize.width || !aImageSize.height)
  1.4765 +    return SnappedImageDrawingParameters();
  1.4766 +
  1.4767 +  gfxRect devPixelDest =
  1.4768 +    nsLayoutUtils::RectToGfxRect(aDest, aAppUnitsPerDevPixel);
  1.4769 +  gfxRect devPixelFill =
  1.4770 +    nsLayoutUtils::RectToGfxRect(aFill, aAppUnitsPerDevPixel);
  1.4771 +  gfxRect devPixelDirty =
  1.4772 +    nsLayoutUtils::RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
  1.4773 +
  1.4774 +  gfxMatrix currentMatrix = aCtx->CurrentMatrix();
  1.4775 +  gfxRect fill = devPixelFill;
  1.4776 +  bool didSnap;
  1.4777 +  // Snap even if we have a scale in the context. But don't snap if
  1.4778 +  // we have something that's not translation+scale, or if the scale flips in
  1.4779 +  // the X or Y direction, because snapped image drawing can't handle that yet.
  1.4780 +  if (!currentMatrix.HasNonAxisAlignedTransform() &&
  1.4781 +      currentMatrix.xx > 0.0 && currentMatrix.yy > 0.0 &&
  1.4782 +      aCtx->UserToDevicePixelSnapped(fill, true)) {
  1.4783 +    didSnap = true;
  1.4784 +    if (fill.IsEmpty()) {
  1.4785 +      return SnappedImageDrawingParameters();
  1.4786 +    }
  1.4787 +  } else {
  1.4788 +    didSnap = false;
  1.4789 +    fill = devPixelFill;
  1.4790 +  }
  1.4791 +
  1.4792 +  gfxSize imageSize(aImageSize.width, aImageSize.height);
  1.4793 +
  1.4794 +  // Compute the set of pixels that would be sampled by an ideal rendering
  1.4795 +  gfxPoint subimageTopLeft =
  1.4796 +    MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.TopLeft());
  1.4797 +  gfxPoint subimageBottomRight =
  1.4798 +    MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.BottomRight());
  1.4799 +  nsIntRect intSubimage;
  1.4800 +  intSubimage.MoveTo(NSToIntFloor(subimageTopLeft.x),
  1.4801 +                     NSToIntFloor(subimageTopLeft.y));
  1.4802 +  intSubimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - intSubimage.x,
  1.4803 +                     NSToIntCeil(subimageBottomRight.y) - intSubimage.y);
  1.4804 +
  1.4805 +  // Compute the anchor point and compute final fill rect.
  1.4806 +  // This code assumes that pixel-based devices have one pixel per
  1.4807 +  // device unit!
  1.4808 +  gfxPoint anchorPoint(gfxFloat(aAnchor.x)/aAppUnitsPerDevPixel,
  1.4809 +                       gfxFloat(aAnchor.y)/aAppUnitsPerDevPixel);
  1.4810 +  gfxPoint imageSpaceAnchorPoint =
  1.4811 +    MapToFloatImagePixels(imageSize, devPixelDest, anchorPoint);
  1.4812 +
  1.4813 +  if (didSnap) {
  1.4814 +    imageSpaceAnchorPoint.Round();
  1.4815 +    anchorPoint = imageSpaceAnchorPoint;
  1.4816 +    anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
  1.4817 +    anchorPoint = currentMatrix.Transform(anchorPoint);
  1.4818 +    anchorPoint.Round();
  1.4819 +
  1.4820 +    // This form of Transform is safe to call since non-axis-aligned
  1.4821 +    // transforms wouldn't be snapped.
  1.4822 +    devPixelDirty = currentMatrix.Transform(devPixelDirty);
  1.4823 +  }
  1.4824 +
  1.4825 +  gfxFloat scaleX = imageSize.width*aAppUnitsPerDevPixel/aDest.width;
  1.4826 +  gfxFloat scaleY = imageSize.height*aAppUnitsPerDevPixel/aDest.height;
  1.4827 +  if (didSnap) {
  1.4828 +    // We'll reset aCTX to the identity matrix before drawing, so we need to
  1.4829 +    // adjust our scales to match.
  1.4830 +    scaleX /= currentMatrix.xx;
  1.4831 +    scaleY /= currentMatrix.yy;
  1.4832 +  }
  1.4833 +  gfxFloat translateX = imageSpaceAnchorPoint.x - anchorPoint.x*scaleX;
  1.4834 +  gfxFloat translateY = imageSpaceAnchorPoint.y - anchorPoint.y*scaleY;
  1.4835 +  gfxMatrix transform(scaleX, 0, 0, scaleY, translateX, translateY);
  1.4836 +
  1.4837 +  gfxRect finalFillRect = fill;
  1.4838 +  // If the user-space-to-image-space transform is not a straight
  1.4839 +  // translation by integers, then filtering will occur, and
  1.4840 +  // restricting the fill rect to the dirty rect would change the values
  1.4841 +  // computed for edge pixels, which we can't allow.
  1.4842 +  // Also, if didSnap is false then rounding out 'devPixelDirty' might not
  1.4843 +  // produce pixel-aligned coordinates, which would also break the values
  1.4844 +  // computed for edge pixels.
  1.4845 +  if (didSnap && !transform.HasNonIntegerTranslation()) {
  1.4846 +    devPixelDirty.RoundOut();
  1.4847 +    finalFillRect = fill.Intersect(devPixelDirty);
  1.4848 +  }
  1.4849 +  if (finalFillRect.IsEmpty())
  1.4850 +    return SnappedImageDrawingParameters();
  1.4851 +
  1.4852 +  return SnappedImageDrawingParameters(transform, finalFillRect, intSubimage,
  1.4853 +                                       didSnap);
  1.4854 +}
  1.4855 +
  1.4856 +
  1.4857 +static nsresult
  1.4858 +DrawImageInternal(nsRenderingContext*    aRenderingContext,
  1.4859 +                  imgIContainer*         aImage,
  1.4860 +                  GraphicsFilter         aGraphicsFilter,
  1.4861 +                  const nsRect&          aDest,
  1.4862 +                  const nsRect&          aFill,
  1.4863 +                  const nsPoint&         aAnchor,
  1.4864 +                  const nsRect&          aDirty,
  1.4865 +                  const nsIntSize&       aImageSize,
  1.4866 +                  const SVGImageContext* aSVGContext,
  1.4867 +                  uint32_t               aImageFlags)
  1.4868 +{
  1.4869 +  if (aDest.Contains(aFill)) {
  1.4870 +    aImageFlags |= imgIContainer::FLAG_CLAMP;
  1.4871 +  }
  1.4872 +  int32_t appUnitsPerDevPixel = aRenderingContext->AppUnitsPerDevPixel();
  1.4873 +  gfxContext* ctx = aRenderingContext->ThebesContext();
  1.4874 +
  1.4875 +  SnappedImageDrawingParameters drawingParams =
  1.4876 +    ComputeSnappedImageDrawingParameters(ctx, appUnitsPerDevPixel, aDest, aFill,
  1.4877 +                                         aAnchor, aDirty, aImageSize);
  1.4878 +
  1.4879 +  if (!drawingParams.mShouldDraw)
  1.4880 +    return NS_OK;
  1.4881 +
  1.4882 +  gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
  1.4883 +  if (drawingParams.mResetCTM) {
  1.4884 +    ctx->IdentityMatrix();
  1.4885 +  }
  1.4886 +
  1.4887 +  aImage->Draw(ctx, aGraphicsFilter, drawingParams.mUserSpaceToImageSpace,
  1.4888 +               drawingParams.mFillRect, drawingParams.mSubimage, aImageSize,
  1.4889 +               aSVGContext, imgIContainer::FRAME_CURRENT, aImageFlags);
  1.4890 +  return NS_OK;
  1.4891 +}
  1.4892 +
  1.4893 +/* static */ void
  1.4894 +nsLayoutUtils::DrawPixelSnapped(nsRenderingContext* aRenderingContext,
  1.4895 +                                gfxDrawable*         aDrawable,
  1.4896 +                                GraphicsFilter       aFilter,
  1.4897 +                                const nsRect&        aDest,
  1.4898 +                                const nsRect&        aFill,
  1.4899 +                                const nsPoint&       aAnchor,
  1.4900 +                                const nsRect&        aDirty)
  1.4901 +{
  1.4902 +  int32_t appUnitsPerDevPixel = aRenderingContext->AppUnitsPerDevPixel();
  1.4903 +  gfxContext* ctx = aRenderingContext->ThebesContext();
  1.4904 +  gfxIntSize drawableSize = aDrawable->Size();
  1.4905 +  nsIntSize imageSize(drawableSize.width, drawableSize.height);
  1.4906 +
  1.4907 +  SnappedImageDrawingParameters drawingParams =
  1.4908 +    ComputeSnappedImageDrawingParameters(ctx, appUnitsPerDevPixel, aDest, aFill,
  1.4909 +                                         aAnchor, aDirty, imageSize);
  1.4910 +
  1.4911 +  if (!drawingParams.mShouldDraw)
  1.4912 +    return;
  1.4913 +
  1.4914 +  gfxContextMatrixAutoSaveRestore saveMatrix(ctx);
  1.4915 +  if (drawingParams.mResetCTM) {
  1.4916 +    ctx->IdentityMatrix();
  1.4917 +  }
  1.4918 +
  1.4919 +  gfxRect sourceRect =
  1.4920 +    drawingParams.mUserSpaceToImageSpace.Transform(drawingParams.mFillRect);
  1.4921 +  gfxRect imageRect(0, 0, imageSize.width, imageSize.height);
  1.4922 +  gfxRect subimage(drawingParams.mSubimage.x, drawingParams.mSubimage.y,
  1.4923 +                   drawingParams.mSubimage.width, drawingParams.mSubimage.height);
  1.4924 +
  1.4925 +  NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
  1.4926 +               "We must be allowed to sample *some* source pixels!");
  1.4927 +
  1.4928 +  gfxUtils::DrawPixelSnapped(ctx, aDrawable,
  1.4929 +                             drawingParams.mUserSpaceToImageSpace, subimage,
  1.4930 +                             sourceRect, imageRect, drawingParams.mFillRect,
  1.4931 +                             gfxImageFormat::ARGB32, aFilter);
  1.4932 +}
  1.4933 +
  1.4934 +/* static */ nsresult
  1.4935 +nsLayoutUtils::DrawSingleUnscaledImage(nsRenderingContext* aRenderingContext,
  1.4936 +                                       imgIContainer*       aImage,
  1.4937 +                                       GraphicsFilter       aGraphicsFilter,
  1.4938 +                                       const nsPoint&       aDest,
  1.4939 +                                       const nsRect*        aDirty,
  1.4940 +                                       uint32_t             aImageFlags,
  1.4941 +                                       const nsRect*        aSourceArea)
  1.4942 +{
  1.4943 +  nsIntSize imageSize;
  1.4944 +  aImage->GetWidth(&imageSize.width);
  1.4945 +  aImage->GetHeight(&imageSize.height);
  1.4946 +  NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE);
  1.4947 +
  1.4948 +  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
  1.4949 +  nsSize size(imageSize.width*appUnitsPerCSSPixel,
  1.4950 +              imageSize.height*appUnitsPerCSSPixel);
  1.4951 +
  1.4952 +  nsRect source;
  1.4953 +  if (aSourceArea) {
  1.4954 +    source = *aSourceArea;
  1.4955 +  } else {
  1.4956 +    source.SizeTo(size);
  1.4957 +  }
  1.4958 +
  1.4959 +  nsRect dest(aDest - source.TopLeft(), size);
  1.4960 +  nsRect fill(aDest, source.Size());
  1.4961 +  // Ensure that only a single image tile is drawn. If aSourceArea extends
  1.4962 +  // outside the image bounds, we want to honor the aSourceArea-to-aDest
  1.4963 +  // translation but we don't want to actually tile the image.
  1.4964 +  fill.IntersectRect(fill, dest);
  1.4965 +  return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
  1.4966 +                           dest, fill, aDest, aDirty ? *aDirty : dest,
  1.4967 +                           imageSize, nullptr, aImageFlags);
  1.4968 +}
  1.4969 +
  1.4970 +/* static */ nsresult
  1.4971 +nsLayoutUtils::DrawSingleImage(nsRenderingContext*    aRenderingContext,
  1.4972 +                               imgIContainer*         aImage,
  1.4973 +                               GraphicsFilter         aGraphicsFilter,
  1.4974 +                               const nsRect&          aDest,
  1.4975 +                               const nsRect&          aDirty,
  1.4976 +                               const SVGImageContext* aSVGContext,
  1.4977 +                               uint32_t               aImageFlags,
  1.4978 +                               const nsRect*          aSourceArea)
  1.4979 +{
  1.4980 +  nsIntSize imageSize;
  1.4981 +  if (aImage->GetType() == imgIContainer::TYPE_VECTOR) {
  1.4982 +    // We choose a size for vector images that emulates a raster image which
  1.4983 +    // is perfectly sized for the destination rect: each pixel in the image
  1.4984 +    // maps exactly to a single pixel on-screen.
  1.4985 +    nscoord appUnitsPerDevPx = aRenderingContext->AppUnitsPerDevPixel();
  1.4986 +    imageSize.width = NSAppUnitsToIntPixels(aDest.width, appUnitsPerDevPx);
  1.4987 +    imageSize.height = NSAppUnitsToIntPixels(aDest.height, appUnitsPerDevPx);
  1.4988 +  } else {
  1.4989 +    // Raster images have an intrinsic size, so we just use that.
  1.4990 +    aImage->GetWidth(&imageSize.width);
  1.4991 +    aImage->GetHeight(&imageSize.height);
  1.4992 +  }
  1.4993 +  NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE);
  1.4994 +
  1.4995 +  nsRect source;
  1.4996 +  if (aSourceArea) {
  1.4997 +    source = *aSourceArea;
  1.4998 +  } else {
  1.4999 +    nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
  1.5000 +    source.SizeTo(imageSize.width*appUnitsPerCSSPixel,
  1.5001 +                  imageSize.height*appUnitsPerCSSPixel);
  1.5002 +  }
  1.5003 +
  1.5004 +  nsRect dest = nsLayoutUtils::GetWholeImageDestination(imageSize, source,
  1.5005 +                                                        aDest);
  1.5006 +  // Ensure that only a single image tile is drawn. If aSourceArea extends
  1.5007 +  // outside the image bounds, we want to honor the aSourceArea-to-aDest
  1.5008 +  // transform but we don't want to actually tile the image.
  1.5009 +  nsRect fill;
  1.5010 +  fill.IntersectRect(aDest, dest);
  1.5011 +  return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter, dest, fill,
  1.5012 +                           fill.TopLeft(), aDirty, imageSize, aSVGContext, aImageFlags);
  1.5013 +}
  1.5014 +
  1.5015 +/* static */ void
  1.5016 +nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
  1.5017 +                                     nsIntSize&     aImageSize, /*outparam*/
  1.5018 +                                     nsSize&        aIntrinsicRatio, /*outparam*/
  1.5019 +                                     bool&          aGotWidth,  /*outparam*/
  1.5020 +                                     bool&          aGotHeight  /*outparam*/)
  1.5021 +{
  1.5022 +  aGotWidth  = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width));
  1.5023 +  aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height));
  1.5024 +  bool gotRatio = NS_SUCCEEDED(aImage->GetIntrinsicRatio(&aIntrinsicRatio));
  1.5025 +
  1.5026 +  if (!(aGotWidth && aGotHeight) && !gotRatio) {
  1.5027 +    // We hit an error (say, because the image failed to load or couldn't be
  1.5028 +    // decoded) and should return zero size.
  1.5029 +    aGotWidth = aGotHeight = true;
  1.5030 +    aImageSize = nsIntSize(0, 0);
  1.5031 +    aIntrinsicRatio = nsSize(0, 0);
  1.5032 +  }
  1.5033 +}
  1.5034 +
  1.5035 +
  1.5036 +/* static */ nsresult
  1.5037 +nsLayoutUtils::DrawBackgroundImage(nsRenderingContext* aRenderingContext,
  1.5038 +                                   imgIContainer*      aImage,
  1.5039 +                                   const nsIntSize&    aImageSize,
  1.5040 +                                   GraphicsFilter      aGraphicsFilter,
  1.5041 +                                   const nsRect&       aDest,
  1.5042 +                                   const nsRect&       aFill,
  1.5043 +                                   const nsPoint&      aAnchor,
  1.5044 +                                   const nsRect&       aDirty,
  1.5045 +                                   uint32_t            aImageFlags)
  1.5046 +{
  1.5047 +  PROFILER_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage");
  1.5048 +
  1.5049 +  if (UseBackgroundNearestFiltering()) {
  1.5050 +    aGraphicsFilter = GraphicsFilter::FILTER_NEAREST;
  1.5051 +  }
  1.5052 +
  1.5053 +  return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
  1.5054 +                           aDest, aFill, aAnchor, aDirty,
  1.5055 +                           aImageSize, nullptr, aImageFlags);
  1.5056 +}
  1.5057 +
  1.5058 +/* static */ nsresult
  1.5059 +nsLayoutUtils::DrawImage(nsRenderingContext* aRenderingContext,
  1.5060 +                         imgIContainer*       aImage,
  1.5061 +                         GraphicsFilter       aGraphicsFilter,
  1.5062 +                         const nsRect&        aDest,
  1.5063 +                         const nsRect&        aFill,
  1.5064 +                         const nsPoint&       aAnchor,
  1.5065 +                         const nsRect&        aDirty,
  1.5066 +                         uint32_t             aImageFlags)
  1.5067 +{
  1.5068 +  nsIntSize imageSize;
  1.5069 +  nsSize imageRatio;
  1.5070 +  bool gotHeight, gotWidth;
  1.5071 +  ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight);
  1.5072 +
  1.5073 +  // XXX Dimensionless images shouldn't fall back to filled-area size -- the
  1.5074 +  //     caller should provide the image size, a la DrawBackgroundImage.
  1.5075 +  if (gotWidth != gotHeight) {
  1.5076 +    if (!gotWidth) {
  1.5077 +      if (imageRatio.height != 0) {
  1.5078 +        imageSize.width =
  1.5079 +          NSCoordSaturatingNonnegativeMultiply(imageSize.height,
  1.5080 +                                               float(imageRatio.width) /
  1.5081 +                                               float(imageRatio.height));
  1.5082 +        gotWidth = true;
  1.5083 +      }
  1.5084 +    } else {
  1.5085 +      if (imageRatio.width != 0) {
  1.5086 +        imageSize.height =
  1.5087 +          NSCoordSaturatingNonnegativeMultiply(imageSize.width,
  1.5088 +                                               float(imageRatio.height) /
  1.5089 +                                               float(imageRatio.width));
  1.5090 +        gotHeight = true;
  1.5091 +      }
  1.5092 +    }
  1.5093 +  }
  1.5094 +
  1.5095 +  if (!gotWidth) {
  1.5096 +    imageSize.width = nsPresContext::AppUnitsToIntCSSPixels(aFill.width);
  1.5097 +  }
  1.5098 +  if (!gotHeight) {
  1.5099 +    imageSize.height = nsPresContext::AppUnitsToIntCSSPixels(aFill.height);
  1.5100 +  }
  1.5101 +
  1.5102 +  return DrawImageInternal(aRenderingContext, aImage, aGraphicsFilter,
  1.5103 +                           aDest, aFill, aAnchor, aDirty,
  1.5104 +                           imageSize, nullptr, aImageFlags);
  1.5105 +}
  1.5106 +
  1.5107 +/* static */ nsRect
  1.5108 +nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
  1.5109 +                                        const nsRect& aImageSourceArea,
  1.5110 +                                        const nsRect& aDestArea)
  1.5111 +{
  1.5112 +  double scaleX = double(aDestArea.width)/aImageSourceArea.width;
  1.5113 +  double scaleY = double(aDestArea.height)/aImageSourceArea.height;
  1.5114 +  nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
  1.5115 +  nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY);
  1.5116 +  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
  1.5117 +  nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*appUnitsPerCSSPixel*scaleX);
  1.5118 +  nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*appUnitsPerCSSPixel*scaleY);
  1.5119 +  return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY),
  1.5120 +                nsSize(wholeSizeX, wholeSizeY));
  1.5121 +}
  1.5122 +
  1.5123 +/* static */ already_AddRefed<imgIContainer>
  1.5124 +nsLayoutUtils::OrientImage(imgIContainer* aContainer,
  1.5125 +                           const nsStyleImageOrientation& aOrientation)
  1.5126 +{
  1.5127 +  MOZ_ASSERT(aContainer, "Should have an image container");
  1.5128 +  nsCOMPtr<imgIContainer> img(aContainer);
  1.5129 +
  1.5130 +  if (aOrientation.IsFromImage()) {
  1.5131 +    img = ImageOps::Orient(img, img->GetOrientation());
  1.5132 +  } else if (!aOrientation.IsDefault()) {
  1.5133 +    Angle angle = aOrientation.Angle();
  1.5134 +    Flip flip  = aOrientation.IsFlipped() ? Flip::Horizontal
  1.5135 +                                          : Flip::Unflipped;
  1.5136 +    img = ImageOps::Orient(img, Orientation(angle, flip));
  1.5137 +  }
  1.5138 +
  1.5139 +  return img.forget();
  1.5140 +}
  1.5141 +
  1.5142 +static bool NonZeroStyleCoord(const nsStyleCoord& aCoord)
  1.5143 +{
  1.5144 +  if (aCoord.IsCoordPercentCalcUnit()) {
  1.5145 +    // Since negative results are clamped to 0, check > 0.
  1.5146 +    return nsRuleNode::ComputeCoordPercentCalc(aCoord, nscoord_MAX) > 0 ||
  1.5147 +           nsRuleNode::ComputeCoordPercentCalc(aCoord, 0) > 0;
  1.5148 +  }
  1.5149 +
  1.5150 +  return true;
  1.5151 +}
  1.5152 +
  1.5153 +/* static */ bool
  1.5154 +nsLayoutUtils::HasNonZeroCorner(const nsStyleCorners& aCorners)
  1.5155 +{
  1.5156 +  NS_FOR_CSS_HALF_CORNERS(corner) {
  1.5157 +    if (NonZeroStyleCoord(aCorners.Get(corner)))
  1.5158 +      return true;
  1.5159 +  }
  1.5160 +  return false;
  1.5161 +}
  1.5162 +
  1.5163 +// aCorner is a "full corner" value, i.e. NS_CORNER_TOP_LEFT etc
  1.5164 +static bool IsCornerAdjacentToSide(uint8_t aCorner, css::Side aSide)
  1.5165 +{
  1.5166 +  PR_STATIC_ASSERT((int)NS_SIDE_TOP == NS_CORNER_TOP_LEFT);
  1.5167 +  PR_STATIC_ASSERT((int)NS_SIDE_RIGHT == NS_CORNER_TOP_RIGHT);
  1.5168 +  PR_STATIC_ASSERT((int)NS_SIDE_BOTTOM == NS_CORNER_BOTTOM_RIGHT);
  1.5169 +  PR_STATIC_ASSERT((int)NS_SIDE_LEFT == NS_CORNER_BOTTOM_LEFT);
  1.5170 +  PR_STATIC_ASSERT((int)NS_SIDE_TOP == ((NS_CORNER_TOP_RIGHT - 1)&3));
  1.5171 +  PR_STATIC_ASSERT((int)NS_SIDE_RIGHT == ((NS_CORNER_BOTTOM_RIGHT - 1)&3));
  1.5172 +  PR_STATIC_ASSERT((int)NS_SIDE_BOTTOM == ((NS_CORNER_BOTTOM_LEFT - 1)&3));
  1.5173 +  PR_STATIC_ASSERT((int)NS_SIDE_LEFT == ((NS_CORNER_TOP_LEFT - 1)&3));
  1.5174 +
  1.5175 +  return aSide == aCorner || aSide == ((aCorner - 1)&3);
  1.5176 +}
  1.5177 +
  1.5178 +/* static */ bool
  1.5179 +nsLayoutUtils::HasNonZeroCornerOnSide(const nsStyleCorners& aCorners,
  1.5180 +                                      css::Side aSide)
  1.5181 +{
  1.5182 +  PR_STATIC_ASSERT(NS_CORNER_TOP_LEFT_X/2 == NS_CORNER_TOP_LEFT);
  1.5183 +  PR_STATIC_ASSERT(NS_CORNER_TOP_LEFT_Y/2 == NS_CORNER_TOP_LEFT);
  1.5184 +  PR_STATIC_ASSERT(NS_CORNER_TOP_RIGHT_X/2 == NS_CORNER_TOP_RIGHT);
  1.5185 +  PR_STATIC_ASSERT(NS_CORNER_TOP_RIGHT_Y/2 == NS_CORNER_TOP_RIGHT);
  1.5186 +  PR_STATIC_ASSERT(NS_CORNER_BOTTOM_RIGHT_X/2 == NS_CORNER_BOTTOM_RIGHT);
  1.5187 +  PR_STATIC_ASSERT(NS_CORNER_BOTTOM_RIGHT_Y/2 == NS_CORNER_BOTTOM_RIGHT);
  1.5188 +  PR_STATIC_ASSERT(NS_CORNER_BOTTOM_LEFT_X/2 == NS_CORNER_BOTTOM_LEFT);
  1.5189 +  PR_STATIC_ASSERT(NS_CORNER_BOTTOM_LEFT_Y/2 == NS_CORNER_BOTTOM_LEFT);
  1.5190 +
  1.5191 +  NS_FOR_CSS_HALF_CORNERS(corner) {
  1.5192 +    // corner is a "half corner" value, so dividing by two gives us a
  1.5193 +    // "full corner" value.
  1.5194 +    if (NonZeroStyleCoord(aCorners.Get(corner)) &&
  1.5195 +        IsCornerAdjacentToSide(corner/2, aSide))
  1.5196 +      return true;
  1.5197 +  }
  1.5198 +  return false;
  1.5199 +}
  1.5200 +
  1.5201 +/* static */ nsTransparencyMode
  1.5202 +nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame,
  1.5203 +                                    nsIFrame* aCSSRootFrame) {
  1.5204 +  if (aCSSRootFrame->StyleDisplay()->mOpacity < 1.0f)
  1.5205 +    return eTransparencyTransparent;
  1.5206 +
  1.5207 +  if (HasNonZeroCorner(aCSSRootFrame->StyleBorder()->mBorderRadius))
  1.5208 +    return eTransparencyTransparent;
  1.5209 +
  1.5210 +  if (aCSSRootFrame->StyleDisplay()->mAppearance == NS_THEME_WIN_GLASS)
  1.5211 +    return eTransparencyGlass;
  1.5212 +
  1.5213 +  if (aCSSRootFrame->StyleDisplay()->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS)
  1.5214 +    return eTransparencyBorderlessGlass;
  1.5215 +
  1.5216 +  nsITheme::Transparency transparency;
  1.5217 +  if (aCSSRootFrame->IsThemed(&transparency))
  1.5218 +    return transparency == nsITheme::eTransparent
  1.5219 +         ? eTransparencyTransparent
  1.5220 +         : eTransparencyOpaque;
  1.5221 +
  1.5222 +  // We need an uninitialized window to be treated as opaque because
  1.5223 +  // doing otherwise breaks window display effects on some platforms,
  1.5224 +  // specifically Vista. (bug 450322)
  1.5225 +  if (aBackgroundFrame->GetType() == nsGkAtoms::viewportFrame &&
  1.5226 +      !aBackgroundFrame->GetFirstPrincipalChild()) {
  1.5227 +    return eTransparencyOpaque;
  1.5228 +  }
  1.5229 +
  1.5230 +  nsStyleContext* bgSC;
  1.5231 +  if (!nsCSSRendering::FindBackground(aBackgroundFrame, &bgSC)) {
  1.5232 +    return eTransparencyTransparent;
  1.5233 +  }
  1.5234 +  const nsStyleBackground* bg = bgSC->StyleBackground();
  1.5235 +  if (NS_GET_A(bg->mBackgroundColor) < 255 ||
  1.5236 +      // bottom layer's clip is used for the color
  1.5237 +      bg->BottomLayer().mClip != NS_STYLE_BG_CLIP_BORDER)
  1.5238 +    return eTransparencyTransparent;
  1.5239 +  return eTransparencyOpaque;
  1.5240 +}
  1.5241 +
  1.5242 +static bool IsPopupFrame(nsIFrame* aFrame)
  1.5243 +{
  1.5244 +  // aFrame is a popup it's the list control frame dropdown for a combobox.
  1.5245 +  nsIAtom* frameType = aFrame->GetType();
  1.5246 +  if (frameType == nsGkAtoms::listControlFrame) {
  1.5247 +    nsListControlFrame* lcf = static_cast<nsListControlFrame*>(aFrame);
  1.5248 +    return lcf->IsInDropDownMode();
  1.5249 +  }
  1.5250 +
  1.5251 +  // ... or if it's a XUL menupopup frame.
  1.5252 +  return frameType == nsGkAtoms::menuPopupFrame;
  1.5253 +}
  1.5254 +
  1.5255 +/* static */ bool
  1.5256 +nsLayoutUtils::IsPopup(nsIFrame* aFrame)
  1.5257 +{
  1.5258 +  // Optimization: the frame can't possibly be a popup if it has no view.
  1.5259 +  if (!aFrame->HasView()) {
  1.5260 +    NS_ASSERTION(!IsPopupFrame(aFrame), "popup frame must have a view");
  1.5261 +    return false;
  1.5262 +  }
  1.5263 +  return IsPopupFrame(aFrame);
  1.5264 +}
  1.5265 +
  1.5266 +/* static */ nsIFrame*
  1.5267 +nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
  1.5268 +{
  1.5269 +  // We could use GetRootPresContext() here if the
  1.5270 +  // NS_FRAME_IN_POPUP frame bit is set.
  1.5271 +  nsIFrame* f = aFrame;
  1.5272 +  for (;;) {
  1.5273 +    if (!f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
  1.5274 +      f = f->PresContext()->FrameManager()->GetRootFrame();
  1.5275 +    } else if (IsPopup(f)) {
  1.5276 +      return f;
  1.5277 +    }
  1.5278 +    nsIFrame* parent = GetCrossDocParentFrame(f);
  1.5279 +    if (!parent)
  1.5280 +      return f;
  1.5281 +    f = parent;
  1.5282 +  }
  1.5283 +}
  1.5284 +
  1.5285 +/* static */ nsIFrame*
  1.5286 +nsLayoutUtils::GetReferenceFrame(nsIFrame* aFrame)
  1.5287 +{
  1.5288 +  nsIFrame *f = aFrame;
  1.5289 +  for (;;) {
  1.5290 +    if (f->IsTransformed() || IsPopup(f)) {
  1.5291 +      return f;
  1.5292 +    }
  1.5293 +    nsIFrame* parent = GetCrossDocParentFrame(f);
  1.5294 +    if (!parent) {
  1.5295 +      return f;
  1.5296 +    }
  1.5297 +    f = parent;
  1.5298 +  }
  1.5299 +}
  1.5300 +
  1.5301 +/* static */ nsIFrame*
  1.5302 +nsLayoutUtils::GetTransformRootFrame(nsIFrame* aFrame)
  1.5303 +{
  1.5304 +  nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
  1.5305 +  while (parent && parent->Preserves3DChildren()) {
  1.5306 +    parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
  1.5307 +  }
  1.5308 +  return parent;
  1.5309 +}
  1.5310 +
  1.5311 +/* static */ uint32_t
  1.5312 +nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
  1.5313 +                                       const nsStyleFont* aStyleFont,
  1.5314 +                                       const nsStyleText* aStyleText,
  1.5315 +                                       nscoord aLetterSpacing)
  1.5316 +{
  1.5317 +  uint32_t result = 0;
  1.5318 +  if (aLetterSpacing != 0) {
  1.5319 +    result |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES;
  1.5320 +  }
  1.5321 +  if (aStyleText->mControlCharacterVisibility == NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN) {
  1.5322 +    result |= gfxTextRunFactory::TEXT_HIDE_CONTROL_CHARACTERS;
  1.5323 +  }
  1.5324 +  switch (aStyleContext->StyleSVG()->mTextRendering) {
  1.5325 +  case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
  1.5326 +    result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
  1.5327 +    break;
  1.5328 +  case NS_STYLE_TEXT_RENDERING_AUTO:
  1.5329 +    if (aStyleFont->mFont.size <
  1.5330 +        aStyleContext->PresContext()->GetAutoQualityMinFontSize()) {
  1.5331 +      result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
  1.5332 +    }
  1.5333 +    break;
  1.5334 +  default:
  1.5335 +    break;
  1.5336 +  }
  1.5337 +  return result;
  1.5338 +}
  1.5339 +
  1.5340 +/* static */ void
  1.5341 +nsLayoutUtils::GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
  1.5342 +                                       nsRect* aHStrip, nsRect* aVStrip) {
  1.5343 +  NS_ASSERTION(aR1.TopLeft() == aR2.TopLeft(),
  1.5344 +               "expected rects at the same position");
  1.5345 +  nsRect unionRect(aR1.x, aR1.y, std::max(aR1.width, aR2.width),
  1.5346 +                   std::max(aR1.height, aR2.height));
  1.5347 +  nscoord VStripStart = std::min(aR1.width, aR2.width);
  1.5348 +  nscoord HStripStart = std::min(aR1.height, aR2.height);
  1.5349 +  *aVStrip = unionRect;
  1.5350 +  aVStrip->x += VStripStart;
  1.5351 +  aVStrip->width -= VStripStart;
  1.5352 +  *aHStrip = unionRect;
  1.5353 +  aHStrip->y += HStripStart;
  1.5354 +  aHStrip->height -= HStripStart;
  1.5355 +}
  1.5356 +
  1.5357 +nsDeviceContext*
  1.5358 +nsLayoutUtils::GetDeviceContextForScreenInfo(nsPIDOMWindow* aWindow)
  1.5359 +{
  1.5360 +  if (!aWindow) {
  1.5361 +    return nullptr;
  1.5362 +  }
  1.5363 +
  1.5364 +  nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
  1.5365 +  while (docShell) {
  1.5366 +    // Now make sure our size is up to date.  That will mean that the device
  1.5367 +    // context does the right thing on multi-monitor systems when we return it to
  1.5368 +    // the caller.  It will also make sure that our prescontext has been created,
  1.5369 +    // if we're supposed to have one.
  1.5370 +    nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(docShell);
  1.5371 +    if (!win) {
  1.5372 +      // No reason to go on
  1.5373 +      return nullptr;
  1.5374 +    }
  1.5375 +
  1.5376 +    win->EnsureSizeUpToDate();
  1.5377 +
  1.5378 +    nsRefPtr<nsPresContext> presContext;
  1.5379 +    docShell->GetPresContext(getter_AddRefs(presContext));
  1.5380 +    if (presContext) {
  1.5381 +      nsDeviceContext* context = presContext->DeviceContext();
  1.5382 +      if (context) {
  1.5383 +        return context;
  1.5384 +      }
  1.5385 +    }
  1.5386 +
  1.5387 +    nsCOMPtr<nsIDocShellTreeItem> parentItem;
  1.5388 +    docShell->GetParent(getter_AddRefs(parentItem));
  1.5389 +    docShell = do_QueryInterface(parentItem);
  1.5390 +  }
  1.5391 +
  1.5392 +  return nullptr;
  1.5393 +}
  1.5394 +
  1.5395 +/* static */ bool
  1.5396 +nsLayoutUtils::IsReallyFixedPos(nsIFrame* aFrame)
  1.5397 +{
  1.5398 +  NS_PRECONDITION(aFrame->GetParent(),
  1.5399 +                  "IsReallyFixedPos called on frame not in tree");
  1.5400 +  NS_PRECONDITION(aFrame->StyleDisplay()->mPosition ==
  1.5401 +                    NS_STYLE_POSITION_FIXED,
  1.5402 +                  "IsReallyFixedPos called on non-'position:fixed' frame");
  1.5403 +
  1.5404 +  nsIAtom *parentType = aFrame->GetParent()->GetType();
  1.5405 +  return parentType == nsGkAtoms::viewportFrame ||
  1.5406 +         parentType == nsGkAtoms::pageContentFrame;
  1.5407 +}
  1.5408 +
  1.5409 +nsLayoutUtils::SurfaceFromElementResult
  1.5410 +nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement,
  1.5411 +                                  uint32_t aSurfaceFlags,
  1.5412 +                                  DrawTarget* aTarget)
  1.5413 +{
  1.5414 +  SurfaceFromElementResult result;
  1.5415 +  nsresult rv;
  1.5416 +
  1.5417 +  nsCOMPtr<imgIRequest> imgRequest;
  1.5418 +  rv = aElement->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
  1.5419 +                            getter_AddRefs(imgRequest));
  1.5420 +  if (NS_FAILED(rv) || !imgRequest)
  1.5421 +    return result;
  1.5422 +
  1.5423 +  uint32_t status;
  1.5424 +  imgRequest->GetImageStatus(&status);
  1.5425 +  if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
  1.5426 +    // Spec says to use GetComplete, but that only works on
  1.5427 +    // nsIDOMHTMLImageElement, and we support all sorts of other stuff
  1.5428 +    // here.  Do this for now pending spec clarification.
  1.5429 +    result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
  1.5430 +    return result;
  1.5431 +  }
  1.5432 +
  1.5433 +  nsCOMPtr<nsIPrincipal> principal;
  1.5434 +  rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
  1.5435 +  if (NS_FAILED(rv))
  1.5436 +    return result;
  1.5437 +
  1.5438 +  nsCOMPtr<imgIContainer> imgContainer;
  1.5439 +  rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
  1.5440 +  if (NS_FAILED(rv))
  1.5441 +    return result;
  1.5442 +
  1.5443 +  uint32_t noRasterize = aSurfaceFlags & SFE_NO_RASTERIZING_VECTORS;
  1.5444 +
  1.5445 +  uint32_t whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME)
  1.5446 +                        ? (uint32_t) imgIContainer::FRAME_FIRST
  1.5447 +                        : (uint32_t) imgIContainer::FRAME_CURRENT;
  1.5448 +  uint32_t frameFlags = imgIContainer::FLAG_SYNC_DECODE;
  1.5449 +  if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
  1.5450 +    frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
  1.5451 +  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
  1.5452 +    frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
  1.5453 +    result.mIsPremultiplied = false;
  1.5454 +  }
  1.5455 +
  1.5456 +  int32_t imgWidth, imgHeight;
  1.5457 +  rv = imgContainer->GetWidth(&imgWidth);
  1.5458 +  nsresult rv2 = imgContainer->GetHeight(&imgHeight);
  1.5459 +  if (NS_FAILED(rv) || NS_FAILED(rv2))
  1.5460 +    return result;
  1.5461 +
  1.5462 +  if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
  1.5463 +    if (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) {
  1.5464 +      frameFlags |= imgIContainer::FLAG_WANT_DATA_SURFACE;
  1.5465 +    }
  1.5466 +    result.mSourceSurface = imgContainer->GetFrame(whichFrame, frameFlags);
  1.5467 +    if (!result.mSourceSurface) {
  1.5468 +      return result;
  1.5469 +    }
  1.5470 +    // The surface we return is likely to be cached. We don't want to have to
  1.5471 +    // convert to a surface that's compatible with aTarget each time it's used
  1.5472 +    // (that would result in terrible performance), so we convert once here
  1.5473 +    // upfront if aTarget is specified.
  1.5474 +    if (aTarget) {
  1.5475 +      RefPtr<SourceSurface> optSurface =
  1.5476 +        aTarget->OptimizeSourceSurface(result.mSourceSurface);
  1.5477 +      if (optSurface) {
  1.5478 +        result.mSourceSurface = optSurface;
  1.5479 +      }
  1.5480 +    }
  1.5481 +  } else {
  1.5482 +    result.mDrawInfo.mImgContainer = imgContainer;
  1.5483 +    result.mDrawInfo.mWhichFrame = whichFrame;
  1.5484 +    result.mDrawInfo.mDrawingFlags = frameFlags;
  1.5485 +  }
  1.5486 +
  1.5487 +  int32_t corsmode;
  1.5488 +  if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
  1.5489 +    result.mCORSUsed = (corsmode != imgIRequest::CORS_NONE);
  1.5490 +  }
  1.5491 +
  1.5492 +  result.mSize = gfxIntSize(imgWidth, imgHeight);
  1.5493 +  result.mPrincipal = principal.forget();
  1.5494 +  // no images, including SVG images, can load content from another domain.
  1.5495 +  result.mIsWriteOnly = false;
  1.5496 +  result.mImageRequest = imgRequest.forget();
  1.5497 +
  1.5498 +  return result;
  1.5499 +}
  1.5500 +
  1.5501 +nsLayoutUtils::SurfaceFromElementResult
  1.5502 +nsLayoutUtils::SurfaceFromElement(HTMLImageElement *aElement,
  1.5503 +                                  uint32_t aSurfaceFlags,
  1.5504 +                                  DrawTarget* aTarget)
  1.5505 +{
  1.5506 +  return SurfaceFromElement(static_cast<nsIImageLoadingContent*>(aElement),
  1.5507 +                            aSurfaceFlags, aTarget);
  1.5508 +}
  1.5509 +
  1.5510 +nsLayoutUtils::SurfaceFromElementResult
  1.5511 +nsLayoutUtils::SurfaceFromElement(HTMLCanvasElement* aElement,
  1.5512 +                                  uint32_t aSurfaceFlags,
  1.5513 +                                  DrawTarget* aTarget)
  1.5514 +{
  1.5515 +  SurfaceFromElementResult result;
  1.5516 +
  1.5517 +  bool* isPremultiplied = nullptr;
  1.5518 +  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
  1.5519 +    isPremultiplied = &result.mIsPremultiplied;
  1.5520 +  }
  1.5521 +
  1.5522 +  gfxIntSize size = aElement->GetSize();
  1.5523 +
  1.5524 +  result.mSourceSurface = aElement->GetSurfaceSnapshot(isPremultiplied);
  1.5525 +  if (!result.mSourceSurface) {
  1.5526 +     // 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
  1.5527 +     // draw nothing, so return an empty surface.
  1.5528 +     DrawTarget *ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
  1.5529 +     RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
  1.5530 +                                                          SurfaceFormat::B8G8R8A8);
  1.5531 +     if (dt) {
  1.5532 +       result.mSourceSurface = dt->Snapshot();
  1.5533 +     }
  1.5534 +  } else if (aTarget) {
  1.5535 +    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
  1.5536 +    if (opt) {
  1.5537 +      result.mSourceSurface = opt;
  1.5538 +    }
  1.5539 +  }
  1.5540 +
  1.5541 +  // Ensure that any future changes to the canvas trigger proper invalidation,
  1.5542 +  // in case this is being used by -moz-element()
  1.5543 +  aElement->MarkContextClean();
  1.5544 +
  1.5545 +  result.mSize = size;
  1.5546 +  result.mPrincipal = aElement->NodePrincipal();
  1.5547 +  result.mIsWriteOnly = aElement->IsWriteOnly();
  1.5548 +
  1.5549 +  return result;
  1.5550 +}
  1.5551 +
  1.5552 +nsLayoutUtils::SurfaceFromElementResult
  1.5553 +nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
  1.5554 +                                  uint32_t aSurfaceFlags,
  1.5555 +                                  DrawTarget* aTarget)
  1.5556 +{
  1.5557 +  SurfaceFromElementResult result;
  1.5558 +
  1.5559 +  NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
  1.5560 +
  1.5561 +  uint16_t readyState;
  1.5562 +  if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) &&
  1.5563 +      (readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
  1.5564 +       readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) {
  1.5565 +    result.mIsStillLoading = true;
  1.5566 +    return result;
  1.5567 +  }
  1.5568 +
  1.5569 +  // If it doesn't have a principal, just bail
  1.5570 +  nsCOMPtr<nsIPrincipal> principal = aElement->GetCurrentPrincipal();
  1.5571 +  if (!principal)
  1.5572 +    return result;
  1.5573 +
  1.5574 +  ImageContainer *container = aElement->GetImageContainer();
  1.5575 +  if (!container)
  1.5576 +    return result;
  1.5577 +
  1.5578 +  mozilla::gfx::IntSize size;
  1.5579 +  result.mSourceSurface = container->GetCurrentAsSourceSurface(&size);
  1.5580 +  if (!result.mSourceSurface)
  1.5581 +    return result;
  1.5582 +
  1.5583 +  if (aTarget) {
  1.5584 +    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
  1.5585 +    if (opt) {
  1.5586 +      result.mSourceSurface = opt;
  1.5587 +    }
  1.5588 +  }
  1.5589 +
  1.5590 +  result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
  1.5591 +  result.mSize = ThebesIntSize(size);
  1.5592 +  result.mPrincipal = principal.forget();
  1.5593 +  result.mIsWriteOnly = false;
  1.5594 +
  1.5595 +  return result;
  1.5596 +}
  1.5597 +
  1.5598 +nsLayoutUtils::SurfaceFromElementResult
  1.5599 +nsLayoutUtils::SurfaceFromElement(dom::Element* aElement,
  1.5600 +                                  uint32_t aSurfaceFlags,
  1.5601 +                                  DrawTarget* aTarget)
  1.5602 +{
  1.5603 +  // If it's a <canvas>, we may be able to just grab its internal surface
  1.5604 +  if (HTMLCanvasElement* canvas =
  1.5605 +        HTMLCanvasElement::FromContentOrNull(aElement)) {
  1.5606 +    return SurfaceFromElement(canvas, aSurfaceFlags, aTarget);
  1.5607 +  }
  1.5608 +
  1.5609 +  // Maybe it's <video>?
  1.5610 +  if (HTMLVideoElement* video =
  1.5611 +        HTMLVideoElement::FromContentOrNull(aElement)) {
  1.5612 +    return SurfaceFromElement(video, aSurfaceFlags, aTarget);
  1.5613 +  }
  1.5614 +
  1.5615 +  // Finally, check if it's a normal image
  1.5616 +  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
  1.5617 +
  1.5618 +  if (!imageLoader) {
  1.5619 +    return SurfaceFromElementResult();
  1.5620 +  }
  1.5621 +
  1.5622 +  return SurfaceFromElement(imageLoader, aSurfaceFlags, aTarget);
  1.5623 +}
  1.5624 +
  1.5625 +/* static */
  1.5626 +nsIContent*
  1.5627 +nsLayoutUtils::GetEditableRootContentByContentEditable(nsIDocument* aDocument)
  1.5628 +{
  1.5629 +  // If the document is in designMode we should return nullptr.
  1.5630 +  if (!aDocument || aDocument->HasFlag(NODE_IS_EDITABLE)) {
  1.5631 +    return nullptr;
  1.5632 +  }
  1.5633 +
  1.5634 +  // contenteditable only works with HTML document.
  1.5635 +  // Note: Use nsIDOMHTMLDocument rather than nsIHTMLDocument for getting the
  1.5636 +  //       body node because nsIDOMHTMLDocument::GetBody() does something
  1.5637 +  //       additional work for some cases and nsEditor uses them.
  1.5638 +  nsCOMPtr<nsIDOMHTMLDocument> domHTMLDoc = do_QueryInterface(aDocument);
  1.5639 +  if (!domHTMLDoc) {
  1.5640 +    return nullptr;
  1.5641 +  }
  1.5642 +
  1.5643 +  Element* rootElement = aDocument->GetRootElement();
  1.5644 +  if (rootElement && rootElement->IsEditable()) {
  1.5645 +    return rootElement;
  1.5646 +  }
  1.5647 +
  1.5648 +  // If there are no editable root element, check its <body> element.
  1.5649 +  // Note that the body element could be <frameset> element.
  1.5650 +  nsCOMPtr<nsIDOMHTMLElement> body;
  1.5651 +  nsresult rv = domHTMLDoc->GetBody(getter_AddRefs(body));
  1.5652 +  nsCOMPtr<nsIContent> content = do_QueryInterface(body);
  1.5653 +  if (NS_SUCCEEDED(rv) && content && content->IsEditable()) {
  1.5654 +    return content;
  1.5655 +  }
  1.5656 +  return nullptr;
  1.5657 +}
  1.5658 +
  1.5659 +#ifdef DEBUG
  1.5660 +/* static */ void
  1.5661 +nsLayoutUtils::AssertNoDuplicateContinuations(nsIFrame* aContainer,
  1.5662 +                                              const nsFrameList& aFrameList)
  1.5663 +{
  1.5664 +  for (nsIFrame* f = aFrameList.FirstChild(); f ; f = f->GetNextSibling()) {
  1.5665 +    // Check only later continuations of f; we deal with checking the
  1.5666 +    // earlier continuations when we hit those earlier continuations in
  1.5667 +    // the frame list.
  1.5668 +    for (nsIFrame *c = f; (c = c->GetNextInFlow());) {
  1.5669 +      NS_ASSERTION(c->GetParent() != aContainer ||
  1.5670 +                   !aFrameList.ContainsFrame(c),
  1.5671 +                   "Two continuations of the same frame in the same "
  1.5672 +                   "frame list");
  1.5673 +    }
  1.5674 +  }
  1.5675 +}
  1.5676 +
  1.5677 +// Is one of aFrame's ancestors a letter frame?
  1.5678 +static bool
  1.5679 +IsInLetterFrame(nsIFrame *aFrame)
  1.5680 +{
  1.5681 +  for (nsIFrame *f = aFrame->GetParent(); f; f = f->GetParent()) {
  1.5682 +    if (f->GetType() == nsGkAtoms::letterFrame) {
  1.5683 +      return true;
  1.5684 +    }
  1.5685 +  }
  1.5686 +  return false;
  1.5687 +}
  1.5688 +
  1.5689 +/* static */ void
  1.5690 +nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot)
  1.5691 +{
  1.5692 +  NS_ASSERTION(aSubtreeRoot->GetPrevInFlow(),
  1.5693 +               "frame tree not empty, but caller reported complete status");
  1.5694 +
  1.5695 +  // Also assert that text frames map no text.
  1.5696 +  int32_t start, end;
  1.5697 +  nsresult rv = aSubtreeRoot->GetOffsets(start, end);
  1.5698 +  NS_ASSERTION(NS_SUCCEEDED(rv), "GetOffsets failed");
  1.5699 +  // In some cases involving :first-letter, we'll partially unlink a
  1.5700 +  // continuation in the middle of a continuation chain from its
  1.5701 +  // previous and next continuations before destroying it, presumably so
  1.5702 +  // that we don't also destroy the later continuations.  Once we've
  1.5703 +  // done this, GetOffsets returns incorrect values.
  1.5704 +  // For examples, see list of tests in
  1.5705 +  // https://bugzilla.mozilla.org/show_bug.cgi?id=619021#c29
  1.5706 +  NS_ASSERTION(start == end || IsInLetterFrame(aSubtreeRoot),
  1.5707 +               "frame tree not empty, but caller reported complete status");
  1.5708 +
  1.5709 +  nsIFrame::ChildListIterator lists(aSubtreeRoot);
  1.5710 +  for (; !lists.IsDone(); lists.Next()) {
  1.5711 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
  1.5712 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
  1.5713 +      nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(childFrames.get());
  1.5714 +    }
  1.5715 +  }
  1.5716 +}
  1.5717 +#endif
  1.5718 +
  1.5719 +static void
  1.5720 +GetFontFacesForFramesInner(nsIFrame* aFrame, nsFontFaceList* aFontFaceList)
  1.5721 +{
  1.5722 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.5723 +
  1.5724 +  if (aFrame->GetType() == nsGkAtoms::textFrame) {
  1.5725 +    if (!aFrame->GetPrevContinuation()) {
  1.5726 +      nsLayoutUtils::GetFontFacesForText(aFrame, 0, INT32_MAX, true,
  1.5727 +                                         aFontFaceList);
  1.5728 +    }
  1.5729 +    return;
  1.5730 +  }
  1.5731 +
  1.5732 +  nsIFrame::ChildListID childLists[] = { nsIFrame::kPrincipalList,
  1.5733 +                                         nsIFrame::kPopupList };
  1.5734 +  for (size_t i = 0; i < ArrayLength(childLists); ++i) {
  1.5735 +    nsFrameList children(aFrame->GetChildList(childLists[i]));
  1.5736 +    for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
  1.5737 +      nsIFrame* child = e.get();
  1.5738 +      child = nsPlaceholderFrame::GetRealFrameFor(child);
  1.5739 +      GetFontFacesForFramesInner(child, aFontFaceList);
  1.5740 +    }
  1.5741 +  }
  1.5742 +}
  1.5743 +
  1.5744 +/* static */
  1.5745 +nsresult
  1.5746 +nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame,
  1.5747 +                                     nsFontFaceList* aFontFaceList)
  1.5748 +{
  1.5749 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.5750 +
  1.5751 +  while (aFrame) {
  1.5752 +    GetFontFacesForFramesInner(aFrame, aFontFaceList);
  1.5753 +    aFrame = GetNextContinuationOrIBSplitSibling(aFrame);
  1.5754 +  }
  1.5755 +
  1.5756 +  return NS_OK;
  1.5757 +}
  1.5758 +
  1.5759 +/* static */
  1.5760 +nsresult
  1.5761 +nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame,
  1.5762 +                                   int32_t aStartOffset, int32_t aEndOffset,
  1.5763 +                                   bool aFollowContinuations,
  1.5764 +                                   nsFontFaceList* aFontFaceList)
  1.5765 +{
  1.5766 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.5767 +
  1.5768 +  if (aFrame->GetType() != nsGkAtoms::textFrame) {
  1.5769 +    return NS_OK;
  1.5770 +  }
  1.5771 +
  1.5772 +  nsTextFrame* curr = static_cast<nsTextFrame*>(aFrame);
  1.5773 +  do {
  1.5774 +    int32_t fstart = std::max(curr->GetContentOffset(), aStartOffset);
  1.5775 +    int32_t fend = std::min(curr->GetContentEnd(), aEndOffset);
  1.5776 +    if (fstart >= fend) {
  1.5777 +      curr = static_cast<nsTextFrame*>(curr->GetNextContinuation());
  1.5778 +      continue;
  1.5779 +    }
  1.5780 +
  1.5781 +    // curr is overlapping with the offset we want
  1.5782 +    gfxSkipCharsIterator iter = curr->EnsureTextRun(nsTextFrame::eInflated);
  1.5783 +    gfxTextRun* textRun = curr->GetTextRun(nsTextFrame::eInflated);
  1.5784 +    NS_ENSURE_TRUE(textRun, NS_ERROR_OUT_OF_MEMORY);
  1.5785 +
  1.5786 +    // include continuations in the range that share the same textrun
  1.5787 +    nsTextFrame* next = nullptr;
  1.5788 +    if (aFollowContinuations && fend < aEndOffset) {
  1.5789 +      next = static_cast<nsTextFrame*>(curr->GetNextContinuation());
  1.5790 +      while (next && next->GetTextRun(nsTextFrame::eInflated) == textRun) {
  1.5791 +        fend = std::min(next->GetContentEnd(), aEndOffset);
  1.5792 +        next = fend < aEndOffset ?
  1.5793 +          static_cast<nsTextFrame*>(next->GetNextContinuation()) : nullptr;
  1.5794 +      }
  1.5795 +    }
  1.5796 +
  1.5797 +    uint32_t skipStart = iter.ConvertOriginalToSkipped(fstart);
  1.5798 +    uint32_t skipEnd = iter.ConvertOriginalToSkipped(fend);
  1.5799 +    aFontFaceList->AddFontsFromTextRun(textRun, skipStart, skipEnd - skipStart);
  1.5800 +    curr = next;
  1.5801 +  } while (aFollowContinuations && curr);
  1.5802 +
  1.5803 +  return NS_OK;
  1.5804 +}
  1.5805 +
  1.5806 +/* static */
  1.5807 +size_t
  1.5808 +nsLayoutUtils::SizeOfTextRunsForFrames(nsIFrame* aFrame,
  1.5809 +                                       MallocSizeOf aMallocSizeOf,
  1.5810 +                                       bool clear)
  1.5811 +{
  1.5812 +  NS_PRECONDITION(aFrame, "NULL frame pointer");
  1.5813 +
  1.5814 +  size_t total = 0;
  1.5815 +
  1.5816 +  if (aFrame->GetType() == nsGkAtoms::textFrame) {
  1.5817 +    nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
  1.5818 +    for (uint32_t i = 0; i < 2; ++i) {
  1.5819 +      gfxTextRun *run = textFrame->GetTextRun(
  1.5820 +        (i != 0) ? nsTextFrame::eInflated : nsTextFrame::eNotInflated);
  1.5821 +      if (run) {
  1.5822 +        if (clear) {
  1.5823 +          run->ResetSizeOfAccountingFlags();
  1.5824 +        } else {
  1.5825 +          total += run->MaybeSizeOfIncludingThis(aMallocSizeOf);
  1.5826 +        }
  1.5827 +      }
  1.5828 +    }
  1.5829 +    return total;
  1.5830 +  }
  1.5831 +
  1.5832 +  nsAutoTArray<nsIFrame::ChildList,4> childListArray;
  1.5833 +  aFrame->GetChildLists(&childListArray);
  1.5834 +
  1.5835 +  for (nsIFrame::ChildListArrayIterator childLists(childListArray);
  1.5836 +       !childLists.IsDone(); childLists.Next()) {
  1.5837 +    for (nsFrameList::Enumerator e(childLists.CurrentList());
  1.5838 +         !e.AtEnd(); e.Next()) {
  1.5839 +      total += SizeOfTextRunsForFrames(e.get(), aMallocSizeOf, clear);
  1.5840 +    }
  1.5841 +  }
  1.5842 +  return total;
  1.5843 +}
  1.5844 +
  1.5845 +/* static */
  1.5846 +void
  1.5847 +nsLayoutUtils::Initialize()
  1.5848 +{
  1.5849 +  Preferences::AddUintVarCache(&sFontSizeInflationMaxRatio,
  1.5850 +                               "font.size.inflation.maxRatio");
  1.5851 +  Preferences::AddUintVarCache(&sFontSizeInflationEmPerLine,
  1.5852 +                               "font.size.inflation.emPerLine");
  1.5853 +  Preferences::AddUintVarCache(&sFontSizeInflationMinTwips,
  1.5854 +                               "font.size.inflation.minTwips");
  1.5855 +  Preferences::AddUintVarCache(&sFontSizeInflationLineThreshold,
  1.5856 +                               "font.size.inflation.lineThreshold");
  1.5857 +  Preferences::AddIntVarCache(&sFontSizeInflationMappingIntercept,
  1.5858 +                              "font.size.inflation.mappingIntercept");
  1.5859 +  Preferences::AddBoolVarCache(&sFontSizeInflationForceEnabled,
  1.5860 +                               "font.size.inflation.forceEnabled");
  1.5861 +  Preferences::AddBoolVarCache(&sFontSizeInflationDisabledInMasterProcess,
  1.5862 +                               "font.size.inflation.disabledInMasterProcess");
  1.5863 +  Preferences::AddBoolVarCache(&sInvalidationDebuggingIsEnabled,
  1.5864 +                               "nglayout.debug.invalidation");
  1.5865 +  Preferences::AddBoolVarCache(&sCSSVariablesEnabled,
  1.5866 +                               "layout.css.variables.enabled");
  1.5867 +  Preferences::AddBoolVarCache(&sInterruptibleReflowEnabled,
  1.5868 +                               "layout.interruptible-reflow.enabled");
  1.5869 +
  1.5870 +  Preferences::RegisterCallback(GridEnabledPrefChangeCallback,
  1.5871 +                                GRID_ENABLED_PREF_NAME);
  1.5872 +  GridEnabledPrefChangeCallback(GRID_ENABLED_PREF_NAME, nullptr);
  1.5873 +  Preferences::RegisterCallback(StickyEnabledPrefChangeCallback,
  1.5874 +                                STICKY_ENABLED_PREF_NAME);
  1.5875 +  StickyEnabledPrefChangeCallback(STICKY_ENABLED_PREF_NAME, nullptr);
  1.5876 +  Preferences::RegisterCallback(TextAlignTrueEnabledPrefChangeCallback,
  1.5877 +                                TEXT_ALIGN_TRUE_ENABLED_PREF_NAME);
  1.5878 +  TextAlignTrueEnabledPrefChangeCallback(TEXT_ALIGN_TRUE_ENABLED_PREF_NAME,
  1.5879 +                                         nullptr);
  1.5880 +
  1.5881 +  nsComputedDOMStyle::RegisterPrefChangeCallbacks();
  1.5882 +}
  1.5883 +
  1.5884 +/* static */
  1.5885 +void
  1.5886 +nsLayoutUtils::Shutdown()
  1.5887 +{
  1.5888 +  if (sContentMap) {
  1.5889 +    delete sContentMap;
  1.5890 +    sContentMap = nullptr;
  1.5891 +  }
  1.5892 +
  1.5893 +  Preferences::UnregisterCallback(GridEnabledPrefChangeCallback,
  1.5894 +                                  GRID_ENABLED_PREF_NAME);
  1.5895 +  Preferences::UnregisterCallback(StickyEnabledPrefChangeCallback,
  1.5896 +                                  STICKY_ENABLED_PREF_NAME);
  1.5897 +
  1.5898 +  nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
  1.5899 +}
  1.5900 +
  1.5901 +/* static */
  1.5902 +void
  1.5903 +nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
  1.5904 +                                    imgIRequest* aRequest,
  1.5905 +                                    bool* aRequestRegistered)
  1.5906 +{
  1.5907 +  if (!aPresContext) {
  1.5908 +    return;
  1.5909 +  }
  1.5910 +
  1.5911 +  if (aRequestRegistered && *aRequestRegistered) {
  1.5912 +    // Our request is already registered with the refresh driver, so
  1.5913 +    // no need to register it again.
  1.5914 +    return;
  1.5915 +  }
  1.5916 +
  1.5917 +  if (aRequest) {
  1.5918 +    if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
  1.5919 +      NS_WARNING("Unable to add image request");
  1.5920 +      return;
  1.5921 +    }
  1.5922 +
  1.5923 +    if (aRequestRegistered) {
  1.5924 +      *aRequestRegistered = true;
  1.5925 +    }
  1.5926 +  }
  1.5927 +}
  1.5928 +
  1.5929 +/* static */
  1.5930 +void
  1.5931 +nsLayoutUtils::RegisterImageRequestIfAnimated(nsPresContext* aPresContext,
  1.5932 +                                              imgIRequest* aRequest,
  1.5933 +                                              bool* aRequestRegistered)
  1.5934 +{
  1.5935 +  if (!aPresContext) {
  1.5936 +    return;
  1.5937 +  }
  1.5938 +
  1.5939 +  if (aRequestRegistered && *aRequestRegistered) {
  1.5940 +    // Our request is already registered with the refresh driver, so
  1.5941 +    // no need to register it again.
  1.5942 +    return;
  1.5943 +  }
  1.5944 +
  1.5945 +  if (aRequest) {
  1.5946 +    nsCOMPtr<imgIContainer> image;
  1.5947 +    if (NS_SUCCEEDED(aRequest->GetImage(getter_AddRefs(image)))) {
  1.5948 +      // Check to verify that the image is animated. If so, then add it to the
  1.5949 +      // list of images tracked by the refresh driver.
  1.5950 +      bool isAnimated = false;
  1.5951 +      nsresult rv = image->GetAnimated(&isAnimated);
  1.5952 +      if (NS_SUCCEEDED(rv) && isAnimated) {
  1.5953 +        if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
  1.5954 +          NS_WARNING("Unable to add image request");
  1.5955 +          return;
  1.5956 +        }
  1.5957 +
  1.5958 +        if (aRequestRegistered) {
  1.5959 +          *aRequestRegistered = true;
  1.5960 +        }
  1.5961 +      }
  1.5962 +    }
  1.5963 +  }
  1.5964 +}
  1.5965 +
  1.5966 +/* static */
  1.5967 +void
  1.5968 +nsLayoutUtils::DeregisterImageRequest(nsPresContext* aPresContext,
  1.5969 +                                      imgIRequest* aRequest,
  1.5970 +                                      bool* aRequestRegistered)
  1.5971 +{
  1.5972 +  if (!aPresContext) {
  1.5973 +    return;
  1.5974 +  }
  1.5975 +
  1.5976 +  // Deregister our imgIRequest with the refresh driver to
  1.5977 +  // complete tear-down, but only if it has been registered
  1.5978 +  if (aRequestRegistered && !*aRequestRegistered) {
  1.5979 +    return;
  1.5980 +  }
  1.5981 +
  1.5982 +  if (aRequest) {
  1.5983 +    nsCOMPtr<imgIContainer> image;
  1.5984 +    if (NS_SUCCEEDED(aRequest->GetImage(getter_AddRefs(image)))) {
  1.5985 +      aPresContext->RefreshDriver()->RemoveImageRequest(aRequest);
  1.5986 +
  1.5987 +      if (aRequestRegistered) {
  1.5988 +        *aRequestRegistered = false;
  1.5989 +      }
  1.5990 +    }
  1.5991 +  }
  1.5992 +}
  1.5993 +
  1.5994 +/* static */
  1.5995 +void
  1.5996 +nsLayoutUtils::PostRestyleEvent(Element* aElement,
  1.5997 +                                nsRestyleHint aRestyleHint,
  1.5998 +                                nsChangeHint aMinChangeHint)
  1.5999 +{
  1.6000 +  nsIDocument* doc = aElement->GetCurrentDoc();
  1.6001 +  if (doc) {
  1.6002 +    nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
  1.6003 +    if (presShell) {
  1.6004 +      presShell->GetPresContext()->RestyleManager()->PostRestyleEvent(
  1.6005 +        aElement, aRestyleHint, aMinChangeHint);
  1.6006 +    }
  1.6007 +  }
  1.6008 +}
  1.6009 +
  1.6010 +nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
  1.6011 +                                     const nsAString& aValue)
  1.6012 +  : mContent(aContent),
  1.6013 +    mAttrName(aAttrName),
  1.6014 +    mValue(aValue)
  1.6015 +{
  1.6016 +  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
  1.6017 +}
  1.6018 +
  1.6019 +nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
  1.6020 +                                     int32_t aValue)
  1.6021 +  : mContent(aContent),
  1.6022 +    mAttrName(aAttrName)
  1.6023 +{
  1.6024 +  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
  1.6025 +  mValue.AppendInt(aValue);
  1.6026 +}
  1.6027 +
  1.6028 +NS_IMETHODIMP
  1.6029 +nsSetAttrRunnable::Run()
  1.6030 +{
  1.6031 +  return mContent->SetAttr(kNameSpaceID_None, mAttrName, mValue, true);
  1.6032 +}
  1.6033 +
  1.6034 +nsUnsetAttrRunnable::nsUnsetAttrRunnable(nsIContent* aContent,
  1.6035 +                                         nsIAtom* aAttrName)
  1.6036 +  : mContent(aContent),
  1.6037 +    mAttrName(aAttrName)
  1.6038 +{
  1.6039 +  NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
  1.6040 +}
  1.6041 +
  1.6042 +NS_IMETHODIMP
  1.6043 +nsUnsetAttrRunnable::Run()
  1.6044 +{
  1.6045 +  return mContent->UnsetAttr(kNameSpaceID_None, mAttrName, true);
  1.6046 +}
  1.6047 +
  1.6048 +/**
  1.6049 + * Compute the minimum font size inside of a container with the given
  1.6050 + * width, such that **when the user zooms the container to fill the full
  1.6051 + * width of the device**, the fonts satisfy our minima.
  1.6052 + */
  1.6053 +static nscoord
  1.6054 +MinimumFontSizeFor(nsPresContext* aPresContext, nscoord aContainerWidth)
  1.6055 +{
  1.6056 +  nsIPresShell* presShell = aPresContext->PresShell();
  1.6057 +
  1.6058 +  uint32_t emPerLine = presShell->FontSizeInflationEmPerLine();
  1.6059 +  uint32_t minTwips = presShell->FontSizeInflationMinTwips();
  1.6060 +  if (emPerLine == 0 && minTwips == 0) {
  1.6061 +    return 0;
  1.6062 +  }
  1.6063 +
  1.6064 +  // Clamp the container width to the device dimensions
  1.6065 +  nscoord iFrameWidth = aPresContext->GetVisibleArea().width;
  1.6066 +  nscoord effectiveContainerWidth = std::min(iFrameWidth, aContainerWidth);
  1.6067 +
  1.6068 +  nscoord byLine = 0, byInch = 0;
  1.6069 +  if (emPerLine != 0) {
  1.6070 +    byLine = effectiveContainerWidth / emPerLine;
  1.6071 +  }
  1.6072 +  if (minTwips != 0) {
  1.6073 +    // REVIEW: Is this giving us app units and sizes *not* counting
  1.6074 +    // viewport scaling?
  1.6075 +    float deviceWidthInches =
  1.6076 +      aPresContext->ScreenWidthInchesForFontInflation();
  1.6077 +    byInch = NSToCoordRound(effectiveContainerWidth /
  1.6078 +                            (deviceWidthInches * 1440 /
  1.6079 +                             minTwips ));
  1.6080 +  }
  1.6081 +  return std::max(byLine, byInch);
  1.6082 +}
  1.6083 +
  1.6084 +/* static */ float
  1.6085 +nsLayoutUtils::FontSizeInflationInner(const nsIFrame *aFrame,
  1.6086 +                                      nscoord aMinFontSize)
  1.6087 +{
  1.6088 +  // Note that line heights should be inflated by the same ratio as the
  1.6089 +  // font size of the same text; thus we operate only on the font size
  1.6090 +  // even when we're scaling a line height.
  1.6091 +  nscoord styleFontSize = aFrame->StyleFont()->mFont.size;
  1.6092 +  if (styleFontSize <= 0) {
  1.6093 +    // Never scale zero font size.
  1.6094 +    return 1.0;
  1.6095 +  }
  1.6096 +
  1.6097 +  if (aMinFontSize <= 0) {
  1.6098 +    // No need to scale.
  1.6099 +    return 1.0;
  1.6100 +  }
  1.6101 +
  1.6102 +  // If between this current frame and its font inflation container there is a
  1.6103 +  // non-inline element with fixed width or height, then we should not inflate
  1.6104 +  // fonts for this frame.
  1.6105 +  for (const nsIFrame* f = aFrame;
  1.6106 +       f && !f->IsContainerForFontSizeInflation();
  1.6107 +       f = f->GetParent()) {
  1.6108 +    nsIContent* content = f->GetContent();
  1.6109 +    nsIAtom* fType = f->GetType();
  1.6110 +    // Also, if there is more than one frame corresponding to a single
  1.6111 +    // content node, we want the outermost one.
  1.6112 +    if (!(f->GetParent() && f->GetParent()->GetContent() == content) &&
  1.6113 +        // ignore width/height on inlines since they don't apply
  1.6114 +        fType != nsGkAtoms::inlineFrame &&
  1.6115 +        // ignore width on radios and checkboxes since we enlarge them and
  1.6116 +        // they have width/height in ua.css
  1.6117 +        fType != nsGkAtoms::formControlFrame) {
  1.6118 +      nsStyleCoord stylePosWidth = f->StylePosition()->mWidth;
  1.6119 +      nsStyleCoord stylePosHeight = f->StylePosition()->mHeight;
  1.6120 +      if (stylePosWidth.GetUnit() != eStyleUnit_Auto ||
  1.6121 +          stylePosHeight.GetUnit() != eStyleUnit_Auto) {
  1.6122 +
  1.6123 +        return 1.0;
  1.6124 +      }
  1.6125 +    }
  1.6126 +  }
  1.6127 +
  1.6128 +  int32_t interceptParam = nsLayoutUtils::FontSizeInflationMappingIntercept();
  1.6129 +  float maxRatio = (float)nsLayoutUtils::FontSizeInflationMaxRatio() / 100.0f;
  1.6130 +
  1.6131 +  float ratio = float(styleFontSize) / float(aMinFontSize);
  1.6132 +  float inflationRatio;
  1.6133 +
  1.6134 +  // Given a minimum inflated font size m, a specified font size s, we want to
  1.6135 +  // find the inflated font size i and then return the ratio of i to s (i/s).
  1.6136 +  if (interceptParam >= 0) {
  1.6137 +    // Since the mapping intercept parameter P is greater than zero, we use it
  1.6138 +    // to determine the point where our mapping function intersects the i=s
  1.6139 +    // line. This means that we have an equation of the form:
  1.6140 +    //
  1.6141 +    // i = m + s·(P/2)/(1 + P/2), if s <= (1 + P/2)·m
  1.6142 +    // i = s, if s >= (1 + P/2)·m
  1.6143 +
  1.6144 +    float intercept = 1 + float(interceptParam)/2.0f;
  1.6145 +    if (ratio >= intercept) {
  1.6146 +      // If we're already at 1+P/2 or more times the minimum, don't scale.
  1.6147 +      return 1.0;
  1.6148 +    }
  1.6149 +
  1.6150 +    // The point (intercept, intercept) is where the part of the i vs. s graph
  1.6151 +    // that's not slope 1 meets the i=s line.  (This part of the
  1.6152 +    // graph is a line from (0, m), to that point). We calculate the
  1.6153 +    // intersection point to be ((1+P/2)m, (1+P/2)m), where P is the
  1.6154 +    // intercept parameter above. We then need to return i/s.
  1.6155 +    inflationRatio = (1.0f + (ratio * (intercept - 1) / intercept)) / ratio;
  1.6156 +  } else {
  1.6157 +    // This is the case where P is negative. We essentially want to implement
  1.6158 +    // the case for P=infinity here, so we make i = s + m, which means that
  1.6159 +    // i/s = s/s + m/s = 1 + 1/ratio
  1.6160 +    inflationRatio = 1 + 1.0f / ratio;
  1.6161 +  }
  1.6162 +
  1.6163 +  if (maxRatio > 1.0 && inflationRatio > maxRatio) {
  1.6164 +    return maxRatio;
  1.6165 +  } else {
  1.6166 +    return inflationRatio;
  1.6167 +  }
  1.6168 +}
  1.6169 +
  1.6170 +static bool
  1.6171 +ShouldInflateFontsForContainer(const nsIFrame *aFrame)
  1.6172 +{
  1.6173 +  // We only want to inflate fonts for text that is in a place
  1.6174 +  // with room to expand.  The question is what the best heuristic for
  1.6175 +  // that is...
  1.6176 +  // For now, we're going to use NS_FRAME_IN_CONSTRAINED_HEIGHT, which
  1.6177 +  // indicates whether the frame is inside something with a constrained
  1.6178 +  // height (propagating down the tree), but the propagation stops when
  1.6179 +  // we hit overflow-y: scroll or auto.
  1.6180 +  const nsStyleText* styleText = aFrame->StyleText();
  1.6181 +
  1.6182 +  return styleText->mTextSizeAdjust != NS_STYLE_TEXT_SIZE_ADJUST_NONE &&
  1.6183 +         !(aFrame->GetStateBits() & NS_FRAME_IN_CONSTRAINED_HEIGHT) &&
  1.6184 +         // We also want to disable font inflation for containers that have
  1.6185 +         // preformatted text.
  1.6186 +         styleText->WhiteSpaceCanWrap(aFrame);
  1.6187 +}
  1.6188 +
  1.6189 +nscoord
  1.6190 +nsLayoutUtils::InflationMinFontSizeFor(const nsIFrame *aFrame)
  1.6191 +{
  1.6192 +  nsPresContext *presContext = aFrame->PresContext();
  1.6193 +  if (!FontSizeInflationEnabled(presContext) ||
  1.6194 +      presContext->mInflationDisabledForShrinkWrap) {
  1.6195 +    return 0;
  1.6196 +  }
  1.6197 +
  1.6198 +  for (const nsIFrame *f = aFrame; f; f = f->GetParent()) {
  1.6199 +    if (f->IsContainerForFontSizeInflation()) {
  1.6200 +      if (!ShouldInflateFontsForContainer(f)) {
  1.6201 +        return 0;
  1.6202 +      }
  1.6203 +
  1.6204 +      nsFontInflationData *data =
  1.6205 +        nsFontInflationData::FindFontInflationDataFor(aFrame);
  1.6206 +      // FIXME: The need to null-check here is sort of a bug, and might
  1.6207 +      // lead to incorrect results.
  1.6208 +      if (!data || !data->InflationEnabled()) {
  1.6209 +        return 0;
  1.6210 +      }
  1.6211 +
  1.6212 +      return MinimumFontSizeFor(aFrame->PresContext(),
  1.6213 +                                data->EffectiveWidth());
  1.6214 +    }
  1.6215 +  }
  1.6216 +
  1.6217 +  NS_ABORT_IF_FALSE(false, "root should always be container");
  1.6218 +
  1.6219 +  return 0;
  1.6220 +}
  1.6221 +
  1.6222 +float
  1.6223 +nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame)
  1.6224 +{
  1.6225 +  if (aFrame->IsSVGText()) {
  1.6226 +    const nsIFrame* container = aFrame;
  1.6227 +    while (container->GetType() != nsGkAtoms::svgTextFrame) {
  1.6228 +      container = container->GetParent();
  1.6229 +    }
  1.6230 +    NS_ASSERTION(container, "expected to find an ancestor SVGTextFrame");
  1.6231 +    return
  1.6232 +      static_cast<const SVGTextFrame*>(container)->GetFontSizeScaleFactor();
  1.6233 +  }
  1.6234 +
  1.6235 +  if (!FontSizeInflationEnabled(aFrame->PresContext())) {
  1.6236 +    return 1.0f;
  1.6237 +  }
  1.6238 +
  1.6239 +  return FontSizeInflationInner(aFrame, InflationMinFontSizeFor(aFrame));
  1.6240 +}
  1.6241 +
  1.6242 +/* static */ bool
  1.6243 +nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
  1.6244 +{
  1.6245 +  nsIPresShell* presShell = aPresContext->GetPresShell();
  1.6246 +
  1.6247 +  if (!presShell) {
  1.6248 +    return false;
  1.6249 +  }
  1.6250 +
  1.6251 +  return presShell->FontSizeInflationEnabled();
  1.6252 +}
  1.6253 +
  1.6254 +/* static */ nsRect
  1.6255 +nsLayoutUtils::GetBoxShadowRectForFrame(nsIFrame* aFrame, 
  1.6256 +                                        const nsSize& aFrameSize)
  1.6257 +{
  1.6258 +  nsCSSShadowArray* boxShadows = aFrame->StyleBorder()->mBoxShadow;
  1.6259 +  if (!boxShadows) {
  1.6260 +    return nsRect();
  1.6261 +  }
  1.6262 +  
  1.6263 +  nsRect shadows;
  1.6264 +  int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
  1.6265 +  for (uint32_t i = 0; i < boxShadows->Length(); ++i) {
  1.6266 +    nsRect tmpRect(nsPoint(0, 0), aFrameSize);
  1.6267 +    nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
  1.6268 +
  1.6269 +    // inset shadows are never painted outside the frame
  1.6270 +    if (shadow->mInset)
  1.6271 +      continue;
  1.6272 +
  1.6273 +    tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
  1.6274 +    tmpRect.Inflate(shadow->mSpread);
  1.6275 +    tmpRect.Inflate(
  1.6276 +      nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
  1.6277 +    shadows.UnionRect(shadows, tmpRect);
  1.6278 +  }
  1.6279 +  return shadows;
  1.6280 +}
  1.6281 +
  1.6282 +/* static */ void
  1.6283 +nsLayoutUtils::UpdateImageVisibilityForFrame(nsIFrame* aImageFrame)
  1.6284 +{
  1.6285 +#ifdef DEBUG
  1.6286 +  nsIAtom* type = aImageFrame->GetType();
  1.6287 +  MOZ_ASSERT(type == nsGkAtoms::imageFrame ||
  1.6288 +             type == nsGkAtoms::imageControlFrame ||
  1.6289 +             type == nsGkAtoms::svgImageFrame, "wrong type of frame");
  1.6290 +#endif
  1.6291 +
  1.6292 +  nsCOMPtr<nsIImageLoadingContent> content = do_QueryInterface(aImageFrame->GetContent());
  1.6293 +  if (!content) {
  1.6294 +    return;
  1.6295 +  }
  1.6296 +
  1.6297 +  nsIPresShell* presShell = aImageFrame->PresContext()->PresShell();
  1.6298 +  if (presShell->AssumeAllImagesVisible()) {
  1.6299 +    presShell->EnsureImageInVisibleList(content);
  1.6300 +    return;
  1.6301 +  }
  1.6302 +
  1.6303 +  bool visible = true;
  1.6304 +  nsIFrame* f = aImageFrame->GetParent();
  1.6305 +  nsRect rect = aImageFrame->GetContentRectRelativeToSelf();
  1.6306 +  nsIFrame* rectFrame = aImageFrame;
  1.6307 +  while (f) {
  1.6308 +    nsIScrollableFrame* sf = do_QueryFrame(f);
  1.6309 +    if (sf) {
  1.6310 +      nsRect transformedRect =
  1.6311 +        nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
  1.6312 +      if (!sf->IsRectNearlyVisible(transformedRect)) {
  1.6313 +        visible = false;
  1.6314 +        break;
  1.6315 +      }
  1.6316 +      // Move transformedRect to be contained in the scrollport as best we can
  1.6317 +      // (it might not fit) to pretend that it was scrolled into view.
  1.6318 +      nsRect scrollPort = sf->GetScrollPortRect();
  1.6319 +      if (transformedRect.XMost() > scrollPort.XMost()) {
  1.6320 +        transformedRect.x -= transformedRect.XMost() - scrollPort.XMost();
  1.6321 +      }
  1.6322 +      if (transformedRect.x < scrollPort.x) {
  1.6323 +        transformedRect.x = scrollPort.x;
  1.6324 +      }
  1.6325 +      if (transformedRect.YMost() > scrollPort.YMost()) {
  1.6326 +        transformedRect.y -= transformedRect.YMost() - scrollPort.YMost();
  1.6327 +      }
  1.6328 +      if (transformedRect.y < scrollPort.y) {
  1.6329 +        transformedRect.y = scrollPort.y;
  1.6330 +      }
  1.6331 +      transformedRect.width = std::min(transformedRect.width, scrollPort.width);
  1.6332 +      transformedRect.height = std::min(transformedRect.height, scrollPort.height);
  1.6333 +      rect = transformedRect;
  1.6334 +      rectFrame = f;
  1.6335 +    }
  1.6336 +    nsIFrame* parent = f->GetParent();
  1.6337 +    if (!parent) {
  1.6338 +      parent = nsLayoutUtils::GetCrossDocParentFrame(f);
  1.6339 +      if (parent && parent->PresContext()->IsChrome()) {
  1.6340 +        break;
  1.6341 +      }
  1.6342 +    }
  1.6343 +    f = parent;
  1.6344 +  }
  1.6345 +
  1.6346 +  if (visible) {
  1.6347 +    presShell->EnsureImageInVisibleList(content);
  1.6348 +  } else {
  1.6349 +    presShell->RemoveImageFromVisibleList(content);
  1.6350 +  }
  1.6351 +}
  1.6352 +
  1.6353 +/* static */ nsSize
  1.6354 +nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame)
  1.6355 +{
  1.6356 +  nsSize size(aFrame->GetSize());
  1.6357 +
  1.6358 +  nsPresContext* presContext = aFrame->PresContext();
  1.6359 +  nsIPresShell* presShell = presContext->PresShell();
  1.6360 +
  1.6361 +  // See the comments in the code that calculates the root
  1.6362 +  // composition bounds in RecordFrameMetrics.
  1.6363 +  // TODO: Reuse that code here.
  1.6364 +  bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
  1.6365 +                                      && aFrame == presShell->GetRootScrollFrame();
  1.6366 +  if (isRootContentDocRootScrollFrame) {
  1.6367 +    if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
  1.6368 +      if (nsView* view = rootFrame->GetView()) {
  1.6369 +        nsSize viewSize = view->GetBounds().Size();
  1.6370 +        nsIWidget* widget =
  1.6371 +#ifdef MOZ_WIDGET_ANDROID
  1.6372 +            rootFrame->GetNearestWidget();
  1.6373 +#else
  1.6374 +            view->GetWidget();
  1.6375 +#endif
  1.6376 +        if (widget) {
  1.6377 +          nsIntRect widgetBounds;
  1.6378 +          widget->GetBounds(widgetBounds);
  1.6379 +          int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
  1.6380 +          size = nsSize(widgetBounds.width * auPerDevPixel,
  1.6381 +                        widgetBounds.height * auPerDevPixel);
  1.6382 +#ifdef MOZ_WIDGET_ANDROID
  1.6383 +          if (viewSize.height < size.height) {
  1.6384 +            size.height = viewSize.height;
  1.6385 +          }
  1.6386 +#endif
  1.6387 +        } else {
  1.6388 +          size = viewSize;
  1.6389 +        }
  1.6390 +      }
  1.6391 +    }
  1.6392 +  }
  1.6393 +
  1.6394 +  // Adjust composition bounds for the size of scroll bars.
  1.6395 +  nsIScrollableFrame* scrollableFrame = aFrame->GetScrollTargetFrame();
  1.6396 +  if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
  1.6397 +    nsMargin margins = scrollableFrame->GetActualScrollbarSizes();
  1.6398 +    size.width -= margins.LeftRight();
  1.6399 +    size.height -= margins.TopBottom();
  1.6400 +  }
  1.6401 +
  1.6402 +  return size;
  1.6403 +}
  1.6404 +/* static */ CSSSize
  1.6405 +nsLayoutUtils::CalculateRootCompositionSize(nsIFrame* aFrame,
  1.6406 +                                            bool aIsRootContentDocRootScrollFrame,
  1.6407 +                                            const FrameMetrics& aMetrics)
  1.6408 +{
  1.6409 +
  1.6410 +  if (aIsRootContentDocRootScrollFrame) {
  1.6411 +    return ViewAs<LayerPixel>(ParentLayerSize(aMetrics.mCompositionBounds.Size()),
  1.6412 +                              PixelCastJustification::ParentLayerToLayerForRootComposition)
  1.6413 +           / aMetrics.LayersPixelsPerCSSPixel();
  1.6414 +  }
  1.6415 +  nsPresContext* presContext = aFrame->PresContext();
  1.6416 +  LayerSize rootCompositionSize;
  1.6417 +  nsPresContext* rootPresContext =
  1.6418 +    presContext->GetToplevelContentDocumentPresContext();
  1.6419 +  if (!rootPresContext) {
  1.6420 +    rootPresContext = presContext->GetRootPresContext();
  1.6421 +  }
  1.6422 +  nsIPresShell* rootPresShell = nullptr;
  1.6423 +  if (rootPresContext) {
  1.6424 +    // See the comments in the code that calculates the root
  1.6425 +    // composition bounds in RecordFrameMetrics.
  1.6426 +    // TODO: Reuse that code here.
  1.6427 +    nsIPresShell* rootPresShell = rootPresContext->PresShell();
  1.6428 +    if (nsIFrame* rootFrame = rootPresShell->GetRootFrame()) {
  1.6429 +      if (nsView* view = rootFrame->GetView()) {
  1.6430 +        LayoutDeviceToParentLayerScale parentResolution(
  1.6431 +          rootPresShell->GetCumulativeResolution().width
  1.6432 +          / rootPresShell->GetResolution().width);
  1.6433 +        int32_t rootAUPerDevPixel = rootPresContext->AppUnitsPerDevPixel();
  1.6434 +        nsRect viewBounds = view->GetBounds();
  1.6435 +        LayerSize viewSize = ViewAs<LayerPixel>(
  1.6436 +          (LayoutDeviceRect::FromAppUnits(viewBounds, rootAUPerDevPixel)
  1.6437 +           * parentResolution).Size(), PixelCastJustification::ParentLayerToLayerForRootComposition);
  1.6438 +        nsIWidget* widget =
  1.6439 +#ifdef MOZ_WIDGET_ANDROID
  1.6440 +            rootFrame->GetNearestWidget();
  1.6441 +#else
  1.6442 +            view->GetWidget();
  1.6443 +#endif
  1.6444 +        if (widget) {
  1.6445 +          nsIntRect widgetBounds;
  1.6446 +          widget->GetBounds(widgetBounds);
  1.6447 +          rootCompositionSize = LayerSize(ViewAs<LayerPixel>(widgetBounds.Size()));
  1.6448 +#ifdef MOZ_WIDGET_ANDROID
  1.6449 +          if (viewSize.height < rootCompositionSize.height) {
  1.6450 +            rootCompositionSize.height = viewSize.height;
  1.6451 +          }
  1.6452 +#endif
  1.6453 +        } else {
  1.6454 +          rootCompositionSize = viewSize;
  1.6455 +        }
  1.6456 +      }
  1.6457 +    }
  1.6458 +  } else {
  1.6459 +    nsIWidget* widget = aFrame->GetNearestWidget();
  1.6460 +    nsIntRect widgetBounds;
  1.6461 +    widget->GetBounds(widgetBounds);
  1.6462 +    rootCompositionSize = LayerSize(ViewAs<LayerPixel>(widgetBounds.Size()));
  1.6463 +  }
  1.6464 +
  1.6465 +  // Adjust composition size for the size of scroll bars.
  1.6466 +  nsIFrame* rootRootScrollFrame = rootPresShell ? rootPresShell->GetRootScrollFrame() : nullptr;
  1.6467 +  nsIScrollableFrame* rootScrollableFrame = nullptr;
  1.6468 +  if (rootRootScrollFrame) {
  1.6469 +    rootScrollableFrame = rootRootScrollFrame->GetScrollTargetFrame();
  1.6470 +  }
  1.6471 +  if (rootScrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
  1.6472 +    CSSMargin margins = CSSMargin::FromAppUnits(rootScrollableFrame->GetActualScrollbarSizes());
  1.6473 +    // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them.
  1.6474 +    rootCompositionSize.width -= margins.LeftRight();
  1.6475 +    rootCompositionSize.height -= margins.TopBottom();
  1.6476 +  }
  1.6477 +
  1.6478 +  return rootCompositionSize / aMetrics.LayersPixelsPerCSSPixel();
  1.6479 +}
  1.6480 +
  1.6481 +/* static */ nsRect
  1.6482 +nsLayoutUtils::CalculateScrollableRectForFrame(nsIScrollableFrame* aScrollableFrame, nsIFrame* aRootFrame)
  1.6483 +{
  1.6484 +  nsRect contentBounds;
  1.6485 +  if (aScrollableFrame) {
  1.6486 +    contentBounds = aScrollableFrame->GetScrollRange();
  1.6487 +
  1.6488 +    // We ifndef the below code for Fennec because it requires special behaviour
  1.6489 +    // on the APZC side. Because Fennec has it's own PZC implementation which doesn't
  1.6490 +    // provide the special behaviour, this code will cause it to break. We can remove
  1.6491 +    // the ifndef once Fennec switches over to APZ or if we add the special handling
  1.6492 +    // to Fennec
  1.6493 +#ifndef MOZ_WIDGET_ANDROID
  1.6494 +    nsPoint scrollPosition = aScrollableFrame->GetScrollPosition();
  1.6495 +    if (aScrollableFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
  1.6496 +      contentBounds.y = scrollPosition.y;
  1.6497 +      contentBounds.height = 0;
  1.6498 +    }
  1.6499 +    if (aScrollableFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
  1.6500 +      contentBounds.x = scrollPosition.x;
  1.6501 +      contentBounds.width = 0;
  1.6502 +    }
  1.6503 +#endif
  1.6504 +
  1.6505 +    contentBounds.width += aScrollableFrame->GetScrollPortRect().width;
  1.6506 +    contentBounds.height += aScrollableFrame->GetScrollPortRect().height;
  1.6507 +  } else {
  1.6508 +    contentBounds = aRootFrame->GetRect();
  1.6509 +  }
  1.6510 +  return contentBounds;
  1.6511 +}
  1.6512 +
  1.6513 +/* static */ nsRect
  1.6514 +nsLayoutUtils::CalculateExpandedScrollableRect(nsIFrame* aFrame)
  1.6515 +{
  1.6516 +  nsRect scrollableRect =
  1.6517 +    CalculateScrollableRectForFrame(aFrame->GetScrollTargetFrame(),
  1.6518 +                                    aFrame->PresContext()->PresShell()->GetRootFrame());
  1.6519 +  nsSize compSize = CalculateCompositionSizeForFrame(aFrame);
  1.6520 +
  1.6521 +  if (aFrame == aFrame->PresContext()->PresShell()->GetRootScrollFrame()) {
  1.6522 +    // the composition size for the root scroll frame does not include the
  1.6523 +    // local resolution, so we adjust.
  1.6524 +    gfxSize res = aFrame->PresContext()->PresShell()->GetResolution();
  1.6525 +    compSize.width = NSToCoordRound(compSize.width / ((float) res.width));
  1.6526 +    compSize.height = NSToCoordRound(compSize.height / ((float) res.height));
  1.6527 +  }
  1.6528 +
  1.6529 +  if (scrollableRect.width < compSize.width) {
  1.6530 +    scrollableRect.x = std::max(0,
  1.6531 +                                scrollableRect.x - (compSize.width - scrollableRect.width));
  1.6532 +    scrollableRect.width = compSize.width;
  1.6533 +  }
  1.6534 +
  1.6535 +  if (scrollableRect.height < compSize.height) {
  1.6536 +    scrollableRect.y = std::max(0,
  1.6537 +                                scrollableRect.y - (compSize.height - scrollableRect.height));
  1.6538 +    scrollableRect.height = compSize.height;
  1.6539 +  }
  1.6540 +  return scrollableRect;
  1.6541 +}
  1.6542 +
  1.6543 +/* static */ bool
  1.6544 +nsLayoutUtils::WantSubAPZC()
  1.6545 +{
  1.6546 +   // TODO Turn this on for inprocess OMTC on all platforms
  1.6547 +   bool wantSubAPZC = gfxPrefs::APZSubframeEnabled();
  1.6548 +#ifdef MOZ_WIDGET_GONK
  1.6549 +   if (XRE_GetProcessType() != GeckoProcessType_Content) {
  1.6550 +     wantSubAPZC = false;
  1.6551 +   }
  1.6552 +#endif
  1.6553 +   return wantSubAPZC;
  1.6554 + }
  1.6555 +
  1.6556 +nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
  1.6557 +  // Use safe default values here
  1.6558 +  : mIsWriteOnly(true)
  1.6559 +  , mIsStillLoading(false)
  1.6560 +  , mCORSUsed(false)
  1.6561 +  , mIsPremultiplied(true)
  1.6562 +{
  1.6563 +}
  1.6564 +
  1.6565 +bool
  1.6566 +nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
  1.6567 +{
  1.6568 +  return GetAsBlock(aFrame) && !aFrame->IsBlockWrapper();
  1.6569 +}
  1.6570 +
  1.6571 +bool
  1.6572 +nsLayoutUtils::NeedsPrintPreviewBackground(nsPresContext* aPresContext)
  1.6573 +{
  1.6574 +  return aPresContext->IsRootPaginatedDocument() &&
  1.6575 +    (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
  1.6576 +     aPresContext->Type() == nsPresContext::eContext_PageLayout);
  1.6577 +}
  1.6578 +
  1.6579 +AutoMaybeDisableFontInflation::AutoMaybeDisableFontInflation(nsIFrame *aFrame)
  1.6580 +{
  1.6581 +  // FIXME: Now that inflation calculations are based on the flow
  1.6582 +  // root's NCA's (nearest common ancestor of its inflatable
  1.6583 +  // descendants) width, we could probably disable inflation in
  1.6584 +  // fewer cases than we currently do.
  1.6585 +  if (aFrame->IsContainerForFontSizeInflation()) {
  1.6586 +    mPresContext = aFrame->PresContext();
  1.6587 +    mOldValue = mPresContext->mInflationDisabledForShrinkWrap;
  1.6588 +    mPresContext->mInflationDisabledForShrinkWrap = true;
  1.6589 +  } else {
  1.6590 +    // indicate we have nothing to restore
  1.6591 +    mPresContext = nullptr;
  1.6592 +  }
  1.6593 +}
  1.6594 +
  1.6595 +AutoMaybeDisableFontInflation::~AutoMaybeDisableFontInflation()
  1.6596 +{
  1.6597 +  if (mPresContext) {
  1.6598 +    mPresContext->mInflationDisabledForShrinkWrap = mOldValue;
  1.6599 +  }
  1.6600 +}

mercurial