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/Preferences.h"
58 #include "mozilla/UniquePtr.h"
59 #include "ActiveLayerTracker.h"
60 #include "nsContentUtils.h"
61 #include "nsPrintfCString.h"
62 #include "UnitTransforms.h"
63 #include "LayersLogging.h"
64 #include "FrameLayerBuilder.h"
65 #include "RestyleManager.h"
67 #include "nsISelection.h"
69 using namespace mozilla
;
70 using namespace mozilla::layers
;
71 using namespace mozilla::dom
;
72 using namespace mozilla::layout
;
73 using namespace mozilla::gfx
;
75 typedef FrameMetrics::ViewID ViewID
;
79 SpammyLayoutWarningsEnabled()
81 static bool sValue
= false;
82 static bool sValueInitialized
= false;
84 if (!sValueInitialized
) {
85 Preferences::GetBool("layout.spammy_warnings.enabled", &sValue
);
86 sValueInitialized
= true;
93 static inline nsIFrame
*
94 GetTransformRootFrame(nsIFrame
* aFrame
)
96 return nsLayoutUtils::GetTransformRootFrame(aFrame
);
99 static void AddTransformFunctions(nsCSSValueList
* aList
,
100 nsStyleContext
* aContext
,
101 nsPresContext
* aPresContext
,
103 InfallibleTArray
<TransformFunction
>& aFunctions
)
105 if (aList
->mValue
.GetUnit() == eCSSUnit_None
) {
109 for (const nsCSSValueList
* curr
= aList
; curr
; curr
= curr
->mNext
) {
110 const nsCSSValue
& currElem
= curr
->mValue
;
111 NS_ASSERTION(currElem
.GetUnit() == eCSSUnit_Function
,
112 "Stream should consist solely of functions!");
113 nsCSSValue::Array
* array
= currElem
.GetArrayValue();
114 bool canStoreInRuleTree
= true;
115 switch (nsStyleTransformMatrix::TransformFunctionOf(array
)) {
116 case eCSSKeyword_rotatex
:
118 double theta
= array
->Item(1).GetAngleValueInRadians();
119 aFunctions
.AppendElement(RotationX(theta
));
122 case eCSSKeyword_rotatey
:
124 double theta
= array
->Item(1).GetAngleValueInRadians();
125 aFunctions
.AppendElement(RotationY(theta
));
128 case eCSSKeyword_rotatez
:
130 double theta
= array
->Item(1).GetAngleValueInRadians();
131 aFunctions
.AppendElement(RotationZ(theta
));
134 case eCSSKeyword_rotate
:
136 double theta
= array
->Item(1).GetAngleValueInRadians();
137 aFunctions
.AppendElement(Rotation(theta
));
140 case eCSSKeyword_rotate3d
:
142 double x
= array
->Item(1).GetFloatValue();
143 double y
= array
->Item(2).GetFloatValue();
144 double z
= array
->Item(3).GetFloatValue();
145 double theta
= array
->Item(4).GetAngleValueInRadians();
146 aFunctions
.AppendElement(Rotation3D(x
, y
, z
, theta
));
149 case eCSSKeyword_scalex
:
151 double x
= array
->Item(1).GetFloatValue();
152 aFunctions
.AppendElement(Scale(x
, 1, 1));
155 case eCSSKeyword_scaley
:
157 double y
= array
->Item(1).GetFloatValue();
158 aFunctions
.AppendElement(Scale(1, y
, 1));
161 case eCSSKeyword_scalez
:
163 double z
= array
->Item(1).GetFloatValue();
164 aFunctions
.AppendElement(Scale(1, 1, z
));
167 case eCSSKeyword_scale
:
169 double x
= array
->Item(1).GetFloatValue();
170 // scale(x) is shorthand for scale(x, x);
171 double y
= array
->Count() == 2 ? x
: array
->Item(2).GetFloatValue();
172 aFunctions
.AppendElement(Scale(x
, y
, 1));
175 case eCSSKeyword_scale3d
:
177 double x
= array
->Item(1).GetFloatValue();
178 double y
= array
->Item(2).GetFloatValue();
179 double z
= array
->Item(3).GetFloatValue();
180 aFunctions
.AppendElement(Scale(x
, y
, z
));
183 case eCSSKeyword_translatex
:
185 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
186 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
188 aFunctions
.AppendElement(Translation(x
, 0, 0));
191 case eCSSKeyword_translatey
:
193 double y
= nsStyleTransformMatrix::ProcessTranslatePart(
194 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
196 aFunctions
.AppendElement(Translation(0, y
, 0));
199 case eCSSKeyword_translatez
:
201 double z
= nsStyleTransformMatrix::ProcessTranslatePart(
202 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
204 aFunctions
.AppendElement(Translation(0, 0, z
));
207 case eCSSKeyword_translate
:
209 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
210 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
212 // translate(x) is shorthand for translate(x, 0)
214 if (array
->Count() == 3) {
215 y
= nsStyleTransformMatrix::ProcessTranslatePart(
216 array
->Item(2), aContext
, aPresContext
, canStoreInRuleTree
,
219 aFunctions
.AppendElement(Translation(x
, y
, 0));
222 case eCSSKeyword_translate3d
:
224 double x
= nsStyleTransformMatrix::ProcessTranslatePart(
225 array
->Item(1), aContext
, aPresContext
, canStoreInRuleTree
,
227 double y
= nsStyleTransformMatrix::ProcessTranslatePart(
228 array
->Item(2), aContext
, aPresContext
, canStoreInRuleTree
,
230 double z
= nsStyleTransformMatrix::ProcessTranslatePart(
231 array
->Item(3), aContext
, aPresContext
, canStoreInRuleTree
,
234 aFunctions
.AppendElement(Translation(x
, y
, z
));
237 case eCSSKeyword_skewx
:
239 double x
= array
->Item(1).GetAngleValueInRadians();
240 aFunctions
.AppendElement(SkewX(x
));
243 case eCSSKeyword_skewy
:
245 double y
= array
->Item(1).GetAngleValueInRadians();
246 aFunctions
.AppendElement(SkewY(y
));
249 case eCSSKeyword_skew
:
251 double x
= array
->Item(1).GetAngleValueInRadians();
252 // skew(x) is shorthand for skew(x, 0)
254 if (array
->Count() == 3) {
255 y
= array
->Item(2).GetAngleValueInRadians();
257 aFunctions
.AppendElement(Skew(x
, y
));
260 case eCSSKeyword_matrix
:
262 gfx::Matrix4x4 matrix
;
263 matrix
._11
= array
->Item(1).GetFloatValue();
264 matrix
._12
= array
->Item(2).GetFloatValue();
267 matrix
._21
= array
->Item(3).GetFloatValue();
268 matrix
._22
= array
->Item(4).GetFloatValue();
275 matrix
._41
= array
->Item(5).GetFloatValue();
276 matrix
._42
= array
->Item(6).GetFloatValue();
279 aFunctions
.AppendElement(TransformMatrix(matrix
));
282 case eCSSKeyword_matrix3d
:
284 gfx::Matrix4x4 matrix
;
285 matrix
._11
= array
->Item(1).GetFloatValue();
286 matrix
._12
= array
->Item(2).GetFloatValue();
287 matrix
._13
= array
->Item(3).GetFloatValue();
288 matrix
._14
= array
->Item(4).GetFloatValue();
289 matrix
._21
= array
->Item(5).GetFloatValue();
290 matrix
._22
= array
->Item(6).GetFloatValue();
291 matrix
._23
= array
->Item(7).GetFloatValue();
292 matrix
._24
= array
->Item(8).GetFloatValue();
293 matrix
._31
= array
->Item(9).GetFloatValue();
294 matrix
._32
= array
->Item(10).GetFloatValue();
295 matrix
._33
= array
->Item(11).GetFloatValue();
296 matrix
._34
= array
->Item(12).GetFloatValue();
297 matrix
._41
= array
->Item(13).GetFloatValue();
298 matrix
._42
= array
->Item(14).GetFloatValue();
299 matrix
._43
= array
->Item(15).GetFloatValue();
300 matrix
._44
= array
->Item(16).GetFloatValue();
301 aFunctions
.AppendElement(TransformMatrix(matrix
));
304 case eCSSKeyword_interpolatematrix
:
307 nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix
, array
,
312 aFunctions
.AppendElement(TransformMatrix(gfx::ToMatrix4x4(matrix
)));
315 case eCSSKeyword_perspective
:
317 aFunctions
.AppendElement(Perspective(array
->Item(1).GetFloatValue()));
321 NS_ERROR("Function not handled yet!");
326 static TimingFunction
327 ToTimingFunction(ComputedTimingFunction
& aCTF
)
329 if (aCTF
.GetType() == nsTimingFunction::Function
) {
330 const nsSMILKeySpline
* spline
= aCTF
.GetFunction();
331 return TimingFunction(CubicBezierFunction(spline
->X1(), spline
->Y1(),
332 spline
->X2(), spline
->Y2()));
335 uint32_t type
= aCTF
.GetType() == nsTimingFunction::StepStart
? 1 : 2;
336 return TimingFunction(StepFunction(aCTF
.GetSteps(), type
));
340 AddAnimationForProperty(nsIFrame
* aFrame
, nsCSSProperty aProperty
,
341 AnimationPlayer
* aPlayer
, Layer
* aLayer
,
342 AnimationData
& aData
, bool aPending
)
344 MOZ_ASSERT(aLayer
->AsContainerLayer(), "Should only animate ContainerLayer");
345 MOZ_ASSERT(aPlayer
->GetSource(),
346 "Should not be adding an animation for a player without"
348 nsStyleContext
* styleContext
= aFrame
->StyleContext();
349 nsPresContext
* presContext
= aFrame
->PresContext();
350 nsRect bounds
= nsDisplayTransform::GetFrameBoundsForTransform(aFrame
);
352 layers::Animation
* animation
=
354 aLayer
->AddAnimationForNextTransaction() :
355 aLayer
->AddAnimation();
357 const AnimationTiming
& timing
= aPlayer
->GetSource()->Timing();
358 animation
->startTime() = aPlayer
->Timeline()->ToTimeStamp(
359 aPlayer
->GetStartTime().Value() + timing
.mDelay
);
360 animation
->duration() = timing
.mIterationDuration
;
361 animation
->iterationCount() = timing
.mIterationCount
;
362 animation
->direction() = timing
.mDirection
;
363 animation
->property() = aProperty
;
364 animation
->data() = aData
;
366 dom::Animation
* anim
= aPlayer
->GetSource();
367 for (size_t propIdx
= 0;
368 propIdx
< anim
->Properties().Length();
370 AnimationProperty
& property
= anim
->Properties()[propIdx
];
372 if (aProperty
!= property
.mProperty
) {
376 for (uint32_t segIdx
= 0; segIdx
< property
.mSegments
.Length(); segIdx
++) {
377 AnimationPropertySegment
& segment
= property
.mSegments
[segIdx
];
379 AnimationSegment
* animSegment
= animation
->segments().AppendElement();
380 if (aProperty
== eCSSProperty_transform
) {
381 animSegment
->startState() = InfallibleTArray
<TransformFunction
>();
382 animSegment
->endState() = InfallibleTArray
<TransformFunction
>();
384 nsCSSValueSharedList
* list
=
385 segment
.mFromValue
.GetCSSValueSharedListValue();
386 AddTransformFunctions(list
->mHead
, styleContext
, presContext
, bounds
,
387 animSegment
->startState().get_ArrayOfTransformFunction());
389 list
= segment
.mToValue
.GetCSSValueSharedListValue();
390 AddTransformFunctions(list
->mHead
, styleContext
, presContext
, bounds
,
391 animSegment
->endState().get_ArrayOfTransformFunction());
392 } else if (aProperty
== eCSSProperty_opacity
) {
393 animSegment
->startState() = segment
.mFromValue
.GetFloatValue();
394 animSegment
->endState() = segment
.mToValue
.GetFloatValue();
397 animSegment
->startPortion() = segment
.mFromKey
;
398 animSegment
->endPortion() = segment
.mToKey
;
399 animSegment
->sampleFn() = ToTimingFunction(segment
.mTimingFunction
);
405 AddAnimationsForProperty(nsIFrame
* aFrame
, nsCSSProperty aProperty
,
406 AnimationPlayerPtrArray
& aPlayers
,
407 Layer
* aLayer
, AnimationData
& aData
,
409 for (size_t playerIdx
= 0; playerIdx
< aPlayers
.Length(); playerIdx
++) {
410 AnimationPlayer
* player
= aPlayers
[playerIdx
];
411 dom::Animation
* anim
= player
->GetSource();
412 if (!(anim
&& anim
->HasAnimationOfProperty(aProperty
) &&
413 player
->IsRunning())) {
416 AddAnimationForProperty(aFrame
, aProperty
, player
, aLayer
, aData
, aPending
);
417 player
->SetIsRunningOnCompositor();
422 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer
* aLayer
,
423 nsDisplayListBuilder
* aBuilder
,
424 nsDisplayItem
* aItem
,
426 nsCSSProperty aProperty
)
428 // This function can be called in two ways: from
429 // nsDisplay*::BuildLayer while constructing a layer (with all
430 // pointers non-null), or from RestyleManager's handling of
431 // UpdateOpacityLayer/UpdateTransformLayer hints.
432 MOZ_ASSERT(!aBuilder
== !aItem
,
433 "should only be called in two configurations, with both "
434 "aBuilder and aItem, or with neither");
435 MOZ_ASSERT(!aItem
|| aFrame
== aItem
->Frame(), "frame mismatch");
437 bool pending
= !aBuilder
;
440 aLayer
->ClearAnimationsForNextTransaction();
442 aLayer
->ClearAnimations();
445 // Update the animation generation on the layer. We need to do this before
446 // any early returns since even if we don't add any animations to the
447 // layer, we still need to mark it as up-to-date with regards to animations.
448 // Otherwise, in RestyleManager we'll notice the discrepancy between the
449 // animation generation numbers and update the layer indefinitely.
450 uint64_t animationGeneration
=
451 RestyleManager::GetMaxAnimationGenerationForFrame(aFrame
);
452 aLayer
->SetAnimationGeneration(animationGeneration
);
454 nsIContent
* content
= aFrame
->GetContent();
458 AnimationPlayerCollection
* transitions
=
459 nsTransitionManager::GetAnimationsForCompositor(content
, aProperty
);
460 AnimationPlayerCollection
* animations
=
461 nsAnimationManager::GetAnimationsForCompositor(content
, aProperty
);
463 if (!animations
&& !transitions
) {
467 // If the frame is not prerendered, bail out.
468 // Do this check only during layer construction; during updating the
469 // caller is required to check it appropriately.
470 if (aItem
&& !aItem
->CanUseAsyncAnimations(aBuilder
)) {
471 // AnimationManager or TransitionManager need to know that we refused to
472 // run this animation asynchronously so that they will not throttle the
473 // main thread animation.
474 aFrame
->Properties().Set(nsIFrame::RefusedAsyncAnimation(),
475 reinterpret_cast<void*>(intptr_t(true)));
477 // We need to schedule another refresh driver run so that AnimationManager
478 // or TransitionManager get a chance to unthrottle the animation.
479 aFrame
->SchedulePaint();
484 if (aProperty
== eCSSProperty_transform
) {
485 nsRect bounds
= nsDisplayTransform::GetFrameBoundsForTransform(aFrame
);
486 // all data passed directly to the compositor should be in css pixels
487 float scale
= nsDeviceContext::AppUnitsPerCSSPixel();
488 Point3D offsetToTransformOrigin
=
489 nsDisplayTransform::GetDeltaToTransformOrigin(aFrame
, scale
, &bounds
);
490 Point3D offsetToPerspectiveOrigin
=
491 nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame
, scale
);
492 nscoord perspective
= 0.0;
493 nsStyleContext
* parentStyleContext
= aFrame
->StyleContext()->GetParent();
494 if (parentStyleContext
) {
495 const nsStyleDisplay
* disp
= parentStyleContext
->StyleDisplay();
496 if (disp
&& disp
->mChildPerspective
.GetUnit() == eStyleUnit_Coord
) {
497 perspective
= disp
->mChildPerspective
.GetCoordValue();
502 origin
= aItem
->ToReferenceFrame();
504 // transform display items used a reference frame computed from
505 // their GetTransformRootFrame().
506 nsIFrame
* referenceFrame
=
507 nsLayoutUtils::GetReferenceFrame(GetTransformRootFrame(aFrame
));
508 origin
= aFrame
->GetOffsetToCrossDoc(referenceFrame
);
511 data
= TransformData(origin
, offsetToTransformOrigin
,
512 offsetToPerspectiveOrigin
, bounds
, perspective
,
513 aFrame
->PresContext()->AppUnitsPerDevPixel());
514 } else if (aProperty
== eCSSProperty_opacity
) {
519 AddAnimationsForProperty(aFrame
, aProperty
, transitions
->mPlayers
,
520 aLayer
, data
, pending
);
524 AddAnimationsForProperty(aFrame
, aProperty
, animations
->mPlayers
,
525 aLayer
, data
, pending
);
529 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame
* aReferenceFrame
,
530 Mode aMode
, bool aBuildCaret
)
531 : mReferenceFrame(aReferenceFrame
),
532 mIgnoreScrollFrame(nullptr),
533 mLayerEventRegions(nullptr),
534 mCurrentTableItem(nullptr),
535 mCurrentFrame(aReferenceFrame
),
536 mCurrentReferenceFrame(aReferenceFrame
),
537 mCurrentAnimatedGeometryRoot(nullptr),
538 mWillChangeBudgetCalculated(false),
539 mDirtyRect(-1,-1,-1,-1),
540 mGlassDisplayItem(nullptr),
542 mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID
),
543 mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID
),
544 mCurrentScrollbarFlags(0),
545 mBuildCaret(aBuildCaret
),
546 mIgnoreSuppression(false),
547 mHadToIgnoreSuppression(false),
548 mIsAtRootOfPseudoStackingContext(false),
549 mIncludeAllOutOfFlows(false),
550 mDescendIntoSubdocuments(true),
551 mSelectedFramesOnly(false),
552 mAccurateVisibleRegions(false),
553 mAllowMergingAndFlattening(true),
554 mWillComputePluginGeometry(false),
556 mSyncDecodeImages(false),
557 mIsPaintingToWindow(false),
558 mIsCompositingCheap(false),
559 mContainsPluginItem(false),
560 mAncestorHasTouchEventHandler(false),
561 mAncestorHasScrollEventHandler(false),
562 mHaveScrollableDisplayPort(false)
564 MOZ_COUNT_CTOR(nsDisplayListBuilder
);
565 PL_InitArenaPool(&mPool
, "displayListArena", 1024,
566 std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
567 RecomputeCurrentAnimatedGeometryRoot();
569 nsPresContext
* pc
= aReferenceFrame
->PresContext();
570 nsIPresShell
*shell
= pc
->PresShell();
571 if (pc
->IsRenderingOnlySelection()) {
572 nsCOMPtr
<nsISelectionController
> selcon(do_QueryInterface(shell
));
574 selcon
->GetSelection(nsISelectionController::SELECTION_NORMAL
,
575 getter_AddRefs(mBoundingSelection
));
579 nsCSSRendering::BeginFrameTreesLocked();
580 PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX
< (1 << nsDisplayItem::TYPE_BITS
));
583 static void MarkFrameForDisplay(nsIFrame
* aFrame
, nsIFrame
* aStopAtFrame
) {
584 for (nsIFrame
* f
= aFrame
; f
;
585 f
= nsLayoutUtils::GetParentOrPlaceholderFor(f
)) {
586 if (f
->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
)
588 f
->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
);
589 if (f
== aStopAtFrame
) {
590 // we've reached a frame that we know will be painted, so we can stop.
596 void nsDisplayListBuilder::SetContainsBlendMode(uint8_t aBlendMode
)
598 MOZ_ASSERT(aBlendMode
!= NS_STYLE_BLEND_NORMAL
);
599 gfxContext::GraphicsOperator op
= nsCSSRendering::GetGFXBlendMode(aBlendMode
);
600 mContainedBlendModes
+= gfx::CompositionOpForOp(op
);
603 bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem
* aItem
)
605 return aItem
== mGlassDisplayItem
|| aItem
->ClearsBackground();
608 void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame
* aDirtyFrame
,
610 const nsRect
& aDirtyRect
)
612 nsRect dirtyRectRelativeToDirtyFrame
= aDirtyRect
;
613 if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame
) &&
614 IsPaintingToWindow()) {
615 NS_ASSERTION(aDirtyFrame
== aFrame
->GetParent(), "Dirty frame should be viewport frame");
616 // position: fixed items are reflowed into and only drawn inside the
617 // viewport, or the scroll position clamping scrollport size, if one is
619 nsIPresShell
* ps
= aFrame
->PresContext()->PresShell();
620 dirtyRectRelativeToDirtyFrame
.MoveTo(0, 0);
621 if (ps
->IsScrollPositionClampingScrollPortSizeSet()) {
622 dirtyRectRelativeToDirtyFrame
.SizeTo(ps
->GetScrollPositionClampingScrollPortSize());
624 dirtyRectRelativeToDirtyFrame
.SizeTo(aDirtyFrame
->GetSize());
628 nsRect dirty
= dirtyRectRelativeToDirtyFrame
- aFrame
->GetOffsetTo(aDirtyFrame
);
629 nsRect overflowRect
= aFrame
->GetVisualOverflowRect();
631 if (aFrame
->IsTransformed() &&
632 nsLayoutUtils::HasAnimationsForCompositor(aFrame
->GetContent(),
633 eCSSProperty_transform
)) {
635 * Add a fuzz factor to the overflow rectangle so that elements only just
636 * out of view are pulled into the display list, so they can be
637 * prerendered if necessary.
639 overflowRect
.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
642 if (!dirty
.IntersectRect(dirty
, overflowRect
))
644 const DisplayItemClip
* clip
= mClipState
.GetClipForContainingBlockDescendants();
645 OutOfFlowDisplayData
* data
= clip
? new OutOfFlowDisplayData(*clip
, dirty
)
646 : new OutOfFlowDisplayData(dirty
);
647 aFrame
->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data
);
649 MarkFrameForDisplay(aFrame
, aDirtyFrame
);
652 static void UnmarkFrameForDisplay(nsIFrame
* aFrame
) {
653 nsPresContext
* presContext
= aFrame
->PresContext();
654 presContext
->PropertyTable()->
655 Delete(aFrame
, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
657 for (nsIFrame
* f
= aFrame
; f
;
658 f
= nsLayoutUtils::GetParentOrPlaceholderFor(f
)) {
659 if (!(f
->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
))
661 f
->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
);
665 /* static */ FrameMetrics
666 nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame
* aForFrame
,
667 nsIFrame
* aScrollFrame
,
668 const nsIFrame
* aReferenceFrame
,
670 ViewID aScrollParentId
,
671 const nsRect
& aViewport
,
672 bool aForceNullScrollId
,
674 const ContainerLayerParameters
& aContainerParameters
)
676 nsPresContext
* presContext
= aForFrame
->PresContext();
677 int32_t auPerDevPixel
= presContext
->AppUnitsPerDevPixel();
679 nsIPresShell
* presShell
= presContext
->GetPresShell();
680 FrameMetrics metrics
;
681 metrics
.SetViewport(CSSRect::FromAppUnits(aViewport
));
683 ViewID scrollId
= FrameMetrics::NULL_SCROLL_ID
;
684 nsIContent
* content
= aScrollFrame
? aScrollFrame
->GetContent() : nullptr;
686 if (!aForceNullScrollId
) {
687 scrollId
= nsLayoutUtils::FindOrCreateIDFor(content
);
690 if (nsLayoutUtils::GetDisplayPort(content
, &dp
)) {
691 metrics
.mDisplayPort
= CSSRect::FromAppUnits(dp
);
692 nsLayoutUtils::LogTestDataForPaint(aLayer
->Manager(), scrollId
, "displayport",
693 metrics
.mDisplayPort
);
695 if (nsLayoutUtils::GetCriticalDisplayPort(content
, &dp
)) {
696 metrics
.mCriticalDisplayPort
= CSSRect::FromAppUnits(dp
);
698 DisplayPortMarginsPropertyData
* marginsData
=
699 static_cast<DisplayPortMarginsPropertyData
*>(content
->GetProperty(nsGkAtoms::DisplayPortMargins
));
701 metrics
.SetDisplayPortMargins(marginsData
->mMargins
);
705 nsIScrollableFrame
* scrollableFrame
= nullptr;
707 scrollableFrame
= aScrollFrame
->GetScrollTargetFrame();
709 metrics
.mScrollableRect
= CSSRect::FromAppUnits(
710 nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame
, aForFrame
));
712 if (scrollableFrame
) {
713 nsPoint scrollPosition
= scrollableFrame
->GetScrollPosition();
714 metrics
.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition
));
716 nsPoint smoothScrollPosition
= scrollableFrame
->LastScrollDestination();
717 metrics
.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition
));
719 // If the frame was scrolled since the last layers update, and by
720 // something other than the APZ code, we want to tell the APZ to update
721 // its scroll offset.
722 nsIAtom
* lastScrollOrigin
= scrollableFrame
->LastScrollOrigin();
723 if (lastScrollOrigin
&& lastScrollOrigin
!= nsGkAtoms::apz
) {
724 metrics
.SetScrollOffsetUpdated(scrollableFrame
->CurrentScrollGeneration());
726 nsIAtom
* lastSmoothScrollOrigin
= scrollableFrame
->LastSmoothScrollOrigin();
727 if (lastSmoothScrollOrigin
) {
728 metrics
.SetSmoothScrollOffsetUpdated(scrollableFrame
->CurrentScrollGeneration());
731 nsSize lineScrollAmount
= scrollableFrame
->GetLineScrollAmount();
732 LayoutDeviceIntSize lineScrollAmountInDevPixels
=
733 LayoutDeviceIntSize::FromAppUnitsRounded(lineScrollAmount
, presContext
->AppUnitsPerDevPixel());
734 metrics
.SetLineScrollAmount(lineScrollAmountInDevPixels
);
737 metrics
.SetScrollId(scrollId
);
738 metrics
.SetIsRoot(aIsRoot
);
739 metrics
.SetScrollParentId(aScrollParentId
);
741 // Only the root scrollable frame for a given presShell should pick up
742 // the presShell's resolution. All the other frames are 1.0.
743 if (aScrollFrame
== presShell
->GetRootScrollFrame()) {
744 metrics
.mPresShellResolution
= presShell
->GetXResolution();
746 metrics
.mPresShellResolution
= 1.0f
;
748 // The cumulative resolution is the resolution at which the scroll frame's
749 // content is actually rendered. It includes the pres shell resolutions of
750 // all the pres shells from here up to the root, as well as any css-driven
751 // resolution. We don't need to compute it as it's already stored in the
752 // container parameters.
753 metrics
.mCumulativeResolution
= LayoutDeviceToLayerScale(aContainerParameters
.mXScale
,
754 aContainerParameters
.mYScale
);
756 LayoutDeviceToScreenScale
resolutionToScreen(
757 presShell
->GetCumulativeResolution().width
758 * nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame
? aScrollFrame
: aForFrame
).width
);
759 metrics
.SetExtraResolution(metrics
.mCumulativeResolution
/ resolutionToScreen
);
761 metrics
.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(
762 (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel
));
764 // Initially, AsyncPanZoomController should render the content to the screen
765 // at the painted resolution.
766 const LayerToParentLayerScale
layerToParentLayerScale(1.0f
);
767 metrics
.SetZoom(metrics
.mCumulativeResolution
* metrics
.GetDevPixelsPerCSSPixel()
768 * layerToParentLayerScale
);
771 nsIDocument
* document
= nullptr;
772 document
= presShell
->GetDocument();
774 nsCOMPtr
<nsPIDOMWindow
> innerWin(document
->GetInnerWindow());
776 metrics
.SetMayHaveTouchListeners(innerWin
->HasApzAwareEventListeners());
779 metrics
.SetMayHaveTouchCaret(presShell
->MayHaveTouchCaret());
782 // Calculate the composition bounds as the size of the scroll frame and
783 // its origin relative to the reference frame.
784 // If aScrollFrame is null, we are in a document without a root scroll frame,
785 // so it's a xul document. In this case, use the size of the viewport frame.
786 nsIFrame
* frameForCompositionBoundsCalculation
= aScrollFrame
? aScrollFrame
: aForFrame
;
787 nsRect
compositionBounds(frameForCompositionBoundsCalculation
->GetOffsetToCrossDoc(aReferenceFrame
),
788 frameForCompositionBoundsCalculation
->GetSize());
789 ParentLayerRect frameBounds
= LayoutDeviceRect::FromAppUnits(compositionBounds
, auPerDevPixel
)
790 * metrics
.mCumulativeResolution
791 * layerToParentLayerScale
;
792 metrics
.mCompositionBounds
= frameBounds
;
794 // For the root scroll frame of the root content document, the above calculation
795 // will yield the size of the viewport frame as the composition bounds, which
796 // doesn't actually correspond to what is visible when
797 // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
798 // the prescontext that the viewport frame is reflowed into. In that case if our
799 // document has a widget then the widget's bounds will correspond to what is
800 // visible. If we don't have a widget the root view's bounds correspond to what
801 // would be visible because they don't get modified by setCSSViewport.
802 bool isRootScrollFrame
= aScrollFrame
== presShell
->GetRootScrollFrame();
803 bool isRootContentDocRootScrollFrame
= isRootScrollFrame
804 && presContext
->IsRootContentDocument();
805 if (isRootContentDocRootScrollFrame
) {
806 if (nsIFrame
* rootFrame
= presShell
->GetRootFrame()) {
807 // On Android, we need to do things a bit differently to get things
808 // right (see bug 983208, bug 988882). We use the bounds of the nearest
809 // widget, but clamp the height to the frame bounds height. This clamping
810 // is done to get correct results for a page where the page is sized to
811 // the screen and thus the dynamic toolbar never disappears. In such a
812 // case, we want the composition bounds to exclude the toolbar height,
813 // but the widget bounds includes it. We don't currently have a good way
814 // of knowing about the toolbar height, but clamping to the frame bounds
815 // height gives the correct answer in the cases we care about.
816 #ifdef MOZ_WIDGET_ANDROID
817 nsIWidget
* widget
= rootFrame
->GetNearestWidget();
819 nsView
* view
= rootFrame
->GetView();
820 nsIWidget
* widget
= view
? view
->GetWidget() : nullptr;
823 nsIntRect widgetBounds
;
824 widget
->GetBounds(widgetBounds
);
825 metrics
.mCompositionBounds
= ParentLayerRect(ViewAs
<ParentLayerPixel
>(widgetBounds
));
826 #ifdef MOZ_WIDGET_ANDROID
827 if (frameBounds
.height
< metrics
.mCompositionBounds
.height
) {
828 metrics
.mCompositionBounds
.height
= frameBounds
.height
;
832 LayoutDeviceIntSize contentSize
;
833 if (nsLayoutUtils::GetContentViewerSize(presContext
, contentSize
)) {
834 LayoutDeviceToParentLayerScale
scale(1.0f
);
835 if (presContext
->GetParentPresContext()) {
836 gfxSize res
= presContext
->GetParentPresContext()->PresShell()->GetCumulativeResolution();
837 scale
= LayoutDeviceToParentLayerScale(res
.width
, res
.height
);
839 metrics
.mCompositionBounds
.SizeTo(contentSize
* scale
);
845 // Adjust composition bounds for the size of scroll bars.
846 if (scrollableFrame
&& !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars
)) {
847 nsMargin sizes
= scrollableFrame
->GetActualScrollbarSizes();
848 // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them.
849 ParentLayerMargin boundMargins
= CSSMargin::FromAppUnits(sizes
) * CSSToParentLayerScale(1.0f
);
850 metrics
.mCompositionBounds
.Deflate(boundMargins
);
853 metrics
.SetRootCompositionSize(
854 nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame
? aScrollFrame
: aForFrame
,
855 isRootContentDocRootScrollFrame
, metrics
));
857 if (gfxPrefs::APZPrintTree()) {
858 if (nsIContent
* content
= frameForCompositionBoundsCalculation
->GetContent()) {
859 nsAutoString contentDescription
;
860 content
->Describe(contentDescription
);
861 metrics
.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription
));
865 metrics
.SetPresShellId(presShell
->GetPresShellId());
867 // If the scroll frame's content is marked 'scrollgrab', record this
868 // in the FrameMetrics so APZ knows to provide the scroll grabbing
870 if (aScrollFrame
&& nsContentUtils::HasScrollgrab(aScrollFrame
->GetContent())) {
871 metrics
.SetHasScrollgrab(true);
874 // Also compute and set the background color.
875 // This is needed for APZ overscrolling support.
877 if (isRootScrollFrame
) {
878 metrics
.SetBackgroundColor(presShell
->GetCanvasBackground());
880 nsStyleContext
* backgroundStyle
;
881 if (nsCSSRendering::FindBackground(aScrollFrame
, &backgroundStyle
)) {
882 metrics
.SetBackgroundColor(backgroundStyle
->StyleBackground()->mBackgroundColor
);
890 nsDisplayListBuilder::~nsDisplayListBuilder() {
891 NS_ASSERTION(mFramesMarkedForDisplay
.Length() == 0,
892 "All frames should have been unmarked");
893 NS_ASSERTION(mPresShellStates
.Length() == 0,
894 "All presshells should have been exited");
895 NS_ASSERTION(!mCurrentTableItem
, "No table item should be active");
897 nsCSSRendering::EndFrameTreesLocked();
899 for (uint32_t i
= 0; i
< mDisplayItemClipsToDestroy
.Length(); ++i
) {
900 mDisplayItemClipsToDestroy
[i
]->DisplayItemClip::~DisplayItemClip();
903 PL_FinishArenaPool(&mPool
);
904 MOZ_COUNT_DTOR(nsDisplayListBuilder
);
908 nsDisplayListBuilder::GetBackgroundPaintFlags() {
910 if (mSyncDecodeImages
) {
911 flags
|= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES
;
913 if (mIsPaintingToWindow
) {
914 flags
|= nsCSSRendering::PAINTBG_TO_WINDOW
;
920 nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion
* aVisibleRegion
,
921 const nsRegion
& aRegion
)
923 if (aRegion
.IsEmpty())
927 tmp
.Sub(*aVisibleRegion
, aRegion
);
928 // Don't let *aVisibleRegion get too complex, but don't let it fluff out
929 // to its bounds either, which can be very bad (see bug 516740).
930 // Do let aVisibleRegion get more complex if by doing so we reduce its
931 // area by at least half.
932 if (GetAccurateVisibleRegions() || tmp
.GetNumRects() <= 15 ||
933 tmp
.Area() <= aVisibleRegion
->Area()/2) {
934 *aVisibleRegion
= tmp
;
939 nsDisplayListBuilder::GetCaret() {
940 nsRefPtr
<nsCaret
> caret
= CurrentPresShellState()->mPresShell
->GetCaret();
945 nsDisplayListBuilder::EnterPresShell(nsIFrame
* aReferenceFrame
)
947 PresShellState
* state
= mPresShellStates
.AppendElement();
948 state
->mPresShell
= aReferenceFrame
->PresContext()->PresShell();
949 state
->mCaretFrame
= nullptr;
950 state
->mFirstFrameMarkedForDisplay
= mFramesMarkedForDisplay
.Length();
952 state
->mPresShell
->UpdateCanvasBackground();
954 if (mIsPaintingToWindow
) {
955 mReferenceFrame
->AddPaintedPresShell(state
->mPresShell
);
957 state
->mPresShell
->IncrementPaintCount();
960 bool buildCaret
= mBuildCaret
;
961 if (mIgnoreSuppression
|| !state
->mPresShell
->IsPaintingSuppressed()) {
962 if (state
->mPresShell
->IsPaintingSuppressed()) {
963 mHadToIgnoreSuppression
= true;
965 state
->mIsBackgroundOnly
= false;
967 state
->mIsBackgroundOnly
= true;
974 nsRefPtr
<nsCaret
> caret
= state
->mPresShell
->GetCaret();
975 state
->mCaretFrame
= caret
->GetPaintGeometry(&state
->mCaretRect
);
976 if (state
->mCaretFrame
) {
977 mFramesMarkedForDisplay
.AppendElement(state
->mCaretFrame
);
978 MarkFrameForDisplay(state
->mCaretFrame
, nullptr);
983 nsDisplayListBuilder::LeavePresShell(nsIFrame
* aReferenceFrame
)
985 NS_ASSERTION(CurrentPresShellState()->mPresShell
==
986 aReferenceFrame
->PresContext()->PresShell(),
987 "Presshell mismatch");
988 ResetMarkedFramesForDisplayList();
989 mPresShellStates
.SetLength(mPresShellStates
.Length() - 1);
993 nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
995 // Unmark and pop off the frames marked for display in this pres shell.
996 uint32_t firstFrameForShell
= CurrentPresShellState()->mFirstFrameMarkedForDisplay
;
997 for (uint32_t i
= firstFrameForShell
;
998 i
< mFramesMarkedForDisplay
.Length(); ++i
) {
999 UnmarkFrameForDisplay(mFramesMarkedForDisplay
[i
]);
1001 mFramesMarkedForDisplay
.SetLength(firstFrameForShell
);
1005 nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame
* aDirtyFrame
,
1006 const nsFrameList
& aFrames
,
1007 const nsRect
& aDirtyRect
) {
1008 mFramesMarkedForDisplay
.SetCapacity(mFramesMarkedForDisplay
.Length() + aFrames
.GetLength());
1009 for (nsFrameList::Enumerator
e(aFrames
); !e
.AtEnd(); e
.Next()) {
1010 mFramesMarkedForDisplay
.AppendElement(e
.get());
1011 MarkOutOfFlowFrameForDisplay(aDirtyFrame
, e
.get(), aDirtyRect
);
1016 nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame
* aDirtyFrame
, const nsRect
& aDirtyRect
)
1018 nsAutoTArray
<nsIFrame::ChildList
,4> childListArray
;
1019 aDirtyFrame
->GetChildLists(&childListArray
);
1020 nsIFrame::ChildListArrayIterator
lists(childListArray
);
1021 for (; !lists
.IsDone(); lists
.Next()) {
1022 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1023 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1024 nsIFrame
*child
= childFrames
.get();
1025 if (child
->Preserves3D()) {
1026 mFramesMarkedForDisplay
.AppendElement(child
);
1027 nsRect dirty
= aDirtyRect
- child
->GetOffsetTo(aDirtyFrame
);
1029 child
->Properties().Set(nsDisplayListBuilder::Preserve3DDirtyRectProperty(),
1032 MarkFrameForDisplay(child
, aDirtyFrame
);
1039 nsDisplayListBuilder::Allocate(size_t aSize
)
1042 PL_ARENA_ALLOCATE(tmp
, &mPool
, aSize
);
1044 NS_ABORT_OOM(aSize
);
1049 const DisplayItemClip
*
1050 nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip
& aOriginal
)
1052 void* p
= Allocate(sizeof(DisplayItemClip
));
1053 if (!aOriginal
.GetRoundedRectCount()) {
1054 memcpy(p
, &aOriginal
, sizeof(DisplayItemClip
));
1055 return static_cast<DisplayItemClip
*>(p
);
1058 DisplayItemClip
* c
= new (p
) DisplayItemClip(aOriginal
);
1059 mDisplayItemClipsToDestroy
.AppendElement(c
);
1064 nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame
*aFrame
,
1067 if (aFrame
== mCurrentFrame
) {
1069 *aOffset
= mCurrentOffsetToReferenceFrame
;
1071 return mCurrentReferenceFrame
;
1073 for (const nsIFrame
* f
= aFrame
; f
; f
= nsLayoutUtils::GetCrossDocParentFrame(f
))
1075 if (f
== mReferenceFrame
|| f
->IsTransformed()) {
1077 *aOffset
= aFrame
->GetOffsetToCrossDoc(f
);
1083 *aOffset
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
1085 return mReferenceFrame
;
1088 // Sticky frames are active if their nearest scrollable frame is also active.
1090 IsStickyFrameActive(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
, nsIFrame
* aParent
)
1092 MOZ_ASSERT(aFrame
->StyleDisplay()->mPosition
== NS_STYLE_POSITION_STICKY
);
1094 // Find the nearest scrollframe.
1095 nsIFrame
* cursor
= aFrame
;
1096 nsIFrame
* parent
= aParent
;
1097 while (parent
->GetType() != nsGkAtoms::scrollFrame
) {
1099 if ((parent
= nsLayoutUtils::GetCrossDocParentFrame(cursor
)) == nullptr) {
1104 nsIScrollableFrame
* sf
= do_QueryFrame(parent
);
1105 return sf
->IsScrollingActive(aBuilder
) && sf
->GetScrolledFrame() == cursor
;
1109 nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame
* aFrame
, nsIFrame
** aParent
)
1111 if (nsLayoutUtils::IsPopup(aFrame
))
1113 if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame
))
1115 if (!aFrame
->GetParent() &&
1116 nsLayoutUtils::ViewportHasDisplayPort(aFrame
->PresContext())) {
1117 // Viewport frames in a display port need to be animated geometry roots
1118 // for background-attachment:fixed elements.
1122 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrame(aFrame
);
1126 nsIAtom
* parentType
= parent
->GetType();
1127 // Treat the slider thumb as being as an active scrolled root when it wants
1128 // its own layer so that it can move without repainting.
1129 if (parentType
== nsGkAtoms::sliderFrame
&& nsLayoutUtils::IsScrollbarThumbLayerized(aFrame
)) {
1133 if (aFrame
->StyleDisplay()->mPosition
== NS_STYLE_POSITION_STICKY
&&
1134 IsStickyFrameActive(this, aFrame
, parent
))
1139 if (parentType
== nsGkAtoms::scrollFrame
) {
1140 nsIScrollableFrame
* sf
= do_QueryFrame(parent
);
1141 if (sf
->IsScrollingActive(this) && sf
->GetScrolledFrame() == aFrame
) {
1146 // Fixed-pos frames are parented by the viewport frame, which has no parent.
1147 if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame
)) {
1158 ComputeAnimatedGeometryRootFor(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
1159 const nsIFrame
* aStopAtAncestor
= nullptr)
1161 nsIFrame
* cursor
= aFrame
;
1162 while (cursor
!= aStopAtAncestor
) {
1164 if (aBuilder
->IsAnimatedGeometryRoot(cursor
, &next
))
1172 nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame
* aFrame
, const nsIFrame
* aStopAtAncestor
)
1174 if (aFrame
== mCurrentFrame
) {
1175 return mCurrentAnimatedGeometryRoot
;
1177 return ComputeAnimatedGeometryRootFor(this, aFrame
, aStopAtAncestor
);
1181 nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
1183 mCurrentAnimatedGeometryRoot
= ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame
*>(mCurrentFrame
));
1187 nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame
* aFrame
)
1189 if (!IsForPainting() || IsInSubdocument() || IsInTransform()) {
1193 // We do some basic visibility checking on the frame's border box here.
1194 // We intersect it both with the current dirty rect and with the current
1195 // clip. Either one is just a conservative approximation on its own, but
1196 // their intersection luckily works well enough for our purposes, so that
1197 // we don't have to do full-blown visibility computations.
1198 // The most important case we need to handle is the scrolled-off tab:
1199 // If the tab bar overflows, tab parts that are clipped by the scrollbox
1200 // should not be allowed to interfere with the window dragging region. Using
1201 // just the current DisplayItemClip is not enough to cover this case
1202 // completely because clips are reset while building stacking context
1203 // contents, so for example we'd fail to clip frames that have a clip path
1204 // applied to them. But the current dirty rect doesn't get reset in that
1205 // case, so we use it to make this case work.
1206 nsRect borderBox
= aFrame
->GetRectRelativeToSelf().Intersect(mDirtyRect
);
1207 borderBox
+= ToReferenceFrame(aFrame
);
1208 const DisplayItemClip
* clip
= ClipState().GetCurrentCombinedClip(this);
1210 borderBox
= clip
->ApplyNonRoundedIntersection(borderBox
);
1212 if (!borderBox
.IsEmpty()) {
1213 const nsStyleUserInterface
* styleUI
= aFrame
->StyleUserInterface();
1214 if (styleUI
->mWindowDragging
== NS_STYLE_WINDOW_DRAGGING_DRAG
) {
1215 mWindowDraggingRegion
.OrWith(borderBox
);
1217 mWindowDraggingRegion
.SubOut(borderBox
);
1223 nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame
* aFrame
, const nsSize
& aRect
) {
1224 // Make sure that we don't query the budget before the display list is fully
1225 // built and that the will change budget is locked in.
1226 MOZ_ASSERT(!mWillChangeBudgetCalculated
,
1227 "Can't modify the budget once it's been used.");
1229 DocumentWillChangeBudget budget
;
1231 nsPresContext
* key
= aFrame
->PresContext();
1232 if (mWillChangeBudget
.Contains(key
)) {
1233 mWillChangeBudget
.Get(key
, &budget
);
1236 // There's significant overhead for each layer created from Gecko
1237 // (IPC+Shared Objects) and from the backend (like an OpenGL texture).
1238 // Therefore we set a minimum cost threshold of a 64x64 area.
1239 int minBudgetCost
= 64 * 64;
1242 std::max(minBudgetCost
,
1243 nsPresContext::AppUnitsToIntCSSPixels(aRect
.width
) *
1244 nsPresContext::AppUnitsToIntCSSPixels(aRect
.height
));
1246 mWillChangeBudget
.Put(key
, budget
);
1250 nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame
* aFrame
) const {
1251 uint32_t multiplier
= 3;
1253 mWillChangeBudgetCalculated
= true;
1255 nsPresContext
* key
= aFrame
->PresContext();
1256 if (!mWillChangeBudget
.Contains(key
)) {
1257 MOZ_ASSERT(false, "If we added nothing to our budget then this "
1258 "shouldn't be called.");
1262 DocumentWillChangeBudget budget
;
1263 mWillChangeBudget
.Get(key
, &budget
);
1265 nsRect area
= aFrame
->PresContext()->GetVisibleArea();
1266 uint32_t budgetLimit
= nsPresContext::AppUnitsToIntCSSPixels(area
.width
) *
1267 nsPresContext::AppUnitsToIntCSSPixels(area
.height
);
1269 bool onBudget
= budget
.mBudget
/ multiplier
< budgetLimit
;
1272 usageStr
.AppendInt(budget
.mBudget
);
1274 nsString multiplierStr
;
1275 multiplierStr
.AppendInt(multiplier
);
1278 limitStr
.AppendInt(budgetLimit
);
1280 const char16_t
* params
[] = { usageStr
.get(), multiplierStr
.get(), limitStr
.get() };
1281 key
->Document()->WarnOnceAbout(nsIDocument::eWillChangeBudget
, false,
1282 params
, ArrayLength(params
));
1287 void nsDisplayListSet::MoveTo(const nsDisplayListSet
& aDestination
) const
1289 aDestination
.BorderBackground()->AppendToTop(BorderBackground());
1290 aDestination
.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
1291 aDestination
.Floats()->AppendToTop(Floats());
1292 aDestination
.Content()->AppendToTop(Content());
1293 aDestination
.PositionedDescendants()->AppendToTop(PositionedDescendants());
1294 aDestination
.Outlines()->AppendToTop(Outlines());
1298 MoveListTo(nsDisplayList
* aList
, nsTArray
<nsDisplayItem
*>* aElements
) {
1299 nsDisplayItem
* item
;
1300 while ((item
= aList
->RemoveBottom()) != nullptr) {
1301 aElements
->AppendElement(item
);
1306 nsDisplayList::GetBounds(nsDisplayListBuilder
* aBuilder
) const {
1308 for (nsDisplayItem
* i
= GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
1309 bounds
.UnionRect(bounds
, i
->GetClippedBounds(aBuilder
));
1315 nsDisplayList::GetVisibleRect() const {
1317 for (nsDisplayItem
* i
= GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
1318 result
.UnionRect(result
, i
->GetVisibleRect());
1324 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder
* aBuilder
,
1325 nsRegion
* aVisibleRegion
,
1326 nsIFrame
* aDisplayPortFrame
) {
1327 PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
1328 js::ProfileEntry::Category::GRAPHICS
);
1331 r
.And(*aVisibleRegion
, GetBounds(aBuilder
));
1332 return ComputeVisibilityForSublist(aBuilder
, aVisibleRegion
,
1333 r
.GetBounds(), aDisplayPortFrame
);
1337 TreatAsOpaque(nsDisplayItem
* aItem
, nsDisplayListBuilder
* aBuilder
)
1340 nsRegion opaque
= aItem
->GetOpaqueRegion(aBuilder
, &snap
);
1341 if (aBuilder
->IsForPluginGeometry() &&
1342 aItem
->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS
)
1344 // Treat all leaf chrome items as opaque, unless their frames are opacity:0.
1345 // Since opacity:0 frames generate an nsDisplayOpacity, that item will
1346 // not be treated as opaque here, so opacity:0 chrome content will be
1347 // effectively ignored, as it should be.
1348 // We treat leaf chrome items as opaque to ensure that they cover
1349 // content plugins, for security reasons.
1350 // Non-leaf chrome items don't render contents of their own so shouldn't
1351 // be treated as opaque (and their bounds is just the union of their
1352 // children, which might be a large area their contents don't really cover).
1353 nsIFrame
* f
= aItem
->Frame();
1354 if (f
->PresContext()->IsChrome() && !aItem
->GetChildren() &&
1355 f
->StyleDisplay()->mOpacity
!= 0.0) {
1356 opaque
= aItem
->GetBounds(aBuilder
, &snap
);
1359 if (opaque
.IsEmpty()) {
1362 nsRegion opaqueClipped
;
1363 nsRegionRectIterator
iter(opaque
);
1364 for (const nsRect
* r
= iter
.Next(); r
; r
= iter
.Next()) {
1365 opaqueClipped
.Or(opaqueClipped
, aItem
->GetClip().ApproximateIntersectInward(*r
));
1367 return opaqueClipped
;
1371 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder
* aBuilder
,
1372 nsRegion
* aVisibleRegion
,
1373 const nsRect
& aListVisibleBounds
,
1374 nsIFrame
* aDisplayPortFrame
) {
1377 r
.And(*aVisibleRegion
, GetBounds(aBuilder
));
1378 NS_ASSERTION(r
.GetBounds().IsEqualInterior(aListVisibleBounds
),
1379 "bad aListVisibleBounds");
1382 bool anyVisible
= false;
1384 nsAutoTArray
<nsDisplayItem
*, 512> elements
;
1385 MoveListTo(this, &elements
);
1387 for (int32_t i
= elements
.Length() - 1; i
>= 0; --i
) {
1388 nsDisplayItem
* item
= elements
[i
];
1389 nsRect bounds
= item
->GetClippedBounds(aBuilder
);
1391 nsRegion itemVisible
;
1392 itemVisible
.And(*aVisibleRegion
, bounds
);
1393 item
->mVisibleRect
= itemVisible
.GetBounds();
1395 if (item
->ComputeVisibility(aBuilder
, aVisibleRegion
)) {
1398 nsRegion opaque
= TreatAsOpaque(item
, aBuilder
);
1399 // Subtract opaque item from the visible region
1400 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, opaque
);
1402 AppendToBottom(item
);
1405 mIsOpaque
= !aVisibleRegion
->Intersects(aListVisibleBounds
);
1410 * We paint by executing a layer manager transaction, constructing a
1411 * single layer representing the display list, and then making it the
1412 * root of the layer manager, drawing into the PaintedLayers.
1414 already_AddRefed
<LayerManager
> nsDisplayList::PaintRoot(nsDisplayListBuilder
* aBuilder
,
1415 nsRenderingContext
* aCtx
,
1417 PROFILER_LABEL("nsDisplayList", "PaintRoot",
1418 js::ProfileEntry::Category::GRAPHICS
);
1420 nsRefPtr
<LayerManager
> layerManager
;
1421 bool widgetTransaction
= false;
1422 bool allowRetaining
= false;
1423 bool doBeginTransaction
= true;
1424 nsView
*view
= nullptr;
1425 if (aFlags
& PAINT_USE_WIDGET_LAYERS
) {
1426 nsIFrame
* rootReferenceFrame
= aBuilder
->RootReferenceFrame();
1427 view
= rootReferenceFrame
->GetView();
1428 NS_ASSERTION(rootReferenceFrame
== nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame
),
1429 "Reference frame must be a display root for us to use the layer manager");
1430 nsIWidget
* window
= rootReferenceFrame
->GetNearestWidget();
1432 layerManager
= window
->GetLayerManager(&allowRetaining
);
1434 doBeginTransaction
= !(aFlags
& PAINT_EXISTING_TRANSACTION
);
1435 widgetTransaction
= true;
1439 if (!layerManager
) {
1441 NS_WARNING("Nowhere to paint into");
1444 layerManager
= new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN
);
1447 // Store the existing layer builder to reinstate it on return.
1448 FrameLayerBuilder
*oldBuilder
= layerManager
->GetLayerBuilder();
1450 FrameLayerBuilder
*layerBuilder
= new FrameLayerBuilder();
1451 layerBuilder
->Init(aBuilder
, layerManager
);
1453 if (aFlags
& PAINT_COMPRESSED
) {
1454 layerBuilder
->SetLayerTreeCompressionMode();
1457 if (aFlags
& PAINT_FLUSH_LAYERS
) {
1458 FrameLayerBuilder::InvalidateAllLayers(layerManager
);
1461 if (doBeginTransaction
) {
1463 layerManager
->BeginTransactionWithTarget(aCtx
->ThebesContext());
1465 layerManager
->BeginTransaction();
1468 if (widgetTransaction
) {
1469 layerBuilder
->DidBeginRetainedLayerTransaction(layerManager
);
1472 nsIFrame
* frame
= aBuilder
->RootReferenceFrame();
1473 nsPresContext
* presContext
= frame
->PresContext();
1474 nsIPresShell
* presShell
= presContext
->GetPresShell();
1476 NotifySubDocInvalidationFunc computeInvalidFunc
=
1477 presContext
->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation
: 0;
1478 bool computeInvalidRect
= (computeInvalidFunc
||
1479 (!layerManager
->IsCompositingCheap() && layerManager
->NeedsWidgetInvalidation())) &&
1482 UniquePtr
<LayerProperties
> props
;
1483 if (computeInvalidRect
) {
1484 props
= Move(LayerProperties::CloneFrom(layerManager
->GetRoot()));
1487 ContainerLayerParameters containerParameters
1488 (presShell
->GetXResolution(), presShell
->GetYResolution());
1489 nsRefPtr
<ContainerLayer
> root
= layerBuilder
->
1490 BuildContainerLayerFor(aBuilder
, layerManager
, frame
, nullptr, this,
1491 containerParameters
, nullptr);
1493 nsIDocument
* document
= nullptr;
1495 document
= presShell
->GetDocument();
1499 layerManager
->SetUserData(&gLayerManagerLayerBuilder
, oldBuilder
);
1502 // Root is being scaled up by the X/Y resolution. Scale it back down.
1503 root
->SetPostScale(1.0f
/containerParameters
.mXScale
,
1504 1.0f
/containerParameters
.mYScale
);
1506 bool isRoot
= presContext
->IsRootContentDocument();
1508 nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame();
1510 nsRect
viewport(aBuilder
->ToReferenceFrame(frame
), frame
->GetSize());
1512 root
->SetFrameMetrics(
1513 nsDisplayScrollLayer::ComputeFrameMetrics(frame
, rootScrollFrame
,
1514 aBuilder
->FindReferenceFrameFor(frame
),
1515 root
, FrameMetrics::NULL_SCROLL_ID
, viewport
,
1516 !isRoot
, isRoot
, containerParameters
));
1518 // NS_WARNING is debug-only, so don't even bother checking the conditions in
1521 bool usingDisplayport
= false;
1522 if (rootScrollFrame
) {
1523 nsIContent
* content
= rootScrollFrame
->GetContent();
1525 usingDisplayport
= nsLayoutUtils::GetDisplayPort(content
, nullptr);
1528 if (usingDisplayport
&&
1529 !(root
->GetContentFlags() & Layer::CONTENT_OPAQUE
) &&
1530 SpammyLayoutWarningsEnabled()) {
1531 // See bug 693938, attachment 567017
1532 NS_WARNING("Transparent content with displayports can be expensive.");
1536 layerManager
->SetRoot(root
);
1537 layerBuilder
->WillEndTransaction();
1539 if (widgetTransaction
||
1540 // SVG-as-an-image docs don't paint as part of the retained layer tree,
1541 // but they still need the invalidation state bits cleared in order for
1542 // invalidation for CSS/SMIL animation to work properly.
1543 (document
&& document
->IsBeingUsedAsImage())) {
1544 frame
->ClearInvalidationStateBits();
1547 bool temp
= aBuilder
->SetIsCompositingCheap(layerManager
->IsCompositingCheap());
1548 LayerManager::EndTransactionFlags flags
= LayerManager::END_DEFAULT
;
1549 if (layerManager
->NeedsWidgetInvalidation()) {
1550 if (aFlags
& PAINT_NO_COMPOSITE
) {
1551 flags
= LayerManager::END_NO_COMPOSITE
;
1554 // Client layer managers never composite directly, so
1555 // we don't need to worry about END_NO_COMPOSITE.
1556 if (aBuilder
->WillComputePluginGeometry()) {
1557 flags
= LayerManager::END_NO_REMOTE_COMPOSITE
;
1561 MaybeSetupTransactionIdAllocator(layerManager
, view
);
1563 layerManager
->EndTransaction(FrameLayerBuilder::DrawPaintedLayer
,
1565 aBuilder
->SetIsCompositingCheap(temp
);
1566 layerBuilder
->DidEndTransaction();
1568 nsIntRegion invalid
;
1570 invalid
= props
->ComputeDifferences(root
, computeInvalidFunc
);
1571 } else if (widgetTransaction
) {
1572 LayerProperties::ClearInvalidations(root
);
1575 bool shouldInvalidate
= layerManager
->NeedsWidgetInvalidation();
1578 if (!invalid
.IsEmpty()) {
1579 nsIntRect bounds
= invalid
.GetBounds();
1580 nsRect
rect(presContext
->DevPixelsToAppUnits(bounds
.x
),
1581 presContext
->DevPixelsToAppUnits(bounds
.y
),
1582 presContext
->DevPixelsToAppUnits(bounds
.width
),
1583 presContext
->DevPixelsToAppUnits(bounds
.height
));
1584 if (shouldInvalidate
) {
1585 view
->GetViewManager()->InvalidateViewNoSuppression(view
, rect
);
1587 presContext
->NotifyInvalidation(bounds
, 0);
1589 } else if (shouldInvalidate
) {
1590 view
->GetViewManager()->InvalidateView(view
);
1594 if (aFlags
& PAINT_FLUSH_LAYERS
) {
1595 FrameLayerBuilder::InvalidateAllLayers(layerManager
);
1598 layerManager
->SetUserData(&gLayerManagerLayerBuilder
, oldBuilder
);
1599 return layerManager
.forget();
1602 uint32_t nsDisplayList::Count() const {
1604 for (nsDisplayItem
* i
= GetBottom(); i
; i
= i
->GetAbove()) {
1610 nsDisplayItem
* nsDisplayList::RemoveBottom() {
1611 nsDisplayItem
* item
= mSentinel
.mAbove
;
1614 mSentinel
.mAbove
= item
->mAbove
;
1616 // must have been the only item
1619 item
->mAbove
= nullptr;
1623 void nsDisplayList::DeleteAll() {
1624 nsDisplayItem
* item
;
1625 while ((item
= RemoveBottom()) != nullptr) {
1626 item
->~nsDisplayItem();
1631 GetMouseThrough(const nsIFrame
* aFrame
)
1633 if (!aFrame
->IsBoxFrame())
1636 const nsIFrame
* frame
= aFrame
;
1638 if (frame
->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS
) {
1640 } else if (frame
->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER
) {
1643 frame
= nsBox::GetParentBox(frame
);
1649 IsFrameReceivingPointerEvents(nsIFrame
* aFrame
)
1651 nsSubDocumentFrame
* frame
= do_QueryFrame(aFrame
);
1652 if (frame
&& frame
->PassPointerEventsToChildren()) {
1655 return NS_STYLE_POINTER_EVENTS_NONE
!=
1656 aFrame
->StyleVisibility()->GetEffectivePointerEvents(aFrame
);
1659 // A list of frames, and their z depth. Used for sorting
1660 // the results of hit testing.
1661 struct FramesWithDepth
1663 explicit FramesWithDepth(float aDepth
) :
1667 bool operator<(const FramesWithDepth
& aOther
) const {
1668 if (mDepth
!= aOther
.mDepth
) {
1669 // We want to sort so that the shallowest item (highest depth value) is first
1670 return mDepth
> aOther
.mDepth
;
1672 return this < &aOther
;
1674 bool operator==(const FramesWithDepth
& aOther
) const {
1675 return this == &aOther
;
1679 nsTArray
<nsIFrame
*> mFrames
;
1682 // Sort the frames by depth and then moves all the contained frames to the destination
1683 void FlushFramesArray(nsTArray
<FramesWithDepth
>& aSource
, nsTArray
<nsIFrame
*>* aDest
)
1685 if (aSource
.IsEmpty()) {
1689 uint32_t length
= aSource
.Length();
1690 for (uint32_t i
= 0; i
< length
; i
++) {
1691 aDest
->MoveElementsFrom(aSource
[i
].mFrames
);
1696 void nsDisplayList::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
1697 nsDisplayItem::HitTestState
* aState
,
1698 nsTArray
<nsIFrame
*> *aOutFrames
) const {
1699 int32_t itemBufferStart
= aState
->mItemBuffer
.Length();
1700 nsDisplayItem
* item
;
1701 for (item
= GetBottom(); item
; item
= item
->GetAbove()) {
1702 aState
->mItemBuffer
.AppendElement(item
);
1704 nsAutoTArray
<FramesWithDepth
, 16> temp
;
1705 for (int32_t i
= aState
->mItemBuffer
.Length() - 1; i
>= itemBufferStart
; --i
) {
1706 // Pop element off the end of the buffer. We want to shorten the buffer
1707 // so that recursive calls to HitTest have more buffer space.
1708 item
= aState
->mItemBuffer
[i
];
1709 aState
->mItemBuffer
.SetLength(i
);
1712 nsRect r
= item
->GetBounds(aBuilder
, &snap
).Intersect(aRect
);
1713 if (item
->GetClip().MayIntersect(r
)) {
1714 nsAutoTArray
<nsIFrame
*, 16> outFrames
;
1715 item
->HitTest(aBuilder
, aRect
, aState
, &outFrames
);
1717 // For 3d transforms with preserve-3d we add hit frames into the temp list
1718 // so we can sort them later, otherwise we add them directly to the output list.
1719 nsTArray
<nsIFrame
*> *writeFrames
= aOutFrames
;
1720 if (item
->GetType() == nsDisplayItem::TYPE_TRANSFORM
&&
1721 item
->Frame()->Preserves3D()) {
1722 if (outFrames
.Length()) {
1723 nsDisplayTransform
*transform
= static_cast<nsDisplayTransform
*>(item
);
1724 nsPoint point
= aRect
.TopLeft();
1725 // A 1x1 rect means a point, otherwise use the center of the rect
1726 if (aRect
.width
!= 1 || aRect
.height
!= 1) {
1727 point
= aRect
.Center();
1729 temp
.AppendElement(FramesWithDepth(transform
->GetHitDepthAtPoint(aBuilder
, point
)));
1730 writeFrames
= &temp
[temp
.Length() - 1].mFrames
;
1733 // We may have just finished a run of consecutive preserve-3d transforms,
1734 // so flush these into the destination array before processing our frame list.
1735 FlushFramesArray(temp
, aOutFrames
);
1738 for (uint32_t j
= 0; j
< outFrames
.Length(); j
++) {
1739 nsIFrame
*f
= outFrames
.ElementAt(j
);
1740 // Handle the XUL 'mousethrough' feature and 'pointer-events'.
1741 if (!GetMouseThrough(f
) && IsFrameReceivingPointerEvents(f
)) {
1742 writeFrames
->AppendElement(f
);
1747 // Clear any remaining preserve-3d transforms.
1748 FlushFramesArray(temp
, aOutFrames
);
1749 NS_ASSERTION(aState
->mItemBuffer
.Length() == uint32_t(itemBufferStart
),
1750 "How did we forget to pop some elements?");
1753 static void Sort(nsDisplayList
* aList
, int32_t aCount
, nsDisplayList::SortLEQ aCmp
,
1758 nsDisplayList list1
;
1759 nsDisplayList list2
;
1761 int32_t half
= aCount
/2;
1763 nsDisplayItem
* prev
= nullptr;
1764 for (i
= 0; i
< aCount
; ++i
) {
1765 nsDisplayItem
* item
= aList
->RemoveBottom();
1766 (i
< half
? &list1
: &list2
)->AppendToTop(item
);
1767 if (sorted
&& prev
&& !aCmp(prev
, item
, aClosure
)) {
1773 aList
->AppendToTop(&list1
);
1774 aList
->AppendToTop(&list2
);
1778 Sort(&list1
, half
, aCmp
, aClosure
);
1779 Sort(&list2
, aCount
- half
, aCmp
, aClosure
);
1781 for (i
= 0; i
< aCount
; ++i
) {
1782 if (list1
.GetBottom() &&
1783 (!list2
.GetBottom() ||
1784 aCmp(list1
.GetBottom(), list2
.GetBottom(), aClosure
))) {
1785 aList
->AppendToTop(list1
.RemoveBottom());
1787 aList
->AppendToTop(list2
.RemoveBottom());
1792 static nsIContent
* FindContentInDocument(nsDisplayItem
* aItem
, nsIDocument
* aDoc
) {
1793 nsIFrame
* f
= aItem
->Frame();
1795 nsPresContext
* pc
= f
->PresContext();
1796 if (pc
->Document() == aDoc
) {
1797 return f
->GetContent();
1799 f
= nsLayoutUtils::GetCrossDocParentFrame(pc
->PresShell()->GetRootFrame());
1804 static bool IsContentLEQ(nsDisplayItem
* aItem1
, nsDisplayItem
* aItem2
,
1806 nsIContent
* commonAncestor
= static_cast<nsIContent
*>(aClosure
);
1807 // It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument
1808 // of commonAncestor, because display items for subdocuments have been
1809 // mixed into the same list. Ensure that we're looking at content
1810 // in commonAncestor's document.
1811 nsIDocument
* commonAncestorDoc
= commonAncestor
->OwnerDoc();
1812 nsIContent
* content1
= FindContentInDocument(aItem1
, commonAncestorDoc
);
1813 nsIContent
* content2
= FindContentInDocument(aItem2
, commonAncestorDoc
);
1814 if (!content1
|| !content2
) {
1815 NS_ERROR("Document trees are mixed up!");
1816 // Something weird going on
1819 return nsLayoutUtils::CompareTreePosition(content1
, content2
, commonAncestor
) <= 0;
1822 static bool IsZOrderLEQ(nsDisplayItem
* aItem1
, nsDisplayItem
* aItem2
,
1824 // Note that we can't just take the difference of the two
1825 // z-indices here, because that might overflow a 32-bit int.
1826 return aItem1
->ZIndex() <= aItem2
->ZIndex();
1829 void nsDisplayList::SortByZOrder(nsDisplayListBuilder
* aBuilder
,
1830 nsIContent
* aCommonAncestor
) {
1831 Sort(aBuilder
, IsZOrderLEQ
, aCommonAncestor
);
1834 void nsDisplayList::SortByContentOrder(nsDisplayListBuilder
* aBuilder
,
1835 nsIContent
* aCommonAncestor
) {
1836 Sort(aBuilder
, IsContentLEQ
, aCommonAncestor
);
1839 void nsDisplayList::Sort(nsDisplayListBuilder
* aBuilder
,
1840 SortLEQ aCmp
, void* aClosure
) {
1841 ::Sort(this, Count(), aCmp
, aClosure
);
1844 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
1846 , mClip(aBuilder
->ClipState().GetCurrentCombinedClip(aBuilder
))
1847 #ifdef MOZ_DUMP_PAINTING
1851 mReferenceFrame
= aBuilder
->FindReferenceFrameFor(aFrame
, &mToReferenceFrame
);
1852 NS_ASSERTION(aBuilder
->GetDirtyRect().width
>= 0 ||
1853 !aBuilder
->IsForPainting(), "dirty rect not set");
1854 // The dirty rect is for mCurrentFrame, so we have to use
1855 // mCurrentOffsetToReferenceFrame
1856 mVisibleRect
= aBuilder
->GetDirtyRect() +
1857 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
1861 nsDisplayItem::AddInvalidRegionForSyncDecodeBackgroundImages(
1862 nsDisplayListBuilder
* aBuilder
,
1863 const nsDisplayItemGeometry
* aGeometry
,
1864 nsRegion
* aInvalidRegion
)
1866 if (aBuilder
->ShouldSyncDecodeImages()) {
1867 if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame
)) {
1869 aInvalidRegion
->Or(*aInvalidRegion
, GetBounds(aBuilder
, &snap
));
1875 nsDisplayItem::ForceActiveLayers()
1877 static bool sForce
= false;
1878 static bool sForceCached
= false;
1880 if (!sForceCached
) {
1881 Preferences::AddBoolVarCache(&sForce
, "layers.force-active", false);
1882 sForceCached
= true;
1888 /* static */ int32_t
1889 nsDisplayItem::MaxActiveLayers()
1891 static int32_t sMaxLayers
= false;
1892 static bool sMaxLayersCached
= false;
1894 if (!sMaxLayersCached
) {
1895 Preferences::AddIntVarCache(&sMaxLayers
, "layers.max-active", -1);
1896 sMaxLayersCached
= true;
1903 nsDisplayItem::ZIndex() const
1905 if (!mFrame
->IsPositioned() && !mFrame
->IsFlexOrGridItem())
1908 const nsStylePosition
* position
= mFrame
->StylePosition();
1909 if (position
->mZIndex
.GetUnit() == eStyleUnit_Integer
)
1910 return position
->mZIndex
.GetIntValue();
1912 // sort the auto and 0 elements together
1917 nsDisplayItem::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
1918 nsRegion
* aVisibleRegion
)
1920 return !mVisibleRect
.IsEmpty() &&
1921 !IsInvisibleInRect(aVisibleRegion
->GetBounds());
1925 nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder
* aBuilder
,
1926 nsRegion
* aVisibleRegion
) {
1927 nsRect bounds
= GetClippedBounds(aBuilder
);
1929 nsRegion itemVisible
;
1930 itemVisible
.And(*aVisibleRegion
, bounds
);
1931 mVisibleRect
= itemVisible
.GetBounds();
1933 // When we recompute visibility within layers we don't need to
1934 // expand the visible region for content behind plugins (the plugin
1935 // is not in the layer).
1936 if (!ComputeVisibility(aBuilder
, aVisibleRegion
)) {
1937 mVisibleRect
= nsRect();
1941 nsRegion opaque
= TreatAsOpaque(this, aBuilder
);
1942 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, opaque
);
1947 nsDisplayItem::GetClippedBounds(nsDisplayListBuilder
* aBuilder
)
1950 nsRect r
= GetBounds(aBuilder
, &snap
);
1951 return GetClip().ApplyNonRoundedIntersection(r
);
1955 nsDisplaySolidColor::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
1962 nsDisplaySolidColor::Paint(nsDisplayListBuilder
* aBuilder
,
1963 nsRenderingContext
* aCtx
)
1965 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
1966 DrawTarget
* drawTarget
= aCtx
->GetDrawTarget();
1968 NSRectToSnappedRect(mVisibleRect
, appUnitsPerDevPixel
, *drawTarget
);
1969 drawTarget
->FillRect(rect
, ColorPattern(ToDeviceColor(mColor
)));
1972 #ifdef MOZ_DUMP_PAINTING
1974 nsDisplaySolidColor::WriteDebugInfo(std::stringstream
& aStream
)
1976 aStream
<< " (rgba "
1977 << (int)NS_GET_R(mColor
) << ","
1978 << (int)NS_GET_G(mColor
) << ","
1979 << (int)NS_GET_B(mColor
) << ","
1980 << (int)NS_GET_A(mColor
) << ")";
1985 RegisterThemeGeometry(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
1987 if (!aBuilder
->IsInSubdocument() && !aBuilder
->IsInTransform()) {
1988 nsIFrame
* displayRoot
= nsLayoutUtils::GetDisplayRootFrame(aFrame
);
1989 nsRect
borderBox(aFrame
->GetOffsetTo(displayRoot
), aFrame
->GetSize());
1990 aBuilder
->RegisterThemeGeometry(aFrame
->StyleDisplay()->mAppearance
,
1991 borderBox
.ToNearestPixels(aFrame
->PresContext()->AppUnitsPerDevPixel()));
1995 nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder
* aBuilder
,
1998 const nsStyleBackground
* aBackgroundStyle
)
1999 : nsDisplayImageContainer(aBuilder
, aFrame
)
2000 , mBackgroundStyle(aBackgroundStyle
)
2003 MOZ_COUNT_CTOR(nsDisplayBackgroundImage
);
2005 mBounds
= GetBoundsInternal(aBuilder
);
2008 nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
2010 #ifdef NS_BUILD_REFCNT_LOGGING
2011 MOZ_COUNT_DTOR(nsDisplayBackgroundImage
);
2015 static nsStyleContext
* GetBackgroundStyleContext(nsIFrame
* aFrame
)
2018 if (!nsCSSRendering::FindBackground(aFrame
, &sc
)) {
2019 // We don't want to bail out if moz-appearance is set on a root
2020 // node. If it has a parent content node, bail because it's not
2021 // a root, other wise keep going in order to let the theme stuff
2022 // draw the background. The canvas really should be drawing the
2023 // bg, but there's no way to hook that up via css.
2024 if (!aFrame
->StyleDisplay()->mAppearance
) {
2028 nsIContent
* content
= aFrame
->GetContent();
2029 if (!content
|| content
->GetParent()) {
2033 sc
= aFrame
->StyleContext();
2039 SetBackgroundClipRegion(DisplayListClipState::AutoSaveRestore
& aClipState
,
2040 nsIFrame
* aFrame
, const nsPoint
& aToReferenceFrame
,
2041 const nsStyleBackground::Layer
& aLayer
,
2042 bool aWillPaintBorder
)
2044 nsRect borderBox
= nsRect(aToReferenceFrame
, aFrame
->GetSize());
2046 nsCSSRendering::BackgroundClipState clip
;
2047 nsCSSRendering::GetBackgroundClip(aLayer
, aFrame
, *aFrame
->StyleBorder(),
2048 borderBox
, borderBox
, aWillPaintBorder
,
2049 aFrame
->PresContext()->AppUnitsPerDevPixel(),
2052 if (clip
.mHasAdditionalBGClipArea
) {
2053 aClipState
.ClipContentDescendants(clip
.mAdditionalBGClipArea
, clip
.mBGClipArea
,
2054 clip
.mHasRoundedCorners
? clip
.mRadii
: nullptr);
2056 aClipState
.ClipContentDescendants(clip
.mBGClipArea
, clip
.mHasRoundedCorners
? clip
.mRadii
: nullptr);
2062 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder
* aBuilder
,
2064 nsDisplayList
* aList
)
2066 nsStyleContext
* bgSC
= nullptr;
2067 const nsStyleBackground
* bg
= nullptr;
2068 nsPresContext
* presContext
= aFrame
->PresContext();
2069 bool isThemed
= aFrame
->IsThemed();
2071 bgSC
= GetBackgroundStyleContext(aFrame
);
2073 bg
= bgSC
->StyleBackground();
2077 bool drawBackgroundColor
= false;
2079 if (!nsCSSRendering::IsCanvasFrame(aFrame
) && bg
) {
2080 bool drawBackgroundImage
;
2082 nsCSSRendering::DetermineBackgroundColor(presContext
, bgSC
, aFrame
,
2083 drawBackgroundImage
, drawBackgroundColor
);
2086 const nsStyleBorder
* borderStyle
= aFrame
->StyleBorder();
2087 bool hasInsetShadow
= borderStyle
->mBoxShadow
&&
2088 borderStyle
->mBoxShadow
->HasShadowWithInset(true);
2089 bool willPaintBorder
= !isThemed
&& !hasInsetShadow
&&
2090 borderStyle
->HasBorder();
2092 nsPoint toRef
= aBuilder
->ToReferenceFrame(aFrame
);
2094 // An auxiliary list is necessary in case we have background blending; if that
2095 // is the case, background items need to be wrapped by a blend container to
2096 // isolate blending to the background
2097 nsDisplayList bgItemList
;
2098 // Even if we don't actually have a background color to paint, we may still need
2099 // to create an item for hit testing.
2100 if ((drawBackgroundColor
&& color
!= NS_RGBA(0,0,0,0)) ||
2101 aBuilder
->IsForEventDelivery()) {
2102 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
2103 if (bg
&& !aBuilder
->IsForEventDelivery()) {
2104 // Disable the will-paint-border optimization for background
2105 // colors with no border-radius. Enabling it for background colors
2106 // doesn't help much (there are no tiling issues) and clipping the
2107 // background breaks detection of the element's border-box being
2108 // opaque. For nonzero border-radius we still need it because we
2109 // want to inset the background if possible to avoid antialiasing
2110 // artifacts along the rounded corners.
2111 bool useWillPaintBorderOptimization
= willPaintBorder
&&
2112 nsLayoutUtils::HasNonZeroCorner(borderStyle
->mBorderRadius
);
2113 SetBackgroundClipRegion(clipState
, aFrame
, toRef
,
2115 useWillPaintBorderOptimization
);
2117 bgItemList
.AppendNewToTop(
2118 new (aBuilder
) nsDisplayBackgroundColor(aBuilder
, aFrame
, bg
,
2119 drawBackgroundColor
? color
: NS_RGBA(0, 0, 0, 0)));
2123 nsITheme
* theme
= presContext
->GetTheme();
2124 if (theme
->NeedToClearBackgroundBehindWidget(aFrame
->StyleDisplay()->mAppearance
)) {
2125 bgItemList
.AppendNewToTop(
2126 new (aBuilder
) nsDisplayClearBackground(aBuilder
, aFrame
));
2128 nsDisplayThemedBackground
* bgItem
=
2129 new (aBuilder
) nsDisplayThemedBackground(aBuilder
, aFrame
);
2130 bgItemList
.AppendNewToTop(bgItem
);
2131 aList
->AppendToTop(&bgItemList
);
2136 aList
->AppendToTop(&bgItemList
);
2140 bool needBlendContainer
= false;
2142 // Passing bg == nullptr in this macro will result in one iteration with
2144 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i
, bg
) {
2145 if (bg
->mLayers
[i
].mImage
.IsEmpty()) {
2149 if (bg
->mLayers
[i
].mBlendMode
!= NS_STYLE_BLEND_NORMAL
) {
2150 needBlendContainer
= true;
2153 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
2154 if (!aBuilder
->IsForEventDelivery()) {
2155 const nsStyleBackground::Layer
& layer
= bg
->mLayers
[i
];
2156 SetBackgroundClipRegion(clipState
, aFrame
, toRef
,
2157 layer
, willPaintBorder
);
2160 nsDisplayBackgroundImage
* bgItem
=
2161 new (aBuilder
) nsDisplayBackgroundImage(aBuilder
, aFrame
, i
, bg
);
2162 bgItemList
.AppendNewToTop(bgItem
);
2165 if (needBlendContainer
) {
2166 bgItemList
.AppendNewToTop(
2167 new (aBuilder
) nsDisplayBlendContainer(aBuilder
, aFrame
, &bgItemList
));
2170 aList
->AppendToTop(&bgItemList
);
2174 // Check that the rounded border of aFrame, added to aToReferenceFrame,
2175 // intersects aRect. Assumes that the unrounded border has already
2176 // been checked for intersection.
2178 RoundedBorderIntersectsRect(nsIFrame
* aFrame
,
2179 const nsPoint
& aFrameToReferenceFrame
,
2180 const nsRect
& aTestRect
)
2182 if (!nsRect(aFrameToReferenceFrame
, aFrame
->GetSize()).Intersects(aTestRect
))
2186 return !aFrame
->GetBorderRadii(radii
) ||
2187 nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame
,
2192 // Returns TRUE if aContainedRect is guaranteed to be contained in
2193 // the rounded rect defined by aRoundedRect and aRadii. Complex cases are
2194 // handled conservatively by returning FALSE in some situations where
2195 // a more thorough analysis could return TRUE.
2197 // See also RoundedRectIntersectsRect.
2198 static bool RoundedRectContainsRect(const nsRect
& aRoundedRect
,
2199 const nscoord aRadii
[8],
2200 const nsRect
& aContainedRect
) {
2201 nsRegion rgn
= nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect
, aRadii
, aContainedRect
);
2202 return rgn
.Contains(aContainedRect
);
2206 nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder
* aBuilder
,
2207 const nsRect
& aClipRect
,
2210 if (!mBackgroundStyle
)
2213 if (mBackgroundStyle
->mLayers
.Length() != 1)
2216 nsPresContext
* presContext
= mFrame
->PresContext();
2217 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2218 nsRect borderArea
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2219 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2221 if (layer
.mAttachment
!= NS_STYLE_BG_ATTACHMENT_FIXED
)
2224 nsBackgroundLayerState state
=
2225 nsCSSRendering::PrepareBackgroundLayer(presContext
, mFrame
, flags
,
2226 borderArea
, aClipRect
, layer
);
2227 nsImageRenderer
* imageRenderer
= &state
.mImageRenderer
;
2228 // We only care about images here, not gradients.
2229 if (!imageRenderer
->IsRasterImage())
2232 int32_t appUnitsPerDevPixel
= presContext
->AppUnitsPerDevPixel();
2233 *aDestRect
= nsLayoutUtils::RectToGfxRect(state
.mFillArea
, appUnitsPerDevPixel
);
2239 nsDisplayBackgroundImage::ShouldFixToViewport(LayerManager
* aManager
)
2241 // APZ doesn't (yet) know how to scroll the visible region for these type of
2242 // items, so don't layerize them if it's enabled.
2243 if (nsLayoutUtils::UsesAsyncScrolling() ||
2244 (aManager
&& aManager
->ShouldAvoidComponentAlphaLayers())) {
2248 // Put background-attachment:fixed background images in their own
2249 // compositing layer, unless we have APZ enabled
2250 return mBackgroundStyle
->mLayers
[mLayer
].mAttachment
== NS_STYLE_BG_ATTACHMENT_FIXED
&&
2251 !mBackgroundStyle
->mLayers
[mLayer
].mImage
.IsEmpty();
2255 nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager
* aManager
,
2256 nsDisplayListBuilder
* aBuilder
)
2258 if (!mBackgroundStyle
)
2261 nsPresContext
* presContext
= mFrame
->PresContext();
2262 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2263 nsRect borderArea
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2264 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2266 if (layer
.mClip
!= NS_STYLE_BG_CLIP_BORDER
) {
2270 if (mFrame
->GetBorderRadii(radii
)) {
2274 nsBackgroundLayerState state
=
2275 nsCSSRendering::PrepareBackgroundLayer(presContext
, mFrame
, flags
,
2276 borderArea
, borderArea
, layer
);
2277 nsImageRenderer
* imageRenderer
= &state
.mImageRenderer
;
2278 // We only care about images here, not gradients.
2279 if (!imageRenderer
->IsRasterImage())
2282 nsRefPtr
<ImageContainer
> imageContainer
= imageRenderer
->GetContainer(aManager
);
2283 // Image is not ready to be made into a layer yet
2284 if (!imageContainer
)
2287 // We currently can't handle tiled or partial backgrounds.
2288 if (!state
.mDestArea
.IsEqualEdges(state
.mFillArea
)) {
2292 // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
2293 // layer pixel boundaries. This should be OK for now.
2295 int32_t appUnitsPerDevPixel
= presContext
->AppUnitsPerDevPixel();
2296 mDestRect
= nsLayoutUtils::RectToGfxRect(state
.mDestArea
, appUnitsPerDevPixel
);
2297 mImageContainer
= imageContainer
;
2299 // Ok, we can turn this into a layer if needed.
2303 already_AddRefed
<ImageContainer
>
2304 nsDisplayBackgroundImage::GetContainer(LayerManager
* aManager
,
2305 nsDisplayListBuilder
*aBuilder
)
2307 if (!TryOptimizeToImageLayer(aManager
, aBuilder
)) {
2311 nsRefPtr
<ImageContainer
> container
= mImageContainer
;
2313 return container
.forget();
2317 nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder
* aBuilder
,
2318 LayerManager
* aManager
,
2319 const ContainerLayerParameters
& aParameters
)
2321 bool animated
= false;
2322 if (mBackgroundStyle
) {
2323 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2324 const nsStyleImage
* image
= &layer
.mImage
;
2325 if (image
->GetType() == eStyleImageType_Image
) {
2326 imgIRequest
* imgreq
= image
->GetImageData();
2327 nsCOMPtr
<imgIContainer
> image
;
2328 if (NS_SUCCEEDED(imgreq
->GetImage(getter_AddRefs(image
))) && image
) {
2329 if (NS_FAILED(image
->GetAnimated(&animated
))) {
2337 !nsLayoutUtils::AnimatedImageLayersEnabled()) {
2338 if (!aManager
->IsCompositingCheap() ||
2339 !nsLayoutUtils::GPUImageScalingEnabled()) {
2344 if (!TryOptimizeToImageLayer(aManager
, aBuilder
)) {
2349 mozilla::gfx::IntSize imageSize
= mImageContainer
->GetCurrentSize();
2350 NS_ASSERTION(imageSize
.width
!= 0 && imageSize
.height
!= 0, "Invalid image size!");
2352 gfxRect destRect
= mDestRect
;
2354 destRect
.width
*= aParameters
.mXScale
;
2355 destRect
.height
*= aParameters
.mYScale
;
2357 // Calculate the scaling factor for the frame.
2358 gfxSize scale
= gfxSize(destRect
.width
/ imageSize
.width
, destRect
.height
/ imageSize
.height
);
2360 // If we are not scaling at all, no point in separating this into a layer.
2361 if (scale
.width
== 1.0f
&& scale
.height
== 1.0f
) {
2365 // If the target size is pretty small, no point in using a layer.
2366 if (destRect
.width
* destRect
.height
< 64 * 64) {
2371 return LAYER_ACTIVE
;
2374 already_AddRefed
<Layer
>
2375 nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder
* aBuilder
,
2376 LayerManager
* aManager
,
2377 const ContainerLayerParameters
& aParameters
)
2379 nsRefPtr
<ImageLayer
> layer
= static_cast<ImageLayer
*>
2380 (aManager
->GetLayerBuilder()->GetLeafLayerFor(aBuilder
, this));
2382 layer
= aManager
->CreateImageLayer();
2386 layer
->SetContainer(mImageContainer
);
2387 ConfigureLayer(layer
, aParameters
.mOffset
);
2388 return layer
.forget();
2392 nsDisplayBackgroundImage::ConfigureLayer(ImageLayer
* aLayer
, const nsIntPoint
& aOffset
)
2394 aLayer
->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame
));
2396 mozilla::gfx::IntSize imageSize
= mImageContainer
->GetCurrentSize();
2397 NS_ASSERTION(imageSize
.width
!= 0 && imageSize
.height
!= 0, "Invalid image size!");
2399 gfxPoint p
= mDestRect
.TopLeft() + aOffset
;
2400 Matrix transform
= Matrix::Translation(p
.x
, p
.y
);
2401 transform
.PreScale(mDestRect
.width
/ imageSize
.width
,
2402 mDestRect
.height
/ imageSize
.height
);
2403 aLayer
->SetBaseTransform(gfx::Matrix4x4::From2D(transform
));
2407 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder
* aBuilder
,
2408 const nsRect
& aRect
,
2409 HitTestState
* aState
,
2410 nsTArray
<nsIFrame
*> *aOutFrames
)
2412 if (RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
2413 aOutFrames
->AppendElement(mFrame
);
2418 nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
2419 nsRegion
* aVisibleRegion
)
2421 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
2425 // Return false if the background was propagated away from this
2426 // frame. We don't want this display item to show up and confuse
2428 return mBackgroundStyle
;
2431 /* static */ nsRegion
2432 nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem
* aItem
,
2433 nsPresContext
* aPresContext
,
2434 uint8_t aClip
, const nsRect
& aRect
,
2438 if (aRect
.IsEmpty())
2441 nsIFrame
*frame
= aItem
->Frame();
2444 if (frame
->GetType() == nsGkAtoms::canvasFrame
) {
2445 nsCanvasFrame
* canvasFrame
= static_cast<nsCanvasFrame
*>(frame
);
2446 clipRect
= canvasFrame
->CanvasArea() + aItem
->ToReferenceFrame();
2449 case NS_STYLE_BG_CLIP_BORDER
:
2450 clipRect
= nsRect(aItem
->ToReferenceFrame(), frame
->GetSize());
2452 case NS_STYLE_BG_CLIP_PADDING
:
2453 clipRect
= frame
->GetPaddingRect() - frame
->GetPosition() + aItem
->ToReferenceFrame();
2455 case NS_STYLE_BG_CLIP_CONTENT
:
2456 clipRect
= frame
->GetContentRectRelativeToSelf() + aItem
->ToReferenceFrame();
2459 NS_NOTREACHED("Unknown clip type");
2464 return clipRect
.Intersect(aRect
);
2468 nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2473 if (!mBackgroundStyle
)
2479 // For NS_STYLE_BOX_DECORATION_BREAK_SLICE, don't try to optimize here, since
2480 // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
2481 // which expects frames to be sent to it in content order, not reverse
2482 // content order which we'll produce here.
2483 // Of course, if there's only one frame in the flow, it doesn't matter.
2484 if (mFrame
->StyleBorder()->mBoxDecorationBreak
==
2485 NS_STYLE_BOX_DECORATION_BREAK_CLONE
||
2486 (!mFrame
->GetPrevContinuation() && !mFrame
->GetNextContinuation())) {
2487 const nsStyleBackground::Layer
& layer
= mBackgroundStyle
->mLayers
[mLayer
];
2488 if (layer
.mImage
.IsOpaque() && layer
.mBlendMode
== NS_STYLE_BLEND_NORMAL
) {
2489 nsPresContext
* presContext
= mFrame
->PresContext();
2490 result
= GetInsideClipRegion(this, presContext
, layer
.mClip
, mBounds
, aSnap
);
2498 nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
2499 if (!mBackgroundStyle
) {
2500 *aColor
= NS_RGBA(0,0,0,0);
2507 nsDisplayBackgroundImage::GetPositioningArea()
2509 if (!mBackgroundStyle
) {
2512 nsIFrame
* attachedToFrame
;
2513 return nsCSSRendering::ComputeBackgroundPositioningArea(
2514 mFrame
->PresContext(), mFrame
,
2515 nsRect(ToReferenceFrame(), mFrame
->GetSize()),
2516 mBackgroundStyle
->mLayers
[mLayer
],
2517 &attachedToFrame
) + ToReferenceFrame();
2521 nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
2523 if (!mBackgroundStyle
)
2527 if (mFrame
->GetBorderRadii(radii
)) {
2528 // A change in the size of the positioning area might change the position
2529 // of the rounded corners.
2533 const nsStyleBackground::Layer
&layer
= mBackgroundStyle
->mLayers
[mLayer
];
2534 if (layer
.RenderingMightDependOnPositioningAreaSizeChange()) {
2540 static void CheckForBorderItem(nsDisplayItem
*aItem
, uint32_t& aFlags
)
2542 nsDisplayItem
* nextItem
= aItem
->GetAbove();
2543 while (nextItem
&& nextItem
->GetType() == nsDisplayItem::TYPE_BACKGROUND
) {
2544 nextItem
= nextItem
->GetAbove();
2547 nextItem
->Frame() == aItem
->Frame() &&
2548 nextItem
->GetType() == nsDisplayItem::TYPE_BORDER
) {
2549 aFlags
|= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER
;
2554 nsDisplayBackgroundImage::Paint(nsDisplayListBuilder
* aBuilder
,
2555 nsRenderingContext
* aCtx
) {
2556 PaintInternal(aBuilder
, aCtx
, mVisibleRect
, &mBounds
);
2560 nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder
* aBuilder
,
2561 nsRenderingContext
* aCtx
, const nsRect
& aBounds
,
2562 nsRect
* aClipRect
) {
2563 nsPoint offset
= ToReferenceFrame();
2564 uint32_t flags
= aBuilder
->GetBackgroundPaintFlags();
2565 CheckForBorderItem(this, flags
);
2567 nsCSSRendering::PaintBackground(mFrame
->PresContext(), *aCtx
, mFrame
,
2569 nsRect(offset
, mFrame
->GetSize()),
2570 flags
, aClipRect
, mLayer
);
2574 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
2575 const nsDisplayItemGeometry
* aGeometry
,
2576 nsRegion
* aInvalidRegion
)
2578 if (!mBackgroundStyle
) {
2582 const nsDisplayBackgroundGeometry
* geometry
= static_cast<const nsDisplayBackgroundGeometry
*>(aGeometry
);
2585 nsRect bounds
= GetBounds(aBuilder
, &snap
);
2586 nsRect positioningArea
= GetPositioningArea();
2587 if (positioningArea
.TopLeft() != geometry
->mPositioningArea
.TopLeft() ||
2588 (positioningArea
.Size() != geometry
->mPositioningArea
.Size() &&
2589 RenderingMightDependOnPositioningAreaSizeChange())) {
2590 // Positioning area changed in a way that could cause everything to change,
2591 // so invalidate everything (both old and new painting areas).
2592 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
2594 if (positioningArea
.Size() != geometry
->mPositioningArea
.Size()) {
2595 NotifyRenderingChanged();
2599 if (aBuilder
->ShouldSyncDecodeImages()) {
2600 if (mBackgroundStyle
&&
2601 !nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(mBackgroundStyle
, mLayer
)) {
2602 aInvalidRegion
->Or(*aInvalidRegion
, bounds
);
2604 NotifyRenderingChanged();
2607 if (!bounds
.IsEqualInterior(geometry
->mBounds
)) {
2608 // Positioning area is unchanged, so invalidate just the change in the
2610 aInvalidRegion
->Xor(bounds
, geometry
->mBounds
);
2612 NotifyRenderingChanged();
2617 nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
2623 nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder
* aBuilder
) {
2624 nsPresContext
* presContext
= mFrame
->PresContext();
2626 if (!mBackgroundStyle
) {
2630 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2631 nsRect clipRect
= borderBox
;
2632 if (mFrame
->GetType() == nsGkAtoms::canvasFrame
) {
2633 nsCanvasFrame
* frame
= static_cast<nsCanvasFrame
*>(mFrame
);
2634 clipRect
= frame
->CanvasArea() + ToReferenceFrame();
2636 const nsStyleBackground::Layer
& layer
= mBackgroundStyle
->mLayers
[mLayer
];
2637 return nsCSSRendering::GetBackgroundLayerRect(presContext
, mFrame
,
2638 borderBox
, clipRect
, layer
,
2639 aBuilder
->GetBackgroundPaintFlags());
2643 nsDisplayBackgroundImage::GetPerFrameKey()
2645 return (mLayer
<< nsDisplayItem::TYPE_BITS
) |
2646 nsDisplayItem::GetPerFrameKey();
2649 nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder
* aBuilder
,
2651 : nsDisplayItem(aBuilder
, aFrame
)
2653 MOZ_COUNT_CTOR(nsDisplayThemedBackground
);
2655 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
2656 mAppearance
= disp
->mAppearance
;
2657 mFrame
->IsThemed(disp
, &mThemeTransparency
);
2659 // Perform necessary RegisterThemeGeometry
2660 switch (disp
->mAppearance
) {
2661 case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR
:
2662 case NS_THEME_TOOLBAR
:
2663 case NS_THEME_TOOLTIP
:
2664 case NS_THEME_WINDOW_TITLEBAR
:
2665 case NS_THEME_WINDOW_BUTTON_BOX
:
2666 case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON
:
2667 case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED
:
2668 case NS_THEME_MAC_VIBRANCY_LIGHT
:
2669 case NS_THEME_MAC_VIBRANCY_DARK
:
2670 RegisterThemeGeometry(aBuilder
, aFrame
);
2672 case NS_THEME_WIN_BORDERLESS_GLASS
:
2673 case NS_THEME_WIN_GLASS
:
2674 aBuilder
->SetGlassDisplayItem(this);
2678 mBounds
= GetBoundsInternal();
2681 nsDisplayThemedBackground::~nsDisplayThemedBackground()
2683 #ifdef NS_BUILD_REFCNT_LOGGING
2684 MOZ_COUNT_DTOR(nsDisplayThemedBackground
);
2688 #ifdef MOZ_DUMP_PAINTING
2690 nsDisplayThemedBackground::WriteDebugInfo(std::stringstream
& aStream
)
2692 aStream
<< " (themed, appearance:" << (int)mAppearance
<< ")";
2697 nsDisplayThemedBackground::HitTest(nsDisplayListBuilder
* aBuilder
,
2698 const nsRect
& aRect
,
2699 HitTestState
* aState
,
2700 nsTArray
<nsIFrame
*> *aOutFrames
)
2702 // Assume that any point in our border rect is a hit.
2703 if (nsRect(ToReferenceFrame(), mFrame
->GetSize()).Intersects(aRect
)) {
2704 aOutFrames
->AppendElement(mFrame
);
2709 nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2714 if (mThemeTransparency
== nsITheme::eOpaque
) {
2715 result
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2721 nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
2722 if (mAppearance
== NS_THEME_WIN_BORDERLESS_GLASS
||
2723 mAppearance
== NS_THEME_WIN_GLASS
) {
2724 *aColor
= NS_RGBA(0,0,0,0);
2731 nsDisplayThemedBackground::ProvidesFontSmoothingBackgroundColor(nsDisplayListBuilder
* aBuilder
,
2734 nsITheme
* theme
= mFrame
->PresContext()->GetTheme();
2735 return theme
->WidgetProvidesFontSmoothingBackgroundColor(mFrame
, mAppearance
, aColor
);
2739 nsDisplayThemedBackground::GetPositioningArea()
2741 return nsRect(ToReferenceFrame(), mFrame
->GetSize());
2745 nsDisplayThemedBackground::Paint(nsDisplayListBuilder
* aBuilder
,
2746 nsRenderingContext
* aCtx
)
2748 PaintInternal(aBuilder
, aCtx
, mVisibleRect
, nullptr);
2753 nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder
* aBuilder
,
2754 nsRenderingContext
* aCtx
, const nsRect
& aBounds
,
2757 // XXXzw this ignores aClipRect.
2758 nsPresContext
* presContext
= mFrame
->PresContext();
2759 nsITheme
*theme
= presContext
->GetTheme();
2760 nsRect
borderArea(ToReferenceFrame(), mFrame
->GetSize());
2761 nsRect
drawing(borderArea
);
2762 theme
->GetWidgetOverflow(presContext
->DeviceContext(), mFrame
, mAppearance
,
2764 drawing
.IntersectRect(drawing
, aBounds
);
2765 theme
->DrawWidgetBackground(aCtx
, mFrame
, mAppearance
, borderArea
, drawing
);
2768 bool nsDisplayThemedBackground::IsWindowActive()
2770 EventStates docState
= mFrame
->GetContent()->OwnerDoc()->GetDocumentState();
2771 return !docState
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
);
2774 void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
2775 const nsDisplayItemGeometry
* aGeometry
,
2776 nsRegion
* aInvalidRegion
)
2778 const nsDisplayThemedBackgroundGeometry
* geometry
= static_cast<const nsDisplayThemedBackgroundGeometry
*>(aGeometry
);
2781 nsRect bounds
= GetBounds(aBuilder
, &snap
);
2782 nsRect positioningArea
= GetPositioningArea();
2783 if (!positioningArea
.IsEqualInterior(geometry
->mPositioningArea
)) {
2784 // Invalidate everything (both old and new painting areas).
2785 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
2788 if (!bounds
.IsEqualInterior(geometry
->mBounds
)) {
2789 // Positioning area is unchanged, so invalidate just the change in the
2791 aInvalidRegion
->Xor(bounds
, geometry
->mBounds
);
2793 nsITheme
* theme
= mFrame
->PresContext()->GetTheme();
2794 if (theme
->WidgetAppearanceDependsOnWindowFocus(mAppearance
) &&
2795 IsWindowActive() != geometry
->mWindowIsActive
) {
2796 aInvalidRegion
->Or(*aInvalidRegion
, bounds
);
2801 nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
2807 nsDisplayThemedBackground::GetBoundsInternal() {
2808 nsPresContext
* presContext
= mFrame
->PresContext();
2810 nsRect
r(nsPoint(0,0), mFrame
->GetSize());
2811 presContext
->GetTheme()->
2812 GetWidgetOverflow(presContext
->DeviceContext(), mFrame
,
2813 mFrame
->StyleDisplay()->mAppearance
, &r
);
2816 r
.Inflate(mFrame
->PresContext()->AppUnitsPerDevPixel());
2819 return r
+ ToReferenceFrame();
2823 nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder
* aBuilder
,
2825 const DisplayItemClip
* aClip
)
2827 mColor
.a
= mColor
.a
* aOpacity
;
2829 IntersectClip(aBuilder
, *aClip
);
2835 nsDisplayBackgroundColor::Paint(nsDisplayListBuilder
* aBuilder
,
2836 nsRenderingContext
* aCtx
)
2838 DrawTarget
& aDrawTarget
= *aCtx
->GetDrawTarget();
2840 if (mColor
== NS_RGBA(0, 0, 0, 0)) {
2844 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2846 Rect rect
= NSRectToSnappedRect(borderBox
,
2847 mFrame
->PresContext()->AppUnitsPerDevPixel(),
2849 ColorPattern
color(ToDeviceColor(mColor
));
2850 aDrawTarget
.FillRect(rect
, color
);
2854 nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
2857 if (mColor
.a
!= 1) {
2861 if (!mBackgroundStyle
)
2866 const nsStyleBackground::Layer
& bottomLayer
= mBackgroundStyle
->BottomLayer();
2867 nsRect borderBox
= nsRect(ToReferenceFrame(), mFrame
->GetSize());
2868 nsPresContext
* presContext
= mFrame
->PresContext();
2869 return nsDisplayBackgroundImage::GetInsideClipRegion(this, presContext
, bottomLayer
.mClip
, borderBox
, aSnap
);
2873 nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
)
2875 *aColor
= NS_RGBA_FROM_GFXRGBA(mColor
);
2880 nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder
* aBuilder
,
2881 const nsRect
& aRect
,
2882 HitTestState
* aState
,
2883 nsTArray
<nsIFrame
*> *aOutFrames
)
2885 if (!RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
2886 // aRect doesn't intersect our border-radius curve.
2890 aOutFrames
->AppendElement(mFrame
);
2893 #ifdef MOZ_DUMP_PAINTING
2895 nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream
& aStream
)
2897 aStream
<< " (rgba " << mColor
.r
<< "," << mColor
.g
<< ","
2898 << mColor
.b
<< "," << mColor
.a
<< ")";
2902 already_AddRefed
<Layer
>
2903 nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder
* aBuilder
,
2904 LayerManager
* aManager
,
2905 const ContainerLayerParameters
& aParameters
)
2907 nsRefPtr
<ColorLayer
> layer
= static_cast<ColorLayer
*>
2908 (aManager
->GetLayerBuilder()->GetLeafLayerFor(aBuilder
, this));
2910 layer
= aManager
->CreateColorLayer();
2914 layer
->SetColor(NS_RGBA(0, 0, 0, 0));
2915 layer
->SetMixBlendMode(gfx::CompositionOp::OP_SOURCE
);
2918 nsRect bounds
= GetBounds(aBuilder
, &snap
);
2919 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
2920 layer
->SetBounds(bounds
.ToNearestPixels(appUnitsPerDevPixel
)); // XXX Do we need to respect the parent layer's scale here?
2922 return layer
.forget();
2926 nsDisplayOutline::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
2928 return mFrame
->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
2932 nsDisplayOutline::Paint(nsDisplayListBuilder
* aBuilder
,
2933 nsRenderingContext
* aCtx
) {
2934 // TODO join outlines together
2935 nsPoint offset
= ToReferenceFrame();
2936 nsCSSRendering::PaintOutline(mFrame
->PresContext(), *aCtx
, mFrame
,
2938 nsRect(offset
, mFrame
->GetSize()),
2939 mFrame
->StyleContext());
2943 nsDisplayOutline::IsInvisibleInRect(const nsRect
& aRect
)
2945 const nsStyleOutline
* outline
= mFrame
->StyleOutline();
2946 nsRect
borderBox(ToReferenceFrame(), mFrame
->GetSize());
2947 if (borderBox
.Contains(aRect
) &&
2948 !nsLayoutUtils::HasNonZeroCorner(outline
->mOutlineRadius
)) {
2949 if (outline
->mOutlineOffset
>= 0) {
2950 // aRect is entirely inside the border-rect, and the outline isn't
2951 // rendered inside the border-rect, so the outline is not visible.
2960 nsDisplayEventReceiver::HitTest(nsDisplayListBuilder
* aBuilder
,
2961 const nsRect
& aRect
,
2962 HitTestState
* aState
,
2963 nsTArray
<nsIFrame
*> *aOutFrames
)
2965 if (!RoundedBorderIntersectsRect(mFrame
, ToReferenceFrame(), aRect
)) {
2966 // aRect doesn't intersect our border-radius curve.
2970 aOutFrames
->AppendElement(mFrame
);
2974 nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder
* aBuilder
,
2977 NS_ASSERTION(aBuilder
->FindReferenceFrameFor(aFrame
) == aBuilder
->FindReferenceFrameFor(mFrame
),
2978 "Reference frame mismatch");
2979 uint8_t pointerEvents
= aFrame
->StyleVisibility()->mPointerEvents
;
2980 if (pointerEvents
== NS_STYLE_POINTER_EVENTS_NONE
) {
2983 if (!aFrame
->StyleVisibility()->IsVisible()) {
2986 // XXX handle other pointerEvents values for SVG
2987 // XXX Do something clever here for the common case where the border box
2988 // is obviously entirely inside mHitRegion.
2989 nsRect
borderBox(aBuilder
->ToReferenceFrame(aFrame
), aFrame
->GetSize());
2990 const DisplayItemClip
* clip
= aBuilder
->ClipState().GetCurrentCombinedClip(aBuilder
);
2991 bool borderBoxHasRoundedCorners
=
2992 nsLayoutUtils::HasNonZeroCorner(aFrame
->StyleBorder()->mBorderRadius
);
2994 borderBox
= clip
->ApplyNonRoundedIntersection(borderBox
);
2995 if (clip
->GetRoundedRectCount() > 0) {
2996 borderBoxHasRoundedCorners
= true;
2999 if (borderBoxHasRoundedCorners
||
3000 (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
)) {
3001 mMaybeHitRegion
.Or(mMaybeHitRegion
, borderBox
);
3003 mHitRegion
.Or(mHitRegion
, borderBox
);
3005 if (aBuilder
->GetAncestorHasTouchEventHandler() ||
3006 aBuilder
->GetAncestorHasScrollEventHandler())
3008 mDispatchToContentHitRegion
.Or(mDispatchToContentHitRegion
, borderBox
);
3013 nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect
& aRect
)
3015 mDispatchToContentHitRegion
.Or(mDispatchToContentHitRegion
, aRect
);
3018 #ifdef MOZ_DUMP_PAINTING
3020 nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream
& aStream
)
3022 if (!mHitRegion
.IsEmpty()) {
3023 AppendToString(aStream
, mHitRegion
, " (hitRegion ", ")");
3025 if (!mMaybeHitRegion
.IsEmpty()) {
3026 AppendToString(aStream
, mMaybeHitRegion
, " (maybeHitRegion ", ")");
3028 if (!mDispatchToContentHitRegion
.IsEmpty()) {
3029 AppendToString(aStream
, mDispatchToContentHitRegion
, " (dispatchToContentRegion ", ")");
3034 nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder
* aBuilder
,
3035 nsIFrame
* aCaretFrame
)
3036 : nsDisplayItem(aBuilder
, aCaretFrame
)
3037 , mCaret(aBuilder
->GetCaret())
3038 , mBounds(aBuilder
->GetCaretRect() + ToReferenceFrame())
3040 MOZ_COUNT_CTOR(nsDisplayCaret
);
3043 #ifdef NS_BUILD_REFCNT_LOGGING
3044 nsDisplayCaret::~nsDisplayCaret()
3046 MOZ_COUNT_DTOR(nsDisplayCaret
);
3051 nsDisplayCaret::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
3054 // The caret returns a rect in the coordinates of mFrame.
3059 nsDisplayCaret::Paint(nsDisplayListBuilder
* aBuilder
,
3060 nsRenderingContext
* aCtx
) {
3061 // Note: Because we exist, we know that the caret is visible, so we don't
3062 // need to check for the caret's visibility.
3063 mCaret
->PaintCaret(aBuilder
, *aCtx
->GetDrawTarget(), mFrame
, ToReferenceFrame());
3067 nsDisplayBorder::IsInvisibleInRect(const nsRect
& aRect
)
3069 nsRect paddingRect
= mFrame
->GetPaddingRect() - mFrame
->GetPosition() +
3071 const nsStyleBorder
*styleBorder
;
3072 if (paddingRect
.Contains(aRect
) &&
3073 !(styleBorder
= mFrame
->StyleBorder())->IsBorderImageLoaded() &&
3074 !nsLayoutUtils::HasNonZeroCorner(styleBorder
->mBorderRadius
)) {
3075 // aRect is entirely inside the content rect, and no part
3076 // of the border is rendered inside the content rect, so we are not
3078 // Skip this if there's a border-image (which draws a background
3079 // too) or if there is a border-radius (which makes the border draw
3087 nsDisplayItemGeometry
*
3088 nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder
* aBuilder
)
3090 return new nsDisplayBorderGeometry(this, aBuilder
);
3094 nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
3095 const nsDisplayItemGeometry
* aGeometry
,
3096 nsRegion
* aInvalidRegion
)
3098 const nsDisplayBorderGeometry
* geometry
= static_cast<const nsDisplayBorderGeometry
*>(aGeometry
);
3100 if (!geometry
->mBounds
.IsEqualInterior(GetBounds(aBuilder
, &snap
)) ||
3101 !geometry
->mContentRect
.IsEqualInterior(GetContentRect())) {
3102 // We can probably get away with only invalidating the difference
3103 // between the border and padding rects, but the XUL ui at least
3104 // is apparently painting a background with this?
3105 aInvalidRegion
->Or(GetBounds(aBuilder
, &snap
), geometry
->mBounds
);
3110 nsDisplayBorder::Paint(nsDisplayListBuilder
* aBuilder
,
3111 nsRenderingContext
* aCtx
) {
3112 nsPoint offset
= ToReferenceFrame();
3113 nsCSSRendering::PaintBorder(mFrame
->PresContext(), *aCtx
, mFrame
,
3115 nsRect(offset
, mFrame
->GetSize()),
3116 mFrame
->StyleContext(),
3117 mFrame
->GetSkipSides());
3121 nsDisplayBorder::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
3124 return CalculateBounds(*mFrame
->StyleBorder());
3128 nsDisplayBorder::CalculateBounds(const nsStyleBorder
& aStyleBorder
)
3130 nsRect
borderBounds(ToReferenceFrame(), mFrame
->GetSize());
3131 if (aStyleBorder
.IsBorderImageLoaded()) {
3132 borderBounds
.Inflate(aStyleBorder
.GetImageOutset());
3133 return borderBounds
;
3135 nsMargin border
= aStyleBorder
.GetComputedBorder();
3137 if (border
.top
> 0) {
3138 result
= nsRect(borderBounds
.X(), borderBounds
.Y(), borderBounds
.Width(), border
.top
);
3140 if (border
.right
> 0) {
3141 result
.UnionRect(result
, nsRect(borderBounds
.XMost() - border
.right
, borderBounds
.Y(), border
.right
, borderBounds
.Height()));
3143 if (border
.bottom
> 0) {
3144 result
.UnionRect(result
, nsRect(borderBounds
.X(), borderBounds
.YMost() - border
.bottom
, borderBounds
.Width(), border
.bottom
));
3146 if (border
.left
> 0) {
3147 result
.UnionRect(result
, nsRect(borderBounds
.X(), borderBounds
.Y(), border
.left
, borderBounds
.Height()));
3154 // Given a region, compute a conservative approximation to it as a list
3155 // of rectangles that aren't vertically adjacent (i.e., vertically
3156 // adjacent or overlapping rectangles are combined).
3157 // Right now this is only approximate, some vertically overlapping rectangles
3158 // aren't guaranteed to be combined.
3160 ComputeDisjointRectangles(const nsRegion
& aRegion
,
3161 nsTArray
<nsRect
>* aRects
) {
3162 nscoord accumulationMargin
= nsPresContext::CSSPixelsToAppUnits(25);
3164 nsRegionRectIterator
iter(aRegion
);
3166 const nsRect
* r
= iter
.Next();
3167 if (r
&& !accumulated
.IsEmpty() &&
3168 accumulated
.YMost() >= r
->y
- accumulationMargin
) {
3169 accumulated
.UnionRect(accumulated
, *r
);
3173 if (!accumulated
.IsEmpty()) {
3174 aRects
->AppendElement(accumulated
);
3175 accumulated
.SetEmpty();
3186 nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder
* aBuilder
,
3187 nsRenderingContext
* aCtx
) {
3188 nsPoint offset
= ToReferenceFrame();
3189 nsRect borderRect
= mFrame
->VisualBorderRectRelativeToSelf() + offset
;
3190 nsPresContext
* presContext
= mFrame
->PresContext();
3191 nsAutoTArray
<nsRect
,10> rects
;
3192 ComputeDisjointRectangles(mVisibleRegion
, &rects
);
3194 PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint",
3195 js::ProfileEntry::Category::GRAPHICS
);
3197 for (uint32_t i
= 0; i
< rects
.Length(); ++i
) {
3198 nsCSSRendering::PaintBoxShadowOuter(presContext
, *aCtx
, mFrame
,
3199 borderRect
, rects
[i
], mOpacity
);
3204 nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
3210 nsDisplayBoxShadowOuter::GetBoundsInternal() {
3211 return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame
, mFrame
->GetSize()) +
3216 nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect
& aRect
)
3218 nsPoint origin
= ToReferenceFrame();
3219 nsRect
frameRect(origin
, mFrame
->GetSize());
3220 if (!frameRect
.Contains(aRect
))
3223 // the visible region is entirely inside the border-rect, and box shadows
3224 // never render within the border-rect (unless there's a border radius).
3225 nscoord twipsRadii
[8];
3226 bool hasBorderRadii
= mFrame
->GetBorderRadii(twipsRadii
);
3227 if (!hasBorderRadii
)
3230 return RoundedRectContainsRect(frameRect
, twipsRadii
, aRect
);
3234 nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3235 nsRegion
* aVisibleRegion
) {
3236 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
3240 // Store the actual visible region
3241 mVisibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3246 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
3247 const nsDisplayItemGeometry
* aGeometry
,
3248 nsRegion
* aInvalidRegion
)
3250 const nsDisplayBoxShadowOuterGeometry
* geometry
=
3251 static_cast<const nsDisplayBoxShadowOuterGeometry
*>(aGeometry
);
3253 if (!geometry
->mBounds
.IsEqualInterior(GetBounds(aBuilder
, &snap
)) ||
3254 !geometry
->mBorderRect
.IsEqualInterior(GetBorderRect()) ||
3255 mOpacity
!= geometry
->mOpacity
) {
3256 nsRegion oldShadow
, newShadow
;
3257 nscoord dontCare
[8];
3258 bool hasBorderRadius
= mFrame
->GetBorderRadii(dontCare
);
3259 if (hasBorderRadius
) {
3260 // If we have rounded corners then we need to invalidate the frame area
3261 // too since we paint into it.
3262 oldShadow
= geometry
->mBounds
;
3263 newShadow
= GetBounds(aBuilder
, &snap
);
3265 oldShadow
= oldShadow
.Sub(geometry
->mBounds
, geometry
->mBorderRect
);
3266 newShadow
= newShadow
.Sub(GetBounds(aBuilder
, &snap
), GetBorderRect());
3268 aInvalidRegion
->Or(oldShadow
, newShadow
);
3274 nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder
* aBuilder
,
3275 nsRenderingContext
* aCtx
) {
3276 nsPoint offset
= ToReferenceFrame();
3277 nsRect borderRect
= nsRect(offset
, mFrame
->GetSize());
3278 nsPresContext
* presContext
= mFrame
->PresContext();
3279 nsAutoTArray
<nsRect
,10> rects
;
3280 ComputeDisjointRectangles(mVisibleRegion
, &rects
);
3282 PROFILER_LABEL("nsDisplayBoxShadowInner", "Paint",
3283 js::ProfileEntry::Category::GRAPHICS
);
3285 DrawTarget
* drawTarget
= aCtx
->GetDrawTarget();
3286 gfxContext
* gfx
= aCtx
->ThebesContext();
3287 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
3289 for (uint32_t i
= 0; i
< rects
.Length(); ++i
) {
3291 gfx
->Clip(NSRectToSnappedRect(rects
[i
], appUnitsPerDevPixel
, *drawTarget
));
3292 nsCSSRendering::PaintBoxShadowInner(presContext
, *aCtx
, mFrame
,
3293 borderRect
, rects
[i
]);
3299 nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3300 nsRegion
* aVisibleRegion
) {
3301 if (!nsDisplayItem::ComputeVisibility(aBuilder
, aVisibleRegion
)) {
3305 // Store the actual visible region
3306 mVisibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3310 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder
* aBuilder
,
3311 nsIFrame
* aFrame
, nsDisplayList
* aList
)
3312 : nsDisplayItem(aBuilder
, aFrame
)
3313 , mOverrideZIndex(0)
3314 , mHasZIndexOverride(false)
3316 MOZ_COUNT_CTOR(nsDisplayWrapList
);
3318 mList
.AppendToTop(aList
);
3319 UpdateBounds(aBuilder
);
3321 if (!aFrame
|| !aFrame
->IsTransformed()) {
3325 // If the frame is a preserve-3d parent, then we will create transforms
3326 // inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp).
3327 // In this case we will always be outside of the transform, so share
3328 // our parents reference frame.
3329 if (aFrame
->Preserves3DChildren()) {
3331 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(aFrame
));
3332 mToReferenceFrame
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3334 // If we're a transformed frame, then we need to find out if we're inside
3335 // the nsDisplayTransform or outside of it. Frames inside the transform
3336 // need mReferenceFrame == mFrame, outside needs the next ancestor
3338 // If we're inside the transform, then the nsDisplayItem constructor
3339 // will have done the right thing.
3340 // If we're outside the transform, then we should have only one child
3341 // (since nsDisplayTransform wraps all actual content), and that child
3342 // will have the correct reference frame set (since nsDisplayTransform
3343 // handles this explictly).
3345 // Preserve-3d can cause us to have multiple nsDisplayTransform
3347 nsDisplayItem
*i
= mList
.GetBottom();
3348 if (i
&& (!i
->GetAbove() || i
->GetType() == TYPE_TRANSFORM
) &&
3349 i
->Frame() == mFrame
) {
3350 mReferenceFrame
= i
->ReferenceFrame();
3351 mToReferenceFrame
= i
->ToReferenceFrame();
3354 mVisibleRect
= aBuilder
->GetDirtyRect() +
3355 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
3358 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder
* aBuilder
,
3359 nsIFrame
* aFrame
, nsDisplayItem
* aItem
)
3360 : nsDisplayItem(aBuilder
, aFrame
)
3361 , mOverrideZIndex(0)
3362 , mHasZIndexOverride(false)
3364 MOZ_COUNT_CTOR(nsDisplayWrapList
);
3366 mList
.AppendToTop(aItem
);
3367 UpdateBounds(aBuilder
);
3369 if (!aFrame
|| !aFrame
->IsTransformed()) {
3373 if (aFrame
->Preserves3DChildren()) {
3375 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(aFrame
));
3376 mToReferenceFrame
= aFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3378 // See the previous nsDisplayWrapList constructor
3379 if (aItem
->Frame() == aFrame
) {
3380 mReferenceFrame
= aItem
->ReferenceFrame();
3381 mToReferenceFrame
= aItem
->ToReferenceFrame();
3384 mVisibleRect
= aBuilder
->GetDirtyRect() +
3385 aBuilder
->GetCurrentFrameOffsetToReferenceFrame();
3388 nsDisplayWrapList::~nsDisplayWrapList() {
3391 MOZ_COUNT_DTOR(nsDisplayWrapList
);
3395 nsDisplayWrapList::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
3396 HitTestState
* aState
, nsTArray
<nsIFrame
*> *aOutFrames
) {
3397 mList
.HitTest(aBuilder
, aRect
, aState
, aOutFrames
);
3401 nsDisplayWrapList::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) {
3407 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3408 nsRegion
* aVisibleRegion
) {
3409 // Convert the passed in visible region to our appunits.
3410 nsRegion visibleRegion
;
3411 // mVisibleRect has been clipped to GetClippedBounds
3412 visibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
3413 nsRegion originalVisibleRegion
= visibleRegion
;
3416 mList
.ComputeVisibilityForSublist(aBuilder
, &visibleRegion
,
3420 // removed = originalVisibleRegion - visibleRegion
3421 removed
.Sub(originalVisibleRegion
, visibleRegion
);
3422 // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
3423 // SubtractFromVisibleRegion does)
3424 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
3430 nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3434 if (mList
.IsOpaque()) {
3435 // Everything within GetBounds that's visible is opaque.
3436 result
= GetBounds(aBuilder
, aSnap
);
3441 bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder
* aBuilder
, nscolor
* aColor
) {
3442 // We could try to do something but let's conservatively just return false.
3446 void nsDisplayWrapList::Paint(nsDisplayListBuilder
* aBuilder
,
3447 nsRenderingContext
* aCtx
) {
3448 NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
3452 * Returns true if all descendant display items can be placed in the same
3453 * PaintedLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
3454 * and they all have the expected animated geometry root.
3457 RequiredLayerStateForChildren(nsDisplayListBuilder
* aBuilder
,
3458 LayerManager
* aManager
,
3459 const ContainerLayerParameters
& aParameters
,
3460 const nsDisplayList
& aList
,
3461 nsIFrame
* aExpectedAnimatedGeometryRootForChildren
)
3463 LayerState result
= LAYER_INACTIVE
;
3464 for (nsDisplayItem
* i
= aList
.GetBottom(); i
; i
= i
->GetAbove()) {
3465 if (result
== LAYER_INACTIVE
&&
3466 nsLayoutUtils::GetAnimatedGeometryRootFor(i
, aBuilder
, aManager
) !=
3467 aExpectedAnimatedGeometryRootForChildren
) {
3468 result
= LAYER_ACTIVE
;
3471 LayerState state
= i
->GetLayerState(aBuilder
, aManager
, aParameters
);
3472 if ((state
== LAYER_ACTIVE
|| state
== LAYER_ACTIVE_FORCE
) &&
3476 if (state
== LAYER_ACTIVE_EMPTY
&& state
> result
) {
3477 result
= LAYER_ACTIVE_FORCE
;
3479 if (state
== LAYER_NONE
) {
3480 nsDisplayList
* list
= i
->GetSameCoordinateSystemChildren();
3482 LayerState childState
=
3483 RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
, *list
,
3484 aExpectedAnimatedGeometryRootForChildren
);
3485 if (childState
> result
) {
3486 result
= childState
;
3494 nsRect
nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder
* aBuilder
)
3497 for (nsDisplayItem
* i
= mList
.GetBottom(); i
; i
= i
->GetAbove()) {
3498 bounds
.UnionRect(bounds
, i
->GetComponentAlphaBounds(aBuilder
));
3504 nsDisplayWrapList::SetVisibleRect(const nsRect
& aRect
)
3506 mVisibleRect
= aRect
;
3510 nsDisplayWrapList::SetReferenceFrame(const nsIFrame
* aFrame
)
3512 mReferenceFrame
= aFrame
;
3513 mToReferenceFrame
= mFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
3517 WrapDisplayList(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
3518 nsDisplayList
* aList
, nsDisplayWrapper
* aWrapper
) {
3519 if (!aList
->GetTop())
3521 nsDisplayItem
* item
= aWrapper
->WrapList(aBuilder
, aFrame
, aList
);
3523 return NS_ERROR_OUT_OF_MEMORY
;
3524 // aList was emptied
3525 aList
->AppendToTop(item
);
3530 WrapEachDisplayItem(nsDisplayListBuilder
* aBuilder
,
3531 nsDisplayList
* aList
, nsDisplayWrapper
* aWrapper
) {
3532 nsDisplayList newList
;
3533 nsDisplayItem
* item
;
3534 while ((item
= aList
->RemoveBottom())) {
3535 item
= aWrapper
->WrapItem(aBuilder
, item
);
3537 return NS_ERROR_OUT_OF_MEMORY
;
3538 newList
.AppendToTop(item
);
3540 // aList was emptied
3541 aList
->AppendToTop(&newList
);
3545 nsresult
nsDisplayWrapper::WrapLists(nsDisplayListBuilder
* aBuilder
,
3546 nsIFrame
* aFrame
, const nsDisplayListSet
& aIn
, const nsDisplayListSet
& aOut
)
3548 nsresult rv
= WrapListsInPlace(aBuilder
, aFrame
, aIn
);
3549 NS_ENSURE_SUCCESS(rv
, rv
);
3553 aOut
.BorderBackground()->AppendToTop(aIn
.BorderBackground());
3554 aOut
.BlockBorderBackgrounds()->AppendToTop(aIn
.BlockBorderBackgrounds());
3555 aOut
.Floats()->AppendToTop(aIn
.Floats());
3556 aOut
.Content()->AppendToTop(aIn
.Content());
3557 aOut
.PositionedDescendants()->AppendToTop(aIn
.PositionedDescendants());
3558 aOut
.Outlines()->AppendToTop(aIn
.Outlines());
3562 nsresult
nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder
* aBuilder
,
3563 nsIFrame
* aFrame
, const nsDisplayListSet
& aLists
)
3566 if (WrapBorderBackground()) {
3567 // Our border-backgrounds are in-flow
3568 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.BorderBackground(), this);
3569 NS_ENSURE_SUCCESS(rv
, rv
);
3571 // Our block border-backgrounds are in-flow
3572 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.BlockBorderBackgrounds(), this);
3573 NS_ENSURE_SUCCESS(rv
, rv
);
3574 // The floats are not in flow
3575 rv
= WrapEachDisplayItem(aBuilder
, aLists
.Floats(), this);
3576 NS_ENSURE_SUCCESS(rv
, rv
);
3577 // Our child content is in flow
3578 rv
= WrapDisplayList(aBuilder
, aFrame
, aLists
.Content(), this);
3579 NS_ENSURE_SUCCESS(rv
, rv
);
3580 // The positioned descendants may not be in-flow
3581 rv
= WrapEachDisplayItem(aBuilder
, aLists
.PositionedDescendants(), this);
3582 NS_ENSURE_SUCCESS(rv
, rv
);
3583 // The outlines may not be in-flow
3584 return WrapEachDisplayItem(aBuilder
, aLists
.Outlines(), this);
3587 nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder
* aBuilder
,
3588 nsIFrame
* aFrame
, nsDisplayList
* aList
)
3589 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
3590 , mOpacity(aFrame
->StyleDisplay()->mOpacity
) {
3591 MOZ_COUNT_CTOR(nsDisplayOpacity
);
3594 #ifdef NS_BUILD_REFCNT_LOGGING
3595 nsDisplayOpacity::~nsDisplayOpacity() {
3596 MOZ_COUNT_DTOR(nsDisplayOpacity
);
3600 nsRegion
nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3603 // The only time where mOpacity == 1.0 should be when we have will-change.
3604 // We could report this as opaque then but when the will-change value starts
3605 // animating the element would become non opaque and could cause repaints.
3609 // nsDisplayOpacity uses layers for rendering
3610 already_AddRefed
<Layer
>
3611 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3612 LayerManager
* aManager
,
3613 const ContainerLayerParameters
& aContainerParameters
) {
3614 if (mOpacity
== 0 && mFrame
->GetContent() &&
3615 !nsLayoutUtils::HasAnimations(mFrame
->GetContent(), eCSSProperty_opacity
)) {
3618 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
3619 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3620 aContainerParameters
, nullptr);
3624 container
->SetOpacity(mOpacity
);
3625 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container
, aBuilder
,
3627 eCSSProperty_opacity
);
3628 return container
.forget();
3632 * This doesn't take into account layer scaling --- the layer may be
3633 * rendered at a higher (or lower) resolution, affecting the retained layer
3634 * size --- but this should be good enough.
3637 IsItemTooSmallForActiveLayer(nsDisplayItem
* aItem
)
3639 nsIntRect visibleDevPixels
= aItem
->GetVisibleRect().ToOutsidePixels(
3640 aItem
->Frame()->PresContext()->AppUnitsPerDevPixel());
3641 static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
= 16;
3642 return visibleDevPixels
.Size() <
3643 nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS
);
3647 nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder
* aBuilder
)
3649 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_opacity
) &&
3650 !IsItemTooSmallForActiveLayer(this))
3652 if (mFrame
->GetContent()) {
3653 if (nsLayoutUtils::HasAnimationsForCompositor(mFrame
->GetContent(),
3654 eCSSProperty_opacity
)) {
3662 nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder
* aBuilder
,
3664 const DisplayItemClip
* aClip
)
3666 mOpacity
= mOpacity
* aOpacity
;
3668 IntersectClip(aBuilder
, *aClip
);
3674 nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
3676 if (NeedsActiveLayer(aBuilder
))
3679 nsDisplayItem
* child
= mList
.GetBottom();
3680 // Only try folding our opacity down if we have a single
3681 // child. We could potentially do this also if we had multiple
3682 // children as long as they don't overlap.
3683 if (!child
|| child
->GetAbove()) {
3687 return child
->ApplyOpacity(aBuilder
, mOpacity
, mClip
);
3690 nsDisplayItem::LayerState
3691 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder
* aBuilder
,
3692 LayerManager
* aManager
,
3693 const ContainerLayerParameters
& aParameters
) {
3694 if (NeedsActiveLayer(aBuilder
))
3695 return LAYER_ACTIVE
;
3697 return RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
, mList
,
3698 nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder
, aManager
));
3702 nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3703 nsRegion
* aVisibleRegion
) {
3704 // Our children are translucent so we should not allow them to subtract
3705 // area from aVisibleRegion. We do need to find out what is visible under
3706 // our children in the temporary compositing buffer, because if our children
3707 // paint our entire bounds opaquely then we don't need an alpha channel in
3708 // the temporary compositing buffer.
3709 nsRect bounds
= GetClippedBounds(aBuilder
);
3710 nsRegion visibleUnderChildren
;
3711 visibleUnderChildren
.And(*aVisibleRegion
, bounds
);
3713 nsDisplayWrapList::ComputeVisibility(aBuilder
, &visibleUnderChildren
);
3716 bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
3717 if (aItem
->GetType() != TYPE_OPACITY
)
3719 // items for the same content element should be merged into a single
3720 // compositing group
3721 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
3722 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
3724 if (aItem
->GetClip() != GetClip())
3726 MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity
*>(aItem
));
3730 #ifdef MOZ_DUMP_PAINTING
3732 nsDisplayOpacity::WriteDebugInfo(std::stringstream
& aStream
)
3734 aStream
<< " (opacity " << mOpacity
<< ")";
3738 nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder
* aBuilder
,
3739 nsIFrame
* aFrame
, nsDisplayList
* aList
,
3741 : nsDisplayWrapList(aBuilder
, aFrame
, aList
) {
3742 MOZ_COUNT_CTOR(nsDisplayMixBlendMode
);
3745 #ifdef NS_BUILD_REFCNT_LOGGING
3746 nsDisplayMixBlendMode::~nsDisplayMixBlendMode() {
3747 MOZ_COUNT_DTOR(nsDisplayMixBlendMode
);
3751 nsRegion
nsDisplayMixBlendMode::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
3754 // We are never considered opaque
3759 nsDisplayMixBlendMode::GetLayerState(nsDisplayListBuilder
* aBuilder
,
3760 LayerManager
* aManager
,
3761 const ContainerLayerParameters
& aParameters
)
3763 gfxContext::GraphicsOperator op
= nsCSSRendering::GetGFXBlendMode(mFrame
->StyleDisplay()->mMixBlendMode
);
3764 if (aManager
->SupportsMixBlendMode(gfx::CompositionOpForOp(op
))) {
3765 return LAYER_ACTIVE
;
3767 return LAYER_INACTIVE
;
3770 // nsDisplayMixBlendMode uses layers for rendering
3771 already_AddRefed
<Layer
>
3772 nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3773 LayerManager
* aManager
,
3774 const ContainerLayerParameters
& aContainerParameters
) {
3775 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
3776 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
3778 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
3779 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3780 newContainerParameters
, nullptr);
3785 container
->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame
->StyleDisplay()->mMixBlendMode
));
3787 return container
.forget();
3790 bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3791 nsRegion
* aVisibleRegion
) {
3792 // Our children are need their backdrop so we should not allow them to subtract
3793 // area from aVisibleRegion. We do need to find out what is visible under
3794 // our children in the temporary compositing buffer, because if our children
3795 // paint our entire bounds opaquely then we don't need an alpha channel in
3796 // the temporary compositing buffer.
3797 nsRect bounds
= GetClippedBounds(aBuilder
);
3798 nsRegion visibleUnderChildren
;
3799 visibleUnderChildren
.And(*aVisibleRegion
, bounds
);
3800 return nsDisplayWrapList::ComputeVisibility(aBuilder
, &visibleUnderChildren
);
3803 bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
3804 if (aItem
->GetType() != TYPE_MIX_BLEND_MODE
)
3806 // items for the same content element should be merged into a single
3807 // compositing group
3808 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
3809 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
3811 if (aItem
->GetClip() != GetClip())
3813 MergeFromTrackingMergedFrames(static_cast<nsDisplayMixBlendMode
*>(aItem
));
3817 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder
* aBuilder
,
3818 nsIFrame
* aFrame
, nsDisplayList
* aList
,
3819 BlendModeSet
& aContainedBlendModes
)
3820 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
3821 , mContainedBlendModes(aContainedBlendModes
)
3822 , mCanBeActive(true)
3824 MOZ_COUNT_CTOR(nsDisplayBlendContainer
);
3827 nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder
* aBuilder
,
3828 nsIFrame
* aFrame
, nsDisplayList
* aList
)
3829 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
3830 , mCanBeActive(false)
3832 MOZ_COUNT_CTOR(nsDisplayBlendContainer
);
3835 #ifdef NS_BUILD_REFCNT_LOGGING
3836 nsDisplayBlendContainer::~nsDisplayBlendContainer() {
3837 MOZ_COUNT_DTOR(nsDisplayBlendContainer
);
3841 // nsDisplayBlendContainer uses layers for rendering
3842 already_AddRefed
<Layer
>
3843 nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3844 LayerManager
* aManager
,
3845 const ContainerLayerParameters
& aContainerParameters
) {
3846 // turn off anti-aliasing in the parent stacking context because it changes
3847 // how the group is initialized.
3848 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
3849 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
3851 nsRefPtr
<Layer
> container
= aManager
->GetLayerBuilder()->
3852 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3853 newContainerParameters
, nullptr);
3858 container
->SetForceIsolatedGroup(true);
3859 return container
.forget();
3862 bool nsDisplayBlendContainer::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
3863 if (aItem
->GetType() != TYPE_BLEND_CONTAINER
)
3865 // items for the same content element should be merged into a single
3866 // compositing group
3867 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
3868 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
3870 if (aItem
->GetClip() != GetClip())
3872 MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer
*>(aItem
));
3876 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder
* aBuilder
,
3877 nsIFrame
* aFrame
, nsDisplayList
* aList
,
3878 uint32_t aFlags
, ViewID aScrollTarget
)
3879 : nsDisplayWrapList(aBuilder
, aFrame
, aList
)
3881 , mScrollTarget(aScrollTarget
) {
3882 MOZ_COUNT_CTOR(nsDisplayOwnLayer
);
3885 #ifdef NS_BUILD_REFCNT_LOGGING
3886 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
3887 MOZ_COUNT_DTOR(nsDisplayOwnLayer
);
3891 // nsDisplayOpacity uses layers for rendering
3892 already_AddRefed
<Layer
>
3893 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3894 LayerManager
* aManager
,
3895 const ContainerLayerParameters
& aContainerParameters
) {
3896 nsRefPtr
<ContainerLayer
> layer
= aManager
->GetLayerBuilder()->
3897 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
3898 aContainerParameters
, nullptr);
3899 if (mFlags
& VERTICAL_SCROLLBAR
) {
3900 layer
->SetScrollbarData(mScrollTarget
, Layer::ScrollDirection::VERTICAL
);
3902 if (mFlags
& HORIZONTAL_SCROLLBAR
) {
3903 layer
->SetScrollbarData(mScrollTarget
, Layer::ScrollDirection::HORIZONTAL
);
3906 if (mFlags
& GENERATE_SUBDOC_INVALIDATIONS
) {
3907 mFrame
->PresContext()->SetNotifySubDocInvalidationData(layer
);
3909 return layer
.forget();
3912 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder
* aBuilder
,
3913 nsIFrame
* aFrame
, nsDisplayList
* aList
,
3915 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
, aFlags
)
3916 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
3918 MOZ_COUNT_CTOR(nsDisplaySubDocument
);
3921 #ifdef NS_BUILD_REFCNT_LOGGING
3922 nsDisplaySubDocument::~nsDisplaySubDocument() {
3923 MOZ_COUNT_DTOR(nsDisplaySubDocument
);
3927 already_AddRefed
<Layer
>
3928 nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder
* aBuilder
,
3929 LayerManager
* aManager
,
3930 const ContainerLayerParameters
& aContainerParameters
) {
3931 nsPresContext
* presContext
= mFrame
->PresContext();
3932 nsIFrame
* rootScrollFrame
= presContext
->PresShell()->GetRootScrollFrame();
3933 ContainerLayerParameters params
= aContainerParameters
;
3934 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) &&
3935 rootScrollFrame
->GetContent() &&
3936 nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame
->GetContent(), nullptr)) {
3937 params
.mInLowPrecisionDisplayPort
= true;
3940 return nsDisplayOwnLayer::BuildLayer(aBuilder
, aManager
, params
);
3943 UniquePtr
<FrameMetrics
>
3944 nsDisplaySubDocument::ComputeFrameMetrics(Layer
* aLayer
,
3945 const ContainerLayerParameters
& aContainerParameters
)
3947 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
)) {
3948 return UniquePtr
<FrameMetrics
>(nullptr);
3951 nsPresContext
* presContext
= mFrame
->PresContext();
3952 nsIFrame
* rootScrollFrame
= presContext
->PresShell()->GetRootScrollFrame();
3953 bool isRootContentDocument
= presContext
->IsRootContentDocument();
3954 nsIPresShell
* presShell
= presContext
->PresShell();
3955 ContainerLayerParameters
params(presShell
->GetXResolution(),
3956 presShell
->GetYResolution(), nsIntPoint(), aContainerParameters
);
3957 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) &&
3958 rootScrollFrame
->GetContent() &&
3959 nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame
->GetContent(), nullptr)) {
3960 params
.mInLowPrecisionDisplayPort
= true;
3963 nsRect viewport
= mFrame
->GetRect() -
3964 mFrame
->GetPosition() +
3965 mFrame
->GetOffsetToCrossDoc(ReferenceFrame());
3967 return MakeUnique
<FrameMetrics
>(
3968 nsDisplayScrollLayer::ComputeFrameMetrics(mFrame
, rootScrollFrame
, ReferenceFrame(),
3969 aLayer
, mScrollParentId
, viewport
,
3970 false, isRootContentDocument
, params
));
3974 UseDisplayPortForViewport(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
3975 nsRect
* aDisplayPort
= nullptr)
3977 return aBuilder
->IsPaintingToWindow() &&
3978 nsLayoutUtils::ViewportHasDisplayPort(aFrame
->PresContext(), aDisplayPort
);
3982 nsDisplaySubDocument::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
3984 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
3986 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
3988 return mFrame
->GetRect() + aBuilder
->ToReferenceFrame(mFrame
);
3991 return nsDisplayOwnLayer::GetBounds(aBuilder
, aSnap
);
3995 nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
3996 nsRegion
* aVisibleRegion
)
3999 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
, &displayport
);
4001 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
) || !usingDisplayPort
) {
4002 return nsDisplayWrapList::ComputeVisibility(aBuilder
, aVisibleRegion
);
4005 nsRegion childVisibleRegion
;
4006 // The visible region for the children may be much bigger than the hole we
4007 // are viewing the children from, so that the compositor process has enough
4008 // content to asynchronously pan while content is being refreshed.
4009 childVisibleRegion
= displayport
+ mFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4011 nsRect boundedRect
=
4012 childVisibleRegion
.GetBounds().Intersect(mList
.GetBounds(aBuilder
));
4013 bool visible
= mList
.ComputeVisibilityForSublist(
4014 aBuilder
, &childVisibleRegion
, boundedRect
,
4015 usingDisplayPort
? mFrame
: nullptr);
4017 // If APZ is enabled then don't allow this computation to influence
4018 // aVisibleRegion, on the assumption that the layer can be asynchronously
4019 // scrolled so we'll definitely need all the content under it.
4020 if (!nsLayoutUtils::UsesAsyncScrolling()) {
4022 nsRect bounds
= GetBounds(aBuilder
, &snap
);
4024 removed
.Sub(bounds
, childVisibleRegion
);
4026 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4033 nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
4035 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4037 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
4041 return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder
);
4045 nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4047 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4049 if ((mFlags
& GENERATE_SCROLLABLE_LAYER
) && usingDisplayPort
) {
4054 return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder
, aSnap
);
4057 nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder
* aBuilder
,
4058 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4060 : nsDisplaySubDocument(aBuilder
, aFrame
, aList
, aFlags
) {
4061 MOZ_COUNT_CTOR(nsDisplayResolution
);
4064 #ifdef NS_BUILD_REFCNT_LOGGING
4065 nsDisplayResolution::~nsDisplayResolution() {
4066 MOZ_COUNT_DTOR(nsDisplayResolution
);
4070 already_AddRefed
<Layer
>
4071 nsDisplayResolution::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4072 LayerManager
* aManager
,
4073 const ContainerLayerParameters
& aContainerParameters
) {
4074 nsIPresShell
* presShell
= mFrame
->PresContext()->PresShell();
4075 ContainerLayerParameters
containerParameters(
4076 presShell
->GetXResolution(), presShell
->GetYResolution(), nsIntPoint(),
4077 aContainerParameters
);
4079 nsRefPtr
<Layer
> layer
= nsDisplaySubDocument::BuildLayer(
4080 aBuilder
, aManager
, containerParameters
);
4081 layer
->SetPostScale(1.0f
/ presShell
->GetXResolution(),
4082 1.0f
/ presShell
->GetYResolution());
4083 return layer
.forget();
4086 nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder
* aBuilder
,
4088 nsDisplayList
* aList
)
4089 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
)
4091 MOZ_COUNT_CTOR(nsDisplayStickyPosition
);
4094 #ifdef NS_BUILD_REFCNT_LOGGING
4095 nsDisplayStickyPosition::~nsDisplayStickyPosition() {
4096 MOZ_COUNT_DTOR(nsDisplayStickyPosition
);
4100 already_AddRefed
<Layer
>
4101 nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4102 LayerManager
* aManager
,
4103 const ContainerLayerParameters
& aContainerParameters
) {
4104 nsRefPtr
<Layer
> layer
=
4105 nsDisplayOwnLayer::BuildLayer(aBuilder
, aManager
, aContainerParameters
);
4107 StickyScrollContainer
* stickyScrollContainer
= StickyScrollContainer::
4108 GetStickyScrollContainerForFrame(mFrame
);
4109 if (!stickyScrollContainer
) {
4110 return layer
.forget();
4113 nsIFrame
* scrollFrame
= do_QueryFrame(stickyScrollContainer
->ScrollFrame());
4114 nsPresContext
* presContext
= scrollFrame
->PresContext();
4116 // Sticky position frames whose scroll frame is the root scroll frame are
4117 // reflowed into the scroll-port size if one has been set.
4118 nsSize scrollFrameSize
= scrollFrame
->GetSize();
4119 if (scrollFrame
== presContext
->PresShell()->GetRootScrollFrame() &&
4120 presContext
->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
4121 scrollFrameSize
= presContext
->PresShell()->
4122 GetScrollPositionClampingScrollPortSize();
4125 nsLayoutUtils::SetFixedPositionLayerData(layer
, scrollFrame
,
4126 nsRect(scrollFrame
->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize
),
4127 mFrame
, presContext
, aContainerParameters
);
4129 ViewID scrollId
= nsLayoutUtils::FindOrCreateIDFor(
4130 stickyScrollContainer
->ScrollFrame()->GetScrolledFrame()->GetContent());
4132 float factor
= presContext
->AppUnitsPerDevPixel();
4135 stickyScrollContainer
->GetScrollRanges(mFrame
, &outer
, &inner
);
4136 LayerRect
stickyOuter(NSAppUnitsToFloatPixels(outer
.x
, factor
) *
4137 aContainerParameters
.mXScale
,
4138 NSAppUnitsToFloatPixels(outer
.y
, factor
) *
4139 aContainerParameters
.mYScale
,
4140 NSAppUnitsToFloatPixels(outer
.width
, factor
) *
4141 aContainerParameters
.mXScale
,
4142 NSAppUnitsToFloatPixels(outer
.height
, factor
) *
4143 aContainerParameters
.mYScale
);
4144 LayerRect
stickyInner(NSAppUnitsToFloatPixels(inner
.x
, factor
) *
4145 aContainerParameters
.mXScale
,
4146 NSAppUnitsToFloatPixels(inner
.y
, factor
) *
4147 aContainerParameters
.mYScale
,
4148 NSAppUnitsToFloatPixels(inner
.width
, factor
) *
4149 aContainerParameters
.mXScale
,
4150 NSAppUnitsToFloatPixels(inner
.height
, factor
) *
4151 aContainerParameters
.mYScale
);
4152 layer
->SetStickyPositionData(scrollId
, stickyOuter
, stickyInner
);
4154 return layer
.forget();
4157 bool nsDisplayStickyPosition::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
) {
4158 if (aItem
->GetType() != TYPE_STICKY_POSITION
)
4160 // Items with the same fixed position frame can be merged.
4161 nsDisplayStickyPosition
* other
= static_cast<nsDisplayStickyPosition
*>(aItem
);
4162 if (other
->mFrame
!= mFrame
)
4164 if (aItem
->GetClip() != GetClip())
4166 MergeFromTrackingMergedFrames(other
);
4170 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4171 nsDisplayList
* aList
,
4172 nsIFrame
* aForFrame
,
4173 nsIFrame
* aScrolledFrame
,
4174 nsIFrame
* aScrollFrame
)
4175 : nsDisplayWrapList(aBuilder
, aForFrame
, aList
)
4176 , mScrollFrame(aScrollFrame
)
4177 , mScrolledFrame(aScrolledFrame
)
4178 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4179 , mDisplayPortContentsOpaque(false)
4181 #ifdef NS_BUILD_REFCNT_LOGGING
4182 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4185 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4186 "Need a child frame with content");
4189 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4190 nsDisplayItem
* aItem
,
4191 nsIFrame
* aForFrame
,
4192 nsIFrame
* aScrolledFrame
,
4193 nsIFrame
* aScrollFrame
)
4194 : nsDisplayWrapList(aBuilder
, aForFrame
, aItem
)
4195 , mScrollFrame(aScrollFrame
)
4196 , mScrolledFrame(aScrolledFrame
)
4197 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4198 , mDisplayPortContentsOpaque(false)
4200 #ifdef NS_BUILD_REFCNT_LOGGING
4201 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4204 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4205 "Need a child frame with content");
4208 nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder
* aBuilder
,
4209 nsIFrame
* aForFrame
,
4210 nsIFrame
* aScrolledFrame
,
4211 nsIFrame
* aScrollFrame
)
4212 : nsDisplayWrapList(aBuilder
, aForFrame
)
4213 , mScrollFrame(aScrollFrame
)
4214 , mScrolledFrame(aScrolledFrame
)
4215 , mScrollParentId(aBuilder
->GetCurrentScrollParentId())
4216 , mDisplayPortContentsOpaque(false)
4218 #ifdef NS_BUILD_REFCNT_LOGGING
4219 MOZ_COUNT_CTOR(nsDisplayScrollLayer
);
4222 NS_ASSERTION(mScrolledFrame
&& mScrolledFrame
->GetContent(),
4223 "Need a child frame with content");
4226 #ifdef NS_BUILD_REFCNT_LOGGING
4227 nsDisplayScrollLayer::~nsDisplayScrollLayer()
4229 MOZ_COUNT_DTOR(nsDisplayScrollLayer
);
4234 nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4236 nsIScrollableFrame
* sf
= do_QueryFrame(mScrollFrame
);
4239 return sf
->GetScrollPortRect() + aBuilder
->ToReferenceFrame(mScrollFrame
);
4241 return nsDisplayWrapList::GetBounds(aBuilder
, aSnap
);
4245 nsDisplayScrollLayer::GetScrolledContentRectToDraw(nsDisplayListBuilder
* aBuilder
,
4246 nsRect
* aDisplayPort
)
4249 // The visible region for the children may be much bigger than the hole we
4250 // are viewing the children from, so that the compositor process has enough
4251 // content to asynchronously pan while content is being refreshed.
4252 // XXX mScrollFrame seems wrong here; we should add the offset of the
4254 return *aDisplayPort
+ mScrollFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4257 return GetBounds(aBuilder
, &snap
);
4260 already_AddRefed
<Layer
>
4261 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder
* aBuilder
,
4262 LayerManager
* aManager
,
4263 const ContainerLayerParameters
& aContainerParameters
)
4265 ContainerLayerParameters params
= aContainerParameters
;
4266 if (mScrolledFrame
->GetContent() &&
4267 nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4268 params
.mInLowPrecisionDisplayPort
= true;
4271 if (mList
.IsOpaque()) {
4273 bool usingDisplayport
=
4274 nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), &displayport
);
4275 mDisplayPortContentsOpaque
= mList
.GetBounds(aBuilder
).Contains(
4276 GetScrolledContentRectToDraw(aBuilder
, usingDisplayport
? &displayport
: nullptr));
4278 mDisplayPortContentsOpaque
= false;
4281 return aManager
->GetLayerBuilder()->
4282 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
4286 UniquePtr
<FrameMetrics
>
4287 nsDisplayScrollLayer::ComputeFrameMetrics(Layer
* aLayer
,
4288 const ContainerLayerParameters
& aContainerParameters
)
4290 ContainerLayerParameters params
= aContainerParameters
;
4291 if (mScrolledFrame
->GetContent() &&
4292 nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4293 params
.mInLowPrecisionDisplayPort
= true;
4296 nsRect viewport
= mScrollFrame
->GetRect() -
4297 mScrollFrame
->GetPosition() +
4298 mScrollFrame
->GetOffsetToCrossDoc(ReferenceFrame());
4300 return UniquePtr
<FrameMetrics
>(new FrameMetrics(
4301 ComputeFrameMetrics(mScrolledFrame
, mScrollFrame
, ReferenceFrame(), aLayer
,
4302 mScrollParentId
, viewport
, false, false, params
)));
4306 nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
4308 if (nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), nullptr)) {
4312 return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder
);
4316 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
4317 nsRegion
* aVisibleRegion
)
4319 if (aBuilder
->IsForPluginGeometry()) {
4320 return nsDisplayWrapList::ComputeVisibility(aBuilder
, aVisibleRegion
);
4323 bool usingDisplayPort
=
4324 nsLayoutUtils::GetDisplayPort(mScrolledFrame
->GetContent(), &displayport
);
4325 nsRect scrolledContentRect
= GetScrolledContentRectToDraw(aBuilder
,
4326 usingDisplayPort
? &displayport
: nullptr);
4328 nsRect boundedRect
= scrolledContentRect
.Intersect(mList
.GetBounds(aBuilder
));
4329 nsRegion childVisibleRegion
= scrolledContentRect
;
4330 bool visible
= mList
.ComputeVisibilityForSublist(
4331 aBuilder
, &childVisibleRegion
, boundedRect
,
4332 usingDisplayPort
? mScrollFrame
: nullptr);
4334 // If APZ is enabled then don't allow this computation to influence
4335 // aVisibleRegion, on the assumption that the layer can be asynchronously
4336 // scrolled so we'll definitely need all the content under it.
4337 if (!nsLayoutUtils::UsesAsyncScrolling()) {
4339 nsRect bounds
= GetBounds(aBuilder
, &snap
);
4341 removed
.Sub(bounds
, childVisibleRegion
);
4342 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4349 nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder
* aBuilder
,
4350 LayerManager
* aManager
,
4351 const ContainerLayerParameters
& aParameters
)
4353 // Force this as a layer so we can scroll asynchronously.
4354 // This causes incorrect rendering for rounded clips!
4355 return LAYER_ACTIVE_FORCE
;
4358 // Check if we are going to clip an abs pos item that we don't contain.
4359 // Root scroll frames clip all their descendants, so we don't need to worry
4362 WouldCauseIncorrectClippingOnAbsPosItem(nsDisplayListBuilder
* aBuilder
,
4363 nsDisplayScrollLayer
* aItem
)
4365 nsIFrame
* scrollFrame
= aItem
->GetScrollFrame();
4366 nsIPresShell
* presShell
= scrollFrame
->PresContext()->PresShell();
4367 if (scrollFrame
== presShell
->GetRootScrollFrame()) {
4370 nsIFrame
* scrolledFrame
= aItem
->GetScrolledFrame();
4371 nsIFrame
* frame
= aItem
->Frame();
4372 if (frame
== scrolledFrame
|| !frame
->IsAbsolutelyPositioned() ||
4373 nsLayoutUtils::IsAncestorFrameCrossDoc(scrollFrame
, frame
, presShell
->GetRootFrame())) {
4376 if (!aItem
->GetClip().IsRectAffectedByClip(aItem
->GetChildren()->GetBounds(aBuilder
))) {
4383 nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder
* aBuilder
,
4384 nsDisplayItem
* aItem
)
4386 if (aItem
->GetType() != TYPE_SCROLL_LAYER
) {
4389 nsDisplayScrollLayer
* other
= static_cast<nsDisplayScrollLayer
*>(aItem
);
4390 if (other
->mScrolledFrame
!= this->mScrolledFrame
) {
4393 if (aItem
->GetClip() != GetClip()) {
4397 if (WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, this) ||
4398 WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, other
)) {
4402 NS_ASSERTION(other
->mReferenceFrame
== mReferenceFrame
,
4403 "Must have the same reference frame!");
4405 FrameProperties props
= mScrolledFrame
->Properties();
4406 props
.Set(nsIFrame::ScrollLayerCount(),
4407 reinterpret_cast<void*>(GetScrollLayerCount() - 1));
4409 // Swap frames with the other item before doing MergeFrom.
4410 // XXX - This ensures that the frame associated with a scroll layer after
4411 // merging is the first, rather than the last. This tends to change less,
4412 // ensuring we're more likely to retain the associated gfx layer.
4413 // See Bug 729534 and Bug 731641.
4414 nsIFrame
* tmp
= mFrame
;
4415 mFrame
= other
->mFrame
;
4416 other
->mFrame
= tmp
;
4417 MergeFromTrackingMergedFrames(other
);
4422 PropagateClip(nsDisplayListBuilder
* aBuilder
, const DisplayItemClip
& aClip
,
4423 nsDisplayList
* aList
)
4425 for (nsDisplayItem
* i
= aList
->GetBottom(); i
!= nullptr; i
= i
->GetAbove()) {
4426 DisplayItemClip
clip(i
->GetClip());
4427 clip
.IntersectWith(aClip
);
4428 i
->SetClip(aBuilder
, clip
);
4429 nsDisplayList
* list
= i
->GetSameCoordinateSystemChildren();
4431 PropagateClip(aBuilder
, aClip
, list
);
4437 nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
4439 bool badAbsPosClip
= WouldCauseIncorrectClippingOnAbsPosItem(aBuilder
, this);
4440 if (GetScrollLayerCount() > 1 || badAbsPosClip
) {
4441 // Propagate our clip to our children. The clip for the scroll frame is
4442 // on this item, but not our child items so that they can draw non-visible
4443 // parts of the display port. But if we are flattening we failed and can't
4444 // draw the extra content, so it needs to be clipped.
4445 // But don't induce our clip on abs pos frames that we shouldn't be clipping.
4446 if (!badAbsPosClip
) {
4447 PropagateClip(aBuilder
, GetClip(), &mList
);
4450 // Output something so the failure can be noted.
4452 mScrolledFrame
->GetContent()->GetProperty(nsGkAtoms::AsyncScrollLayerCreationFailed
, &status
);
4453 if (status
== NS_PROPTABLE_PROP_NOT_THERE
) {
4454 mScrolledFrame
->GetContent()->SetProperty(nsGkAtoms::AsyncScrollLayerCreationFailed
, nullptr);
4455 if (badAbsPosClip
) {
4456 printf_stderr("Async scrollable layer creation failed: scroll layer would induce incorrent clipping to an abs pos item.\n");
4458 printf_stderr("Async scrollable layer creation failed: scroll layer can't have scrollable and non-scrollable items interleaved.\n");
4460 #ifdef MOZ_DUMP_PAINTING
4461 std::stringstream ss
;
4462 nsFrame::PrintDisplayItem(aBuilder
, this, ss
, true, false);
4463 printf_stderr("%s\n", ss
.str().c_str());
4469 if (mFrame
!= mScrolledFrame
) {
4470 mMergedFrames
.AppendElement(mFrame
);
4471 mFrame
= mScrolledFrame
;
4477 nsDisplayScrollLayer::GetScrollLayerCount()
4479 FrameProperties props
= mScrolledFrame
->Properties();
4481 bool hasCount
= false;
4482 intptr_t result
= reinterpret_cast<intptr_t>(
4483 props
.Get(nsIFrame::ScrollLayerCount(), &hasCount
));
4484 // If this aborts, then the property was either not added before scroll
4485 // layers were created or the property was deleted to early. If the latter,
4486 // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so
4487 // that it is processed last.
4488 NS_ABORT_IF_FALSE(hasCount
, "nsDisplayScrollLayer should always be defined");
4491 return reinterpret_cast<intptr_t>(props
.Get(nsIFrame::ScrollLayerCount()));
4495 #ifdef MOZ_DUMP_PAINTING
4497 nsDisplayScrollLayer::WriteDebugInfo(std::stringstream
& aStream
)
4499 aStream
<< " (scrollframe " << mScrollFrame
4500 << " scrolledFrame " << mScrolledFrame
<< ")";
4504 nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
4505 nsDisplayListBuilder
* aBuilder
,
4506 nsIFrame
* aScrolledFrame
,
4507 nsIFrame
* aScrollFrame
)
4508 : nsDisplayScrollLayer(aBuilder
, aScrollFrame
, aScrolledFrame
, aScrollFrame
)
4510 #ifdef NS_BUILD_REFCNT_LOGGING
4511 MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer
);
4515 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
4517 MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer
);
4521 nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4523 return nsDisplayWrapList::GetBounds(aBuilder
, aSnap
);
4527 nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder
* aBuilder
,
4528 LayerManager
* aManager
,
4529 const ContainerLayerParameters
& aParameters
)
4531 return LAYER_ACTIVE_EMPTY
;
4535 nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder
* aBuilder
,
4536 nsDisplayItem
* aItem
)
4542 nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder
* aBuilder
)
4544 // Layer metadata for a particular scroll frame needs to be unique. Only
4545 // one nsDisplayScrollLayer (with rendered content) or one
4546 // nsDisplayScrollInfoLayer (with only the metadata) should survive the
4547 // visibility computation.
4548 return GetScrollLayerCount() == 1;
4551 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder
* aBuilder
,
4552 nsIFrame
* aFrame
, nsDisplayList
* aList
,
4553 int32_t aAPD
, int32_t aParentAPD
,
4555 : nsDisplaySubDocument(aBuilder
, aFrame
, aList
, aFlags
)
4556 , mAPD(aAPD
), mParentAPD(aParentAPD
) {
4557 MOZ_COUNT_CTOR(nsDisplayZoom
);
4560 #ifdef NS_BUILD_REFCNT_LOGGING
4561 nsDisplayZoom::~nsDisplayZoom() {
4562 MOZ_COUNT_DTOR(nsDisplayZoom
);
4566 nsRect
nsDisplayZoom::GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
)
4568 nsRect bounds
= nsDisplaySubDocument::GetBounds(aBuilder
, aSnap
);
4570 return bounds
.ConvertAppUnitsRoundOut(mAPD
, mParentAPD
);
4573 void nsDisplayZoom::HitTest(nsDisplayListBuilder
*aBuilder
,
4574 const nsRect
& aRect
,
4575 HitTestState
*aState
,
4576 nsTArray
<nsIFrame
*> *aOutFrames
)
4579 // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
4580 // rect as well instead of possibly rounding the width or height to zero.
4581 if (aRect
.width
== 1 && aRect
.height
== 1) {
4582 rect
.MoveTo(aRect
.TopLeft().ConvertAppUnits(mParentAPD
, mAPD
));
4583 rect
.width
= rect
.height
= 1;
4585 rect
= aRect
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4587 mList
.HitTest(aBuilder
, rect
, aState
, aOutFrames
);
4590 bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder
*aBuilder
,
4591 nsRegion
*aVisibleRegion
)
4593 // Convert the passed in visible region to our appunits.
4594 nsRegion visibleRegion
;
4595 // mVisibleRect has been clipped to GetClippedBounds
4596 visibleRegion
.And(*aVisibleRegion
, mVisibleRect
);
4597 visibleRegion
= visibleRegion
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4598 nsRegion originalVisibleRegion
= visibleRegion
;
4600 nsRect transformedVisibleRect
=
4601 mVisibleRect
.ConvertAppUnitsRoundOut(mParentAPD
, mAPD
);
4603 // If we are to generate a scrollable layer we call
4604 // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
4605 // for ComputeVisibility, it does all it's calculations in the child APD.
4606 bool usingDisplayPort
= UseDisplayPortForViewport(aBuilder
, mFrame
);
4607 if (!(mFlags
& GENERATE_SCROLLABLE_LAYER
) || !usingDisplayPort
) {
4609 mList
.ComputeVisibilityForSublist(aBuilder
, &visibleRegion
,
4610 transformedVisibleRect
);
4613 nsDisplaySubDocument::ComputeVisibility(aBuilder
, &visibleRegion
);
4617 // removed = originalVisibleRegion - visibleRegion
4618 removed
.Sub(originalVisibleRegion
, visibleRegion
);
4619 // Convert removed region to parent appunits.
4620 removed
= removed
.ConvertAppUnitsRoundIn(mAPD
, mParentAPD
);
4621 // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
4622 // SubtractFromVisibleRegion does)
4623 aBuilder
->SubtractFromVisibleRegion(aVisibleRegion
, removed
);
4628 ///////////////////////////////////////////////////
4629 // nsDisplayTransform Implementation
4632 // Write #define UNIFIED_CONTINUATIONS here to have the transform property try
4633 // to transform content with continuations as one unified block instead of
4634 // several smaller ones. This is currently disabled because it doesn't work
4635 // correctly, since when the frames are initially being reflowed, their
4636 // continuations all compute their bounding rects independently of each other
4637 // and consequently get the wrong value. Write #define DEBUG_HIT here to have
4638 // the nsDisplayTransform class dump out a bunch of information about hit
4640 #undef UNIFIED_CONTINUATIONS
4643 /* Returns the bounds of a frame as defined for transforms. If
4644 * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
4645 * rectangle, translated to the origin. Otherwise, returns the smallest
4646 * rectangle containing a frame and all of its continuations. For example, if
4647 * there is a <span> element with several continuations split over several
4648 * lines, this function will return the rectangle containing all of those
4649 * continuations. This rectangle is relative to the origin of the frame's local
4652 #ifndef UNIFIED_CONTINUATIONS
4655 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame
* aFrame
)
4657 NS_PRECONDITION(aFrame
, "Can't get the bounds of a nonexistent frame!");
4659 if (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) {
4660 // TODO: SVG needs to define what percentage translations resolve against.
4664 return nsRect(nsPoint(0, 0), aFrame
->GetSize());
4670 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame
* aFrame
)
4672 NS_PRECONDITION(aFrame
, "Can't get the bounds of a nonexistent frame!");
4676 if (aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) {
4677 // TODO: SVG needs to define what percentage translations resolve against.
4681 /* Iterate through the continuation list, unioning together all the
4684 for (const nsIFrame
*currFrame
= aFrame
->FirstContinuation();
4685 currFrame
!= nullptr;
4686 currFrame
= currFrame
->GetNextContinuation())
4688 /* Get the frame rect in local coordinates, then translate back to the
4689 * original coordinates.
4691 result
.UnionRect(result
, nsRect(currFrame
->GetOffsetTo(aFrame
),
4692 currFrame
->GetSize()));
4700 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4701 nsIFrame
*aFrame
, nsDisplayList
*aList
,
4702 const nsRect
& aChildrenVisibleRect
,
4703 ComputeTransformFunction aTransformGetter
,
4705 : nsDisplayItem(aBuilder
, aFrame
)
4706 , mStoredList(aBuilder
, aFrame
, aList
)
4707 , mTransformGetter(aTransformGetter
)
4708 , mChildrenVisibleRect(aChildrenVisibleRect
)
4711 MOZ_COUNT_CTOR(nsDisplayTransform
);
4712 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4713 NS_ABORT_IF_FALSE(!aFrame
->IsTransformed(), "Can't specify a transform getter for a transformed frame!");
4718 nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder
* aBuilder
)
4721 aBuilder
->FindReferenceFrameFor(GetTransformRootFrame(mFrame
));
4722 mToReferenceFrame
= mFrame
->GetOffsetToCrossDoc(mReferenceFrame
);
4723 mVisibleRect
= aBuilder
->GetDirtyRect() + mToReferenceFrame
;
4727 nsDisplayTransform::Init(nsDisplayListBuilder
* aBuilder
)
4729 mStoredList
.SetClip(aBuilder
, DisplayItemClip::NoClip());
4730 mStoredList
.SetVisibleRect(mChildrenVisibleRect
);
4731 mMaybePrerender
= ShouldPrerenderTransformedContent(aBuilder
, mFrame
);
4733 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
4734 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
)) {
4735 // We will only pre-render if this will-change is on budget.
4736 mMaybePrerender
= true;
4739 if (mMaybePrerender
) {
4741 mVisibleRect
= GetBounds(aBuilder
, &snap
);
4745 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4746 nsIFrame
*aFrame
, nsDisplayList
*aList
,
4747 const nsRect
& aChildrenVisibleRect
,
4749 : nsDisplayItem(aBuilder
, aFrame
)
4750 , mStoredList(aBuilder
, aFrame
, aList
)
4751 , mTransformGetter(nullptr)
4752 , mChildrenVisibleRect(aChildrenVisibleRect
)
4755 MOZ_COUNT_CTOR(nsDisplayTransform
);
4756 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4757 SetReferenceFrameToAncestor(aBuilder
);
4761 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder
* aBuilder
,
4762 nsIFrame
*aFrame
, nsDisplayItem
*aItem
,
4763 const nsRect
& aChildrenVisibleRect
,
4765 : nsDisplayItem(aBuilder
, aFrame
)
4766 , mStoredList(aBuilder
, aFrame
, aItem
)
4767 , mTransformGetter(nullptr)
4768 , mChildrenVisibleRect(aChildrenVisibleRect
)
4771 MOZ_COUNT_CTOR(nsDisplayTransform
);
4772 NS_ABORT_IF_FALSE(aFrame
, "Must have a frame!");
4773 SetReferenceFrameToAncestor(aBuilder
);
4777 /* Returns the delta specified by the -moz-transform-origin property.
4778 * This is a positive delta, meaning that it indicates the direction to move
4779 * to get from (0, 0) of the frame to the transform origin. This function is
4780 * called off the main thread.
4782 /* static */ Point3D
4783 nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame
* aFrame
,
4784 float aAppUnitsPerPixel
,
4785 const nsRect
* aBoundsOverride
)
4787 NS_PRECONDITION(aFrame
, "Can't get delta for a null frame!");
4788 NS_PRECONDITION(aFrame
->IsTransformed() || aFrame
->StyleDisplay()->BackfaceIsHidden(),
4789 "Shouldn't get a delta for an untransformed frame!");
4791 if (!aFrame
->IsTransformed()) {
4795 /* For both of the coordinates, if the value of -moz-transform is a
4796 * percentage, it's relative to the size of the frame. Otherwise, if it's
4797 * a distance, it's already computed for us!
4799 const nsStyleDisplay
* display
= aFrame
->StyleDisplay();
4800 nsRect boundingRect
= (aBoundsOverride
? *aBoundsOverride
:
4801 nsDisplayTransform::GetFrameBoundsForTransform(aFrame
));
4803 /* Allows us to access named variables by index. */
4805 const nscoord
* dimensions
[2] =
4806 {&boundingRect
.width
, &boundingRect
.height
};
4808 for (uint8_t index
= 0; index
< 2; ++index
) {
4809 /* If the -moz-transform-origin specifies a percentage, take the percentage
4810 * of the size of the box.
4812 const nsStyleCoord
&coord
= display
->mTransformOrigin
[index
];
4813 if (coord
.GetUnit() == eStyleUnit_Calc
) {
4814 const nsStyleCoord::Calc
*calc
= coord
.GetCalcValue();
4816 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
4818 NSAppUnitsToFloatPixels(calc
->mLength
, aAppUnitsPerPixel
);
4819 } else if (coord
.GetUnit() == eStyleUnit_Percent
) {
4821 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
4822 coord
.GetPercentValue();
4824 NS_ABORT_IF_FALSE(coord
.GetUnit() == eStyleUnit_Coord
, "unexpected unit");
4826 NSAppUnitsToFloatPixels(coord
.GetCoordValue(), aAppUnitsPerPixel
);
4828 if ((aFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
) &&
4829 coord
.GetUnit() != eStyleUnit_Percent
) {
4830 // <length> values represent offsets from the origin of the SVG element's
4831 // user space, not the top left of its bounds, so we must adjust for that:
4833 (index
== 0) ? aFrame
->GetPosition().x
: aFrame
->GetPosition().y
;
4834 coords
[index
] -= NSAppUnitsToFloatPixels(offset
, aAppUnitsPerPixel
);
4838 coords
[2] = NSAppUnitsToFloatPixels(display
->mTransformOrigin
[2].GetCoordValue(),
4840 /* Adjust based on the origin of the rectangle. */
4841 coords
[0] += NSAppUnitsToFloatPixels(boundingRect
.x
, aAppUnitsPerPixel
);
4842 coords
[1] += NSAppUnitsToFloatPixels(boundingRect
.y
, aAppUnitsPerPixel
);
4844 return Point3D(coords
[0], coords
[1], coords
[2]);
4847 /* Returns the delta specified by the -moz-perspective-origin property.
4848 * This is a positive delta, meaning that it indicates the direction to move
4849 * to get from (0, 0) of the frame to the perspective origin. This function is
4850 * called off the main thread.
4852 /* static */ Point3D
4853 nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame
* aFrame
,
4854 float aAppUnitsPerPixel
)
4856 NS_PRECONDITION(aFrame
, "Can't get delta for a null frame!");
4857 NS_PRECONDITION(aFrame
->IsTransformed() || aFrame
->StyleDisplay()->BackfaceIsHidden(),
4858 "Shouldn't get a delta for an untransformed frame!");
4860 if (!aFrame
->IsTransformed()) {
4864 /* For both of the coordinates, if the value of -moz-perspective-origin is a
4865 * percentage, it's relative to the size of the frame. Otherwise, if it's
4866 * a distance, it's already computed for us!
4869 //TODO: Should this be using our bounds or the parent's bounds?
4870 // How do we handle aBoundsOverride in the latter case?
4872 nsStyleContext
* psc
= aFrame
->GetParentStyleContext(&parent
);
4877 parent
= aFrame
->GetParent();
4882 const nsStyleDisplay
* display
= psc
->StyleDisplay();
4883 nsRect boundingRect
= nsDisplayTransform::GetFrameBoundsForTransform(parent
);
4885 /* Allows us to access named variables by index. */
4888 gfx::Float
* coords
[2] = {&result
.x
, &result
.y
};
4889 const nscoord
* dimensions
[2] =
4890 {&boundingRect
.width
, &boundingRect
.height
};
4892 for (uint8_t index
= 0; index
< 2; ++index
) {
4893 /* If the -moz-transform-origin specifies a percentage, take the percentage
4894 * of the size of the box.
4896 const nsStyleCoord
&coord
= display
->mPerspectiveOrigin
[index
];
4897 if (coord
.GetUnit() == eStyleUnit_Calc
) {
4898 const nsStyleCoord::Calc
*calc
= coord
.GetCalcValue();
4900 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
4902 NSAppUnitsToFloatPixels(calc
->mLength
, aAppUnitsPerPixel
);
4903 } else if (coord
.GetUnit() == eStyleUnit_Percent
) {
4905 NSAppUnitsToFloatPixels(*dimensions
[index
], aAppUnitsPerPixel
) *
4906 coord
.GetPercentValue();
4908 NS_ABORT_IF_FALSE(coord
.GetUnit() == eStyleUnit_Coord
, "unexpected unit");
4910 NSAppUnitsToFloatPixels(coord
.GetCoordValue(), aAppUnitsPerPixel
);
4914 nsPoint parentOffset
= aFrame
->GetOffsetTo(parent
);
4916 NSAppUnitsToFloatPixels(parentOffset
.x
, aAppUnitsPerPixel
),
4917 NSAppUnitsToFloatPixels(parentOffset
.y
, aAppUnitsPerPixel
),
4920 return result
- gfxOffset
;
4923 nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame
* aFrame
,
4924 float aAppUnitsPerPixel
,
4925 const nsRect
* aBoundsOverride
)
4927 , mTransformList(aFrame
->StyleDisplay()->mSpecifiedTransform
)
4928 , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame
, aAppUnitsPerPixel
, aBoundsOverride
))
4929 , mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame
, aAppUnitsPerPixel
))
4930 , mChildPerspective(0)
4932 const nsStyleDisplay
* parentDisp
= nullptr;
4933 nsStyleContext
* parentStyleContext
= aFrame
->StyleContext()->GetParent();
4934 if (parentStyleContext
) {
4935 parentDisp
= parentStyleContext
->StyleDisplay();
4937 if (parentDisp
&& parentDisp
->mChildPerspective
.GetUnit() == eStyleUnit_Coord
) {
4938 mChildPerspective
= parentDisp
->mChildPerspective
.GetCoordValue();
4942 /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
4943 * translates from local coordinate space to transform coordinate space, then
4947 nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties
& aProperties
,
4948 const nsPoint
& aOrigin
,
4949 float aAppUnitsPerPixel
,
4950 const nsRect
* aBoundsOverride
,
4951 nsIFrame
** aOutAncestor
)
4953 return GetResultingTransformMatrixInternal(aProperties
, aOrigin
, aAppUnitsPerPixel
,
4954 aBoundsOverride
, aOutAncestor
, false);
4958 nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame
* aFrame
,
4959 const nsPoint
& aOrigin
,
4960 float aAppUnitsPerPixel
,
4961 const nsRect
* aBoundsOverride
,
4962 nsIFrame
** aOutAncestor
,
4963 bool aOffsetByOrigin
)
4965 FrameTransformProperties
props(aFrame
,
4969 return GetResultingTransformMatrixInternal(props
, aOrigin
, aAppUnitsPerPixel
,
4970 aBoundsOverride
, aOutAncestor
,
4975 nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties
& aProperties
,
4976 const nsPoint
& aOrigin
,
4977 float aAppUnitsPerPixel
,
4978 const nsRect
* aBoundsOverride
,
4979 nsIFrame
** aOutAncestor
,
4980 bool aOffsetByOrigin
)
4982 const nsIFrame
*frame
= aProperties
.mFrame
;
4985 *aOutAncestor
= nsLayoutUtils::GetCrossDocParentFrame(frame
);
4988 /* Get the underlying transform matrix. This requires us to get the
4989 * bounds of the frame.
4991 nsRect bounds
= (aBoundsOverride
? *aBoundsOverride
:
4992 nsDisplayTransform::GetFrameBoundsForTransform(frame
));
4994 /* Get the matrix, then change its basis to factor in the origin. */
4997 // Call IsSVGTransformed() regardless of the value of
4998 // disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
4999 Matrix svgTransform
, transformFromSVGParent
;
5000 bool hasSVGTransforms
=
5001 frame
&& frame
->IsSVGTransformed(&svgTransform
, &transformFromSVGParent
);
5002 /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
5003 if (aProperties
.mTransformList
) {
5004 result
= nsStyleTransformMatrix::ReadTransforms(aProperties
.mTransformList
->mHead
,
5005 frame
? frame
->StyleContext() : nullptr,
5006 frame
? frame
->PresContext() : nullptr,
5007 dummy
, bounds
, aAppUnitsPerPixel
);
5008 } else if (hasSVGTransforms
) {
5009 // Correct the translation components for zoom:
5010 float pixelsPerCSSPx
= frame
->PresContext()->AppUnitsPerCSSPixel() /
5012 svgTransform
._31
*= pixelsPerCSSPx
;
5013 svgTransform
._32
*= pixelsPerCSSPx
;
5014 result
= gfx3DMatrix::From2D(ThebesMatrix(svgTransform
));
5017 if (hasSVGTransforms
&& !transformFromSVGParent
.IsIdentity()) {
5018 // Correct the translation components for zoom:
5019 float pixelsPerCSSPx
= frame
->PresContext()->AppUnitsPerCSSPixel() /
5021 transformFromSVGParent
._31
*= pixelsPerCSSPx
;
5022 transformFromSVGParent
._32
*= pixelsPerCSSPx
;
5023 result
= result
* gfx3DMatrix::From2D(ThebesMatrix(transformFromSVGParent
));
5026 if (aProperties
.mChildPerspective
> 0.0) {
5027 gfx3DMatrix perspective
;
5029 -1.0 / NSAppUnitsToFloatPixels(aProperties
.mChildPerspective
, aAppUnitsPerPixel
);
5030 /* At the point when perspective is applied, we have been translated to the transform origin.
5031 * The translation to the perspective origin is the difference between these values.
5033 perspective
.ChangeBasis(aProperties
.mToPerspectiveOrigin
- aProperties
.mToTransformOrigin
);
5034 result
= result
* perspective
;
5037 /* Account for the -moz-transform-origin property by translating the
5038 * coordinate space to the new origin.
5041 Point3D(NSAppUnitsToFloatPixels(aOrigin
.x
, aAppUnitsPerPixel
),
5042 NSAppUnitsToFloatPixels(aOrigin
.y
, aAppUnitsPerPixel
),
5044 Point3D
roundedOrigin(hasSVGTransforms
? newOrigin
.x
: NS_round(newOrigin
.x
),
5045 hasSVGTransforms
? newOrigin
.y
: NS_round(newOrigin
.y
),
5047 Point3D offsetBetweenOrigins
= roundedOrigin
+ aProperties
.mToTransformOrigin
;
5049 if (frame
&& frame
->Preserves3D()) {
5050 // Include the transform set on our parent
5051 NS_ASSERTION(frame
->GetParent() &&
5052 frame
->GetParent()->IsTransformed() &&
5053 frame
->GetParent()->Preserves3DChildren(),
5054 "Preserve3D mismatch!");
5055 FrameTransformProperties
props(frame
->GetParent(),
5059 // If this frame isn't transformed (but we exist for backface-visibility),
5060 // then we're not a reference frame so no offset to origin will be added. Our
5061 // parent transform however *is* the reference frame, so we pass true for
5062 // aOffsetByOrigin to convert into the correct coordinate space.
5063 gfx3DMatrix parent
=
5064 GetResultingTransformMatrixInternal(props
,
5065 aOrigin
- frame
->GetPosition(),
5066 aAppUnitsPerPixel
, nullptr,
5067 aOutAncestor
, !frame
->IsTransformed());
5069 result
.ChangeBasis(offsetBetweenOrigins
);
5070 result
= result
* parent
;
5071 if (aOffsetByOrigin
) {
5072 result
.Translate(roundedOrigin
);
5077 if (aOffsetByOrigin
) {
5078 // We can fold the final translation by roundedOrigin into the first matrix
5079 // basis change translation. This is more stable against variation due to
5080 // insufficient floating point precision than reversing the translation
5082 result
.Translate(-aProperties
.mToTransformOrigin
);
5083 result
.TranslatePost(offsetBetweenOrigins
);
5085 result
.ChangeBasis(offsetBetweenOrigins
);
5091 nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder
* aBuilder
)
5093 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_opacity
)) {
5097 if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
5099 message
.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
5100 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5101 Frame()->GetContent());
5107 nsDisplayTransform::ShouldPrerender(nsDisplayListBuilder
* aBuilder
) {
5108 if (!mMaybePrerender
) {
5112 if (ShouldPrerenderTransformedContent(aBuilder
, mFrame
)) {
5116 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
5117 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
) &&
5118 aBuilder
->IsInWillChangeBudget(mFrame
)) {
5126 nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder
* aBuilder
)
5128 if (mMaybePrerender
) {
5129 // TODO We need to make sure that if we use async animation we actually
5130 // pre-render even if we're out of will change budget.
5133 DebugOnly
<bool> prerender
= ShouldPrerenderTransformedContent(aBuilder
, mFrame
, true);
5134 NS_ASSERTION(!prerender
, "Something changed under us!");
5139 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder
* aBuilder
,
5141 bool aLogAnimations
)
5143 // Elements whose transform has been modified recently, or which
5144 // have a compositor-animated transform, can be prerendered. An element
5145 // might have only just had its transform animated in which case
5146 // the ActiveLayerManager may not have been notified yet.
5147 if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame
, eCSSProperty_transform
) &&
5148 (!aFrame
->GetContent() ||
5149 !nsLayoutUtils::HasAnimationsForCompositor(aFrame
->GetContent(),
5150 eCSSProperty_transform
))) {
5151 if (aLogAnimations
) {
5153 message
.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
5154 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5155 aFrame
->GetContent());
5160 nsSize refSize
= aBuilder
->RootReferenceFrame()->GetSize();
5161 // Only prerender if the transformed frame's size is <= the
5162 // reference frame size (~viewport), allowing a 1/8th fuzz factor
5163 // for shadows, borders, etc.
5164 refSize
+= nsSize(refSize
.width
/ 8, refSize
.height
/ 8);
5165 nsSize frameSize
= aFrame
->GetVisualOverflowRectRelativeToSelf().Size();
5166 nscoord maxInAppUnits
= nscoord_MAX
;
5167 if (frameSize
<= refSize
) {
5168 maxInAppUnits
= aFrame
->PresContext()->DevPixelsToAppUnits(4096);
5169 nsRect visual
= aFrame
->GetVisualOverflowRect();
5170 if (visual
.width
<= maxInAppUnits
&& visual
.height
<= maxInAppUnits
) {
5175 if (aLogAnimations
) {
5176 nsRect visual
= aFrame
->GetVisualOverflowRect();
5179 message
.AppendLiteral("Performance warning: Async animation disabled because frame size (");
5180 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize
.width
));
5181 message
.AppendLiteral(", ");
5182 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize
.height
));
5183 message
.AppendLiteral(") is bigger than the viewport (");
5184 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize
.width
));
5185 message
.AppendLiteral(", ");
5186 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize
.height
));
5187 message
.AppendLiteral(") or the visual rectangle (");
5188 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual
.width
));
5189 message
.AppendLiteral(", ");
5190 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual
.height
));
5191 message
.AppendLiteral(") is larger than the max allowable value (");
5192 message
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits
));
5193 message
.Append(')');
5194 AnimationPlayerCollection::LogAsyncAnimationFailure(message
,
5195 aFrame
->GetContent());
5200 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
5201 static bool IsFrameVisible(nsIFrame
* aFrame
, const Matrix4x4
& aMatrix
)
5203 if (aMatrix
.IsSingular()) {
5206 if (aFrame
->StyleDisplay()->mBackfaceVisibility
== NS_STYLE_BACKFACE_VISIBILITY_HIDDEN
&&
5207 aMatrix
.IsBackfaceVisible()) {
5214 nsDisplayTransform::GetTransform()
5216 if (mTransform
.IsIdentity()) {
5217 float scale
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5219 Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame
.x
, scale
),
5220 NSAppUnitsToFloatPixels(mToReferenceFrame
.y
, scale
),
5222 if (mTransformGetter
) {
5223 mTransform
= mTransformGetter(mFrame
, scale
);
5224 mTransform
.ChangeBasis(newOrigin
.x
, newOrigin
.y
, newOrigin
.z
);
5227 * Passing true as the final argument means that we want to shift the
5228 * coordinates to be relative to our reference frame instead of relative
5230 * When we have preserve-3d, our reference frame is already guaranteed
5231 * to be an ancestor of the preserve-3d chain, so we only need to do
5234 mTransform
= ToMatrix4x4(
5235 GetResultingTransformMatrix(mFrame
, ToReferenceFrame(), scale
,
5236 nullptr, nullptr, mFrame
->IsTransformed()));
5243 nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder
* aBuilder
)
5245 return ShouldPrerender(aBuilder
);
5248 already_AddRefed
<Layer
> nsDisplayTransform::BuildLayer(nsDisplayListBuilder
*aBuilder
,
5249 LayerManager
*aManager
,
5250 const ContainerLayerParameters
& aContainerParameters
)
5252 const Matrix4x4
& newTransformMatrix
= GetTransform();
5254 if (mFrame
->StyleDisplay()->mBackfaceVisibility
== NS_STYLE_BACKFACE_VISIBILITY_HIDDEN
&&
5255 newTransformMatrix
.IsBackfaceVisible()) {
5259 uint32_t flags
= ShouldPrerender(aBuilder
) ?
5260 FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS
: 0;
5261 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
5262 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, mStoredList
.GetChildren(),
5263 aContainerParameters
, &newTransformMatrix
, flags
);
5269 // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
5270 // so we never need to explicitely unset this flag.
5271 if (mFrame
->Preserves3D() || mFrame
->Preserves3DChildren()) {
5272 container
->SetContentFlags(container
->GetContentFlags() | Layer::CONTENT_PRESERVE_3D
);
5274 container
->SetContentFlags(container
->GetContentFlags() & ~Layer::CONTENT_PRESERVE_3D
);
5277 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container
, aBuilder
,
5279 eCSSProperty_transform
);
5280 if (ShouldPrerender(aBuilder
)) {
5281 container
->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
5282 /*the value is irrelevant*/nullptr);
5283 container
->SetContentFlags(container
->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM
);
5285 container
->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
5286 container
->SetContentFlags(container
->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM
);
5288 return container
.forget();
5291 nsDisplayItem::LayerState
5292 nsDisplayTransform::GetLayerState(nsDisplayListBuilder
* aBuilder
,
5293 LayerManager
* aManager
,
5294 const ContainerLayerParameters
& aParameters
) {
5295 // If the transform is 3d, or the layer takes part in preserve-3d sorting
5296 // then we *always* want this to be an active layer.
5297 if (!GetTransform().Is2D() || mFrame
->Preserves3D()) {
5298 return LAYER_ACTIVE_FORCE
;
5300 // Here we check if the *post-transform* bounds of this item are big enough
5301 // to justify an active layer.
5302 if (ActiveLayerTracker::IsStyleAnimated(aBuilder
, mFrame
, eCSSProperty_transform
) &&
5303 !IsItemTooSmallForActiveLayer(this))
5304 return LAYER_ACTIVE
;
5305 if (mFrame
->GetContent()) {
5306 if (nsLayoutUtils::HasAnimationsForCompositor(mFrame
->GetContent(),
5307 eCSSProperty_transform
)) {
5308 return LAYER_ACTIVE
;
5312 const nsStyleDisplay
* disp
= mFrame
->StyleDisplay();
5313 if ((disp
->mWillChangeBitField
& NS_STYLE_WILL_CHANGE_TRANSFORM
)) {
5314 return LAYER_ACTIVE
;
5317 // Expect the child display items to have this frame as their animated
5318 // geometry root (since it will be their reference frame). If they have a
5319 // different animated geometry root, we'll make this an active layer so the
5320 // animation can be accelerated.
5321 return RequiredLayerStateForChildren(aBuilder
, aManager
, aParameters
,
5322 *mStoredList
.GetChildren(), Frame());
5325 bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder
*aBuilder
,
5326 nsRegion
*aVisibleRegion
)
5328 /* As we do this, we need to be sure to
5329 * untransform the visible rect, since we want everything that's painting to
5330 * think that it's painting in its original rectangular coordinate space.
5331 * If we can't untransform, take the entire overflow rect */
5332 nsRect untransformedVisibleRect
;
5333 if (ShouldPrerender(aBuilder
) ||
5334 !UntransformVisibleRect(aBuilder
, &untransformedVisibleRect
))
5336 untransformedVisibleRect
= mFrame
->GetVisualOverflowRectRelativeToSelf();
5338 nsRegion untransformedVisible
= untransformedVisibleRect
;
5339 // Call RecomputeVisiblity instead of ComputeVisibility since
5340 // nsDisplayItem::ComputeVisibility should only be called from
5341 // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
5342 mStoredList
.RecomputeVisibility(aBuilder
, &untransformedVisible
);
5350 /* HitTest does some fun stuff with matrix transforms to obtain the answer. */
5351 void nsDisplayTransform::HitTest(nsDisplayListBuilder
*aBuilder
,
5352 const nsRect
& aRect
,
5353 HitTestState
*aState
,
5354 nsTArray
<nsIFrame
*> *aOutFrames
)
5356 /* Here's how this works:
5357 * 1. Get the matrix. If it's singular, abort (clearly we didn't hit
5359 * 2. Invert the matrix.
5360 * 3. Use it to transform the rect into the correct space.
5361 * 4. Pass that rect down through to the list's version of HitTest.
5363 // GetTransform always operates in dev pixels.
5364 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5365 Matrix4x4 matrix
= GetTransform();
5367 if (!IsFrameVisible(mFrame
, matrix
)) {
5371 /* We want to go from transformed-space to regular space.
5372 * Thus we have to invert the matrix, which normally does
5373 * the reverse operation (e.g. regular->transformed)
5376 /* Now, apply the transform and pass it down the channel. */
5378 nsRect resultingRect
;
5379 if (aRect
.width
== 1 && aRect
.height
== 1) {
5380 // Magic width/height indicating we're hit testing a point, not a rect
5381 Point4D point
= matrix
.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect
.x
, factor
),
5382 NSAppUnitsToFloatPixels(aRect
.y
, factor
)));
5383 if (!point
.HasPositiveWCoord()) {
5387 Point point2d
= point
.As2DPoint();
5389 resultingRect
= nsRect(NSFloatPixelsToAppUnits(float(point2d
.x
), factor
),
5390 NSFloatPixelsToAppUnits(float(point2d
.y
), factor
),
5394 Rect
originalRect(NSAppUnitsToFloatPixels(aRect
.x
, factor
),
5395 NSAppUnitsToFloatPixels(aRect
.y
, factor
),
5396 NSAppUnitsToFloatPixels(aRect
.width
, factor
),
5397 NSAppUnitsToFloatPixels(aRect
.height
, factor
));
5399 Rect rect
= matrix
.ProjectRectBounds(originalRect
);
5402 nsRect childBounds
= mStoredList
.GetBounds(aBuilder
, &snap
);
5403 Rect
childGfxBounds(NSAppUnitsToFloatPixels(childBounds
.x
, factor
),
5404 NSAppUnitsToFloatPixels(childBounds
.y
, factor
),
5405 NSAppUnitsToFloatPixels(childBounds
.width
, factor
),
5406 NSAppUnitsToFloatPixels(childBounds
.height
, factor
));
5407 rect
= rect
.Intersect(childGfxBounds
);
5409 resultingRect
= nsRect(NSFloatPixelsToAppUnits(float(rect
.X()), factor
),
5410 NSFloatPixelsToAppUnits(float(rect
.Y()), factor
),
5411 NSFloatPixelsToAppUnits(float(rect
.Width()), factor
),
5412 NSFloatPixelsToAppUnits(float(rect
.Height()), factor
));
5415 if (resultingRect
.IsEmpty()) {
5421 printf("Frame: %p\n", dynamic_cast<void *>(mFrame
));
5422 printf(" Untransformed point: (%f, %f)\n", resultingRect
.X(), resultingRect
.Y());
5423 uint32_t originalFrameCount
= aOutFrames
.Length();
5426 mStoredList
.HitTest(aBuilder
, resultingRect
, aState
, aOutFrames
);
5429 if (originalFrameCount
!= aOutFrames
.Length())
5430 printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
5431 dynamic_cast<void *>(aOutFrames
.ElementAt(0)));
5432 printf("=== end of hit test ===\n");
5438 nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder
* aBuilder
, const nsPoint
& aPoint
)
5440 // GetTransform always operates in dev pixels.
5441 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5442 Matrix4x4 matrix
= GetTransform();
5444 NS_ASSERTION(IsFrameVisible(mFrame
, matrix
), "We can't have hit a frame that isn't visible!");
5446 Matrix4x4 inverse
= matrix
;
5448 Point4D point
= inverse
.ProjectPoint(Point(NSAppUnitsToFloatPixels(aPoint
.x
, factor
),
5449 NSAppUnitsToFloatPixels(aPoint
.y
, factor
)));
5450 NS_ASSERTION(point
.HasPositiveWCoord(), "Why are we trying to get the depth for a point we didn't hit?");
5452 Point point2d
= point
.As2DPoint();
5454 Point3D transformed
= matrix
* Point3D(point2d
.x
, point2d
.y
, 0);
5455 return transformed
.z
;
5458 /* The bounding rectangle for the object is the overflow rectangle translated
5459 * by the reference point.
5461 nsRect
nsDisplayTransform::GetBounds(nsDisplayListBuilder
*aBuilder
, bool* aSnap
)
5463 nsRect untransformedBounds
= MaybePrerender() ?
5464 mFrame
->GetVisualOverflowRectRelativeToSelf() :
5465 mStoredList
.GetBounds(aBuilder
, aSnap
);
5467 // GetTransform always operates in dev pixels.
5468 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5469 return nsLayoutUtils::MatrixTransformRect(untransformedBounds
,
5470 To3DMatrix(GetTransform()),
5474 /* The transform is opaque iff the transform consists solely of scales and
5475 * translations and if the underlying content is opaque. Thus if the transform
5482 * We need b and c to be zero.
5484 * We also need to check whether the underlying opaque content completely fills
5485 * our visible rect. We use UntransformRect which expands to the axis-aligned
5486 * bounding rect, but that's OK since if
5487 * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
5488 * certainly contains the actual (non-axis-aligned) untransformed rect.
5490 nsRegion
nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder
*aBuilder
,
5494 nsRect untransformedVisible
;
5495 // If we're going to prerender all our content, pretend like we
5496 // don't have opqaue content so that everything under us is rendered
5497 // as well. That will increase graphics memory usage if our frame
5498 // covers the entire window, but it allows our transform to be
5499 // updated extremely cheaply, without invalidating any other
5501 if (MaybePrerender() ||
5502 !UntransformVisibleRect(aBuilder
, &untransformedVisible
)) {
5506 const Matrix4x4
& matrix
= GetTransform();
5511 if (matrix
.Is2D(&matrix2d
) &&
5512 matrix2d
.PreservesAxisAlignedRectangles() &&
5513 mStoredList
.GetOpaqueRegion(aBuilder
, &tmpSnap
).Contains(untransformedVisible
)) {
5514 result
= mVisibleRect
.Intersect(GetBounds(aBuilder
, &tmpSnap
));
5519 /* The transform is uniform if it fills the entire bounding rect and the
5520 * wrapped list is uniform. See GetOpaqueRegion for discussion of why this
5523 bool nsDisplayTransform::IsUniform(nsDisplayListBuilder
*aBuilder
, nscolor
* aColor
)
5525 nsRect untransformedVisible
;
5526 if (!UntransformVisibleRect(aBuilder
, &untransformedVisible
)) {
5529 const Matrix4x4
& matrix
= GetTransform();
5532 return matrix
.Is2D(&matrix2d
) &&
5533 matrix2d
.PreservesAxisAlignedRectangles() &&
5534 mStoredList
.GetVisibleRect().Contains(untransformedVisible
) &&
5535 mStoredList
.IsUniform(aBuilder
, aColor
);
5538 /* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
5539 * share the same underlying content. Otherwise, doing so results in graphical
5542 #ifndef UNIFIED_CONTINUATIONS
5545 nsDisplayTransform::TryMerge(nsDisplayListBuilder
*aBuilder
,
5546 nsDisplayItem
*aItem
)
5554 nsDisplayTransform::TryMerge(nsDisplayListBuilder
*aBuilder
,
5555 nsDisplayItem
*aItem
)
5557 NS_PRECONDITION(aItem
, "Why did you try merging with a null item?");
5558 NS_PRECONDITION(aBuilder
, "Why did you try merging with a null builder?");
5560 /* Make sure that we're dealing with two transforms. */
5561 if (aItem
->GetType() != TYPE_TRANSFORM
)
5564 /* Check to see that both frames are part of the same content. */
5565 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
5568 if (aItem
->GetClip() != GetClip())
5571 /* Now, move everything over to this frame and signal that
5574 mStoredList
.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform
*>(aItem
)->mStoredList
);
5580 /* TransformRect takes in as parameters a rectangle (in app space) and returns
5581 * the smallest rectangle (in app space) containing the transformed image of
5582 * that rectangle. That is, it takes the four corners of the rectangle,
5583 * transforms them according to the matrix associated with the specified frame,
5584 * then returns the smallest rectangle containing the four transformed points.
5586 * @param aUntransformedBounds The rectangle (in app units) to transform.
5587 * @param aFrame The frame whose transformation should be applied.
5588 * @param aOrigin The delta from the frame origin to the coordinate space origin
5589 * @param aBoundsOverride (optional) Force the frame bounds to be the
5591 * @return The smallest rectangle containing the image of the transformed
5594 nsRect
nsDisplayTransform::TransformRect(const nsRect
&aUntransformedBounds
,
5595 const nsIFrame
* aFrame
,
5596 const nsPoint
&aOrigin
,
5597 const nsRect
* aBoundsOverride
)
5599 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5601 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5602 return nsLayoutUtils::MatrixTransformRect
5603 (aUntransformedBounds
,
5604 GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, aBoundsOverride
),
5608 nsRect
nsDisplayTransform::TransformRectOut(const nsRect
&aUntransformedBounds
,
5609 const nsIFrame
* aFrame
,
5610 const nsPoint
&aOrigin
,
5611 const nsRect
* aBoundsOverride
)
5613 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5615 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5616 return nsLayoutUtils::MatrixTransformRectOut
5617 (aUntransformedBounds
,
5618 GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, aBoundsOverride
),
5622 bool nsDisplayTransform::UntransformRect(const nsRect
&aTransformedBounds
,
5623 const nsRect
&aChildBounds
,
5624 const nsIFrame
* aFrame
,
5625 const nsPoint
&aOrigin
,
5628 NS_PRECONDITION(aFrame
, "Can't take the transform based on a null frame!");
5630 float factor
= aFrame
->PresContext()->AppUnitsPerDevPixel();
5632 gfx3DMatrix transform
= GetResultingTransformMatrix(aFrame
, aOrigin
, factor
, nullptr);
5633 if (transform
.IsSingular()) {
5637 Rect
result(NSAppUnitsToFloatPixels(aTransformedBounds
.x
, factor
),
5638 NSAppUnitsToFloatPixels(aTransformedBounds
.y
, factor
),
5639 NSAppUnitsToFloatPixels(aTransformedBounds
.width
, factor
),
5640 NSAppUnitsToFloatPixels(aTransformedBounds
.height
, factor
));
5642 Rect
childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds
.x
, factor
),
5643 NSAppUnitsToFloatPixels(aChildBounds
.y
, factor
),
5644 NSAppUnitsToFloatPixels(aChildBounds
.width
, factor
),
5645 NSAppUnitsToFloatPixels(aChildBounds
.height
, factor
));
5647 result
= ToMatrix4x4(transform
.Inverse()).ProjectRectBounds(result
);
5648 result
= result
.Intersect(childGfxBounds
);
5649 *aOutRect
= nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result
), factor
);
5653 bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder
* aBuilder
,
5656 const gfx3DMatrix
& matrix
= To3DMatrix(GetTransform());
5657 if (matrix
.IsSingular())
5660 // GetTransform always operates in dev pixels.
5661 float factor
= mFrame
->PresContext()->AppUnitsPerDevPixel();
5662 Rect
result(NSAppUnitsToFloatPixels(mVisibleRect
.x
, factor
),
5663 NSAppUnitsToFloatPixels(mVisibleRect
.y
, factor
),
5664 NSAppUnitsToFloatPixels(mVisibleRect
.width
, factor
),
5665 NSAppUnitsToFloatPixels(mVisibleRect
.height
, factor
));
5668 nsRect childBounds
= mStoredList
.GetBounds(aBuilder
, &snap
);
5669 Rect
childGfxBounds(NSAppUnitsToFloatPixels(childBounds
.x
, factor
),
5670 NSAppUnitsToFloatPixels(childBounds
.y
, factor
),
5671 NSAppUnitsToFloatPixels(childBounds
.width
, factor
),
5672 NSAppUnitsToFloatPixels(childBounds
.height
, factor
));
5674 /* We want to untransform the matrix, so invert the transformation first! */
5675 result
= ToMatrix4x4(matrix
.Inverse()).ProjectRectBounds(result
);
5676 result
= result
.Intersect(childGfxBounds
);
5678 *aOutRect
= nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result
), factor
);
5683 #ifdef MOZ_DUMP_PAINTING
5685 nsDisplayTransform::WriteDebugInfo(std::stringstream
& aStream
)
5687 AppendToString(aStream
, GetTransform());
5691 nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder
* aBuilder
,
5692 nsIFrame
* aFrame
, nsDisplayList
* aList
)
5693 : nsDisplayWrapList(aBuilder
, aFrame
, aList
),
5694 mEffectsBounds(aFrame
->GetVisualOverflowRectRelativeToSelf())
5696 MOZ_COUNT_CTOR(nsDisplaySVGEffects
);
5699 #ifdef NS_BUILD_REFCNT_LOGGING
5700 nsDisplaySVGEffects::~nsDisplaySVGEffects()
5702 MOZ_COUNT_DTOR(nsDisplaySVGEffects
);
5706 nsDisplayVR::nsDisplayVR(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
,
5707 nsDisplayList
* aList
, mozilla::gfx::VRHMDInfo
* aHMD
)
5708 : nsDisplayOwnLayer(aBuilder
, aFrame
, aList
)
5713 already_AddRefed
<Layer
>
5714 nsDisplayVR::BuildLayer(nsDisplayListBuilder
* aBuilder
,
5715 LayerManager
* aManager
,
5716 const ContainerLayerParameters
& aContainerParameters
)
5718 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
5719 uint32_t flags
= FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS
;
5720 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
5721 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
5722 newContainerParameters
, nullptr, flags
);
5724 container
->SetVRHMDInfo(mHMD
);
5725 container
->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
5726 /*the value is irrelevant*/nullptr);
5728 return container
.forget();
5730 nsRegion
nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder
* aBuilder
,
5738 nsDisplaySVGEffects::HitTest(nsDisplayListBuilder
* aBuilder
, const nsRect
& aRect
,
5739 HitTestState
* aState
, nsTArray
<nsIFrame
*> *aOutFrames
)
5741 nsPoint
rectCenter(aRect
.x
+ aRect
.width
/ 2, aRect
.y
+ aRect
.height
/ 2);
5742 if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame
,
5743 rectCenter
- ToReferenceFrame())) {
5744 mList
.HitTest(aBuilder
, aRect
, aState
, aOutFrames
);
5749 nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder
* aBuilder
,
5750 nsRenderingContext
* aCtx
,
5751 LayerManager
* aManager
)
5753 nsSVGIntegrationUtils::PaintFramesWithEffects(*aCtx
->ThebesContext(), mFrame
,
5755 aBuilder
, aManager
);
5759 nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder
* aBuilder
,
5760 LayerManager
* aManager
,
5761 const ContainerLayerParameters
& aParameters
)
5763 return LAYER_SVG_EFFECTS
;
5766 already_AddRefed
<Layer
>
5767 nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder
* aBuilder
,
5768 LayerManager
* aManager
,
5769 const ContainerLayerParameters
& aContainerParameters
)
5771 const nsIContent
* content
= mFrame
->GetContent();
5772 bool hasSVGLayout
= (mFrame
->GetStateBits() & NS_FRAME_SVG_LAYOUT
);
5774 nsISVGChildFrame
*svgChildFrame
= do_QueryFrame(mFrame
);
5775 if (!svgChildFrame
|| !mFrame
->GetContent()->IsSVG()) {
5776 NS_ASSERTION(false, "why?");
5779 if (!static_cast<const nsSVGElement
*>(content
)->HasValidDimensions()) {
5780 return nullptr; // The SVG spec says not to draw filters for this
5784 float opacity
= mFrame
->StyleDisplay()->mOpacity
;
5785 if (opacity
== 0.0f
)
5788 nsIFrame
* firstFrame
=
5789 nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame
);
5790 nsSVGEffects::EffectProperties effectProperties
=
5791 nsSVGEffects::GetEffectProperties(firstFrame
);
5793 bool isOK
= effectProperties
.HasNoFilterOrHasValidFilter();
5794 effectProperties
.GetClipPathFrame(&isOK
);
5795 effectProperties
.GetMaskFrame(&isOK
);
5801 ContainerLayerParameters newContainerParameters
= aContainerParameters
;
5802 if (effectProperties
.HasValidFilter()) {
5803 newContainerParameters
.mDisableSubpixelAntialiasingInDescendants
= true;
5806 nsRefPtr
<ContainerLayer
> container
= aManager
->GetLayerBuilder()->
5807 BuildContainerLayerFor(aBuilder
, aManager
, mFrame
, this, &mList
,
5808 newContainerParameters
, nullptr);
5810 return container
.forget();
5813 bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder
* aBuilder
,
5814 nsRegion
* aVisibleRegion
) {
5815 nsPoint offset
= ToReferenceFrame();
5817 nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame
,
5818 mVisibleRect
- offset
) +
5821 // Our children may be made translucent or arbitrarily deformed so we should
5822 // not allow them to subtract area from aVisibleRegion.
5823 nsRegion
childrenVisible(dirtyRect
);
5824 nsRect r
= dirtyRect
.Intersect(mList
.GetBounds(aBuilder
));
5825 mList
.ComputeVisibilityForSublist(aBuilder
, &childrenVisible
, r
);
5829 bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder
* aBuilder
, nsDisplayItem
* aItem
)
5831 if (aItem
->GetType() != TYPE_SVG_EFFECTS
)
5833 // items for the same content element should be merged into a single
5834 // compositing group
5835 // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
5836 if (aItem
->Frame()->GetContent() != mFrame
->GetContent())
5838 if (aItem
->GetClip() != GetClip())
5840 nsDisplaySVGEffects
* other
= static_cast<nsDisplaySVGEffects
*>(aItem
);
5841 MergeFromTrackingMergedFrames(other
);
5842 mEffectsBounds
.UnionRect(mEffectsBounds
,
5843 other
->mEffectsBounds
+ other
->mFrame
->GetOffsetTo(mFrame
));
5848 nsDisplaySVGEffects::BBoxInUserSpace() const
5850 return nsSVGUtils::GetBBox(mFrame
);
5854 nsDisplaySVGEffects::UserSpaceOffset() const
5856 return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame
);
5860 nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder
* aBuilder
,
5861 const nsDisplayItemGeometry
* aGeometry
,
5862 nsRegion
* aInvalidRegion
)
5864 const nsDisplaySVGEffectsGeometry
* geometry
=
5865 static_cast<const nsDisplaySVGEffectsGeometry
*>(aGeometry
);
5867 nsRect bounds
= GetBounds(aBuilder
, &snap
);
5868 if (geometry
->mFrameOffsetToReferenceFrame
!= ToReferenceFrame() ||
5869 geometry
->mUserSpaceOffset
!= UserSpaceOffset() ||
5870 !geometry
->mBBox
.IsEqualInterior(BBoxInUserSpace())) {
5871 // Filter and mask output can depend on the location of the frame's user
5872 // space and on the frame's BBox. We need to invalidate if either of these
5873 // change relative to the reference frame.
5874 // Invalidations from our inactive layer manager are not enough to catch
5875 // some of these cases because filters can produce output even if there's
5876 // nothing in the filter input.
5877 aInvalidRegion
->Or(bounds
, geometry
->mBounds
);
5881 #ifdef MOZ_DUMP_PAINTING
5883 nsDisplaySVGEffects::PrintEffects(nsACString
& aTo
)
5885 nsIFrame
* firstFrame
=
5886 nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame
);
5887 nsSVGEffects::EffectProperties effectProperties
=
5888 nsSVGEffects::GetEffectProperties(firstFrame
);
5890 nsSVGClipPathFrame
*clipPathFrame
= effectProperties
.GetClipPathFrame(&isOK
);
5892 aTo
+= " effects=(";
5893 if (mFrame
->StyleDisplay()->mOpacity
!= 1.0f
) {
5895 aTo
+= nsPrintfCString("opacity(%f)", mFrame
->StyleDisplay()->mOpacity
);
5897 if (clipPathFrame
) {
5901 aTo
+= nsPrintfCString("clip(%s)", clipPathFrame
->IsTrivial() ? "trivial" : "non-trivial");
5904 if (effectProperties
.HasValidFilter()) {
5911 if (effectProperties
.GetMaskFrame(&isOK
)) {