Bug 307394 part 2. Fix the indexing in ContentInserted to work correctly even when XBL is around. r+sr=dbaron. Also fixes bug 232990, bug 261826 , bug 272646, bug 386310, bug 468546

This commit is contained in:
Boris Zbarsky 2009-01-29 14:46:20 -05:00
parent f79bc67cfb
commit 4905383347
23 changed files with 614 additions and 282 deletions

View File

@ -155,6 +155,12 @@ public:
* anonymous content tree. Specifically, aChild should be inserted
* beneath aResult at the index specified by aIndex.
*/
// XXXbz That's false. The aIndex doesn't seem to accurately reflect
// anything resembling reality in terms of inserting content. It's really
// only used to tell apart two different insertion points with the same
// insertion parent when managing our internal data structures. We really
// shouldn't be handing it out in our public API, since it's not useful to
// anyone.
nsIContent* GetInsertionPoint(nsIContent* aParent,
nsIContent* aChild, PRUint32* aIndex);

View File

@ -144,6 +144,8 @@ public:
nsInsertionPointList* GetExistingInsertionPointsFor(nsIContent* aParent);
// XXXbz this aIndex has nothing to do with an index into the child
// list of the insertion parent or anything.
nsIContent* GetInsertionPoint(nsIContent* aChild, PRUint32* aIndex);
nsIContent* GetSingleInsertionPoint(PRUint32* aIndex,

View File

@ -155,6 +155,8 @@ public:
void InstantiateInsertionPoints(nsXBLBinding* aBinding);
// XXXbz this aIndex has nothing to do with an index into the child
// list of the insertion parent or anything.
nsIContent* GetInsertionPoint(nsIContent* aBoundElement,
nsIContent* aCopyRoot, nsIContent *aChild,
PRUint32* aIndex);

View File

@ -0,0 +1,25 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
[class='anon'], #v { float: left; }
[class='anon']:first-line { word-spacing: 30ch; }
body { width: 30ch; }
</style>
<bindings xmlns="http://www.mozilla.org/xbl"><binding id="foo"><content><div class="anon"><span>A BCDE</span><children xmlns="http://www.mozilla.org/xbl"/></div></content></binding></bindings>
<script type="text/javascript">
function boom()
{
document.body.insertBefore(document.createTextNode("fijkl"), document.body.firstChild);
}
</script>
</head>
<body onload="boom();" style="-moz-binding: url(#foo)"><div id="v">&#x202C;</div></body>
</html>

View File

@ -139,6 +139,7 @@ load 455063-2.html
load 455063-3.html
load 455171-4.html
load 466763-1.html
load 468546-1.xhtml
# These three didn't actually crash without the resizing that the
# browser does when setting up print preview, but adding them anyway.
load 468645-1.xhtml

View File

@ -7232,114 +7232,6 @@ nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState& aState,
#define UNSET_DISPLAY 255
nsIFrame*
nsCSSFrameConstructor::FindPreviousAnonymousSibling(nsIContent* aContainer,
nsIContent* aChild)
{
nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(mDocument));
NS_ASSERTION(xblDoc, "null xblDoc for content element in FindNextAnonymousSibling");
if (! xblDoc)
return nsnull;
// Grovel through the anonymous elements looking for aChild. We'll
// start our search for a previous frame there.
nsCOMPtr<nsIDOMNodeList> nodeList;
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(aContainer));
xblDoc->GetAnonymousNodes(elt, getter_AddRefs(nodeList));
if (! nodeList)
return nsnull;
PRUint32 length;
nodeList->GetLength(&length);
PRInt32 index;
for (index = PRInt32(length) - 1; index >= 0; --index) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(PRUint32(index), getter_AddRefs(node));
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
if (child == aChild)
break;
}
// We want the node immediately before aChild. Keep going until we
// run off the beginning of the nodeList, or we find a frame.
PRUint8 childDisplay = UNSET_DISPLAY;
while (--index >= 0) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(PRUint32(index), getter_AddRefs(node));
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
// Get its frame. If it doesn't have one, continue on to the
// anonymous element that preceded it.
nsIFrame* prevSibling = FindFrameForContentSibling(child, aChild,
childDisplay, PR_TRUE);
if (prevSibling) {
// Found a previous sibling, we're done!
return prevSibling;
}
}
return nsnull;
}
/**
* Find the frame for the anonymous content immediately following
* aChild.
*/
nsIFrame*
nsCSSFrameConstructor::FindNextAnonymousSibling(nsIContent* aContainer,
nsIContent* aChild)
{
nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(mDocument));
NS_ASSERTION(xblDoc, "null xblDoc for content element in FindNextAnonymousSibling");
if (! xblDoc)
return nsnull;
// Grovel through the anonymous elements looking for aChild
nsCOMPtr<nsIDOMNodeList> nodeList;
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(aContainer));
xblDoc->GetAnonymousNodes(elt, getter_AddRefs(nodeList));
if (! nodeList)
return nsnull;
PRUint32 length;
nodeList->GetLength(&length);
PRInt32 index;
for (index = 0; index < PRInt32(length); ++index) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(PRUint32(index), getter_AddRefs(node));
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
if (child == aChild)
break;
}
// We want the node immediately after aChild. Keep going until we
// run off the end of the nodeList, or we find a next sibling.
PRUint8 childDisplay = UNSET_DISPLAY;
while (++index < PRInt32(length)) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(PRUint32(index), getter_AddRefs(node));
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
// Get its frame
nsIFrame* nextSibling = FindFrameForContentSibling(child, aChild,
childDisplay, PR_FALSE);
if (nextSibling) {
// Found a next sibling, we're done!
return nextSibling;
}
}
return nsnull;
}
// This gets called to see if the frames corresponding to aSiblingDisplay and aDisplay
// should be siblings in the frame tree. Although (1) rows and cols, (2) row groups
// and col groups, (3) row groups and captions, (4) legends and content inside fieldsets, (5) popups and other kids of the menu
@ -7464,36 +7356,20 @@ nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
return sibling;
}
/**
* Find the ``rightmost'' frame for the content immediately preceding
* aIndexInContainer, following continuations if necessary.
*/
nsIFrame*
nsCSSFrameConstructor::FindPreviousSibling(nsIContent* aContainer,
PRInt32 aIndexInContainer,
nsIContent* aChild)
nsCSSFrameConstructor::FindPreviousSibling(const ChildIterator& aFirst,
ChildIterator aIter)
{
NS_ASSERTION(aContainer, "null argument");
ChildIterator first, iter;
nsresult rv = ChildIterator::Init(aContainer, &first, &iter);
NS_ENSURE_SUCCESS(rv, nsnull);
iter.seek(aIndexInContainer);
nsIContent* child = *aIter;
PRUint8 childDisplay = UNSET_DISPLAY;
// Note: not all content objects are associated with a frame (e.g., if it's
// `display: none') so keep looking until we find a previous frame
while (iter-- != first) {
while (aIter-- != aFirst) {
nsIFrame* prevSibling =
FindFrameForContentSibling(nsCOMPtr<nsIContent>(*iter), aChild,
childDisplay, PR_TRUE);
FindFrameForContentSibling(*aIter, child, childDisplay, PR_TRUE);
if (prevSibling) {
#ifdef DEBUG
nsIFrame* containerFrame = nsnull;
containerFrame = mPresShell->GetPrimaryFrameFor(aContainer);
NS_ASSERTION(prevSibling != containerFrame, "Previous Sibling is the Container's frame");
#endif
// Found a previous sibling, we're done!
return prevSibling;
}
@ -7502,30 +7378,22 @@ nsCSSFrameConstructor::FindPreviousSibling(nsIContent* aContainer,
return nsnull;
}
/**
* Find the frame for the content node immediately following
* aIndexInContainer.
*/
nsIFrame*
nsCSSFrameConstructor::FindNextSibling(nsIContent* aContainer,
PRInt32 aIndexInContainer,
nsIContent* aChild)
nsCSSFrameConstructor::FindNextSibling(ChildIterator aIter,
const ChildIterator& aLast)
{
ChildIterator iter, last;
nsresult rv = ChildIterator::Init(aContainer, &iter, &last);
NS_ENSURE_SUCCESS(rv, nsnull);
iter.seek(aIndexInContainer);
// Catch the case where someone tries to append
if (iter == last)
if (aIter == aLast) {
// XXXbz Can happen when XBL lies to us about insertion points. This check
// might be able to go away once bug 474324 is fixed.
return nsnull;
}
nsIContent* child = *aIter;
PRUint8 childDisplay = UNSET_DISPLAY;
while (++iter != last) {
while (++aIter != aLast) {
nsIFrame* nextSibling =
FindFrameForContentSibling(nsCOMPtr<nsIContent>(*iter), aChild,
childDisplay, PR_FALSE);
FindFrameForContentSibling(*aIter, child, childDisplay, PR_FALSE);
if (nextSibling) {
// We found a next sibling, we're done!
@ -7540,19 +7408,17 @@ nsCSSFrameConstructor::FindNextSibling(nsIContent* aContainer,
static nsIFrame*
GetAdjustedParentFrame(nsIFrame* aParentFrame,
nsIAtom* aParentFrameType,
nsIContent* aParentContent,
PRInt32 aChildIndex)
nsIContent* aChildContent)
{
NS_PRECONDITION(nsGkAtoms::tableOuterFrame != aParentFrameType,
"Shouldn't be happening!");
nsIContent *childContent = aParentContent->GetChildAt(aChildIndex);
nsIFrame* newParent = nsnull;
if (nsGkAtoms::fieldSetFrame == aParentFrameType) {
// If the parent is a fieldSet, use the fieldSet's area frame as the
// parent unless the new content is a legend.
nsCOMPtr<nsIDOMHTMLLegendElement> legendContent(do_QueryInterface(childContent));
nsCOMPtr<nsIDOMHTMLLegendElement> legendContent(do_QueryInterface(aChildContent));
if (!legendContent) {
newParent = GetFieldSetBlockFrame(aParentFrame);
}
@ -7654,39 +7520,18 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
}
if (multiple || childCount > 0) {
// Now comes the fun part. For each appended child, we must obtain its
// insertion point and find its exact position within that insertion point.
// We then make a ContentInserted call with the correct computed index.
nsIContent* insertionContent = insertionPoint->GetContent();
// Now comes the fun part. For each appended child, make a
// ContentInserted call as if it had just gotten inserted at the index
// it's at in aContainer and let ContentInserted handle the mess. If our
// insertion point is non-XBL that's the correct index, and otherwise
// ContentInserted will ignore the passed-in index.
PRUint32 containerCount = aContainer->GetChildCount();
for (PRUint32 i = aNewIndexInContainer; i < containerCount; i++) {
nsIContent *child = aContainer->GetChildAt(i);
if (multiple) {
// Filters are in effect, so the insertion point needs to be refetched for
// each child.
GetInsertionPoint(parentFrame, child, &insertionPoint);
if (!insertionPoint) {
// This content node doesn't have an insertion point, so we just
// skip over it
continue;
}
insertionContent = insertionPoint->GetContent();
}
// Construct an iterator to locate this child at its correct index.
ChildIterator iter, last;
for (ChildIterator::Init(insertionContent, &iter, &last);
iter != last;
++iter) {
LAYOUT_PHASE_TEMP_EXIT();
nsIContent* item = nsCOMPtr<nsIContent>(*iter);
if (item == child)
// Call ContentInserted with this index.
ContentInserted(aContainer, child,
iter.position(), mTempFrameTreeState);
LAYOUT_PHASE_TEMP_REENTER();
}
LAYOUT_PHASE_TEMP_EXIT();
// Call ContentInserted with this index.
ContentInserted(aContainer, aContainer->GetChildAt(i), i,
mTempFrameTreeState);
LAYOUT_PHASE_TEMP_REENTER();
}
return NS_OK;
@ -7737,9 +7582,10 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
nsIAtom* frameType = parentFrame->GetType();
// Deal with fieldsets
parentFrame = ::GetAdjustedParentFrame(parentFrame, frameType,
aContainer, aNewIndexInContainer);
// We should never get here with fieldsets, since they have multiple
// insertion points.
NS_ASSERTION(frameType != nsGkAtoms::fieldSetFrame,
"Unexpected parent");
// Deal with possible :after generated content on the parent
nsIFrame* parentAfterFrame;
@ -7910,6 +7756,9 @@ PRBool NotifyListBoxBody(nsPresContext* aPresContext,
return PR_TRUE;
}
} else {
// If this codepath ever starts using aIndexInContainer, need to
// change ContentInserted to pass in something resembling a correct
// one in the XBL cases.
listBoxBodyFrame->OnContentInserted(aPresContext, aChild);
return PR_TRUE;
}
@ -7948,6 +7797,8 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
nsresult rv = NS_OK;
#ifdef MOZ_XUL
// aIndexInContainer might be bogus here, but it's not used by
// NotifyListBoxBody's CONTENT_INSERTED handling in any case.
if (NotifyListBoxBody(mPresShell->GetPresContext(), aContainer, aChild,
aIndexInContainer,
mDocument, nsnull, CONTENT_INSERTED))
@ -8031,27 +7882,25 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
// the preceding frame.
nsIContent* container = parentFrame->GetContent();
// XXX if the insertionPoint was different from the original
// parentFrame, then aIndexInContainer is most likely completely
// wrong. What we need to do here is remember the original index,
// then as we insert, search the child list where we're about to put
// the new frame to make sure that it appears after any siblings
// with a lower index, and before any siblings with a higher
// index. Same with FindNextSibling(), below.
nsIFrame* prevSibling = (aIndexInContainer >= 0)
? FindPreviousSibling(container, aIndexInContainer, aChild)
: FindPreviousAnonymousSibling(aContainer, aChild);
ChildIterator first, last;
ChildIterator::Init(container, &first, &last);
ChildIterator iter(first);
if (iter.XBLInvolved() || container != aContainer) {
iter.seek(aChild);
// Don't touch our aIndexInContainer, though it's almost certainly bogus in
// this case. If someone wants to use an index below, they should make
// sure to use the right index (aIndexInContainer vs iter.position()) with
// the right parent node.
} else {
// Do things the fast way if we can.
iter.seek(aIndexInContainer);
NS_ASSERTION(*iter == aChild, "Someone screwed up the indexing");
}
nsIFrame* prevSibling = FindPreviousSibling(first, iter);
PRBool isAppend = PR_FALSE;
nsIFrame* appendAfterFrame; // This is only looked at when isAppend is true
nsIFrame* nextSibling = nsnull;
// If there is no previous sibling, then find the frame that follows
if (! prevSibling) {
nextSibling = (aIndexInContainer >= 0)
? FindNextSibling(container, aIndexInContainer, aChild)
: FindNextAnonymousSibling(aContainer, aChild);
}
// Now, find the geometric parent so that we can handle
// continuations properly. Use the prev sibling if we have it;
@ -8059,21 +7908,27 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
if (prevSibling) {
parentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
}
else if (nextSibling) {
parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
}
else {
// No previous or next sibling, so treat this like an appended frame.
isAppend = PR_TRUE;
// Get continuation that parents the last child
parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
// Deal with fieldsets
parentFrame = ::GetAdjustedParentFrame(parentFrame, parentFrame->GetType(),
aContainer, aIndexInContainer);
parentFrame =
::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
aContainer, parentFrame,
&appendAfterFrame);
// If there is no previous sibling, then find the frame that follows
nsIFrame* nextSibling = FindNextSibling(iter, last);
if (nextSibling) {
parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
}
else {
// No previous or next sibling, so treat this like an appended frame.
isAppend = PR_TRUE;
// Get continuation that parents the last child
parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
// Deal with fieldsets
parentFrame = ::GetAdjustedParentFrame(parentFrame,
parentFrame->GetType(),
aChild);
parentFrame =
::AdjustAppendParentForAfterContent(mPresShell->GetPresContext(),
aContainer, parentFrame,
&appendAfterFrame);
}
}
if (parentFrame->GetType() == nsGkAtoms::frameSetFrame &&
@ -8143,17 +7998,14 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
// Removing the letterframes messes around with the frame tree, removing
// and creating frames. We need to reget our prevsibling.
// See XXX comment the first time we do this in this method....
prevSibling = (aIndexInContainer >= 0)
? FindPreviousSibling(container, aIndexInContainer, aChild)
: FindPreviousAnonymousSibling(aContainer, aChild);
// If there is no previous sibling, then find the frame that follows
if (! prevSibling) {
nextSibling = (aIndexInContainer >= 0)
? FindNextSibling(container, aIndexInContainer, aChild)
: FindNextAnonymousSibling(aContainer, aChild);
ChildIterator::Init(container, &first, &last);
if (container == aContainer && !last.XBLInvolved()) {
last.seek(aIndexInContainer);
} else {
last.seek(aChild);
}
prevSibling = FindPreviousSibling(first, last);
}
}
@ -10581,8 +10433,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
for (ChildIterator::Init(aContent, &iter, &last);
iter != last;
++iter) {
rv = ConstructFrame(aState, nsCOMPtr<nsIContent>(*iter),
aFrame, aFrameItems);
rv = ConstructFrame(aState, *iter, aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
}
@ -11995,8 +11846,7 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsFrameConstructorState& aState,
++iter) {
// Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild;
rv = ConstructFrame(aState, nsCOMPtr<nsIContent>(*iter),
aFrame, aFrameItems);
rv = ConstructFrame(aState, *iter, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;

View File

@ -68,6 +68,7 @@ class nsPresContext;
class nsStyleChangeList;
class nsIFrame;
struct nsGenConInitializer;
class ChildIterator;
struct nsFindFrameHint
{
@ -1281,16 +1282,17 @@ private:
PRUint8& aTargetContentDisplay,
PRBool aPrevSibling);
// Find the ``rightmost'' frame for the content immediately preceding
// aIndexInContainer, following continuations if necessary.
nsIFrame* FindPreviousSibling(nsIContent* aContainer,
PRInt32 aIndexInContainer,
nsIContent* aChild);
// Find the ``rightmost'' frame for the content immediately preceding the one
// aIter points to, following continuations if necessary. aIter is passed by
// value on purpose, so as not to modify the callee's iterator.
nsIFrame* FindPreviousSibling(const ChildIterator& aFirst,
ChildIterator aIter);
// Find the frame for the content node immediately following aIndexInContainer.
nsIFrame* FindNextSibling(nsIContent* aContainer,
PRInt32 aIndexInContainer,
nsIContent* aChild);
// Find the frame for the content node immediately following the one aIter
// points to, following continuations if necessary. aIter is passed by value
// on purpose, so as not to modify the callee's iterator.
nsIFrame* FindNextSibling(ChildIterator aIter,
const ChildIterator& aIter);
// see if aContent and aSibling are legitimate siblings due to restrictions
// imposed by table columns
@ -1300,22 +1302,6 @@ private:
nsIContent* aContent,
PRUint8& aDisplay);
/**
* Find the ``rightmost'' frame for the anonymous content immediately
* preceding aChild, following continuation if necessary.
*/
nsIFrame*
FindPreviousAnonymousSibling(nsIContent* aContainer,
nsIContent* aChild);
/**
* Find the frame for the anonymous content immediately following
* aChild.
*/
nsIFrame*
FindNextAnonymousSibling(nsIContent* aContainer,
nsIContent* aChild);
void QuotesDirty() {
NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
mQuotesDirty = PR_TRUE;

View File

@ -58,15 +58,14 @@ ChildIterator::Init(nsIContent* aContent,
if (! aContent)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDocument> doc = aContent->GetDocument();
nsIDocument* doc = aContent->GetOwnerDoc();
NS_ASSERTION(doc, "element not in the document");
if (! doc)
return NS_ERROR_FAILURE;
// If this node has XBL children, then use them. Otherwise, just use
// the vanilla content APIs.
nsCOMPtr<nsIDOMNodeList> nodes;
doc->BindingManager()->GetXBLChildNodesFor(aContent, getter_AddRefs(nodes));
nsINodeList* nodes = doc->BindingManager()->GetXBLChildNodesFor(aContent);
PRUint32 length;
if (nodes)

View File

@ -43,8 +43,7 @@
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMNode.h"
#include "nsINodeList.h"
/**
* Helper class for iterating children during frame construction.
@ -55,9 +54,14 @@
class NS_STACK_CLASS ChildIterator
{
protected:
// We could just use a mNodes for the case when we're not dealing with XBL
// anon content too, but in practice that would basically replace our current
// branch on mNodes with an extra virtual function call in the common case.
// XXXbz do these really need to be strong pointers?
nsCOMPtr<nsIContent> mContent;
PRUint32 mIndex;
nsCOMPtr<nsIDOMNodeList> mNodes;
nsCOMPtr<nsINodeList> mNodes;
public:
ChildIterator()
@ -97,21 +101,15 @@ public:
return result;
}
already_AddRefed<nsIContent> get() const {
nsIContent* result = nsnull;
if (mNodes) {
nsCOMPtr<nsIDOMNode> node;
mNodes->Item(mIndex, getter_AddRefs(node));
CallQueryInterface(node, &result);
} else {
result = mContent->GetChildAt(PRInt32(mIndex));
NS_IF_ADDREF(result);
nsIContent* get() const {
if (XBLInvolved()) {
return mNodes->GetNodeAt(mIndex);
}
return result;
return mContent->GetChildAt(mIndex);
}
already_AddRefed<nsIContent> operator*() const { return get(); }
nsIContent* operator*() const { return get(); }
PRBool operator==(const ChildIterator& aOther) const {
return mContent == aOther.mContent && mIndex == aOther.mIndex;
@ -129,21 +127,43 @@ public:
// Make sure that aIndex is reasonable. This should be |#ifdef
// DEBUG|, but we need these numbers for the temporary workaround
// for bug 133219.
PRUint32 length;
if (mNodes)
mNodes->GetLength(&length);
else
length = mContent->GetChildCount();
PRUint32 l = length();
NS_ASSERTION(PRInt32(aIndex) >= 0 && aIndex <= length, "out of bounds");
NS_ASSERTION(PRInt32(aIndex) >= 0 && aIndex <= l, "out of bounds");
// Temporary workaround for bug 133219.
if (aIndex > length)
aIndex = length;
if (aIndex > l)
aIndex = l;
mIndex = aIndex;
}
void seek(nsIContent* aContent) {
PRInt32 index;
if (XBLInvolved()) {
index = mNodes->IndexOf(aContent);
} else {
index = mContent->IndexOf(aContent);
}
// XXXbz I wish we could assert that index != -1, but I think that's not
// necessarily the case when called from ContentInserted if first-letter
// frames are about. It also seems to not be the case in some XBL cases
// with filtered insertion points and no default insertion point. I will
// now claim that XBL's management of its insertion points is broken in
// those cases, since it's returning an insertion parent for a node that
// doesn't actually have the node in its child list according to
// ChildIterator. See bug 474324.
if (index != -1) {
mIndex = index;
} else {
// If aContent isn't going to get hit by this iterator, just seek to the
// end of the list for lack of anything better to do.
mIndex = length();
}
}
PRBool XBLInvolved() const { return mNodes != nsnull; }
/**
* Create a pair of ChildIterators for a content node. aFirst will
* point to the first child of aContent; aLast will point one past
@ -152,4 +172,15 @@ public:
static nsresult Init(nsIContent* aContent,
ChildIterator* aFirst,
ChildIterator* aLast);
private:
PRUint32 length() {
PRUint32 l;
if (XBLInvolved()) {
mNodes->GetLength(&l);
} else {
l = mContent->GetChildCount();
}
return l;
}
};

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
<![CDATA[
@namespace pp url("prettyprint");
pp|expander-box,
pp|pre-content {
display: block;
}
pp|expander-box[collapsed] > pp|float,
pp|expander-box[collapsed] > pp|pre-content {
display: inline;
float: none;
}
pp|float {
float: left;
}
]]></style>
</head>
<body>
<div>
<pp:content xmlns:pp="prettyprint">
<pp:expander-box collapsed="collapsed"><pp:float>-</pp:float>
<pp:pre-content>pre</pp:pre-content>
</pp:expander-box>
</pp:content>
</div>
</body>
</html>

View File

@ -0,0 +1,49 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
<![CDATA[
@namespace pp url("prettyprint");
pp|expander-box,
pp|pre-content {
display: block;
}
pp|expander-box[collapsed] > pp|float,
pp|expander-box[collapsed] > pp|pre-content {
display: inline;
float: none;
}
pp|float {
float: left;
}
]]></style>
<script>
<![CDATA[
var target;
function onLoad() {
var res = document.evaluate("descendant::pp:expander-box",
document.documentElement,
function(aPref){return "prettyprint";},
0, null);
target = res.iterateNext();
toggle();
}
function toggle() {
target.setAttribute("collapsed", "collapsed");
}
]]></script>
</head>
<body onload="onLoad()">
<div>
<pp:content xmlns:pp="prettyprint">
<pp:expander-box><pp:float>-</pp:float>
<pp:pre-content>pre</pp:pre-content>
</pp:expander-box>
</pp:content>
</div>
</body>
</html>

View File

@ -0,0 +1,63 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>display test</title>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:pp="prettyprint"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="expander">
<content><pp:float>-</pp:float><children/></content>
</binding>
</bindings>
<style type="text/css">
<![CDATA[
@namespace pp url("prettyprint");
pp|expander-box,
pp|pre-content {
display: block;
}
pp|expander-box[collapsed] > pp|float,
pp|expander-box[collapsed] > pp|pre-content {
display: inline;
float: none;
}
pp|expander-box[xbl] {
-moz-binding: url(#expander);
}
pp|float {
float: left;
}
]]></style>
<script>
<![CDATA[
var target;
function onLoad() {
var res = document.evaluate("descendant::pp:expander-box",
document.documentElement,
function(aPref){return "prettyprint";},
0, null);
target = res.iterateNext();
toggle();
}
function toggle() {
target.setAttribute("collapsed", "collapsed");
}
]]></script>
</head>
<body onload="onLoad()">
<div>
<pp:content xmlns:pp="prettyprint">
<pp:expander-box xbl="yes">
<pp:pre-content>pre</pp:pre-content>
</pp:expander-box>
</pp:content>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="MyWindow"
title=""
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="800"
height="600"
onload="revealTab()">
<tabbox>
<tabs>
<tab label="first"/>
<tab label="second"/>
<tab label="third"/>
<tab label="fourth"/>
</tabs>
<tabpanels>
<tabpanel>
<label value="First page"/>
</tabpanel>
<tabpanel>
<label value="second page"/>
</tabpanel>
<tabpanel>
<label value="third page"/>
</tabpanel>
<tabpanel>
<label value="fourth page"/>
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="MyWindow"
title=""
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="800"
height="600"
onload="revealTab()">
<script type="application/x-javascript">
function revealTab(){
document.getElementById("fourthTab").setAttribute("hidden", "false");
}
</script>
<tabbox>
<tabs>
<tab label="first"/>
<tab label="second"/>
<tab label="third"/>
<tab id="fourthTab" label="fourth" hidden="true"/>
</tabs>
<tabpanels>
<tabpanel>
<label value="First page"/>
</tabpanel>
<tabpanel>
<label value="second page"/>
</tabpanel>
<tabpanel>
<label value="third page"/>
</tabpanel>
<tabpanel>
<label value="fourth page"/>
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:nc="http://home.netscape.com/NC-rdf#"
title="insertBefore - Weirdness"
>
<tabbox>
<tabs>
<tab label="foo" />
<tab label="new" />
<tab label="bar" />
</tabs>
<tabpanels>
<tabpanel>
<vbox>
<label value="foo"/>
</vbox>
</tabpanel>
<tabpanel>
<vbox>
<label value="bar"/>
</vbox>
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:nc="http://home.netscape.com/NC-rdf#"
title="insertBefore - Weirdness"
onload="var atab = document.createElement('tab'); atab.setAttribute('label','new'); document.getElementById('tabs-id').insertBefore(atab,document.getElementById('tabs-id').lastChild);" >
<tabbox>
<tabs id="tabs-id">
<tab label="foo" />
<tab label="bar" />
</tabs>
<tabpanels>
<tabpanel>
<vbox>
<label value="foo"/>
</vbox>
</tabpanel>
<tabpanel>
<vbox>
<label value="bar"/>
</vbox>
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="tab-test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<tabbox id="main_courseframe" flex="1">
<tabs id="main_coursetabs" ida-type="gradient">
<tab id="main_coursetab_general" label="General" />
<tab id="main_coursetab_overview" label="Overview" />
<tab id="main_coursetab_extensions" label="Extensions" />
</tabs>
<tabpanels id="main_coursetabpanels" flex="1">
<tabpanel id="main_coursetabpanel_general">
<label value="this is the general tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_overview">
<label value="this is the OVERVIEW tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_extensions">
<label value="this is the EXTENSIONS tabpanel" />
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="tab-test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="var e =
document.getElementById('main_coursetab_extensions'); e.hidden = true;
document.documentElement.getBoundingClientRect(); e.hidden = false;">
<tabbox id="main_courseframe" flex="1">
<tabs id="main_coursetabs" ida-type="gradient">
<tab id="main_coursetab_general" label="General" />
<tab id="main_coursetab_overview" label="Overview" />
<tab id="main_coursetab_extensions" label="Extensions" />
</tabs>
<tabpanels id="main_coursetabpanels" flex="1">
<tabpanel id="main_coursetabpanel_general">
<label value="this is the general tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_overview">
<label value="this is the OVERVIEW tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_extensions">
<label value="this is the EXTENSIONS tabpanel" />
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="tab-test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="var e =
document.getElementById('main_coursetab_overview'); e.hidden = true;
document.documentElement.getBoundingClientRect(); e.hidden = false;">
<tabbox id="main_courseframe" flex="1">
<tabs id="main_coursetabs" ida-type="gradient">
<tab id="main_coursetab_general" label="General" />
<tab id="main_coursetab_overview" label="Overview" />
<tab id="main_coursetab_extensions" label="Extensions" />
</tabs>
<tabpanels id="main_coursetabpanels" flex="1">
<tabpanel id="main_coursetabpanel_general">
<label value="this is the general tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_overview">
<label value="this is the OVERVIEW tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_extensions">
<label value="this is the EXTENSIONS tabpanel" />
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="tab-test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="var e =
document.getElementById('main_coursetab_general'); e.hidden = true;
document.documentElement.getBoundingClientRect(); e.hidden = false;">
<tabbox id="main_courseframe" flex="1">
<tabs id="main_coursetabs" ida-type="gradient">
<tab id="main_coursetab_general" label="General" />
<tab id="main_coursetab_overview" label="Overview" />
<tab id="main_coursetab_extensions" label="Extensions" />
</tabs>
<tabpanels id="main_coursetabpanels" flex="1">
<tabpanel id="main_coursetabpanel_general">
<label value="this is the general tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_overview">
<label value="this is the OVERVIEW tabpanel" />
</tabpanel>
<tabpanel id="main_coursetabpanel_extensions">
<label value="this is the EXTENSIONS tabpanel" />
</tabpanel>
</tabpanels>
</tabbox>
</window>

View File

@ -0,0 +1,12 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
[class='anon'] { float: left; }
[class='anon']:first-line { word-spacing: 30ch; }
body { width: 30ch; }
</style>
</head>
<body><div class="anon"><span>A B</span>jk</div></body>
</html>

View File

@ -0,0 +1,25 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
[class='anon'], #v { float: left; }
[class='anon']:first-line { word-spacing: 30ch; }
body { width: 30ch; }
</style>
<bindings xmlns="http://www.mozilla.org/xbl"><binding id="foo"><content><div class="anon"><span>A B</span><children xmlns="http://www.mozilla.org/xbl"/></div></content></binding></bindings>
<script type="text/javascript">
function boom()
{
document.body.insertBefore(document.createTextNode("jk"), document.body.firstChild);
}
</script>
</head>
<body onload="boom();" style="-moz-binding: url(#foo)"><div id="v"></div></body>
</html>

View File

@ -148,6 +148,8 @@ random == 99850-1b.html 99850-1-ref.html # bug 471629
== 228856-1.html 228856-1-ref.html
== 228856-2.html 228856-2-ref.html
# == 231823-1.html 231823-1-ref.html
== 232990-1a.xhtml 232990-1-ref.xhtml
== 232990-1b.xhtml 232990-1-ref.xhtml
== 233094-1.html 233094-1-ref.html
== 233094-2a.html 233094-2-ref.html
== 233094-2b.html 233094-2-ref.html
@ -209,11 +211,16 @@ skip-if(MOZ_WIDGET_TOOLKIT=="cocoa") != 240536-resizer-ltr.xul 240536-resizer-rt
== 252920-1.html 252920-1-ref.html
== 253701-1.html 253701-1-ref.html
== 255820-1.html 255820-1-ref.html
== 261826-1.xul 261826-1-ref.xul
== 262151-1.html 262151-1-ref.html
#== 263683-1.html 263683-1-ref.html
== 267353-1.html 267353-1-ref.html
== 271747-1a.html 271747-1-ref.html
== 271747-1b.html 271747-1-ref.html
== 272646-1.xul 272646-1-ref.xul
== 272646-2a.xul 272646-2-ref.xul
== 272646-2b.xul 272646-2-ref.xul
== 272646-2c.xul 272646-2-ref.xul
== 273681-1.html 273681-1-ref.html
== 278266-1a.html 278266-1-ref.html
== 278266-1b.html 278266-1-ref.html
@ -620,9 +627,9 @@ fails == 385823-2b.html 385823-2-ref.html
== 386065-2.html about:blank
fails == 386147-1.html 386147-1-ref.html # bug 447460
== 386310-1a.html 386310-1-ref.html
fails == 386310-1b.html 386310-1-ref.html
== 386310-1b.html 386310-1-ref.html
== 386310-1c.html 386310-1-ref.html
fails == 386310-1d.html 386310-1-ref.html
== 386310-1d.html 386310-1-ref.html
== 386401-1.html 386401-1-ref.html
== 386401-2.html 386401-2-ref.html
== 386401-3.html 386401-3-ref.html
@ -1017,6 +1024,7 @@ fails == 461512-1.html 461512-1-ref.html # Bug 461512
== 467084-1.html 467084-1-ref.html
== 467084-2.html 467084-2-ref.html
== 467460-1.html 467460-1-ref.html
== 468546-1.xhtml 468546-1-ref.xhtml
== 468473-1.xul 468473-1-ref.xul
== 471356-1.html 471356-1-ref.html
== 471594-1.xhtml 471594-1-ref.html