layout/base/nsDisplayList.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim: set ts=2 sw=2 et tw=78:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  */
     8 /*
     9  * structures that represent things to be painted (ordered in z-order),
    10  * used during painting and hit testing
    11  */
    13 #include "mozilla/dom/TabChild.h"
    14 #include "mozilla/layers/PLayerTransaction.h"
    16 #include "nsDisplayList.h"
    18 #include "nsCSSRendering.h"
    19 #include "nsRenderingContext.h"
    20 #include "nsISelectionController.h"
    21 #include "nsIPresShell.h"
    22 #include "nsRegion.h"
    23 #include "nsStyleStructInlines.h"
    24 #include "nsStyleTransformMatrix.h"
    25 #include "gfxMatrix.h"
    26 #include "nsSVGIntegrationUtils.h"
    27 #include "nsLayoutUtils.h"
    28 #include "nsIScrollableFrame.h"
    29 #include "nsIFrameInlines.h"
    30 #include "nsThemeConstants.h"
    31 #include "LayerTreeInvalidation.h"
    33 #include "imgIContainer.h"
    34 #include "BasicLayers.h"
    35 #include "nsBoxFrame.h"
    36 #include "nsViewportFrame.h"
    37 #include "nsSubDocumentFrame.h"
    38 #include "nsSVGEffects.h"
    39 #include "nsSVGElement.h"
    40 #include "nsSVGClipPathFrame.h"
    41 #include "GeckoProfiler.h"
    42 #include "nsAnimationManager.h"
    43 #include "nsTransitionManager.h"
    44 #include "nsViewManager.h"
    45 #include "ImageLayers.h"
    46 #include "ImageContainer.h"
    47 #include "nsCanvasFrame.h"
    48 #include "StickyScrollContainer.h"
    49 #include "mozilla/EventStates.h"
    50 #include "mozilla/LookAndFeel.h"
    51 #include "mozilla/Preferences.h"
    52 #include "ActiveLayerTracker.h"
    53 #include "nsContentUtils.h"
    54 #include "nsPrintfCString.h"
    55 #include "UnitTransforms.h"
    57 #include <stdint.h>
    58 #include <algorithm>
    60 using namespace mozilla;
    61 using namespace mozilla::css;
    62 using namespace mozilla::layers;
    63 using namespace mozilla::dom;
    64 typedef FrameMetrics::ViewID ViewID;
    66 static inline nsIFrame*
    67 GetTransformRootFrame(nsIFrame* aFrame)
    68 {
    69   return nsLayoutUtils::GetTransformRootFrame(aFrame);
    70 }
    72 static void AddTransformFunctions(nsCSSValueList* aList,
    73                                   nsStyleContext* aContext,
    74                                   nsPresContext* aPresContext,
    75                                   nsRect& aBounds,
    76                                   float aAppUnitsPerPixel,
    77                                   InfallibleTArray<TransformFunction>& aFunctions)
    78 {
    79   if (aList->mValue.GetUnit() == eCSSUnit_None) {
    80     return;
    81   }
    83   for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
    84     const nsCSSValue& currElem = curr->mValue;
    85     NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
    86                  "Stream should consist solely of functions!");
    87     nsCSSValue::Array* array = currElem.GetArrayValue();
    88     bool canStoreInRuleTree = true;
    89     switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
    90       case eCSSKeyword_rotatex:
    91       {
    92         double theta = array->Item(1).GetAngleValueInRadians();
    93         aFunctions.AppendElement(RotationX(theta));
    94         break;
    95       }
    96       case eCSSKeyword_rotatey:
    97       {
    98         double theta = array->Item(1).GetAngleValueInRadians();
    99         aFunctions.AppendElement(RotationY(theta));
   100         break;
   101       }
   102       case eCSSKeyword_rotatez:
   103       {
   104         double theta = array->Item(1).GetAngleValueInRadians();
   105         aFunctions.AppendElement(RotationZ(theta));
   106         break;
   107       }
   108       case eCSSKeyword_rotate:
   109       {
   110         double theta = array->Item(1).GetAngleValueInRadians();
   111         aFunctions.AppendElement(Rotation(theta));
   112         break;
   113       }
   114       case eCSSKeyword_rotate3d:
   115       {
   116         double x = array->Item(1).GetFloatValue();
   117         double y = array->Item(2).GetFloatValue();
   118         double z = array->Item(3).GetFloatValue();
   119         double theta = array->Item(4).GetAngleValueInRadians();
   120         aFunctions.AppendElement(Rotation3D(x, y, z, theta));
   121         break;
   122       }
   123       case eCSSKeyword_scalex:
   124       {
   125         double x = array->Item(1).GetFloatValue();
   126         aFunctions.AppendElement(Scale(x, 1, 1));
   127         break;
   128       }
   129       case eCSSKeyword_scaley:
   130       {
   131         double y = array->Item(1).GetFloatValue();
   132         aFunctions.AppendElement(Scale(1, y, 1));
   133         break;
   134       }
   135       case eCSSKeyword_scalez:
   136       {
   137         double z = array->Item(1).GetFloatValue();
   138         aFunctions.AppendElement(Scale(1, 1, z));
   139         break;
   140       }
   141       case eCSSKeyword_scale:
   142       {
   143         double x = array->Item(1).GetFloatValue();
   144         // scale(x) is shorthand for scale(x, x);
   145         double y = array->Count() == 2 ? x : array->Item(2).GetFloatValue();
   146         aFunctions.AppendElement(Scale(x, y, 1));
   147         break;
   148       }
   149       case eCSSKeyword_scale3d:
   150       {
   151         double x = array->Item(1).GetFloatValue();
   152         double y = array->Item(2).GetFloatValue();
   153         double z = array->Item(3).GetFloatValue();
   154         aFunctions.AppendElement(Scale(x, y, z));
   155         break;
   156       }
   157       case eCSSKeyword_translatex:
   158       {
   159         double x = nsStyleTransformMatrix::ProcessTranslatePart(
   160           array->Item(1), aContext, aPresContext, canStoreInRuleTree,
   161           aBounds.Width(), aAppUnitsPerPixel);
   162         aFunctions.AppendElement(Translation(x, 0, 0));
   163         break;
   164       }
   165       case eCSSKeyword_translatey:
   166       {
   167         double y = nsStyleTransformMatrix::ProcessTranslatePart(
   168           array->Item(1), aContext, aPresContext, canStoreInRuleTree,
   169           aBounds.Height(), aAppUnitsPerPixel);
   170         aFunctions.AppendElement(Translation(0, y, 0));
   171         break;
   172       }
   173       case eCSSKeyword_translatez:
   174       {
   175         double z = nsStyleTransformMatrix::ProcessTranslatePart(
   176           array->Item(1), aContext, aPresContext, canStoreInRuleTree,
   177           0, aAppUnitsPerPixel);
   178         aFunctions.AppendElement(Translation(0, 0, z));
   179         break;
   180       }
   181       case eCSSKeyword_translate:
   182       {
   183         double x = nsStyleTransformMatrix::ProcessTranslatePart(
   184           array->Item(1), aContext, aPresContext, canStoreInRuleTree,
   185           aBounds.Width(), aAppUnitsPerPixel);
   186         // translate(x) is shorthand for translate(x, 0)
   187         double y = 0;
   188         if (array->Count() == 3) {
   189            y = nsStyleTransformMatrix::ProcessTranslatePart(
   190             array->Item(2), aContext, aPresContext, canStoreInRuleTree,
   191             aBounds.Height(), aAppUnitsPerPixel);
   192         }
   193         aFunctions.AppendElement(Translation(x, y, 0));
   194         break;
   195       }
   196       case eCSSKeyword_translate3d:
   197       {
   198         double x = nsStyleTransformMatrix::ProcessTranslatePart(
   199           array->Item(1), aContext, aPresContext, canStoreInRuleTree,
   200           aBounds.Width(), aAppUnitsPerPixel);
   201         double y = nsStyleTransformMatrix::ProcessTranslatePart(
   202           array->Item(2), aContext, aPresContext, canStoreInRuleTree,
   203           aBounds.Height(), aAppUnitsPerPixel);
   204         double z = nsStyleTransformMatrix::ProcessTranslatePart(
   205           array->Item(3), aContext, aPresContext, canStoreInRuleTree,
   206           0, aAppUnitsPerPixel);
   208         aFunctions.AppendElement(Translation(x, y, z));
   209         break;
   210       }
   211       case eCSSKeyword_skewx:
   212       {
   213         double x = array->Item(1).GetAngleValueInRadians();
   214         aFunctions.AppendElement(SkewX(x));
   215         break;
   216       }
   217       case eCSSKeyword_skewy:
   218       {
   219         double y = array->Item(1).GetAngleValueInRadians();
   220         aFunctions.AppendElement(SkewY(y));
   221         break;
   222       }
   223       case eCSSKeyword_skew:
   224       {
   225         double x = array->Item(1).GetAngleValueInRadians();
   226         // skew(x) is shorthand for skew(x, 0)
   227         double y = 0;
   228         if (array->Count() == 3) {
   229           y = array->Item(2).GetAngleValueInRadians();
   230         }
   231         aFunctions.AppendElement(Skew(x, y));
   232         break;
   233       }
   234       case eCSSKeyword_matrix:
   235       {
   236         gfx::Matrix4x4 matrix;
   237         matrix._11 = array->Item(1).GetFloatValue();
   238         matrix._12 = array->Item(2).GetFloatValue();
   239         matrix._13 = 0;
   240         matrix._14 = 0;
   241         matrix._21 = array->Item(3).GetFloatValue();
   242         matrix._22 = array->Item(4).GetFloatValue();
   243         matrix._23 = 0;
   244         matrix._24 = 0;
   245         matrix._31 = 0;
   246         matrix._32 = 0;
   247         matrix._33 = 1;
   248         matrix._34 = 0;
   249         matrix._41 = array->Item(5).GetFloatValue();
   250         matrix._42 = array->Item(6).GetFloatValue();
   251         matrix._43 = 0;
   252         matrix._44 = 1;
   253         aFunctions.AppendElement(TransformMatrix(matrix));
   254         break;
   255       }
   256       case eCSSKeyword_matrix3d:
   257       {
   258         gfx::Matrix4x4 matrix;
   259         matrix._11 = array->Item(1).GetFloatValue();
   260         matrix._12 = array->Item(2).GetFloatValue();
   261         matrix._13 = array->Item(3).GetFloatValue();
   262         matrix._14 = array->Item(4).GetFloatValue();
   263         matrix._21 = array->Item(5).GetFloatValue();
   264         matrix._22 = array->Item(6).GetFloatValue();
   265         matrix._23 = array->Item(7).GetFloatValue();
   266         matrix._24 = array->Item(8).GetFloatValue();
   267         matrix._31 = array->Item(9).GetFloatValue();
   268         matrix._32 = array->Item(10).GetFloatValue();
   269         matrix._33 = array->Item(11).GetFloatValue();
   270         matrix._34 = array->Item(12).GetFloatValue();
   271         matrix._41 = array->Item(13).GetFloatValue();
   272         matrix._42 = array->Item(14).GetFloatValue();
   273         matrix._43 = array->Item(15).GetFloatValue();
   274         matrix._44 = array->Item(16).GetFloatValue();
   275         aFunctions.AppendElement(TransformMatrix(matrix));
   276         break;
   277       }
   278       case eCSSKeyword_interpolatematrix:
   279       {
   280         gfx3DMatrix matrix;
   281         nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
   282                                                          aContext,
   283                                                          aPresContext,
   284                                                          canStoreInRuleTree,
   285                                                          aBounds,
   286                                                          aAppUnitsPerPixel);
   287         gfx::Matrix4x4 transform;
   288         gfx::ToMatrix4x4(matrix, transform);
   289         aFunctions.AppendElement(TransformMatrix(transform));
   290         break;
   291       }
   292       case eCSSKeyword_perspective:
   293       {
   294         aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
   295         break;
   296       }
   297       default:
   298         NS_ERROR("Function not handled yet!");
   299     }
   300   }
   301 }
   303 static TimingFunction
   304 ToTimingFunction(css::ComputedTimingFunction& aCTF)
   305 {
   306   if (aCTF.GetType() == nsTimingFunction::Function) {
   307     const nsSMILKeySpline* spline = aCTF.GetFunction();
   308     return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(),
   309                                               spline->X2(), spline->Y2()));
   310   }
   312   uint32_t type = aCTF.GetType() == nsTimingFunction::StepStart ? 1 : 2;
   313   return TimingFunction(StepFunction(aCTF.GetSteps(), type));
   314 }
   316 static void
   317 AddAnimationForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
   318                         mozilla::StyleAnimation* ea, Layer* aLayer,
   319                         AnimationData& aData, bool aPending)
   320 {
   321   NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
   322   nsStyleContext* styleContext = aFrame->StyleContext();
   323   nsPresContext* presContext = aFrame->PresContext();
   324   nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
   325   // all data passed directly to the compositor should be in css pixels
   326   float scale = nsDeviceContext::AppUnitsPerCSSPixel();
   328   mozilla::layers::Animation* animation =
   329     aPending ?
   330     aLayer->AddAnimationForNextTransaction() :
   331     aLayer->AddAnimation();
   333   animation->startTime() = ea->mStartTime + ea->mDelay;
   334   animation->duration() = ea->mIterationDuration;
   335   animation->numIterations() =
   336     ea->mIterationCount != NS_IEEEPositiveInfinity() ? ea->mIterationCount : -1;
   337   animation->direction() = ea->mDirection;
   338   animation->property() = aProperty;
   339   animation->data() = aData;
   341   for (uint32_t propIdx = 0; propIdx < ea->mProperties.Length(); propIdx++) {
   342     AnimationProperty* property = &ea->mProperties[propIdx];
   344     if (aProperty != property->mProperty) {
   345       continue;
   346     }
   348     for (uint32_t segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
   349       AnimationPropertySegment* segment = &property->mSegments[segIdx];
   351       AnimationSegment* animSegment = animation->segments().AppendElement();
   352       if (aProperty == eCSSProperty_transform) {
   353         animSegment->startState() = InfallibleTArray<TransformFunction>();
   354         animSegment->endState() = InfallibleTArray<TransformFunction>();
   356         nsCSSValueSharedList* list = segment->mFromValue.GetCSSValueSharedListValue();
   357         AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale,
   358                               animSegment->startState().get_ArrayOfTransformFunction());
   360         list = segment->mToValue.GetCSSValueSharedListValue();
   361         AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale,
   362                               animSegment->endState().get_ArrayOfTransformFunction());
   363       } else if (aProperty == eCSSProperty_opacity) {
   364         animSegment->startState() = segment->mFromValue.GetFloatValue();
   365         animSegment->endState() = segment->mToValue.GetFloatValue();
   366       }
   368       animSegment->startPortion() = segment->mFromKey;
   369       animSegment->endPortion() = segment->mToKey;
   370       animSegment->sampleFn() = ToTimingFunction(segment->mTimingFunction);
   371     }
   372   }
   373 }
   375 template<class T>
   376 static void
   377 AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
   378                          nsTArray<T>& aAnimations,
   379                          Layer* aLayer, AnimationData& aData,
   380                          bool aPending) {
   381   mozilla::TimeStamp currentTime =
   382     aFrame->PresContext()->RefreshDriver()->MostRecentRefresh();
   383   for (uint32_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) {
   384     mozilla::StyleAnimation* anim = &aAnimations[animIdx];
   385     if (!(anim->HasAnimationOfProperty(aProperty) &&
   386           anim->IsRunningAt(currentTime))) {
   387       continue;
   388     }
   389     AddAnimationForProperty(aFrame, aProperty, anim, aLayer, aData, aPending);
   390     anim->mIsRunningOnCompositor = true;
   391   }
   392 }
   394 /* static */ void
   395 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
   396                                                          nsDisplayListBuilder* aBuilder,
   397                                                          nsDisplayItem* aItem,
   398                                                          nsIFrame* aFrame,
   399                                                          nsCSSProperty aProperty)
   400 {
   401   // This function can be called in two ways:  from
   402   // nsDisplay*::BuildLayer while constructing a layer (with all
   403   // pointers non-null), or from RestyleManager's handling of
   404   // UpdateOpacityLayer/UpdateTransformLayer hints.
   405   MOZ_ASSERT(!aBuilder == !aItem,
   406              "should only be called in two configurations, with both "
   407              "aBuilder and aItem, or with neither");
   408   MOZ_ASSERT(!aItem || aFrame == aItem->Frame(), "frame mismatch");
   410   bool pending = !aBuilder;
   412   if (pending) {
   413     aLayer->ClearAnimationsForNextTransaction();
   414   } else {
   415     aLayer->ClearAnimations();
   416   }
   418   nsIContent* content = aFrame->GetContent();
   419   if (!content) {
   420     return;
   421   }
   422   ElementTransitions* et =
   423     nsTransitionManager::GetTransitionsForCompositor(content, aProperty);
   425   ElementAnimations* ea =
   426     nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
   428   if (!ea && !et) {
   429     return;
   430   }
   432   // If the frame is not prerendered, bail out.
   433   // Do this check only during layer construction; during updating the
   434   // caller is required to check it appropriately.
   435   if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
   436     // AnimationManager or TransitionManager need to know that we refused to
   437     // run this animation asynchronously so that they will not throttle the
   438     // main thread animation.
   439     aFrame->Properties().Set(nsIFrame::RefusedAsyncAnimation(),
   440                             reinterpret_cast<void*>(intptr_t(true)));
   442     // We need to schedule another refresh driver run so that AnimationManager
   443     // or TransitionManager get a chance to unthrottle the animation.
   444     aFrame->SchedulePaint();
   445     return;
   446   }
   448   AnimationData data;
   449   if (aProperty == eCSSProperty_transform) {
   450     nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
   451     // all data passed directly to the compositor should be in css pixels
   452     float scale = nsDeviceContext::AppUnitsPerCSSPixel();
   453     gfxPoint3D offsetToTransformOrigin =
   454       nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
   455     gfxPoint3D offsetToPerspectiveOrigin =
   456       nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame, scale);
   457     nscoord perspective = 0.0;
   458     nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent();
   459     if (parentStyleContext) {
   460       const nsStyleDisplay* disp = parentStyleContext->StyleDisplay();
   461       if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
   462         perspective = disp->mChildPerspective.GetCoordValue();
   463       }
   464     }
   465     nsPoint origin;
   466     if (aItem) {
   467       origin = aItem->ToReferenceFrame();
   468     } else {
   469       // transform display items used a reference frame computed from
   470       // their GetTransformRootFrame().
   471       nsIFrame* referenceFrame =
   472         nsLayoutUtils::GetReferenceFrame(GetTransformRootFrame(aFrame));
   473       origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
   474     }
   476     data = TransformData(origin, offsetToTransformOrigin,
   477                          offsetToPerspectiveOrigin, bounds, perspective,
   478                          aFrame->PresContext()->AppUnitsPerDevPixel());
   479   } else if (aProperty == eCSSProperty_opacity) {
   480     data = null_t();
   481   }
   483   if (et) {
   484     AddAnimationsForProperty(aFrame, aProperty, et->mPropertyTransitions,
   485                              aLayer, data, pending);
   486     aLayer->SetAnimationGeneration(et->mAnimationGeneration);
   487   }
   489   if (ea) {
   490     AddAnimationsForProperty(aFrame, aProperty, ea->mAnimations,
   491                              aLayer, data, pending);
   492     aLayer->SetAnimationGeneration(ea->mAnimationGeneration);
   493   }
   494 }
   496 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
   497     Mode aMode, bool aBuildCaret)
   498     : mReferenceFrame(aReferenceFrame),
   499       mIgnoreScrollFrame(nullptr),
   500       mLayerEventRegions(nullptr),
   501       mCurrentTableItem(nullptr),
   502       mFinalTransparentRegion(nullptr),
   503       mCachedOffsetFrame(aReferenceFrame),
   504       mCachedReferenceFrame(aReferenceFrame),
   505       mCachedOffset(0, 0),
   506       mGlassDisplayItem(nullptr),
   507       mMode(aMode),
   508       mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
   509       mBuildCaret(aBuildCaret),
   510       mIgnoreSuppression(false),
   511       mHadToIgnoreSuppression(false),
   512       mIsAtRootOfPseudoStackingContext(false),
   513       mIncludeAllOutOfFlows(false),
   514       mDescendIntoSubdocuments(true),
   515       mSelectedFramesOnly(false),
   516       mAccurateVisibleRegions(false),
   517       mAllowMergingAndFlattening(true),
   518       mWillComputePluginGeometry(false),
   519       mInTransform(false),
   520       mInFixedPos(false),
   521       mSyncDecodeImages(false),
   522       mIsPaintingToWindow(false),
   523       mIsCompositingCheap(false),
   524       mContainsPluginItem(false),
   525       mContainsBlendMode(false),
   526       mAncestorHasTouchEventHandler(false),
   527       mHaveScrollableDisplayPort(false)
   528 {
   529   MOZ_COUNT_CTOR(nsDisplayListBuilder);
   530   PL_InitArenaPool(&mPool, "displayListArena", 1024,
   531                    std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
   533   nsPresContext* pc = aReferenceFrame->PresContext();
   534   nsIPresShell *shell = pc->PresShell();
   535   if (pc->IsRenderingOnlySelection()) {
   536     nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
   537     if (selcon) {
   538       selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
   539                            getter_AddRefs(mBoundingSelection));
   540     }
   541   }
   543   nsCSSRendering::BeginFrameTreesLocked();
   544   PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS));
   545 }
   547 static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
   548   for (nsIFrame* f = aFrame; f;
   549        f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
   550     if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
   551       return;
   552     f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   553     if (f == aStopAtFrame) {
   554       // we've reached a frame that we know will be painted, so we can stop.
   555       break;
   556     }
   557   }
   558 }
   560 void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
   561                                                         nsIFrame* aFrame,
   562                                                         const nsRect& aDirtyRect)
   563 {
   564   nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
   565   if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
   566     NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
   567     // position: fixed items are reflowed into and only drawn inside the
   568     // viewport, or the scroll position clamping scrollport size, if one is
   569     // set.
   570     nsIPresShell* ps = aFrame->PresContext()->PresShell();
   571     dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
   572     if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
   573       dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
   574     } else {
   575       dirtyRectRelativeToDirtyFrame.SizeTo(aDirtyFrame->GetSize());
   576     }
   577   }
   579   nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
   580   nsRect overflowRect = aFrame->GetVisualOverflowRect();
   582   if (aFrame->IsTransformed() &&
   583       nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
   584                                                 eCSSProperty_transform)) {
   585    /**
   586     * Add a fuzz factor to the overflow rectangle so that elements only just
   587     * out of view are pulled into the display list, so they can be
   588     * prerendered if necessary.
   589     */
   590     overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
   591   }
   593   if (!dirty.IntersectRect(dirty, overflowRect))
   594     return;
   595   const DisplayItemClip* clip = mClipState.GetClipForContainingBlockDescendants();
   596   OutOfFlowDisplayData* data = clip ? new OutOfFlowDisplayData(*clip, dirty)
   597     : new OutOfFlowDisplayData(dirty);
   598   aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
   600   MarkFrameForDisplay(aFrame, aDirtyFrame);
   601 }
   603 static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
   604   nsPresContext* presContext = aFrame->PresContext();
   605   presContext->PropertyTable()->
   606     Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
   608   for (nsIFrame* f = aFrame; f;
   609        f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
   610     if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
   611       return;
   612     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   613   }
   614 }
   616 static bool gPrintApzcTree = false;
   618 static bool GetApzcTreePrintPref() {
   619   static bool initialized = false;
   620   if (!initialized) {
   621     Preferences::AddBoolVarCache(&gPrintApzcTree, "apz.printtree", gPrintApzcTree);
   622     initialized = true;
   623   }
   624   return gPrintApzcTree;
   625 }
   627 static void RecordFrameMetrics(nsIFrame* aForFrame,
   628                                nsIFrame* aScrollFrame,
   629                                const nsIFrame* aReferenceFrame,
   630                                ContainerLayer* aRoot,
   631                                const nsRect& aVisibleRect,
   632                                const nsRect& aViewport,
   633                                nsRect* aDisplayPort,
   634                                nsRect* aCriticalDisplayPort,
   635                                ViewID aScrollId,
   636                                bool aIsRoot,
   637                                const ContainerLayerParameters& aContainerParameters) {
   638   nsPresContext* presContext = aForFrame->PresContext();
   639   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
   640   LayoutDeviceToLayerScale resolution(aContainerParameters.mXScale, aContainerParameters.mYScale);
   642   nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
   643     resolution.scale, resolution.scale, auPerDevPixel);
   644   aRoot->SetVisibleRegion(visible);
   646   FrameMetrics metrics;
   647   metrics.mViewport = CSSRect::FromAppUnits(aViewport);
   648   if (aDisplayPort) {
   649     metrics.mDisplayPort = CSSRect::FromAppUnits(*aDisplayPort);
   650     if (aCriticalDisplayPort) {
   651       metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(*aCriticalDisplayPort);
   652     }
   653   }
   655   nsIScrollableFrame* scrollableFrame = nullptr;
   656   if (aScrollFrame)
   657     scrollableFrame = aScrollFrame->GetScrollTargetFrame();
   659   metrics.mScrollableRect = CSSRect::FromAppUnits(
   660     nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame, aForFrame));
   662   if (scrollableFrame) {
   663     nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
   664     metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
   666     // If the frame was scrolled since the last layers update, and by
   667     // something other than the APZ code, we want to tell the APZ to update
   668     // its scroll offset.
   669     nsIAtom* originOfLastScroll = scrollableFrame->OriginOfLastScroll();
   670     if (originOfLastScroll && originOfLastScroll != nsGkAtoms::apz) {
   671       metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
   672     }
   673   }
   675   metrics.SetScrollId(aScrollId);
   676   metrics.mIsRoot = aIsRoot;
   678   // Only the root scrollable frame for a given presShell should pick up
   679   // the presShell's resolution. All the other frames are 1.0.
   680   nsIPresShell* presShell = presContext->GetPresShell();
   681   if (aScrollFrame == presShell->GetRootScrollFrame()) {
   682     metrics.mResolution = ParentLayerToLayerScale(presShell->GetXResolution(),
   683                                                   presShell->GetYResolution());
   684   } else {
   685     metrics.mResolution = ParentLayerToLayerScale(1.0f);
   686   }
   688   // For the cumulateive resolution, multiply the resolutions of all the
   689   // presShells back up to the root
   690   metrics.mCumulativeResolution = LayoutDeviceToLayerScale(1.0f);
   691   nsIPresShell* curPresShell = presShell;
   692   while (curPresShell != nullptr) {
   693     ParentLayerToLayerScale presShellResolution(curPresShell->GetXResolution(),
   694                                                 curPresShell->GetYResolution());
   695     metrics.mCumulativeResolution.scale *= presShellResolution.scale;
   696     nsPresContext* parentContext = curPresShell->GetPresContext()->GetParentPresContext();
   697     curPresShell = parentContext ? parentContext->GetPresShell() : nullptr;
   698   }
   700   metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(
   701     (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel);
   703   // Initially, AsyncPanZoomController should render the content to the screen
   704   // at the painted resolution.
   705   const LayerToScreenScale layerToScreenScale(1.0f);
   706   metrics.SetZoom(metrics.mCumulativeResolution * metrics.mDevPixelsPerCSSPixel
   707                   * layerToScreenScale);
   709   if (presShell) {
   710     nsIDocument* document = nullptr;
   711     document = presShell->GetDocument();
   712     if (document) {
   713       nsCOMPtr<nsPIDOMWindow> innerWin(document->GetInnerWindow());
   714       if (innerWin) {
   715         metrics.mMayHaveTouchListeners = innerWin->HasTouchEventListeners();
   716       }
   717     }
   718   }
   720   LayoutDeviceToParentLayerScale layoutToParentLayerScale =
   721     // The ScreenToParentLayerScale should be mTransformScale which is not calculated yet,
   722     // but we don't yet handle CSS transforms, so we assume it's 1 here.
   723     metrics.mCumulativeResolution * LayerToScreenScale(1.0) * ScreenToParentLayerScale(1.0);
   725   // Calculate the composition bounds as the size of the scroll frame and
   726   // its origin relative to the reference frame.
   727   // If aScrollFrame is null, we are in a document without a root scroll frame,
   728   // so it's a xul document. In this case, use the size of the viewport frame.
   729   nsIFrame* frameForCompositionBoundsCalculation = aScrollFrame ? aScrollFrame : aForFrame;
   730   nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame),
   731                            frameForCompositionBoundsCalculation->GetSize());
   732   metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
   733                                             * layoutToParentLayerScale);
   736   // For the root scroll frame of the root content document, the above calculation
   737   // will yield the size of the viewport frame as the composition bounds, which
   738   // doesn't actually correspond to what is visible when
   739   // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
   740   // the prescontext that the viewport frame is reflowed into. In that case if our
   741   // document has a widget then the widget's bounds will correspond to what is
   742   // visible. If we don't have a widget the root view's bounds correspond to what
   743   // would be visible because they don't get modified by setCSSViewport.
   744   bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
   745                                       && aScrollFrame == presShell->GetRootScrollFrame();
   746   if (isRootContentDocRootScrollFrame) {
   747     if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
   748       if (nsView* view = rootFrame->GetView()) {
   749         nsRect viewBoundsAppUnits = view->GetBounds() + rootFrame->GetOffsetToCrossDoc(aReferenceFrame);
   750         ParentLayerIntRect viewBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(viewBoundsAppUnits, auPerDevPixel)
   751                                                      * layoutToParentLayerScale);
   753         // On Android, we need to do things a bit differently to get things
   754         // right (see bug 983208, bug 988882). We use the bounds of the nearest
   755         // widget, but clamp the height to the view bounds height. This clamping
   756         // is done to get correct results for a page where the page is sized to
   757         // the screen and thus the dynamic toolbar never disappears. In such a
   758         // case, we want the composition bounds to exclude the toolbar height,
   759         // but the widget bounds includes it. We don't currently have a good way
   760         // of knowing about the toolbar height, but clamping to the view bounds
   761         // height gives the correct answer in the cases we care about.
   762         nsIWidget* widget =
   763 #ifdef MOZ_WIDGET_ANDROID
   764             rootFrame->GetNearestWidget();
   765 #else
   766             view->GetWidget();
   767 #endif
   768         if (widget) {
   769           nsIntRect widgetBounds;
   770           widget->GetBounds(widgetBounds);
   771           metrics.mCompositionBounds = ViewAs<ParentLayerPixel>(widgetBounds);
   772 #ifdef MOZ_WIDGET_ANDROID
   773           if (viewBounds.height < metrics.mCompositionBounds.height) {
   774             metrics.mCompositionBounds.height = viewBounds.height;
   775           }
   776 #endif
   777         } else {
   778           metrics.mCompositionBounds = viewBounds;
   779         }
   780       }
   781     }
   782   }
   784   // Adjust composition bounds for the size of scroll bars.
   785   if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
   786     nsMargin sizes = scrollableFrame->GetActualScrollbarSizes();
   787     // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them.
   788     ParentLayerIntMargin boundMargins = RoundedToInt(CSSMargin::FromAppUnits(sizes) * CSSToParentLayerScale(1.0f));
   789     metrics.mCompositionBounds.Deflate(boundMargins);
   790   }
   792   metrics.SetRootCompositionSize(
   793     nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame ? aScrollFrame : aForFrame,
   794                                                 isRootContentDocRootScrollFrame, metrics));
   796   if (GetApzcTreePrintPref()) {
   797     if (nsIContent* content = frameForCompositionBoundsCalculation->GetContent()) {
   798       nsAutoString contentDescription;
   799       content->Describe(contentDescription);
   800       metrics.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription).get());
   801     }
   802   }
   804   metrics.mPresShellId = presShell->GetPresShellId();
   806   // If the scroll frame's content is marked 'scrollgrab', record this
   807   // in the FrameMetrics so APZ knows to provide the scroll grabbing
   808   // behaviour.
   809   if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) {
   810     metrics.mHasScrollgrab = true;
   811   }
   813   aRoot->SetFrameMetrics(metrics);
   814 }
   816 nsDisplayListBuilder::~nsDisplayListBuilder() {
   817   NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
   818                "All frames should have been unmarked");
   819   NS_ASSERTION(mPresShellStates.Length() == 0,
   820                "All presshells should have been exited");
   821   NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
   823   nsCSSRendering::EndFrameTreesLocked();
   825   for (uint32_t i = 0; i < mDisplayItemClipsToDestroy.Length(); ++i) {
   826     mDisplayItemClipsToDestroy[i]->DisplayItemClip::~DisplayItemClip();
   827   }
   829   PL_FinishArenaPool(&mPool);
   830   MOZ_COUNT_DTOR(nsDisplayListBuilder);
   831 }
   833 uint32_t
   834 nsDisplayListBuilder::GetBackgroundPaintFlags() {
   835   uint32_t flags = 0;
   836   if (mSyncDecodeImages) {
   837     flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES;
   838   }
   839   if (mIsPaintingToWindow) {
   840     flags |= nsCSSRendering::PAINTBG_TO_WINDOW;
   841   }
   842   return flags;
   843 }
   845 void
   846 nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
   847                                                 const nsRegion& aRegion)
   848 {
   849   if (aRegion.IsEmpty())
   850     return;
   852   nsRegion tmp;
   853   tmp.Sub(*aVisibleRegion, aRegion);
   854   // Don't let *aVisibleRegion get too complex, but don't let it fluff out
   855   // to its bounds either, which can be very bad (see bug 516740).
   856   // Do let aVisibleRegion get more complex if by doing so we reduce its
   857   // area by at least half.
   858   if (GetAccurateVisibleRegions() || tmp.GetNumRects() <= 15 ||
   859       tmp.Area() <= aVisibleRegion->Area()/2) {
   860     *aVisibleRegion = tmp;
   861   }
   862 }
   864 nsCaret *
   865 nsDisplayListBuilder::GetCaret() {
   866   nsRefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
   867   return caret;
   868 }
   870 void
   871 nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
   872                                      const nsRect& aDirtyRect) {
   873   PresShellState* state = mPresShellStates.AppendElement();
   874   if (!state)
   875     return;
   876   state->mPresShell = aReferenceFrame->PresContext()->PresShell();
   877   state->mCaretFrame = nullptr;
   878   state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
   880   state->mPresShell->UpdateCanvasBackground();
   882   if (mIsPaintingToWindow) {
   883     mReferenceFrame->AddPaintedPresShell(state->mPresShell);
   885     state->mPresShell->IncrementPaintCount();
   886   }
   888   bool buildCaret = mBuildCaret;
   889   if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) {
   890     if (state->mPresShell->IsPaintingSuppressed()) {
   891       mHadToIgnoreSuppression = true;
   892     }
   893     state->mIsBackgroundOnly = false;
   894   } else {
   895     state->mIsBackgroundOnly = true;
   896     buildCaret = false;
   897   }
   899   if (!buildCaret)
   900     return;
   902   nsRefPtr<nsCaret> caret = state->mPresShell->GetCaret();
   903   state->mCaretFrame = caret->GetCaretFrame();
   904   NS_ASSERTION(state->mCaretFrame == caret->GetCaretFrame(),
   905                "GetCaretFrame() is unstable");
   907   if (state->mCaretFrame) {
   908     // Check if the dirty rect intersects with the caret's dirty rect.
   909     nsRect caretRect =
   910       caret->GetCaretRect() + state->mCaretFrame->GetOffsetTo(aReferenceFrame);
   911     if (caretRect.Intersects(aDirtyRect)) {
   912       // Okay, our rects intersect, let's mark the frame and all of its ancestors.
   913       mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
   914       MarkFrameForDisplay(state->mCaretFrame, nullptr);
   915     }
   916   }
   917 }
   919 void
   920 nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
   921                                      const nsRect& aDirtyRect) {
   922   if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) {
   923     // Must have not allocated a state for this presshell, presumably due
   924     // to OOM.
   925     return;
   926   }
   928   ResetMarkedFramesForDisplayList();
   929   mPresShellStates.SetLength(mPresShellStates.Length() - 1);
   930 }
   932 void
   933 nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
   934 {
   935   // Unmark and pop off the frames marked for display in this pres shell.
   936   uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
   937   for (uint32_t i = firstFrameForShell;
   938        i < mFramesMarkedForDisplay.Length(); ++i) {
   939     UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
   940   }
   941   mFramesMarkedForDisplay.SetLength(firstFrameForShell);
   942 }
   944 void
   945 nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
   946                                                const nsFrameList& aFrames,
   947                                                const nsRect& aDirtyRect) {
   948   mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
   949   for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) {
   950     mFramesMarkedForDisplay.AppendElement(e.get());
   951     MarkOutOfFlowFrameForDisplay(aDirtyFrame, e.get(), aDirtyRect);
   952   }
   953 }
   955 void
   956 nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect)
   957 {
   958   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
   959   aDirtyFrame->GetChildLists(&childListArray);
   960   nsIFrame::ChildListArrayIterator lists(childListArray);
   961   for (; !lists.IsDone(); lists.Next()) {
   962     nsFrameList::Enumerator childFrames(lists.CurrentList());
   963     for (; !childFrames.AtEnd(); childFrames.Next()) {
   964       nsIFrame *child = childFrames.get();
   965       if (child->Preserves3D()) {
   966         mFramesMarkedForDisplay.AppendElement(child);
   967         nsRect dirty = aDirtyRect - child->GetOffsetTo(aDirtyFrame);
   969         child->Properties().Set(nsDisplayListBuilder::Preserve3DDirtyRectProperty(),
   970                            new nsRect(dirty));
   972         MarkFrameForDisplay(child, aDirtyFrame);
   973       }
   974     }
   975   }
   976 }
   978 void*
   979 nsDisplayListBuilder::Allocate(size_t aSize) {
   980   void *tmp;
   981   PL_ARENA_ALLOCATE(tmp, &mPool, aSize);
   982   if (!tmp) {
   983     NS_RUNTIMEABORT("out of memory");
   984   }
   985   return tmp;
   986 }
   988 const DisplayItemClip*
   989 nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip& aOriginal)
   990 {
   991   void* p = Allocate(sizeof(DisplayItemClip));
   992   if (!aOriginal.GetRoundedRectCount()) {
   993     memcpy(p, &aOriginal, sizeof(DisplayItemClip));
   994     return static_cast<DisplayItemClip*>(p);
   995   }
   997   DisplayItemClip* c = new (p) DisplayItemClip(aOriginal);
   998   mDisplayItemClipsToDestroy.AppendElement(c);
   999   return c;
  1002 void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const
  1004   aDestination.BorderBackground()->AppendToTop(BorderBackground());
  1005   aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
  1006   aDestination.Floats()->AppendToTop(Floats());
  1007   aDestination.Content()->AppendToTop(Content());
  1008   aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
  1009   aDestination.Outlines()->AppendToTop(Outlines());
  1012 void
  1013 nsDisplayList::FlattenTo(nsTArray<nsDisplayItem*>* aElements) {
  1014   nsDisplayItem* item;
  1015   while ((item = RemoveBottom()) != nullptr) {
  1016     if (item->GetType() == nsDisplayItem::TYPE_WRAP_LIST) {
  1017       item->GetSameCoordinateSystemChildren()->FlattenTo(aElements);
  1018       item->~nsDisplayItem();
  1019     } else {
  1020       aElements->AppendElement(item);
  1025 nsRect
  1026 nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
  1027   nsRect bounds;
  1028   for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
  1029     bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
  1031   return bounds;
  1034 bool
  1035 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
  1036                                         nsRegion* aVisibleRegion,
  1037                                         nsIFrame* aDisplayPortFrame) {
  1038   PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot");
  1039   nsRegion r;
  1040   r.And(*aVisibleRegion, GetBounds(aBuilder));
  1041   return ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
  1042                                      r.GetBounds(), r.GetBounds(),
  1043                                      aDisplayPortFrame);
  1046 static nsRegion
  1047 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
  1049   bool snap;
  1050   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
  1051   if (aBuilder->IsForPluginGeometry()) {
  1052     // Treat all leaf chrome items as opaque, unless their frames are opacity:0.
  1053     // Since opacity:0 frames generate an nsDisplayOpacity, that item will
  1054     // not be treated as opaque here, so opacity:0 chrome content will be
  1055     // effectively ignored, as it should be.
  1056     // We treat leaf chrome items as opaque to ensure that they cover
  1057     // content plugins, for security reasons.
  1058     // Non-leaf chrome items don't render contents of their own so shouldn't
  1059     // be treated as opaque (and their bounds is just the union of their
  1060     // children, which might be a large area their contents don't really cover).
  1061     nsIFrame* f = aItem->Frame();
  1062     if (f->PresContext()->IsChrome() && !aItem->GetChildren() &&
  1063         f->StyleDisplay()->mOpacity != 0.0) {
  1064       opaque = aItem->GetBounds(aBuilder, &snap);
  1067   if (opaque.IsEmpty()) {
  1068     return opaque;
  1070   nsRegion opaqueClipped;
  1071   nsRegionRectIterator iter(opaque);
  1072   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
  1073     opaqueClipped.Or(opaqueClipped, aItem->GetClip().ApproximateIntersectInward(*r));
  1075   return opaqueClipped;
  1078 /* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem
  1079  * is an overlay scrollbar item for the same scroll frame.
  1080  */
  1081 static bool
  1082 IsScrollLayerItemAndOverlayScrollbarForScrollFrame(
  1083   nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem)
  1085   if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER &&
  1086       aPotentialScrollbarItem &&
  1087       aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER &&
  1088       LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
  1089     nsDisplayScrollLayer* scrollItem =
  1090       static_cast<nsDisplayScrollLayer*>(aPotentialScrollItem);
  1091     nsDisplayOwnLayer* layerItem =
  1092       static_cast<nsDisplayOwnLayer*>(aPotentialScrollbarItem);
  1093     if ((layerItem->GetFlags() &
  1094          (nsDisplayOwnLayer::VERTICAL_SCROLLBAR |
  1095           nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) &&
  1096         layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) {
  1097       return true;
  1100   return false;
  1103 bool
  1104 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
  1105                                            nsRegion* aVisibleRegion,
  1106                                            const nsRect& aListVisibleBounds,
  1107                                            const nsRect& aAllowVisibleRegionExpansion,
  1108                                            nsIFrame* aDisplayPortFrame) {
  1109 #ifdef DEBUG
  1110   nsRegion r;
  1111   r.And(*aVisibleRegion, GetBounds(aBuilder));
  1112   NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
  1113                "bad aListVisibleBounds");
  1114 #endif
  1116   mVisibleRect = aListVisibleBounds;
  1117   bool anyVisible = false;
  1119   nsAutoTArray<nsDisplayItem*, 512> elements;
  1120   FlattenTo(&elements);
  1122   bool forceTransparentSurface = false;
  1124   for (int32_t i = elements.Length() - 1; i >= 0; --i) {
  1125     nsDisplayItem* item = elements[i];
  1126     nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1];
  1128     nsDisplayList* list = item->GetSameCoordinateSystemChildren();
  1129     if (aBuilder->AllowMergingAndFlattening()) {
  1130       if (belowItem && item->TryMerge(aBuilder, belowItem)) {
  1131         belowItem->~nsDisplayItem();
  1132         elements.ReplaceElementsAt(i - 1, 1, item);
  1133         continue;
  1136       // If an overlay scrollbar item is between a scroll layer item and the
  1137       // other scroll layer items that we need to merge with just move the
  1138       // scrollbar item up, that way it will be on top of the scrolled content
  1139       // and we can try to merge all the scroll layer items.
  1140       if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(item, belowItem)) {
  1141         elements[i] = belowItem;
  1142         elements[i-1] = item;
  1143         i++;
  1144         continue;
  1147       if (list && item->ShouldFlattenAway(aBuilder)) {
  1148         // The elements on the list >= i no longer serve any use.
  1149         elements.SetLength(i);
  1150         list->FlattenTo(&elements);
  1151         i = elements.Length();
  1152         item->~nsDisplayItem();
  1153         continue;
  1157     nsRect bounds = item->GetClippedBounds(aBuilder);
  1159     nsRegion itemVisible;
  1160     itemVisible.And(*aVisibleRegion, bounds);
  1161     item->mVisibleRect = itemVisible.GetBounds();
  1163     if (item->ComputeVisibility(aBuilder, aVisibleRegion,
  1164                                 aAllowVisibleRegionExpansion.Intersect(bounds))) {
  1165       anyVisible = true;
  1167       // If we're in a displayport, we need to make sure that fixed position
  1168       // items do not subtract from the visible region, as async scrolling
  1169       // may expose these occluded areas.
  1170       // If the item is fixed pos in the same document as the displayport
  1171       // then don't let it occlude this list. The only other case possible
  1172       // is that the fixed pos content is in a child document, in which it
  1173       // would scroll with the rest of the content.
  1174       bool occlude = true;
  1175       if (aDisplayPortFrame && item->IsInFixedPos()) {
  1176         if (item->Frame()->PresContext() == aDisplayPortFrame->PresContext()) {
  1177           occlude = false;
  1181       if (occlude) {
  1182         nsRegion opaque = TreatAsOpaque(item, aBuilder);
  1183         // Subtract opaque item from the visible region
  1184         aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
  1187       if (aBuilder->NeedToForceTransparentSurfaceForItem(item) ||
  1188           (list && list->NeedsTransparentSurface())) {
  1189         forceTransparentSurface = true;
  1192     AppendToBottom(item);
  1195   mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect);
  1196   mForceTransparentSurface = forceTransparentSurface;
  1197 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
  1198   mDidComputeVisibility = true;
  1199 #endif
  1200   return anyVisible;
  1203 void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
  1204                               nsRenderingContext* aCtx,
  1205                               uint32_t aFlags) const {
  1206   PROFILER_LABEL("nsDisplayList", "PaintRoot");
  1207   PaintForFrame(aBuilder, aCtx, aBuilder->RootReferenceFrame(), aFlags);
  1210 /**
  1211  * We paint by executing a layer manager transaction, constructing a
  1212  * single layer representing the display list, and then making it the
  1213  * root of the layer manager, drawing into the ThebesLayers.
  1214  */
  1215 void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
  1216                                   nsRenderingContext* aCtx,
  1217                                   nsIFrame* aForFrame,
  1218                                   uint32_t aFlags) const {
  1219   NS_ASSERTION(mDidComputeVisibility,
  1220                "Must call ComputeVisibility before calling Paint");
  1222   nsRefPtr<LayerManager> layerManager;
  1223   bool widgetTransaction = false;
  1224   bool allowRetaining = false;
  1225   bool doBeginTransaction = true;
  1226   nsView *view = nullptr;
  1227   if (aFlags & PAINT_USE_WIDGET_LAYERS) {
  1228     nsIFrame* rootReferenceFrame = aBuilder->RootReferenceFrame();
  1229     view = rootReferenceFrame->GetView();
  1230     NS_ASSERTION(rootReferenceFrame == nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame),
  1231                  "Reference frame must be a display root for us to use the layer manager");
  1232     nsIWidget* window = rootReferenceFrame->GetNearestWidget();
  1233     if (window) {
  1234       layerManager = window->GetLayerManager(&allowRetaining);
  1235       if (layerManager) {
  1236         doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
  1237         widgetTransaction = true;
  1241   if (!layerManager) {
  1242     if (!aCtx) {
  1243       NS_WARNING("Nowhere to paint into");
  1244       return;
  1246     layerManager = new BasicLayerManager();
  1249   // Store the existing layer builder to reinstate it on return.
  1250   FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
  1252   FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
  1253   layerBuilder->Init(aBuilder, layerManager);
  1255   if (aFlags & PAINT_COMPRESSED) {
  1256     layerBuilder->SetLayerTreeCompressionMode();
  1259   if (aFlags & PAINT_FLUSH_LAYERS) {
  1260     FrameLayerBuilder::InvalidateAllLayers(layerManager);
  1263   if (doBeginTransaction) {
  1264     if (aCtx) {
  1265       layerManager->BeginTransactionWithTarget(aCtx->ThebesContext());
  1266     } else {
  1267       layerManager->BeginTransaction();
  1270   if (widgetTransaction) {
  1271     layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
  1274   nsPresContext* presContext = aForFrame->PresContext();
  1275   nsIPresShell* presShell = presContext->GetPresShell();
  1277   NotifySubDocInvalidationFunc computeInvalidFunc =
  1278     presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
  1279   bool computeInvalidRect = (computeInvalidFunc ||
  1280                              (!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) &&
  1281                             widgetTransaction;
  1283   nsAutoPtr<LayerProperties> props(computeInvalidRect ? 
  1284                                      LayerProperties::CloneFrom(layerManager->GetRoot()) : 
  1285                                      nullptr);
  1287   ContainerLayerParameters containerParameters
  1288     (presShell->GetXResolution(), presShell->GetYResolution());
  1289   nsRefPtr<ContainerLayer> root = layerBuilder->
  1290     BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this,
  1291                            containerParameters, nullptr);
  1293   nsIDocument* document = nullptr;
  1294   if (presShell) {
  1295     document = presShell->GetDocument();
  1298   if (widgetTransaction ||
  1299       // SVG-as-an-image docs don't paint as part of the retained layer tree,
  1300       // but they still need the invalidation state bits cleared in order for
  1301       // invalidation for CSS/SMIL animation to work properly.
  1302       (document && document->IsBeingUsedAsImage())) {
  1303     aForFrame->ClearInvalidationStateBits();
  1306   if (!root) {
  1307     layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
  1308     return;
  1310   // Root is being scaled up by the X/Y resolution. Scale it back down.
  1311   root->SetPostScale(1.0f/containerParameters.mXScale,
  1312                      1.0f/containerParameters.mYScale);
  1314   ViewID id = FrameMetrics::NULL_SCROLL_ID;
  1315   bool isRoot = presContext->IsRootContentDocument();
  1317   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
  1318   nsRect displayport, criticalDisplayport;
  1319   bool usingDisplayport = false;
  1320   bool usingCriticalDisplayport = false;
  1321   if (rootScrollFrame) {
  1322     nsIContent* content = rootScrollFrame->GetContent();
  1323     if (content) {
  1324       usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
  1325       usingCriticalDisplayport =
  1326         nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport);
  1328       // If this is the root content document, we want it to have a scroll id.
  1329       if (isRoot) {
  1330         id = nsLayoutUtils::FindOrCreateIDFor(content);
  1335   nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
  1337   RecordFrameMetrics(aForFrame, rootScrollFrame,
  1338                      aBuilder->FindReferenceFrameFor(aForFrame),
  1339                      root, mVisibleRect, viewport,
  1340                      (usingDisplayport ? &displayport : nullptr),
  1341                      (usingCriticalDisplayport ? &criticalDisplayport : nullptr),
  1342                      id, isRoot, containerParameters);
  1343   if (usingDisplayport &&
  1344       !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
  1345     // See bug 693938, attachment 567017
  1346     NS_WARNING("Transparent content with displayports can be expensive.");
  1349   layerManager->SetRoot(root);
  1350   layerBuilder->WillEndTransaction();
  1351   bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
  1352   LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT;
  1353   if (layerManager->NeedsWidgetInvalidation()) {
  1354     if (aFlags & PAINT_NO_COMPOSITE) {
  1355       flags = LayerManager::END_NO_COMPOSITE;
  1357   } else {
  1358     // Client layer managers never composite directly, so
  1359     // we don't need to worry about END_NO_COMPOSITE.
  1360     if (aBuilder->WillComputePluginGeometry()) {
  1361       flags = LayerManager::END_NO_REMOTE_COMPOSITE;
  1365   layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
  1366                                aBuilder, flags);
  1367   aBuilder->SetIsCompositingCheap(temp);
  1368   layerBuilder->DidEndTransaction();
  1370   nsIntRegion invalid;
  1371   if (props) {
  1372     invalid = props->ComputeDifferences(root, computeInvalidFunc);
  1373   } else if (widgetTransaction) {
  1374     LayerProperties::ClearInvalidations(root);
  1377   bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
  1378   if (view) {
  1379     if (props) {
  1380       if (!invalid.IsEmpty()) {
  1381         nsIntRect bounds = invalid.GetBounds();
  1382         nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
  1383                     presContext->DevPixelsToAppUnits(bounds.y),
  1384                     presContext->DevPixelsToAppUnits(bounds.width),
  1385                     presContext->DevPixelsToAppUnits(bounds.height));
  1386         if (shouldInvalidate) {
  1387           view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
  1389         presContext->NotifyInvalidation(bounds, 0);
  1391     } else if (shouldInvalidate) {
  1392       view->GetViewManager()->InvalidateView(view);
  1396   if (aFlags & PAINT_FLUSH_LAYERS) {
  1397     FrameLayerBuilder::InvalidateAllLayers(layerManager);
  1400   layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
  1403 uint32_t nsDisplayList::Count() const {
  1404   uint32_t count = 0;
  1405   for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
  1406     ++count;
  1408   return count;
  1411 nsDisplayItem* nsDisplayList::RemoveBottom() {
  1412   nsDisplayItem* item = mSentinel.mAbove;
  1413   if (!item)
  1414     return nullptr;
  1415   mSentinel.mAbove = item->mAbove;
  1416   if (item == mTop) {
  1417     // must have been the only item
  1418     mTop = &mSentinel;
  1420   item->mAbove = nullptr;
  1421   return item;
  1424 void nsDisplayList::DeleteAll() {
  1425   nsDisplayItem* item;
  1426   while ((item = RemoveBottom()) != nullptr) {
  1427     item->~nsDisplayItem();
  1431 static bool
  1432 GetMouseThrough(const nsIFrame* aFrame)
  1434   if (!aFrame->IsBoxFrame())
  1435     return false;
  1437   const nsIFrame* frame = aFrame;
  1438   while (frame) {
  1439     if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS) {
  1440       return true;
  1441     } else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
  1442       return false;
  1444     frame = frame->GetParentBox();
  1446   return false;
  1449 static bool
  1450 IsFrameReceivingPointerEvents(nsIFrame* aFrame)
  1452   nsSubDocumentFrame* frame = do_QueryFrame(aFrame);
  1453   if (frame && frame->PassPointerEventsToChildren()) {
  1454     return true;
  1456   return NS_STYLE_POINTER_EVENTS_NONE !=
  1457     aFrame->StyleVisibility()->GetEffectivePointerEvents(aFrame);
  1460 // A list of frames, and their z depth. Used for sorting
  1461 // the results of hit testing.
  1462 struct FramesWithDepth
  1464   FramesWithDepth(float aDepth) :
  1465     mDepth(aDepth)
  1466   {}
  1468   bool operator<(const FramesWithDepth& aOther) const {
  1469     if (mDepth != aOther.mDepth) {
  1470       // We want to sort so that the shallowest item (highest depth value) is first
  1471       return mDepth > aOther.mDepth;
  1473     return this < &aOther;
  1475   bool operator==(const FramesWithDepth& aOther) const {
  1476     return this == &aOther;
  1479   float mDepth;
  1480   nsTArray<nsIFrame*> mFrames;
  1481 };
  1483 // Sort the frames by depth and then moves all the contained frames to the destination
  1484 void FlushFramesArray(nsTArray<FramesWithDepth>& aSource, nsTArray<nsIFrame*>* aDest)
  1486   if (aSource.IsEmpty()) {
  1487     return;
  1489   aSource.Sort();
  1490   uint32_t length = aSource.Length();
  1491   for (uint32_t i = 0; i < length; i++) {
  1492     aDest->MoveElementsFrom(aSource[i].mFrames);
  1494   aSource.Clear();
  1497 void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  1498                             nsDisplayItem::HitTestState* aState,
  1499                             nsTArray<nsIFrame*> *aOutFrames) const {
  1500   int32_t itemBufferStart = aState->mItemBuffer.Length();
  1501   nsDisplayItem* item;
  1502   for (item = GetBottom(); item; item = item->GetAbove()) {
  1503     aState->mItemBuffer.AppendElement(item);
  1505   nsAutoTArray<FramesWithDepth, 16> temp;
  1506   for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) {
  1507     // Pop element off the end of the buffer. We want to shorten the buffer
  1508     // so that recursive calls to HitTest have more buffer space.
  1509     item = aState->mItemBuffer[i];
  1510     aState->mItemBuffer.SetLength(i);
  1512     bool snap;
  1513     nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
  1514     if (item->GetClip().MayIntersect(r)) {
  1515       nsAutoTArray<nsIFrame*, 16> outFrames;
  1516       item->HitTest(aBuilder, aRect, aState, &outFrames);
  1518       // For 3d transforms with preserve-3d we add hit frames into the temp list
  1519       // so we can sort them later, otherwise we add them directly to the output list.
  1520       nsTArray<nsIFrame*> *writeFrames = aOutFrames;
  1521       if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
  1522           item->Frame()->Preserves3D()) {
  1523         if (outFrames.Length()) {
  1524           nsDisplayTransform *transform = static_cast<nsDisplayTransform*>(item);
  1525           nsPoint point = aRect.TopLeft();
  1526           // A 1x1 rect means a point, otherwise use the center of the rect
  1527           if (aRect.width != 1 || aRect.height != 1) {
  1528             point = aRect.Center();
  1530           temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point)));
  1531           writeFrames = &temp[temp.Length() - 1].mFrames;
  1533       } else {
  1534         // We may have just finished a run of consecutive preserve-3d transforms,
  1535         // so flush these into the destination array before processing our frame list.
  1536         FlushFramesArray(temp, aOutFrames);
  1539       for (uint32_t j = 0; j < outFrames.Length(); j++) {
  1540         nsIFrame *f = outFrames.ElementAt(j);
  1541         // Handle the XUL 'mousethrough' feature and 'pointer-events'.
  1542         if (!GetMouseThrough(f) && IsFrameReceivingPointerEvents(f)) {
  1543           writeFrames->AppendElement(f);
  1548   // Clear any remaining preserve-3d transforms.
  1549   FlushFramesArray(temp, aOutFrames);
  1550   NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart),
  1551                "How did we forget to pop some elements?");
  1554 static void Sort(nsDisplayList* aList, int32_t aCount, nsDisplayList::SortLEQ aCmp,
  1555                  void* aClosure) {
  1556   if (aCount < 2)
  1557     return;
  1559   nsDisplayList list1;
  1560   nsDisplayList list2;
  1561   int i;
  1562   int32_t half = aCount/2;
  1563   bool sorted = true;
  1564   nsDisplayItem* prev = nullptr;
  1565   for (i = 0; i < aCount; ++i) {
  1566     nsDisplayItem* item = aList->RemoveBottom();
  1567     (i < half ? &list1 : &list2)->AppendToTop(item);
  1568     if (sorted && prev && !aCmp(prev, item, aClosure)) {
  1569       sorted = false;
  1571     prev = item;
  1573   if (sorted) {
  1574     aList->AppendToTop(&list1);
  1575     aList->AppendToTop(&list2);
  1576     return;
  1579   Sort(&list1, half, aCmp, aClosure);
  1580   Sort(&list2, aCount - half, aCmp, aClosure);
  1582   for (i = 0; i < aCount; ++i) {
  1583     if (list1.GetBottom() &&
  1584         (!list2.GetBottom() ||
  1585          aCmp(list1.GetBottom(), list2.GetBottom(), aClosure))) {
  1586       aList->AppendToTop(list1.RemoveBottom());
  1587     } else {
  1588       aList->AppendToTop(list2.RemoveBottom());
  1593 static nsIContent* FindContentInDocument(nsDisplayItem* aItem, nsIDocument* aDoc) {
  1594   nsIFrame* f = aItem->Frame();
  1595   while (f) {
  1596     nsPresContext* pc = f->PresContext();
  1597     if (pc->Document() == aDoc) {
  1598       return f->GetContent();
  1600     f = nsLayoutUtils::GetCrossDocParentFrame(pc->PresShell()->GetRootFrame());
  1602   return nullptr;
  1605 static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
  1606                          void* aClosure) {
  1607   nsIContent* commonAncestor = static_cast<nsIContent*>(aClosure);
  1608   // It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument
  1609   // of commonAncestor, because display items for subdocuments have been
  1610   // mixed into the same list. Ensure that we're looking at content
  1611   // in commonAncestor's document.
  1612   nsIDocument* commonAncestorDoc = commonAncestor->OwnerDoc();
  1613   nsIContent* content1 = FindContentInDocument(aItem1, commonAncestorDoc);
  1614   nsIContent* content2 = FindContentInDocument(aItem2, commonAncestorDoc);
  1615   if (!content1 || !content2) {
  1616     NS_ERROR("Document trees are mixed up!");
  1617     // Something weird going on
  1618     return true;
  1620   return nsLayoutUtils::CompareTreePosition(content1, content2, commonAncestor) <= 0;
  1623 static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
  1624                         void* aClosure) {
  1625   // Note that we can't just take the difference of the two
  1626   // z-indices here, because that might overflow a 32-bit int.
  1627   return aItem1->ZIndex() <= aItem2->ZIndex();
  1630 void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder,
  1631                                  nsIContent* aCommonAncestor) {
  1632   Sort(aBuilder, IsZOrderLEQ, aCommonAncestor);
  1635 void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder,
  1636                                        nsIContent* aCommonAncestor) {
  1637   Sort(aBuilder, IsContentLEQ, aCommonAncestor);
  1640 void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
  1641                          SortLEQ aCmp, void* aClosure) {
  1642   ::Sort(this, Count(), aCmp, aClosure);
  1645 void
  1646 nsDisplayItem::AddInvalidRegionForSyncDecodeBackgroundImages(
  1647   nsDisplayListBuilder* aBuilder,
  1648   const nsDisplayItemGeometry* aGeometry,
  1649   nsRegion* aInvalidRegion)
  1651   if (aBuilder->ShouldSyncDecodeImages()) {
  1652     if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
  1653       bool snap;
  1654       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
  1659 /* static */ bool
  1660 nsDisplayItem::ForceActiveLayers()
  1662   static bool sForce = false;
  1663   static bool sForceCached = false;
  1665   if (!sForceCached) {
  1666     Preferences::AddBoolVarCache(&sForce, "layers.force-active", false);
  1667     sForceCached = true;
  1670   return sForce;
  1673 /* static */ int32_t
  1674 nsDisplayItem::MaxActiveLayers()
  1676   static int32_t sMaxLayers = false;
  1677   static bool sMaxLayersCached = false;
  1679   if (!sMaxLayersCached) {
  1680     Preferences::AddIntVarCache(&sMaxLayers, "layers.max-active", -1);
  1681     sMaxLayersCached = true;
  1684   return sMaxLayers;
  1687 int32_t
  1688 nsDisplayItem::ZIndex() const
  1690   if (!mFrame->IsPositioned() && !mFrame->IsFlexItem())
  1691     return 0;
  1693   const nsStylePosition* position = mFrame->StylePosition();
  1694   if (position->mZIndex.GetUnit() == eStyleUnit_Integer)
  1695     return position->mZIndex.GetIntValue();
  1697   // sort the auto and 0 elements together
  1698   return 0;
  1701 bool
  1702 nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
  1703                                    nsRegion* aVisibleRegion) {
  1704   nsRect bounds = GetClippedBounds(aBuilder);
  1706   nsRegion itemVisible;
  1707   itemVisible.And(*aVisibleRegion, bounds);
  1708   mVisibleRect = itemVisible.GetBounds();
  1710   // When we recompute visibility within layers we don't need to
  1711   // expand the visible region for content behind plugins (the plugin
  1712   // is not in the layer).
  1713   if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect()))
  1714     return false;
  1716   nsRegion opaque = TreatAsOpaque(this, aBuilder);
  1717   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
  1718   return true;
  1721 nsRect
  1722 nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
  1724   bool snap;
  1725   nsRect r = GetBounds(aBuilder, &snap);
  1726   return GetClip().ApplyNonRoundedIntersection(r);
  1729 nsRect
  1730 nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  1732   *aSnap = true;
  1733   return mBounds;
  1736 void
  1737 nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
  1738                            nsRenderingContext* aCtx)
  1740   aCtx->SetColor(mColor);
  1741   aCtx->FillRect(mVisibleRect);
  1744 #ifdef MOZ_DUMP_PAINTING
  1745 void
  1746 nsDisplaySolidColor::WriteDebugInfo(nsACString& aTo)
  1748   aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)",
  1749                  NS_GET_R(mColor), NS_GET_G(mColor),
  1750                  NS_GET_B(mColor), NS_GET_A(mColor));
  1752 #endif
  1754 static void
  1755 RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
  1757   nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
  1759   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
  1760     // Bail out if we're in a transformed subtree
  1761     if (f->IsTransformed())
  1762       return;
  1763     // Bail out if we're not in the displayRoot's document
  1764     if (!f->GetParent() && f != displayRoot)
  1765       return;
  1768   nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize());
  1769   aBuilder->RegisterThemeGeometry(aFrame->StyleDisplay()->mAppearance,
  1770       borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
  1773 nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
  1774                                                    nsIFrame* aFrame,
  1775                                                    uint32_t aLayer,
  1776                                                    const nsStyleBackground* aBackgroundStyle)
  1777   : nsDisplayImageContainer(aBuilder, aFrame)
  1778   , mBackgroundStyle(aBackgroundStyle)
  1779   , mLayer(aLayer)
  1781   MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
  1783   mBounds = GetBoundsInternal(aBuilder);
  1786 nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
  1788 #ifdef NS_BUILD_REFCNT_LOGGING
  1789   MOZ_COUNT_DTOR(nsDisplayBackgroundImage);
  1790 #endif
  1793 static nsStyleContext* GetBackgroundStyleContext(nsIFrame* aFrame)
  1795   nsStyleContext *sc;
  1796   if (!nsCSSRendering::FindBackground(aFrame, &sc)) {
  1797     // We don't want to bail out if moz-appearance is set on a root
  1798     // node. If it has a parent content node, bail because it's not
  1799     // a root, other wise keep going in order to let the theme stuff
  1800     // draw the background. The canvas really should be drawing the
  1801     // bg, but there's no way to hook that up via css.
  1802     if (!aFrame->StyleDisplay()->mAppearance) {
  1803       return nullptr;
  1806     nsIContent* content = aFrame->GetContent();
  1807     if (!content || content->GetParent()) {
  1808       return nullptr;
  1811     sc = aFrame->StyleContext();
  1813   return sc;
  1816 /*static*/ bool
  1817 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
  1818                                                      nsIFrame* aFrame,
  1819                                                      nsDisplayList* aList)
  1821   nsStyleContext* bgSC = nullptr;
  1822   const nsStyleBackground* bg = nullptr;
  1823   nsPresContext* presContext = aFrame->PresContext();
  1824   bool isThemed = aFrame->IsThemed();
  1825   if (!isThemed) {
  1826     bgSC = GetBackgroundStyleContext(aFrame);
  1827     if (bgSC) {
  1828       bg = bgSC->StyleBackground();
  1832   bool drawBackgroundColor = false;
  1833   nscolor color;
  1834   if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) {
  1835     bool drawBackgroundImage;
  1836     color =
  1837       nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame,
  1838                                                drawBackgroundImage, drawBackgroundColor);
  1841   // An auxiliary list is necessary in case we have background blending; if that
  1842   // is the case, background items need to be wrapped by a blend container to
  1843   // isolate blending to the background
  1844   nsDisplayList bgItemList;
  1845   // Even if we don't actually have a background color to paint, we may still need
  1846   // to create an item for hit testing.
  1847   if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) ||
  1848       aBuilder->IsForEventDelivery()) {
  1849     bgItemList.AppendNewToTop(
  1850         new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bg,
  1851                                                 drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
  1854   if (isThemed) {
  1855     nsDisplayThemedBackground* bgItem =
  1856       new (aBuilder) nsDisplayThemedBackground(aBuilder, aFrame);
  1857     bgItemList.AppendNewToTop(bgItem);
  1858     aList->AppendToTop(&bgItemList);
  1859     return true;
  1862   if (!bg) {
  1863     aList->AppendToTop(&bgItemList);
  1864     return false;
  1867   bool needBlendContainer = false;
  1869   // Passing bg == nullptr in this macro will result in one iteration with
  1870   // i = 0.
  1871   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
  1872     if (bg->mLayers[i].mImage.IsEmpty()) {
  1873       continue;
  1876     if (bg->mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
  1877       needBlendContainer = true;
  1880     nsDisplayBackgroundImage* bgItem =
  1881       new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bg);
  1882     bgItemList.AppendNewToTop(bgItem);
  1885   if (needBlendContainer) {
  1886     bgItemList.AppendNewToTop(
  1887       new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList));
  1890   aList->AppendToTop(&bgItemList);
  1891   return false;
  1894 // Check that the rounded border of aFrame, added to aToReferenceFrame,
  1895 // intersects aRect.  Assumes that the unrounded border has already
  1896 // been checked for intersection.
  1897 static bool
  1898 RoundedBorderIntersectsRect(nsIFrame* aFrame,
  1899                             const nsPoint& aFrameToReferenceFrame,
  1900                             const nsRect& aTestRect)
  1902   if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize()).Intersects(aTestRect))
  1903     return false;
  1905   nscoord radii[8];
  1906   return !aFrame->GetBorderRadii(radii) ||
  1907          nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
  1908                                                   aFrame->GetSize()),
  1909                                                   radii, aTestRect);
  1912 // Returns TRUE if aContainedRect is guaranteed to be contained in
  1913 // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
  1914 // handled conservatively by returning FALSE in some situations where
  1915 // a more thorough analysis could return TRUE.
  1916 //
  1917 // See also RoundedRectIntersectsRect.
  1918 static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
  1919                                     const nscoord aRadii[8],
  1920                                     const nsRect& aContainedRect) {
  1921   nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
  1922   return rgn.Contains(aContainedRect);
  1925 bool
  1926 nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
  1927                                                      const nsRect& aClipRect,
  1928                                                      gfxRect* aDestRect)
  1930   if (!mBackgroundStyle)
  1931     return false;
  1933   if (mBackgroundStyle->mLayers.Length() != 1)
  1934     return false;
  1936   nsPresContext* presContext = mFrame->PresContext();
  1937   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
  1938   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
  1939   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
  1941   if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
  1942     return false;
  1944   nsBackgroundLayerState state =
  1945     nsCSSRendering::PrepareBackgroundLayer(presContext,
  1946                                            mFrame,
  1947                                            flags,
  1948                                            borderArea,
  1949                                            aClipRect,
  1950                                            *mBackgroundStyle,
  1951                                            layer);
  1953   nsImageRenderer* imageRenderer = &state.mImageRenderer;
  1954   // We only care about images here, not gradients.
  1955   if (!imageRenderer->IsRasterImage())
  1956     return false;
  1958   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
  1959   *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
  1961   return true;
  1964 bool
  1965 nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager* aManager,
  1966                                                   nsDisplayListBuilder* aBuilder)
  1968   if (!mBackgroundStyle)
  1969     return false;
  1971   nsPresContext* presContext = mFrame->PresContext();
  1972   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
  1973   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
  1974   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
  1976   if (layer.mClip != NS_STYLE_BG_CLIP_BORDER) {
  1977     return false;
  1979   nscoord radii[8];
  1980   if (mFrame->GetBorderRadii(radii)) {
  1981     return false;
  1984   nsBackgroundLayerState state =
  1985     nsCSSRendering::PrepareBackgroundLayer(presContext,
  1986                                            mFrame,
  1987                                            flags,
  1988                                            borderArea,
  1989                                            borderArea,
  1990                                            *mBackgroundStyle,
  1991                                            layer);
  1993   nsImageRenderer* imageRenderer = &state.mImageRenderer;
  1994   // We only care about images here, not gradients.
  1995   if (!imageRenderer->IsRasterImage())
  1996     return false;
  1998   nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager);
  1999   // Image is not ready to be made into a layer yet
  2000   if (!imageContainer)
  2001     return false;
  2003   // We currently can't handle tiled or partial backgrounds.
  2004   if (!state.mDestArea.IsEqualEdges(state.mFillArea)) {
  2005     return false;
  2008   // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
  2009   // layer pixel boundaries. This should be OK for now.
  2011   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
  2012   mDestRect = nsLayoutUtils::RectToGfxRect(state.mDestArea, appUnitsPerDevPixel);
  2013   mImageContainer = imageContainer;
  2015   // Ok, we can turn this into a layer if needed.
  2016   return true;
  2019 already_AddRefed<ImageContainer>
  2020 nsDisplayBackgroundImage::GetContainer(LayerManager* aManager,
  2021                                        nsDisplayListBuilder *aBuilder)
  2023   if (!TryOptimizeToImageLayer(aManager, aBuilder)) {
  2024     return nullptr;
  2027   nsRefPtr<ImageContainer> container = mImageContainer;
  2029   return container.forget();
  2032 LayerState
  2033 nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
  2034                                         LayerManager* aManager,
  2035                                         const ContainerLayerParameters& aParameters)
  2037   bool animated = false;
  2038   if (mBackgroundStyle) {
  2039     const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
  2040     const nsStyleImage* image = &layer.mImage;
  2041     if (image->GetType() == eStyleImageType_Image) {
  2042       imgIRequest* imgreq = image->GetImageData();
  2043       nsCOMPtr<imgIContainer> image;
  2044       if (NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) && image) {
  2045         if (NS_FAILED(image->GetAnimated(&animated))) {
  2046           animated = false;
  2052   if (!animated ||
  2053       !nsLayoutUtils::AnimatedImageLayersEnabled()) {
  2054     if (!aManager->IsCompositingCheap() ||
  2055         !nsLayoutUtils::GPUImageScalingEnabled()) {
  2056       return LAYER_NONE;
  2060   if (!TryOptimizeToImageLayer(aManager, aBuilder)) {
  2061     return LAYER_NONE;
  2064   if (!animated) {
  2065     mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
  2066     NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
  2068     gfxRect destRect = mDestRect;
  2070     destRect.width *= aParameters.mXScale;
  2071     destRect.height *= aParameters.mYScale;
  2073     // Calculate the scaling factor for the frame.
  2074     gfxSize scale = gfxSize(destRect.width / imageSize.width, destRect.height / imageSize.height);
  2076     // If we are not scaling at all, no point in separating this into a layer.
  2077     if (scale.width == 1.0f && scale.height == 1.0f) {
  2078       return LAYER_NONE;
  2081     // If the target size is pretty small, no point in using a layer.
  2082     if (destRect.width * destRect.height < 64 * 64) {
  2083       return LAYER_NONE;
  2087   return LAYER_ACTIVE;
  2090 already_AddRefed<Layer>
  2091 nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
  2092                                      LayerManager* aManager,
  2093                                      const ContainerLayerParameters& aParameters)
  2095   nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
  2096     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
  2097   if (!layer) {
  2098     layer = aManager->CreateImageLayer();
  2099     if (!layer)
  2100       return nullptr;
  2102   layer->SetContainer(mImageContainer);
  2103   ConfigureLayer(layer, aParameters.mOffset);
  2104   return layer.forget();
  2107 void
  2108 nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
  2110   aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
  2112   mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
  2113   NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
  2115   gfxPoint p = mDestRect.TopLeft() + aOffset;
  2116   gfx::Matrix transform;
  2117   transform.Translate(p.x, p.y);
  2118   transform.Scale(mDestRect.width/imageSize.width,
  2119                   mDestRect.height/imageSize.height);
  2120   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
  2121   aLayer->SetVisibleRegion(nsIntRect(0, 0, imageSize.width, imageSize.height));
  2124 void
  2125 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
  2126                                   const nsRect& aRect,
  2127                                   HitTestState* aState,
  2128                                   nsTArray<nsIFrame*> *aOutFrames)
  2130   if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
  2131     aOutFrames->AppendElement(mFrame);
  2135 bool
  2136 nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  2137                                             nsRegion* aVisibleRegion,
  2138                                             const nsRect& aAllowVisibleRegionExpansion)
  2140   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
  2141                                         aAllowVisibleRegionExpansion)) {
  2142     return false;
  2145   // Return false if the background was propagated away from this
  2146   // frame. We don't want this display item to show up and confuse
  2147   // anything.
  2148   return mBackgroundStyle;
  2151 /* static */ nsRegion
  2152 nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
  2153                                               nsPresContext* aPresContext,
  2154                                               uint8_t aClip, const nsRect& aRect,
  2155                                               bool* aSnap)
  2157   nsRegion result;
  2158   if (aRect.IsEmpty())
  2159     return result;
  2161   nsIFrame *frame = aItem->Frame();
  2163   nscoord radii[8];
  2164   nsRect clipRect;
  2165   bool haveRadii;
  2166   switch (aClip) {
  2167   case NS_STYLE_BG_CLIP_BORDER:
  2168     haveRadii = frame->GetBorderRadii(radii);
  2169     clipRect = nsRect(aItem->ToReferenceFrame(), frame->GetSize());
  2170     break;
  2171   case NS_STYLE_BG_CLIP_PADDING:
  2172     haveRadii = frame->GetPaddingBoxBorderRadii(radii);
  2173     clipRect = frame->GetPaddingRect() - frame->GetPosition() + aItem->ToReferenceFrame();
  2174     break;
  2175   case NS_STYLE_BG_CLIP_CONTENT:
  2176     haveRadii = frame->GetContentBoxBorderRadii(radii);
  2177     clipRect = frame->GetContentRect() - frame->GetPosition() + aItem->ToReferenceFrame();
  2178     break;
  2179   default:
  2180     NS_NOTREACHED("Unknown clip type");
  2181     return result;
  2184   if (haveRadii) {
  2185     *aSnap = false;
  2186     result = nsLayoutUtils::RoundedRectIntersectRect(clipRect, radii, aRect);
  2187   } else {
  2188     result = clipRect.Intersect(aRect);
  2190   return result;
  2193 nsRegion
  2194 nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  2195                                           bool* aSnap) {
  2196   nsRegion result;
  2197   *aSnap = false;
  2199   if (!mBackgroundStyle)
  2200     return result;
  2203   *aSnap = true;
  2205   // For policies other than EACH_BOX, don't try to optimize here, since
  2206   // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
  2207   // which expects frames to be sent to it in content order, not reverse
  2208   // content order which we'll produce here.
  2209   // Of course, if there's only one frame in the flow, it doesn't matter.
  2210   if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
  2211       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
  2212     const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
  2213     if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL) {
  2214       nsPresContext* presContext = mFrame->PresContext();
  2215       result = GetInsideClipRegion(this, presContext, layer.mClip, mBounds, aSnap);
  2219   return result;
  2222 bool
  2223 nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
  2224   if (!mBackgroundStyle) {
  2225     *aColor = NS_RGBA(0,0,0,0);
  2226     return true;
  2228   return false;
  2231 bool
  2232 nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
  2233                                                          nsIFrame* aFrame)
  2235   if (!mBackgroundStyle)
  2236     return false;
  2237   if (!mBackgroundStyle->HasFixedBackground())
  2238     return false;
  2240   // If aFrame is mFrame or an ancestor in this document, and aFrame is
  2241   // not the viewport frame, then moving aFrame will move mFrame
  2242   // relative to the viewport, so our fixed-pos background will change.
  2243   return aFrame->GetParent() &&
  2244     (aFrame == mFrame ||
  2245      nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
  2248 nsRect
  2249 nsDisplayBackgroundImage::GetPositioningArea()
  2251   if (!mBackgroundStyle) {
  2252     return nsRect();
  2254   nsIFrame* attachedToFrame;
  2255   return nsCSSRendering::ComputeBackgroundPositioningArea(
  2256       mFrame->PresContext(), mFrame,
  2257       nsRect(ToReferenceFrame(), mFrame->GetSize()),
  2258       *mBackgroundStyle, mBackgroundStyle->mLayers[mLayer],
  2259       &attachedToFrame) + ToReferenceFrame();
  2262 bool
  2263 nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
  2265   if (!mBackgroundStyle)
  2266     return false;
  2268   nscoord radii[8];
  2269   if (mFrame->GetBorderRadii(radii)) {
  2270     // A change in the size of the positioning area might change the position
  2271     // of the rounded corners.
  2272     return true;
  2275   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
  2276   if (layer.RenderingMightDependOnPositioningAreaSizeChange()) {
  2277     return true;
  2279   return false;
  2282 static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
  2284   nsDisplayItem* nextItem = aItem->GetAbove();
  2285   while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) {
  2286     nextItem = nextItem->GetAbove();
  2288   if (nextItem && 
  2289       nextItem->Frame() == aItem->Frame() &&
  2290       nextItem->GetType() == nsDisplayItem::TYPE_BORDER) {
  2291     aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
  2295 void
  2296 nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
  2297                                 nsRenderingContext* aCtx) {
  2298   PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr);
  2301 void
  2302 nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
  2303                                         nsRenderingContext* aCtx, const nsRect& aBounds,
  2304                                         nsRect* aClipRect) {
  2305   nsPoint offset = ToReferenceFrame();
  2306   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
  2307   CheckForBorderItem(this, flags);
  2309   nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
  2310                                   aBounds,
  2311                                   nsRect(offset, mFrame->GetSize()),
  2312                                   flags, aClipRect, mLayer);
  2316 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  2317                                                          const nsDisplayItemGeometry* aGeometry,
  2318                                                          nsRegion* aInvalidRegion)
  2320   if (!mBackgroundStyle) {
  2321     return;
  2324   const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
  2326   bool snap;
  2327   nsRect bounds = GetBounds(aBuilder, &snap);
  2328   nsRect positioningArea = GetPositioningArea();
  2329   if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
  2330       (positioningArea.Size() != geometry->mPositioningArea.Size() &&
  2331        RenderingMightDependOnPositioningAreaSizeChange())) {
  2332     // Positioning area changed in a way that could cause everything to change,
  2333     // so invalidate everything (both old and new painting areas).
  2334     aInvalidRegion->Or(bounds, geometry->mBounds);
  2336     if (positioningArea.Size() != geometry->mPositioningArea.Size()) {
  2337       NotifyRenderingChanged();
  2339     return;
  2341   if (aBuilder->ShouldSyncDecodeImages()) {
  2342     if (mBackgroundStyle &&
  2343         !nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(mBackgroundStyle, mLayer)) {
  2344       aInvalidRegion->Or(*aInvalidRegion, bounds);
  2346       NotifyRenderingChanged();
  2349   if (!bounds.IsEqualInterior(geometry->mBounds)) {
  2350     // Positioning area is unchanged, so invalidate just the change in the
  2351     // painting area.
  2352     aInvalidRegion->Xor(bounds, geometry->mBounds);
  2354     NotifyRenderingChanged();
  2358 nsRect
  2359 nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
  2360   *aSnap = true;
  2361   return mBounds;
  2364 nsRect
  2365 nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder) {
  2366   nsPresContext* presContext = mFrame->PresContext();
  2368   if (!mBackgroundStyle) {
  2369     return nsRect();
  2372   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
  2373   nsRect clipRect = borderBox;
  2374   if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
  2375     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
  2376     clipRect = frame->CanvasArea() + ToReferenceFrame();
  2378   const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
  2379   return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
  2380                                                 borderBox, clipRect,
  2381                                                 *mBackgroundStyle, layer,
  2382                                                 aBuilder->GetBackgroundPaintFlags());
  2385 uint32_t
  2386 nsDisplayBackgroundImage::GetPerFrameKey()
  2388   return (mLayer << nsDisplayItem::TYPE_BITS) |
  2389     nsDisplayItem::GetPerFrameKey();
  2392 nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder,
  2393                                                      nsIFrame* aFrame)
  2394   : nsDisplayItem(aBuilder, aFrame)
  2396   MOZ_COUNT_CTOR(nsDisplayThemedBackground);
  2398   const nsStyleDisplay* disp = mFrame->StyleDisplay();
  2399   mAppearance = disp->mAppearance;
  2400   mFrame->IsThemed(disp, &mThemeTransparency);
  2402   // Perform necessary RegisterThemeGeometry
  2403   switch (disp->mAppearance) {
  2404     case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
  2405     case NS_THEME_TOOLBAR:
  2406     case NS_THEME_WINDOW_TITLEBAR:
  2407     case NS_THEME_WINDOW_BUTTON_BOX:
  2408     case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
  2409     case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
  2410       RegisterThemeGeometry(aBuilder, aFrame);
  2411       break;
  2412     case NS_THEME_WIN_BORDERLESS_GLASS:
  2413     case NS_THEME_WIN_GLASS:
  2414       aBuilder->SetGlassDisplayItem(this);
  2415       break;
  2418   mBounds = GetBoundsInternal();
  2421 nsDisplayThemedBackground::~nsDisplayThemedBackground()
  2423 #ifdef NS_BUILD_REFCNT_LOGGING
  2424   MOZ_COUNT_DTOR(nsDisplayThemedBackground);
  2425 #endif
  2428 #ifdef MOZ_DUMP_PAINTING
  2429 void
  2430 nsDisplayThemedBackground::WriteDebugInfo(nsACString& aTo)
  2432   aTo += nsPrintfCString(" (themed, appearance:%d)", mAppearance);
  2434 #endif
  2436 void
  2437 nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder,
  2438                                   const nsRect& aRect,
  2439                                   HitTestState* aState,
  2440                                   nsTArray<nsIFrame*> *aOutFrames)
  2442   // Assume that any point in our border rect is a hit.
  2443   if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
  2444     aOutFrames->AppendElement(mFrame);
  2448 nsRegion
  2449 nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  2450                                            bool* aSnap) {
  2451   nsRegion result;
  2452   *aSnap = false;
  2454   if (mThemeTransparency == nsITheme::eOpaque) {
  2455     result = nsRect(ToReferenceFrame(), mFrame->GetSize());
  2457   return result;
  2460 bool
  2461 nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
  2462   if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
  2463       mAppearance == NS_THEME_WIN_GLASS) {
  2464     *aColor = NS_RGBA(0,0,0,0);
  2465     return true;
  2467   return false;
  2470 nsRect
  2471 nsDisplayThemedBackground::GetPositioningArea()
  2473   return nsRect(ToReferenceFrame(), mFrame->GetSize());
  2476 void
  2477 nsDisplayThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
  2478                                  nsRenderingContext* aCtx)
  2480   PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr);
  2484 void
  2485 nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
  2486                                          nsRenderingContext* aCtx, const nsRect& aBounds,
  2487                                          nsRect* aClipRect)
  2489   // XXXzw this ignores aClipRect.
  2490   nsPresContext* presContext = mFrame->PresContext();
  2491   nsITheme *theme = presContext->GetTheme();
  2492   nsRect borderArea(ToReferenceFrame(), mFrame->GetSize());
  2493   nsRect drawing(borderArea);
  2494   theme->GetWidgetOverflow(presContext->DeviceContext(), mFrame, mAppearance,
  2495                            &drawing);
  2496   drawing.IntersectRect(drawing, aBounds);
  2497   theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, borderArea, drawing);
  2500 bool nsDisplayThemedBackground::IsWindowActive()
  2502   EventStates docState = mFrame->GetContent()->OwnerDoc()->GetDocumentState();
  2503   return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
  2506 void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  2507                                                           const nsDisplayItemGeometry* aGeometry,
  2508                                                           nsRegion* aInvalidRegion)
  2510   const nsDisplayThemedBackgroundGeometry* geometry = static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry);
  2512   bool snap;
  2513   nsRect bounds = GetBounds(aBuilder, &snap);
  2514   nsRect positioningArea = GetPositioningArea();
  2515   if (!positioningArea.IsEqualInterior(geometry->mPositioningArea)) {
  2516     // Invalidate everything (both old and new painting areas).
  2517     aInvalidRegion->Or(bounds, geometry->mBounds);
  2518     return;
  2520   if (!bounds.IsEqualInterior(geometry->mBounds)) {
  2521     // Positioning area is unchanged, so invalidate just the change in the
  2522     // painting area.
  2523     aInvalidRegion->Xor(bounds, geometry->mBounds);
  2525   nsITheme* theme = mFrame->PresContext()->GetTheme();
  2526   if (theme->WidgetAppearanceDependsOnWindowFocus(mAppearance) &&
  2527       IsWindowActive() != geometry->mWindowIsActive) {
  2528     aInvalidRegion->Or(*aInvalidRegion, bounds);
  2532 nsRect
  2533 nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
  2534   *aSnap = true;
  2535   return mBounds;
  2538 nsRect
  2539 nsDisplayThemedBackground::GetBoundsInternal() {
  2540   nsPresContext* presContext = mFrame->PresContext();
  2542   nsRect r(nsPoint(0,0), mFrame->GetSize());
  2543   presContext->GetTheme()->
  2544       GetWidgetOverflow(presContext->DeviceContext(), mFrame,
  2545                         mFrame->StyleDisplay()->mAppearance, &r);
  2546 #ifdef XP_MACOSX
  2547   // Bug 748219
  2548   r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
  2549 #endif
  2551   return r + ToReferenceFrame();
  2554 void
  2555 nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
  2556                                 nsRenderingContext* aCtx) 
  2558   if (mColor == NS_RGBA(0, 0, 0, 0)) {
  2559     return;
  2562   nsPoint offset = ToReferenceFrame();
  2563   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
  2564   CheckForBorderItem(this, flags);
  2565   nsCSSRendering::PaintBackgroundColor(mFrame->PresContext(), *aCtx, mFrame,
  2566                                        mVisibleRect,
  2567                                        nsRect(offset, mFrame->GetSize()),
  2568                                        flags);
  2571 nsRegion
  2572 nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  2573                                           bool* aSnap) 
  2575   if (NS_GET_A(mColor) != 255) {
  2576     return nsRegion();
  2579   if (!mBackgroundStyle)
  2580     return nsRegion();
  2582   *aSnap = true;
  2584   const nsStyleBackground::Layer& bottomLayer = mBackgroundStyle->BottomLayer();
  2585   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
  2586   nsPresContext* presContext = mFrame->PresContext();
  2587   return nsDisplayBackgroundImage::GetInsideClipRegion(this, presContext, bottomLayer.mClip, borderBox, aSnap);
  2590 bool
  2591 nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) 
  2593   *aColor = mColor;
  2595   if (!mBackgroundStyle)
  2596     return true;
  2598   return (!nsLayoutUtils::HasNonZeroCorner(mFrame->StyleBorder()->mBorderRadius) &&
  2599           mBackgroundStyle->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER);
  2602 void
  2603 nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
  2604                                   const nsRect& aRect,
  2605                                   HitTestState* aState,
  2606                                   nsTArray<nsIFrame*> *aOutFrames)
  2608   if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
  2609     // aRect doesn't intersect our border-radius curve.
  2610     return;
  2613   aOutFrames->AppendElement(mFrame);
  2616 #ifdef MOZ_DUMP_PAINTING
  2617 void
  2618 nsDisplayBackgroundColor::WriteDebugInfo(nsACString& aTo)
  2620   aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", 
  2621           NS_GET_R(mColor), NS_GET_G(mColor),
  2622           NS_GET_B(mColor), NS_GET_A(mColor));
  2624 #endif
  2626 nsRect
  2627 nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
  2628   *aSnap = false;
  2629   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
  2632 void
  2633 nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
  2634                         nsRenderingContext* aCtx) {
  2635   // TODO join outlines together
  2636   nsPoint offset = ToReferenceFrame();
  2637   nsCSSRendering::PaintOutline(mFrame->PresContext(), *aCtx, mFrame,
  2638                                mVisibleRect,
  2639                                nsRect(offset, mFrame->GetSize()),
  2640                                mFrame->StyleContext());
  2643 bool
  2644 nsDisplayOutline::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  2645                                     nsRegion* aVisibleRegion,
  2646                                     const nsRect& aAllowVisibleRegionExpansion) {
  2647   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
  2648                                         aAllowVisibleRegionExpansion)) {
  2649     return false;
  2652   const nsStyleOutline* outline = mFrame->StyleOutline();
  2653   nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
  2654   if (borderBox.Contains(aVisibleRegion->GetBounds()) &&
  2655       !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) {
  2656     if (outline->mOutlineOffset >= 0) {
  2657       // the visible region is entirely inside the border-rect, and the outline
  2658       // isn't rendered inside the border-rect, so the outline is not visible
  2659       return false;
  2663   return true;
  2666 void
  2667 nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
  2668                                 const nsRect& aRect,
  2669                                 HitTestState* aState,
  2670                                 nsTArray<nsIFrame*> *aOutFrames)
  2672   if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
  2673     // aRect doesn't intersect our border-radius curve.
  2674     return;
  2677   aOutFrames->AppendElement(mFrame);
  2680 void
  2681 nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
  2682                                      nsIFrame* aFrame)
  2684   NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
  2685                "Reference frame mismatch");
  2686   uint8_t pointerEvents = aFrame->StyleVisibility()->mPointerEvents;
  2687   if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
  2688     return;
  2690   // XXX handle other pointerEvents values for SVG
  2691   // XXX Do something clever here for the common case where the border box
  2692   // is obviously entirely inside mHitRegion.
  2693   nsRect borderBox(aBuilder->ToReferenceFrame(aFrame), aFrame->GetSize());
  2694   const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
  2695   bool borderBoxHasRoundedCorners =
  2696     nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius);
  2697   if (clip) {
  2698     borderBox = clip->ApplyNonRoundedIntersection(borderBox);
  2699     if (clip->GetRoundedRectCount() > 0) {
  2700       borderBoxHasRoundedCorners = true;
  2703   if (borderBoxHasRoundedCorners ||
  2704       (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
  2705     mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
  2706   } else {
  2707     mHitRegion.Or(mHitRegion, borderBox);
  2709   if (aBuilder->GetAncestorHasTouchEventHandler()) {
  2710     mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
  2714 void
  2715 nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
  2716                       nsRenderingContext* aCtx) {
  2717   // Note: Because we exist, we know that the caret is visible, so we don't
  2718   // need to check for the caret's visibility.
  2719   mCaret->PaintCaret(aBuilder, aCtx, mFrame, ToReferenceFrame());
  2722 bool
  2723 nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  2724                                    nsRegion* aVisibleRegion,
  2725                                    const nsRect& aAllowVisibleRegionExpansion) {
  2726   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
  2727                                         aAllowVisibleRegionExpansion)) {
  2728     return false;
  2731   nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
  2732     ToReferenceFrame();
  2733   const nsStyleBorder *styleBorder;
  2734   if (paddingRect.Contains(aVisibleRegion->GetBounds()) &&
  2735       !(styleBorder = mFrame->StyleBorder())->IsBorderImageLoaded() &&
  2736       !nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
  2737     // the visible region is entirely inside the content rect, and no part
  2738     // of the border is rendered inside the content rect, so we are not
  2739     // visible
  2740     // Skip this if there's a border-image (which draws a background
  2741     // too) or if there is a border-radius (which makes the border draw
  2742     // further in).
  2743     return false;
  2746   return true;
  2749 nsDisplayItemGeometry* 
  2750 nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
  2752   return new nsDisplayBorderGeometry(this, aBuilder);
  2755 void
  2756 nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  2757                                            const nsDisplayItemGeometry* aGeometry,
  2758                                            nsRegion* aInvalidRegion)
  2760   const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
  2761   bool snap;
  2762   if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
  2763       !geometry->mContentRect.IsEqualInterior(GetContentRect())) {
  2764     // We can probably get away with only invalidating the difference
  2765     // between the border and padding rects, but the XUL ui at least
  2766     // is apparently painting a background with this?
  2767     aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
  2771 void
  2772 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
  2773                        nsRenderingContext* aCtx) {
  2774   nsPoint offset = ToReferenceFrame();
  2775   nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
  2776                               mVisibleRect,
  2777                               nsRect(offset, mFrame->GetSize()),
  2778                               mFrame->StyleContext(),
  2779                               mFrame->GetSkipSides());
  2782 nsRect
  2783 nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  2785   *aSnap = true;
  2786   return CalculateBounds(*mFrame->StyleBorder());
  2789 nsRect
  2790 nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder)
  2792   nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
  2793   if (aStyleBorder.IsBorderImageLoaded()) {
  2794     borderBounds.Inflate(aStyleBorder.GetImageOutset());
  2795     return borderBounds;
  2796   } else {
  2797     nsMargin border = aStyleBorder.GetComputedBorder();
  2798     nsRect result;
  2799     if (border.top > 0) {
  2800       result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(), border.top);
  2802     if (border.right > 0) {
  2803       result.UnionRect(result, nsRect(borderBounds.XMost() - border.right, borderBounds.Y(), border.right, borderBounds.Height()));
  2805     if (border.bottom > 0) {
  2806       result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.YMost() - border.bottom, borderBounds.Width(), border.bottom));
  2808     if (border.left > 0) {
  2809       result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.Y(), border.left, borderBounds.Height()));
  2812     return result;
  2816 // Given a region, compute a conservative approximation to it as a list
  2817 // of rectangles that aren't vertically adjacent (i.e., vertically
  2818 // adjacent or overlapping rectangles are combined).
  2819 // Right now this is only approximate, some vertically overlapping rectangles
  2820 // aren't guaranteed to be combined.
  2821 static void
  2822 ComputeDisjointRectangles(const nsRegion& aRegion,
  2823                           nsTArray<nsRect>* aRects) {
  2824   nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
  2825   nsRect accumulated;
  2826   nsRegionRectIterator iter(aRegion);
  2827   while (true) {
  2828     const nsRect* r = iter.Next();
  2829     if (r && !accumulated.IsEmpty() &&
  2830         accumulated.YMost() >= r->y - accumulationMargin) {
  2831       accumulated.UnionRect(accumulated, *r);
  2832       continue;
  2835     if (!accumulated.IsEmpty()) {
  2836       aRects->AppendElement(accumulated);
  2837       accumulated.SetEmpty();
  2840     if (!r)
  2841       break;
  2843     accumulated = *r;
  2847 void
  2848 nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
  2849                                nsRenderingContext* aCtx) {
  2850   nsPoint offset = ToReferenceFrame();
  2851   nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
  2852   nsPresContext* presContext = mFrame->PresContext();
  2853   nsAutoTArray<nsRect,10> rects;
  2854   ComputeDisjointRectangles(mVisibleRegion, &rects);
  2856   PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint");
  2857   for (uint32_t i = 0; i < rects.Length(); ++i) {
  2858     aCtx->PushState();
  2859     aCtx->IntersectClip(rects[i]);
  2860     nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
  2861                                         borderRect, rects[i], mOpacity);
  2862     aCtx->PopState();
  2866 nsRect
  2867 nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
  2868   *aSnap = false;
  2869   return mBounds;
  2872 nsRect
  2873 nsDisplayBoxShadowOuter::GetBoundsInternal() {
  2874   return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame, mFrame->GetSize()) +
  2875          ToReferenceFrame();
  2878 bool
  2879 nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  2880                                            nsRegion* aVisibleRegion,
  2881                                            const nsRect& aAllowVisibleRegionExpansion) {
  2882   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
  2883                                         aAllowVisibleRegionExpansion)) {
  2884     return false;
  2887   // Store the actual visible region
  2888   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
  2890   nsPoint origin = ToReferenceFrame();
  2891   nsRect visibleBounds = aVisibleRegion->GetBounds();
  2892   nsRect frameRect(origin, mFrame->GetSize());
  2893   if (!frameRect.Contains(visibleBounds))
  2894     return true;
  2896   // the visible region is entirely inside the border-rect, and box shadows
  2897   // never render within the border-rect (unless there's a border radius).
  2898   nscoord twipsRadii[8];
  2899   bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
  2900   if (!hasBorderRadii)
  2901     return false;
  2903   return !RoundedRectContainsRect(frameRect, twipsRadii, visibleBounds);
  2906 void
  2907 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  2908                                                    const nsDisplayItemGeometry* aGeometry,
  2909                                                    nsRegion* aInvalidRegion)
  2911   const nsDisplayItemGenericGeometry* geometry =
  2912     static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
  2913   bool snap;
  2914   if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
  2915       !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
  2916     nsRegion oldShadow, newShadow;
  2917     nscoord dontCare[8];
  2918     bool hasBorderRadius = mFrame->GetBorderRadii(dontCare);
  2919     if (hasBorderRadius) {
  2920       // If we have rounded corners then we need to invalidate the frame area
  2921       // too since we paint into it.
  2922       oldShadow = geometry->mBounds;
  2923       newShadow = GetBounds(aBuilder, &snap);
  2924     } else {
  2925       oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
  2926       newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
  2928     aInvalidRegion->Or(oldShadow, newShadow);
  2933 void
  2934 nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
  2935                                nsRenderingContext* aCtx) {
  2936   nsPoint offset = ToReferenceFrame();
  2937   nsRect borderRect = nsRect(offset, mFrame->GetSize());
  2938   nsPresContext* presContext = mFrame->PresContext();
  2939   nsAutoTArray<nsRect,10> rects;
  2940   ComputeDisjointRectangles(mVisibleRegion, &rects);
  2942   PROFILER_LABEL("nsDisplayBoxShadowInner", "Paint");
  2943   for (uint32_t i = 0; i < rects.Length(); ++i) {
  2944     aCtx->PushState();
  2945     aCtx->IntersectClip(rects[i]);
  2946     nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame,
  2947                                         borderRect, rects[i]);
  2948     aCtx->PopState();
  2952 bool
  2953 nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  2954                                            nsRegion* aVisibleRegion,
  2955                                            const nsRect& aAllowVisibleRegionExpansion) {
  2956   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
  2957                                         aAllowVisibleRegionExpansion)) {
  2958     return false;
  2961   // Store the actual visible region
  2962   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
  2963   return true;
  2966 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
  2967                                      nsIFrame* aFrame, nsDisplayList* aList)
  2968   : nsDisplayItem(aBuilder, aFrame)
  2969   , mOverrideZIndex(0)
  2971   mList.AppendToTop(aList);
  2972   UpdateBounds(aBuilder);
  2974   if (!aFrame || !aFrame->IsTransformed()) {
  2975     return;
  2978   // If the frame is a preserve-3d parent, then we will create transforms
  2979   // inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp).
  2980   // In this case we will always be outside of the transform, so share
  2981   // our parents reference frame.
  2982   if (aFrame->Preserves3DChildren()) {
  2983     mReferenceFrame = 
  2984       aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
  2985     mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
  2986     return;
  2989   // If we're a transformed frame, then we need to find out if we're inside
  2990   // the nsDisplayTransform or outside of it. Frames inside the transform
  2991   // need mReferenceFrame == mFrame, outside needs the next ancestor
  2992   // reference frame.
  2993   // If we're inside the transform, then the nsDisplayItem constructor
  2994   // will have done the right thing.
  2995   // If we're outside the transform, then we should have only one child
  2996   // (since nsDisplayTransform wraps all actual content), and that child
  2997   // will have the correct reference frame set (since nsDisplayTransform
  2998   // handles this explictly).
  2999   //
  3000   // Preserve-3d can cause us to have multiple nsDisplayTransform
  3001   // children.
  3002   nsDisplayItem *i = mList.GetBottom();
  3003   if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) && 
  3004       i->Frame() == mFrame) {
  3005     mReferenceFrame = i->ReferenceFrame();
  3006     mToReferenceFrame = i->ToReferenceFrame();
  3010 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
  3011                                      nsIFrame* aFrame, nsDisplayItem* aItem)
  3012   : nsDisplayItem(aBuilder, aFrame)
  3013   , mOverrideZIndex(0)
  3015   mList.AppendToTop(aItem);
  3016   UpdateBounds(aBuilder);
  3018   if (!aFrame || !aFrame->IsTransformed()) {
  3019     return;
  3022   if (aFrame->Preserves3DChildren()) {
  3023     mReferenceFrame = 
  3024       aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
  3025     mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
  3026     return;
  3029   // See the previous nsDisplayWrapList constructor
  3030   if (aItem->Frame() == aFrame) {
  3031     mReferenceFrame = aItem->ReferenceFrame();
  3032     mToReferenceFrame = aItem->ToReferenceFrame();
  3036 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
  3037                                      nsIFrame* aFrame, nsDisplayItem* aItem,
  3038                                      const nsIFrame* aReferenceFrame,
  3039                                      const nsPoint& aToReferenceFrame)
  3040   : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame)
  3041   , mOverrideZIndex(0)
  3043   mList.AppendToTop(aItem);
  3044   mBounds = mList.GetBounds(aBuilder);
  3047 nsDisplayWrapList::~nsDisplayWrapList() {
  3048   mList.DeleteAll();
  3051 void
  3052 nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  3053                            HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
  3054   mList.HitTest(aBuilder, aRect, aState, aOutFrames);
  3057 nsRect
  3058 nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
  3059   *aSnap = false;
  3060   return mBounds;
  3063 bool
  3064 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  3065                                      nsRegion* aVisibleRegion,
  3066                                      const nsRect& aAllowVisibleRegionExpansion) {
  3067   // Convert the passed in visible region to our appunits.
  3068   nsRegion visibleRegion;
  3069   // mVisibleRect has been clipped to GetClippedBounds
  3070   visibleRegion.And(*aVisibleRegion, mVisibleRect);
  3071   nsRegion originalVisibleRegion = visibleRegion;
  3073   bool retval =
  3074     mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
  3075                                       mVisibleRect,
  3076                                       aAllowVisibleRegionExpansion);
  3078   nsRegion removed;
  3079   // removed = originalVisibleRegion - visibleRegion
  3080   removed.Sub(originalVisibleRegion, visibleRegion);
  3081   // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
  3082   // SubtractFromVisibleRegion does)
  3083   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
  3085   return retval;
  3088 nsRegion
  3089 nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  3090                                    bool* aSnap) {
  3091   *aSnap = false;
  3092   nsRegion result;
  3093   if (mList.IsOpaque()) {
  3094     // Everything within GetBounds that's visible is opaque.
  3095     result = GetBounds(aBuilder, aSnap);
  3097   return result;
  3100 bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
  3101   // We could try to do something but let's conservatively just return false.
  3102   return false;
  3105 bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
  3106                                                          nsIFrame* aFrame) {
  3107   NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly");
  3108   // We could try to do something but let's conservatively just return true.
  3109   return true;
  3112 void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
  3113                               nsRenderingContext* aCtx) {
  3114   NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
  3117 /**
  3118  * Returns true if all descendant display items can be placed in the same
  3119  * ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
  3120  * and they all have the expected animated geometry root.
  3121  */
  3122 static LayerState
  3123 RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
  3124                               LayerManager* aManager,
  3125                               const ContainerLayerParameters& aParameters,
  3126                               const nsDisplayList& aList,
  3127                               nsIFrame* aExpectedAnimatedGeometryRootForChildren)
  3129   LayerState result = LAYER_INACTIVE;
  3130   for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
  3131     if (result == LAYER_INACTIVE &&
  3132         nsLayoutUtils::GetAnimatedGeometryRootFor(i, aBuilder) !=
  3133           aExpectedAnimatedGeometryRootForChildren) {
  3134       result = LAYER_ACTIVE;
  3137     LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
  3138     if ((state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE) &&
  3139         state > result) {
  3140       result = state;
  3142     if (state == LAYER_ACTIVE_EMPTY && state > result) {
  3143       result = LAYER_ACTIVE_FORCE;
  3145     if (state == LAYER_NONE) {
  3146       nsDisplayList* list = i->GetSameCoordinateSystemChildren();
  3147       if (list) {
  3148         LayerState childState =
  3149           RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list,
  3150               aExpectedAnimatedGeometryRootForChildren);
  3151         if (childState > result) {
  3152           result = childState;
  3157   return result;
  3160 nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
  3162   nsRect bounds;
  3163   for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
  3164     bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
  3166   return bounds;
  3169 static nsresult
  3170 WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
  3171                 nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
  3172   if (!aList->GetTop())
  3173     return NS_OK;
  3174   nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
  3175   if (!item)
  3176     return NS_ERROR_OUT_OF_MEMORY;
  3177   // aList was emptied
  3178   aList->AppendToTop(item);
  3179   return NS_OK;
  3182 static nsresult
  3183 WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
  3184                     nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
  3185   nsDisplayList newList;
  3186   nsDisplayItem* item;
  3187   while ((item = aList->RemoveBottom())) {
  3188     item = aWrapper->WrapItem(aBuilder, item);
  3189     if (!item)
  3190       return NS_ERROR_OUT_OF_MEMORY;
  3191     newList.AppendToTop(item);
  3193   // aList was emptied
  3194   aList->AppendToTop(&newList);
  3195   return NS_OK;
  3198 nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
  3199     nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut)
  3201   nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
  3202   NS_ENSURE_SUCCESS(rv, rv);
  3204   if (&aOut == &aIn)
  3205     return NS_OK;
  3206   aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
  3207   aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
  3208   aOut.Floats()->AppendToTop(aIn.Floats());
  3209   aOut.Content()->AppendToTop(aIn.Content());
  3210   aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
  3211   aOut.Outlines()->AppendToTop(aIn.Outlines());
  3212   return NS_OK;
  3215 nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder,
  3216     nsIFrame* aFrame, const nsDisplayListSet& aLists)
  3218   nsresult rv;
  3219   if (WrapBorderBackground()) {
  3220     // Our border-backgrounds are in-flow
  3221     rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
  3222     NS_ENSURE_SUCCESS(rv, rv);
  3224   // Our block border-backgrounds are in-flow
  3225   rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
  3226   NS_ENSURE_SUCCESS(rv, rv);
  3227   // The floats are not in flow
  3228   rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
  3229   NS_ENSURE_SUCCESS(rv, rv);
  3230   // Our child content is in flow
  3231   rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
  3232   NS_ENSURE_SUCCESS(rv, rv);
  3233   // The positioned descendants may not be in-flow
  3234   rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
  3235   NS_ENSURE_SUCCESS(rv, rv);
  3236   // The outlines may not be in-flow
  3237   return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
  3240 nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
  3241                                    nsIFrame* aFrame, nsDisplayList* aList)
  3242     : nsDisplayWrapList(aBuilder, aFrame, aList) {
  3243   MOZ_COUNT_CTOR(nsDisplayOpacity);
  3246 #ifdef NS_BUILD_REFCNT_LOGGING
  3247 nsDisplayOpacity::~nsDisplayOpacity() {
  3248   MOZ_COUNT_DTOR(nsDisplayOpacity);
  3250 #endif
  3252 nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  3253                                            bool* aSnap) {
  3254   *aSnap = false;
  3255   // We are never opaque, if our opacity was < 1 then we wouldn't have
  3256   // been created.
  3257   return nsRegion();
  3260 // nsDisplayOpacity uses layers for rendering
  3261 already_AddRefed<Layer>
  3262 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
  3263                              LayerManager* aManager,
  3264                              const ContainerLayerParameters& aContainerParameters) {
  3265   if (mFrame->StyleDisplay()->mOpacity == 0 && mFrame->GetContent() &&
  3266       !nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) {
  3267     return nullptr;
  3269   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
  3270     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  3271                            aContainerParameters, nullptr);
  3272   if (!container)
  3273     return nullptr;
  3275   container->SetOpacity(mFrame->StyleDisplay()->mOpacity);
  3276   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
  3277                                                            this, mFrame,
  3278                                                            eCSSProperty_opacity);
  3279   return container.forget();
  3282 /**
  3283  * This doesn't take into account layer scaling --- the layer may be
  3284  * rendered at a higher (or lower) resolution, affecting the retained layer
  3285  * size --- but this should be good enough.
  3286  */
  3287 static bool
  3288 IsItemTooSmallForActiveLayer(nsDisplayItem* aItem)
  3290   nsIntRect visibleDevPixels = aItem->GetVisibleRect().ToOutsidePixels(
  3291           aItem->Frame()->PresContext()->AppUnitsPerDevPixel());
  3292   static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16;
  3293   return visibleDevPixels.Size() <
  3294     nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS);
  3297 bool
  3298 nsDisplayOpacity::NeedsActiveLayer()
  3300   if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity) &&
  3301       !IsItemTooSmallForActiveLayer(this))
  3302     return true;
  3303   if (mFrame->GetContent()) {
  3304     if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
  3305                                                   eCSSProperty_opacity)) {
  3306       return true;
  3309   return false;
  3312 bool
  3313 nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
  3315   if (NeedsActiveLayer())
  3316     return false;
  3318   nsDisplayItem* child = mList.GetBottom();
  3319   // Only try folding our opacity down if we have a single
  3320   // child. We could potentially do this also if we had multiple
  3321   // children as long as they don't overlap.
  3322   if (!child || child->GetAbove()) {
  3323     return false;
  3326   return child->ApplyOpacity(aBuilder, mFrame->StyleDisplay()->mOpacity, mClip);
  3329 nsDisplayItem::LayerState
  3330 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
  3331                                 LayerManager* aManager,
  3332                                 const ContainerLayerParameters& aParameters) {
  3333   if (NeedsActiveLayer())
  3334     return LAYER_ACTIVE;
  3336   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList,
  3337     nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder));
  3340 bool
  3341 nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  3342                                     nsRegion* aVisibleRegion,
  3343                                     const nsRect& aAllowVisibleRegionExpansion) {
  3344   // Our children are translucent so we should not allow them to subtract
  3345   // area from aVisibleRegion. We do need to find out what is visible under
  3346   // our children in the temporary compositing buffer, because if our children
  3347   // paint our entire bounds opaquely then we don't need an alpha channel in
  3348   // the temporary compositing buffer.
  3349   nsRect bounds = GetClippedBounds(aBuilder);
  3350   nsRegion visibleUnderChildren;
  3351   visibleUnderChildren.And(*aVisibleRegion, bounds);
  3352   nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion);
  3353   return
  3354     nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
  3355                                          allowExpansion);
  3358 bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
  3359   if (aItem->GetType() != TYPE_OPACITY)
  3360     return false;
  3361   // items for the same content element should be merged into a single
  3362   // compositing group
  3363   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
  3364   if (aItem->Frame()->GetContent() != mFrame->GetContent())
  3365     return false;
  3366   if (aItem->GetClip() != GetClip())
  3367     return false;
  3368   MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
  3369   return true;
  3372 #ifdef MOZ_DUMP_PAINTING
  3373 void
  3374 nsDisplayOpacity::WriteDebugInfo(nsACString& aTo)
  3376   aTo += nsPrintfCString(" (opacity %f)", mFrame->StyleDisplay()->mOpacity);
  3378 #endif
  3380 nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder,
  3381                                              nsIFrame* aFrame, nsDisplayList* aList,
  3382                                              uint32_t aFlags)
  3383 : nsDisplayWrapList(aBuilder, aFrame, aList) {
  3384   MOZ_COUNT_CTOR(nsDisplayMixBlendMode);
  3387 #ifdef NS_BUILD_REFCNT_LOGGING
  3388 nsDisplayMixBlendMode::~nsDisplayMixBlendMode() {
  3389   MOZ_COUNT_DTOR(nsDisplayMixBlendMode);
  3391 #endif
  3393 nsRegion nsDisplayMixBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  3394                                                 bool* aSnap) {
  3395   *aSnap = false;
  3396   // We are never considered opaque
  3397   return nsRegion();
  3400 // nsDisplayMixBlendMode uses layers for rendering
  3401 already_AddRefed<Layer>
  3402 nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
  3403                                   LayerManager* aManager,
  3404                                   const ContainerLayerParameters& aContainerParameters) {
  3405   ContainerLayerParameters newContainerParameters = aContainerParameters;
  3406   newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
  3408   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
  3409   BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  3410                          newContainerParameters, nullptr);
  3411   if (!container) {
  3412     return nullptr;
  3415   container->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode));
  3417   return container.forget();
  3420 bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  3421                                               nsRegion* aVisibleRegion,
  3422                                               const nsRect& aAllowVisibleRegionExpansion) {
  3423   // Our children are need their backdrop so we should not allow them to subtract
  3424   // area from aVisibleRegion. We do need to find out what is visible under
  3425   // our children in the temporary compositing buffer, because if our children
  3426   // paint our entire bounds opaquely then we don't need an alpha channel in
  3427   // the temporary compositing buffer.
  3428   nsRect bounds = GetClippedBounds(aBuilder);
  3429   nsRegion visibleUnderChildren;
  3430   visibleUnderChildren.And(*aVisibleRegion, bounds);
  3431   nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion);
  3432   return
  3433   nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
  3434                                        allowExpansion);
  3437 bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
  3438   if (aItem->GetType() != TYPE_MIX_BLEND_MODE)
  3439     return false;
  3440   // items for the same content element should be merged into a single
  3441   // compositing group
  3442   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
  3443   if (aItem->Frame()->GetContent() != mFrame->GetContent())
  3444     return false;
  3445   if (aItem->GetClip() != GetClip())
  3446     return false;
  3447   MergeFromTrackingMergedFrames(static_cast<nsDisplayMixBlendMode*>(aItem));
  3448   return true;
  3451 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
  3452                                                  nsIFrame* aFrame, nsDisplayList* aList,
  3453                                                  uint32_t aFlags)
  3454     : nsDisplayWrapList(aBuilder, aFrame, aList) {
  3455   MOZ_COUNT_CTOR(nsDisplayBlendContainer);
  3458 #ifdef NS_BUILD_REFCNT_LOGGING
  3459 nsDisplayBlendContainer::~nsDisplayBlendContainer() {
  3460   MOZ_COUNT_DTOR(nsDisplayBlendContainer);
  3462 #endif
  3464 // nsDisplayBlendContainer uses layers for rendering
  3465 already_AddRefed<Layer>
  3466 nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder,
  3467                                     LayerManager* aManager,
  3468                                     const ContainerLayerParameters& aContainerParameters) {
  3469   // turn off anti-aliasing in the parent stacking context because it changes
  3470   // how the group is initialized.
  3471   ContainerLayerParameters newContainerParameters = aContainerParameters;
  3472   newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
  3474   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
  3475   BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  3476                          newContainerParameters, nullptr);
  3477   if (!container) {
  3478     return nullptr;
  3481   container->SetForceIsolatedGroup(true);
  3482   return container.forget();
  3485 bool nsDisplayBlendContainer::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
  3486   if (aItem->GetType() != TYPE_BLEND_CONTAINER)
  3487     return false;
  3488   // items for the same content element should be merged into a single
  3489   // compositing group
  3490   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
  3491   if (aItem->Frame()->GetContent() != mFrame->GetContent())
  3492     return false;
  3493   if (aItem->GetClip() != GetClip())
  3494     return false;
  3495   MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
  3496   return true;
  3499 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
  3500                                      nsIFrame* aFrame, nsDisplayList* aList,
  3501                                      uint32_t aFlags, ViewID aScrollTarget)
  3502     : nsDisplayWrapList(aBuilder, aFrame, aList)
  3503     , mFlags(aFlags)
  3504     , mScrollTarget(aScrollTarget) {
  3505   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
  3508 #ifdef NS_BUILD_REFCNT_LOGGING
  3509 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
  3510   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
  3512 #endif
  3514 // nsDisplayOpacity uses layers for rendering
  3515 already_AddRefed<Layer>
  3516 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
  3517                               LayerManager* aManager,
  3518                               const ContainerLayerParameters& aContainerParameters) {
  3519   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
  3520     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  3521                            aContainerParameters, nullptr);
  3522   if (mFlags & VERTICAL_SCROLLBAR) {
  3523     layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL);
  3525   if (mFlags & HORIZONTAL_SCROLLBAR) {
  3526     layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL);
  3529   if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
  3530     mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
  3532   return layer.forget();
  3535 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
  3536                                            nsIFrame* aFrame, nsDisplayList* aList,
  3537                                            uint32_t aFlags)
  3538     : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
  3539     , mScrollParentId(aBuilder->GetCurrentScrollParentId())
  3541   MOZ_COUNT_CTOR(nsDisplaySubDocument);
  3544 #ifdef NS_BUILD_REFCNT_LOGGING
  3545 nsDisplaySubDocument::~nsDisplaySubDocument() {
  3546   MOZ_COUNT_DTOR(nsDisplaySubDocument);
  3548 #endif
  3550 already_AddRefed<Layer>
  3551 nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder,
  3552                                  LayerManager* aManager,
  3553                                  const ContainerLayerParameters& aContainerParameters) {
  3554   nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(
  3555     aBuilder, aManager, aContainerParameters);
  3557   if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) {
  3558     return layer.forget();
  3561   NS_ASSERTION(layer->AsContainerLayer(), "nsDisplayOwnLayer should have made a ContainerLayer");
  3562   if (ContainerLayer* container = layer->AsContainerLayer()) {
  3563     nsPresContext* presContext = mFrame->PresContext();
  3564     nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
  3565     bool isRootContentDocument = presContext->IsRootContentDocument();
  3567     bool usingDisplayport = false;
  3568     bool usingCriticalDisplayport = false;
  3569     nsRect displayport, criticalDisplayport;
  3570     ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
  3571     if (rootScrollFrame) {
  3572       nsIContent* content = rootScrollFrame->GetContent();
  3573       if (content) {
  3574         usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
  3575         usingCriticalDisplayport =
  3576           nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport);
  3578         if (isRootContentDocument) {
  3579           scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
  3580         } else {
  3581           nsLayoutUtils::FindIDFor(content, &scrollId);
  3586     nsRect viewport = mFrame->GetRect() -
  3587                       mFrame->GetPosition() +
  3588                       mFrame->GetOffsetToCrossDoc(ReferenceFrame());
  3590     container->SetScrollHandoffParentId(mScrollParentId);
  3591     RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
  3592                        container, mList.GetVisibleRect(), viewport,
  3593                        (usingDisplayport ? &displayport : nullptr),
  3594                        (usingCriticalDisplayport ? &criticalDisplayport : nullptr),
  3595                        scrollId, isRootContentDocument, aContainerParameters);
  3598   return layer.forget();
  3601 nsRect
  3602 nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  3604   bool usingDisplayPort =
  3605     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
  3607   if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
  3608     *aSnap = false;
  3609     return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame);
  3612   return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap);
  3615 bool
  3616 nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  3617                                         nsRegion* aVisibleRegion,
  3618                                         const nsRect& aAllowVisibleRegionExpansion)
  3620   nsRect displayport;
  3621   bool usingDisplayPort =
  3622     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext(), &displayport);
  3624   if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
  3625     return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
  3626                                                 aAllowVisibleRegionExpansion);
  3629   nsRegion childVisibleRegion;
  3630   // The visible region for the children may be much bigger than the hole we
  3631   // are viewing the children from, so that the compositor process has enough
  3632   // content to asynchronously pan while content is being refreshed.
  3633   childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
  3635   nsRect boundedRect =
  3636     childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
  3637   nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
  3638   bool visible = mList.ComputeVisibilityForSublist(
  3639     aBuilder, &childVisibleRegion, boundedRect, allowExpansion,
  3640     usingDisplayPort ? mFrame : nullptr);
  3641   // We don't allow this computation to influence aVisibleRegion, on the
  3642   // assumption that the layer can be asynchronously scrolled so we'll
  3643   // definitely need all the content under it.
  3645   return visible;
  3648 bool
  3649 nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
  3651   bool usingDisplayPort =
  3652     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
  3654   if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
  3655     return true;
  3658   return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder);
  3661 nsRegion
  3662 nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap)
  3664   bool usingDisplayPort =
  3665     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
  3667   if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
  3668     *aSnap = false;
  3669     return nsRegion();
  3672   return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder, aSnap);
  3675 nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder,
  3676                                          nsIFrame* aFrame, nsDisplayList* aList,
  3677                                          uint32_t aFlags)
  3678     : nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags) {
  3679   MOZ_COUNT_CTOR(nsDisplayResolution);
  3682 #ifdef NS_BUILD_REFCNT_LOGGING
  3683 nsDisplayResolution::~nsDisplayResolution() {
  3684   MOZ_COUNT_DTOR(nsDisplayResolution);
  3686 #endif
  3688 already_AddRefed<Layer>
  3689 nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
  3690                                 LayerManager* aManager,
  3691                                 const ContainerLayerParameters& aContainerParameters) {
  3692   nsIPresShell* presShell = mFrame->PresContext()->PresShell();
  3693   ContainerLayerParameters containerParameters(
  3694     presShell->GetXResolution(), presShell->GetYResolution(), nsIntPoint(),
  3695     aContainerParameters);
  3697   nsRefPtr<Layer> layer = nsDisplaySubDocument::BuildLayer(
  3698     aBuilder, aManager, containerParameters);
  3699   layer->SetPostScale(1.0f / presShell->GetXResolution(),
  3700                       1.0f / presShell->GetYResolution());
  3701   return layer.forget();
  3704 nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
  3705                                                  nsIFrame* aFrame,
  3706                                                  nsDisplayList* aList)
  3707   : nsDisplayOwnLayer(aBuilder, aFrame, aList)
  3709   MOZ_COUNT_CTOR(nsDisplayStickyPosition);
  3712 #ifdef NS_BUILD_REFCNT_LOGGING
  3713 nsDisplayStickyPosition::~nsDisplayStickyPosition() {
  3714   MOZ_COUNT_DTOR(nsDisplayStickyPosition);
  3716 #endif
  3718 already_AddRefed<Layer>
  3719 nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
  3720                                     LayerManager* aManager,
  3721                                     const ContainerLayerParameters& aContainerParameters) {
  3722   nsRefPtr<Layer> layer =
  3723     nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
  3725   StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::
  3726     GetStickyScrollContainerForFrame(mFrame);
  3727   if (!stickyScrollContainer) {
  3728     return layer.forget();
  3731   nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
  3732   nsPresContext* presContext = scrollFrame->PresContext();
  3734   // Sticky position frames whose scroll frame is the root scroll frame are
  3735   // reflowed into the scroll-port size if one has been set.
  3736   nsSize scrollFrameSize = scrollFrame->GetSize();
  3737   if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() &&
  3738       presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
  3739     scrollFrameSize = presContext->PresShell()->
  3740       GetScrollPositionClampingScrollPortSize();
  3743   nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame,
  3744     nsRect(scrollFrame->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize),
  3745     mFrame, presContext, aContainerParameters);
  3747   ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
  3748     stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
  3750   float factor = presContext->AppUnitsPerDevPixel();
  3751   nsRect outer;
  3752   nsRect inner;
  3753   stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
  3754   LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) *
  3755                           aContainerParameters.mXScale,
  3756                         NSAppUnitsToFloatPixels(outer.y, factor) *
  3757                           aContainerParameters.mYScale,
  3758                         NSAppUnitsToFloatPixels(outer.width, factor) *
  3759                           aContainerParameters.mXScale,
  3760                         NSAppUnitsToFloatPixels(outer.height, factor) *
  3761                           aContainerParameters.mYScale);
  3762   LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) *
  3763                           aContainerParameters.mXScale,
  3764                         NSAppUnitsToFloatPixels(inner.y, factor) *
  3765                           aContainerParameters.mYScale,
  3766                         NSAppUnitsToFloatPixels(inner.width, factor) *
  3767                           aContainerParameters.mXScale,
  3768                         NSAppUnitsToFloatPixels(inner.height, factor) *
  3769                           aContainerParameters.mYScale);
  3770   layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
  3772   return layer.forget();
  3775 bool nsDisplayStickyPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
  3776   if (aItem->GetType() != TYPE_STICKY_POSITION)
  3777     return false;
  3778   // Items with the same fixed position frame can be merged.
  3779   nsDisplayStickyPosition* other = static_cast<nsDisplayStickyPosition*>(aItem);
  3780   if (other->mFrame != mFrame)
  3781     return false;
  3782   if (aItem->GetClip() != GetClip())
  3783     return false;
  3784   MergeFromTrackingMergedFrames(other);
  3785   return true;
  3788 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
  3789                                            nsDisplayList* aList,
  3790                                            nsIFrame* aForFrame,
  3791                                            nsIFrame* aScrolledFrame,
  3792                                            nsIFrame* aScrollFrame)
  3793   : nsDisplayWrapList(aBuilder, aForFrame, aList)
  3794   , mScrollFrame(aScrollFrame)
  3795   , mScrolledFrame(aScrolledFrame)
  3796   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
  3798 #ifdef NS_BUILD_REFCNT_LOGGING
  3799   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
  3800 #endif
  3802   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
  3803                "Need a child frame with content");
  3806 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
  3807                                            nsDisplayItem* aItem,
  3808                                            nsIFrame* aForFrame,
  3809                                            nsIFrame* aScrolledFrame,
  3810                                            nsIFrame* aScrollFrame)
  3811   : nsDisplayWrapList(aBuilder, aForFrame, aItem)
  3812   , mScrollFrame(aScrollFrame)
  3813   , mScrolledFrame(aScrolledFrame)
  3814   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
  3816 #ifdef NS_BUILD_REFCNT_LOGGING
  3817   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
  3818 #endif
  3820   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
  3821                "Need a child frame with content");
  3824 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
  3825                                            nsIFrame* aForFrame,
  3826                                            nsIFrame* aScrolledFrame,
  3827                                            nsIFrame* aScrollFrame)
  3828   : nsDisplayWrapList(aBuilder, aForFrame)
  3829   , mScrollFrame(aScrollFrame)
  3830   , mScrolledFrame(aScrolledFrame)
  3831   , mScrollParentId(aBuilder->GetCurrentScrollParentId())
  3833 #ifdef NS_BUILD_REFCNT_LOGGING
  3834   MOZ_COUNT_CTOR(nsDisplayScrollLayer);
  3835 #endif
  3837   NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(),
  3838                "Need a child frame with content");
  3841 #ifdef NS_BUILD_REFCNT_LOGGING
  3842 nsDisplayScrollLayer::~nsDisplayScrollLayer()
  3844   MOZ_COUNT_DTOR(nsDisplayScrollLayer);
  3846 #endif
  3848 nsRect
  3849 nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  3851   nsIScrollableFrame* sf = do_QueryFrame(mScrollFrame);
  3852   if (sf) {
  3853     *aSnap = false;
  3854     return sf->GetScrollPortRect() + aBuilder->ToReferenceFrame(mScrollFrame);
  3856   return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
  3859 already_AddRefed<Layer>
  3860 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
  3861                                  LayerManager* aManager,
  3862                                  const ContainerLayerParameters& aContainerParameters) {
  3863   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
  3864     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  3865                            aContainerParameters, nullptr);
  3867   // Get the already set unique ID for scrolling this content remotely.
  3868   // Or, if not set, generate a new ID.
  3869   nsIContent* content = mScrolledFrame->GetContent();
  3870   ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
  3872   nsRect viewport = mScrollFrame->GetRect() -
  3873                     mScrollFrame->GetPosition() +
  3874                     mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
  3876   bool usingDisplayport = false;
  3877   bool usingCriticalDisplayport = false;
  3878   nsRect displayport, criticalDisplayport;
  3879   if (content) {
  3880     usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
  3881     usingCriticalDisplayport =
  3882       nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport);
  3884   layer->SetScrollHandoffParentId(mScrollParentId);
  3885   RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer,
  3886                      mList.GetVisibleRect(), viewport,
  3887                      (usingDisplayport ? &displayport : nullptr),
  3888                      (usingCriticalDisplayport ? &criticalDisplayport : nullptr),
  3889                      scrollId, false, aContainerParameters);
  3891   return layer.forget();
  3894 bool
  3895 nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
  3897   if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
  3898     return true;
  3901   return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder);
  3904 bool
  3905 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  3906                                         nsRegion* aVisibleRegion,
  3907                                         const nsRect& aAllowVisibleRegionExpansion)
  3909   nsRect displayport;
  3910   bool usingDisplayPort =
  3911     nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport);
  3912   nsRegion childVisibleRegion;
  3913   if (usingDisplayPort) {
  3914     // The visible region for the children may be much bigger than the hole we
  3915     // are viewing the children from, so that the compositor process has enough
  3916     // content to asynchronously pan while content is being refreshed.
  3917     childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
  3918   } else {
  3919     bool snap;
  3920     childVisibleRegion = GetBounds(aBuilder, &snap);
  3923   nsRect boundedRect =
  3924     childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
  3925   nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
  3926   bool visible = mList.ComputeVisibilityForSublist(
  3927     aBuilder, &childVisibleRegion, boundedRect, allowExpansion,
  3928     usingDisplayPort ? mScrollFrame : nullptr);
  3929   // We don't allow this computation to influence aVisibleRegion, on the
  3930   // assumption that the layer can be asynchronously scrolled so we'll
  3931   // definitely need all the content under it.
  3933   return visible;
  3936 LayerState
  3937 nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
  3938                                     LayerManager* aManager,
  3939                                     const ContainerLayerParameters& aParameters)
  3941   // Force this as a layer so we can scroll asynchronously.
  3942   // This causes incorrect rendering for rounded clips!
  3943   return LAYER_ACTIVE_FORCE;
  3946 // Check if we are going to clip an abs pos item that we don't contain.
  3947 // Root scroll frames clip all their descendants, so we don't need to worry
  3948 // about them.
  3949 bool
  3950 WouldCauseIncorrectClippingOnAbsPosItem(nsDisplayListBuilder* aBuilder,
  3951                                         nsDisplayScrollLayer* aItem)
  3953   nsIFrame* scrollFrame = aItem->GetScrollFrame();
  3954   nsIPresShell* presShell = scrollFrame->PresContext()->PresShell();
  3955   if (scrollFrame == presShell->GetRootScrollFrame()) {
  3956     return false;
  3958   nsIFrame* scrolledFrame = aItem->GetScrolledFrame();
  3959   nsIFrame* frame = aItem->Frame();
  3960   if (frame == scrolledFrame || !frame->IsAbsolutelyPositioned() ||
  3961       nsLayoutUtils::IsAncestorFrameCrossDoc(scrollFrame, frame, presShell->GetRootFrame())) {
  3962     return false;
  3964   if (!aItem->GetClip().IsRectAffectedByClip(aItem->GetChildren()->GetBounds(aBuilder))) {
  3965     return false;
  3967   return true;
  3970 bool
  3971 nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder,
  3972                                nsDisplayItem* aItem)
  3974   if (aItem->GetType() != TYPE_SCROLL_LAYER) {
  3975     return false;
  3977   nsDisplayScrollLayer* other = static_cast<nsDisplayScrollLayer*>(aItem);
  3978   if (other->mScrolledFrame != this->mScrolledFrame) {
  3979     return false;
  3981   if (aItem->GetClip() != GetClip()) {
  3982     return false;
  3985   if (WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, this) ||
  3986       WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, other)) {
  3987     return false;
  3990   NS_ASSERTION(other->mReferenceFrame == mReferenceFrame,
  3991                "Must have the same reference frame!");
  3993   FrameProperties props = mScrolledFrame->Properties();
  3994   props.Set(nsIFrame::ScrollLayerCount(),
  3995     reinterpret_cast<void*>(GetScrollLayerCount() - 1));
  3997   // Swap frames with the other item before doing MergeFrom.
  3998   // XXX - This ensures that the frame associated with a scroll layer after
  3999   // merging is the first, rather than the last. This tends to change less,
  4000   // ensuring we're more likely to retain the associated gfx layer.
  4001   // See Bug 729534 and Bug 731641.
  4002   nsIFrame* tmp = mFrame;
  4003   mFrame = other->mFrame;
  4004   other->mFrame = tmp;
  4005   MergeFromTrackingMergedFrames(other);
  4006   return true;
  4009 void
  4010 PropagateClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip,
  4011               nsDisplayList* aList)
  4013   for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
  4014     DisplayItemClip clip(i->GetClip());
  4015     clip.IntersectWith(aClip);
  4016     i->SetClip(aBuilder, clip);
  4017     nsDisplayList* list = i->GetSameCoordinateSystemChildren();
  4018     if (list) {
  4019       PropagateClip(aBuilder, aClip, list);
  4024 bool
  4025 nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
  4027   bool badAbsPosClip = WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, this);
  4028   if (GetScrollLayerCount() > 1 || badAbsPosClip) {
  4029     // Propagate our clip to our children. The clip for the scroll frame is
  4030     // on this item, but not our child items so that they can draw non-visible
  4031     // parts of the display port. But if we are flattening we failed and can't
  4032     // draw the extra content, so it needs to be clipped.
  4033     // But don't induce our clip on abs pos frames that we shouldn't be clipping.
  4034     if (!badAbsPosClip) {
  4035       PropagateClip(aBuilder, GetClip(), &mList);
  4037     return true;
  4039   if (mFrame != mScrolledFrame) {
  4040     mMergedFrames.AppendElement(mFrame);
  4041     mFrame = mScrolledFrame;
  4043   return false;
  4046 intptr_t
  4047 nsDisplayScrollLayer::GetScrollLayerCount()
  4049   FrameProperties props = mScrolledFrame->Properties();
  4050 #ifdef DEBUG
  4051   bool hasCount = false;
  4052   intptr_t result = reinterpret_cast<intptr_t>(
  4053     props.Get(nsIFrame::ScrollLayerCount(), &hasCount));
  4054   // If this aborts, then the property was either not added before scroll
  4055   // layers were created or the property was deleted to early. If the latter,
  4056   // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so
  4057   // that it is processed last.
  4058   NS_ABORT_IF_FALSE(hasCount, "nsDisplayScrollLayer should always be defined");
  4059   return result;
  4060 #else
  4061   return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount()));
  4062 #endif
  4065 #ifdef MOZ_DUMP_PAINTING
  4066 void
  4067 nsDisplayScrollLayer::WriteDebugInfo(nsACString& aTo)
  4069   aTo += nsPrintfCString(" (scrollframe %p scrolledframe %p)",
  4070                          mScrollFrame, mScrolledFrame);
  4072 #endif
  4074 nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
  4075   nsDisplayListBuilder* aBuilder,
  4076   nsIFrame* aScrolledFrame,
  4077   nsIFrame* aScrollFrame)
  4078   : nsDisplayScrollLayer(aBuilder, aScrollFrame, aScrolledFrame, aScrollFrame)
  4080 #ifdef NS_BUILD_REFCNT_LOGGING
  4081   MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
  4082 #endif
  4085 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
  4087   FrameProperties props = mScrolledFrame->Properties();
  4088   props.Remove(nsIFrame::ScrollLayerCount());
  4089   MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
  4092 nsRect
  4093 nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  4095   return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
  4098 LayerState
  4099 nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
  4100                                         LayerManager* aManager,
  4101                                         const ContainerLayerParameters& aParameters)
  4103   return LAYER_ACTIVE_EMPTY;
  4106 bool
  4107 nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder* aBuilder,
  4108                                    nsDisplayItem* aItem)
  4110   return false;
  4113 bool
  4114 nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
  4116   // Layer metadata for a particular scroll frame needs to be unique. Only
  4117   // one nsDisplayScrollLayer (with rendered content) or one
  4118   // nsDisplayScrollInfoLayer (with only the metadata) should survive the
  4119   // visibility computation.
  4120   return GetScrollLayerCount() == 1;
  4123 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
  4124                              nsIFrame* aFrame, nsDisplayList* aList,
  4125                              int32_t aAPD, int32_t aParentAPD,
  4126                              uint32_t aFlags)
  4127     : nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags)
  4128     , mAPD(aAPD), mParentAPD(aParentAPD) {
  4129   MOZ_COUNT_CTOR(nsDisplayZoom);
  4132 #ifdef NS_BUILD_REFCNT_LOGGING
  4133 nsDisplayZoom::~nsDisplayZoom() {
  4134   MOZ_COUNT_DTOR(nsDisplayZoom);
  4136 #endif
  4138 nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
  4140   nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap);
  4141   *aSnap = false;
  4142   return bounds.ConvertAppUnitsRoundOut(mAPD, mParentAPD);
  4145 void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
  4146                             const nsRect& aRect,
  4147                             HitTestState *aState,
  4148                             nsTArray<nsIFrame*> *aOutFrames)
  4150   nsRect rect;
  4151   // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
  4152   // rect as well instead of possibly rounding the width or height to zero.
  4153   if (aRect.width == 1 && aRect.height == 1) {
  4154     rect.MoveTo(aRect.TopLeft().ConvertAppUnits(mParentAPD, mAPD));
  4155     rect.width = rect.height = 1;
  4156   } else {
  4157     rect = aRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
  4159   mList.HitTest(aBuilder, rect, aState, aOutFrames);
  4162 void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder,
  4163                           nsRenderingContext* aCtx)
  4165   mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT);
  4168 bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
  4169                                       nsRegion *aVisibleRegion,
  4170                                       const nsRect& aAllowVisibleRegionExpansion)
  4172   // Convert the passed in visible region to our appunits.
  4173   nsRegion visibleRegion;
  4174   // mVisibleRect has been clipped to GetClippedBounds
  4175   visibleRegion.And(*aVisibleRegion, mVisibleRect);
  4176   visibleRegion = visibleRegion.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
  4177   nsRegion originalVisibleRegion = visibleRegion;
  4179   nsRect transformedVisibleRect =
  4180     mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
  4181   nsRect allowExpansion =
  4182     aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD);
  4183   bool retval;
  4184   // If we are to generate a scrollable layer we call
  4185   // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
  4186   // for ComputeVisibility, it does all it's calculations in the child APD.
  4187   bool usingDisplayPort =
  4188     nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext());
  4189   if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
  4190     retval =
  4191       mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
  4192                                         transformedVisibleRect,
  4193                                         allowExpansion);
  4194   } else {
  4195     retval =
  4196       nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion,
  4197                                               allowExpansion);
  4200   nsRegion removed;
  4201   // removed = originalVisibleRegion - visibleRegion
  4202   removed.Sub(originalVisibleRegion, visibleRegion);
  4203   // Convert removed region to parent appunits.
  4204   removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD);
  4205   // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
  4206   // SubtractFromVisibleRegion does)
  4207   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
  4209   return retval;
  4212 ///////////////////////////////////////////////////
  4213 // nsDisplayTransform Implementation
  4214 //
  4216 // Write #define UNIFIED_CONTINUATIONS here to have the transform property try
  4217 // to transform content with continuations as one unified block instead of
  4218 // several smaller ones.  This is currently disabled because it doesn't work
  4219 // correctly, since when the frames are initially being reflowed, their
  4220 // continuations all compute their bounding rects independently of each other
  4221 // and consequently get the wrong value.  Write #define DEBUG_HIT here to have
  4222 // the nsDisplayTransform class dump out a bunch of information about hit
  4223 // detection.
  4224 #undef  UNIFIED_CONTINUATIONS
  4225 #undef  DEBUG_HIT
  4227 /* Returns the bounds of a frame as defined for transforms.  If
  4228  * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
  4229  * rectangle, translated to the origin. Otherwise, returns the smallest
  4230  * rectangle containing a frame and all of its continuations.  For example, if
  4231  * there is a <span> element with several continuations split over several
  4232  * lines, this function will return the rectangle containing all of those
  4233  * continuations.  This rectangle is relative to the origin of the frame's local
  4234  * coordinate space.
  4235  */
  4236 #ifndef UNIFIED_CONTINUATIONS
  4238 nsRect
  4239 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
  4241   NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
  4243   if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  4244     // TODO: SVG needs to define what percentage translations resolve against.
  4245     return nsRect();
  4248   return nsRect(nsPoint(0, 0), aFrame->GetSize());
  4251 #else
  4253 nsRect
  4254 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
  4256   NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
  4258   nsRect result;
  4260   if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  4261     // TODO: SVG needs to define what percentage translations resolve against.
  4262     return result;
  4265   /* Iterate through the continuation list, unioning together all the
  4266    * bounding rects.
  4267    */
  4268   for (const nsIFrame *currFrame = aFrame->FirstContinuation();
  4269        currFrame != nullptr;
  4270        currFrame = currFrame->GetNextContinuation())
  4272       /* Get the frame rect in local coordinates, then translate back to the
  4273        * original coordinates.
  4274        */
  4275       result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame),
  4276                                       currFrame->GetSize()));
  4279   return result;
  4282 #endif
  4284 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
  4285                                        nsDisplayList *aList, ComputeTransformFunction aTransformGetter, 
  4286                                        uint32_t aIndex) 
  4287   : nsDisplayItem(aBuilder, aFrame)
  4288   , mStoredList(aBuilder, aFrame, aList)
  4289   , mTransformGetter(aTransformGetter)
  4290   , mIndex(aIndex)
  4292   MOZ_COUNT_CTOR(nsDisplayTransform);
  4293   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
  4294   NS_ABORT_IF_FALSE(!aFrame->IsTransformed(), "Can't specify a transform getter for a transformed frame!");
  4295   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
  4298 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
  4299                                        nsDisplayList *aList, uint32_t aIndex) 
  4300   : nsDisplayItem(aBuilder, aFrame)
  4301   , mStoredList(aBuilder, aFrame, aList)
  4302   , mTransformGetter(nullptr)
  4303   , mIndex(aIndex)
  4305   MOZ_COUNT_CTOR(nsDisplayTransform);
  4306   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
  4307   mReferenceFrame = 
  4308     aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
  4309   mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
  4310   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
  4313 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
  4314                                        nsDisplayItem *aItem, uint32_t aIndex)
  4315   : nsDisplayItem(aBuilder, aFrame)
  4316   , mStoredList(aBuilder, aFrame, aItem)
  4317   , mTransformGetter(nullptr)
  4318   , mIndex(aIndex)
  4320   MOZ_COUNT_CTOR(nsDisplayTransform);
  4321   NS_ABORT_IF_FALSE(aFrame, "Must have a frame!");
  4322   mReferenceFrame =
  4323     aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame));
  4324   mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
  4325   mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
  4328 /* Returns the delta specified by the -moz-transform-origin property.
  4329  * This is a positive delta, meaning that it indicates the direction to move
  4330  * to get from (0, 0) of the frame to the transform origin.  This function is
  4331  * called off the main thread.
  4332  */
  4333 /* static */ gfxPoint3D
  4334 nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
  4335                                               float aAppUnitsPerPixel,
  4336                                               const nsRect* aBoundsOverride)
  4338   NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
  4339   NS_PRECONDITION(aFrame->IsTransformed() || aFrame->StyleDisplay()->BackfaceIsHidden(),
  4340                   "Shouldn't get a delta for an untransformed frame!");
  4342   if (!aFrame->IsTransformed()) {
  4343     return gfxPoint3D();
  4346   /* For both of the coordinates, if the value of -moz-transform is a
  4347    * percentage, it's relative to the size of the frame.  Otherwise, if it's
  4348    * a distance, it's already computed for us!
  4349    */
  4350   const nsStyleDisplay* display = aFrame->StyleDisplay();
  4351   nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
  4352                          nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
  4354   /* Allows us to access named variables by index. */
  4355   float coords[3];
  4356   const nscoord* dimensions[2] =
  4357     {&boundingRect.width, &boundingRect.height};
  4359   for (uint8_t index = 0; index < 2; ++index) {
  4360     /* If the -moz-transform-origin specifies a percentage, take the percentage
  4361      * of the size of the box.
  4362      */
  4363     const nsStyleCoord &coord = display->mTransformOrigin[index];
  4364     if (coord.GetUnit() == eStyleUnit_Calc) {
  4365       const nsStyleCoord::Calc *calc = coord.GetCalcValue();
  4366       coords[index] =
  4367         NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
  4368           calc->mPercent +
  4369         NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
  4370     } else if (coord.GetUnit() == eStyleUnit_Percent) {
  4371       coords[index] =
  4372         NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
  4373         coord.GetPercentValue();
  4374     } else {
  4375       NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
  4376       coords[index] =
  4377         NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
  4379     if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
  4380         coord.GetUnit() != eStyleUnit_Percent) {
  4381       // <length> values represent offsets from the origin of the SVG element's
  4382       // user space, not the top left of its bounds, so we must adjust for that:
  4383       nscoord offset =
  4384         (index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
  4385       coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
  4389   coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
  4390                                       aAppUnitsPerPixel);
  4391   /* Adjust based on the origin of the rectangle. */
  4392   coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
  4393   coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
  4395   return gfxPoint3D(coords[0], coords[1], coords[2]);
  4398 /* Returns the delta specified by the -moz-perspective-origin property.
  4399  * This is a positive delta, meaning that it indicates the direction to move
  4400  * to get from (0, 0) of the frame to the perspective origin. This function is
  4401  * called off the main thread.
  4402  */
  4403 /* static */ gfxPoint3D
  4404 nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
  4405                                                 float aAppUnitsPerPixel)
  4407   NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
  4408   NS_PRECONDITION(aFrame->IsTransformed() || aFrame->StyleDisplay()->BackfaceIsHidden(),
  4409                   "Shouldn't get a delta for an untransformed frame!");
  4411   if (!aFrame->IsTransformed()) {
  4412     return gfxPoint3D();
  4415   /* For both of the coordinates, if the value of -moz-perspective-origin is a
  4416    * percentage, it's relative to the size of the frame.  Otherwise, if it's
  4417    * a distance, it's already computed for us!
  4418    */
  4420   //TODO: Should this be using our bounds or the parent's bounds?
  4421   // How do we handle aBoundsOverride in the latter case?
  4422   nsIFrame* parent = aFrame->GetParentStyleContextFrame();
  4423   if (!parent) {
  4424     return gfxPoint3D();
  4426   const nsStyleDisplay* display = parent->StyleDisplay();
  4427   nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent);
  4429   /* Allows us to access named variables by index. */
  4430   gfxPoint3D result;
  4431   result.z = 0.0f;
  4432   gfxFloat* coords[2] = {&result.x, &result.y};
  4433   const nscoord* dimensions[2] =
  4434     {&boundingRect.width, &boundingRect.height};
  4436   for (uint8_t index = 0; index < 2; ++index) {
  4437     /* If the -moz-transform-origin specifies a percentage, take the percentage
  4438      * of the size of the box.
  4439      */
  4440     const nsStyleCoord &coord = display->mPerspectiveOrigin[index];
  4441     if (coord.GetUnit() == eStyleUnit_Calc) {
  4442       const nsStyleCoord::Calc *calc = coord.GetCalcValue();
  4443       *coords[index] =
  4444         NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
  4445           calc->mPercent +
  4446         NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
  4447     } else if (coord.GetUnit() == eStyleUnit_Percent) {
  4448       *coords[index] =
  4449         NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
  4450         coord.GetPercentValue();
  4451     } else {
  4452       NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
  4453       *coords[index] =
  4454         NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
  4458   nsPoint parentOffset = aFrame->GetOffsetTo(parent);
  4459   gfxPoint3D gfxOffset(
  4460                NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel),
  4461                NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel),
  4462                0.0f);
  4464   return result - gfxOffset;
  4467 nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame,
  4468                                                                        float aAppUnitsPerPixel,
  4469                                                                        const nsRect* aBoundsOverride)
  4470   : mFrame(aFrame)
  4471   , mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform)
  4472   , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
  4473   , mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel))
  4474   , mChildPerspective(0)
  4476   const nsStyleDisplay* parentDisp = nullptr;
  4477   nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent();
  4478   if (parentStyleContext) {
  4479     parentDisp = parentStyleContext->StyleDisplay();
  4481   if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
  4482     mChildPerspective = parentDisp->mChildPerspective.GetCoordValue();
  4486 /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
  4487  * translates from local coordinate space to transform coordinate space, then
  4488  * hands it back.
  4489  */
  4490 gfx3DMatrix
  4491 nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties& aProperties,
  4492                                                 const nsPoint& aOrigin,
  4493                                                 float aAppUnitsPerPixel,
  4494                                                 const nsRect* aBoundsOverride,
  4495                                                 nsIFrame** aOutAncestor)
  4497   return GetResultingTransformMatrixInternal(aProperties, aOrigin, aAppUnitsPerPixel,
  4498                                              aBoundsOverride, aOutAncestor);
  4501 gfx3DMatrix
  4502 nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
  4503                                                 const nsPoint& aOrigin,
  4504                                                 float aAppUnitsPerPixel,
  4505                                                 const nsRect* aBoundsOverride,
  4506                                                 nsIFrame** aOutAncestor)
  4508   FrameTransformProperties props(aFrame,
  4509                                  aAppUnitsPerPixel,
  4510                                  aBoundsOverride);
  4512   return GetResultingTransformMatrixInternal(props, aOrigin, aAppUnitsPerPixel, 
  4513                                              aBoundsOverride, aOutAncestor);
  4516 gfx3DMatrix
  4517 nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
  4518                                                         const nsPoint& aOrigin,
  4519                                                         float aAppUnitsPerPixel,
  4520                                                         const nsRect* aBoundsOverride,
  4521                                                         nsIFrame** aOutAncestor)
  4523   const nsIFrame *frame = aProperties.mFrame;
  4525   if (aOutAncestor) {
  4526     *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame);
  4529   /* Account for the -moz-transform-origin property by translating the
  4530    * coordinate space to the new origin.
  4531    */
  4532   gfxPoint3D newOrigin =
  4533     gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
  4534                NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
  4535                0.0f);
  4537   /* Get the underlying transform matrix.  This requires us to get the
  4538    * bounds of the frame.
  4539    */
  4540   nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
  4541                    nsDisplayTransform::GetFrameBoundsForTransform(frame));
  4543   /* Get the matrix, then change its basis to factor in the origin. */
  4544   bool dummy;
  4545   gfx3DMatrix result;
  4546   // Call IsSVGTransformed() regardless of the value of
  4547   // disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
  4548   mozilla::gfx::Matrix svgTransform, transformFromSVGParent;
  4549   bool hasSVGTransforms =
  4550     frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
  4551   /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
  4552   if (aProperties.mTransformList) {
  4553     result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
  4554                                                     frame ? frame->StyleContext() : nullptr,
  4555                                                     frame ? frame->PresContext() : nullptr,
  4556                                                     dummy, bounds, aAppUnitsPerPixel);
  4557   } else if (hasSVGTransforms) {
  4558     // Correct the translation components for zoom:
  4559     float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
  4560                              aAppUnitsPerPixel;
  4561     svgTransform._31 *= pixelsPerCSSPx;
  4562     svgTransform._32 *= pixelsPerCSSPx;
  4563     result = gfx3DMatrix::From2D(ThebesMatrix(svgTransform));
  4566   if (hasSVGTransforms && !transformFromSVGParent.IsIdentity()) {
  4567     // Correct the translation components for zoom:
  4568     float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
  4569                              aAppUnitsPerPixel;
  4570     transformFromSVGParent._31 *= pixelsPerCSSPx;
  4571     transformFromSVGParent._32 *= pixelsPerCSSPx;
  4572     result = result * gfx3DMatrix::From2D(ThebesMatrix(transformFromSVGParent));
  4575   if (aProperties.mChildPerspective > 0.0) {
  4576     gfx3DMatrix perspective;
  4577     perspective._34 =
  4578       -1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel);
  4579     /* At the point when perspective is applied, we have been translated to the transform origin.
  4580      * The translation to the perspective origin is the difference between these values.
  4581      */
  4582     result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.mToPerspectiveOrigin - aProperties.mToTransformOrigin, perspective);
  4585   gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x),
  4586                      hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y),
  4587                      0);
  4589   if (frame && frame->Preserves3D()) {
  4590       // Include the transform set on our parent
  4591       NS_ASSERTION(frame->GetParent() &&
  4592                    frame->GetParent()->IsTransformed() &&
  4593                    frame->GetParent()->Preserves3DChildren(),
  4594                    "Preserve3D mismatch!");
  4595       FrameTransformProperties props(frame->GetParent(),
  4596                                      aAppUnitsPerPixel,
  4597                                      nullptr);
  4598       gfx3DMatrix parent =
  4599         GetResultingTransformMatrixInternal(props,
  4600                                             aOrigin - frame->GetPosition(),
  4601                                             aAppUnitsPerPixel, nullptr, aOutAncestor);
  4602       return nsLayoutUtils::ChangeMatrixBasis(rounded + aProperties.mToTransformOrigin, result) * parent;
  4605   return nsLayoutUtils::ChangeMatrixBasis
  4606     (rounded + aProperties.mToTransformOrigin, result);
  4609 bool
  4610 nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
  4612   if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity)) {
  4613     return true;
  4616   if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
  4617     nsCString message;
  4618     message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
  4619     CommonElementAnimationData::LogAsyncAnimationFailure(message,
  4620                                                          Frame()->GetContent());
  4622   return false;
  4625 bool
  4626 nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
  4628   return ShouldPrerenderTransformedContent(aBuilder,
  4629                                            Frame(),
  4630                                            nsLayoutUtils::IsAnimationLoggingEnabled());
  4633 /* static */ bool
  4634 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
  4635                                                       nsIFrame* aFrame,
  4636                                                       bool aLogAnimations)
  4638   // Elements whose transform has been modified recently, or which
  4639   // have a compositor-animated transform, can be prerendered. An element
  4640   // might have only just had its transform animated in which case
  4641   // the ActiveLayerManager may not have been notified yet.
  4642   if (!ActiveLayerTracker::IsStyleAnimated(aFrame, eCSSProperty_transform) &&
  4643       (!aFrame->GetContent() ||
  4644        !nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
  4645                                                   eCSSProperty_transform))) {
  4646     if (aLogAnimations) {
  4647       nsCString message;
  4648       message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
  4649       CommonElementAnimationData::LogAsyncAnimationFailure(message,
  4650                                                            aFrame->GetContent());
  4652     return false;
  4655   nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
  4656   // Only prerender if the transformed frame's size (in the reference
  4657   // frames coordinate space) is <= the reference frame size (~viewport),
  4658   // allowing a 1/8th fuzz factor for shadows, borders, etc.
  4659   refSize += nsSize(refSize.width / 8, refSize.height / 8);
  4660   nsRect frameRect = aFrame->GetVisualOverflowRectRelativeToSelf();
  4662   frameRect =
  4663     nsLayoutUtils::TransformFrameRectToAncestor(aFrame, frameRect,
  4664                                                 aBuilder->RootReferenceFrame());
  4666   if (frameRect.Size() <= refSize) {
  4667     return true;
  4670   if (aLogAnimations) {
  4671     nsCString message;
  4672     message.AppendLiteral("Performance warning: Async animation disabled because frame size (");
  4673     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameRect.width));
  4674     message.AppendLiteral(", ");
  4675     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameRect.height));
  4676     message.AppendLiteral(") is bigger than the viewport (");
  4677     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width));
  4678     message.AppendLiteral(", ");
  4679     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
  4680     message.AppendLiteral(")");
  4681     CommonElementAnimationData::LogAsyncAnimationFailure(message,
  4682                                                          aFrame->GetContent());
  4684   return false;
  4687 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
  4688 static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
  4690   if (aMatrix.IsSingular()) {
  4691     return false;
  4693   if (aFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
  4694       aMatrix.IsBackfaceVisible()) {
  4695     return false;
  4697   return true;
  4700 const gfx3DMatrix&
  4701 nsDisplayTransform::GetTransform()
  4703   if (mTransform.IsIdentity()) {
  4704     float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
  4705     gfxPoint3D newOrigin =
  4706       gfxPoint3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale),
  4707                  NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale),
  4708                   0.0f);
  4709     if (mTransformGetter) {
  4710       mTransform = mTransformGetter(mFrame, scale);
  4711       mTransform = nsLayoutUtils::ChangeMatrixBasis(newOrigin, mTransform);
  4712     } else {
  4713       mTransform =
  4714         GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale);
  4716       /**
  4717        * Shift the coorindates to be relative to our reference frame instead of relative to this frame.
  4718        *  When we have preserve-3d, our reference frame is already guaranteed to be an ancestor of the
  4719        * preserve-3d chain, so we only need to do this once.
  4720        */
  4721       bool hasSVGTransforms = mFrame->IsSVGTransformed();
  4722       gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x), 
  4723                          hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), 
  4724                          0);
  4725       mTransform.Translate(rounded);
  4728   return mTransform;
  4731 bool
  4732 nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
  4734   return ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
  4737 already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
  4738                                                        LayerManager *aManager,
  4739                                                        const ContainerLayerParameters& aContainerParameters)
  4741   const gfx3DMatrix& newTransformMatrix = GetTransform();
  4743   if (mFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN &&
  4744       newTransformMatrix.IsBackfaceVisible()) {
  4745     return nullptr;
  4748   uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ?
  4749     FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0;
  4750   nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
  4751     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(),
  4752                            aContainerParameters, &newTransformMatrix, flags);
  4754   if (!container) {
  4755     return nullptr;
  4758   // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
  4759   // so we never need to explicitely unset this flag.
  4760   if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) {
  4761     container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
  4762   } else {
  4763     container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_PRESERVE_3D);
  4766   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
  4767                                                            this, mFrame,
  4768                                                            eCSSProperty_transform);
  4769   if (ShouldPrerenderTransformedContent(aBuilder, mFrame, false)) {
  4770     container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
  4771                            /*the value is irrelevant*/nullptr);
  4772     container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
  4773   } else {
  4774     container->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
  4775     container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM);
  4777   return container.forget();
  4780 nsDisplayItem::LayerState
  4781 nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
  4782                                   LayerManager* aManager,
  4783                                   const ContainerLayerParameters& aParameters) {
  4784   // If the transform is 3d, or the layer takes part in preserve-3d sorting
  4785   // then we *always* want this to be an active layer.
  4786   if (!GetTransform().Is2D() || mFrame->Preserves3D()) {
  4787     return LAYER_ACTIVE_FORCE;
  4789   // Here we check if the *post-transform* bounds of this item are big enough
  4790   // to justify an active layer.
  4791   if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_transform) &&
  4792       !IsItemTooSmallForActiveLayer(this))
  4793     return LAYER_ACTIVE;
  4794   if (mFrame->GetContent()) {
  4795     if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
  4796                                                   eCSSProperty_transform)) {
  4797       return LAYER_ACTIVE;
  4801   const nsStyleDisplay* disp = mFrame->StyleDisplay();
  4802   if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM)) {
  4803     return LAYER_ACTIVE;
  4806   // Expect the child display items to have this frame as their animated
  4807   // geometry root (since it will be their reference frame). If they have a
  4808   // different animated geometry root, we'll make this an active layer so the
  4809   // animation can be accelerated.
  4810   return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
  4811     *mStoredList.GetChildren(), Frame());
  4814 bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
  4815                                              nsRegion *aVisibleRegion,
  4816                                              const nsRect& aAllowVisibleRegionExpansion)
  4818   /* As we do this, we need to be sure to
  4819    * untransform the visible rect, since we want everything that's painting to
  4820    * think that it's painting in its original rectangular coordinate space.
  4821    * If we can't untransform, take the entire overflow rect */
  4822   nsRect untransformedVisibleRect;
  4823   if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
  4824       !UntransformVisibleRect(aBuilder, &untransformedVisibleRect))
  4826     untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf();
  4828   nsRegion untransformedVisible = untransformedVisibleRect;
  4829   // Call RecomputeVisiblity instead of ComputeVisibility since
  4830   // nsDisplayItem::ComputeVisibility should only be called from
  4831   // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
  4832   mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
  4833   return true;
  4836 #ifdef DEBUG_HIT
  4837 #include <time.h>
  4838 #endif
  4840 /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
  4841 void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
  4842                                  const nsRect& aRect,
  4843                                  HitTestState *aState,
  4844                                  nsTArray<nsIFrame*> *aOutFrames)
  4846   /* Here's how this works:
  4847    * 1. Get the matrix.  If it's singular, abort (clearly we didn't hit
  4848    *    anything).
  4849    * 2. Invert the matrix.
  4850    * 3. Use it to transform the rect into the correct space.
  4851    * 4. Pass that rect down through to the list's version of HitTest.
  4852    */
  4853   // GetTransform always operates in dev pixels.
  4854   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
  4855   gfx3DMatrix matrix = GetTransform();
  4857   if (!IsFrameVisible(mFrame, matrix)) {
  4858     return;
  4861   /* We want to go from transformed-space to regular space.
  4862    * Thus we have to invert the matrix, which normally does
  4863    * the reverse operation (e.g. regular->transformed)
  4864    */
  4865   bool snap;
  4866   nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
  4867   gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
  4868                          NSAppUnitsToFloatPixels(childBounds.y, factor),
  4869                          NSAppUnitsToFloatPixels(childBounds.width, factor),
  4870                          NSAppUnitsToFloatPixels(childBounds.height, factor));
  4872   /* Now, apply the transform and pass it down the channel. */
  4873   nsRect resultingRect;
  4874   if (aRect.width == 1 && aRect.height == 1) {
  4875     // Magic width/height indicating we're hit testing a point, not a rect
  4876     gfxPoint point;
  4877     if (!matrix.UntransformPoint(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor),
  4878                                           NSAppUnitsToFloatPixels(aRect.y, factor)),
  4879                                  childGfxBounds,
  4880                                  &point)) {
  4881       return;
  4884     resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point.x), factor),
  4885                            NSFloatPixelsToAppUnits(float(point.y), factor),
  4886                            1, 1);
  4888   } else {
  4889     gfxRect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
  4890                          NSAppUnitsToFloatPixels(aRect.y, factor),
  4891                          NSAppUnitsToFloatPixels(aRect.width, factor),
  4892                          NSAppUnitsToFloatPixels(aRect.height, factor));
  4894     gfxRect rect = matrix.UntransformBounds(originalRect, childGfxBounds);
  4896     resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
  4897                            NSFloatPixelsToAppUnits(float(rect.Y()), factor),
  4898                            NSFloatPixelsToAppUnits(float(rect.Width()), factor),
  4899                            NSFloatPixelsToAppUnits(float(rect.Height()), factor));
  4902   if (resultingRect.IsEmpty()) {
  4903     return;
  4907 #ifdef DEBUG_HIT
  4908   printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
  4909   printf("  Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y());
  4910   uint32_t originalFrameCount = aOutFrames.Length();
  4911 #endif
  4913   mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
  4915 #ifdef DEBUG_HIT
  4916   if (originalFrameCount != aOutFrames.Length())
  4917     printf("  Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
  4918            dynamic_cast<void *>(aOutFrames.ElementAt(0)));
  4919   printf("=== end of hit test ===\n");
  4920 #endif
  4924 float
  4925 nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint)
  4927   // GetTransform always operates in dev pixels.
  4928   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
  4929   gfx3DMatrix matrix = GetTransform();
  4931   NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!");
  4933   bool snap;
  4934   nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
  4935   gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
  4936                          NSAppUnitsToFloatPixels(childBounds.y, factor),
  4937                          NSAppUnitsToFloatPixels(childBounds.width, factor),
  4938                          NSAppUnitsToFloatPixels(childBounds.height, factor));
  4940   gfxPoint point;
  4941   DebugOnly<bool> result = matrix.UntransformPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
  4942                                                             NSAppUnitsToFloatPixels(aPoint.y, factor)),
  4943                                                    childGfxBounds,
  4944                                                    &point);
  4945   NS_ASSERTION(result, "Why are we trying to get the depth for a point we didn't hit?");
  4947   gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point.x, point.y, 0));
  4948   return transformed.z;
  4951 /* The bounding rectangle for the object is the overflow rectangle translated
  4952  * by the reference point.
  4953  */
  4954 nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap)
  4956   nsRect untransformedBounds =
  4957     ShouldPrerenderTransformedContent(aBuilder, mFrame) ?
  4958     mFrame->GetVisualOverflowRectRelativeToSelf() :
  4959     mStoredList.GetBounds(aBuilder, aSnap);
  4960   *aSnap = false;
  4961   // GetTransform always operates in dev pixels.
  4962   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
  4963   return nsLayoutUtils::MatrixTransformRect(untransformedBounds,
  4964                                             GetTransform(),
  4965                                             factor);
  4968 /* The transform is opaque iff the transform consists solely of scales and
  4969  * translations and if the underlying content is opaque.  Thus if the transform
  4970  * is of the form
  4972  * |a c e|
  4973  * |b d f|
  4974  * |0 0 1|
  4976  * We need b and c to be zero.
  4978  * We also need to check whether the underlying opaque content completely fills
  4979  * our visible rect. We use UntransformRect which expands to the axis-aligned
  4980  * bounding rect, but that's OK since if
  4981  * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
  4982  * certainly contains the actual (non-axis-aligned) untransformed rect.
  4983  */
  4984 nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
  4985                                              bool* aSnap)
  4987   *aSnap = false;
  4988   nsRect untransformedVisible;
  4989   // If we're going to prerender all our content, pretend like we
  4990   // don't have opqaue content so that everything under us is rendered
  4991   // as well.  That will increase graphics memory usage if our frame
  4992   // covers the entire window, but it allows our transform to be
  4993   // updated extremely cheaply, without invalidating any other
  4994   // content.
  4995   if (ShouldPrerenderTransformedContent(aBuilder, mFrame) ||
  4996       !UntransformVisibleRect(aBuilder, &untransformedVisible)) {
  4997       return nsRegion();
  5000   const gfx3DMatrix& matrix = GetTransform();
  5002   nsRegion result;
  5003   gfxMatrix matrix2d;
  5004   bool tmpSnap;
  5005   if (matrix.Is2D(&matrix2d) &&
  5006       matrix2d.PreservesAxisAlignedRectangles() &&
  5007       mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
  5008     result = mVisibleRect;
  5010   return result;
  5013 /* The transform is uniform if it fills the entire bounding rect and the
  5014  * wrapped list is uniform.  See GetOpaqueRegion for discussion of why this
  5015  * works.
  5016  */
  5017 bool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
  5019   nsRect untransformedVisible;
  5020   if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
  5021     return false;
  5023   const gfx3DMatrix& matrix = GetTransform();
  5025   gfxMatrix matrix2d;
  5026   return matrix.Is2D(&matrix2d) &&
  5027          matrix2d.PreservesAxisAlignedRectangles() &&
  5028          mStoredList.GetVisibleRect().Contains(untransformedVisible) &&
  5029          mStoredList.IsUniform(aBuilder, aColor);
  5032 /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
  5033  * share the same underlying content.  Otherwise, doing so results in graphical
  5034  * glitches.
  5035  */
  5036 #ifndef UNIFIED_CONTINUATIONS
  5038 bool
  5039 nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
  5040                              nsDisplayItem *aItem)
  5042   return false;
  5045 #else
  5047 bool
  5048 nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
  5049                              nsDisplayItem *aItem)
  5051   NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
  5052   NS_PRECONDITION(aBuilder, "Why did you try merging with a null builder?");
  5054   /* Make sure that we're dealing with two transforms. */
  5055   if (aItem->GetType() != TYPE_TRANSFORM)
  5056     return false;
  5058   /* Check to see that both frames are part of the same content. */
  5059   if (aItem->Frame()->GetContent() != mFrame->GetContent())
  5060     return false;
  5062   if (aItem->GetClip() != GetClip())
  5063     return false;
  5065   /* Now, move everything over to this frame and signal that
  5066    * we merged things!
  5067    */
  5068   mStoredList.MergeFrom(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
  5069   return true;
  5072 #endif
  5074 /* TransformRect takes in as parameters a rectangle (in app space) and returns
  5075  * the smallest rectangle (in app space) containing the transformed image of
  5076  * that rectangle.  That is, it takes the four corners of the rectangle,
  5077  * transforms them according to the matrix associated with the specified frame,
  5078  * then returns the smallest rectangle containing the four transformed points.
  5080  * @param aUntransformedBounds The rectangle (in app units) to transform.
  5081  * @param aFrame The frame whose transformation should be applied.
  5082  * @param aOrigin The delta from the frame origin to the coordinate space origin
  5083  * @param aBoundsOverride (optional) Force the frame bounds to be the
  5084  *        specified bounds.
  5085  * @return The smallest rectangle containing the image of the transformed
  5086  *         rectangle.
  5087  */
  5088 nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
  5089                                          const nsIFrame* aFrame,
  5090                                          const nsPoint &aOrigin,
  5091                                          const nsRect* aBoundsOverride)
  5093   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
  5095   float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
  5096   return nsLayoutUtils::MatrixTransformRect
  5097     (aUntransformedBounds,
  5098      GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
  5099      factor);
  5102 nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds,
  5103                                             const nsIFrame* aFrame,
  5104                                             const nsPoint &aOrigin,
  5105                                             const nsRect* aBoundsOverride)
  5107   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
  5109   float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
  5110   return nsLayoutUtils::MatrixTransformRectOut
  5111     (aUntransformedBounds,
  5112      GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
  5113      factor);
  5116 bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds,
  5117                                          const nsRect &aChildBounds,
  5118                                          const nsIFrame* aFrame,
  5119                                          const nsPoint &aOrigin,
  5120                                          nsRect *aOutRect)
  5122   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
  5124   float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
  5126   gfx3DMatrix transform = GetResultingTransformMatrix(aFrame, aOrigin, factor, nullptr);
  5127   if (transform.IsSingular()) {
  5128     return false;
  5131   gfxRect result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor),
  5132                  NSAppUnitsToFloatPixels(aTransformedBounds.y, factor),
  5133                  NSAppUnitsToFloatPixels(aTransformedBounds.width, factor),
  5134                  NSAppUnitsToFloatPixels(aTransformedBounds.height, factor));
  5136   gfxRect childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor),
  5137                          NSAppUnitsToFloatPixels(aChildBounds.y, factor),
  5138                          NSAppUnitsToFloatPixels(aChildBounds.width, factor),
  5139                          NSAppUnitsToFloatPixels(aChildBounds.height, factor));
  5141   result = transform.UntransformBounds(result, childGfxBounds);
  5142   *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor);
  5143   return true;
  5146 bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder,
  5147                                                 nsRect *aOutRect)
  5149   const gfx3DMatrix& matrix = GetTransform();
  5150   if (matrix.IsSingular())
  5151     return false;
  5153   // GetTransform always operates in dev pixels.
  5154   float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
  5155   gfxRect result(NSAppUnitsToFloatPixels(mVisibleRect.x, factor),
  5156                  NSAppUnitsToFloatPixels(mVisibleRect.y, factor),
  5157                  NSAppUnitsToFloatPixels(mVisibleRect.width, factor),
  5158                  NSAppUnitsToFloatPixels(mVisibleRect.height, factor));
  5160   bool snap;
  5161   nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
  5162   gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
  5163                          NSAppUnitsToFloatPixels(childBounds.y, factor),
  5164                          NSAppUnitsToFloatPixels(childBounds.width, factor),
  5165                          NSAppUnitsToFloatPixels(childBounds.height, factor));
  5167   /* We want to untransform the matrix, so invert the transformation first! */
  5168   result = matrix.UntransformBounds(result, childGfxBounds);
  5170   *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor);
  5172   return true;
  5175 nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
  5176                                          nsIFrame* aFrame, nsDisplayList* aList)
  5177     : nsDisplayWrapList(aBuilder, aFrame, aList),
  5178       mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
  5180   MOZ_COUNT_CTOR(nsDisplaySVGEffects);
  5183 #ifdef NS_BUILD_REFCNT_LOGGING
  5184 nsDisplaySVGEffects::~nsDisplaySVGEffects()
  5186   MOZ_COUNT_DTOR(nsDisplaySVGEffects);
  5188 #endif
  5190 nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
  5191                                               bool* aSnap)
  5193   *aSnap = false;
  5194   return nsRegion();
  5197 void
  5198 nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  5199                              HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
  5201   nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
  5202   if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame,
  5203       rectCenter - ToReferenceFrame())) {
  5204     mList.HitTest(aBuilder, aRect, aState, aOutFrames);
  5208 void
  5209 nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
  5210                                   nsRenderingContext* aCtx,
  5211                                   LayerManager* aManager)
  5213   nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx, mFrame,
  5214                                                 mVisibleRect,
  5215                                                 aBuilder, aManager);
  5218 LayerState
  5219 nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder,
  5220                                    LayerManager* aManager,
  5221                                    const ContainerLayerParameters& aParameters)
  5223   return LAYER_SVG_EFFECTS;
  5226 already_AddRefed<Layer>
  5227 nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder,
  5228                                 LayerManager* aManager,
  5229                                 const ContainerLayerParameters& aContainerParameters)
  5231   const nsIContent* content = mFrame->GetContent();
  5232   bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
  5233   if (hasSVGLayout) {
  5234     nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame);
  5235     if (!svgChildFrame || !mFrame->GetContent()->IsSVG()) {
  5236       NS_ASSERTION(false, "why?");
  5237       return nullptr;
  5239     if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
  5240       return nullptr; // The SVG spec says not to draw filters for this
  5244   float opacity = mFrame->StyleDisplay()->mOpacity;
  5245   if (opacity == 0.0f)
  5246     return nullptr;
  5248   nsIFrame* firstFrame =
  5249     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
  5250   nsSVGEffects::EffectProperties effectProperties =
  5251     nsSVGEffects::GetEffectProperties(firstFrame);
  5253   bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
  5254   effectProperties.GetClipPathFrame(&isOK);
  5255   effectProperties.GetMaskFrame(&isOK);
  5257   if (!isOK) {
  5258     return nullptr;
  5261   ContainerLayerParameters newContainerParameters = aContainerParameters;
  5262   if (effectProperties.HasValidFilter()) {
  5263     newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
  5266   nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
  5267     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
  5268                            newContainerParameters, nullptr);
  5270   return container.forget();
  5273 bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,
  5274                                               nsRegion* aVisibleRegion,
  5275                                               const nsRect& aAllowVisibleRegionExpansion) {
  5276   nsPoint offset = ToReferenceFrame();
  5277   nsRect dirtyRect =
  5278     nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
  5279                                                            mVisibleRect - offset) +
  5280     offset;
  5282   // Our children may be made translucent or arbitrarily deformed so we should
  5283   // not allow them to subtract area from aVisibleRegion.
  5284   nsRegion childrenVisible(dirtyRect);
  5285   nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
  5286   mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect());
  5287   return true;
  5290 bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
  5292   if (aItem->GetType() != TYPE_SVG_EFFECTS)
  5293     return false;
  5294   // items for the same content element should be merged into a single
  5295   // compositing group
  5296   // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
  5297   if (aItem->Frame()->GetContent() != mFrame->GetContent())
  5298     return false;
  5299   if (aItem->GetClip() != GetClip())
  5300     return false;
  5301   nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
  5302   MergeFromTrackingMergedFrames(other);
  5303   mEffectsBounds.UnionRect(mEffectsBounds,
  5304     other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
  5305   return true;
  5308 #ifdef MOZ_DUMP_PAINTING
  5309 void
  5310 nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
  5312   nsIFrame* firstFrame =
  5313     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
  5314   nsSVGEffects::EffectProperties effectProperties =
  5315     nsSVGEffects::GetEffectProperties(firstFrame);
  5316   bool isOK = true;
  5317   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
  5318   bool first = true;
  5319   aTo += " effects=(";
  5320   if (mFrame->StyleDisplay()->mOpacity != 1.0f) {
  5321     first = false;
  5322     aTo += nsPrintfCString("opacity(%f)", mFrame->StyleDisplay()->mOpacity);
  5324   if (clipPathFrame) {
  5325     if (!first) {
  5326       aTo += ", ";
  5328     aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
  5329     first = false;
  5331   if (effectProperties.HasValidFilter()) {
  5332     if (!first) {
  5333       aTo += ", ";
  5335     aTo += "filter";
  5336     first = false;
  5338   if (effectProperties.GetMaskFrame(&isOK)) {
  5339     if (!first) {
  5340       aTo += ", ";
  5342     aTo += "mask";
  5344   aTo += ")";
  5346 #endif

mercurial