Bug 928403 - optimize nsFrameConstructorState::ProcessFrameInsertions, r=roc

--HG--
rename : testing/mochitest/b2g-debug.json => testing/mochitest/b2g.json
extra : rebase_source : c45d39f4b50f248b28a6ebfb50128084bb59ebe4
This commit is contained in:
Olli Pettay 2013-10-22 15:06:01 +03:00
parent 6e507300dc
commit 2d19654cb3
3 changed files with 102 additions and 22 deletions

View File

@ -1241,23 +1241,67 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems,
// so this will make out-of-flows respect the ordering of placeholders,
// which is great because it takes care of anonymous content.
nsIFrame* firstNewFrame = aFrameItems.FirstChild();
// Cache the ancestor chain so that we can reuse it if needed.
nsAutoTArray<nsIFrame*, 20> firstNewFrameAncestors;
nsIFrame* notCommonAncestor = nullptr;
if (lastChild) {
notCommonAncestor = nsLayoutUtils::FillAncestors(firstNewFrame,
containingBlock,
&firstNewFrameAncestors);
}
if (!lastChild ||
nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame, containingBlock) < 0) {
nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
firstNewFrameAncestors,
notCommonAncestor ?
containingBlock : nullptr) < 0) {
// no lastChild, or lastChild comes before the new children, so just append
rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
} else {
// try the other children
nsIFrame* insertionPoint = nullptr;
// Try the other children. First collect them to an array so that a
// reasonable fast binary search can be used to find the insertion point.
nsAutoTArray<nsIFrame*, 128> children;
for (nsIFrame* f = childList.FirstChild(); f != lastChild;
f = f->GetNextSibling()) {
children.AppendElement(f);
}
nsIFrame* insertionPoint = nullptr;
int32_t imin = 0;
int32_t max = children.Length();
while (max > imin) {
int32_t imid = imin + ((max - imin) / 2);
nsIFrame* f = children[imid];
int32_t compare =
nsLayoutUtils::CompareTreePosition(f, firstNewFrame, containingBlock);
nsLayoutUtils::CompareTreePosition(f, firstNewFrame, firstNewFrameAncestors,
notCommonAncestor ? containingBlock : nullptr);
if (compare > 0) {
// f comes after the new children, so stop here and insert after
// the previous frame
// f is after the new frame.
max = imid;
insertionPoint = imid > 0 ? children[imid - 1] : nullptr;
} else if (compare < 0) {
// f is before the new frame.
imin = imid + 1;
insertionPoint = f;
} else {
// This is for the old behavior. Should be removed once it is
// guaranteed that CompareTreePosition can't return 0!
// See bug 928645.
NS_WARNING("Something odd happening???");
insertionPoint = nullptr;
for (uint32_t i = 0; i < children.Length(); ++i) {
nsIFrame* f = children[i];
if (nsLayoutUtils::CompareTreePosition(f, firstNewFrame,
firstNewFrameAncestors,
notCommonAncestor ?
containingBlock : nullptr) > 0) {
break;
}
insertionPoint = f;
}
break;
}
insertionPoint = f;
}
rv = mFrameManager->InsertFrames(containingBlock, aChildListID,
insertionPoint, aFrameItems);

View File

@ -1002,9 +1002,11 @@ nsLayoutUtils::DoCompareTreePosition(nsIContent* aContent1,
return index1 - index2;
}
static nsIFrame* FillAncestors(nsIFrame* aFrame,
nsIFrame* aStopAtAncestor,
nsTArray<nsIFrame*>* aAncestors)
// static
nsIFrame*
nsLayoutUtils::FillAncestors(nsIFrame* aFrame,
nsIFrame* aStopAtAncestor,
nsTArray<nsIFrame*>* aAncestors)
{
while (aFrame && aFrame != aStopAtAncestor) {
aAncestors->AppendElement(aFrame);
@ -1036,6 +1038,27 @@ nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
nsAutoTArray<nsIFrame*,20> frame2Ancestors;
nsIFrame* nonCommonAncestor =
FillAncestors(aFrame2, aCommonAncestor, &frame2Ancestors);
return DoCompareTreePosition(aFrame1, aFrame2, frame2Ancestors,
aIf1Ancestor, aIf2Ancestor,
nonCommonAncestor ? aCommonAncestor : nullptr);
}
// static
int32_t
nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
nsIFrame* aFrame2,
nsTArray<nsIFrame*>& aFrame2Ancestors,
int32_t aIf1Ancestor,
int32_t aIf2Ancestor,
nsIFrame* aCommonAncestor)
{
NS_PRECONDITION(aFrame1, "aFrame1 must not be null");
NS_PRECONDITION(aFrame2, "aFrame2 must not be null");
nsPresContext* presContext = aFrame1->PresContext();
if (presContext != aFrame2->PresContext()) {
NS_ERROR("no common ancestor at all, different documents");
@ -1043,25 +1066,18 @@ nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
}
nsAutoTArray<nsIFrame*,20> frame1Ancestors;
if (!FillAncestors(aFrame1, aCommonAncestor, &frame1Ancestors)) {
if (aCommonAncestor &&
!FillAncestors(aFrame1, aCommonAncestor, &frame1Ancestors)) {
// We reached the root of the frame tree ... if aCommonAncestor was set,
// it is wrong
aCommonAncestor = nullptr;
}
nsAutoTArray<nsIFrame*,20> frame2Ancestors;
if (!FillAncestors(aFrame2, aCommonAncestor, &frame2Ancestors) &&
aCommonAncestor) {
// We reached the root of the frame tree ... aCommonAncestor was wrong.
// Try again with no hint.
return DoCompareTreePosition(aFrame1, aFrame2,
aIf1Ancestor, aIf2Ancestor, nullptr);
}
int32_t last1 = int32_t(frame1Ancestors.Length()) - 1;
int32_t last2 = int32_t(frame2Ancestors.Length()) - 1;
int32_t last2 = int32_t(aFrame2Ancestors.Length()) - 1;
while (last1 >= 0 && last2 >= 0 &&
frame1Ancestors[last1] == frame2Ancestors[last2]) {
frame1Ancestors[last1] == aFrame2Ancestors[last2]) {
last1--;
last2--;
}
@ -1081,7 +1097,7 @@ nsLayoutUtils::DoCompareTreePosition(nsIFrame* aFrame1,
}
nsIFrame* ancestor1 = frame1Ancestors[last1];
nsIFrame* ancestor2 = frame2Ancestors[last2];
nsIFrame* ancestor2 = aFrame2Ancestors[last2];
// Now we should be able to walk sibling chains to find which one is first
if (IsFrameAfter(ancestor2, ancestor1))
return -1;

View File

@ -263,6 +263,15 @@ public:
return DoCompareTreePosition(aFrame1, aFrame2, -1, 1, aCommonAncestor);
}
static int32_t CompareTreePosition(nsIFrame* aFrame1,
nsIFrame* aFrame2,
nsTArray<nsIFrame*>& aFrame2Ancestors,
nsIFrame* aCommonAncestor = nullptr)
{
return DoCompareTreePosition(aFrame1, aFrame2, aFrame2Ancestors,
-1, 1, aCommonAncestor);
}
/*
* More generic version of |CompareTreePosition|. |aIf1Ancestor|
* gives the value to return when 1 is an ancestor of 2, and likewise
@ -275,6 +284,17 @@ public:
int32_t aIf2Ancestor,
nsIFrame* aCommonAncestor = nullptr);
static nsIFrame* FillAncestors(nsIFrame* aFrame,
nsIFrame* aStopAtAncestor,
nsTArray<nsIFrame*>* aAncestors);
static int32_t DoCompareTreePosition(nsIFrame* aFrame1,
nsIFrame* aFrame2,
nsTArray<nsIFrame*>& aFrame2Ancestors,
int32_t aIf1Ancestor,
int32_t aIf2Ancestor,
nsIFrame* aCommonAncestor);
/**
* LastContinuationWithChild gets the last continuation in aFrame's chain
* that has a child, or the first continuation if the frame has no children.