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/.
9 * structures that represent things to be painted (ordered in z-order),
10 * used during painting and hit testing
13 #include "nsDisplayList.h"
19 #include "mozilla/dom/TabChild.h"
20 #include "mozilla/gfx/2D.h"
21 #include "mozilla/layers/PLayerTransaction.h"
22 #include "nsCSSRendering.h"
23 #include "nsRenderingContext.h"
24 #include "nsISelectionController.h"
25 #include "nsIPresShell.h"
27 #include "nsStyleStructInlines.h"
28 #include "nsStyleTransformMatrix.h"
29 #include "gfxMatrix.h"
31 #include "nsSVGIntegrationUtils.h"
32 #include "nsSVGUtils.h"
33 #include "nsLayoutUtils.h"
34 #include "nsIScrollableFrame.h"
35 #include "nsIFrameInlines.h"
36 #include "nsThemeConstants.h"
37 #include "LayerTreeInvalidation.h"
39 #include "imgIContainer.h"
40 #include "BasicLayers.h"
41 #include "nsBoxFrame.h"
42 #include "nsViewportFrame.h"
43 #include "nsSubDocumentFrame.h"
44 #include "nsSVGEffects.h"
45 #include "nsSVGElement.h"
46 #include "nsSVGClipPathFrame.h"
47 #include "GeckoProfiler.h"
48 #include "nsAnimationManager.h"
49 #include "nsTransitionManager.h"
50 #include "nsViewManager.h"
51 #include "ImageLayers.h"
52 #include "ImageContainer.h"
53 #include "nsCanvasFrame.h"
54 #include "StickyScrollContainer.h"
55 #include "mozilla/EventStates.h"
56 #include "mozilla/LookAndFeel.h"
57 #include "mozilla/PendingPlayerTracker.h"
58 #include "mozilla/Preferences.h"
59 #include "mozilla/UniquePtr.h"
60 #include "ActiveLayerTracker.h"
61 #include "nsContentUtils.h"
62 #include "nsPrintfCString.h"
63 #include "UnitTransforms.h"
64 #include "LayersLogging.h"
65 #include "FrameLayerBuilder.h"
66 #include "RestyleManager.h"
68 #include "nsISelection.h"
70 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
76 using namespace mozilla
;
77 using namespace mozilla::layers
;
78 using namespace mozilla::dom
;
79 using namespace mozilla::image
;
80 using namespace mozilla::layout
;
81 using namespace mozilla::gfx
;
83 typedef FrameMetrics::ViewID ViewID
;
87 SpammyLayoutWarningsEnabled()
89 static bool sValue
= false;
90 static bool sValueInitialized
= false;
92 if (!sValueInitialized
) {
93 Preferences::GetBool("layout.spammy_warnings.enabled", &sValue
);
94 sValueInitialized
= true;
101 static inline nsIFrame
*
102 GetTransformRootFrame(nsIFrame
* aFrame
)
104 return nsLayoutUtils::GetTransformRootFrame(aFrame
);
107 static void AddTransformFunctions(nsCSSValueList
* aList
,
108 nsStyleContext
* aContext
,
109 nsPresContext
* aPresContext
,
111 InfallibleTArray
<TransformFunction
>& aFunctions
)
113 if (aList
->mValue
.GetUnit() == eCSSUnit_None
) {
117 for (const nsCSSValueList
* curr
= aList
; curr
; curr
= curr
->mNext
) {
118 const nsCSSValue
& currElem
= curr
->mValue
;
119 NS_ASSERTION(currElem
.GetUnit() == eCSSUnit_Function
,
120 "Stream should consist solely of functions!");
121 nsCSSValue::Array
* array
= currElem
.GetArrayValue();
122 bool canStoreInRuleTree
= true;
123 switch (nsStyleTransformMatrix::TransformFunctionOf(array
)) {
124 case eCSSKeyword_rotatex
:
126 double theta
= array
->Item(1).GetAngleValueInRadians();
127 aFunctions
.AppendElement(RotationX(theta
));
130 case eCSSKeyword_rotatey
:
132 double theta
= array
->Item(1).GetAngleValueInRadians();
133 aFunctions
.AppendElement(RotationY(theta
));
136 case eCSSKeyword_rotatez
:
138 double theta
= array
->Item(1).GetAngleValueInRadians();
139 aFunctions
.AppendElement(RotationZ(theta
));
142 case eCSSKeyword_rotate
:
144 double theta
= array
->Item(1).GetAngleValueInRadians();
145 aFunctions
.AppendElement(Rotation(theta
));
148 case eCSSKeyword_rotate3d
:
150 double x
= array
->Item(1).GetFloatValue();
151 double y
= array
->Item(2).GetFloatValue();
152 double z
= array
->Item(3).GetFloatValue();
153 double theta
= array
->Item(4).GetAngleValueInRadians();
154 aFunctions
.AppendElement(Rotation3D(x
, y
, z
, theta
));
157 case eCSSKeyword_scalex
:
159 double x
= array
->Item(1).GetFloatValue();
160 aFunctions
.AppendElement(Scale(x
, 1, 1));
163 case eCSSKeyword_scaley
:
165 double y
= array
->Item(1).GetFloatValue();
166 aFunctions
.AppendElement(Scale(1, y
, 1));
169 case eCSSKeyword_scalez
:
171 double z
= array
->Item(1).GetFloatValue();
172 aFunctions
.AppendElement(Scale(1, 1, z
));
175 case eCSSKeyword_scale
:
177 double x
= array
->Item(1).GetFloatValue();
178 // scale(x) is shorthand for scale(x, x);
179 double y
= array
->Count() == 2 ? x
: array
->Item(2).GetFloatValue();
180 aFunctions
.AppendElement(Scale(x
, y
, 1));
183 case eCSSKeyword_scale3d
:
185 double x
= array
->Item(1).GetFloatValue();
186 double y
= array
->Item(2).GetFloatValue();
187 double z
= array
->Item(3).GetFloatValue();
188 aFunctions
.AppendElement(Scale(x
, y
, z
));
191 case eCSSKeyword_translatex
:
193 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
194 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
196 aFunctions
.AppendElement(Translation(x
, 0, 0));
199 case eCSSKeyword_translatey
:
201 double y
= nsStyleTransformMatrix::ProcessTranslatePart(
202 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
204 aFunctions
.AppendElement(Translation(0, y
, 0));
207 case eCSSKeyword_translatez
:
209 double z
= nsStyleTransformMatrix::ProcessTranslatePart(
210 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
212 aFunctions
.AppendElement(Translation(0, 0, z
));
215 case eCSSKeyword_translate
:
217 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
218 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
220 // translate(x) is shorthand for translate(x, 0)
222 if (array
->Count() == 3) {
223 y
= nsStyleTransformMatrix::ProcessTranslatePart(
224 array
->Item(2), aContext
, aPresContext
, canStoreInRuleTree
,
227 aFunctions
.AppendElement(Translation(x
, y
, 0));
230 case eCSSKeyword_translate3d
:
232 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
233 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
235 double y
= nsStyleTransformMatrix::ProcessTranslatePart(
236 array
->Item(2), aContext
, aPresContext
, canStoreInRuleTree
,
238 double z
= nsStyleTransformMatrix::ProcessTranslatePart(
239 array
->Item(3), aContext
, aPresContext
, canStoreInRuleTree
,
242 aFunctions
.AppendElement(Translation(x
, y
, z
));
245 case eCSSKeyword_skewx
:
247 double x
= array
->Item(1).GetAngleValueInRadians();
248 aFunctions
.AppendElement(SkewX(x
));
251 case eCSSKeyword_skewy
:
253 double y
= array
->Item(1).GetAngleValueInRadians();
254 aFunctions
.AppendElement(SkewY(y
));
257 case eCSSKeyword_skew
:
259 double x
= array
->Item(1).GetAngleValueInRadians();
260 // skew(x) is shorthand for skew(x, 0)
262 if (array
->Count() == 3) {
263 y
= array
->Item(2).GetAngleValueInRadians();
265 aFunctions
.AppendElement(Skew(x
, y
));
268 case eCSSKeyword_matrix
:
270 gfx::Matrix4x4 matrix
;
271 matrix
._11
= array
->Item(1).GetFloatValue();
272 matrix
._12
= array
->Item(2).GetFloatValue();
275 matrix
._21
= array
->Item(3).GetFloatValue();
276 matrix
._22
= array
->Item(4).GetFloatValue();
283 matrix
._41
= array
->Item(5).GetFloatValue();
284 matrix
._42
= array
->Item(6).GetFloatValue();
287 aFunctions
.AppendElement(TransformMatrix(matrix
));
290 case eCSSKeyword_matrix3d
:
292 gfx::Matrix4x4 matrix
;
293 matrix
._11
= array
->Item(1).GetFloatValue();
294 matrix
._12
= array
->Item(2).GetFloatValue();
295 matrix
._13
= array
->Item(3).GetFloatValue();
296 matrix
._14
= array
->Item(4).GetFloatValue();
297 matrix
._21
= array
->Item(5).GetFloatValue();
298 matrix
._22
= array
->Item(6).GetFloatValue();
299 matrix
._23
= array
->Item(7).GetFloatValue();
300 matrix
._24
= array
->Item(8).GetFloatValue();
301 matrix
._31
= array
->Item(9).GetFloatValue();
302 matrix
._32
= array
->Item(10).GetFloatValue();
303 matrix
._33
= array
->Item(11).GetFloatValue();
304 matrix
._34
= array
->Item(12).GetFloatValue();
305 matrix
._41
= array
->Item(13).GetFloatValue();
306 matrix
._42
= array
->Item(14).GetFloatValue();
307 matrix
._43
= array
->Item(15).GetFloatValue();
308 matrix
._44
= array
->Item(16).GetFloatValue();
309 aFunctions
.AppendElement(TransformMatrix(matrix
));
312 case eCSSKeyword_interpolatematrix
:
315 nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix
, array
,
320 aFunctions
.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix
)));
323 case eCSSKeyword_perspective
:
325 aFunctions
.AppendElement(Perspective(array
->Item(1).GetFloatValue()));
329 NS_ERROR("Function not handled yet!");
334 static TimingFunction
335 ToTimingFunction(ComputedTimingFunction
& aCTF
)
337 if (aCTF
.GetType() == nsTimingFunction::Function
) {
338 const nsSMILKeySpline
* spline
= aCTF
.GetFunction();
339 return TimingFunction(CubicBezierFunction(spline
->X1(), spline
->Y1(),
340 spline
->X2(), spline
->Y2()));
343 uint32_t type
= aCTF
.GetType() == nsTimingFunction::StepStart
? 1 : 2;
344 return TimingFunction(StepFunction(aCTF
.GetSteps(), type
));
348 AddAnimationForProperty(nsIFrame
* aFrame
, nsCSSProperty aProperty
,
349 AnimationPlayer
* aPlayer
, Layer
* aLayer
,
350 AnimationData
& aData
, bool aPending
)
352 MOZ_ASSERT(aLayer
->AsContainerLayer(), "Should only animate ContainerLayer");
353 MOZ_ASSERT(aPlayer
->GetSource(),
354 "Should not be adding an animation for a player without"
356 nsStyleContext
* styleContext
= aFrame
->StyleContext();
357 nsPresContext
* presContext
= aFrame
->PresContext();
358 nsRect bounds
= nsDisplayTransform::GetFrameBoundsForTransform(aFrame
);
360 layers::Animation
* animation
=
362 aLayer
->AddAnimationForNextTransaction() :
363 aLayer
->AddAnimation();
365 const AnimationTiming
& timing
= aPlayer
->GetSource()->Timing();
366 Nullable
<TimeDuration
> startTime
= aPlayer
->GetCurrentOrPendingStartTime();
367 animation
->startTime() = startTime
.IsNull()
369 : aPlayer
->Timeline()->ToTimeStamp(
370 startTime
.Value() + timing
.mDelay
);
371 animation
->initialCurrentTime() = aPlayer
->GetCurrentTime().Value()
373 animation
->duration() = timing
.mIterationDuration
;
374 animation
->iterationCount() = timing
.mIterationCount
;
375 animation
->direction() = timing
.mDirection
;
376 animation
->property() = aProperty
;
377 animation
->data() = aData
;
379 dom::Animation
* anim
= aPlayer
->GetSource();
380 for (size_t propIdx
= 0;
381 propIdx
< anim
->Properties().Length();
383 AnimationProperty
& property
= anim
->Properties()[propIdx
];
385 if (aProperty
!= property
.mProperty
) {
389 for (uint32_t segIdx
= 0; segIdx
< property
.mSegments
.Length(); segIdx
++) {
390 AnimationPropertySegment
& segment
= property
.mSegments
[segIdx
];
392 AnimationSegment
* animSegment
= animation
->segments().AppendElement();
393 if (aProperty
== eCSSProperty_transform
) {
394 animSegment
->startState() = InfallibleTArray
<TransformFunction
>();
395 animSegment
->endState() = InfallibleTArray
<TransformFunction
>();
397 nsCSSValueSharedList
* list
=
398 segment
.mFromValue
.GetCSSValueSharedListValue();
399 AddTransformFunctions(list
->mHead
, styleContext
, presContext
, bounds
,
400 animSegment
->startState().get_ArrayOfTransformFunction());
402 list
= segment
.mToValue
.GetCSSValueSharedListValue();
403 AddTransformFunctions(list
->mHead
, styleContext
, presContext
, bounds
,
404 animSegment
->endState().get_ArrayOfTransformFunction());
405 } else if (aProperty
== eCSSProperty_opacity
) {
406 animSegment
->startState() = segment
.mFromValue
.GetFloatValue();
407 animSegment
->endState() = segment
.mToValue
.GetFloatValue();
410 animSegment
->startPortion() = segment
.mFromKey
;
411 animSegment
->endPortion() = segment
.mToKey
;
412 animSegment
->sampleFn() = ToTimingFunction(segment
.mTimingFunction
);
418 AddAnimationsForProperty(nsIFrame
* aFrame
, nsCSSProperty aProperty
,
419 AnimationPlayerPtrArray
& aPlayers
,
420 Layer
* aLayer
, AnimationData
& aData
,
422 for (size_t playerIdx
= 0; playerIdx
< aPlayers
.Length(); playerIdx
++) {
423 AnimationPlayer
* player
= aPlayers
[playerIdx
];
424 dom::Animation
* anim
= player
->GetSource();
425 if (!(anim
&& anim
->HasAnimationOfProperty(aProperty
) &&
426 player
->IsRunning())) {
430 // Don't add animations that are pending when their corresponding
431 // refresh driver is under test control. This is because any pending
432 // animations on layers will have their start time updated with the
433 // current timestamp but when the refresh driver is under test control
434 // its refresh times are unrelated to timestamp values.
436 // Instead we leave the animation running on the main thread and the
437 // next time the refresh driver is advanced it will trigger any pending
439 if (player
->PlayState() == AnimationPlayState::Pending
) {
440 nsRefreshDriver
* driver
= player
->Timeline()->GetRefreshDriver();
441 if (driver
&& driver
->IsTestControllingRefreshesEnabled()) {
446 AddAnimationForProperty(aFrame
, aProperty
, player
, aLayer
, aData
, aPending
);
447 player
->SetIsRunningOnCompositor();
452 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer
* aLayer
,
453 nsDisplayListBuilder
* aBuilder
,
454 nsDisplayItem
* aItem
,
456 nsCSSProperty aProperty
)
458 // This function can be called in two ways: from
459 // nsDisplay*::BuildLayer while constructing a layer (with all
460 // pointers non-null), or from RestyleManager's handling of
461 // UpdateOpacityLayer/UpdateTransformLayer hints.
462 MOZ_ASSERT(!aBuilder
== !aItem
,
463 "should only be called in two configurations, with both "
464 "aBuilder and aItem, or with neither");
465 MOZ_ASSERT(!aItem
|| aFrame
== aItem
->Frame(), "frame mismatch");
467 bool pending
= !aBuilder
;
470 aLayer
->ClearAnimationsForNextTransaction();
472 aLayer
->ClearAnimations();
475 // Update the animation generation on the layer. We need to do this before
476 // any early returns since even if we don't add any animations to the
477 // layer, we still need to mark it as up-to-date with regards to animations.
478 // Otherwise, in RestyleManager we'll notice the discrepancy between the
479 // animation generation numbers and update the layer indefinitely.
480 uint64_t animationGeneration
=
481 RestyleManager::GetMaxAnimationGenerationForFrame(aFrame
);
482 aLayer
->SetAnimationGeneration(animationGeneration
);
484 nsIContent
* content
= aFrame
->GetContent();
488 AnimationPlayerCollection
* transitions
=
489 nsTransitionManager::GetAnimationsForCompositor(content
, aProperty
);
490 AnimationPlayerCollection
* animations
=
491 nsAnimationManager::GetAnimationsForCompositor(content
, aProperty
);
493 if (!animations
&& !transitions
) {
497 // If the frame is not prerendered, bail out.
498 // Do this check only during layer construction; during updating the
499 // caller is required to check it appropriately.
500 if (aItem
&& !aItem
->CanUseAsyncAnimations(aBuilder
)) {
501 // AnimationManager or TransitionManager need to know that we refused to
502 // run this animation asynchronously so that they will not throttle the
503 // main thread animation.
504 aFrame
->Properties().Set(nsIFrame::RefusedAsyncAnimation(),
505 reinterpret_cast<void*>(intptr_t(true)));
507 // We need to schedule another refresh driver run so that AnimationManager
508 // or TransitionManager get a chance to unthrottle the animation.
509 aFrame
->SchedulePaint();
514 if (aProperty
== eCSSProperty_transform
) {
515 nsRect bounds
= nsDisplayTransform::GetFrameBoundsForTransform(aFrame
);
516 // all data passed directly to the compositor should be in css pixels
517 float scale
= nsDeviceContext::AppUnitsPerCSSPixel();
518 Point3D offsetToTransformOrigin
=
519 nsDisplayTransform::GetDeltaToTransformOrigin(aFrame
, scale
, &bounds
);
520 Point3D offsetToPerspectiveOrigin
=
521 nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame
, scale
);
522 nscoord perspective
= 0.0;
523 nsStyleContext
* parentStyleContext
= aFrame
->StyleContext()->GetParent();
524 if (parentStyleContext
) {
525 const nsStyleDisplay
* disp
= parentStyleContext
->StyleDisplay();
526 if (disp
&& disp
->mChildPerspective
.GetUnit() == eStyleUnit_Coord
) {
527 perspective
= disp
->mChildPerspective
.GetCoordValue();
532 origin
= aItem
->ToReferenceFrame();
534 // transform display items used a reference frame computed from
535 // their GetTransformRootFrame().
536 nsIFrame
* referenceFrame
=
537 nsLayoutUtils::GetReferenceFrame(GetTransformRootFrame(aFrame
));
538 origin
= aFrame
->GetOffsetToCrossDoc(referenceFrame
);
541 data
= TransformData(origin
, offsetToTransformOrigin
,
542 offsetToPerspectiveOrigin
, bounds
, perspective
,
543 aFrame
->PresContext()->AppUnitsPerDevPixel());
544 } else if (aProperty
== eCSSProperty_opacity
) {
549 AddAnimationsForProperty(aFrame
, aProperty
, transitions
->mPlayers
,
550 aLayer
, data
, pending
);
554 AddAnimationsForProperty(aFrame
, aProperty
, animations
->mPlayers
,
555 aLayer
, data
, pending
);
559 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame
* aReferenceFrame
,
560 Mode aMode
, bool aBuildCaret
)
561 : mReferenceFrame(aReferenceFrame
),
562 mIgnoreScrollFrame(nullptr),
563 mLayerEventRegions(nullptr),
564 mCurrentTableItem(nullptr),
565 mCurrentFrame(aReferenceFrame
),
566 mCurrentReferenceFrame(aReferenceFrame
),
567 mCurrentAnimatedGeometryRoot(nullptr),
568 mWillChangeBudgetCalculated(false),
569 mDirtyRect(-1,-1,-1,-1),
570 mGlassDisplayItem(nullptr),
572 mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID
),
573 mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID
),
574 mCurrentScrollbarFlags(0),
575 mBuildCaret(aBuildCaret
),
576 mIgnoreSuppression(false),
577 mHadToIgnoreSuppression(false),
578 mIsAtRootOfPseudoStackingContext(false),
579 mIncludeAllOutOfFlows(false),
580 mDescendIntoSubdocuments(true),
581 mSelectedFramesOnly(false),
582 mAccurateVisibleRegions(false),
583 mAllowMergingAndFlattening(true),
584 mWillComputePluginGeometry(false),
586 mSyncDecodeImages(false),
587 mIsPaintingToWindow(false),
588 mIsCompositingCheap(false),
589 mContainsPluginItem(false),
590 mAncestorHasApzAwareEventHandler(false),
591 mHaveScrollableDisplayPort(false)
593 MOZ_COUNT_CTOR(nsDisplayListBuilder
);
594 PL_InitArenaPool(&mPool
, "displayListArena", 1024,
595 std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
596 RecomputeCurrentAnimatedGeometryRoot();
598 nsPresContext
* pc
= aReferenceFrame
->PresContext();
599 nsIPresShell
*shell
= pc
->PresShell();
600 if (pc
->IsRenderingOnlySelection()) {
601 nsCOMPtr
<nsISelectionController
> selcon(do_QueryInterface(shell
));
603 selcon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
604 getter_AddRefs(mBoundingSelection
));
608 nsCSSRendering::BeginFrameTreesLocked();
609 PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX
< (1 << nsDisplayItem::TYPE_BITS
));
612 static void MarkFrameForDisplay(nsIFrame
* aFrame
, nsIFrame
* aStopAtFrame
) {
613 for (nsIFrame
* f
= aFrame
; f
;
614 f
= nsLayoutUtils::GetParentOrPlaceholderFor(f
)) {
615 if (f
->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
)
617 f
->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
);
618 if (f
== aStopAtFrame
) {
619 // we've reached a frame that we know will be painted, so we can stop.
625 void nsDisplayListBuilder::SetContainsBlendMode(uint8_t aBlendMode
)
627 MOZ_ASSERT(aBlendMode
!= NS_STYLE_BLEND_NORMAL
);
628 gfxContext::GraphicsOperator op
= nsCSSRendering::GetGFXBlendMode(aBlendMode
);
629 mContainedBlendModes
+= gfx::CompositionOpForOp(op
);
632 bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem
* aItem
)
634 return aItem
== mGlassDisplayItem
|| aItem
->ClearsBackground();
637 void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame
* aDirtyFrame
,
639 const nsRect
& aDirtyRect
)
641 nsRect dirtyRectRelativeToDirtyFrame
= aDirtyRect
;
642 if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame
) &&
643 IsPaintingToWindow()) {
644 NS_ASSERTION(aDirtyFrame
== aFrame
->GetParent(), "Dirty frame should be viewport frame");
645 // position: fixed items are reflowed into and only drawn inside the
646 // viewport, or the scroll position clamping scrollport size, if one is
648 nsIPresShell
* ps
= aFrame
->PresContext()->PresShell();
649 dirtyRectRelativeToDirtyFrame
.MoveTo(0, 0);
650 if (ps
->IsScrollPositionClampingScrollPortSizeSet()) {
651 dirtyRectRelativeToDirtyFrame
.SizeTo(ps
->GetScrollPositionClampingScrollPortSize());
653 dirtyRectRelativeToDirtyFrame
.SizeTo(aDirtyFrame
->GetSize());
657 nsRect dirty
= dirtyRectRelativeToDirtyFrame
- aFrame
->GetOffsetTo(aDirtyFrame
);
658 nsRect overflowRect
= aFrame
->GetVisualOverflowRect();
660 if (aFrame
->IsTransformed() &&
661 nsLayoutUtils::HasAnimationsForCompositor(aFrame
->GetContent(),
662 eCSSProperty_transform
)) {
664 * Add a fuzz factor to the overflow rectangle so that elements only just
665 * out of view are pulled into the display list, so they can be
666 * prerendered if necessary.
668 overflowRect
.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
671 if (!dirty
.IntersectRect(dirty
, overflowRect
))
673 const DisplayItemClip
* clip
= mClipState
.GetClipForContainingBlockDescendants();
674 OutOfFlowDisplayData
* data
= clip
? new OutOfFlowDisplayData(*clip
, dirty
)
675 : new OutOfFlowDisplayData(dirty
);
676 aFrame
->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data
);
678 MarkFrameForDisplay(aFrame
, aDirtyFrame
);
681 static void UnmarkFrameForDisplay(nsIFrame
* aFrame
) {
682 nsPresContext
* presContext
= aFrame
->PresContext();
683 presContext
->PropertyTable()->
684 Delete(aFrame
, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
686 for (nsIFrame
* f
= aFrame
; f
;
687 f
= nsLayoutUtils::GetParentOrPlaceholderFor(f
)) {
688 if (!(f
->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
))
690 f
->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
);
694 /* static */ FrameMetrics
695 nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame
* aForFrame
,
696 nsIFrame
* aScrollFrame
,
697 const nsIFrame
* aReferenceFrame
,
699 ViewID aScrollParentId
,
700 const nsRect
& aViewport
,
702 const ContainerLayerParameters
& aContainerParameters
)
704 nsPresContext
* presContext
= aForFrame
->PresContext();
705 int32_t auPerDevPixel
= presContext
->AppUnitsPerDevPixel();
707 nsIPresShell
* presShell
= presContext
->GetPresShell();
708 FrameMetrics metrics
;
709 metrics
.SetViewport(CSSRect::FromAppUnits(aViewport
));
711 ViewID scrollId
= FrameMetrics::NULL_SCROLL_ID
;
712 nsIContent
* content
= aScrollFrame
? aScrollFrame
->GetContent() : nullptr;
714 scrollId
= nsLayoutUtils::FindOrCreateIDFor(content
);
716 if (nsLayoutUtils::GetDisplayPort(content
, &dp
)) {
717 metrics
.SetDisplayPort(CSSRect::FromAppUnits(dp
));
718 nsLayoutUtils::LogTestDataForPaint(aLayer
->Manager(), scrollId
, "displayport",
719 metrics
.GetDisplayPort());
721 if (nsLayoutUtils::GetCriticalDisplayPort(content
, &dp
)) {
722 metrics
.SetCriticalDisplayPort(CSSRect::FromAppUnits(dp
));
724 DisplayPortMarginsPropertyData
* marginsData
=
725 static_cast<DisplayPortMarginsPropertyData
*>(content
->GetProperty(nsGkAtoms::DisplayPortMargins
));
727 metrics
.SetDisplayPortMargins(marginsData
->mMargins
);
731 nsIScrollableFrame
* scrollableFrame
= nullptr;
733 scrollableFrame
= aScrollFrame
->GetScrollTargetFrame();
735 metrics
.SetScrollableRect(CSSRect::FromAppUnits(
736 nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame
, aForFrame
)));
738 if (scrollableFrame
) {
739 nsPoint scrollPosition
= scrollableFrame
->GetScrollPosition();
740 metrics
.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition
));
742 nsPoint smoothScrollPosition
= scrollableFrame
->LastScrollDestination();
743 metrics
.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition
));
745 // If the frame was scrolled since the last layers update, and by
746 // something other than the APZ code, we want to tell the APZ to update
747 // its scroll offset.
748 nsIAtom
* lastScrollOrigin
= scrollableFrame
->LastScrollOrigin();
749 if (lastScrollOrigin
&& lastScrollOrigin
!= nsGkAtoms::apz
) {
750 metrics
.SetScrollOffsetUpdated(scrollableFrame
->CurrentScrollGeneration());
752 nsIAtom
* lastSmoothScrollOrigin
= scrollableFrame
->LastSmoothScrollOrigin();
753 if (lastSmoothScrollOrigin
) {
754 metrics
.SetSmoothScrollOffsetUpdated(scrollableFrame
->CurrentScrollGeneration());
757 nsSize lineScrollAmount
= scrollableFrame
->GetLineScrollAmount();
758 LayoutDeviceIntSize lineScrollAmountInDevPixels
=
759 LayoutDeviceIntSize::FromAppUnitsRounded(lineScrollAmount
, presContext
->AppUnitsPerDevPixel());
760 metrics
.SetLineScrollAmount(lineScrollAmountInDevPixels
);
763 metrics
.SetScrollId(scrollId
);
764 metrics
.SetIsRoot(aIsRoot
);
765 metrics
.SetScrollParentId(aScrollParentId
);
767 // Only the root scrollable frame for a given presShell should pick up
768 // the presShell's resolution. All the other frames are 1.0.
769 if (aScrollFrame
== presShell
->GetRootScrollFrame()) {
770 metrics
.mPresShellResolution
= presShell
->GetXResolution();
772 metrics
.mPresShellResolution
= 1.0f
;
774 // The cumulative resolution is the resolution at which the scroll frame's
775 // content is actually rendered. It includes the pres shell resolutions of
776 // all the pres shells from here up to the root, as well as any css-driven
777 // resolution. We don't need to compute it as it's already stored in the
778 // container parameters.
779 metrics
.SetCumulativeResolution(LayoutDeviceToLayerScale(aContainerParameters
.mXScale
,
780 aContainerParameters
.mYScale
));
782 LayoutDeviceToScreenScale
resolutionToScreen(
783 presShell
->GetCumulativeResolution().width
784 * nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame
? aScrollFrame
: aForFrame
).width
);
785 metrics
.SetExtraResolution(metrics
.GetCumulativeResolution() / resolutionToScreen
);
787 metrics
.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(
788 (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel
));
790 // Initially, AsyncPanZoomController should render the content to the screen
791 // at the painted resolution.
792 const LayerToParentLayerScale
layerToParentLayerScale(1.0f
);
793 metrics
.SetZoom(metrics
.GetCumulativeResolution() * metrics
.GetDevPixelsPerCSSPixel()
794 * layerToParentLayerScale
);
797 nsIDocument
* document
= nullptr;
798 document
= presShell
->GetDocument();
800 nsCOMPtr
<nsPIDOMWindow
> innerWin(document
->GetInnerWindow());
802 metrics
.SetMayHaveTouchListeners(innerWin
->HasApzAwareEventListeners());
805 metrics
.SetMayHaveTouchCaret(presShell
->MayHaveTouchCaret());
808 // Calculate the composition bounds as the size of the scroll frame and
809 // its origin relative to the reference frame.
810 // If aScrollFrame is null, we are in a document without a root scroll frame,
811 // so it's a xul document. In this case, use the size of the viewport frame.
812 nsIFrame
* frameForCompositionBoundsCalculation
= aScrollFrame
? aScrollFrame
: aForFrame
;
813 nsRect
compositionBounds(frameForCompositionBoundsCalculation
->GetOffsetToCrossDoc(aReferenceFrame
),
814 frameForCompositionBoundsCalculation
->GetSize());
815 if (scrollableFrame
) {
816 // If we have a scrollable frame, restrict the composition bounds to its
817 // scroll port. The scroll port excludes the frame borders and the scroll
818 // bars, which we don't want to be part of the composition bounds.
819 nsRect scrollPort
= scrollableFrame
->GetScrollPortRect();
820 compositionBounds
= nsRect(compositionBounds
.TopLeft() + scrollPort
.TopLeft(),
823 ParentLayerRect frameBounds
= LayoutDeviceRect::FromAppUnits(compositionBounds
, auPerDevPixel
)
824 * metrics
.GetCumulativeResolution()
825 * layerToParentLayerScale
;
826 metrics
.mCompositionBounds
= frameBounds
;
828 // For the root scroll frame of the root content document (RCD-RSF), the above calculation
829 // will yield the size of the viewport frame as the composition bounds, which
830 // doesn't actually correspond to what is visible when
831 // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
832 // the prescontext that the viewport frame is reflowed into. In that case if our
833 // document has a widget then the widget's bounds will correspond to what is
834 // visible. If we don't have a widget the root view's bounds correspond to what
835 // would be visible because they don't get modified by setCSSViewport.
836 bool isRootScrollFrame
= aScrollFrame
== presShell
->GetRootScrollFrame();
837 bool isRootContentDocRootScrollFrame
= isRootScrollFrame
838 && presContext
->IsRootContentDocument();
839 if (isRootContentDocRootScrollFrame
) {
840 if (nsIFrame
* rootFrame
= presShell
->GetRootFrame()) {
841 // On Android, we need to do things a bit differently to get things
842 // right (see bug 983208, bug 988882). We use the bounds of the nearest
843 // widget, but clamp the height to the frame bounds height. This clamping
844 // is done to get correct results for a page where the page is sized to
845 // the screen and thus the dynamic toolbar never disappears. In such a
846 // case, we want the composition bounds to exclude the toolbar height,
847 // but the widget bounds includes it. We don't currently have a good way
848 // of knowing about the toolbar height, but clamping to the frame bounds
849 // height gives the correct answer in the cases we care about.
850 #ifdef MOZ_WIDGET_ANDROID
851 nsIWidget
* widget
= rootFrame
->GetNearestWidget();
853 nsView
* view
= rootFrame
->GetView();
854 nsIWidget
* widget
= view
? view
->GetWidget() : nullptr;
857 nsIntRect widgetBounds
;
858 widget
->GetBounds(widgetBounds
);
859 metrics
.mCompositionBounds
= ParentLayerRect(ViewAs
<ParentLayerPixel
>(widgetBounds
));
860 #ifdef MOZ_WIDGET_ANDROID
861 if (frameBounds
.height
< metrics
.mCompositionBounds
.height
) {
862 metrics
.mCompositionBounds
.height
= frameBounds
.height
;
866 LayoutDeviceIntSize contentSize
;
867 if (nsLayoutUtils::GetContentViewerSize(presContext
, contentSize
)) {
868 LayoutDeviceToParentLayerScale
scale(1.0f
);
869 if (presContext
->GetParentPresContext()) {
870 gfxSize res
= presContext
->GetParentPresContext()->PresShell()->GetCumulativeResolution();
871 scale
= LayoutDeviceToParentLayerScale(res
.width
, res
.height
);
873 metrics
.mCompositionBounds
.SizeTo(contentSize
* scale
);
877 // Exclude any non-overlay scroll bars from the composition bounds.
878 // This is only done for the RCD-RSF case, because otherwise the scroll
879 // port size is used and that already excludes the scroll bars.
880 if (scrollableFrame
&& !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars
)) {
881 nsMargin sizes
= scrollableFrame
->GetActualScrollbarSizes();
882 // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them.
883 ParentLayerMargin boundMargins
= CSSMargin::FromAppUnits(sizes
) * CSSToParentLayerScale(1.0f
);
884 metrics
.mCompositionBounds
.Deflate(boundMargins
);
889 metrics
.SetRootCompositionSize(
890 nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame
? aScrollFrame
: aForFrame
,
891 isRootContentDocRootScrollFrame
, metrics
));
893 if (gfxPrefs::APZPrintTree()) {
894 if (nsIContent
* content
= frameForCompositionBoundsCalculation
->GetContent()) {
895 nsAutoString contentDescription
;
896 content
->Describe(contentDescription
);
897 metrics
.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription
));
901 metrics
.SetPresShellId(presShell
->GetPresShellId());
903 // If the scroll frame's content is marked 'scrollgrab', record this
904 // in the FrameMetrics so APZ knows to provide the scroll grabbing
906 if (aScrollFrame
&& nsContentUtils::HasScrollgrab(aScrollFrame
->GetContent())) {
907 metrics
.SetHasScrollgrab(true);
910 // Also compute and set the background color.
911 // This is needed for APZ overscrolling support.
913 if (isRootScrollFrame
) {
914 metrics
.SetBackgroundColor(presShell
->GetCanvasBackground());
916 nsStyleContext
* backgroundStyle
;
917 if (nsCSSRendering::FindBackground(aScrollFrame
, &backgroundStyle
)) {
918 metrics
.SetBackgroundColor(backgroundStyle
->StyleBackground()->mBackgroundColor
);
926 nsDisplayListBuilder::~nsDisplayListBuilder() {
927 NS_ASSERTION(mFramesMarkedForDisplay
.Length() == 0,
928 "All frames should have been unmarked");
929 NS_ASSERTION(mPresShellStates
.Length() == 0,
930 "All presshells should have been exited");
931 NS_ASSERTION(!mCurrentTableItem
, "No table item should be active");
933 nsCSSRendering::EndFrameTreesLocked();
935 for (uint32_t i
= 0; i
< mDisplayItemClipsToDestroy
.Length(); ++i
) {
936 mDisplayItemClipsToDestroy
[i
]->DisplayItemClip::~DisplayItemClip();
939 PL_FinishArenaPool(&mPool
);
940 MOZ_COUNT_DTOR(nsDisplayListBuilder
);
944 nsDisplayListBuilder::GetBackgroundPaintFlags() {
946 if (mSyncDecodeImages
) {
947 flags
|= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES
;
949 if (mIsPaintingToWindow
) {
950 flags
|= nsCSSRendering::PAINTBG_TO_WINDOW
;
956 nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion
* aVisibleRegion
,
957 const nsRegion
& aRegion
)
959 if (aRegion
.IsEmpty())
963 tmp
.Sub(*aVisibleRegion
, aRegion
);
964 // Don't let *aVisibleRegion get too complex, but don't let it fluff out
965 // to its bounds either, which can be very bad (see bug 516740).
966 // Do let aVisibleRegion get more complex if by doing so we reduce its
967 // area by at least half.
968 if (GetAccurateVisibleRegions() || tmp
.GetNumRects() <= 15 ||
969 tmp
.Area() <= aVisibleRegion
->Area()/2) {
970 *aVisibleRegion
= tmp
;
975 nsDisplayListBuilder::GetCaret() {
976 nsRefPtr
<nsCaret
> caret
= CurrentPresShellState()->mPresShell
->GetCaret();
981 nsDisplayListBuilder::EnterPresShell(nsIFrame
* aReferenceFrame
,
982 bool aPointerEventsNoneDoc
)
984 PresShellState
* state
= mPresShellStates
.AppendElement();
985 state
->mPresShell
= aReferenceFrame
->PresContext()->PresShell();
986 state
->mCaretFrame
= nullptr;
987 state
->mFirstFrameMarkedForDisplay
= mFramesMarkedForDisplay
.Length();
989 state
->mPresShell
->UpdateCanvasBackground();
991 if (mIsPaintingToWindow
) {
992 mReferenceFrame
->AddPaintedPresShell(state
->mPresShell
);
994 state
->mPresShell
->IncrementPaintCount();
997 bool buildCaret
= mBuildCaret
;
998 if (mIgnoreSuppression
|| !state
->mPresShell
->IsPaintingSuppressed()) {
999 if (state
->mPresShell
->IsPaintingSuppressed()) {
1000 mHadToIgnoreSuppression
= true;
1002 state
->mIsBackgroundOnly
= false;
1004 state
->mIsBackgroundOnly
= true;
1008 bool pointerEventsNone
= aPointerEventsNoneDoc
;
1009 if (IsInSubdocument()) {
1010 pointerEventsNone
|= mPresShellStates
[mPresShellStates
.Length() - 2].mInsidePointerEventsNoneDoc
;
1012 state
->mInsidePointerEventsNoneDoc
= pointerEventsNone
;
1017 nsRefPtr
<nsCaret
> caret
= state
->mPresShell
->GetCaret();
1018 state
->mCaretFrame
= caret
->GetPaintGeometry(&state
->mCaretRect
);
1019 if (state
->mCaretFrame
) {
1020 mFramesMarkedForDisplay
.AppendElement(state
->mCaretFrame
);
1021 MarkFrameForDisplay(state
->mCaretFrame
, nullptr);
1026 nsDisplayListBuilder::LeavePresShell(nsIFrame
* aReferenceFrame
)
1028 NS_ASSERTION(CurrentPresShellState()->mPresShell
==
1029 aReferenceFrame
->PresContext()->PresShell(),
1030 "Presshell mismatch");
1031 ResetMarkedFramesForDisplayList();
1032 mPresShellStates
.SetLength(mPresShellStates
.Length() - 1);
1036 nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
1038 // Unmark and pop off the frames marked for display in this pres shell.
1039 uint32_t firstFrameForShell
= CurrentPresShellState()->mFirstFrameMarkedForDisplay
;
1040 for (uint32_t i
= firstFrameForShell
;
1041 i
< mFramesMarkedForDisplay
.Length(); ++i
) {
1042 UnmarkFrameForDisplay(mFramesMarkedForDisplay
[i
]);
1044 mFramesMarkedForDisplay
.SetLength(firstFrameForShell
);
1048 nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame
* aDirtyFrame
,
1049 const nsFrameList
& aFrames
,
1050 const nsRect
& aDirtyRect
) {
1051 mFramesMarkedForDisplay
.SetCapacity(mFramesMarkedForDisplay
.Length() + aFrames
.GetLength());
1052 for (nsFrameList::Enumerator
e(aFrames
); !e
.AtEnd(); e
.Next()) {
1053 mFramesMarkedForDisplay
.AppendElement(e
.get());
1054 MarkOutOfFlowFrameForDisplay(aDirtyFrame
, e
.get(), aDirtyRect
);
1059 nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame
* aDirtyFrame
, const nsRect
& aDirtyRect
)
1061 nsAutoTArray
<nsIFrame::ChildList
,4> childListArray
;
1062 aDirtyFrame
->GetChildLists(&childListArray
);
1063 nsIFrame::ChildListArrayIterator
lists(childListArray
);
1064 for (; !lists
.IsDone(); lists
.Next()) {
1065 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1066 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1067 nsIFrame
*child
= childFrames
.get();
1068 if (child
->Preserves3D()) {
1069 mFramesMarkedForDisplay
.AppendElement(child
);
1070 nsRect dirty
= aDirtyRect
- child
->GetOffsetTo(aDirtyFrame
);
1072 child
->Properties().Set(nsDisplayListBuilder::Preserve3DDirtyRectProperty(),
1075 MarkFrameForDisplay(child
, aDirtyFrame
);
1082 nsDisplayListBuilder::Allocate(size_t aSize
)
1085 PL_ARENA_ALLOCATE(tmp
, &mPool
, aSize
);
1087 NS_ABORT_OOM(aSize
);
1092 const DisplayItemClip
*
1093 nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip
& aOriginal
)
1095 void* p
= Allocate(sizeof(DisplayItemClip
));
1096 if (!aOriginal
.GetRoundedRectCount()) {
1097 memcpy(p
, &aOriginal
, sizeof(DisplayItemClip
));
1098 return static_cast<DisplayItemClip
*>(p
);
1101 DisplayItemClip
* c
= new (p
) DisplayItemClip(aOriginal
);
1102 mDisplayItemClipsToDestroy
.AppendElement(c
);
1107 nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame
*aFrame
,
1110 if (aFrame
== mCurrentFrame
) {
1112 *aOffset
= mCurrentOffsetToReferenceFrame
;
1114 return mCurrentReferenceFrame
;
1116 for (const nsIFrame
* f
= aFrame
; f
; f
= nsLayoutUtils::GetCrossDocParentFrame(f
))
1118 if (f
== mReferenceFrame
|| f
->IsTransformed()) {
1120 *aOffset
= aFrame
->GetOffsetToCrossDoc(f
);
1126 *aOffset
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
1128 return mReferenceFrame
;
1131 // Sticky frames are active if their nearest scrollable frame is also active.
1133 IsStickyFrameActive(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
, nsIFrame
* aParent
)
1135 MOZ_ASSERT(aFrame
->StyleDisplay()->mPosition
== NS_STYLE_POSITION_STICKY
);
1137 // Find the nearest scrollframe.
1138 nsIFrame
* cursor
= aFrame
;
1139 nsIFrame
* parent
= aParent
;
1140 while (parent
->GetType() != nsGkAtoms::scrollFrame
) {
1142 if ((parent
= nsLayoutUtils::GetCrossDocParentFrame(cursor
)) == nullptr) {
1147 nsIScrollableFrame
* sf
= do_QueryFrame(parent
);
1148 return sf
->IsScrollingActive(aBuilder
) && sf
->GetScrolledFrame() == cursor
;
1152 nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame
* aFrame
, nsIFrame
** aParent
)
1154 if (nsLayoutUtils::IsPopup(aFrame
))
1156 if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame
))
1158 if (!aFrame
->GetParent() &&
1159 nsLayoutUtils::ViewportHasDisplayPort(aFrame
->PresContext())) {
1160 // Viewport frames in a display port need to be animated geometry roots
1161 // for background-attachment:fixed elements.
1165 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrame(aFrame
);
1169 nsIAtom
* parentType
= parent
->GetType();
1170 // Treat the slider thumb as being as an active scrolled root when it wants
1171 // its own layer so that it can move without repainting.
1172 if (parentType
== nsGkAtoms::sliderFrame
&& nsLayoutUtils::IsScrollbarThumbLayerized(aFrame
)) {
1176 if (aFrame
->StyleDisplay()->mPosition
== NS_STYLE_POSITION_STICKY
&&
1177 IsStickyFrameActive(this, aFrame
, parent
))
1182 if (parentType
== nsGkAtoms::scrollFrame
|| parentType
== nsGkAtoms::listControlFrame
) {
1183 nsIScrollableFrame
* sf
= do_QueryFrame(parent
);
1184 if (sf
->IsScrollingActive(this) && sf
->GetScrolledFrame() == aFrame
) {
1189 // Fixed-pos frames are parented by the viewport frame, which has no parent.
1190 if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame
)) {
1201 nsDisplayListBuilder::GetCachedAnimatedGeometryRoot(const nsIFrame
* aFrame
,
1202 const nsIFrame
* aStopAtAncestor
,
1203 nsIFrame
** aOutResult
)
1205 AnimatedGeometryRootLookup
lookup(aFrame
, aStopAtAncestor
);
1206 return mAnimatedGeometryRootCache
.Get(lookup
, aOutResult
);
1210 ComputeAnimatedGeometryRootFor(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
1211 const nsIFrame
* aStopAtAncestor
= nullptr,
1212 bool aUseCache
= false)
1214 nsIFrame
* cursor
= aFrame
;
1215 while (cursor
!= aStopAtAncestor
) {
1218 if (aBuilder
->GetCachedAnimatedGeometryRoot(cursor
, aStopAtAncestor
, &result
)) {
1223 if (aBuilder
->IsAnimatedGeometryRoot(cursor
, &next
))
1231 nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame
* aFrame
, const nsIFrame
* aStopAtAncestor
)
1233 if (aFrame
== mCurrentFrame
) {
1234 return mCurrentAnimatedGeometryRoot
;
1237 nsIFrame
* result
= ComputeAnimatedGeometryRootFor(this, aFrame
, aStopAtAncestor
, true);
1238 AnimatedGeometryRootLookup
lookup(aFrame
, aStopAtAncestor
);
1239 mAnimatedGeometryRootCache
.Put(lookup
, result
);
1244 nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
1246 mCurrentAnimatedGeometryRoot
= ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame
*>(mCurrentFrame
));
1247 AnimatedGeometryRootLookup
lookup(mCurrentFrame
, nullptr);
1248 mAnimatedGeometryRootCache
.Put(lookup
, mCurrentAnimatedGeometryRoot
);
1252 nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame
* aFrame
)
1254 if (!IsForPainting() || IsInSubdocument()) {
1258 Matrix4x4 referenceFrameToRootReferenceFrame
;
1260 // The const_cast is for nsLayoutUtils::GetTransformToAncestor.
1261 nsIFrame
* referenceFrame
= const_cast<nsIFrame
*>(FindReferenceFrameFor(aFrame
));
1263 if (IsInTransform()) {
1264 // Only support 2d rectilinear transforms. Transform support is needed for
1265 // the horizontal flip transform that's applied to the urlbar textbox in
1266 // RTL mode - it should be able to exclude itself from the draggable region.
1267 referenceFrameToRootReferenceFrame
=
1268 nsLayoutUtils::GetTransformToAncestor(referenceFrame
, mReferenceFrame
);
1269 Matrix referenceFrameToRootReferenceFrame2d
;
1270 if (!referenceFrameToRootReferenceFrame
.Is2D(&referenceFrameToRootReferenceFrame2d
) ||
1271 !referenceFrameToRootReferenceFrame2d
.IsRectilinear()) {
1275 MOZ_ASSERT(referenceFrame
== mReferenceFrame
,
1276 "referenceFrameToRootReferenceFrame needs to be adjusted");
1279 // We do some basic visibility checking on the frame's border box here.
1280 // We intersect it both with the current dirty rect and with the current
1281 // clip. Either one is just a conservative approximation on its own, but
1282 // their intersection luckily works well enough for our purposes, so that
1283 // we don't have to do full-blown visibility computations.
1284 // The most important case we need to handle is the scrolled-off tab:
1285 // If the tab bar overflows, tab parts that are clipped by the scrollbox
1286 // should not be allowed to interfere with the window dragging region. Using
1287 // just the current DisplayItemClip is not enough to cover this case
1288 // completely because clips are reset while building stacking context
1289 // contents, so for example we'd fail to clip frames that have a clip path
1290 // applied to them. But the current dirty rect doesn't get reset in that
1291 // case, so we use it to make this case work.
1292 nsRect borderBox
= aFrame
->GetRectRelativeToSelf().Intersect(mDirtyRect
);
1293 borderBox
+= ToReferenceFrame(aFrame
);
1294 const DisplayItemClip
* clip
= ClipState().GetCurrentCombinedClip(this);
1296 borderBox
= clip
->ApplyNonRoundedIntersection(borderBox
);
1298 if (!borderBox
.IsEmpty()) {
1299 LayoutDeviceRect devPixelBorderBox
=
1300 LayoutDevicePixel::FromAppUnits(borderBox
, aFrame
->PresContext()->AppUnitsPerDevPixel());
1301 LayoutDeviceRect transformedDevPixelBorderBox
=
1302 TransformTo
<LayoutDevicePixel
>(referenceFrameToRootReferenceFrame
, devPixelBorderBox
);
1303 transformedDevPixelBorderBox
.Round();
1304 LayoutDeviceIntRect transformedDevPixelBorderBoxInt
;
1305 if (transformedDevPixelBorderBox
.ToIntRect(&transformedDevPixelBorderBoxInt
)) {
1306 const nsStyleUserInterface
* styleUI
= aFrame
->StyleUserInterface();
1307 if (styleUI
->mWindowDragging
== NS_STYLE_WINDOW_DRAGGING_DRAG
) {
1308 mWindowDraggingRegion
.OrWith(LayoutDevicePixel::ToUntyped(transformedDevPixelBorderBoxInt
));
1310 mWindowDraggingRegion
.SubOut(LayoutDevicePixel::ToUntyped(transformedDevPixelBorderBoxInt
));
1317 nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame
* aFrame
, const nsSize
& aRect
) {
1318 // Make sure that we don't query the budget before the display list is fully
1319 // built and that the will change budget is locked in.
1320 NS_ASSERTION(!mWillChangeBudgetCalculated
,
1321 "Can't modify the budget once it's been used.");
1323 DocumentWillChangeBudget budget
;
1325 nsPresContext
* key
= aFrame
->PresContext();
1326 if (mWillChangeBudget
.Contains(key
)) {
1327 mWillChangeBudget
.Get(key
, &budget
);
1330 // There's significant overhead for each layer created from Gecko
1331 // (IPC+Shared Objects) and from the backend (like an OpenGL texture).
1332 // Therefore we set a minimum cost threshold of a 64x64 area.
1333 int minBudgetCost
= 64 * 64;
1336 std::max(minBudgetCost
,
1337 nsPresContext::AppUnitsToIntCSSPixels(aRect
.width
) *
1338 nsPresContext::AppUnitsToIntCSSPixels(aRect
.height
));
1340 mWillChangeBudget
.Put(key
, budget
);
1344 nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame
* aFrame
) const {
1345 uint32_t multiplier
= 3;
1347 mWillChangeBudgetCalculated
= true;
1349 nsPresContext
* key
= aFrame
->PresContext();
1350 if (!mWillChangeBudget
.Contains(key
)) {
1351 NS_ASSERTION(false, "If we added nothing to our budget then this "
1352 "shouldn't be called.");
1356 DocumentWillChangeBudget budget
;
1357 mWillChangeBudget
.Get(key
, &budget
);
1359 nsRect area
= aFrame
->PresContext()->GetVisibleArea();
1360 uint32_t budgetLimit
= nsPresContext::AppUnitsToIntCSSPixels(area
.width
) *
1361 nsPresContext::AppUnitsToIntCSSPixels(area
.height
);
1363 bool onBudget
= budget
.mBudget
/ multiplier
< budgetLimit
;
1366 usageStr
.AppendInt(budget
.mBudget
);
1368 nsString multiplierStr
;
1369 multiplierStr
.AppendInt(multiplier
);
1372 limitStr
.AppendInt(budgetLimit
);
1374 const char16_t
* params
[] = { usageStr
.get(), multiplierStr
.get(), limitStr
.get() };
1375 key
->Document()->WarnOnceAbout(nsIDocument::eWillChangeBudget
, false,
1376 params
, ArrayLength(params
));
1381 void nsDisplayListSet::MoveTo(const nsDisplayListSet
& aDestination
) const
1383 aDestination
.BorderBackground()->AppendToTop(BorderBackground());
1384 aDestination
.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
1385 aDestination
.Floats()->AppendToTop(Floats());
1386 aDestination
.Content()->AppendToTop(Content());
1387 aDestination
.PositionedDescendants()->AppendToTop(PositionedDescendants());
1388 aDestination
.Outlines()->AppendToTop(Outlines());
1392 MoveListTo(nsDisplayList
* aList
, nsTArray
<nsDisplayItem
*>* aElements
) {
1393 nsDisplayItem
* item
;
1394 while ((item
= aList
->RemoveBottom()) != nullptr) {
1395 aElements
->AppendElement(item
);
1400 nsDisplayList::GetBounds(nsDisplayListBuilder
* aBuilder
) const {
1402 for (nsDisplayItem
* i
= GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
1403 bounds
.UnionRect(bounds
, i
->GetClippedBounds(aBuilder
));
1409 nsDisplayList::GetVisibleRect() const {
1411 for (nsDisplayItem
* i
= GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
1412 result
.UnionRect(result
, i
->GetVisibleRect());
1418 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder
* aBuilder
,
1419 nsRegion
* aVisibleRegion
,
1420 nsIFrame
* aDisplayPortFrame
) {
1421 PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
1422 js::ProfileEntry::Category::GRAPHICS
);
1425 r
.And(*aVisibleRegion
, GetBounds(aBuilder
));
1426 return ComputeVisibilityForSublist(aBuilder
, aVisibleRegion
,
1427 r
.GetBounds(), aDisplayPortFrame
);
1431 TreatAsOpaque(nsDisplayItem
* aItem
, nsDisplayListBuilder
* aBuilder
)
1434 nsRegion opaque
= aItem
->GetOpaqueRegion(aBuilder
, &snap
);
1435 if (aBuilder
->IsForPluginGeometry() &&
1436 aItem
->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS
)
1438 // Treat all leaf chrome items as opaque, unless their frames are opacity:0.
1439 // Since opacity:0 frames generate an nsDisplayOpacity, that item will
1440 // not be treated as opaque here, so opacity:0 chrome content will be
1441 // effectively ignored, as it should be.
1442 // We treat leaf chrome items as opaque to ensure that they cover
1443 // content plugins, for security reasons.
1444 // Non-leaf chrome items don't render contents of their own so shouldn't
1445 // be treated as opaque (and their bounds is just the union of their
1446 // children, which might be a large area their contents don't really cover).
1447 nsIFrame
* f
= aItem
->Frame();
1448 if (f
->PresContext()->IsChrome() && !aItem
->GetChildren() &&
1449 f
->StyleDisplay()->mOpacity
!= 0.0) {
1450 opaque
= aItem
->GetBounds(aBuilder
, &snap
);
1453 if (opaque
.IsEmpty()) {
1456 nsRegion opaqueClipped
;
1457 nsRegionRectIterator
iter(opaque
);
1458 for (const nsRect
* r
= iter
.Next(); r
; r
= iter
.Next()) {
1459 opaqueClipped
.Or(opaqueClipped
, aItem
->GetClip().ApproximateIntersectInward(*r
));
1461 return opaqueClipped
;
1465 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder
* aBuilder
,
1466 nsRegion
* aVisibleRegion
,
1467 const nsRect
& aListVisibleBounds
,
1468 nsIFrame
* aDisplayPortFrame
) {
1471 r
.And(*aVisibleRegion
, GetBounds(aBuilder
));
1472 NS_ASSERTION(r
.GetBounds().IsEqualInterior(aListVisibleBounds
),
1473 "bad aListVisibleBounds");
1476 bool anyVisible
= false;
1478 nsAutoTArray
<nsDisplayItem
*, 512> elements
;
1479 MoveListTo(this, &elements
);
1481 for (int32_t i
= elements
.Length() - 1; i
>= 0; --i
) {
1482 nsDisplayItem
* item
= elements
[i
];
1483 nsRect bounds
= item
->GetClippedBounds(aBuilder
);
1485 nsRegion itemVisible
;
1486 itemVisible
.And(*aVisibleRegion
, bounds
);
1487 item
->mVisibleRect
= itemVisible
.GetBounds();
1489 if (item
->ComputeVisibility(aBuilder
, aVisibleRegion
)) {
1492 nsRegion opaque
= TreatAsOpaque(item
, aBuilder
);
1493 // Subtract opaque item from the visible region
1494 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, opaque
);
1496 AppendToBottom(item
);
1499 mIsOpaque
= !aVisibleRegion
->Intersects(aListVisibleBounds
);
1504 StartPendingAnimationsOnSubDocuments(nsIDocument
* aDocument
, void* aReadyTime
)
1506 PendingPlayerTracker
* tracker
= aDocument
->GetPendingPlayerTracker();
1508 nsIPresShell
* shell
= aDocument
->GetShell();
1509 // If paint-suppression is in effect then we haven't finished painting
1510 // this document yet so we shouldn't start animations
1511 if (!shell
|| !shell
->IsPaintingSuppressed()) {
1512 const TimeStamp
& readyTime
= *static_cast<TimeStamp
*>(aReadyTime
);
1513 tracker
->StartPendingPlayersOnNextTick(readyTime
);
1516 aDocument
->EnumerateSubDocuments(StartPendingAnimationsOnSubDocuments
,
1522 StartPendingAnimations(nsIDocument
* aDocument
,
1523 const TimeStamp
& aReadyTime
) {
1524 MOZ_ASSERT(!aReadyTime
.IsNull(),
1525 "Animation ready time is not set. Perhaps we're using a layer"
1526 " manager that doesn't update it");
1527 StartPendingAnimationsOnSubDocuments(aDocument
,
1528 const_cast<TimeStamp
*>(&aReadyTime
));
1532 * We paint by executing a layer manager transaction, constructing a
1533 * single layer representing the display list, and then making it the
1534 * root of the layer manager, drawing into the PaintedLayers.
1536 already_AddRefed
<LayerManager
> nsDisplayList::PaintRoot(nsDisplayListBuilder
* aBuilder
,
1537 nsRenderingContext
* aCtx
,
1539 PROFILER_LABEL("nsDisplayList", "PaintRoot",
1540 js::ProfileEntry::Category::GRAPHICS
);
1542 nsRefPtr
<LayerManager
> layerManager
;
1543 bool widgetTransaction
= false;
1544 bool allowRetaining
= false;
1545 bool doBeginTransaction
= true;
1546 nsView
*view
= nullptr;
1547 if (aFlags
& PAINT_USE_WIDGET_LAYERS
) {
1548 nsIFrame
* rootReferenceFrame
= aBuilder
->RootReferenceFrame();
1549 view
= rootReferenceFrame
->GetView();
1550 NS_ASSERTION(rootReferenceFrame
== nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame
),
1551 "Reference frame must be a display root for us to use the layer manager");
1552 nsIWidget
* window
= rootReferenceFrame
->GetNearestWidget();
1554 layerManager
= window
->GetLayerManager(&allowRetaining
);
1556 doBeginTransaction
= !(aFlags
& PAINT_EXISTING_TRANSACTION
);
1557 widgetTransaction
= true;
1561 if (!layerManager
) {
1563 NS_WARNING("Nowhere to paint into");
1566 layerManager
= new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN
);
1569 // Store the existing layer builder to reinstate it on return.
1570 FrameLayerBuilder
*oldBuilder
= layerManager
->GetLayerBuilder();
1572 FrameLayerBuilder
*layerBuilder
= new FrameLayerBuilder();
1573 layerBuilder
->Init(aBuilder
, layerManager
);
1575 if (aFlags
& PAINT_COMPRESSED
) {
1576 layerBuilder
->SetLayerTreeCompressionMode();
1579 if (aFlags
& PAINT_FLUSH_LAYERS
) {
1580 FrameLayerBuilder::InvalidateAllLayers(layerManager
);
1583 if (doBeginTransaction
) {
1585 layerManager
->BeginTransactionWithTarget(aCtx
->ThebesContext());
1587 layerManager
->BeginTransaction();
1590 if (widgetTransaction
) {
1591 layerBuilder
->DidBeginRetainedLayerTransaction(layerManager
);
1594 nsIFrame
* frame
= aBuilder
->RootReferenceFrame();
1595 nsPresContext
* presContext
= frame
->PresContext();
1596 nsIPresShell
* presShell
= presContext
->GetPresShell();
1598 NotifySubDocInvalidationFunc computeInvalidFunc
=
1599 presContext
->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation
: 0;
1600 bool computeInvalidRect
= (computeInvalidFunc
||
1601 (!layerManager
->IsCompositingCheap() && layerManager
->NeedsWidgetInvalidation())) &&
1604 UniquePtr
<LayerProperties
> props
;
1605 if (computeInvalidRect
) {
1606 props
= Move(LayerProperties::CloneFrom(layerManager
->GetRoot()));
1609 ContainerLayerParameters containerParameters
1610 (presShell
->GetXResolution(), presShell
->GetYResolution());
1611 nsRefPtr
<ContainerLayer
> root
= layerBuilder
->
1612 BuildContainerLayerFor(aBuilder
, layerManager
, frame
, nullptr, this,
1613 containerParameters
, nullptr);
1615 nsIDocument
* document
= nullptr;
1617 document
= presShell
->GetDocument();
1621 layerManager
->SetUserData(&gLayerManagerLayerBuilder
, oldBuilder
);
1624 // Root is being scaled up by the X/Y resolution. Scale it back down.
1625 root
->SetPostScale(1.0f
/containerParameters
.mXScale
,
1626 1.0f
/containerParameters
.mYScale
);
1627 root
->SetScaleToResolution(presShell
->ScaleToResolution(),
1628 containerParameters
.mXScale
);
1629 if (aBuilder
->IsBuildingLayerEventRegions() &&
1630 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell
)) {
1631 root
->SetEventRegionsOverride(EventRegionsOverride::ForceDispatchToContent
);
1633 root
->SetEventRegionsOverride(EventRegionsOverride::NoOverride
);
1636 if (gfxPrefs::LayoutUseContainersForRootFrames()) {
1637 bool isRoot
= presContext
->IsRootContentDocument();
1639 nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame();
1641 nsRect
viewport(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
1643 root
->SetFrameMetrics(
1644 nsDisplayScrollLayer::ComputeFrameMetrics(frame
, rootScrollFrame
,
1645 aBuilder
->FindReferenceFrameFor(frame
),
1646 root
, FrameMetrics::NULL_SCROLL_ID
, viewport
,
1647 isRoot
, containerParameters
));
1650 // NS_WARNING is debug-only, so don't even bother checking the conditions in
1653 bool usingDisplayport
= false;
1654 if (nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame()) {
1655 nsIContent
* content
= rootScrollFrame
->GetContent();
1657 usingDisplayport
= nsLayoutUtils::GetDisplayPort(content
, nullptr);
1660 if (usingDisplayport
&&
1661 !(root
->GetContentFlags() & Layer::CONTENT_OPAQUE
) &&
1662 SpammyLayoutWarningsEnabled()) {
1663 // See bug 693938, attachment 567017
1664 NS_WARNING("Transparent content with displayports can be expensive.");
1668 layerManager
->SetRoot(root
);
1669 layerBuilder
->WillEndTransaction();
1671 if (widgetTransaction
||
1672 // SVG-as-an-image docs don't paint as part of the retained layer tree,
1673 // but they still need the invalidation state bits cleared in order for
1674 // invalidation for CSS/SMIL animation to work properly.
1675 (document
&& document
->IsBeingUsedAsImage())) {
1676 frame
->ClearInvalidationStateBits();
1679 bool temp
= aBuilder
->SetIsCompositingCheap(layerManager
->IsCompositingCheap());
1680 LayerManager::EndTransactionFlags flags
= LayerManager::END_DEFAULT
;
1681 if (layerManager
->NeedsWidgetInvalidation()) {
1682 if (aFlags
& PAINT_NO_COMPOSITE
) {
1683 flags
= LayerManager::END_NO_COMPOSITE
;
1686 // Client layer managers never composite directly, so
1687 // we don't need to worry about END_NO_COMPOSITE.
1688 if (aBuilder
->WillComputePluginGeometry()) {
1689 flags
= LayerManager::END_NO_REMOTE_COMPOSITE
;
1693 MaybeSetupTransactionIdAllocator(layerManager
, view
);
1695 layerManager
->EndTransaction(FrameLayerBuilder::DrawPaintedLayer
,
1697 aBuilder
->SetIsCompositingCheap(temp
);
1698 layerBuilder
->DidEndTransaction();
1700 if (document
&& widgetTransaction
) {
1701 StartPendingAnimations(document
, layerManager
->GetAnimationReadyTime());
1704 nsIntRegion invalid
;
1706 invalid
= props
->ComputeDifferences(root
, computeInvalidFunc
);
1707 } else if (widgetTransaction
) {
1708 LayerProperties::ClearInvalidations(root
);
1711 bool shouldInvalidate
= layerManager
->NeedsWidgetInvalidation();
1714 if (!invalid
.IsEmpty()) {
1715 nsIntRect bounds
= invalid
.GetBounds();
1716 nsRect
rect(presContext
->DevPixelsToAppUnits(bounds
.x
),
1717 presContext
->DevPixelsToAppUnits(bounds
.y
),
1718 presContext
->DevPixelsToAppUnits(bounds
.width
),
1719 presContext
->DevPixelsToAppUnits(bounds
.height
));
1720 if (shouldInvalidate
) {
1721 view
->GetViewManager()->InvalidateViewNoSuppression(view
, rect
);
1723 presContext
->NotifyInvalidation(bounds
, 0);
1725 } else if (shouldInvalidate
) {
1726 view
->GetViewManager()->InvalidateView(view
);
1730 if (aFlags
& PAINT_FLUSH_LAYERS
) {
1731 FrameLayerBuilder::InvalidateAllLayers(layerManager
);
1734 layerManager
->SetUserData(&gLayerManagerLayerBuilder
, oldBuilder
);
1735 return layerManager
.forget();
1738 uint32_t nsDisplayList::Count() const {
1740 for (nsDisplayItem
* i
= GetBottom(); i
; i
= i
->GetAbove()) {
1746 nsDisplayItem
* nsDisplayList::RemoveBottom() {
1747 nsDisplayItem
* item
= mSentinel
.mAbove
;
1750 mSentinel
.mAbove
= item
->mAbove
;
1752 // must have been the only item
1755 item
->mAbove
= nullptr;
1759 void nsDisplayList::DeleteAll() {
1760 nsDisplayItem
* item
;
1761 while ((item
= RemoveBottom()) != nullptr) {
1762 item
->~nsDisplayItem();
1767 GetMouseThrough(const nsIFrame
* aFrame
)
1769 if (!aFrame
->IsBoxFrame())
1772 const nsIFrame
* frame
= aFrame
;
1774 if (frame
->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS
) {
1776 } else if (frame
->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER
) {
1779 frame
= nsBox::GetParentBox(frame
);
1785 IsFrameReceivingPointerEvents(nsIFrame
* aFrame
)
1787 nsSubDocumentFrame
* frame
= do_QueryFrame(aFrame
);
1788 if (frame
&& frame
->PassPointerEventsToChildren()) {
1791 return NS_STYLE_POINTER_EVENTS_NONE
!=
1792 aFrame
->StyleVisibility()->GetEffectivePointerEvents(aFrame
);
1795 // A list of frames, and their z depth. Used for sorting
1796 // the results of hit testing.
1797 struct FramesWithDepth
1799 explicit FramesWithDepth(float aDepth
) :
1803 bool operator<(const FramesWithDepth
& aOther
) const {
1804 if (mDepth
!= aOther
.mDepth
) {
1805 // We want to sort so that the shallowest item (highest depth value) is first
1806 return mDepth
> aOther
.mDepth
;
1808 return this < &aOther
;
1810 bool operator==(const FramesWithDepth
& aOther
) const {
1811 return this == &aOther
;
1815 nsTArray
<nsIFrame
*> mFrames
;
1818 // Sort the frames by depth and then moves all the contained frames to the destination
1819 void FlushFramesArray(nsTArray
<FramesWithDepth
>& aSource
, nsTArray
<nsIFrame
*>* aDest
)
1821 if (aSource
.IsEmpty()) {
1825 uint32_t length
= aSource
.Length();
1826 for (uint32_t i
= 0; i
< length
; i
++) {
1827 aDest
->MoveElementsFrom(aSource
[i
].mFrames
);
1832 void nsDisplayList::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
1833 nsDisplayItem::HitTestState
* aState
,
1834 nsTArray
<nsIFrame
*> *aOutFrames
) const {
1835 int32_t itemBufferStart
= aState
->mItemBuffer
.Length();
1836 nsDisplayItem
* item
;
1837 for (item
= GetBottom(); item
; item
= item
->GetAbove()) {
1838 aState
->mItemBuffer
.AppendElement(item
);
1840 nsAutoTArray
<FramesWithDepth
, 16> temp
;
1841 for (int32_t i
= aState
->mItemBuffer
.Length() - 1; i
>= itemBufferStart
; --i
) {
1842 // Pop element off the end of the buffer. We want to shorten the buffer
1843 // so that recursive calls to HitTest have more buffer space.
1844 item
= aState
->mItemBuffer
[i
];
1845 aState
->mItemBuffer
.SetLength(i
);
1848 nsRect r
= item
->GetBounds(aBuilder
, &snap
).Intersect(aRect
);
1849 if (item
->GetClip().MayIntersect(r
)) {
1850 nsAutoTArray
<nsIFrame
*, 16> outFrames
;
1851 item
->HitTest(aBuilder
, aRect
, aState
, &outFrames
);
1853 // For 3d transforms with preserve-3d we add hit frames into the temp list
1854 // so we can sort them later, otherwise we add them directly to the output list.
1855 nsTArray
<nsIFrame
*> *writeFrames
= aOutFrames
;
1856 if (item
->GetType() == nsDisplayItem::TYPE_TRANSFORM
&&
1857 item
->Frame()->Preserves3D()) {
1858 if (outFrames
.Length()) {
1859 nsDisplayTransform
*transform
= static_cast<nsDisplayTransform
*>(item
);
1860 nsPoint point
= aRect
.TopLeft();
1861 // A 1x1 rect means a point, otherwise use the center of the rect
1862 if (aRect
.width
!= 1 || aRect
.height
!= 1) {
1863 point
= aRect
.Center();
1865 temp
.AppendElement(FramesWithDepth(transform
->GetHitDepthAtPoint(aBuilder
, point
)));
1866 writeFrames
= &temp
[temp
.Length() - 1].mFrames
;
1869 // We may have just finished a run of consecutive preserve-3d transforms,
1870 // so flush these into the destination array before processing our frame list.
1871 FlushFramesArray(temp
, aOutFrames
);
1874 for (uint32_t j
= 0; j
< outFrames
.Length(); j
++) {
1875 nsIFrame
*f
= outFrames
.ElementAt(j
);
1876 // Handle the XUL 'mousethrough' feature and 'pointer-events'.
1877 if (!GetMouseThrough(f
) && IsFrameReceivingPointerEvents(f
)) {
1878 writeFrames
->AppendElement(f
);
1883 // Clear any remaining preserve-3d transforms.
1884 FlushFramesArray(temp
, aOutFrames
);
1885 NS_ASSERTION(aState
->mItemBuffer
.Length() == uint32_t(itemBufferStart
),
1886 "How did we forget to pop some elements?");
1889 static void Sort(nsDisplayList
* aList
, int32_t aCount
, nsDisplayList::SortLEQ aCmp
,
1894 nsDisplayList list1
;
1895 nsDisplayList list2
;
1897 int32_t half
= aCount
/2;
1899 nsDisplayItem
* prev
= nullptr;
1900 for (i
= 0; i
< aCount
; ++i
) {
1901 nsDisplayItem
* item
= aList
->RemoveBottom();
1902 (i
< half
? &list1
: &list2
)->AppendToTop(item
);
1903 if (sorted
&& prev
&& !aCmp(prev
, item
, aClosure
)) {
1909 aList
->AppendToTop(&list1
);
1910 aList
->AppendToTop(&list2
);
1914 Sort(&list1
, half
, aCmp
, aClosure
);
1915 Sort(&list2
, aCount
- half
, aCmp
, aClosure
);
1917 for (i
= 0; i
< aCount
; ++i
) {
1918 if (list1
.GetBottom() &&
1919 (!list2
.GetBottom() ||
1920 aCmp(list1
.GetBottom(), list2
.GetBottom(), aClosure
))) {
1921 aList
->AppendToTop(list1
.RemoveBottom());
1923 aList
->AppendToTop(list2
.RemoveBottom());
1928 static nsIContent
* FindContentInDocument(nsDisplayItem
* aItem
, nsIDocument
* aDoc
) {
1929 nsIFrame
* f
= aItem
->Frame();
1931 nsPresContext
* pc
= f
->PresContext();
1932 if (pc
->Document() == aDoc
) {
1933 return f
->GetContent();
1935 f
= nsLayoutUtils::GetCrossDocParentFrame(pc
->PresShell()->GetRootFrame());
1940 static bool IsContentLEQ(nsDisplayItem
* aItem1
, nsDisplayItem
* aItem2
,
1942 nsIContent
* commonAncestor
= static_cast<nsIContent
*>(aClosure
);
1943 // It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument
1944 // of commonAncestor, because display items for subdocuments have been
1945 // mixed into the same list. Ensure that we're looking at content
1946 // in commonAncestor's document.
1947 nsIDocument
* commonAncestorDoc
= commonAncestor
->OwnerDoc();
1948 nsIContent
* content1
= FindContentInDocument(aItem1
, commonAncestorDoc
);
1949 nsIContent
* content2
= FindContentInDocument(aItem2
, commonAncestorDoc
);
1950 if (!content1
|| !content2
) {
1951 NS_ERROR("Document trees are mixed up!");
1952 // Something weird going on
1955 return nsLayoutUtils::CompareTreePosition(content1
, content2
, commonAncestor
) <= 0;
1958 static bool IsZOrderLEQ(nsDisplayItem
* aItem1
, nsDisplayItem
* aItem2
,
1960 // Note that we can't just take the difference of the two
1961 // z-indices here, because that might overflow a 32-bit int.
1962 return aItem1
->ZIndex() <= aItem2
->ZIndex();
1965 void nsDisplayList::SortByZOrder(nsDisplayListBuilder
* aBuilder
,
1966 nsIContent
* aCommonAncestor
) {
1967 Sort(aBuilder
, IsZOrderLEQ
, aCommonAncestor
);
1970 void nsDisplayList::SortByContentOrder(nsDisplayListBuilder
* aBuilder
,
1971 nsIContent
* aCommonAncestor
) {
1972 Sort(aBuilder
, IsContentLEQ
, aCommonAncestor
);
1975 void nsDisplayList::Sort(nsDisplayListBuilder
* aBuilder
,
1976 SortLEQ aCmp
, void* aClosure
) {
1977 ::Sort(this, Count(), aCmp
, aClosure
);
1980 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
1982 , mClip(aBuilder
->ClipState().GetCurrentCombinedClip(aBuilder
))
1983 #ifdef MOZ_DUMP_PAINTING
1987 mReferenceFrame
= aBuilder
->FindReferenceFrameFor(aFrame
, &mToReferenceFrame
);
1988 NS_ASSERTION(aBuilder
->GetDirtyRect().width
>= 0 ||
1989 !aBuilder
->IsForPainting(), "dirty rect not set");
1990 // The dirty rect is for mCurrentFrame, so we have to use
1991 // mCurrentOffsetToReferenceFrame
1992 mVisibleRect
= aBuilder
->GetDirtyRect() +
1993 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
1997 nsDisplayItem::ForceActiveLayers()
1999 static bool sForce
= false;
2000 static bool sForceCached
= false;
2002 if (!sForceCached
) {
2003 Preferences::AddBoolVarCache(&sForce
, "layers.force-active", false);
2004 sForceCached
= true;
2010 /* static */ int32_t
2011 nsDisplayItem::MaxActiveLayers()
2013 static int32_t sMaxLayers
= false;
2014 static bool sMaxLayersCached
= false;
2016 if (!sMaxLayersCached
) {
2017 Preferences::AddIntVarCache(&sMaxLayers
, "layers.max-active", -1);
2018 sMaxLayersCached
= true;
2025 nsDisplayItem::ZIndex() const
2027 if (!mFrame
->IsPositioned() && !mFrame
->IsFlexOrGridItem())
2030 const nsStylePosition
* position
= mFrame
->StylePosition();
2031 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
)
2032 return position
->mZIndex
.GetIntValue();
2034 // sort the auto and 0 elements together
2039 nsDisplayItem::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
2040 nsRegion
* aVisibleRegion
)
2042 return !mVisibleRect
.IsEmpty() &&
2043 !IsInvisibleInRect(aVisibleRegion
->GetBounds());
2047 nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder
* aBuilder
,
2048 nsRegion
* aVisibleRegion
) {
2049 nsRect bounds
= GetClippedBounds(aBuilder
);
2051 nsRegion itemVisible
;
2052 itemVisible
.And(*aVisibleRegion
, bounds
);
2053 mVisibleRect
= itemVisible
.GetBounds();
2055 // When we recompute visibility within layers we don't need to
2056 // expand the visible region for content behind plugins (the plugin
2057 // is not in the layer).
2058 if (!ComputeVisibility(aBuilder
, aVisibleRegion
)) {
2059 mVisibleRect
= nsRect();
2063 nsRegion opaque
= TreatAsOpaque(this, aBuilder
);
2064 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, opaque
);
2069 nsDisplayItem::GetClippedBounds(nsDisplayListBuilder
* aBuilder
)
2072 nsRect r
= GetBounds(aBuilder
, &snap
);
2073 return GetClip().ApplyNonRoundedIntersection(r
);
2077 nsDisplaySolidColor::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
2084 nsDisplaySolidColor::Paint(nsDisplayListBuilder
* aBuilder
,
2085 nsRenderingContext
* aCtx
)
2087 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
2088 DrawTarget
* drawTarget
= aCtx
->GetDrawTarget();
2090 NSRectToSnappedRect(mVisibleRect
, appUnitsPerDevPixel
, *drawTarget
);
2091 drawTarget
->FillRect(rect
, ColorPattern(ToDeviceColor(mColor
)));
2095 nsDisplaySolidColor::WriteDebugInfo(std::stringstream
& aStream
)
2097 aStream
<< " (rgba "
2098 << (int)NS_GET_R(mColor
) << ","
2099 << (int)NS_GET_G(mColor
) << ","
2100 << (int)NS_GET_B(mColor
) << ","
2101 << (int)NS_GET_A(mColor
) << ")";
2105 RegisterThemeGeometry(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
2107 if (!aBuilder
->IsInSubdocument() && !aBuilder
->IsInTransform()) {
2108 nsIFrame
* displayRoot
= nsLayoutUtils::GetDisplayRootFrame(aFrame
);
2109 nsRect
borderBox(aFrame
->GetOffsetTo(displayRoot
), aFrame
->GetSize());
2110 aBuilder
->RegisterThemeGeometry(aFrame
->StyleDisplay()->mAppearance
,
2111 borderBox
.ToNearestPixels(aFrame
->PresContext()->AppUnitsPerDevPixel()));
2115 nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder
* aBuilder
,
2118 const nsStyleBackground
* aBackgroundStyle
)
2119 : nsDisplayImageContainer(aBuilder
, aFrame
)
2120 , mBackgroundStyle(aBackgroundStyle
)
2123 MOZ_COUNT_CTOR(nsDisplayBackgroundImage
);
2125 mBounds
= GetBoundsInternal(aBuilder
);
2128 nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
2130 #ifdef NS_BUILD_REFCNT_LOGGING
2131 MOZ_COUNT_DTOR(nsDisplayBackgroundImage
);
2135 static nsStyleContext
* GetBackgroundStyleContext(nsIFrame
* aFrame
)
2138 if (!nsCSSRendering::FindBackground(aFrame
, &sc
)) {
2139 // We don't want to bail out if moz-appearance is set on a root
2140 // node. If it has a parent content node, bail because it's not
2141 // a root, other wise keep going in order to let the theme stuff
2142 // draw the background. The canvas really should be drawing the
2143 // bg, but there's no way to hook that up via css.
2144 if (!aFrame
->StyleDisplay()->mAppearance
) {
2148 nsIContent
* content
= aFrame
->GetContent();
2149 if (!content
|| content
->GetParent()) {
2153 sc
= aFrame
->StyleContext();
2159 SetBackgroundClipRegion(DisplayListClipState::AutoSaveRestore
& aClipState
,
2160 nsIFrame
* aFrame
, const nsPoint
& aToReferenceFrame
,
2161 const nsStyleBackground::Layer
& aLayer
,
2162 bool aWillPaintBorder
)
2164 nsRect borderBox
= nsRect(aToReferenceFrame
, aFrame
->GetSize());
2166 nsCSSRendering::BackgroundClipState clip
;
2167 nsCSSRendering::GetBackgroundClip(aLayer
, aFrame
, *aFrame
->StyleBorder(),
2168 borderBox
, borderBox
, aWillPaintBorder
,
2169 aFrame
->PresContext()->AppUnitsPerDevPixel(),
2172 if (clip
.mHasAdditionalBGClipArea
) {
2173 aClipState
.ClipContentDescendants(clip
.mAdditionalBGClipArea
, clip
.mBGClipArea
,
2174 clip
.mHasRoundedCorners
? clip
.mRadii
: nullptr);
2176 aClipState
.ClipContentDescendants(clip
.mBGClipArea
, clip
.mHasRoundedCorners
? clip
.mRadii
: nullptr);
2182 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder
* aBuilder
,
2184 nsDisplayList
* aList
)
2186 nsStyleContext
* bgSC
= nullptr;
2187 const nsStyleBackground
* bg
= nullptr;
2188 nsPresContext
* presContext
= aFrame
->PresContext();
2189 bool isThemed
= aFrame
->IsThemed();
2191 bgSC
= GetBackgroundStyleContext(aFrame
);
2193 bg
= bgSC
->StyleBackground();
2197 bool drawBackgroundColor
= false;
2199 if (!nsCSSRendering::IsCanvasFrame(aFrame
) && bg
) {
2200 bool drawBackgroundImage
;
2202 nsCSSRendering::DetermineBackgroundColor(presContext
, bgSC
, aFrame
,
2203 drawBackgroundImage
, drawBackgroundColor
);
2206 const nsStyleBorder
* borderStyle
= aFrame
->StyleBorder();
2207 bool hasInsetShadow
= borderStyle
->mBoxShadow
&&
2208 borderStyle
->mBoxShadow
->HasShadowWithInset(true);
2209 bool willPaintBorder
= !isThemed
&& !hasInsetShadow
&&
2210 borderStyle
->HasBorder();
2212 nsPoint toRef
= aBuilder
->ToReferenceFrame(aFrame
);
2214 // An auxiliary list is necessary in case we have background blending; if that
2215 // is the case, background items need to be wrapped by a blend container to
2216 // isolate blending to the background
2217 nsDisplayList bgItemList
;
2218 // Even if we don't actually have a background color to paint, we may still need
2219 // to create an item for hit testing.
2220 if ((drawBackgroundColor
&& color
!= NS_RGBA(0,0,0,0)) ||
2221 aBuilder
->IsForEventDelivery()) {
2222 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
2223 if (bg
&& !aBuilder
->IsForEventDelivery()) {
2224 // Disable the will-paint-border optimization for background
2225 // colors with no border-radius. Enabling it for background colors
2226 // doesn't help much (there are no tiling issues) and clipping the
2227 // background breaks detection of the element's border-box being
2228 // opaque. For nonzero border-radius we still need it because we
2229 // want to inset the background if possible to avoid antialiasing
2230 // artifacts along the rounded corners.
2231 bool useWillPaintBorderOptimization
= willPaintBorder
&&
2232 nsLayoutUtils::HasNonZeroCorner(borderStyle
->mBorderRadius
);
2233 SetBackgroundClipRegion(clipState
, aFrame
, toRef
,
2235 useWillPaintBorderOptimization
);
2237 bgItemList
.AppendNewToTop(
2238 new (aBuilder
) nsDisplayBackgroundColor(aBuilder
, aFrame
, bg
,
2239 drawBackgroundColor
? color
: NS_RGBA(0, 0, 0, 0)));
2243 nsITheme
* theme
= presContext
->GetTheme();
2244 if (theme
->NeedToClearBackgroundBehindWidget(aFrame
->StyleDisplay()->mAppearance
)) {
2245 bgItemList
.AppendNewToTop(
2246 new (aBuilder
) nsDisplayClearBackground(aBuilder
, aFrame
));
2248 nsDisplayThemedBackground
* bgItem
=
2249 new (aBuilder
) nsDisplayThemedBackground(aBuilder
, aFrame
);
2250 bgItemList
.AppendNewToTop(bgItem
);
2251 aList
->AppendToTop(&bgItemList
);
2256 aList
->AppendToTop(&bgItemList
);
2260 bool needBlendContainer
= false;
2262 // Passing bg == nullptr in this macro will result in one iteration with
2264 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i
, bg
) {
2265 if (bg
->mLayers
[i
].mImage
.IsEmpty()) {
2269 if (bg
->mLayers
[i
].mBlendMode
!= NS_STYLE_BLEND_NORMAL
) {
2270 needBlendContainer
= true;
2273 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
2274 if (!aBuilder
->IsForEventDelivery()) {
2275 const nsStyleBackground::Layer
& layer
= bg
->mLayers
[i
];
2276 SetBackgroundClipRegion(clipState
, aFrame
, toRef
,
2277 layer
, willPaintBorder
);
2280 nsDisplayBackgroundImage
* bgItem
=
2281 new (aBuilder
) nsDisplayBackgroundImage(aBuilder
, aFrame
, i
, bg
);
2282 bgItemList
.AppendNewToTop(bgItem
);
2285 if (needBlendContainer
) {
2286 bgItemList
.AppendNewToTop(
2287 new (aBuilder
) nsDisplayBlendContainer(aBuilder
, aFrame
, &bgItemList
));
2290 aList
->AppendToTop(&bgItemList
);
2294 // Check that the rounded border of aFrame, added to aToReferenceFrame,
2295 // intersects aRect. Assumes that the unrounded border has already
2296 // been checked for intersection.
2298 RoundedBorderIntersectsRect(nsIFrame
* aFrame
,
2299 const nsPoint
& aFrameToReferenceFrame
,
2300 const nsRect
& aTestRect
)
2302 if (!nsRect(aFrameToReferenceFrame
, aFrame
->GetSize()).Intersects(aTestRect
))
2306 return !aFrame
->GetBorderRadii(radii
) ||
2307 nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame
,
2312 // Returns TRUE if aContainedRect is guaranteed to be contained in
2313 // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
2314 // handled conservatively by returning FALSE in some situations where
2315 // a more thorough analysis could return TRUE.
2317 // See also RoundedRectIntersectsRect.
2318 static bool RoundedRectContainsRect(const nsRect
& aRoundedRect
,
2319 const nscoord aRadii
[8],
2320 const nsRect
& aContainedRect
) {
2321 nsRegion rgn
= nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect
, aRadii
, aContainedRect
);
2322 return rgn
.Contains(aContainedRect
);
2326 nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder
* aBuilder
,
2327 const nsRect
& aClipRect
,
2330 if (!mBackgroundStyle
)
2333 if (mBackgroundStyle
->mLayers
.Length() != 1)
2336 nsPresContext
* presContext
= mFrame
->PresContext();
2337 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2338 nsRect borderArea
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2339 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2341 if (layer
.mAttachment
!= NS_STYLE_BG_ATTACHMENT_FIXED
)
2344 nsBackgroundLayerState state
=
2345 nsCSSRendering::PrepareBackgroundLayer(presContext
, mFrame
, flags
,
2346 borderArea
, aClipRect
, layer
);
2347 nsImageRenderer
* imageRenderer
= &state
.mImageRenderer
;
2348 // We only care about images here, not gradients.
2349 if (!imageRenderer
->IsRasterImage())
2352 int32_t appUnitsPerDevPixel
= presContext
->AppUnitsPerDevPixel();
2353 *aDestRect
= nsLayoutUtils::RectToGfxRect(state
.mFillArea
, appUnitsPerDevPixel
);
2359 nsDisplayBackgroundImage::ShouldFixToViewport(LayerManager
* aManager
)
2361 // APZ doesn't (yet) know how to scroll the visible region for these type of
2362 // items, so don't layerize them if it's enabled.
2363 if (nsLayoutUtils::UsesAsyncScrolling() ||
2364 (aManager
&& aManager
->ShouldAvoidComponentAlphaLayers())) {
2368 // Put background-attachment:fixed background images in their own
2369 // compositing layer, unless we have APZ enabled
2370 return mBackgroundStyle
->mLayers
[mLayer
].mAttachment
== NS_STYLE_BG_ATTACHMENT_FIXED
&&
2371 !mBackgroundStyle
->mLayers
[mLayer
].mImage
.IsEmpty();
2375 nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager
* aManager
,
2376 nsDisplayListBuilder
* aBuilder
)
2378 if (!mBackgroundStyle
)
2381 nsPresContext
* presContext
= mFrame
->PresContext();
2382 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2383 nsRect borderArea
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2384 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2386 if (layer
.mClip
!= NS_STYLE_BG_CLIP_BORDER
) {
2390 if (mFrame
->GetBorderRadii(radii
)) {
2394 nsBackgroundLayerState state
=
2395 nsCSSRendering::PrepareBackgroundLayer(presContext
, mFrame
, flags
,
2396 borderArea
, borderArea
, layer
);
2397 nsImageRenderer
* imageRenderer
= &state
.mImageRenderer
;
2398 // We only care about images here, not gradients.
2399 if (!imageRenderer
->IsRasterImage())
2402 nsRefPtr
<ImageContainer
> imageContainer
= imageRenderer
->GetContainer(aManager
);
2403 // Image is not ready to be made into a layer yet
2404 if (!imageContainer
)
2407 // We currently can't handle tiled or partial backgrounds.
2408 if (!state
.mDestArea
.IsEqualEdges(state
.mFillArea
)) {
2412 // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
2413 // layer pixel boundaries. This should be OK for now.
2415 int32_t appUnitsPerDevPixel
= presContext
->AppUnitsPerDevPixel();
2416 mDestRect
= nsLayoutUtils::RectToGfxRect(state
.mDestArea
, appUnitsPerDevPixel
);
2417 mImageContainer
= imageContainer
;
2419 // Ok, we can turn this into a layer if needed.
2423 already_AddRefed
<ImageContainer
>
2424 nsDisplayBackgroundImage::GetContainer(LayerManager
* aManager
,
2425 nsDisplayListBuilder
*aBuilder
)
2427 if (!TryOptimizeToImageLayer(aManager
, aBuilder
)) {
2431 nsRefPtr
<ImageContainer
> container
= mImageContainer
;
2433 return container
.forget();
2437 nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder
* aBuilder
,
2438 LayerManager
* aManager
,
2439 const ContainerLayerParameters
& aParameters
)
2441 bool animated
= false;
2442 if (mBackgroundStyle
) {
2443 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2444 const nsStyleImage
* image
= &layer
.mImage
;
2445 if (image
->GetType() == eStyleImageType_Image
) {
2446 imgIRequest
* imgreq
= image
->GetImageData();
2447 nsCOMPtr
<imgIContainer
> image
;
2448 if (NS_SUCCEEDED(imgreq
->GetImage(getter_AddRefs(image
))) && image
) {
2449 if (NS_FAILED(image
->GetAnimated(&animated
))) {
2457 !nsLayoutUtils::AnimatedImageLayersEnabled()) {
2458 if (!aManager
->IsCompositingCheap() ||
2459 !nsLayoutUtils::GPUImageScalingEnabled()) {
2464 if (!TryOptimizeToImageLayer(aManager
, aBuilder
)) {
2469 mozilla::gfx::IntSize imageSize
= mImageContainer
->GetCurrentSize();
2470 NS_ASSERTION(imageSize
.width
!= 0 && imageSize
.height
!= 0, "Invalid image size!");
2472 gfxRect destRect
= mDestRect
;
2474 destRect
.width
*= aParameters
.mXScale
;
2475 destRect
.height
*= aParameters
.mYScale
;
2477 // Calculate the scaling factor for the frame.
2478 gfxSize scale
= gfxSize(destRect
.width
/ imageSize
.width
, destRect
.height
/ imageSize
.height
);
2480 // If we are not scaling at all, no point in separating this into a layer.
2481 if (scale
.width
== 1.0f
&& scale
.height
== 1.0f
) {
2485 // If the target size is pretty small, no point in using a layer.
2486 if (destRect
.width
* destRect
.height
< 64 * 64) {
2491 return LAYER_ACTIVE
;
2494 already_AddRefed
<Layer
>
2495 nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder
* aBuilder
,
2496 LayerManager
* aManager
,
2497 const ContainerLayerParameters
& aParameters
)
2499 nsRefPtr
<ImageLayer
> layer
= static_cast<ImageLayer
*>
2500 (aManager
->GetLayerBuilder()->GetLeafLayerFor(aBuilder
, this));
2502 layer
= aManager
->CreateImageLayer();
2506 layer
->SetContainer(mImageContainer
);
2507 ConfigureLayer(layer
, aParameters
.mOffset
);
2508 return layer
.forget();
2512 nsDisplayBackgroundImage::ConfigureLayer(ImageLayer
* aLayer
, const nsIntPoint
& aOffset
)
2514 aLayer
->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame
));
2516 mozilla::gfx::IntSize imageSize
= mImageContainer
->GetCurrentSize();
2517 NS_ASSERTION(imageSize
.width
!= 0 && imageSize
.height
!= 0, "Invalid image size!");
2518 if (imageSize
.width
> 0 && imageSize
.height
> 0) {
2519 // We're actually using the ImageContainer. Let our frame know that it
2520 // should consider itself to have painted successfully.
2521 nsDisplayBackgroundGeometry::UpdateDrawResult(this, DrawResult::SUCCESS
);
2524 gfxPoint p
= mDestRect
.TopLeft() + aOffset
;
2525 Matrix transform
= Matrix::Translation(p
.x
, p
.y
);
2526 transform
.PreScale(mDestRect
.width
/ imageSize
.width
,
2527 mDestRect
.height
/ imageSize
.height
);
2528 aLayer
->SetBaseTransform(gfx::Matrix4x4::From2D(transform
));
2532 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder
* aBuilder
,
2533 const nsRect
& aRect
,
2534 HitTestState
* aState
,
2535 nsTArray
<nsIFrame
*> *aOutFrames
)
2537 if (RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
2538 aOutFrames
->AppendElement(mFrame
);
2543 nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
2544 nsRegion
* aVisibleRegion
)
2546 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
2550 // Return false if the background was propagated away from this
2551 // frame. We don't want this display item to show up and confuse
2553 return mBackgroundStyle
;
2556 /* static */ nsRegion
2557 nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem
* aItem
,
2558 nsPresContext
* aPresContext
,
2559 uint8_t aClip
, const nsRect
& aRect
,
2563 if (aRect
.IsEmpty())
2566 nsIFrame
*frame
= aItem
->Frame();
2569 if (frame
->GetType() == nsGkAtoms::canvasFrame
) {
2570 nsCanvasFrame
* canvasFrame
= static_cast<nsCanvasFrame
*>(frame
);
2571 clipRect
= canvasFrame
->CanvasArea() + aItem
->ToReferenceFrame();
2574 case NS_STYLE_BG_CLIP_BORDER
:
2575 clipRect
= nsRect(aItem
->ToReferenceFrame(), frame
->GetSize());
2577 case NS_STYLE_BG_CLIP_PADDING
:
2578 clipRect
= frame
->GetPaddingRect() - frame
->GetPosition() + aItem
->ToReferenceFrame();
2580 case NS_STYLE_BG_CLIP_CONTENT
:
2581 clipRect
= frame
->GetContentRectRelativeToSelf() + aItem
->ToReferenceFrame();
2584 NS_NOTREACHED("Unknown clip type");
2589 return clipRect
.Intersect(aRect
);
2593 nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2598 if (!mBackgroundStyle
)
2604 // For NS_STYLE_BOX_DECORATION_BREAK_SLICE, don't try to optimize here, since
2605 // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
2606 // which expects frames to be sent to it in content order, not reverse
2607 // content order which we'll produce here.
2608 // Of course, if there's only one frame in the flow, it doesn't matter.
2609 if (mFrame
->StyleBorder()->mBoxDecorationBreak
==
2610 NS_STYLE_BOX_DECORATION_BREAK_CLONE
||
2611 (!mFrame
->GetPrevContinuation() && !mFrame
->GetNextContinuation())) {
2612 const nsStyleBackground::Layer
& layer
= mBackgroundStyle
->mLayers
[mLayer
];
2613 if (layer
.mImage
.IsOpaque() && layer
.mBlendMode
== NS_STYLE_BLEND_NORMAL
) {
2614 nsPresContext
* presContext
= mFrame
->PresContext();
2615 result
= GetInsideClipRegion(this, presContext
, layer
.mClip
, mBounds
, aSnap
);
2623 nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
2624 if (!mBackgroundStyle
) {
2625 *aColor
= NS_RGBA(0,0,0,0);
2632 nsDisplayBackgroundImage::GetPositioningArea()
2634 if (!mBackgroundStyle
) {
2637 nsIFrame
* attachedToFrame
;
2638 return nsCSSRendering::ComputeBackgroundPositioningArea(
2639 mFrame
->PresContext(), mFrame
,
2640 nsRect(ToReferenceFrame(), mFrame
->GetSize()),
2641 mBackgroundStyle
->mLayers
[mLayer
],
2642 &attachedToFrame
) + ToReferenceFrame();
2646 nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
2648 if (!mBackgroundStyle
)
2652 if (mFrame
->GetBorderRadii(radii
)) {
2653 // A change in the size of the positioning area might change the position
2654 // of the rounded corners.
2658 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2659 if (layer
.RenderingMightDependOnPositioningAreaSizeChange()) {
2665 static void CheckForBorderItem(nsDisplayItem
*aItem
, uint32_t& aFlags
)
2667 nsDisplayItem
* nextItem
= aItem
->GetAbove();
2668 while (nextItem
&& nextItem
->GetType() == nsDisplayItem::TYPE_BACKGROUND
) {
2669 nextItem
= nextItem
->GetAbove();
2672 nextItem
->Frame() == aItem
->Frame() &&
2673 nextItem
->GetType() == nsDisplayItem::TYPE_BORDER
) {
2674 aFlags
|= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER
;
2679 nsDisplayBackgroundImage::Paint(nsDisplayListBuilder
* aBuilder
,
2680 nsRenderingContext
* aCtx
) {
2681 PaintInternal(aBuilder
, aCtx
, mVisibleRect
, &mBounds
);
2685 nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder
* aBuilder
,
2686 nsRenderingContext
* aCtx
, const nsRect
& aBounds
,
2687 nsRect
* aClipRect
) {
2688 nsPoint offset
= ToReferenceFrame();
2689 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2690 CheckForBorderItem(this, flags
);
2693 nsCSSRendering::PaintBackground(mFrame
->PresContext(), *aCtx
, mFrame
,
2695 nsRect(offset
, mFrame
->GetSize()),
2696 flags
, aClipRect
, mLayer
);
2698 nsDisplayBackgroundGeometry::UpdateDrawResult(this, result
);
2701 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
2702 const nsDisplayItemGeometry
* aGeometry
,
2703 nsRegion
* aInvalidRegion
)
2705 if (!mBackgroundStyle
) {
2709 const nsDisplayBackgroundGeometry
* geometry
= static_cast<const nsDisplayBackgroundGeometry
*>(aGeometry
);
2712 nsRect bounds
= GetBounds(aBuilder
, &snap
);
2713 nsRect positioningArea
= GetPositioningArea();
2714 if (positioningArea
.TopLeft() != geometry
->mPositioningArea
.TopLeft() ||
2715 (positioningArea
.Size() != geometry
->mPositioningArea
.Size() &&
2716 RenderingMightDependOnPositioningAreaSizeChange())) {
2717 // Positioning area changed in a way that could cause everything to change,
2718 // so invalidate everything (both old and new painting areas).
2719 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
2721 if (positioningArea
.Size() != geometry
->mPositioningArea
.Size()) {
2722 NotifyRenderingChanged();
2726 if (aBuilder
->ShouldSyncDecodeImages()) {
2727 const nsStyleImage
& image
= mBackgroundStyle
->mLayers
[mLayer
].mImage
;
2728 if (image
.GetType() == eStyleImageType_Image
&&
2729 geometry
->ShouldInvalidateToSyncDecodeImages()) {
2730 aInvalidRegion
->Or(*aInvalidRegion
, bounds
);
2732 NotifyRenderingChanged();
2735 if (!bounds
.IsEqualInterior(geometry
->mBounds
)) {
2736 // Positioning area is unchanged, so invalidate just the change in the
2738 aInvalidRegion
->Xor(bounds
, geometry
->mBounds
);
2740 NotifyRenderingChanged();
2745 nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
2751 nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder
* aBuilder
) {
2752 nsPresContext
* presContext
= mFrame
->PresContext();
2754 if (!mBackgroundStyle
) {
2758 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2759 nsRect clipRect
= borderBox
;
2760 if (mFrame
->GetType() == nsGkAtoms::canvasFrame
) {
2761 nsCanvasFrame
* frame
= static_cast<nsCanvasFrame
*>(mFrame
);
2762 clipRect
= frame
->CanvasArea() + ToReferenceFrame();
2764 const nsStyleBackground::Layer
& layer
= mBackgroundStyle
->mLayers
[mLayer
];
2765 return nsCSSRendering::GetBackgroundLayerRect(presContext
, mFrame
,
2766 borderBox
, clipRect
, layer
,
2767 aBuilder
->GetBackgroundPaintFlags());
2771 nsDisplayBackgroundImage::GetPerFrameKey()
2773 return (mLayer
<< nsDisplayItem::TYPE_BITS
) |
2774 nsDisplayItem::GetPerFrameKey();
2777 nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder
* aBuilder
,
2779 : nsDisplayItem(aBuilder
, aFrame
)
2781 MOZ_COUNT_CTOR(nsDisplayThemedBackground
);
2783 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
2784 mAppearance
= disp
->mAppearance
;
2785 mFrame
->IsThemed(disp
, &mThemeTransparency
);
2787 // Perform necessary RegisterThemeGeometry
2788 switch (disp
->mAppearance
) {
2789 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR
:
2790 case NS_THEME_TOOLBAR
:
2791 case NS_THEME_TOOLTIP
:
2792 case NS_THEME_WINDOW_TITLEBAR
:
2793 case NS_THEME_WINDOW_BUTTON_BOX
:
2794 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON
:
2795 case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED
:
2796 case NS_THEME_MAC_VIBRANCY_LIGHT
:
2797 case NS_THEME_MAC_VIBRANCY_DARK
:
2798 RegisterThemeGeometry(aBuilder
, aFrame
);
2800 case NS_THEME_WIN_BORDERLESS_GLASS
:
2801 case NS_THEME_WIN_GLASS
:
2802 aBuilder
->SetGlassDisplayItem(this);
2806 mBounds
= GetBoundsInternal();
2809 nsDisplayThemedBackground::~nsDisplayThemedBackground()
2811 #ifdef NS_BUILD_REFCNT_LOGGING
2812 MOZ_COUNT_DTOR(nsDisplayThemedBackground
);
2817 nsDisplayThemedBackground::WriteDebugInfo(std::stringstream
& aStream
)
2819 aStream
<< " (themed, appearance:" << (int)mAppearance
<< ")";
2823 nsDisplayThemedBackground::HitTest(nsDisplayListBuilder
* aBuilder
,
2824 const nsRect
& aRect
,
2825 HitTestState
* aState
,
2826 nsTArray
<nsIFrame
*> *aOutFrames
)
2828 // Assume that any point in our border rect is a hit.
2829 if (nsRect(ToReferenceFrame(), mFrame
->GetSize()).Intersects(aRect
)) {
2830 aOutFrames
->AppendElement(mFrame
);
2835 nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2840 if (mThemeTransparency
== nsITheme::eOpaque
) {
2841 result
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2847 nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
2848 if (mAppearance
== NS_THEME_WIN_BORDERLESS_GLASS
||
2849 mAppearance
== NS_THEME_WIN_GLASS
) {
2850 *aColor
= NS_RGBA(0,0,0,0);
2857 nsDisplayThemedBackground::ProvidesFontSmoothingBackgroundColor(nsDisplayListBuilder
* aBuilder
,
2860 nsITheme
* theme
= mFrame
->PresContext()->GetTheme();
2861 return theme
->WidgetProvidesFontSmoothingBackgroundColor(mFrame
, mAppearance
, aColor
);
2865 nsDisplayThemedBackground::GetPositioningArea()
2867 return nsRect(ToReferenceFrame(), mFrame
->GetSize());
2871 nsDisplayThemedBackground::Paint(nsDisplayListBuilder
* aBuilder
,
2872 nsRenderingContext
* aCtx
)
2874 PaintInternal(aBuilder
, aCtx
, mVisibleRect
, nullptr);
2879 nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder
* aBuilder
,
2880 nsRenderingContext
* aCtx
, const nsRect
& aBounds
,
2883 // XXXzw this ignores aClipRect.
2884 nsPresContext
* presContext
= mFrame
->PresContext();
2885 nsITheme
*theme
= presContext
->GetTheme();
2886 nsRect
borderArea(ToReferenceFrame(), mFrame
->GetSize());
2887 nsRect
drawing(borderArea
);
2888 theme
->GetWidgetOverflow(presContext
->DeviceContext(), mFrame
, mAppearance
,
2890 drawing
.IntersectRect(drawing
, aBounds
);
2891 theme
->DrawWidgetBackground(aCtx
, mFrame
, mAppearance
, borderArea
, drawing
);
2894 bool nsDisplayThemedBackground::IsWindowActive()
2896 EventStates docState
= mFrame
->GetContent()->OwnerDoc()->GetDocumentState();
2897 return !docState
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
);
2900 void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
2901 const nsDisplayItemGeometry
* aGeometry
,
2902 nsRegion
* aInvalidRegion
)
2904 const nsDisplayThemedBackgroundGeometry
* geometry
= static_cast<const nsDisplayThemedBackgroundGeometry
*>(aGeometry
);
2907 nsRect bounds
= GetBounds(aBuilder
, &snap
);
2908 nsRect positioningArea
= GetPositioningArea();
2909 if (!positioningArea
.IsEqualInterior(geometry
->mPositioningArea
)) {
2910 // Invalidate everything (both old and new painting areas).
2911 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
2914 if (!bounds
.IsEqualInterior(geometry
->mBounds
)) {
2915 // Positioning area is unchanged, so invalidate just the change in the
2917 aInvalidRegion
->Xor(bounds
, geometry
->mBounds
);
2919 nsITheme
* theme
= mFrame
->PresContext()->GetTheme();
2920 if (theme
->WidgetAppearanceDependsOnWindowFocus(mAppearance
) &&
2921 IsWindowActive() != geometry
->mWindowIsActive
) {
2922 aInvalidRegion
->Or(*aInvalidRegion
, bounds
);
2927 nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
2933 nsDisplayThemedBackground::GetBoundsInternal() {
2934 nsPresContext
* presContext
= mFrame
->PresContext();
2936 nsRect
r(nsPoint(0,0), mFrame
->GetSize());
2937 presContext
->GetTheme()->
2938 GetWidgetOverflow(presContext
->DeviceContext(), mFrame
,
2939 mFrame
->StyleDisplay()->mAppearance
, &r
);
2942 r
.Inflate(mFrame
->PresContext()->AppUnitsPerDevPixel());
2945 return r
+ ToReferenceFrame();
2949 nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder
* aBuilder
,
2951 const DisplayItemClip
* aClip
)
2953 NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
2954 mColor
.a
= mColor
.a
* aOpacity
;
2956 IntersectClip(aBuilder
, *aClip
);
2961 nsDisplayBackgroundColor::CanApplyOpacity() const
2967 nsDisplayBackgroundColor::Paint(nsDisplayListBuilder
* aBuilder
,
2968 nsRenderingContext
* aCtx
)
2970 DrawTarget
& aDrawTarget
= *aCtx
->GetDrawTarget();
2972 if (mColor
== NS_RGBA(0, 0, 0, 0)) {
2976 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2978 Rect rect
= NSRectToSnappedRect(borderBox
,
2979 mFrame
->PresContext()->AppUnitsPerDevPixel(),
2981 ColorPattern
color(ToDeviceColor(mColor
));
2982 aDrawTarget
.FillRect(rect
, color
);
2986 nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2989 if (mColor
.a
!= 1) {
2993 if (!mBackgroundStyle
)
2998 const nsStyleBackground::Layer
& bottomLayer
= mBackgroundStyle
->BottomLayer();
2999 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
3000 nsPresContext
* presContext
= mFrame
->PresContext();
3001 return nsDisplayBackgroundImage::GetInsideClipRegion(this, presContext
, bottomLayer
.mClip
, borderBox
, aSnap
);
3005 nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
)
3007 *aColor
= NS_RGBA_FROM_GFXRGBA(mColor
);
3012 nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder
* aBuilder
,
3013 const nsRect
& aRect
,
3014 HitTestState
* aState
,
3015 nsTArray
<nsIFrame
*> *aOutFrames
)
3017 if (!RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
3018 // aRect doesn't intersect our border-radius curve.
3022 aOutFrames
->AppendElement(mFrame
);
3026 nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream
& aStream
)
3028 aStream
<< " (rgba " << mColor
.r
<< "," << mColor
.g
<< ","
3029 << mColor
.b
<< "," << mColor
.a
<< ")";
3032 already_AddRefed
<Layer
>
3033 nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3034 LayerManager
* aManager
,
3035 const ContainerLayerParameters
& aParameters
)
3037 nsRefPtr
<ColorLayer
> layer
= static_cast<ColorLayer
*>
3038 (aManager
->GetLayerBuilder()->GetLeafLayerFor(aBuilder
, this));
3040 layer
= aManager
->CreateColorLayer();
3044 layer
->SetColor(NS_RGBA(0, 0, 0, 0));
3045 layer
->SetMixBlendMode(gfx::CompositionOp::OP_SOURCE
);
3048 nsRect bounds
= GetBounds(aBuilder
, &snap
);
3049 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
3050 layer
->SetBounds(bounds
.ToNearestPixels(appUnitsPerDevPixel
)); // XXX Do we need to respect the parent layer's scale here?
3052 return layer
.forget();
3056 nsDisplayOutline::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
3058 return mFrame
->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
3062 nsDisplayOutline::Paint(nsDisplayListBuilder
* aBuilder
,
3063 nsRenderingContext
* aCtx
) {
3064 // TODO join outlines together
3065 nsPoint offset
= ToReferenceFrame();
3066 nsCSSRendering::PaintOutline(mFrame
->PresContext(), *aCtx
, mFrame
,
3068 nsRect(offset
, mFrame
->GetSize()),
3069 mFrame
->StyleContext());
3073 nsDisplayOutline::IsInvisibleInRect(const nsRect
& aRect
)
3075 const nsStyleOutline
* outline
= mFrame
->StyleOutline();
3076 nsRect
borderBox(ToReferenceFrame(), mFrame
->GetSize());
3077 if (borderBox
.Contains(aRect
) &&
3078 !nsLayoutUtils::HasNonZeroCorner(outline
->mOutlineRadius
)) {
3079 if (outline
->mOutlineOffset
>= 0) {
3080 // aRect is entirely inside the border-rect, and the outline isn't
3081 // rendered inside the border-rect, so the outline is not visible.
3090 nsDisplayEventReceiver::HitTest(nsDisplayListBuilder
* aBuilder
,
3091 const nsRect
& aRect
,
3092 HitTestState
* aState
,
3093 nsTArray
<nsIFrame
*> *aOutFrames
)
3095 if (!RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
3096 // aRect doesn't intersect our border-radius curve.
3100 aOutFrames
->AppendElement(mFrame
);
3104 nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder
* aBuilder
,
3107 NS_ASSERTION(aBuilder
->FindReferenceFrameFor(aFrame
) == aBuilder
->FindReferenceFrameFor(mFrame
),
3108 "Reference frame mismatch");
3109 if (aBuilder
->IsInsidePointerEventsNoneDoc()) {
3110 // Somewhere up the parent document chain is a subdocument with pointer-
3111 // events:none set on it (and without a mozpasspointerevents).
3114 if (!aFrame
->GetParent()) {
3115 MOZ_ASSERT(aFrame
->GetType() == nsGkAtoms::viewportFrame
);
3116 nsSubDocumentFrame
* subdoc
= static_cast<nsSubDocumentFrame
*>(
3117 nsLayoutUtils::GetCrossDocParentFrame(aFrame
));
3118 if (subdoc
&& subdoc
->PassPointerEventsToChildren()) {
3119 // If this viewport frame is for a subdocument with
3120 // mozpasspointerevents, then we don't want to add the viewport itself
3121 // to the event regions. Instead we want to add only subframes.
3125 uint8_t pointerEvents
= aFrame
->StyleVisibility()->GetEffectivePointerEvents(aFrame
);
3126 if (pointerEvents
== NS_STYLE_POINTER_EVENTS_NONE
) {
3129 if (!aFrame
->StyleVisibility()->IsVisible()) {
3132 // XXX handle other pointerEvents values for SVG
3134 // XXX Do something clever here for the common case where the border box
3135 // is obviously entirely inside mHitRegion.
3137 if (nsLayoutUtils::GetScrollableFrameFor(aFrame
)) {
3138 // If the frame is content of a scrollframe, then we need to pick up the
3139 // area corresponding to the overflow rect as well. Otherwise the parts of
3140 // the overflow that are not occupied by descendants get skipped and the
3141 // APZ code sends touch events to the content underneath instead.
3142 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1127773#c15.
3143 borderBox
= aFrame
->GetScrollableOverflowRect();
3145 borderBox
= nsRect(nsPoint(0, 0), aFrame
->GetSize());
3147 borderBox
+= aBuilder
->ToReferenceFrame(aFrame
);
3149 const DisplayItemClip
* clip
= aBuilder
->ClipState().GetCurrentCombinedClip(aBuilder
);
3150 bool borderBoxHasRoundedCorners
=
3151 nsLayoutUtils::HasNonZeroCorner(aFrame
->StyleBorder()->mBorderRadius
);
3153 borderBox
= clip
->ApplyNonRoundedIntersection(borderBox
);
3154 if (clip
->GetRoundedRectCount() > 0) {
3155 borderBoxHasRoundedCorners
= true;
3158 if (borderBoxHasRoundedCorners
||
3159 (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
)) {
3160 mMaybeHitRegion
.Or(mMaybeHitRegion
, borderBox
);
3162 mHitRegion
.Or(mHitRegion
, borderBox
);
3164 if (aBuilder
->GetAncestorHasApzAwareEventHandler()) {
3165 mDispatchToContentHitRegion
.Or(mDispatchToContentHitRegion
, borderBox
);
3170 nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect
& aRect
)
3172 mDispatchToContentHitRegion
.Or(mDispatchToContentHitRegion
, aRect
);
3176 nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream
& aStream
)
3178 if (!mHitRegion
.IsEmpty()) {
3179 AppendToString(aStream
, mHitRegion
, " (hitRegion ", ")");
3181 if (!mMaybeHitRegion
.IsEmpty()) {
3182 AppendToString(aStream
, mMaybeHitRegion
, " (maybeHitRegion ", ")");
3184 if (!mDispatchToContentHitRegion
.IsEmpty()) {
3185 AppendToString(aStream
, mDispatchToContentHitRegion
, " (dispatchToContentRegion ", ")");
3189 nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder
* aBuilder
,
3190 nsIFrame
* aCaretFrame
)
3191 : nsDisplayItem(aBuilder
, aCaretFrame
)
3192 , mCaret(aBuilder
->GetCaret())
3193 , mBounds(aBuilder
->GetCaretRect() + ToReferenceFrame())
3195 MOZ_COUNT_CTOR(nsDisplayCaret
);
3198 #ifdef NS_BUILD_REFCNT_LOGGING
3199 nsDisplayCaret::~nsDisplayCaret()
3201 MOZ_COUNT_DTOR(nsDisplayCaret
);
3206 nsDisplayCaret::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
3209 // The caret returns a rect in the coordinates of mFrame.
3214 nsDisplayCaret::Paint(nsDisplayListBuilder
* aBuilder
,
3215 nsRenderingContext
* aCtx
) {
3216 // Note: Because we exist, we know that the caret is visible, so we don't
3217 // need to check for the caret's visibility.
3218 mCaret
->PaintCaret(aBuilder
, *aCtx
->GetDrawTarget(), mFrame
, ToReferenceFrame());
3222 nsDisplayBorder::IsInvisibleInRect(const nsRect
& aRect
)
3224 nsRect paddingRect
= mFrame
->GetPaddingRect() - mFrame
->GetPosition() +
3226 const nsStyleBorder
*styleBorder
;
3227 if (paddingRect
.Contains(aRect
) &&
3228 !(styleBorder
= mFrame
->StyleBorder())->IsBorderImageLoaded() &&
3229 !nsLayoutUtils::HasNonZeroCorner(styleBorder
->mBorderRadius
)) {
3230 // aRect is entirely inside the content rect, and no part
3231 // of the border is rendered inside the content rect, so we are not
3233 // Skip this if there's a border-image (which draws a background
3234 // too) or if there is a border-radius (which makes the border draw
3242 nsDisplayItemGeometry
*
3243 nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder
* aBuilder
)
3245 return new nsDisplayBorderGeometry(this, aBuilder
);
3249 nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
3250 const nsDisplayItemGeometry
* aGeometry
,
3251 nsRegion
* aInvalidRegion
)
3253 const nsDisplayBorderGeometry
* geometry
= static_cast<const nsDisplayBorderGeometry
*>(aGeometry
);
3255 if (!geometry
->mBounds
.IsEqualInterior(GetBounds(aBuilder
, &snap
)) ||
3256 !geometry
->mContentRect
.IsEqualInterior(GetContentRect())) {
3257 // We can probably get away with only invalidating the difference
3258 // between the border and padding rects, but the XUL ui at least
3259 // is apparently painting a background with this?
3260 aInvalidRegion
->Or(GetBounds(aBuilder
, &snap
), geometry
->mBounds
);
3265 nsDisplayBorder::Paint(nsDisplayListBuilder
* aBuilder
,
3266 nsRenderingContext
* aCtx
) {
3267 nsPoint offset
= ToReferenceFrame();
3268 nsCSSRendering::PaintBorder(mFrame
->PresContext(), *aCtx
, mFrame
,
3270 nsRect(offset
, mFrame
->GetSize()),
3271 mFrame
->StyleContext(),
3272 mFrame
->GetSkipSides());
3276 nsDisplayBorder::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
3279 return CalculateBounds(*mFrame
->StyleBorder());
3283 nsDisplayBorder::CalculateBounds(const nsStyleBorder
& aStyleBorder
)
3285 nsRect
borderBounds(ToReferenceFrame(), mFrame
->GetSize());
3286 if (aStyleBorder
.IsBorderImageLoaded()) {
3287 borderBounds
.Inflate(aStyleBorder
.GetImageOutset());
3288 return borderBounds
;
3290 nsMargin border
= aStyleBorder
.GetComputedBorder();
3292 if (border
.top
> 0) {
3293 result
= nsRect(borderBounds
.X(), borderBounds
.Y(), borderBounds
.Width(), border
.top
);
3295 if (border
.right
> 0) {
3296 result
.UnionRect(result
, nsRect(borderBounds
.XMost() - border
.right
, borderBounds
.Y(), border
.right
, borderBounds
.Height()));
3298 if (border
.bottom
> 0) {
3299 result
.UnionRect(result
, nsRect(borderBounds
.X(), borderBounds
.YMost() - border
.bottom
, borderBounds
.Width(), border
.bottom
));
3301 if (border
.left
> 0) {
3302 result
.UnionRect(result
, nsRect(borderBounds
.X(), borderBounds
.Y(), border
.left
, borderBounds
.Height()));
3309 // Given a region, compute a conservative approximation to it as a list
3310 // of rectangles that aren't vertically adjacent (i.e., vertically
3311 // adjacent or overlapping rectangles are combined).
3312 // Right now this is only approximate, some vertically overlapping rectangles
3313 // aren't guaranteed to be combined.
3315 ComputeDisjointRectangles(const nsRegion
& aRegion
,
3316 nsTArray
<nsRect
>* aRects
) {
3317 nscoord accumulationMargin
= nsPresContext::CSSPixelsToAppUnits(25);
3319 nsRegionRectIterator
iter(aRegion
);
3321 const nsRect
* r
= iter
.Next();
3322 if (r
&& !accumulated
.IsEmpty() &&
3323 accumulated
.YMost() >= r
->y
- accumulationMargin
) {
3324 accumulated
.UnionRect(accumulated
, *r
);
3328 if (!accumulated
.IsEmpty()) {
3329 aRects
->AppendElement(accumulated
);
3330 accumulated
.SetEmpty();
3341 nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder
* aBuilder
,
3342 nsRenderingContext
* aCtx
) {
3343 nsPoint offset
= ToReferenceFrame();
3344 nsRect borderRect
= mFrame
->VisualBorderRectRelativeToSelf() + offset
;
3345 nsPresContext
* presContext
= mFrame
->PresContext();
3346 nsAutoTArray
<nsRect
,10> rects
;
3347 ComputeDisjointRectangles(mVisibleRegion
, &rects
);
3349 PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint",
3350 js::ProfileEntry::Category::GRAPHICS
);
3352 for (uint32_t i
= 0; i
< rects
.Length(); ++i
) {
3353 nsCSSRendering::PaintBoxShadowOuter(presContext
, *aCtx
, mFrame
,
3354 borderRect
, rects
[i
], mOpacity
);
3359 nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
3365 nsDisplayBoxShadowOuter::GetBoundsInternal() {
3366 return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame
, mFrame
->GetSize()) +
3371 nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect
& aRect
)
3373 nsPoint origin
= ToReferenceFrame();
3374 nsRect
frameRect(origin
, mFrame
->GetSize());
3375 if (!frameRect
.Contains(aRect
))
3378 // the visible region is entirely inside the border-rect, and box shadows
3379 // never render within the border-rect (unless there's a border radius).
3380 nscoord twipsRadii
[8];
3381 bool hasBorderRadii
= mFrame
->GetBorderRadii(twipsRadii
);
3382 if (!hasBorderRadii
)
3385 return RoundedRectContainsRect(frameRect
, twipsRadii
, aRect
);
3389 nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3390 nsRegion
* aVisibleRegion
) {
3391 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
3395 // Store the actual visible region
3396 mVisibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3401 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
3402 const nsDisplayItemGeometry
* aGeometry
,
3403 nsRegion
* aInvalidRegion
)
3405 const nsDisplayBoxShadowOuterGeometry
* geometry
=
3406 static_cast<const nsDisplayBoxShadowOuterGeometry
*>(aGeometry
);
3408 if (!geometry
->mBounds
.IsEqualInterior(GetBounds(aBuilder
, &snap
)) ||
3409 !geometry
->mBorderRect
.IsEqualInterior(GetBorderRect()) ||
3410 mOpacity
!= geometry
->mOpacity
) {
3411 nsRegion oldShadow
, newShadow
;
3412 nscoord dontCare
[8];
3413 bool hasBorderRadius
= mFrame
->GetBorderRadii(dontCare
);
3414 if (hasBorderRadius
) {
3415 // If we have rounded corners then we need to invalidate the frame area
3416 // too since we paint into it.
3417 oldShadow
= geometry
->mBounds
;
3418 newShadow
= GetBounds(aBuilder
, &snap
);
3420 oldShadow
= oldShadow
.Sub(geometry
->mBounds
, geometry
->mBorderRect
);
3421 newShadow
= newShadow
.Sub(GetBounds(aBuilder
, &snap
), GetBorderRect());
3423 aInvalidRegion
->Or(oldShadow
, newShadow
);
3429 nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder
* aBuilder
,
3430 nsRenderingContext
* aCtx
) {
3431 nsPoint offset
= ToReferenceFrame();
3432 nsRect borderRect
= nsRect(offset
, mFrame
->GetSize());
3433 nsPresContext
* presContext
= mFrame
->PresContext();
3434 nsAutoTArray
<nsRect
,10> rects
;
3435 ComputeDisjointRectangles(mVisibleRegion
, &rects
);
3437 PROFILER_LABEL("nsDisplayBoxShadowInner", "Paint",
3438 js::ProfileEntry::Category::GRAPHICS
);
3440 DrawTarget
* drawTarget
= aCtx
->GetDrawTarget();
3441 gfxContext
* gfx
= aCtx
->ThebesContext();
3442 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
3444 for (uint32_t i
= 0; i
< rects
.Length(); ++i
) {
3446 gfx
->Clip(NSRectToSnappedRect(rects
[i
], appUnitsPerDevPixel
, *drawTarget
));
3447 nsCSSRendering::PaintBoxShadowInner(presContext
, *aCtx
, mFrame
,
3448 borderRect
, rects
[i
]);
3454 nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3455 nsRegion
* aVisibleRegion
) {
3456 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
3460 // Store the actual visible region
3461 mVisibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3465 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder
* aBuilder
,
3466 nsIFrame
* aFrame
, nsDisplayList
* aList
)
3467 : nsDisplayItem(aBuilder
, aFrame
)
3468 , mOverrideZIndex(0)
3469 , mHasZIndexOverride(false)
3471 MOZ_COUNT_CTOR(nsDisplayWrapList
);
3473 mBaseVisibleRect
= mVisibleRect
;
3475 mList
.AppendToTop(aList
);
3476 UpdateBounds(aBuilder
);
3478 if (!aFrame
|| !aFrame
->IsTransformed()) {
3482 // If the frame is a preserve-3d parent, then we will create transforms
3483 // inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp).
3484 // In this case we will always be outside of the transform, so share
3485 // our parents reference frame.
3486 if (aFrame
->Preserves3DChildren()) {
3488 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(aFrame
));
3489 mToReferenceFrame
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3491 // If we're a transformed frame, then we need to find out if we're inside
3492 // the nsDisplayTransform or outside of it. Frames inside the transform
3493 // need mReferenceFrame == mFrame, outside needs the next ancestor
3495 // If we're inside the transform, then the nsDisplayItem constructor
3496 // will have done the right thing.
3497 // If we're outside the transform, then we should have only one child
3498 // (since nsDisplayTransform wraps all actual content), and that child
3499 // will have the correct reference frame set (since nsDisplayTransform
3500 // handles this explictly).
3502 // Preserve-3d can cause us to have multiple nsDisplayTransform
3504 nsDisplayItem
*i
= mList
.GetBottom();
3505 if (i
&& (!i
->GetAbove() || i
->GetType() == TYPE_TRANSFORM
) &&
3506 i
->Frame() == mFrame
) {
3507 mReferenceFrame
= i
->ReferenceFrame();
3508 mToReferenceFrame
= i
->ToReferenceFrame();
3511 mVisibleRect
= aBuilder
->GetDirtyRect() +
3512 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
3515 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder
* aBuilder
,
3516 nsIFrame
* aFrame
, nsDisplayItem
* aItem
)
3517 : nsDisplayItem(aBuilder
, aFrame
)
3518 , mOverrideZIndex(0)
3519 , mHasZIndexOverride(false)
3521 MOZ_COUNT_CTOR(nsDisplayWrapList
);
3523 mBaseVisibleRect
= mVisibleRect
;
3525 mList
.AppendToTop(aItem
);
3526 UpdateBounds(aBuilder
);
3528 if (!aFrame
|| !aFrame
->IsTransformed()) {
3532 if (aFrame
->Preserves3DChildren()) {
3534 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(aFrame
));
3535 mToReferenceFrame
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3537 // See the previous nsDisplayWrapList constructor
3538 if (aItem
->Frame() == aFrame
) {
3539 mReferenceFrame
= aItem
->ReferenceFrame();
3540 mToReferenceFrame
= aItem
->ToReferenceFrame();
3543 mVisibleRect
= aBuilder
->GetDirtyRect() +
3544 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
3547 nsDisplayWrapList::~nsDisplayWrapList() {
3550 MOZ_COUNT_DTOR(nsDisplayWrapList
);
3554 nsDisplayWrapList::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
3555 HitTestState
* aState
, nsTArray
<nsIFrame
*> *aOutFrames
) {
3556 mList
.HitTest(aBuilder
, aRect
, aState
, aOutFrames
);
3560 nsDisplayWrapList::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
3566 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3567 nsRegion
* aVisibleRegion
) {
3568 // Convert the passed in visible region to our appunits.
3569 nsRegion visibleRegion
;
3570 // mVisibleRect has been clipped to GetClippedBounds
3571 visibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3572 nsRegion originalVisibleRegion
= visibleRegion
;
3575 mList
.ComputeVisibilityForSublist(aBuilder
, &visibleRegion
,
3579 // removed = originalVisibleRegion - visibleRegion
3580 removed
.Sub(originalVisibleRegion
, visibleRegion
);
3581 // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
3582 // SubtractFromVisibleRegion does)
3583 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
3589 nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3593 if (mList
.IsOpaque()) {
3594 // Everything within GetBounds that's visible is opaque.
3595 result
= GetBounds(aBuilder
, aSnap
);
3600 bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
3601 // We could try to do something but let's conservatively just return false.
3605 void nsDisplayWrapList::Paint(nsDisplayListBuilder
* aBuilder
,
3606 nsRenderingContext
* aCtx
) {
3607 NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
3611 * Returns true if all descendant display items can be placed in the same
3612 * PaintedLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
3613 * and they all have the expected animated geometry root.
3616 RequiredLayerStateForChildren(nsDisplayListBuilder
* aBuilder
,
3617 LayerManager
* aManager
,
3618 const ContainerLayerParameters
& aParameters
,
3619 const nsDisplayList
& aList
,
3620 nsIFrame
* aExpectedAnimatedGeometryRootForChildren
)
3622 LayerState result
= LAYER_INACTIVE
;
3623 for (nsDisplayItem
* i
= aList
.GetBottom(); i
; i
= i
->GetAbove()) {
3624 if (result
== LAYER_INACTIVE
&&
3625 nsLayoutUtils::GetAnimatedGeometryRootFor(i
, aBuilder
, aManager
) !=
3626 aExpectedAnimatedGeometryRootForChildren
) {
3627 result
= LAYER_ACTIVE
;
3630 LayerState state
= i
->GetLayerState(aBuilder
, aManager
, aParameters
);
3631 if ((state
== LAYER_ACTIVE
|| state
== LAYER_ACTIVE_FORCE
) &&
3635 if (state
== LAYER_ACTIVE_EMPTY
&& state
> result
) {
3636 result
= LAYER_ACTIVE_FORCE
;
3638 if (state
== LAYER_NONE
) {
3639 nsDisplayList
* list
= i
->GetSameCoordinateSystemChildren();
3641 LayerState childState
=
3642 RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
, *list
,
3643 aExpectedAnimatedGeometryRootForChildren
);
3644 if (childState
> result
) {
3645 result
= childState
;
3653 nsRect
nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder
* aBuilder
)
3656 for (nsDisplayItem
* i
= mList
.GetBottom(); i
; i
= i
->GetAbove()) {
3657 bounds
.UnionRect(bounds
, i
->GetComponentAlphaBounds(aBuilder
));
3663 nsDisplayWrapList::SetVisibleRect(const nsRect
& aRect
)
3665 mVisibleRect
= aRect
;
3669 nsDisplayWrapList::SetReferenceFrame(const nsIFrame
* aFrame
)
3671 mReferenceFrame
= aFrame
;
3672 mToReferenceFrame
= mFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3676 WrapDisplayList(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
3677 nsDisplayList
* aList
, nsDisplayWrapper
* aWrapper
) {
3678 if (!aList
->GetTop())
3680 nsDisplayItem
* item
= aWrapper
->WrapList(aBuilder
, aFrame
, aList
);
3682 return NS_ERROR_OUT_OF_MEMORY
;
3683 // aList was emptied
3684 aList
->AppendToTop(item
);
3689 WrapEachDisplayItem(nsDisplayListBuilder
* aBuilder
,
3690 nsDisplayList
* aList
, nsDisplayWrapper
* aWrapper
) {
3691 nsDisplayList newList
;
3692 nsDisplayItem
* item
;
3693 while ((item
= aList
->RemoveBottom())) {
3694 item
= aWrapper
->WrapItem(aBuilder
, item
);
3696 return NS_ERROR_OUT_OF_MEMORY
;
3697 newList
.AppendToTop(item
);
3699 // aList was emptied
3700 aList
->AppendToTop(&newList
);
3704 nsresult
nsDisplayWrapper::WrapLists(nsDisplayListBuilder
* aBuilder
,
3705 nsIFrame
* aFrame
, const nsDisplayListSet
& aIn
, const nsDisplayListSet
& aOut
)
3707 nsresult rv
= WrapListsInPlace(aBuilder
, aFrame
, aIn
);
3708 NS_ENSURE_SUCCESS(rv
, rv
);
3712 aOut
.BorderBackground()->AppendToTop(aIn
.BorderBackground());
3713 aOut
.BlockBorderBackgrounds()->AppendToTop(aIn
.BlockBorderBackgrounds());
3714 aOut
.Floats()->AppendToTop(aIn
.Floats());
3715 aOut
.Content()->AppendToTop(aIn
.Content());
3716 aOut
.PositionedDescendants()->AppendToTop(aIn
.PositionedDescendants());
3717 aOut
.Outlines()->AppendToTop(aIn
.Outlines());
3721 nsresult
nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder
* aBuilder
,
3722 nsIFrame
* aFrame
, const nsDisplayListSet
& aLists
)
3725 if (WrapBorderBackground()) {
3726 // Our border-backgrounds are in-flow
3727 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.BorderBackground(), this);
3728 NS_ENSURE_SUCCESS(rv
, rv
);
3730 // Our block border-backgrounds are in-flow
3731 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.BlockBorderBackgrounds(), this);
3732 NS_ENSURE_SUCCESS(rv
, rv
);
3733 // The floats are not in flow
3734 rv
= WrapEachDisplayItem(aBuilder
, aLists
.Floats(), this);
3735 NS_ENSURE_SUCCESS(rv
, rv
);
3736 // Our child content is in flow
3737 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.Content(), this);
3738 NS_ENSURE_SUCCESS(rv
, rv
);
3739 // The positioned descendants may not be in-flow
3740 rv
= WrapEachDisplayItem(aBuilder
, aLists
.PositionedDescendants(), this);
3741 NS_ENSURE_SUCCESS(rv
, rv
);
3742 // The outlines may not be in-flow
3743 return WrapEachDisplayItem(aBuilder
, aLists
.Outlines(), this);
3746 nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder
* aBuilder
,
3747 nsIFrame
* aFrame
, nsDisplayList
* aList
)
3748 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
3749 , mOpacity(aFrame
->StyleDisplay()->mOpacity
) {
3750 MOZ_COUNT_CTOR(nsDisplayOpacity
);
3753 #ifdef NS_BUILD_REFCNT_LOGGING
3754 nsDisplayOpacity::~nsDisplayOpacity() {
3755 MOZ_COUNT_DTOR(nsDisplayOpacity
);
3759 nsRegion
nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3762 // The only time where mOpacity == 1.0 should be when we have will-change.
3763 // We could report this as opaque then but when the will-change value starts
3764 // animating the element would become non opaque and could cause repaints.
3768 // nsDisplayOpacity uses layers for rendering
3769 already_AddRefed
<Layer
>
3770 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3771 LayerManager
* aManager
,
3772 const ContainerLayerParameters
& aContainerParameters
) {
3773 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
3774 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3775 aContainerParameters
, nullptr);
3779 container
->SetOpacity(mOpacity
);
3780 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container
, aBuilder
,
3782 eCSSProperty_opacity
);
3783 return container
.forget();
3787 * This doesn't take into account layer scaling --- the layer may be
3788 * rendered at a higher (or lower) resolution, affecting the retained layer
3789 * size --- but this should be good enough.
3792 IsItemTooSmallForActiveLayer(nsDisplayItem
* aItem
)
3794 nsIntRect visibleDevPixels
= aItem
->GetVisibleRect().ToOutsidePixels(
3795 aItem
->Frame()->PresContext()->AppUnitsPerDevPixel());
3796 static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
= 16;
3797 return visibleDevPixels
.Size() <
3798 nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
);
3802 nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder
* aBuilder
)
3804 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_opacity
) &&
3805 !IsItemTooSmallForActiveLayer(this))
3807 if (mFrame
->GetContent()) {
3808 if (nsLayoutUtils::HasAnimationsForCompositor(mFrame
->GetContent(),
3809 eCSSProperty_opacity
)) {
3817 nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder
* aBuilder
,
3819 const DisplayItemClip
* aClip
)
3821 NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
3822 mOpacity
= mOpacity
* aOpacity
;
3824 IntersectClip(aBuilder
, *aClip
);
3829 nsDisplayOpacity::CanApplyOpacity() const
3835 nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
3837 if (NeedsActiveLayer(aBuilder
))
3840 nsDisplayItem
* child
= mList
.GetBottom();
3841 // Only try folding our opacity down if we have at most three children
3842 // that don't overlap and can all apply the opacity to themselves.
3847 nsDisplayItem
* item
;
3851 uint32_t numChildren
= 0;
3852 for (; numChildren
< ArrayLength(children
) && child
; numChildren
++, child
= child
->GetAbove()) {
3853 if (!child
->CanApplyOpacity()) {
3856 children
[numChildren
].item
= child
;
3857 children
[numChildren
].bounds
= child
->GetBounds(aBuilder
, &snap
);
3860 // we have a fourth (or more) child
3864 for (uint32_t i
= 0; i
< numChildren
; i
++) {
3865 for (uint32_t j
= i
+1; j
< numChildren
; j
++) {
3866 if (children
[i
].bounds
.Intersects(children
[j
].bounds
)) {
3872 for (uint32_t i
= 0; i
< numChildren
; i
++) {
3873 children
[i
].item
->ApplyOpacity(aBuilder
, mOpacity
, mClip
);
3878 nsDisplayItem::LayerState
3879 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder
* aBuilder
,
3880 LayerManager
* aManager
,
3881 const ContainerLayerParameters
& aParameters
) {
3882 if (NeedsActiveLayer(aBuilder
))
3883 return LAYER_ACTIVE
;
3885 return RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
, mList
,
3886 nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder
, aManager
));
3890 nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3891 nsRegion
* aVisibleRegion
) {
3892 // Our children are translucent so we should not allow them to subtract
3893 // area from aVisibleRegion. We do need to find out what is visible under
3894 // our children in the temporary compositing buffer, because if our children
3895 // paint our entire bounds opaquely then we don't need an alpha channel in
3896 // the temporary compositing buffer.
3897 nsRect bounds
= GetClippedBounds(aBuilder
);
3898 nsRegion visibleUnderChildren
;
3899 visibleUnderChildren
.And(*aVisibleRegion
, bounds
);
3901 nsDisplayWrapList::ComputeVisibility(aBuilder
, &visibleUnderChildren
);
3904 bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
3905 if (aItem
->GetType() != TYPE_OPACITY
)
3907 // items for the same content element should be merged into a single
3908 // compositing group
3909 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
3910 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
3912 if (aItem
->GetClip() != GetClip())
3914 MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity
*>(aItem
));
3919 nsDisplayOpacity::WriteDebugInfo(std::stringstream
& aStream
)
3921 aStream
<< " (opacity " << mOpacity
<< ")";
3924 nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder
* aBuilder
,
3925 nsIFrame
* aFrame
, nsDisplayList
* aList
,
3927 : nsDisplayWrapList(aBuilder
, aFrame
, aList
) {
3928 MOZ_COUNT_CTOR(nsDisplayMixBlendMode
);
3931 #ifdef NS_BUILD_REFCNT_LOGGING
3932 nsDisplayMixBlendMode::~nsDisplayMixBlendMode() {
3933 MOZ_COUNT_DTOR(nsDisplayMixBlendMode
);
3937 nsRegion
nsDisplayMixBlendMode::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3940 // We are never considered opaque
3945 nsDisplayMixBlendMode::GetLayerState(nsDisplayListBuilder
* aBuilder
,
3946 LayerManager
* aManager
,
3947 const ContainerLayerParameters
& aParameters
)
3949 gfxContext::GraphicsOperator op
= nsCSSRendering::GetGFXBlendMode(mFrame
->StyleDisplay()->mMixBlendMode
);
3950 if (aManager
->SupportsMixBlendMode(gfx::CompositionOpForOp(op
))) {
3951 return LAYER_ACTIVE
;
3953 return LAYER_INACTIVE
;
3956 // nsDisplayMixBlendMode uses layers for rendering
3957 already_AddRefed
<Layer
>
3958 nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3959 LayerManager
* aManager
,
3960 const ContainerLayerParameters
& aContainerParameters
) {
3961 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
3962 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
3964 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
3965 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3966 newContainerParameters
, nullptr);
3971 container
->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame
->StyleDisplay()->mMixBlendMode
));
3973 return container
.forget();
3976 bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3977 nsRegion
* aVisibleRegion
) {
3978 // Our children are need their backdrop so we should not allow them to subtract
3979 // area from aVisibleRegion. We do need to find out what is visible under
3980 // our children in the temporary compositing buffer, because if our children
3981 // paint our entire bounds opaquely then we don't need an alpha channel in
3982 // the temporary compositing buffer.
3983 nsRect bounds
= GetClippedBounds(aBuilder
);
3984 nsRegion visibleUnderChildren
;
3985 visibleUnderChildren
.And(*aVisibleRegion
, bounds
);
3986 return nsDisplayWrapList::ComputeVisibility(aBuilder
, &visibleUnderChildren
);
3989 bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
3990 if (aItem
->GetType() != TYPE_MIX_BLEND_MODE
)
3992 // items for the same content element should be merged into a single
3993 // compositing group
3994 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
3995 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
3997 if (aItem
->GetClip() != GetClip())
3999 MergeFromTrackingMergedFrames(static_cast<nsDisplayMixBlendMode
*>(aItem
));
4003 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder
* aBuilder
,
4004 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4005 BlendModeSet
& aContainedBlendModes
)
4006 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
4007 , mContainedBlendModes(aContainedBlendModes
)
4008 , mCanBeActive(true)
4010 MOZ_COUNT_CTOR(nsDisplayBlendContainer
);
4013 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder
* aBuilder
,
4014 nsIFrame
* aFrame
, nsDisplayList
* aList
)
4015 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
4016 , mCanBeActive(false)
4018 MOZ_COUNT_CTOR(nsDisplayBlendContainer
);
4021 #ifdef NS_BUILD_REFCNT_LOGGING
4022 nsDisplayBlendContainer::~nsDisplayBlendContainer() {
4023 MOZ_COUNT_DTOR(nsDisplayBlendContainer
);
4027 // nsDisplayBlendContainer uses layers for rendering
4028 already_AddRefed
<Layer
>
4029 nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4030 LayerManager
* aManager
,
4031 const ContainerLayerParameters
& aContainerParameters
) {
4032 // turn off anti-aliasing in the parent stacking context because it changes
4033 // how the group is initialized.
4034 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
4035 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
4037 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
4038 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
4039 newContainerParameters
, nullptr);
4044 container
->SetForceIsolatedGroup(true);
4045 return container
.forget();
4048 bool nsDisplayBlendContainer::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
4049 if (aItem
->GetType() != TYPE_BLEND_CONTAINER
)
4051 // items for the same content element should be merged into a single
4052 // compositing group
4053 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
4054 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
4056 if (aItem
->GetClip() != GetClip())
4058 MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer
*>(aItem
));
4062 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder
* aBuilder
,
4063 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4064 uint32_t aFlags
, ViewID aScrollTarget
)
4065 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
4067 , mScrollTarget(aScrollTarget
) {
4068 MOZ_COUNT_CTOR(nsDisplayOwnLayer
);
4071 #ifdef NS_BUILD_REFCNT_LOGGING
4072 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
4073 MOZ_COUNT_DTOR(nsDisplayOwnLayer
);
4077 // nsDisplayOpacity uses layers for rendering
4078 already_AddRefed
<Layer
>
4079 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4080 LayerManager
* aManager
,
4081 const ContainerLayerParameters
& aContainerParameters
) {
4082 nsRefPtr
<ContainerLayer
> layer
= aManager
->GetLayerBuilder()->
4083 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
4084 aContainerParameters
, nullptr);
4085 if (mFlags
& VERTICAL_SCROLLBAR
) {
4086 layer
->SetScrollbarData(mScrollTarget
, Layer::ScrollDirection::VERTICAL
);
4088 if (mFlags
& HORIZONTAL_SCROLLBAR
) {
4089 layer
->SetScrollbarData(mScrollTarget
, Layer::ScrollDirection::HORIZONTAL
);
4092 if (mFlags
& GENERATE_SUBDOC_INVALIDATIONS
) {
4093 mFrame
->PresContext()->SetNotifySubDocInvalidationData(layer
);
4095 return layer
.forget();
4098 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder
* aBuilder
,
4099 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4101 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
, aFlags
)
4102 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4104 MOZ_COUNT_CTOR(nsDisplaySubDocument
);
4105 mForceDispatchToContentRegion
=
4106 aBuilder
->IsBuildingLayerEventRegions() &&
4107 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame
->PresContext()->PresShell());
4110 #ifdef NS_BUILD_REFCNT_LOGGING
4111 nsDisplaySubDocument::~nsDisplaySubDocument() {
4112 MOZ_COUNT_DTOR(nsDisplaySubDocument
);
4116 already_AddRefed
<Layer
>
4117 nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4118 LayerManager
* aManager
,
4119 const ContainerLayerParameters
& aContainerParameters
) {
4120 nsPresContext
* presContext
= mFrame
->PresContext();
4121 nsIFrame
* rootScrollFrame
= presContext
->PresShell()->GetRootScrollFrame();
4122 ContainerLayerParameters params
= aContainerParameters
;
4123 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) &&
4124 rootScrollFrame
->GetContent() &&
4125 nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame
->GetContent(), nullptr)) {
4126 params
.mInLowPrecisionDisplayPort
= true;
4129 nsRefPtr
<Layer
> layer
= nsDisplayOwnLayer::BuildLayer(aBuilder
, aManager
, params
);
4130 layer
->AsContainerLayer()->SetEventRegionsOverride(mForceDispatchToContentRegion
4131 ? EventRegionsOverride::ForceDispatchToContent
4132 : EventRegionsOverride::NoOverride
);
4133 return layer
.forget();
4136 UniquePtr
<FrameMetrics
>
4137 nsDisplaySubDocument::ComputeFrameMetrics(Layer
* aLayer
,
4138 const ContainerLayerParameters
& aContainerParameters
)
4140 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
)) {
4141 return UniquePtr
<FrameMetrics
>(nullptr);
4144 nsPresContext
* presContext
= mFrame
->PresContext();
4145 nsIFrame
* rootScrollFrame
= presContext
->PresShell()->GetRootScrollFrame();
4146 bool isRootContentDocument
= presContext
->IsRootContentDocument();
4147 nsIPresShell
* presShell
= presContext
->PresShell();
4148 ContainerLayerParameters
params(
4149 aContainerParameters
.mXScale
* presShell
->GetXResolution(),
4150 aContainerParameters
.mYScale
* presShell
->GetYResolution(),
4151 nsIntPoint(), aContainerParameters
);
4152 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) &&
4153 rootScrollFrame
->GetContent() &&
4154 nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame
->GetContent(), nullptr)) {
4155 params
.mInLowPrecisionDisplayPort
= true;
4158 nsRect viewport
= mFrame
->GetRect() -
4159 mFrame
->GetPosition() +
4160 mFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4162 return MakeUnique
<FrameMetrics
>(
4163 nsDisplayScrollLayer::ComputeFrameMetrics(mFrame
, rootScrollFrame
, ReferenceFrame(),
4164 aLayer
, mScrollParentId
, viewport
,
4165 isRootContentDocument
, params
));
4169 UseDisplayPortForViewport(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
4170 nsRect
* aDisplayPort
= nullptr)
4172 return aBuilder
->IsPaintingToWindow() &&
4173 nsLayoutUtils::ViewportHasDisplayPort(aFrame
->PresContext(), aDisplayPort
);
4177 nsDisplaySubDocument::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4179 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4181 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
4183 return mFrame
->GetRect() + aBuilder
->ToReferenceFrame(mFrame
);
4186 return nsDisplayOwnLayer::GetBounds(aBuilder
, aSnap
);
4190 nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
4191 nsRegion
* aVisibleRegion
)
4194 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
, &displayport
);
4196 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
) || !usingDisplayPort
) {
4197 return nsDisplayWrapList::ComputeVisibility(aBuilder
, aVisibleRegion
);
4200 nsRegion childVisibleRegion
;
4201 // The visible region for the children may be much bigger than the hole we
4202 // are viewing the children from, so that the compositor process has enough
4203 // content to asynchronously pan while content is being refreshed.
4204 childVisibleRegion
= displayport
+ mFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4206 nsRect boundedRect
=
4207 childVisibleRegion
.GetBounds().Intersect(mList
.GetBounds(aBuilder
));
4208 bool visible
= mList
.ComputeVisibilityForSublist(
4209 aBuilder
, &childVisibleRegion
, boundedRect
,
4210 usingDisplayPort
? mFrame
: nullptr);
4212 // If APZ is enabled then don't allow this computation to influence
4213 // aVisibleRegion, on the assumption that the layer can be asynchronously
4214 // scrolled so we'll definitely need all the content under it.
4215 if (!nsLayoutUtils::UsesAsyncScrolling()) {
4217 nsRect bounds
= GetBounds(aBuilder
, &snap
);
4219 removed
.Sub(bounds
, childVisibleRegion
);
4221 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4228 nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
4230 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4232 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
4236 return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder
);
4240 nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4242 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4244 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
4249 return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder
, aSnap
);
4252 nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder
* aBuilder
,
4253 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4255 : nsDisplaySubDocument(aBuilder
, aFrame
, aList
, aFlags
) {
4256 MOZ_COUNT_CTOR(nsDisplayResolution
);
4259 #ifdef NS_BUILD_REFCNT_LOGGING
4260 nsDisplayResolution::~nsDisplayResolution() {
4261 MOZ_COUNT_DTOR(nsDisplayResolution
);
4265 already_AddRefed
<Layer
>
4266 nsDisplayResolution::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4267 LayerManager
* aManager
,
4268 const ContainerLayerParameters
& aContainerParameters
) {
4269 nsIPresShell
* presShell
= mFrame
->PresContext()->PresShell();
4270 ContainerLayerParameters
containerParameters(
4271 presShell
->GetXResolution(), presShell
->GetYResolution(), nsIntPoint(),
4272 aContainerParameters
);
4274 nsRefPtr
<Layer
> layer
= nsDisplaySubDocument::BuildLayer(
4275 aBuilder
, aManager
, containerParameters
);
4276 layer
->SetPostScale(1.0f
/ presShell
->GetXResolution(),
4277 1.0f
/ presShell
->GetYResolution());
4278 layer
->AsContainerLayer()->SetScaleToResolution(
4279 presShell
->ScaleToResolution(), presShell
->GetXResolution());
4280 return layer
.forget();
4283 nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder
* aBuilder
,
4285 nsDisplayList
* aList
)
4286 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
)
4288 MOZ_COUNT_CTOR(nsDisplayStickyPosition
);
4291 #ifdef NS_BUILD_REFCNT_LOGGING
4292 nsDisplayStickyPosition::~nsDisplayStickyPosition() {
4293 MOZ_COUNT_DTOR(nsDisplayStickyPosition
);
4297 already_AddRefed
<Layer
>
4298 nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4299 LayerManager
* aManager
,
4300 const ContainerLayerParameters
& aContainerParameters
) {
4301 nsRefPtr
<Layer
> layer
=
4302 nsDisplayOwnLayer::BuildLayer(aBuilder
, aManager
, aContainerParameters
);
4304 StickyScrollContainer
* stickyScrollContainer
= StickyScrollContainer::
4305 GetStickyScrollContainerForFrame(mFrame
);
4306 if (!stickyScrollContainer
) {
4307 return layer
.forget();
4310 nsIFrame
* scrollFrame
= do_QueryFrame(stickyScrollContainer
->ScrollFrame());
4311 nsPresContext
* presContext
= scrollFrame
->PresContext();
4313 // Sticky position frames whose scroll frame is the root scroll frame are
4314 // reflowed into the scroll-port size if one has been set.
4315 nsSize scrollFrameSize
= scrollFrame
->GetSize();
4316 if (scrollFrame
== presContext
->PresShell()->GetRootScrollFrame() &&
4317 presContext
->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
4318 scrollFrameSize
= presContext
->PresShell()->
4319 GetScrollPositionClampingScrollPortSize();
4322 nsLayoutUtils::SetFixedPositionLayerData(layer
, scrollFrame
,
4323 nsRect(scrollFrame
->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize
),
4324 mFrame
, presContext
, aContainerParameters
);
4326 ViewID scrollId
= nsLayoutUtils::FindOrCreateIDFor(
4327 stickyScrollContainer
->ScrollFrame()->GetScrolledFrame()->GetContent());
4329 float factor
= presContext
->AppUnitsPerDevPixel();
4332 stickyScrollContainer
->GetScrollRanges(mFrame
, &outer
, &inner
);
4333 LayerRect
stickyOuter(NSAppUnitsToFloatPixels(outer
.x
, factor
) *
4334 aContainerParameters
.mXScale
,
4335 NSAppUnitsToFloatPixels(outer
.y
, factor
) *
4336 aContainerParameters
.mYScale
,
4337 NSAppUnitsToFloatPixels(outer
.width
, factor
) *
4338 aContainerParameters
.mXScale
,
4339 NSAppUnitsToFloatPixels(outer
.height
, factor
) *
4340 aContainerParameters
.mYScale
);
4341 LayerRect
stickyInner(NSAppUnitsToFloatPixels(inner
.x
, factor
) *
4342 aContainerParameters
.mXScale
,
4343 NSAppUnitsToFloatPixels(inner
.y
, factor
) *
4344 aContainerParameters
.mYScale
,
4345 NSAppUnitsToFloatPixels(inner
.width
, factor
) *
4346 aContainerParameters
.mXScale
,
4347 NSAppUnitsToFloatPixels(inner
.height
, factor
) *
4348 aContainerParameters
.mYScale
);
4349 layer
->SetStickyPositionData(scrollId
, stickyOuter
, stickyInner
);
4351 return layer
.forget();
4354 bool nsDisplayStickyPosition::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
4355 if (aItem
->GetType() != TYPE_STICKY_POSITION
)
4357 // Items with the same fixed position frame can be merged.
4358 nsDisplayStickyPosition
* other
= static_cast<nsDisplayStickyPosition
*>(aItem
);
4359 if (other
->mFrame
!= mFrame
)
4361 if (aItem
->GetClip() != GetClip())
4363 MergeFromTrackingMergedFrames(other
);
4367 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4368 nsDisplayList
* aList
,
4369 nsIFrame
* aForFrame
,
4370 nsIFrame
* aScrolledFrame
,
4371 nsIFrame
* aScrollFrame
)
4372 : nsDisplayWrapList(aBuilder
, aForFrame
, aList
)
4373 , mScrollFrame(aScrollFrame
)
4374 , mScrolledFrame(aScrolledFrame
)
4375 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4376 , mDisplayPortContentsOpaque(false)
4378 #ifdef NS_BUILD_REFCNT_LOGGING
4379 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4382 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4383 "Need a child frame with content");
4386 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4387 nsDisplayItem
* aItem
,
4388 nsIFrame
* aForFrame
,
4389 nsIFrame
* aScrolledFrame
,
4390 nsIFrame
* aScrollFrame
)
4391 : nsDisplayWrapList(aBuilder
, aForFrame
, aItem
)
4392 , mScrollFrame(aScrollFrame
)
4393 , mScrolledFrame(aScrolledFrame
)
4394 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4395 , mDisplayPortContentsOpaque(false)
4397 #ifdef NS_BUILD_REFCNT_LOGGING
4398 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4401 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4402 "Need a child frame with content");
4405 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4406 nsIFrame
* aForFrame
,
4407 nsIFrame
* aScrolledFrame
,
4408 nsIFrame
* aScrollFrame
)
4409 : nsDisplayWrapList(aBuilder
, aForFrame
)
4410 , mScrollFrame(aScrollFrame
)
4411 , mScrolledFrame(aScrolledFrame
)
4412 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4413 , mDisplayPortContentsOpaque(false)
4415 #ifdef NS_BUILD_REFCNT_LOGGING
4416 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4419 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4420 "Need a child frame with content");
4423 #ifdef NS_BUILD_REFCNT_LOGGING
4424 nsDisplayScrollLayer::~nsDisplayScrollLayer()
4426 MOZ_COUNT_DTOR(nsDisplayScrollLayer
);
4431 nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4433 nsIScrollableFrame
* sf
= do_QueryFrame(mScrollFrame
);
4436 return sf
->GetScrollPortRect() + aBuilder
->ToReferenceFrame(mScrollFrame
);
4438 return nsDisplayWrapList::GetBounds(aBuilder
, aSnap
);
4442 nsDisplayScrollLayer::GetScrolledContentRectToDraw(nsDisplayListBuilder
* aBuilder
,
4443 nsRect
* aDisplayPort
)
4446 // The visible region for the children may be much bigger than the hole we
4447 // are viewing the children from, so that the compositor process has enough
4448 // content to asynchronously pan while content is being refreshed.
4449 // XXX mScrollFrame seems wrong here; we should add the offset of the
4451 return *aDisplayPort
+ mScrollFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4454 return GetBounds(aBuilder
, &snap
);
4457 already_AddRefed
<Layer
>
4458 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4459 LayerManager
* aManager
,
4460 const ContainerLayerParameters
& aContainerParameters
)
4462 ContainerLayerParameters params
= aContainerParameters
;
4463 if (mScrolledFrame
->GetContent() &&
4464 nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4465 params
.mInLowPrecisionDisplayPort
= true;
4468 if (mList
.IsOpaque()) {
4470 bool usingDisplayport
=
4471 nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), &displayport
);
4472 mDisplayPortContentsOpaque
= mList
.GetBounds(aBuilder
).Contains(
4473 GetScrolledContentRectToDraw(aBuilder
, usingDisplayport
? &displayport
: nullptr));
4475 mDisplayPortContentsOpaque
= false;
4478 return aManager
->GetLayerBuilder()->
4479 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
4483 UniquePtr
<FrameMetrics
>
4484 nsDisplayScrollLayer::ComputeFrameMetrics(Layer
* aLayer
,
4485 const ContainerLayerParameters
& aContainerParameters
)
4487 ContainerLayerParameters params
= aContainerParameters
;
4488 if (mScrolledFrame
->GetContent() &&
4489 nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4490 params
.mInLowPrecisionDisplayPort
= true;
4493 nsRect viewport
= mScrollFrame
->GetRect() -
4494 mScrollFrame
->GetPosition() +
4495 mScrollFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4497 return UniquePtr
<FrameMetrics
>(new FrameMetrics(
4498 ComputeFrameMetrics(mScrolledFrame
, mScrollFrame
, ReferenceFrame(), aLayer
,
4499 mScrollParentId
, viewport
, false, params
)));
4503 nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
4505 if (nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4509 return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder
);
4513 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
4514 nsRegion
* aVisibleRegion
)
4516 if (aBuilder
->IsForPluginGeometry()) {
4517 return nsDisplayWrapList::ComputeVisibility(aBuilder
, aVisibleRegion
);
4520 bool usingDisplayPort
=
4521 nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), &displayport
);
4522 nsRect scrolledContentRect
= GetScrolledContentRectToDraw(aBuilder
,
4523 usingDisplayPort
? &displayport
: nullptr);
4525 nsRect boundedRect
= scrolledContentRect
.Intersect(mList
.GetBounds(aBuilder
));
4526 nsRegion childVisibleRegion
= scrolledContentRect
;
4527 bool visible
= mList
.ComputeVisibilityForSublist(
4528 aBuilder
, &childVisibleRegion
, boundedRect
,
4529 usingDisplayPort
? mScrollFrame
: nullptr);
4531 // If APZ is enabled then don't allow this computation to influence
4532 // aVisibleRegion, on the assumption that the layer can be asynchronously
4533 // scrolled so we'll definitely need all the content under it.
4534 if (!nsLayoutUtils::UsesAsyncScrolling()) {
4536 nsRect bounds
= GetBounds(aBuilder
, &snap
);
4538 removed
.Sub(bounds
, childVisibleRegion
);
4539 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4546 nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder
* aBuilder
,
4547 LayerManager
* aManager
,
4548 const ContainerLayerParameters
& aParameters
)
4550 // Force this as a layer so we can scroll asynchronously.
4551 // This causes incorrect rendering for rounded clips!
4552 return LAYER_ACTIVE_FORCE
;
4555 // Check if we are going to clip an abs pos item that we don't contain.
4556 // Root scroll frames clip all their descendants, so we don't need to worry
4559 WouldCauseIncorrectClippingOnAbsPosItem(nsDisplayListBuilder
* aBuilder
,
4560 nsDisplayScrollLayer
* aItem
)
4562 nsIFrame
* scrollFrame
= aItem
->GetScrollFrame();
4563 nsIPresShell
* presShell
= scrollFrame
->PresContext()->PresShell();
4564 if (scrollFrame
== presShell
->GetRootScrollFrame()) {
4567 nsIFrame
* scrolledFrame
= aItem
->GetScrolledFrame();
4568 nsIFrame
* frame
= aItem
->Frame();
4569 if (frame
== scrolledFrame
|| !frame
->IsAbsolutelyPositioned() ||
4570 nsLayoutUtils::IsAncestorFrameCrossDoc(scrollFrame
, frame
, presShell
->GetRootFrame())) {
4573 if (!aItem
->GetClip().IsRectAffectedByClip(aItem
->GetChildren()->GetBounds(aBuilder
))) {
4580 nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder
* aBuilder
,
4581 nsDisplayItem
* aItem
)
4583 if (aItem
->GetType() != TYPE_SCROLL_LAYER
) {
4586 nsDisplayScrollLayer
* other
= static_cast<nsDisplayScrollLayer
*>(aItem
);
4587 if (other
->mScrolledFrame
!= this->mScrolledFrame
) {
4590 if (aItem
->GetClip() != GetClip()) {
4594 if (WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, this) ||
4595 WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, other
)) {
4599 NS_ASSERTION(other
->mReferenceFrame
== mReferenceFrame
,
4600 "Must have the same reference frame!");
4602 FrameProperties props
= mScrolledFrame
->Properties();
4603 props
.Set(nsIFrame::ScrollLayerCount(),
4604 reinterpret_cast<void*>(GetScrollLayerCount() - 1));
4606 // Swap frames with the other item before doing MergeFrom.
4607 // XXX - This ensures that the frame associated with a scroll layer after
4608 // merging is the first, rather than the last. This tends to change less,
4609 // ensuring we're more likely to retain the associated gfx layer.
4610 // See Bug 729534 and Bug 731641.
4611 nsIFrame
* tmp
= mFrame
;
4612 mFrame
= other
->mFrame
;
4613 other
->mFrame
= tmp
;
4614 MergeFromTrackingMergedFrames(other
);
4619 PropagateClip(nsDisplayListBuilder
* aBuilder
, const DisplayItemClip
& aClip
,
4620 nsDisplayList
* aList
)
4622 for (nsDisplayItem
* i
= aList
->GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
4623 DisplayItemClip
clip(i
->GetClip());
4624 clip
.IntersectWith(aClip
);
4625 i
->SetClip(aBuilder
, clip
);
4626 nsDisplayList
* list
= i
->GetSameCoordinateSystemChildren();
4628 PropagateClip(aBuilder
, aClip
, list
);
4634 nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
4636 bool badAbsPosClip
= WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, this);
4637 if (GetScrollLayerCount() > 1 || badAbsPosClip
) {
4638 // Propagate our clip to our children. The clip for the scroll frame is
4639 // on this item, but not our child items so that they can draw non-visible
4640 // parts of the display port. But if we are flattening we failed and can't
4641 // draw the extra content, so it needs to be clipped.
4642 // But don't induce our clip on abs pos frames that we shouldn't be clipping.
4643 if (!badAbsPosClip
) {
4644 PropagateClip(aBuilder
, GetClip(), &mList
);
4647 // Output something so the failure can be noted.
4649 mScrolledFrame
->GetContent()->GetProperty(nsGkAtoms::AsyncScrollLayerCreationFailed
, &status
);
4650 if (status
== NS_PROPTABLE_PROP_NOT_THERE
) {
4651 mScrolledFrame
->GetContent()->SetProperty(nsGkAtoms::AsyncScrollLayerCreationFailed
, nullptr);
4652 if (badAbsPosClip
) {
4653 printf_stderr("Async scrollable layer creation failed: scroll layer would induce incorrent clipping to an abs pos item.\n");
4655 printf_stderr("Async scrollable layer creation failed: scroll layer can't have scrollable and non-scrollable items interleaved.\n");
4657 #ifdef MOZ_DUMP_PAINTING
4658 std::stringstream ss
;
4659 nsFrame::PrintDisplayItem(aBuilder
, this, ss
, true, false);
4660 printf_stderr("%s\n", ss
.str().c_str());
4666 if (mFrame
!= mScrolledFrame
) {
4667 mMergedFrames
.AppendElement(mFrame
);
4668 mFrame
= mScrolledFrame
;
4674 nsDisplayScrollLayer::GetScrollLayerCount()
4676 FrameProperties props
= mScrolledFrame
->Properties();
4678 bool hasCount
= false;
4679 intptr_t result
= reinterpret_cast<intptr_t>(
4680 props
.Get(nsIFrame::ScrollLayerCount(), &hasCount
));
4681 // If this aborts, then the property was either not added before scroll
4682 // layers were created or the property was deleted to early. If the latter,
4683 // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so
4684 // that it is processed last.
4685 NS_ABORT_IF_FALSE(hasCount
, "nsDisplayScrollLayer should always be defined");
4688 return reinterpret_cast<intptr_t>(props
.Get(nsIFrame::ScrollLayerCount()));
4693 nsDisplayScrollLayer::WriteDebugInfo(std::stringstream
& aStream
)
4695 aStream
<< " (scrollframe " << mScrollFrame
4696 << " scrolledFrame " << mScrolledFrame
<< ")";
4699 nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
4700 nsDisplayListBuilder
* aBuilder
,
4701 nsIFrame
* aScrolledFrame
,
4702 nsIFrame
* aScrollFrame
)
4703 : nsDisplayScrollLayer(aBuilder
, aScrollFrame
, aScrolledFrame
, aScrollFrame
)
4706 #ifdef NS_BUILD_REFCNT_LOGGING
4707 MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer
);
4711 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
4713 MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer
);
4717 nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4719 return nsDisplayWrapList::GetBounds(aBuilder
, aSnap
);
4722 already_AddRefed
<Layer
>
4723 nsDisplayScrollInfoLayer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4724 LayerManager
* aManager
,
4725 const ContainerLayerParameters
& aContainerParameters
)
4727 // Only build scrollinfo layers if event-regions are disabled, so that the
4728 // compositor knows where the inactive scrollframes are. When event-regions
4729 // are enabled, the dispatch-to-content regions generally provide this
4730 // information to the APZ code. However, in some cases, there might be
4731 // content that cannot be layerized, and so needs to scroll synchronously.
4732 // To handle those cases (which are indicated by setting mHoisted to true), we
4733 // still want to generate scrollinfo layers.
4734 if (gfxPrefs::LayoutEventRegionsEnabled() && !mHoisted
) {
4737 return nsDisplayScrollLayer::BuildLayer(aBuilder
, aManager
, aContainerParameters
);
4741 nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder
* aBuilder
,
4742 LayerManager
* aManager
,
4743 const ContainerLayerParameters
& aParameters
)
4745 // See comment in BuildLayer
4746 if (gfxPrefs::LayoutEventRegionsEnabled() && !mHoisted
) {
4749 return LAYER_ACTIVE_EMPTY
;
4753 nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder
* aBuilder
,
4754 nsDisplayItem
* aItem
)
4760 nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
4762 // Layer metadata for a particular scroll frame needs to be unique. Only
4763 // one nsDisplayScrollLayer (with rendered content) or one
4764 // nsDisplayScrollInfoLayer (with only the metadata) should survive the
4765 // visibility computation.
4766 return GetScrollLayerCount() == 1;
4769 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder
* aBuilder
,
4770 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4771 int32_t aAPD
, int32_t aParentAPD
,
4773 : nsDisplaySubDocument(aBuilder
, aFrame
, aList
, aFlags
)
4774 , mAPD(aAPD
), mParentAPD(aParentAPD
) {
4775 MOZ_COUNT_CTOR(nsDisplayZoom
);
4778 #ifdef NS_BUILD_REFCNT_LOGGING
4779 nsDisplayZoom::~nsDisplayZoom() {
4780 MOZ_COUNT_DTOR(nsDisplayZoom
);
4784 nsRect
nsDisplayZoom::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4786 nsRect bounds
= nsDisplaySubDocument::GetBounds(aBuilder
, aSnap
);
4788 return bounds
.ConvertAppUnitsRoundOut(mAPD
, mParentAPD
);
4791 void nsDisplayZoom::HitTest(nsDisplayListBuilder
*aBuilder
,
4792 const nsRect
& aRect
,
4793 HitTestState
*aState
,
4794 nsTArray
<nsIFrame
*> *aOutFrames
)
4797 // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
4798 // rect as well instead of possibly rounding the width or height to zero.
4799 if (aRect
.width
== 1 && aRect
.height
== 1) {
4800 rect
.MoveTo(aRect
.TopLeft().ConvertAppUnits(mParentAPD
, mAPD
));
4801 rect
.width
= rect
.height
= 1;
4803 rect
= aRect
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4805 mList
.HitTest(aBuilder
, rect
, aState
, aOutFrames
);
4808 bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder
*aBuilder
,
4809 nsRegion
*aVisibleRegion
)
4811 // Convert the passed in visible region to our appunits.
4812 nsRegion visibleRegion
;
4813 // mVisibleRect has been clipped to GetClippedBounds
4814 visibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
4815 visibleRegion
= visibleRegion
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4816 nsRegion originalVisibleRegion
= visibleRegion
;
4818 nsRect transformedVisibleRect
=
4819 mVisibleRect
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4821 // If we are to generate a scrollable layer we call
4822 // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
4823 // for ComputeVisibility, it does all it's calculations in the child APD.
4824 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4825 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
) || !usingDisplayPort
) {
4827 mList
.ComputeVisibilityForSublist(aBuilder
, &visibleRegion
,
4828 transformedVisibleRect
);
4831 nsDisplaySubDocument::ComputeVisibility(aBuilder
, &visibleRegion
);
4835 // removed = originalVisibleRegion - visibleRegion
4836 removed
.Sub(originalVisibleRegion
, visibleRegion
);
4837 // Convert removed region to parent appunits.
4838 removed
= removed
.ConvertAppUnitsRoundIn(mAPD
, mParentAPD
);
4839 // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
4840 // SubtractFromVisibleRegion does)
4841 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4846 ///////////////////////////////////////////////////
4847 // nsDisplayTransform Implementation
4850 // Write #define UNIFIED_CONTINUATIONS here to have the transform property try
4851 // to transform content with continuations as one unified block instead of
4852 // several smaller ones. This is currently disabled because it doesn't work
4853 // correctly, since when the frames are initially being reflowed, their
4854 // continuations all compute their bounding rects independently of each other
4855 // and consequently get the wrong value. Write #define DEBUG_HIT here to have
4856 // the nsDisplayTransform class dump out a bunch of information about hit
4858 #undef UNIFIED_CONTINUATIONS
4861 /* Returns the bounds of a frame as defined for transforms. If
4862 * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
4863 * rectangle, translated to the origin. Otherwise, returns the smallest
4864 * rectangle containing a frame and all of its continuations. For example, if
4865 * there is a <span> element with several continuations split over several
4866 * lines, this function will return the rectangle containing all of those
4867 * continuations. This rectangle is relative to the origin of the frame's local
4870 #ifndef UNIFIED_CONTINUATIONS
4873 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame
* aFrame
)
4875 NS_PRECONDITION(aFrame
, "Can't get the bounds of a nonexistent frame!");
4877 if (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) {
4878 // TODO: SVG needs to define what percentage translations resolve against.
4882 return nsRect(nsPoint(0, 0), aFrame
->GetSize());
4888 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame
* aFrame
)
4890 NS_PRECONDITION(aFrame
, "Can't get the bounds of a nonexistent frame!");
4894 if (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) {
4895 // TODO: SVG needs to define what percentage translations resolve against.
4899 /* Iterate through the continuation list, unioning together all the
4902 for (const nsIFrame
*currFrame
= aFrame
->FirstContinuation();
4903 currFrame
!= nullptr;
4904 currFrame
= currFrame
->GetNextContinuation())
4906 /* Get the frame rect in local coordinates, then translate back to the
4907 * original coordinates.
4909 result
.UnionRect(result
, nsRect(currFrame
->GetOffsetTo(aFrame
),
4910 currFrame
->GetSize()));
4918 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4919 nsIFrame
*aFrame
, nsDisplayList
*aList
,
4920 const nsRect
& aChildrenVisibleRect
,
4921 ComputeTransformFunction aTransformGetter
,
4923 : nsDisplayItem(aBuilder
, aFrame
)
4924 , mStoredList(aBuilder
, aFrame
, aList
)
4925 , mTransformGetter(aTransformGetter
)
4926 , mChildrenVisibleRect(aChildrenVisibleRect
)
4929 MOZ_COUNT_CTOR(nsDisplayTransform
);
4930 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4931 NS_ABORT_IF_FALSE(!aFrame
->IsTransformed(), "Can't specify a transform getter for a transformed frame!");
4936 nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder
* aBuilder
)
4939 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(mFrame
));
4940 mToReferenceFrame
= mFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
4941 mVisibleRect
= aBuilder
->GetDirtyRect() + mToReferenceFrame
;
4945 nsDisplayTransform::Init(nsDisplayListBuilder
* aBuilder
)
4947 mStoredList
.SetClip(aBuilder
, DisplayItemClip::NoClip());
4948 mStoredList
.SetVisibleRect(mChildrenVisibleRect
);
4949 mMaybePrerender
= ShouldPrerenderTransformedContent(aBuilder
, mFrame
);
4951 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
4952 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
)) {
4953 // We will only pre-render if this will-change is on budget.
4954 mMaybePrerender
= true;
4957 if (mMaybePrerender
) {
4959 mVisibleRect
= GetBounds(aBuilder
, &snap
);
4963 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4964 nsIFrame
*aFrame
, nsDisplayList
*aList
,
4965 const nsRect
& aChildrenVisibleRect
,
4967 : nsDisplayItem(aBuilder
, aFrame
)
4968 , mStoredList(aBuilder
, aFrame
, aList
)
4969 , mTransformGetter(nullptr)
4970 , mChildrenVisibleRect(aChildrenVisibleRect
)
4973 MOZ_COUNT_CTOR(nsDisplayTransform
);
4974 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4975 SetReferenceFrameToAncestor(aBuilder
);
4979 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4980 nsIFrame
*aFrame
, nsDisplayItem
*aItem
,
4981 const nsRect
& aChildrenVisibleRect
,
4983 : nsDisplayItem(aBuilder
, aFrame
)
4984 , mStoredList(aBuilder
, aFrame
, aItem
)
4985 , mTransformGetter(nullptr)
4986 , mChildrenVisibleRect(aChildrenVisibleRect
)
4989 MOZ_COUNT_CTOR(nsDisplayTransform
);
4990 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4991 SetReferenceFrameToAncestor(aBuilder
);
4995 /* Returns the delta specified by the -moz-transform-origin property.
4996 * This is a positive delta, meaning that it indicates the direction to move
4997 * to get from (0, 0) of the frame to the transform origin. This function is
4998 * called off the main thread.
5000 /* static */ Point3D
5001 nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame
* aFrame
,
5002 float aAppUnitsPerPixel
,
5003 const nsRect
* aBoundsOverride
)
5005 NS_PRECONDITION(aFrame
, "Can't get delta for a null frame!");
5006 NS_PRECONDITION(aFrame
->IsTransformed() || aFrame
->StyleDisplay()->BackfaceIsHidden(),
5007 "Shouldn't get a delta for an untransformed frame!");
5009 if (!aFrame
->IsTransformed()) {
5013 /* For both of the coordinates, if the value of -moz-transform is a
5014 * percentage, it's relative to the size of the frame. Otherwise, if it's
5015 * a distance, it's already computed for us!
5017 const nsStyleDisplay
* display
= aFrame
->StyleDisplay();
5018 nsRect boundingRect
= (aBoundsOverride
? *aBoundsOverride
:
5019 nsDisplayTransform::GetFrameBoundsForTransform(aFrame
));
5021 /* Allows us to access named variables by index. */
5023 const nscoord
* dimensions
[2] =
5024 {&boundingRect
.width
, &boundingRect
.height
};
5026 for (uint8_t index
= 0; index
< 2; ++index
) {
5027 /* If the -moz-transform-origin specifies a percentage, take the percentage
5028 * of the size of the box.
5030 const nsStyleCoord
&coord
= display
->mTransformOrigin
[index
];
5031 if (coord
.GetUnit() == eStyleUnit_Calc
) {
5032 const nsStyleCoord::Calc
*calc
= coord
.GetCalcValue();
5034 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
5036 NSAppUnitsToFloatPixels(calc
->mLength
, aAppUnitsPerPixel
);
5037 } else if (coord
.GetUnit() == eStyleUnit_Percent
) {
5039 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
5040 coord
.GetPercentValue();
5042 NS_ABORT_IF_FALSE(coord
.GetUnit() == eStyleUnit_Coord
, "unexpected unit");
5044 NSAppUnitsToFloatPixels(coord
.GetCoordValue(), aAppUnitsPerPixel
);
5046 if ((aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) &&
5047 coord
.GetUnit() != eStyleUnit_Percent
) {
5048 // <length> values represent offsets from the origin of the SVG element's
5049 // user space, not the top left of its bounds, so we must adjust for that:
5051 (index
== 0) ? aFrame
->GetPosition().x
: aFrame
->GetPosition().y
;
5052 coords
[index
] -= NSAppUnitsToFloatPixels(offset
, aAppUnitsPerPixel
);
5056 coords
[2] = NSAppUnitsToFloatPixels(display
->mTransformOrigin
[2].GetCoordValue(),
5058 /* Adjust based on the origin of the rectangle. */
5059 coords
[0] += NSAppUnitsToFloatPixels(boundingRect
.x
, aAppUnitsPerPixel
);
5060 coords
[1] += NSAppUnitsToFloatPixels(boundingRect
.y
, aAppUnitsPerPixel
);
5062 return Point3D(coords
[0], coords
[1], coords
[2]);
5065 /* Returns the delta specified by the -moz-perspective-origin property.
5066 * This is a positive delta, meaning that it indicates the direction to move
5067 * to get from (0, 0) of the frame to the perspective origin. This function is
5068 * called off the main thread.
5070 /* static */ Point3D
5071 nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame
* aFrame
,
5072 float aAppUnitsPerPixel
)
5074 NS_PRECONDITION(aFrame
, "Can't get delta for a null frame!");
5075 NS_PRECONDITION(aFrame
->IsTransformed() || aFrame
->StyleDisplay()->BackfaceIsHidden(),
5076 "Shouldn't get a delta for an untransformed frame!");
5078 if (!aFrame
->IsTransformed()) {
5082 /* For both of the coordinates, if the value of -moz-perspective-origin is a
5083 * percentage, it's relative to the size of the frame. Otherwise, if it's
5084 * a distance, it's already computed for us!
5087 //TODO: Should this be using our bounds or the parent's bounds?
5088 // How do we handle aBoundsOverride in the latter case?
5090 nsStyleContext
* psc
= aFrame
->GetParentStyleContext(&parent
);
5095 parent
= aFrame
->GetParent();
5100 const nsStyleDisplay
* display
= psc
->StyleDisplay();
5101 nsRect boundingRect
= nsDisplayTransform::GetFrameBoundsForTransform(parent
);
5103 /* Allows us to access named variables by index. */
5106 gfx::Float
* coords
[2] = {&result
.x
, &result
.y
};
5107 const nscoord
* dimensions
[2] =
5108 {&boundingRect
.width
, &boundingRect
.height
};
5110 for (uint8_t index
= 0; index
< 2; ++index
) {
5111 /* If the -moz-transform-origin specifies a percentage, take the percentage
5112 * of the size of the box.
5114 const nsStyleCoord
&coord
= display
->mPerspectiveOrigin
[index
];
5115 if (coord
.GetUnit() == eStyleUnit_Calc
) {
5116 const nsStyleCoord::Calc
*calc
= coord
.GetCalcValue();
5118 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
5120 NSAppUnitsToFloatPixels(calc
->mLength
, aAppUnitsPerPixel
);
5121 } else if (coord
.GetUnit() == eStyleUnit_Percent
) {
5123 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
5124 coord
.GetPercentValue();
5126 NS_ABORT_IF_FALSE(coord
.GetUnit() == eStyleUnit_Coord
, "unexpected unit");
5128 NSAppUnitsToFloatPixels(coord
.GetCoordValue(), aAppUnitsPerPixel
);
5132 nsPoint parentOffset
= aFrame
->GetOffsetTo(parent
);
5134 NSAppUnitsToFloatPixels(parentOffset
.x
, aAppUnitsPerPixel
),
5135 NSAppUnitsToFloatPixels(parentOffset
.y
, aAppUnitsPerPixel
),
5138 return result
- gfxOffset
;
5141 nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame
* aFrame
,
5142 float aAppUnitsPerPixel
,
5143 const nsRect
* aBoundsOverride
)
5145 , mTransformList(aFrame
->StyleDisplay()->mSpecifiedTransform
)
5146 , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame
, aAppUnitsPerPixel
, aBoundsOverride
))
5147 , mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame
, aAppUnitsPerPixel
))
5148 , mChildPerspective(0)
5150 const nsStyleDisplay
* parentDisp
= nullptr;
5151 nsStyleContext
* parentStyleContext
= aFrame
->StyleContext()->GetParent();
5152 if (parentStyleContext
) {
5153 parentDisp
= parentStyleContext
->StyleDisplay();
5155 if (parentDisp
&& parentDisp
->mChildPerspective
.GetUnit() == eStyleUnit_Coord
) {
5156 mChildPerspective
= parentDisp
->mChildPerspective
.GetCoordValue();
5160 /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
5161 * translates from local coordinate space to transform coordinate space, then
5165 nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties
& aProperties
,
5166 const nsPoint
& aOrigin
,
5167 float aAppUnitsPerPixel
,
5168 const nsRect
* aBoundsOverride
,
5169 nsIFrame
** aOutAncestor
)
5171 return GetResultingTransformMatrixInternal(aProperties
, aOrigin
, aAppUnitsPerPixel
,
5172 aBoundsOverride
, aOutAncestor
, false);
5176 nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame
* aFrame
,
5177 const nsPoint
& aOrigin
,
5178 float aAppUnitsPerPixel
,
5179 const nsRect
* aBoundsOverride
,
5180 nsIFrame
** aOutAncestor
,
5181 bool aOffsetByOrigin
)
5183 FrameTransformProperties
props(aFrame
,
5187 return GetResultingTransformMatrixInternal(props
, aOrigin
, aAppUnitsPerPixel
,
5188 aBoundsOverride
, aOutAncestor
,
5193 nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties
& aProperties
,
5194 const nsPoint
& aOrigin
,
5195 float aAppUnitsPerPixel
,
5196 const nsRect
* aBoundsOverride
,
5197 nsIFrame
** aOutAncestor
,
5198 bool aOffsetByOrigin
)
5200 const nsIFrame
*frame
= aProperties
.mFrame
;
5203 *aOutAncestor
= nsLayoutUtils::GetCrossDocParentFrame(frame
);
5206 /* Get the underlying transform matrix. This requires us to get the
5207 * bounds of the frame.
5209 nsRect bounds
= (aBoundsOverride
? *aBoundsOverride
:
5210 nsDisplayTransform::GetFrameBoundsForTransform(frame
));
5212 /* Get the matrix, then change its basis to factor in the origin. */
5215 // Call IsSVGTransformed() regardless of the value of
5216 // disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
5217 Matrix svgTransform
, transformFromSVGParent
;
5218 bool hasSVGTransforms
=
5219 frame
&& frame
->IsSVGTransformed(&svgTransform
, &transformFromSVGParent
);
5220 /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
5221 if (aProperties
.mTransformList
) {
5222 result
= nsStyleTransformMatrix::ReadTransforms(aProperties
.mTransformList
->mHead
,
5223 frame
? frame
->StyleContext() : nullptr,
5224 frame
? frame
->PresContext() : nullptr,
5225 dummy
, bounds
, aAppUnitsPerPixel
);
5226 } else if (hasSVGTransforms
) {
5227 // Correct the translation components for zoom:
5228 float pixelsPerCSSPx
= frame
->PresContext()->AppUnitsPerCSSPixel() /
5230 svgTransform
._31
*= pixelsPerCSSPx
;
5231 svgTransform
._32
*= pixelsPerCSSPx
;
5232 result
= gfx3DMatrix::From2D(ThebesMatrix(svgTransform
));
5235 if (hasSVGTransforms
&& !transformFromSVGParent
.IsIdentity()) {
5236 // Correct the translation components for zoom:
5237 float pixelsPerCSSPx
= frame
->PresContext()->AppUnitsPerCSSPixel() /
5239 transformFromSVGParent
._31
*= pixelsPerCSSPx
;
5240 transformFromSVGParent
._32
*= pixelsPerCSSPx
;
5241 result
= result
* gfx3DMatrix::From2D(ThebesMatrix(transformFromSVGParent
));
5244 if (aProperties
.mChildPerspective
> 0.0) {
5245 gfx3DMatrix perspective
;
5247 -1.0 / NSAppUnitsToFloatPixels(aProperties
.mChildPerspective
, aAppUnitsPerPixel
);
5248 /* At the point when perspective is applied, we have been translated to the transform origin.
5249 * The translation to the perspective origin is the difference between these values.
5251 perspective
.ChangeBasis(aProperties
.mToPerspectiveOrigin
- aProperties
.mToTransformOrigin
);
5252 result
= result
* perspective
;
5255 /* Account for the -moz-transform-origin property by translating the
5256 * coordinate space to the new origin.
5259 Point3D(NSAppUnitsToFloatPixels(aOrigin
.x
, aAppUnitsPerPixel
),
5260 NSAppUnitsToFloatPixels(aOrigin
.y
, aAppUnitsPerPixel
),
5262 Point3D
roundedOrigin(hasSVGTransforms
? newOrigin
.x
: NS_round(newOrigin
.x
),
5263 hasSVGTransforms
? newOrigin
.y
: NS_round(newOrigin
.y
),
5265 Point3D offsetBetweenOrigins
= roundedOrigin
+ aProperties
.mToTransformOrigin
;
5267 if (frame
&& frame
->Preserves3D()) {
5268 // Include the transform set on our parent
5269 NS_ASSERTION(frame
->GetParent() &&
5270 frame
->GetParent()->IsTransformed() &&
5271 frame
->GetParent()->Preserves3DChildren(),
5272 "Preserve3D mismatch!");
5273 FrameTransformProperties
props(frame
->GetParent(),
5277 // If this frame isn't transformed (but we exist for backface-visibility),
5278 // then we're not a reference frame so no offset to origin will be added. Our
5279 // parent transform however *is* the reference frame, so we pass true for
5280 // aOffsetByOrigin to convert into the correct coordinate space.
5281 gfx3DMatrix parent
=
5282 GetResultingTransformMatrixInternal(props
,
5283 aOrigin
- frame
->GetPosition(),
5284 aAppUnitsPerPixel
, nullptr,
5285 aOutAncestor
, !frame
->IsTransformed());
5287 result
.ChangeBasis(offsetBetweenOrigins
);
5288 result
= result
* parent
;
5289 if (aOffsetByOrigin
) {
5290 result
.Translate(roundedOrigin
);
5295 if (aOffsetByOrigin
) {
5296 // We can fold the final translation by roundedOrigin into the first matrix
5297 // basis change translation. This is more stable against variation due to
5298 // insufficient floating point precision than reversing the translation
5300 result
.Translate(-aProperties
.mToTransformOrigin
);
5301 result
.TranslatePost(offsetBetweenOrigins
);
5303 result
.ChangeBasis(offsetBetweenOrigins
);
5309 nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder
* aBuilder
)
5311 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_opacity
)) {
5315 if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
5317 message
.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
5318 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5319 Frame()->GetContent());
5325 nsDisplayTransform::ShouldPrerender(nsDisplayListBuilder
* aBuilder
) {
5326 if (!mMaybePrerender
) {
5330 if (ShouldPrerenderTransformedContent(aBuilder
, mFrame
)) {
5334 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
5335 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
) &&
5336 aBuilder
->IsInWillChangeBudget(mFrame
)) {
5344 nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder
* aBuilder
)
5346 if (mMaybePrerender
) {
5347 // TODO We need to make sure that if we use async animation we actually
5348 // pre-render even if we're out of will change budget.
5351 DebugOnly
<bool> prerender
= ShouldPrerenderTransformedContent(aBuilder
, mFrame
, true);
5352 NS_ASSERTION(!prerender
, "Something changed under us!");
5357 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder
* aBuilder
,
5359 bool aLogAnimations
)
5361 // Elements whose transform has been modified recently, or which
5362 // have a compositor-animated transform, can be prerendered. An element
5363 // might have only just had its transform animated in which case
5364 // the ActiveLayerManager may not have been notified yet.
5365 if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame
, eCSSProperty_transform
) &&
5366 (!aFrame
->GetContent() ||
5367 !nsLayoutUtils::HasAnimationsForCompositor(aFrame
->GetContent(),
5368 eCSSProperty_transform
))) {
5369 if (aLogAnimations
) {
5371 message
.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
5372 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5373 aFrame
->GetContent());
5378 nsSize refSize
= aBuilder
->RootReferenceFrame()->GetSize();
5379 // Only prerender if the transformed frame's size is <= the
5380 // reference frame size (~viewport), allowing a 1/8th fuzz factor
5381 // for shadows, borders, etc.
5382 refSize
+= nsSize(refSize
.width
/ 8, refSize
.height
/ 8);
5383 nsSize frameSize
= aFrame
->GetVisualOverflowRectRelativeToSelf().Size();
5384 nscoord maxInAppUnits
= nscoord_MAX
;
5385 if (frameSize
<= refSize
) {
5386 maxInAppUnits
= aFrame
->PresContext()->DevPixelsToAppUnits(4096);
5387 nsRect visual
= aFrame
->GetVisualOverflowRect();
5388 if (visual
.width
<= maxInAppUnits
&& visual
.height
<= maxInAppUnits
) {
5393 if (aLogAnimations
) {
5394 nsRect visual
= aFrame
->GetVisualOverflowRect();
5397 message
.AppendLiteral("Performance warning: Async animation disabled because frame size (");
5398 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize
.width
));
5399 message
.AppendLiteral(", ");
5400 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize
.height
));
5401 message
.AppendLiteral(") is bigger than the viewport (");
5402 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize
.width
));
5403 message
.AppendLiteral(", ");
5404 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize
.height
));
5405 message
.AppendLiteral(") or the visual rectangle (");
5406 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual
.width
));
5407 message
.AppendLiteral(", ");
5408 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual
.height
));
5409 message
.AppendLiteral(") is larger than the max allowable value (");
5410 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits
));
5411 message
.Append(')');
5412 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5413 aFrame
->GetContent());
5418 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
5419 static bool IsFrameVisible(nsIFrame
* aFrame
, const Matrix4x4
& aMatrix
)
5421 if (aMatrix
.IsSingular()) {
5424 if (aFrame
->StyleDisplay()->mBackfaceVisibility
== NS_STYLE_BACKFACE_VISIBILITY_HIDDEN
&&
5425 aMatrix
.IsBackfaceVisible()) {
5432 nsDisplayTransform::GetTransform()
5434 if (mTransform
.IsIdentity()) {
5435 float scale
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5437 Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame
.x
, scale
),
5438 NSAppUnitsToFloatPixels(mToReferenceFrame
.y
, scale
),
5440 if (mTransformGetter
) {
5441 mTransform
= mTransformGetter(mFrame
, scale
);
5442 mTransform
.ChangeBasis(newOrigin
.x
, newOrigin
.y
, newOrigin
.z
);
5445 * Passing true as the final argument means that we want to shift the
5446 * coordinates to be relative to our reference frame instead of relative
5448 * When we have preserve-3d, our reference frame is already guaranteed
5449 * to be an ancestor of the preserve-3d chain, so we only need to do
5452 mTransform
= ToMatrix4x4(
5453 GetResultingTransformMatrix(mFrame
, ToReferenceFrame(), scale
,
5454 nullptr, nullptr, mFrame
->IsTransformed()));
5461 nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
5463 return ShouldPrerender(aBuilder
);
5466 already_AddRefed
<Layer
> nsDisplayTransform::BuildLayer(nsDisplayListBuilder
*aBuilder
,
5467 LayerManager
*aManager
,
5468 const ContainerLayerParameters
& aContainerParameters
)
5470 const Matrix4x4
& newTransformMatrix
= GetTransform();
5472 if (mFrame
->StyleDisplay()->mBackfaceVisibility
== NS_STYLE_BACKFACE_VISIBILITY_HIDDEN
&&
5473 newTransformMatrix
.IsBackfaceVisible()) {
5477 uint32_t flags
= ShouldPrerender(aBuilder
) ?
5478 FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS
: 0;
5479 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
5480 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, mStoredList
.GetChildren(),
5481 aContainerParameters
, &newTransformMatrix
, flags
);
5487 // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
5488 // so we never need to explicitely unset this flag.
5489 if (mFrame
->Preserves3D() || mFrame
->Preserves3DChildren()) {
5490 container
->SetContentFlags(container
->GetContentFlags() | Layer::CONTENT_PRESERVE_3D
);
5492 container
->SetContentFlags(container
->GetContentFlags() & ~Layer::CONTENT_PRESERVE_3D
);
5495 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container
, aBuilder
,
5497 eCSSProperty_transform
);
5498 if (ShouldPrerender(aBuilder
)) {
5499 container
->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
5500 /*the value is irrelevant*/nullptr);
5501 container
->SetContentFlags(container
->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM
);
5503 container
->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
5504 container
->SetContentFlags(container
->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM
);
5506 return container
.forget();
5509 nsDisplayItem::LayerState
5510 nsDisplayTransform::GetLayerState(nsDisplayListBuilder
* aBuilder
,
5511 LayerManager
* aManager
,
5512 const ContainerLayerParameters
& aParameters
) {
5513 // If the transform is 3d, or the layer takes part in preserve-3d sorting
5514 // then we *always* want this to be an active layer.
5515 if (!GetTransform().Is2D() || mFrame
->Preserves3D()) {
5516 return LAYER_ACTIVE_FORCE
;
5518 // Here we check if the *post-transform* bounds of this item are big enough
5519 // to justify an active layer.
5520 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_transform
) &&
5521 !IsItemTooSmallForActiveLayer(this))
5522 return LAYER_ACTIVE
;
5523 if (mFrame
->GetContent()) {
5524 if (nsLayoutUtils::HasAnimationsForCompositor(mFrame
->GetContent(),
5525 eCSSProperty_transform
)) {
5526 return LAYER_ACTIVE
;
5530 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
5531 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
)) {
5532 return LAYER_ACTIVE
;
5535 // Expect the child display items to have this frame as their animated
5536 // geometry root (since it will be their reference frame). If they have a
5537 // different animated geometry root, we'll make this an active layer so the
5538 // animation can be accelerated.
5539 return RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
,
5540 *mStoredList
.GetChildren(), Frame());
5543 bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder
*aBuilder
,
5544 nsRegion
*aVisibleRegion
)
5546 /* As we do this, we need to be sure to
5547 * untransform the visible rect, since we want everything that's painting to
5548 * think that it's painting in its original rectangular coordinate space.
5549 * If we can't untransform, take the entire overflow rect */
5550 nsRect untransformedVisibleRect
;
5551 if (ShouldPrerender(aBuilder
) ||
5552 !UntransformVisibleRect(aBuilder
, &untransformedVisibleRect
))
5554 untransformedVisibleRect
= mFrame
->GetVisualOverflowRectRelativeToSelf();
5556 nsRegion untransformedVisible
= untransformedVisibleRect
;
5557 // Call RecomputeVisiblity instead of ComputeVisibility since
5558 // nsDisplayItem::ComputeVisibility should only be called from
5559 // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
5560 mStoredList
.RecomputeVisibility(aBuilder
, &untransformedVisible
);
5568 /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
5569 void nsDisplayTransform::HitTest(nsDisplayListBuilder
*aBuilder
,
5570 const nsRect
& aRect
,
5571 HitTestState
*aState
,
5572 nsTArray
<nsIFrame
*> *aOutFrames
)
5574 /* Here's how this works:
5575 * 1. Get the matrix. If it's singular, abort (clearly we didn't hit
5577 * 2. Invert the matrix.
5578 * 3. Use it to transform the rect into the correct space.
5579 * 4. Pass that rect down through to the list's version of HitTest.
5581 // GetTransform always operates in dev pixels.
5582 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5583 Matrix4x4 matrix
= GetTransform();
5585 if (!IsFrameVisible(mFrame
, matrix
)) {
5589 /* We want to go from transformed-space to regular space.
5590 * Thus we have to invert the matrix, which normally does
5591 * the reverse operation (e.g. regular->transformed)
5594 /* Now, apply the transform and pass it down the channel. */
5596 nsRect resultingRect
;
5597 if (aRect
.width
== 1 && aRect
.height
== 1) {
5598 // Magic width/height indicating we're hit testing a point, not a rect
5599 Point4D point
= matrix
.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect
.x
, factor
),
5600 NSAppUnitsToFloatPixels(aRect
.y
, factor
)));
5601 if (!point
.HasPositiveWCoord()) {
5605 Point point2d
= point
.As2DPoint();
5607 resultingRect
= nsRect(NSFloatPixelsToAppUnits(float(point2d
.x
), factor
),
5608 NSFloatPixelsToAppUnits(float(point2d
.y
), factor
),
5612 Rect
originalRect(NSAppUnitsToFloatPixels(aRect
.x
, factor
),
5613 NSAppUnitsToFloatPixels(aRect
.y
, factor
),
5614 NSAppUnitsToFloatPixels(aRect
.width
, factor
),
5615 NSAppUnitsToFloatPixels(aRect
.height
, factor
));
5617 Rect rect
= matrix
.ProjectRectBounds(originalRect
);
5620 nsRect childBounds
= mStoredList
.GetBounds(aBuilder
, &snap
);
5621 Rect
childGfxBounds(NSAppUnitsToFloatPixels(childBounds
.x
, factor
),
5622 NSAppUnitsToFloatPixels(childBounds
.y
, factor
),
5623 NSAppUnitsToFloatPixels(childBounds
.width
, factor
),
5624 NSAppUnitsToFloatPixels(childBounds
.height
, factor
));
5625 rect
= rect
.Intersect(childGfxBounds
);
5627 resultingRect
= nsRect(NSFloatPixelsToAppUnits(float(rect
.X()), factor
),
5628 NSFloatPixelsToAppUnits(float(rect
.Y()), factor
),
5629 NSFloatPixelsToAppUnits(float(rect
.Width()), factor
),
5630 NSFloatPixelsToAppUnits(float(rect
.Height()), factor
));
5633 if (resultingRect
.IsEmpty()) {
5639 printf("Frame: %p\n", dynamic_cast<void *>(mFrame
));
5640 printf(" Untransformed point: (%f, %f)\n", resultingRect
.X(), resultingRect
.Y());
5641 uint32_t originalFrameCount
= aOutFrames
.Length();
5644 mStoredList
.HitTest(aBuilder
, resultingRect
, aState
, aOutFrames
);
5647 if (originalFrameCount
!= aOutFrames
.Length())
5648 printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
5649 dynamic_cast<void *>(aOutFrames
.ElementAt(0)));
5650 printf("=== end of hit test ===\n");
5656 nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder
* aBuilder
, const nsPoint
& aPoint
)
5658 // GetTransform always operates in dev pixels.
5659 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5660 Matrix4x4 matrix
= GetTransform();
5662 NS_ASSERTION(IsFrameVisible(mFrame
, matrix
), "We can't have hit a frame that isn't visible!");
5664 Matrix4x4 inverse
= matrix
;
5666 Point4D point
= inverse
.ProjectPoint(Point(NSAppUnitsToFloatPixels(aPoint
.x
, factor
),
5667 NSAppUnitsToFloatPixels(aPoint
.y
, factor
)));
5668 NS_ASSERTION(point
.HasPositiveWCoord(), "Why are we trying to get the depth for a point we didn't hit?");
5670 Point point2d
= point
.As2DPoint();
5672 Point3D transformed
= matrix
* Point3D(point2d
.x
, point2d
.y
, 0);
5673 return transformed
.z
;
5676 /* The bounding rectangle for the object is the overflow rectangle translated
5677 * by the reference point.
5679 nsRect
nsDisplayTransform::GetBounds(nsDisplayListBuilder
*aBuilder
, bool* aSnap
)
5681 nsRect untransformedBounds
= MaybePrerender() ?
5682 mFrame
->GetVisualOverflowRectRelativeToSelf() :
5683 mStoredList
.GetBounds(aBuilder
, aSnap
);
5685 // GetTransform always operates in dev pixels.
5686 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5687 return nsLayoutUtils::MatrixTransformRect(untransformedBounds
,
5688 To3DMatrix(GetTransform()),
5692 /* The transform is opaque iff the transform consists solely of scales and
5693 * translations and if the underlying content is opaque. Thus if the transform
5700 * We need b and c to be zero.
5702 * We also need to check whether the underlying opaque content completely fills
5703 * our visible rect. We use UntransformRect which expands to the axis-aligned
5704 * bounding rect, but that's OK since if
5705 * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
5706 * certainly contains the actual (non-axis-aligned) untransformed rect.
5708 nsRegion
nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder
*aBuilder
,
5712 nsRect untransformedVisible
;
5713 // If we're going to prerender all our content, pretend like we
5714 // don't have opqaue content so that everything under us is rendered
5715 // as well. That will increase graphics memory usage if our frame
5716 // covers the entire window, but it allows our transform to be
5717 // updated extremely cheaply, without invalidating any other
5719 if (MaybePrerender() ||
5720 !UntransformVisibleRect(aBuilder
, &untransformedVisible
)) {
5724 const Matrix4x4
& matrix
= GetTransform();
5729 if (matrix
.Is2D(&matrix2d
) &&
5730 matrix2d
.PreservesAxisAlignedRectangles() &&
5731 mStoredList
.GetOpaqueRegion(aBuilder
, &tmpSnap
).Contains(untransformedVisible
)) {
5732 result
= mVisibleRect
.Intersect(GetBounds(aBuilder
, &tmpSnap
));
5737 /* The transform is uniform if it fills the entire bounding rect and the
5738 * wrapped list is uniform. See GetOpaqueRegion for discussion of why this
5741 bool nsDisplayTransform::IsUniform(nsDisplayListBuilder
*aBuilder
, nscolor
* aColor
)
5743 nsRect untransformedVisible
;
5744 if (!UntransformVisibleRect(aBuilder
, &untransformedVisible
)) {
5747 const Matrix4x4
& matrix
= GetTransform();
5750 return matrix
.Is2D(&matrix2d
) &&
5751 matrix2d
.PreservesAxisAlignedRectangles() &&
5752 mStoredList
.GetVisibleRect().Contains(untransformedVisible
) &&
5753 mStoredList
.IsUniform(aBuilder
, aColor
);
5756 /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
5757 * share the same underlying content. Otherwise, doing so results in graphical
5760 #ifndef UNIFIED_CONTINUATIONS
5763 nsDisplayTransform::TryMerge(nsDisplayListBuilder
*aBuilder
,
5764 nsDisplayItem
*aItem
)
5772 nsDisplayTransform::TryMerge(nsDisplayListBuilder
*aBuilder
,
5773 nsDisplayItem
*aItem
)
5775 NS_PRECONDITION(aItem
, "Why did you try merging with a null item?");
5776 NS_PRECONDITION(aBuilder
, "Why did you try merging with a null builder?");
5778 /* Make sure that we're dealing with two transforms. */
5779 if (aItem
->GetType() != TYPE_TRANSFORM
)
5782 /* Check to see that both frames are part of the same content. */
5783 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
5786 if (aItem
->GetClip() != GetClip())
5789 /* Now, move everything over to this frame and signal that
5792 mStoredList
.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform
*>(aItem
)->mStoredList
);
5798 /* TransformRect takes in as parameters a rectangle (in app space) and returns
5799 * the smallest rectangle (in app space) containing the transformed image of
5800 * that rectangle. That is, it takes the four corners of the rectangle,
5801 * transforms them according to the matrix associated with the specified frame,
5802 * then returns the smallest rectangle containing the four transformed points.
5804 * @param aUntransformedBounds The rectangle (in app units) to transform.
5805 * @param aFrame The frame whose transformation should be applied.
5806 * @param aOrigin The delta from the frame origin to the coordinate space origin
5807 * @param aBoundsOverride (optional) Force the frame bounds to be the
5809 * @return The smallest rectangle containing the image of the transformed
5812 nsRect
nsDisplayTransform::TransformRect(const nsRect
&aUntransformedBounds
,
5813 const nsIFrame
* aFrame
,
5814 const nsPoint
&aOrigin
,
5815 const nsRect
* aBoundsOverride
)
5817 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5819 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5820 return nsLayoutUtils::MatrixTransformRect
5821 (aUntransformedBounds
,
5822 GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, aBoundsOverride
),
5826 nsRect
nsDisplayTransform::TransformRectOut(const nsRect
&aUntransformedBounds
,
5827 const nsIFrame
* aFrame
,
5828 const nsPoint
&aOrigin
,
5829 const nsRect
* aBoundsOverride
)
5831 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5833 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5834 return nsLayoutUtils::MatrixTransformRectOut
5835 (aUntransformedBounds
,
5836 GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, aBoundsOverride
),
5840 bool nsDisplayTransform::UntransformRect(const nsRect
&aTransformedBounds
,
5841 const nsRect
&aChildBounds
,
5842 const nsIFrame
* aFrame
,
5843 const nsPoint
&aOrigin
,
5846 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5848 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5850 gfx3DMatrix transform
= GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, nullptr);
5851 if (transform
.IsSingular()) {
5855 Rect
result(NSAppUnitsToFloatPixels(aTransformedBounds
.x
, factor
),
5856 NSAppUnitsToFloatPixels(aTransformedBounds
.y
, factor
),
5857 NSAppUnitsToFloatPixels(aTransformedBounds
.width
, factor
),
5858 NSAppUnitsToFloatPixels(aTransformedBounds
.height
, factor
));
5860 Rect
childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds
.x
, factor
),
5861 NSAppUnitsToFloatPixels(aChildBounds
.y
, factor
),
5862 NSAppUnitsToFloatPixels(aChildBounds
.width
, factor
),
5863 NSAppUnitsToFloatPixels(aChildBounds
.height
, factor
));
5865 result
= ToMatrix4x4(transform
.Inverse()).ProjectRectBounds(result
);
5866 result
= result
.Intersect(childGfxBounds
);
5867 *aOutRect
= nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result
), factor
);
5871 bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder
* aBuilder
,
5874 const gfx3DMatrix
& matrix
= To3DMatrix(GetTransform());
5875 if (matrix
.IsSingular())
5878 // GetTransform always operates in dev pixels.
5879 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5880 Rect
result(NSAppUnitsToFloatPixels(mVisibleRect
.x
, factor
),
5881 NSAppUnitsToFloatPixels(mVisibleRect
.y
, factor
),
5882 NSAppUnitsToFloatPixels(mVisibleRect
.width
, factor
),
5883 NSAppUnitsToFloatPixels(mVisibleRect
.height
, factor
));
5886 nsRect childBounds
= mStoredList
.GetBounds(aBuilder
, &snap
);
5887 Rect
childGfxBounds(NSAppUnitsToFloatPixels(childBounds
.x
, factor
),
5888 NSAppUnitsToFloatPixels(childBounds
.y
, factor
),
5889 NSAppUnitsToFloatPixels(childBounds
.width
, factor
),
5890 NSAppUnitsToFloatPixels(childBounds
.height
, factor
));
5892 /* We want to untransform the matrix, so invert the transformation first! */
5893 result
= ToMatrix4x4(matrix
.Inverse()).ProjectRectBounds(result
);
5894 result
= result
.Intersect(childGfxBounds
);
5896 *aOutRect
= nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result
), factor
);
5902 nsDisplayTransform::WriteDebugInfo(std::stringstream
& aStream
)
5904 AppendToString(aStream
, GetTransform());
5907 nsDisplayItemGeometry
*
5908 nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder
* aBuilder
)
5910 return new nsCharClipGeometry(this, aBuilder
);
5914 nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
5915 const nsDisplayItemGeometry
* aGeometry
,
5916 nsRegion
* aInvalidRegion
)
5918 const nsCharClipGeometry
* geometry
= static_cast<const nsCharClipGeometry
*>(aGeometry
);
5921 nsRect newRect
= geometry
->mBounds
;
5922 nsRect oldRect
= GetBounds(aBuilder
, &snap
);
5923 if (mLeftEdge
!= geometry
->mLeftEdge
||
5924 mRightEdge
!= geometry
->mRightEdge
||
5925 !oldRect
.IsEqualInterior(newRect
) ||
5926 !geometry
->mBorderRect
.IsEqualInterior(GetBorderRect())) {
5927 aInvalidRegion
->Or(oldRect
, newRect
);
5931 nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder
* aBuilder
,
5932 nsIFrame
* aFrame
, nsDisplayList
* aList
)
5933 : nsDisplayWrapList(aBuilder
, aFrame
, aList
),
5934 mEffectsBounds(aFrame
->GetVisualOverflowRectRelativeToSelf())
5936 MOZ_COUNT_CTOR(nsDisplaySVGEffects
);
5939 #ifdef NS_BUILD_REFCNT_LOGGING
5940 nsDisplaySVGEffects::~nsDisplaySVGEffects()
5942 MOZ_COUNT_DTOR(nsDisplaySVGEffects
);
5946 nsDisplayVR::nsDisplayVR(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
5947 nsDisplayList
* aList
, mozilla::gfx::VRHMDInfo
* aHMD
)
5948 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
)
5953 already_AddRefed
<Layer
>
5954 nsDisplayVR::BuildLayer(nsDisplayListBuilder
* aBuilder
,
5955 LayerManager
* aManager
,
5956 const ContainerLayerParameters
& aContainerParameters
)
5958 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
5959 uint32_t flags
= FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS
;
5960 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
5961 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
5962 newContainerParameters
, nullptr, flags
);
5964 container
->SetVRHMDInfo(mHMD
);
5965 container
->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
5966 /*the value is irrelevant*/nullptr);
5968 return container
.forget();
5970 nsRegion
nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
5978 nsDisplaySVGEffects::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
5979 HitTestState
* aState
, nsTArray
<nsIFrame
*> *aOutFrames
)
5981 nsPoint
rectCenter(aRect
.x
+ aRect
.width
/ 2, aRect
.y
+ aRect
.height
/ 2);
5982 if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame
,
5983 rectCenter
- ToReferenceFrame())) {
5984 mList
.HitTest(aBuilder
, aRect
, aState
, aOutFrames
);
5989 nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder
* aBuilder
,
5990 nsRenderingContext
* aCtx
,
5991 LayerManager
* aManager
)
5993 nsSVGIntegrationUtils::PaintFramesWithEffects(*aCtx
->ThebesContext(), mFrame
,
5995 aBuilder
, aManager
);
5999 nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder
* aBuilder
,
6000 LayerManager
* aManager
,
6001 const ContainerLayerParameters
& aParameters
)
6003 return LAYER_SVG_EFFECTS
;
6006 already_AddRefed
<Layer
>
6007 nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder
* aBuilder
,
6008 LayerManager
* aManager
,
6009 const ContainerLayerParameters
& aContainerParameters
)
6011 const nsIContent
* content
= mFrame
->GetContent();
6012 bool hasSVGLayout
= (mFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
);
6014 nsISVGChildFrame
*svgChildFrame
= do_QueryFrame(mFrame
);
6015 if (!svgChildFrame
|| !mFrame
->GetContent()->IsSVG()) {
6016 NS_ASSERTION(false, "why?");
6019 if (!static_cast<const nsSVGElement
*>(content
)->HasValidDimensions()) {
6020 return nullptr; // The SVG spec says not to draw filters for this
6024 float opacity
= mFrame
->StyleDisplay()->mOpacity
;
6025 if (opacity
== 0.0f
)
6028 nsIFrame
* firstFrame
=
6029 nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame
);
6030 nsSVGEffects::EffectProperties effectProperties
=
6031 nsSVGEffects::GetEffectProperties(firstFrame
);
6033 bool isOK
= effectProperties
.HasNoFilterOrHasValidFilter();
6034 effectProperties
.GetClipPathFrame(&isOK
);
6035 effectProperties
.GetMaskFrame(&isOK
);
6041 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
6042 if (effectProperties
.HasValidFilter()) {
6043 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
6046 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
6047 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
6048 newContainerParameters
, nullptr);
6050 return container
.forget();
6053 bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
6054 nsRegion
* aVisibleRegion
) {
6055 nsPoint offset
= ToReferenceFrame();
6057 nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame
,
6058 mVisibleRect
- offset
) +
6061 // Our children may be made translucent or arbitrarily deformed so we should
6062 // not allow them to subtract area from aVisibleRegion.
6063 nsRegion
childrenVisible(dirtyRect
);
6064 nsRect r
= dirtyRect
.Intersect(mList
.GetBounds(aBuilder
));
6065 mList
.ComputeVisibilityForSublist(aBuilder
, &childrenVisible
, r
);
6069 bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
)
6071 if (aItem
->GetType() != TYPE_SVG_EFFECTS
)
6073 // items for the same content element should be merged into a single
6074 // compositing group
6075 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
6076 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
6078 if (aItem
->GetClip() != GetClip())
6080 nsDisplaySVGEffects
* other
= static_cast<nsDisplaySVGEffects
*>(aItem
);
6081 MergeFromTrackingMergedFrames(other
);
6082 mEffectsBounds
.UnionRect(mEffectsBounds
,
6083 other
->mEffectsBounds
+ other
->mFrame
->GetOffsetTo(mFrame
));
6088 nsDisplaySVGEffects::BBoxInUserSpace() const
6090 return nsSVGUtils::GetBBox(mFrame
);
6094 nsDisplaySVGEffects::UserSpaceOffset() const
6096 return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame
);
6100 nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
6101 const nsDisplayItemGeometry
* aGeometry
,
6102 nsRegion
* aInvalidRegion
)
6104 const nsDisplaySVGEffectsGeometry
* geometry
=
6105 static_cast<const nsDisplaySVGEffectsGeometry
*>(aGeometry
);
6107 nsRect bounds
= GetBounds(aBuilder
, &snap
);
6108 if (geometry
->mFrameOffsetToReferenceFrame
!= ToReferenceFrame() ||
6109 geometry
->mUserSpaceOffset
!= UserSpaceOffset() ||
6110 !geometry
->mBBox
.IsEqualInterior(BBoxInUserSpace())) {
6111 // Filter and mask output can depend on the location of the frame's user
6112 // space and on the frame's BBox. We need to invalidate if either of these
6113 // change relative to the reference frame.
6114 // Invalidations from our inactive layer manager are not enough to catch
6115 // some of these cases because filters can produce output even if there's
6116 // nothing in the filter input.
6117 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
6121 #ifdef MOZ_DUMP_PAINTING
6123 nsDisplaySVGEffects::PrintEffects(nsACString
& aTo
)
6125 nsIFrame
* firstFrame
=
6126 nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame
);
6127 nsSVGEffects::EffectProperties effectProperties
=
6128 nsSVGEffects::GetEffectProperties(firstFrame
);
6130 nsSVGClipPathFrame
*clipPathFrame
= effectProperties
.GetClipPathFrame(&isOK
);
6132 aTo
+= " effects=(";
6133 if (mFrame
->StyleDisplay()->mOpacity
!= 1.0f
) {
6135 aTo
+= nsPrintfCString("opacity(%f)", mFrame
->StyleDisplay()->mOpacity
);
6137 if (clipPathFrame
) {
6141 aTo
+= nsPrintfCString("clip(%s)", clipPathFrame
->IsTrivial() ? "trivial" : "non-trivial");
6144 if (effectProperties
.HasValidFilter()) {
6151 if (effectProperties
.GetMaskFrame(&isOK
)) {