зеркало из https://github.com/mozilla/gecko-dev.git
Bug 584494 - Regression: Transform rotation testcase performs significantly worse - r=dbaron
This commit is contained in:
Родитель
f629b6152b
Коммит
8c37d3bfef
|
@ -494,14 +494,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
|
|||
}
|
||||
|
||||
if (oldRect.TopLeft() != rect.TopLeft() ||
|
||||
(aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
|
||||
(kidDesiredSize.mOverflowArea + rect.TopLeft() != oldOverflowRect &&
|
||||
(kidDesiredSize.mOverflowArea + rect.TopLeft() != rect || oldRect != oldOverflowRect))) {
|
||||
// The frame moved; we have to invalidate the whole frame
|
||||
// because the children may have moved after they were reflowed
|
||||
// We also have to invalidate when we have overflow and the overflow
|
||||
// changes because the change might be caused by clipping
|
||||
// XXX This could be optimized in some cases, especially clipping changes
|
||||
(aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
// The frame moved
|
||||
aKidFrame->GetParent()->Invalidate(oldOverflowRect);
|
||||
aKidFrame->GetParent()->Invalidate(kidDesiredSize.mOverflowArea +
|
||||
rect.TopLeft());
|
||||
|
|
|
@ -520,17 +520,21 @@ nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
|
|||
PRUint32 aFlags)
|
||||
{
|
||||
// Optimize by suppressing invalidation of areas that are clipped out
|
||||
// with CSS 'clip'.
|
||||
const nsStyleDisplay* disp = GetStyleDisplay();
|
||||
nsRect absPosClipRect;
|
||||
if (GetAbsPosClipRect(disp, &absPosClipRect, GetSize())) {
|
||||
// Restrict the invalidated area to abs-pos clip rect
|
||||
// abs-pos clipping clips everything in the frame
|
||||
nsRect r;
|
||||
if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) {
|
||||
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
|
||||
// with CSS 'clip'. Don't suppress invalidation of *this* frame directly,
|
||||
// because when 'clip' shrinks we need to invalidate this frame and
|
||||
// be able to invalidate areas outside the 'clip'.
|
||||
if (aForChild) {
|
||||
const nsStyleDisplay* disp = GetStyleDisplay();
|
||||
nsRect absPosClipRect;
|
||||
if (GetAbsPosClipRect(disp, &absPosClipRect, GetSize())) {
|
||||
// Restrict the invalidated area to abs-pos clip rect
|
||||
// abs-pos clipping clips everything in the frame
|
||||
nsRect r;
|
||||
if (r.IntersectRect(aDamageRect, absPosClipRect - nsPoint(aX, aY))) {
|
||||
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
|
||||
|
|
|
@ -5866,26 +5866,6 @@ IsInlineFrame(nsIFrame *aFrame)
|
|||
type == nsGkAtoms::positionedInlineFrame;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsIFrame::GetAdditionalOverflow(const nsRect& aOverflowArea,
|
||||
const nsSize& aNewSize,
|
||||
PRBool* aHasOutlineOrEffects)
|
||||
{
|
||||
nsRect overflowRect =
|
||||
ComputeOutlineAndEffectsRect(this, aHasOutlineOrEffects,
|
||||
aOverflowArea, aNewSize, PR_TRUE);
|
||||
|
||||
// Absolute position clipping
|
||||
PRBool hasAbsPosClip;
|
||||
nsRect absPosClipRect;
|
||||
hasAbsPosClip = GetAbsPosClipRect(GetStyleDisplay(), &absPosClipRect, aNewSize);
|
||||
if (hasAbsPosClip) {
|
||||
overflowRect.IntersectRect(overflowRect, absPosClipRect);
|
||||
}
|
||||
|
||||
return overflowRect;
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
||||
{
|
||||
|
@ -5931,8 +5911,20 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
|||
}
|
||||
|
||||
PRBool hasOutlineOrEffects;
|
||||
*aOverflowArea = GetAdditionalOverflow(*aOverflowArea, aNewSize,
|
||||
&hasOutlineOrEffects);
|
||||
*aOverflowArea =
|
||||
ComputeOutlineAndEffectsRect(this, &hasOutlineOrEffects,
|
||||
*aOverflowArea, aNewSize, PR_TRUE);
|
||||
|
||||
// Absolute position clipping
|
||||
PRBool didHaveAbsPosClip = (GetStateBits() & NS_FRAME_HAS_CLIP) != 0;
|
||||
nsRect absPosClipRect;
|
||||
PRBool hasAbsPosClip = GetAbsPosClipRect(disp, &absPosClipRect, aNewSize);
|
||||
if (hasAbsPosClip) {
|
||||
aOverflowArea->IntersectRect(*aOverflowArea, absPosClipRect);
|
||||
AddStateBits(NS_FRAME_HAS_CLIP);
|
||||
} else {
|
||||
RemoveStateBits(NS_FRAME_HAS_CLIP);
|
||||
}
|
||||
|
||||
/* If we're transformed, transform the overflow rect by the current transformation. */
|
||||
PRBool hasTransform = IsTransformed();
|
||||
|
@ -5962,19 +5954,46 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
|||
}
|
||||
}
|
||||
|
||||
if (overflowChanged && (hasOutlineOrEffects || hasTransform)) {
|
||||
// When there's an outline or box-shadow or SVG effects or transform,
|
||||
// changes to those styles might require repainting of the old and new
|
||||
// overflow areas. Repainting of the old overflow area is handled in
|
||||
// nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
|
||||
// to nsChangeHint_RepaintFrame. Since the new overflow area is not
|
||||
// known at that time, we have to handle it here.
|
||||
// If the overflow area hasn't changed, then we don't have to do
|
||||
// anything here since repainting the old overflow area was enough.
|
||||
// If there is no outline or other effects now, then we don't have
|
||||
// to do anything here since removing those styles can't require
|
||||
// repainting of areas that weren't in the old overflow area.
|
||||
Invalidate(*aOverflowArea);
|
||||
if (overflowChanged) {
|
||||
if (hasOutlineOrEffects) {
|
||||
// When there's an outline or box-shadow or SVG effects,
|
||||
// changes to those styles might require repainting of the old and new
|
||||
// overflow areas. Repainting of the old overflow area is handled in
|
||||
// nsCSSFrameConstructor::DoApplyRenderingChangeToTree in response
|
||||
// to nsChangeHint_RepaintFrame. Since the new overflow area is not
|
||||
// known at that time, we have to handle it here.
|
||||
// If the overflow area hasn't changed, then we don't have to do
|
||||
// anything here since repainting the old overflow area was enough.
|
||||
// If there is no outline or other effects now, then we don't have
|
||||
// to do anything here since removing those styles can't require
|
||||
// repainting of areas that weren't in the old overflow area.
|
||||
Invalidate(*aOverflowArea);
|
||||
} else if (hasAbsPosClip || didHaveAbsPosClip) {
|
||||
// If we are (or were) clipped by the 'clip' property, and our
|
||||
// overflow area changes, it might be because the clipping changed.
|
||||
// The nsChangeHint_RepaintFrame for the style change will only
|
||||
// repaint the old overflow area, so if the overflow area has
|
||||
// changed (in particular, if it grows), we have to repaint the
|
||||
// new area here.
|
||||
Invalidate(*aOverflowArea);
|
||||
} else if (hasTransform) {
|
||||
// When there's a transform, changes to that style might require
|
||||
// repainting of the old and new overflow areas in the widget.
|
||||
// Repainting of the frame itself will not be required if there's
|
||||
// a retained layer, so we can call InvalidateLayer here
|
||||
// which will avoid repainting ThebesLayers if possible.
|
||||
// nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
|
||||
// the old overflow area in the widget in response to
|
||||
// nsChangeHint_UpdateTransformLayer. But since the new overflow
|
||||
// area is not known at that time, we have to handle it here.
|
||||
// If the overflow area hasn't changed, then it doesn't matter that
|
||||
// we didn't reach here since repainting the old overflow area was enough.
|
||||
// If there is no transform now, then the container layer for
|
||||
// the transform will go away and the frame contents will change
|
||||
// ThebesLayers, forcing it to be invalidated, so it doesn't matter
|
||||
// that we didn't reach here.
|
||||
InvalidateLayer(*aOverflowArea, nsDisplayItem::TYPE_TRANSFORM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -266,6 +266,9 @@ typedef PRUint64 nsFrameState;
|
|||
// NS_FRAME_HAS_CONTAINER_LAYER bit.
|
||||
#define NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT NS_FRAME_STATE_BIT(34)
|
||||
|
||||
// Frame's overflow area was clipped by the 'clip' property.
|
||||
#define NS_FRAME_HAS_CLIP NS_FRAME_STATE_BIT(35)
|
||||
|
||||
// The lower 20 bits and upper 32 bits of the frame state are reserved
|
||||
// by this API.
|
||||
#define NS_FRAME_RESERVED ~NS_FRAME_IMPL_RESERVED
|
||||
|
@ -2519,13 +2522,6 @@ protected:
|
|||
*/
|
||||
void InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags);
|
||||
|
||||
/**
|
||||
* Gets the overflow area for any properties that are common to all types of frames
|
||||
* e.g. outlines.
|
||||
*/
|
||||
nsRect GetAdditionalOverflow(const nsRect& aOverflowArea, const nsSize& aNewSize,
|
||||
PRBool* aHasOutlineOrEffects);
|
||||
|
||||
/**
|
||||
* Can we stop inside this frame when we're skipping non-rendered whitespace?
|
||||
* @param aForward [in] Are we moving forward (or backward) in content order.
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="position:absolute; left:10px; top:10px; width:100px; height:100px; background:lime">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body>
|
||||
<div id="d" style="position:absolute; left:10px; top:10px; width:10px; height:10px; clip:rect(auto,100px,50px,auto)">
|
||||
<div style="width:100px; height:100px; background:lime;"></div>
|
||||
</div>
|
||||
<script>
|
||||
var d = document.getElementById("d");
|
||||
function doTest() {
|
||||
d.style.clip = "";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body>
|
||||
<div id="d" style="position:absolute; left:10px; top:10px; width:10px; height:10px;">
|
||||
<div style="width:100px; height:100px; background:lime;"></div>
|
||||
</div>
|
||||
<script>
|
||||
var d = document.getElementById("d");
|
||||
function doTest() {
|
||||
d.style.clip = "rect(0,0,0,0)";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -725,6 +725,8 @@ random == 387876-2.html 387876-2-ref.html # bug 471630
|
|||
== 388367-1.html about:blank
|
||||
== 388980-1.html 388980-1-ref.html
|
||||
== 389074-1.html 389074-1-ref.html
|
||||
== 389224-1.html 389224-1-ref.html
|
||||
== 389224-2.html about:blank
|
||||
== 389468-1.html 389468-1-ref.html
|
||||
== 389623-1.html 389623-1-ref.html
|
||||
== 389636-1.html about:blank # assertion test
|
||||
|
|
|
@ -1983,16 +1983,13 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|
|||
nsChangeHint_NeedDirtyReflow)));
|
||||
}
|
||||
|
||||
if (mClipFlags != aOther.mClipFlags || mClip != aOther.mClip) {
|
||||
// FIXME: Bug 507764. Could we use a more precise hint here?
|
||||
NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
|
||||
}
|
||||
// XXX the following is conservative, for now: changing float breaking shouldn't
|
||||
// necessarily require a repaint, reflow should suffice.
|
||||
if (mBreakType != aOther.mBreakType
|
||||
|| mBreakBefore != aOther.mBreakBefore
|
||||
|| mBreakAfter != aOther.mBreakAfter
|
||||
|| mAppearance != aOther.mAppearance)
|
||||
|| mAppearance != aOther.mAppearance
|
||||
|| mClipFlags != aOther.mClipFlags || mClip != aOther.mClip)
|
||||
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame));
|
||||
|
||||
if (mOpacity != aOther.mOpacity) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче