Bug 84645. Move XBL insertion point logic into nsCSSFrameConstructor, where it can interact nicely with continuing frames. r=dbaron, sr=hyatt
git-svn-id: svn://10.0.0.236/trunk@102820 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
316
mozilla/layout/base/nsFrameContentIterator.cpp
Normal file
316
mozilla/layout/base/nsFrameContentIterator.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "MPL"); you may not use this file except in
|
||||
* compliance with the MPL. You may obtain a copy of the MPL at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the MPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* MPL.
|
||||
*
|
||||
* The Initial Developer of this code under the MPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsFrameList.h"
|
||||
|
||||
class nsFrameContentIterator : public nsIContentIterator
|
||||
{
|
||||
public:
|
||||
nsFrameContentIterator(nsIPresContext* aPresContext, nsIFrame* aFrame);
|
||||
virtual ~nsFrameContentIterator();
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIContentIterator
|
||||
NS_IMETHOD Init(nsIContent* aRoot);
|
||||
NS_IMETHOD Init(nsIDOMRange* aRange);
|
||||
|
||||
NS_IMETHOD First();
|
||||
NS_IMETHOD Last();
|
||||
NS_IMETHOD Next();
|
||||
NS_IMETHOD Prev();
|
||||
|
||||
NS_IMETHOD CurrentNode(nsIContent **aNode);
|
||||
NS_IMETHOD IsDone();
|
||||
NS_IMETHOD PositionAt(nsIContent* aCurNode);
|
||||
|
||||
NS_IMETHOD MakePre();
|
||||
NS_IMETHOD MakePost();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPresContext> mPresContext;
|
||||
nsIFrame* mParentFrame;
|
||||
nsIFrame* mCurrentChild;
|
||||
PRBool mIsDone;
|
||||
};
|
||||
|
||||
nsFrameContentIterator::nsFrameContentIterator(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame)
|
||||
: mPresContext(aPresContext), mParentFrame(aFrame), mIsDone(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
First();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFrameContentIterator, nsIContentIterator);
|
||||
|
||||
nsFrameContentIterator::~nsFrameContentIterator()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::Init(nsIContent* aRoot)
|
||||
{
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::Init(nsIDOMRange* aRange)
|
||||
{
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::First()
|
||||
{
|
||||
// Get the first child frame and make it the current node
|
||||
mParentFrame->FirstChild(mPresContext, nsnull, &mCurrentChild);
|
||||
if (!mCurrentChild) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mIsDone = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
static nsIFrame*
|
||||
GetNextChildFrame(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "null pointer");
|
||||
|
||||
// Get the last-in-flow
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* nextInFlow;
|
||||
aFrame->GetNextInFlow(&nextInFlow);
|
||||
if (nextInFlow) {
|
||||
aFrame = nextInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get its next sibling
|
||||
nsIFrame* nextSibling;
|
||||
aFrame->GetNextSibling(&nextSibling);
|
||||
|
||||
// If there's no next sibling, then check if the parent frame
|
||||
// has a next-in-flow and look there
|
||||
if (!nextSibling) {
|
||||
nsIFrame* parent;
|
||||
aFrame->GetParent(&parent);
|
||||
parent->GetNextInFlow(&parent);
|
||||
|
||||
if (parent) {
|
||||
parent->FirstChild(aPresContext, nsnull, &nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
return nextSibling;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::Last()
|
||||
{
|
||||
nsIFrame* nextChild;
|
||||
|
||||
// Starting with the first child walk and find the last child
|
||||
mCurrentChild = nsnull;
|
||||
mParentFrame->FirstChild(mPresContext, nsnull, &nextChild);
|
||||
while (nextChild) {
|
||||
mCurrentChild = nextChild;
|
||||
nextChild = ::GetNextChildFrame(mPresContext, nextChild);
|
||||
}
|
||||
|
||||
if (!mCurrentChild) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mIsDone = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::Next()
|
||||
{
|
||||
nsIFrame* nextChild = ::GetNextChildFrame(mPresContext, mCurrentChild);
|
||||
|
||||
if (nextChild) {
|
||||
// Advance to the next child
|
||||
mCurrentChild = nextChild;
|
||||
|
||||
// If we're at the end then the collection is at the end
|
||||
mIsDone = (nsnull == ::GetNextChildFrame(mPresContext, mCurrentChild));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetPrevChildFrame(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "null pointer");
|
||||
|
||||
// Get its previous sibling. Because we have a singly linked list we
|
||||
// need to search from the first child
|
||||
nsIFrame* parent;
|
||||
nsIFrame* firstChild;
|
||||
nsIFrame* prevSibling;
|
||||
|
||||
aFrame->GetParent(&parent);
|
||||
parent->FirstChild(aPresContext, nsnull, &firstChild);
|
||||
|
||||
NS_ASSERTION(firstChild, "parent has no first child");
|
||||
nsFrameList frameList(firstChild);
|
||||
prevSibling = frameList.GetPrevSiblingFor(aFrame);
|
||||
|
||||
// If there's no previous sibling, then check if the parent frame
|
||||
// has a prev-in-flow and look there
|
||||
if (!prevSibling) {
|
||||
parent->GetPrevInFlow(&parent);
|
||||
|
||||
if (parent) {
|
||||
parent->FirstChild(aPresContext, nsnull, &firstChild);
|
||||
frameList.SetFrames(firstChild);
|
||||
prevSibling = frameList.LastChild();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the first-in-flow
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* prevInFlow;
|
||||
prevSibling->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
prevSibling = prevInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return prevSibling;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::Prev()
|
||||
{
|
||||
nsIFrame* prevChild = ::GetPrevChildFrame(mPresContext, mCurrentChild);
|
||||
|
||||
if (prevChild) {
|
||||
// Make the previous child the current child
|
||||
mCurrentChild = prevChild;
|
||||
|
||||
// If we're at the beginning then the collection is at the end
|
||||
mIsDone = (nsnull == ::GetPrevChildFrame(mPresContext, mCurrentChild));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::CurrentNode(nsIContent **aNode)
|
||||
{
|
||||
if (mCurrentChild) {
|
||||
mCurrentChild->GetContent(aNode);
|
||||
return NS_OK;
|
||||
|
||||
} else {
|
||||
*aNode = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::IsDone()
|
||||
{
|
||||
return mIsDone ? NS_OK : NS_ENUMERATOR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::PositionAt(nsIContent* aCurNode)
|
||||
{
|
||||
nsIFrame* child;
|
||||
|
||||
// Starting with the first child frame search for the child frame
|
||||
// with the matching content object
|
||||
mParentFrame->FirstChild(mPresContext, nsnull, &child);
|
||||
while (child) {
|
||||
nsCOMPtr<nsIContent> content;
|
||||
|
||||
child->GetContent(getter_AddRefs(content));
|
||||
if (content.get() == aCurNode) {
|
||||
break;
|
||||
}
|
||||
child = ::GetNextChildFrame(mPresContext, child);
|
||||
}
|
||||
|
||||
if (child) {
|
||||
// Make it the current child
|
||||
mCurrentChild = child;
|
||||
mIsDone = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::MakePre()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameContentIterator::MakePost()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewFrameContentIterator(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContentIterator** aIterator)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIterator);
|
||||
if (!aIterator) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
NS_ENSURE_ARG_POINTER(aFrame);
|
||||
if (!aFrame) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Make sure the frame corresponds to generated content
|
||||
#ifdef DEBUG
|
||||
nsFrameState frameState;
|
||||
aFrame->GetFrameState(&frameState);
|
||||
NS_ASSERTION(frameState & NS_FRAME_GENERATED_CONTENT, "unexpected frame");
|
||||
#endif
|
||||
|
||||
nsFrameContentIterator* it = new nsFrameContentIterator(aPresContext, aFrame);
|
||||
if (!it) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return it->QueryInterface(NS_GET_IID(nsIContentIterator), (void **)aIterator);
|
||||
}
|
||||
Reference in New Issue
Block a user