зеркало из https://github.com/mozilla/gecko-dev.git
Bug 745485. Optimize positioning offset changes whenever the computed size does not change. r=dholbert
--HG-- extra : rebase_source : 16388d3cb0c6ee9acc1416ca0d27b2a53b0062ee
This commit is contained in:
Родитель
ca9efa851c
Коммит
9e62a53158
|
@ -386,59 +386,60 @@ RestyleManager::RecomputePosition(nsIFrame* aFrame)
|
|||
return true;
|
||||
}
|
||||
|
||||
// For absolute positioning, the width can potentially change if width is
|
||||
// auto and either of left or right are not. The height can also potentially
|
||||
// change if height is auto and either of top or bottom are not. In these
|
||||
// cases we fall back to a reflow, and in all other cases, we attempt to
|
||||
// move the frame here.
|
||||
// Note that it is possible for the dimensions to not change in the above
|
||||
// cases, so we should be a little smarter here and only fall back to reflow
|
||||
// when the dimensions will really change (bug 745485).
|
||||
const nsStylePosition* position = aFrame->StylePosition();
|
||||
if (position->mWidth.GetUnit() != eStyleUnit_Auto &&
|
||||
position->mHeight.GetUnit() != eStyleUnit_Auto) {
|
||||
// For the absolute positioning case, set up a fake HTML reflow state for
|
||||
// the frame, and then get the offsets from it.
|
||||
nsRefPtr<nsRenderingContext> rc = aFrame->PresContext()->GetPresShell()->
|
||||
GetReferenceRenderingContext();
|
||||
// For the absolute positioning case, set up a fake HTML reflow state for
|
||||
// the frame, and then get the offsets and size from it. If the frame's size
|
||||
// doesn't need to change, we can simply update the frame position. Otherwise
|
||||
// we fall back to a reflow.
|
||||
nsRefPtr<nsRenderingContext> rc = aFrame->PresContext()->GetPresShell()->
|
||||
GetReferenceRenderingContext();
|
||||
|
||||
// Construct a bogus parent reflow state so that there's a usable
|
||||
// containing block reflow state.
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
nsSize parentSize = parentFrame->GetSize();
|
||||
// Construct a bogus parent reflow state so that there's a usable
|
||||
// containing block reflow state.
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
nsSize parentSize = parentFrame->GetSize();
|
||||
|
||||
nsFrameState savedState = parentFrame->GetStateBits();
|
||||
nsHTMLReflowState parentReflowState(aFrame->PresContext(), parentFrame,
|
||||
rc, parentSize);
|
||||
parentFrame->RemoveStateBits(~nsFrameState(0));
|
||||
parentFrame->AddStateBits(savedState);
|
||||
nsFrameState savedState = parentFrame->GetStateBits();
|
||||
nsHTMLReflowState parentReflowState(aFrame->PresContext(), parentFrame,
|
||||
rc, parentSize);
|
||||
parentFrame->RemoveStateBits(~nsFrameState(0));
|
||||
parentFrame->AddStateBits(savedState);
|
||||
|
||||
NS_WARN_IF_FALSE(parentSize.width != NS_INTRINSICSIZE &&
|
||||
parentSize.height != NS_INTRINSICSIZE,
|
||||
"parentSize should be valid");
|
||||
parentReflowState.SetComputedWidth(std::max(parentSize.width, 0));
|
||||
parentReflowState.SetComputedHeight(std::max(parentSize.height, 0));
|
||||
parentReflowState.mComputedMargin.SizeTo(0, 0, 0, 0);
|
||||
parentSize.height = NS_AUTOHEIGHT;
|
||||
NS_WARN_IF_FALSE(parentSize.width != NS_INTRINSICSIZE &&
|
||||
parentSize.height != NS_INTRINSICSIZE,
|
||||
"parentSize should be valid");
|
||||
parentReflowState.SetComputedWidth(std::max(parentSize.width, 0));
|
||||
parentReflowState.SetComputedHeight(std::max(parentSize.height, 0));
|
||||
parentReflowState.mComputedMargin.SizeTo(0, 0, 0, 0);
|
||||
|
||||
parentReflowState.mComputedPadding = parentFrame->GetUsedPadding();
|
||||
parentReflowState.mComputedBorderPadding =
|
||||
parentFrame->GetUsedBorderAndPadding();
|
||||
|
||||
nsSize availSize(parentSize.width, NS_INTRINSICSIZE);
|
||||
|
||||
nsSize size = aFrame->GetSize();
|
||||
ViewportFrame* viewport = do_QueryFrame(parentFrame);
|
||||
nsSize cbSize = viewport ?
|
||||
viewport->AdjustReflowStateAsContainingBlock(&parentReflowState).Size()
|
||||
: aFrame->GetContainingBlock()->GetSize();
|
||||
const nsMargin& parentBorder =
|
||||
parentReflowState.mStyleBorder->GetComputedBorder();
|
||||
cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
|
||||
nsHTMLReflowState reflowState(aFrame->PresContext(), parentReflowState,
|
||||
aFrame, availSize, cbSize.width,
|
||||
cbSize.height);
|
||||
parentReflowState.mComputedPadding = parentFrame->GetUsedPadding();
|
||||
parentReflowState.mComputedBorderPadding =
|
||||
parentFrame->GetUsedBorderAndPadding();
|
||||
nsSize availSize(parentSize.width, NS_INTRINSICSIZE);
|
||||
|
||||
ViewportFrame* viewport = do_QueryFrame(parentFrame);
|
||||
nsSize cbSize = viewport ?
|
||||
viewport->AdjustReflowStateAsContainingBlock(&parentReflowState).Size()
|
||||
: aFrame->GetContainingBlock()->GetSize();
|
||||
const nsMargin& parentBorder =
|
||||
parentReflowState.mStyleBorder->GetComputedBorder();
|
||||
cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
|
||||
nsHTMLReflowState reflowState(aFrame->PresContext(), parentReflowState,
|
||||
aFrame, availSize, cbSize.width,
|
||||
cbSize.height);
|
||||
nsSize computedSize(reflowState.ComputedWidth(), reflowState.ComputedHeight());
|
||||
computedSize.width += reflowState.mComputedBorderPadding.LeftRight();
|
||||
if (computedSize.height != NS_INTRINSICSIZE) {
|
||||
computedSize.height += reflowState.mComputedBorderPadding.TopBottom();
|
||||
}
|
||||
nsSize size = aFrame->GetSize();
|
||||
// The RecomputePosition hint is not used if any offset changed between auto
|
||||
// and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
|
||||
// element height will be its intrinsic height, and since 'top' and 'bottom''s
|
||||
// auto-ness hasn't changed, the old height must also be its intrinsic
|
||||
// height, which we can assume hasn't changed (or reflow would have
|
||||
// been triggered).
|
||||
if (computedSize.width == size.width &&
|
||||
(computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
|
||||
// If we're solving for 'left' or 'top', then compute it here, in order to
|
||||
// match the reflow code path.
|
||||
if (NS_AUTOOFFSET == reflowState.mComputedOffsets.left) {
|
||||
|
|
|
@ -1278,6 +1278,18 @@ nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
|
|||
memcpy((nsStylePosition*)this, &aSource, sizeof(nsStylePosition));
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
|
||||
{
|
||||
NS_FOR_CSS_SIDES(side) {
|
||||
if ((aSides1.GetUnit(side) == eStyleUnit_Auto) !=
|
||||
(aSides2.GetUnit(side) == eStyleUnit_Auto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
|
||||
{
|
||||
nsChangeHint hint =
|
||||
|
@ -1346,9 +1358,15 @@ nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) cons
|
|||
// Note that it is possible that we'll need to reflow when processing
|
||||
// restyles, but we don't have enough information to make a good decision
|
||||
// right now.
|
||||
// Don't try to handle changes between "auto" and non-auto efficiently;
|
||||
// that's tricky to do and will hardly ever be able to avoid a reflow.
|
||||
if (mOffset != aOther.mOffset) {
|
||||
NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition |
|
||||
nsChangeHint_UpdateOverflow));
|
||||
if (IsAutonessEqual(mOffset, aOther.mOffset)) {
|
||||
NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition |
|
||||
nsChangeHint_UpdateOverflow));
|
||||
} else {
|
||||
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
||||
}
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче