From effef91cf6c4879a98f0f2e6a7e2469d105326cf Mon Sep 17 00:00:00 2001 From: "troy%netscape.com" Date: Thu, 10 Sep 1998 19:32:14 +0000 Subject: [PATCH] Phase one of frame construction changes --- content/base/public/nsIDocument.h | 3 +- content/base/public/nsIDocumentObserver.h | 5 +- content/base/src/nsContentList.cpp | 3 +- content/base/src/nsContentList.h | 3 +- content/base/src/nsDocument.cpp | 5 +- content/base/src/nsDocument.h | 3 +- content/base/src/nsStyleSet.cpp | 105 +- .../html/content/src/nsGenericHTMLElement.cpp | 2 +- content/html/content/src/nsHTMLAtoms.cpp | 10 + content/html/content/src/nsHTMLAtoms.h | 3 + .../html/document/src/nsHTMLContentSink.cpp | 13 +- content/html/style/src/nsHTMLStyleSheet.cpp | 344 ++- content/shared/public/nsHTMLAtoms.h | 3 + content/shared/src/nsHTMLAtoms.cpp | 10 + layout/base/nsIPresShell.h | 9 + layout/base/nsPresContext.cpp | 80 + layout/base/nsPresContext.h | 30 + layout/base/public/Makefile | 1 + layout/base/public/makefile.win | 1 + layout/base/public/nsIDocument.h | 3 +- layout/base/public/nsIDocumentObserver.h | 5 +- layout/base/public/nsIFrame.h | 22 + layout/base/public/nsIPresContext.h | 30 + layout/base/public/nsIPresShell.h | 9 + layout/base/public/nsIReflowCommand.h | 5 + .../base/public/nsIStyleFrameConstruction.h | 47 + layout/base/public/nsIStyleSet.h | 31 + layout/base/public/nsPresContext.h | 30 + layout/base/src/nsContainerFrame.cpp | 16 + layout/base/src/nsContainerFrame.h | 2 + layout/base/src/nsContentList.cpp | 3 +- layout/base/src/nsContentList.h | 3 +- layout/base/src/nsDocument.cpp | 5 +- layout/base/src/nsDocument.h | 3 +- layout/base/src/nsFrame.cpp | 13 + layout/base/src/nsFrame.h | 4 + layout/base/src/nsPresContext.cpp | 80 + layout/base/src/nsPresContext.h | 21 + layout/base/src/nsPresShell.cpp | 169 +- layout/base/src/nsStyleSet.cpp | 105 +- layout/css/layout/src/nsCSSBlockFrame.cpp | 153 +- layout/generic/nsHTMLFrame.cpp | 29 + layout/generic/nsHTMLParts.h | 34 + layout/generic/nsHTMLReflowCommand.cpp | 6 + layout/generic/nsHTMLReflowCommand.h | 1 + layout/generic/nsIFrame.h | 22 + layout/generic/nsPlaceholderFrame.cpp | 3 + layout/generic/nsPlaceholderFrame.h | 3 + layout/html/base/src/nsAbsoluteFrame.cpp | 3 + layout/html/base/src/nsAbsoluteFrame.h | 3 + layout/html/base/src/nsBodyFrame.cpp | 55 +- layout/html/base/src/nsBodyFrame.h | 5 + layout/html/base/src/nsHTMLAtoms.cpp | 10 + layout/html/base/src/nsHTMLAtoms.h | 3 + layout/html/base/src/nsHTMLContainer.cpp | 2 +- layout/html/base/src/nsHTMLFrame.cpp | 29 + layout/html/base/src/nsHTMLParts.h | 34 + layout/html/base/src/nsHTMLReflowCommand.cpp | 6 + layout/html/base/src/nsHTMLReflowCommand.h | 1 + layout/html/base/src/nsPlaceholderFrame.cpp | 3 + layout/html/base/src/nsPlaceholderFrame.h | 3 + .../html/content/src/nsGenericHTMLElement.cpp | 2 +- .../html/content/src/nsHTMLGenericContent.cpp | 2732 +++++++++++++++++ .../html/document/src/nsHTMLContentSink.cpp | 13 +- layout/html/forms/src/nsInputButton.cpp | 12 + layout/html/forms/src/nsInputCheckbox.cpp | 12 + layout/html/forms/src/nsInputFile.cpp | 12 + layout/html/forms/src/nsInputRadio.cpp | 12 + layout/html/forms/src/nsInputText.cpp | 12 + layout/html/forms/src/nsSelect.cpp | 11 + layout/html/style/src/nsHTMLStyleSheet.cpp | 344 ++- layout/style/nsHTMLStyleSheet.cpp | 344 ++- layout/style/nsStyleSet.cpp | 105 +- 73 files changed, 5162 insertions(+), 96 deletions(-) create mode 100644 layout/base/public/nsIStyleFrameConstruction.h create mode 100644 layout/html/content/src/nsHTMLGenericContent.cpp diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 706c54eac0dd..a9b9ecb11919 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -163,7 +163,8 @@ public: virtual void ContentChanged(nsIContent* aContent, nsISupports* aSubContent) = 0; - virtual void ContentAppended(nsIContent* aContainer) = 0; + virtual void ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; virtual void ContentInserted(nsIContent* aContainer, nsIContent* aChild, diff --git a/content/base/public/nsIDocumentObserver.h b/content/base/public/nsIDocumentObserver.h index 5cc18db60686..56715c03789e 100644 --- a/content/base/public/nsIDocumentObserver.h +++ b/content/base/public/nsIDocumentObserver.h @@ -98,9 +98,12 @@ public: * * @param aDocument The document being observed * @param aContainer the container that had a new child appended + * @param aNewIndexInContainer the index in the container of the first + * new child */ NS_IMETHOD ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer) = 0; + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; /** * Notification that content has been inserted. This method is called diff --git a/content/base/src/nsContentList.cpp b/content/base/src/nsContentList.cpp index dcab6a5be31c..20792e7e395c 100644 --- a/content/base/src/nsContentList.cpp +++ b/content/base/src/nsContentList.cpp @@ -277,7 +277,8 @@ void nsContentList::PopulateSelf(nsIContent *aContent) NS_IMETHODIMP nsContentList::ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer) + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) { PRInt32 count; aContainer->ChildCount(count); diff --git a/content/base/src/nsContentList.h b/content/base/src/nsContentList.h index be8ef4dff473..3a373282dc88 100644 --- a/content/base/src/nsContentList.h +++ b/content/base/src/nsContentList.h @@ -69,7 +69,8 @@ public: nsIContent* aContent, nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer); + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); NS_IMETHOD ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 4e900605893e..90cf2ea6693b 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -507,12 +507,13 @@ void nsDocument::ContentChanged(nsIContent* aContent, } } -void nsDocument::ContentAppended(nsIContent* aContainer) +void nsDocument::ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer) { PRInt32 count = mObservers.Count(); for (PRInt32 i = 0; i < count; i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; - observer->ContentAppended(this, aContainer); + observer->ContentAppended(this, aContainer, aNewIndexInContainer); } } diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 16abff60fd0c..bcb6dd37517c 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -140,7 +140,8 @@ public: virtual void ContentChanged(nsIContent* aContent, nsISupports* aSubContent); - virtual void ContentAppended(nsIContent* aContainer); + virtual void ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer); virtual void ContentInserted(nsIContent* aContainer, nsIContent* aChild, diff --git a/content/base/src/nsStyleSet.cpp b/content/base/src/nsStyleSet.cpp index 25819769c79c..cdd7b99ffb74 100644 --- a/content/base/src/nsStyleSet.cpp +++ b/content/base/src/nsStyleSet.cpp @@ -22,8 +22,13 @@ #include "nsISupportsArray.h" #include "nsIFrame.h" #include "nsHashtable.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIContent.h" +#include "nsIStyleFrameConstruction.h" static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class ContextKey : public nsHashKey { public: @@ -207,6 +212,31 @@ public: nsIFrame* aParentFrame, PRBool aForceUnique = PR_FALSE); + NS_IMETHODIMP ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); + NS_IMETHOD ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + // xxx style rules enumeration virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); @@ -240,13 +270,15 @@ protected: nsISupportsArray* mDocSheets; nsISupportsArray* mBackstopSheets; nsHashtable mStyleContexts; + nsIStyleFrameConstruction* mFrameConstructor; }; StyleSetImpl::StyleSetImpl() : mOverrideSheets(nsnull), mDocSheets(nsnull), - mBackstopSheets(nsnull) + mBackstopSheets(nsnull), + mFrameConstructor(nsnull) { NS_INIT_REFCNT(); } @@ -262,6 +294,7 @@ StyleSetImpl::~StyleSetImpl() NS_IF_RELEASE(mOverrideSheets); NS_IF_RELEASE(mDocSheets); NS_IF_RELEASE(mBackstopSheets); + NS_IF_RELEASE(mFrameConstructor); mStyleContexts.Enumerate(ReleaseContext); } @@ -340,6 +373,9 @@ void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet) NS_PRECONDITION(nsnull != aSheet, "null arg"); if (EnsureArray(&mDocSheets)) { mDocSheets->AppendElement(aSheet); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -350,6 +386,9 @@ void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aAfterSheet); mDocSheets->InsertElementAt(aSheet, ++index); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -360,6 +399,9 @@ void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aBeforeSheet); mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0)); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -665,6 +707,67 @@ nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext, return result; } +NS_IMETHODIMP StyleSetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + return mFrameConstructor->ConstructFrame(aPresContext, aContent, + aParentFrame, aFrameSubTree); +} + +NS_IMETHODIMP StyleSetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + return mFrameConstructor->ContentAppended(aPresContext, aDocument, + aContainer, aNewIndexInContainer); +} + +NS_IMETHODIMP StyleSetImpl::ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentInserted(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentReplaced(aPresContext, aDocument, aContainer, + aOldChild, aNewChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentRemoved(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + // xxx style rules enumeration void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets) diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 6867fa7932d6..6131b572a56c 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -3266,7 +3266,7 @@ nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify) if (nsnull != doc) { aKid->SetDocument(doc); if (aNotify) { - doc->ContentAppended(mContent); + doc->ContentAppended(mContent, mChildren->Count() - 1); } } } diff --git a/content/html/content/src/nsHTMLAtoms.cpp b/content/html/content/src/nsHTMLAtoms.cpp index aa8d1299c88e..dc4e0cae5889 100644 --- a/content/html/content/src/nsHTMLAtoms.cpp +++ b/content/html/content/src/nsHTMLAtoms.cpp @@ -107,6 +107,7 @@ nsIAtom* nsHTMLAtoms::id; nsIAtom* nsHTMLAtoms::iframe; nsIAtom* nsHTMLAtoms::img; nsIAtom* nsHTMLAtoms::index; +nsIAtom* nsHTMLAtoms::input; nsIAtom* nsHTMLAtoms::ismap; nsIAtom* nsHTMLAtoms::label; nsIAtom* nsHTMLAtoms::lang; @@ -171,6 +172,7 @@ nsIAtom* nsHTMLAtoms::rules; nsIAtom* nsHTMLAtoms::scheme; nsIAtom* nsHTMLAtoms::scope; nsIAtom* nsHTMLAtoms::scrolling; +nsIAtom* nsHTMLAtoms::select; nsIAtom* nsHTMLAtoms::selected; nsIAtom* nsHTMLAtoms::selectedindex; nsIAtom* nsHTMLAtoms::shape; @@ -189,6 +191,7 @@ nsIAtom* nsHTMLAtoms::tabstop; nsIAtom* nsHTMLAtoms::target; nsIAtom* nsHTMLAtoms::td; nsIAtom* nsHTMLAtoms::text; +nsIAtom* nsHTMLAtoms::textarea; nsIAtom* nsHTMLAtoms::th; nsIAtom* nsHTMLAtoms::title; nsIAtom* nsHTMLAtoms::top; @@ -304,6 +307,7 @@ void nsHTMLAtoms::AddrefAtoms() iframe = NS_NewAtom("IFRAME"); img = NS_NewAtom("IMG"); index = NS_NewAtom("INDEX"); + input = NS_NewAtom("INPUT"); ismap = NS_NewAtom("ISMAP"); label = NS_NewAtom("LABEL"); lang = NS_NewAtom("LANG"); @@ -367,6 +371,7 @@ void nsHTMLAtoms::AddrefAtoms() scheme = NS_NewAtom("SCHEME"); scope = NS_NewAtom("SCOPE"); scrolling = NS_NewAtom("SCROLLING"); + select = NS_NewAtom("SELECT"); selected = NS_NewAtom("SELECTED"); selectedindex = NS_NewAtom("SELECTEDINDEX"); shape = NS_NewAtom("SHAPE"); @@ -385,6 +390,7 @@ void nsHTMLAtoms::AddrefAtoms() target = NS_NewAtom("TARGET"); td = NS_NewAtom("TD"); text = NS_NewAtom("TEXT"); + textarea = NS_NewAtom("TEXTAREA"); th = NS_NewAtom("TH"); title = NS_NewAtom("TITLE"); top = NS_NewAtom("TOP"); @@ -493,6 +499,8 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(id); NS_RELEASE(iframe); NS_RELEASE(img); + NS_RELEASE(index); + NS_RELEASE(input); NS_RELEASE(ismap); NS_RELEASE(label); NS_RELEASE(lang); @@ -555,6 +563,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(scheme); NS_RELEASE(scope); NS_RELEASE(scrolling); + NS_RELEASE(select); NS_RELEASE(selected); NS_RELEASE(selectedindex); NS_RELEASE(shape); @@ -572,6 +581,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(target); NS_RELEASE(td); NS_RELEASE(text); + NS_RELEASE(textarea); NS_RELEASE(th); NS_RELEASE(top); NS_RELEASE(toppadding); diff --git a/content/html/content/src/nsHTMLAtoms.h b/content/html/content/src/nsHTMLAtoms.h index f7572d6f58ae..0a55c79afe29 100644 --- a/content/html/content/src/nsHTMLAtoms.h +++ b/content/html/content/src/nsHTMLAtoms.h @@ -134,6 +134,7 @@ public: static nsIAtom* iframe; static nsIAtom* img; static nsIAtom* index; + static nsIAtom* input; static nsIAtom* ismap; static nsIAtom* label; @@ -205,6 +206,7 @@ public: static nsIAtom* scheme; static nsIAtom* scope; static nsIAtom* scrolling; + static nsIAtom* select; static nsIAtom* selected; static nsIAtom* selectedindex; static nsIAtom* shape; @@ -224,6 +226,7 @@ public: static nsIAtom* target; static nsIAtom* td; static nsIAtom* text; + static nsIAtom* textarea; static nsIAtom* th; static nsIAtom* title; static nsIAtom* top; diff --git a/content/html/document/src/nsHTMLContentSink.cpp b/content/html/document/src/nsHTMLContentSink.cpp index 107b2194bf0b..462063f3f437 100644 --- a/content/html/document/src/nsHTMLContentSink.cpp +++ b/content/html/document/src/nsHTMLContentSink.cpp @@ -170,6 +170,7 @@ public: nsIHTMLContent* mRoot; nsIHTMLContent* mBody; + PRInt32 mBodyChildCount; nsIHTMLContent* mFrameset; nsIHTMLContent* mHead; nsString* mTitle; @@ -1378,7 +1379,8 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) ("HTMLContentSink::DidBuildModel: layout final content")); // Reflow the last batch of content - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); ScrollToRef(); mDocument->EndLoad(); @@ -1391,7 +1393,8 @@ HTMLContentSink::WillInterrupt() SINK_TRACE(SINK_TRACE_CALLS, ("HTMLContentSink::WillInterrupt: this=%p", this)); if (mDirty && !mInMonolithicContainer) { - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); mDirty = PR_FALSE; } return NS_OK; @@ -1571,6 +1574,7 @@ HTMLContentSink::OpenBody(const nsIParserNode& aNode) return rv; } mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent; + mBodyChildCount = 0; NS_ADDREF(mBody); StartLayout(); @@ -1592,7 +1596,8 @@ HTMLContentSink::CloseBody(const nsIParserNode& aNode) if (didFlush) { // Trigger a reflow for the flushed text - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); } return NS_OK; @@ -1815,7 +1820,7 @@ HTMLContentSink::StartLayout() nsIPresContext* cx = shell->GetPresContext(); nsRect r; cx->GetVisibleArea(r); - shell->ResizeReflow(r.width, r.height); + shell->InitialReflow(r.width, r.height); NS_RELEASE(cx); // Now trigger a refresh diff --git a/content/html/style/src/nsHTMLStyleSheet.cpp b/content/html/style/src/nsHTMLStyleSheet.cpp index d214750b6387..ff0a65eab4c9 100644 --- a/content/html/style/src/nsHTMLStyleSheet.cpp +++ b/content/html/style/src/nsHTMLStyleSheet.cpp @@ -35,10 +35,17 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsHTMLIIDs.h" +#include "nsIStyleFrameConstruction.h" +#include "nsHTMLParts.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsStyleConsts.h" +#include "nsTableOuterFrame.h" static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class HTMLAnchorRule : public nsIStyleRule { @@ -173,7 +180,8 @@ nsHashKey* AttributeKey::Clone(void) const // ----------------------------------------------------------- -class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet, + public nsIStyleFrameConstruction { public: void* operator new(size_t size); void* operator new(size_t size, nsIArena* aArena); @@ -217,6 +225,15 @@ public: NS_IMETHOD UnsetAttributeFor(nsIAtom* aAttribute, nsIHTMLContent* aContent, nsIHTMLAttributes*& aAttributes); + NS_IMETHOD ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); // XXX style rule enumerations @@ -239,6 +256,14 @@ protected: PRInt32 aAttrCount, nsIHTMLAttributes*& aAttributes); + nsresult ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent); + + nsresult CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame); + protected: PRUint32 mInHeap : 1; PRUint32 mRefCnt : 31; @@ -330,8 +355,13 @@ nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, AddRef(); return NS_OK; } + if (aIID.Equals(kIStyleFrameConstructionIID)) { + *aInstancePtrResult = (void*) ((nsIStyleFrameConstruction*)this); + AddRef(); + return NS_OK; + } if (aIID.Equals(kISupportsIID)) { - *aInstancePtrResult = (void*) ((nsISupports*)this); + *aInstancePtrResult = (void*) this; AddRef(); return NS_OK; } @@ -816,6 +846,316 @@ NS_IMETHODIMP HTMLStyleSheetImpl::UnsetAttributeFor(nsIAtom* aAttribute, } +nsresult HTMLStyleSheetImpl::ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent) +{ + nsIFrame* childList = nsnull; + nsIFrame* lastChildFrame = nsnull; + PRInt32 count; + aContent->ChildCount(count); + + for (PRInt32 i = 0; i < count; i++) { + nsIContent* childContent; + aContent->ChildAt(i, childContent); + + if (nsnull != childContent) { + nsIFrame* childFrame; + + // Construct a child frame + ConstructFrame(aPresContext, childContent, aFrame, childFrame); + + if (nsnull != childFrame) { + // Link the frame into the child list + if (nsnull == lastChildFrame) { + childList = childFrame; + } else { + lastChildFrame->SetNextSibling(childFrame); + } + lastChildFrame = childFrame; + } + + NS_RELEASE(childContent); + } + } + + // Initialize the frame giving it its child list. + // XXX Should we call Init(), or just return the child list and let the + // caller call Init()? + aFrame->Init(*aPresContext, childList); + return NS_OK; +} + +nsresult +HTMLStyleSheetImpl::CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame) +{ + nsresult rv; + + // Figure out which type of input frame to create + nsAutoString val; + if (NS_OK == aContent->GetAttribute(nsAutoString("type"), val)) { + if (val.EqualsIgnoreCase("submit")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("reset")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("button")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("checkbox")) { + rv = NS_NewInputCheckboxFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("file")) { + rv = NS_NewInputFileFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("hidden")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("image")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("password")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("radio")) { + rv = NS_NewInputRadioFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("text")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + } else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + + return rv; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + // Get the tag + nsIAtom* tag; + aContent->GetTag(tag); + + aFrameSubTree = nsnull; + + // Resolve the style context. + // XXX Cheesy hack for text + nsIStyleContext* styleContext; + if (nsnull == tag) { + styleContext = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::text, aParentFrame); + } else { + styleContext = aPresContext->ResolveStyleContextFor(aContent, aParentFrame); + } + + // Create a frame. + if (nsnull == aParentFrame) { + // This should only be the case for the root content object. + // XXX Add assertion... + nsIFrame* rootFrame; + + // Create the root frame and set its style context + NS_NewHTMLFrame(aContent, nsnull, rootFrame); + rootFrame->SetStyleContext(aPresContext, styleContext); + + // Bind root frame to root view (and root window) + nsIPresShell* presShell = aPresContext->GetShell(); + nsIViewManager* viewManager = presShell->GetViewManager(); + nsIView* rootView; + + NS_RELEASE(presShell); + viewManager->GetRootView(rootView); + rootFrame->SetView(rootView); + NS_RELEASE(viewManager); + + // Process the children + ProcessChildren(aPresContext, rootFrame, aContent); + + // Return the frame sub-tree + aFrameSubTree = rootFrame; + + } else { + nsIFrame* frame = nsnull; + nsresult rv = NS_OK; + + // Handle specific frame types + if (nsnull == tag) { + rv = NS_NewTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::applet == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::body == tag) { + rv = NS_NewBodyFrame(aContent, aParentFrame, frame); + + // Process the children + ProcessChildren(aPresContext, frame, aContent); + } + else if (nsHTMLAtoms::frameset == tag) { + rv = NS_NewHTMLFramesetFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::br == tag) { + rv = NS_NewBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::embed == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::hr == tag) { + rv = NS_NewHRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::img == tag) { + rv = NS_NewImageFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::object == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::spacer == tag) { + rv = NS_NewSpacerFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::wbr == tag) { + rv = NS_NewWBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::table == tag) { + rv = nsTableOuterFrame::NewFrame(&frame, aContent, aParentFrame); + } + else if (nsHTMLAtoms::input == tag) { + rv = CreateInputFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::textarea == tag) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::select == tag) { + rv = NS_NewHTMLSelectFrame(aContent, aParentFrame, frame); + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + + // XXX add code in here to force the odd ones into the empty frame? + // AREA, HEAD, META, MAP, etc... + + if (nsnull == frame) { + // When there is no explicit frame to create, assume it's a + // container and let style dictate the rest. + const nsStyleDisplay* styleDisplay = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + // Use style to choose what kind of frame to create + nsresult rv; + switch (styleDisplay->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + rv = NS_NewCSSBlockFrame(&frame, aContent, aParentFrame); + ProcessChildren(aPresContext, frame, aContent); + break; + + case NS_STYLE_DISPLAY_INLINE: + rv = NS_NewCSSInlineFrame(&frame, aContent, aParentFrame); + break; + + default: + // XXX Don't create a placeholder frame for content that's not + // displayed... +#if 0 + // Create an empty frame for holding content that is not being + // reflowed. + rv = nsFrame::NewFrame(&frame, aContent, aParentFrame); +#endif + break; + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + } + + if (nsnull != frame) { + frame->SetStyleContext(aPresContext, styleContext); + } + aFrameSubTree = frame; + } + + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return NS_OK; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + nsIPresShell* shell = aPresContext->GetShell(); + nsIContent* parentContainer = aContainer; + while (nsnull != parentContainer) { + nsIFrame* parentFrame = shell->FindFrameWithContent(parentContainer); + if (nsnull != parentFrame) { + // Get the parent frame's last-in-flow + nsIFrame* nextInFlow = parentFrame; + while (nsnull != nextInFlow) { + parentFrame->GetNextInFlow(nextInFlow); + if (nsnull != nextInFlow) { + parentFrame = nextInFlow; + } + } + + // Create some new frames + PRInt32 count; + nsIFrame* lastChildFrame = nsnull; + nsIFrame* firstAppendedFrame = nsnull; + + aContainer->ChildCount(count); + + for (PRInt32 i = aNewIndexInContainer; i < count; i++) { + nsIContent* child; + nsIFrame* frame; + + aContainer->ChildAt(i, child); + ConstructFrame(aPresContext, child, parentFrame, frame); + + // Link the frame into the child frame list + if (nsnull == lastChildFrame) { + firstAppendedFrame = frame; + } else { + lastChildFrame->SetNextSibling(frame); + } + + // XXX We should probably mark the frame as being dirty: that way the + // parent frame can easily identify the newly added frames. Either that + // or pass along in count in which case they must be contiguus... + lastChildFrame = frame; + } + + // Notify the parent frame with a reflow command, passing it the list of + // new frames. + nsIReflowCommand* reflowCmd; + nsresult result; + + result = NS_NewHTMLReflowCommand(&reflowCmd, parentFrame, + nsIReflowCommand::FrameAppended, + firstAppendedFrame); + if (NS_SUCCEEDED(result)) { + shell->AppendReflowCommand(reflowCmd); + } + break; + } + parentContainer->GetParent(parentContainer); + } + + NS_RELEASE(shell); + return NS_OK; +} void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const { diff --git a/content/shared/public/nsHTMLAtoms.h b/content/shared/public/nsHTMLAtoms.h index f7572d6f58ae..0a55c79afe29 100644 --- a/content/shared/public/nsHTMLAtoms.h +++ b/content/shared/public/nsHTMLAtoms.h @@ -134,6 +134,7 @@ public: static nsIAtom* iframe; static nsIAtom* img; static nsIAtom* index; + static nsIAtom* input; static nsIAtom* ismap; static nsIAtom* label; @@ -205,6 +206,7 @@ public: static nsIAtom* scheme; static nsIAtom* scope; static nsIAtom* scrolling; + static nsIAtom* select; static nsIAtom* selected; static nsIAtom* selectedindex; static nsIAtom* shape; @@ -224,6 +226,7 @@ public: static nsIAtom* target; static nsIAtom* td; static nsIAtom* text; + static nsIAtom* textarea; static nsIAtom* th; static nsIAtom* title; static nsIAtom* top; diff --git a/content/shared/src/nsHTMLAtoms.cpp b/content/shared/src/nsHTMLAtoms.cpp index aa8d1299c88e..dc4e0cae5889 100644 --- a/content/shared/src/nsHTMLAtoms.cpp +++ b/content/shared/src/nsHTMLAtoms.cpp @@ -107,6 +107,7 @@ nsIAtom* nsHTMLAtoms::id; nsIAtom* nsHTMLAtoms::iframe; nsIAtom* nsHTMLAtoms::img; nsIAtom* nsHTMLAtoms::index; +nsIAtom* nsHTMLAtoms::input; nsIAtom* nsHTMLAtoms::ismap; nsIAtom* nsHTMLAtoms::label; nsIAtom* nsHTMLAtoms::lang; @@ -171,6 +172,7 @@ nsIAtom* nsHTMLAtoms::rules; nsIAtom* nsHTMLAtoms::scheme; nsIAtom* nsHTMLAtoms::scope; nsIAtom* nsHTMLAtoms::scrolling; +nsIAtom* nsHTMLAtoms::select; nsIAtom* nsHTMLAtoms::selected; nsIAtom* nsHTMLAtoms::selectedindex; nsIAtom* nsHTMLAtoms::shape; @@ -189,6 +191,7 @@ nsIAtom* nsHTMLAtoms::tabstop; nsIAtom* nsHTMLAtoms::target; nsIAtom* nsHTMLAtoms::td; nsIAtom* nsHTMLAtoms::text; +nsIAtom* nsHTMLAtoms::textarea; nsIAtom* nsHTMLAtoms::th; nsIAtom* nsHTMLAtoms::title; nsIAtom* nsHTMLAtoms::top; @@ -304,6 +307,7 @@ void nsHTMLAtoms::AddrefAtoms() iframe = NS_NewAtom("IFRAME"); img = NS_NewAtom("IMG"); index = NS_NewAtom("INDEX"); + input = NS_NewAtom("INPUT"); ismap = NS_NewAtom("ISMAP"); label = NS_NewAtom("LABEL"); lang = NS_NewAtom("LANG"); @@ -367,6 +371,7 @@ void nsHTMLAtoms::AddrefAtoms() scheme = NS_NewAtom("SCHEME"); scope = NS_NewAtom("SCOPE"); scrolling = NS_NewAtom("SCROLLING"); + select = NS_NewAtom("SELECT"); selected = NS_NewAtom("SELECTED"); selectedindex = NS_NewAtom("SELECTEDINDEX"); shape = NS_NewAtom("SHAPE"); @@ -385,6 +390,7 @@ void nsHTMLAtoms::AddrefAtoms() target = NS_NewAtom("TARGET"); td = NS_NewAtom("TD"); text = NS_NewAtom("TEXT"); + textarea = NS_NewAtom("TEXTAREA"); th = NS_NewAtom("TH"); title = NS_NewAtom("TITLE"); top = NS_NewAtom("TOP"); @@ -493,6 +499,8 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(id); NS_RELEASE(iframe); NS_RELEASE(img); + NS_RELEASE(index); + NS_RELEASE(input); NS_RELEASE(ismap); NS_RELEASE(label); NS_RELEASE(lang); @@ -555,6 +563,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(scheme); NS_RELEASE(scope); NS_RELEASE(scrolling); + NS_RELEASE(select); NS_RELEASE(selected); NS_RELEASE(selectedindex); NS_RELEASE(shape); @@ -572,6 +581,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(target); NS_RELEASE(td); NS_RELEASE(text); + NS_RELEASE(textarea); NS_RELEASE(th); NS_RELEASE(top); NS_RELEASE(toppadding); diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 4565b938a9a7..ffdd8ea8a776 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -71,6 +71,15 @@ public: // Make shell stop being a document observer virtual void EndObservingDocument() = 0; + /** + * Perform the initial reflow. Constructs the frame for the root content + * object and then reflows the frame model into the specified width and + * height. + * + * The coordinates for aWidth and aHeight must be in standard nscoord's. + */ + NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight) = 0; + /** * Reflow the frame model into a new width and height. The * coordinates for aWidth and aHeight must be in standard nscoord's. diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 8927b064b6e8..a0c417c25b95 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -551,3 +551,83 @@ nsPresContext::GetEventStateManager(nsIEventStateManager** aManager) return NS_OK; } +NS_IMETHODIMP +nsPresContext::ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ConstructFrame(this, aContent, aParentFrame, aFrameSubTree); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentAppended(this, aDocument, aContainer, aNewIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentInserted(this, aDocument, aContainer, aChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentReplaced(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentReplaced(this, aDocument, aContainer, aOldChild, + aNewChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentRemoved(this, aDocument, aContainer, aChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 1b41a5bb39df..de7abb6fd6ae 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -26,6 +26,7 @@ struct nsFont; class nsIContent; +class nsIDocument; class nsIDeviceContext; class nsIFontMetrics; class nsIFrame; @@ -214,6 +215,35 @@ public: virtual nsIDeviceContext * GetDeviceContext() const = 0; NS_IMETHOD GetEventStateManager(nsIEventStateManager** aManager) = 0; + + /** + * Handles association of elements in the content model to frames. Finds the + * applicable construction rule, applies the action, and produces a sub-tree + * of frame objects. Can return nsnull. + */ + NS_IMETHOD ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) = 0; + + /** + * Notifications of content changes + */ + NS_IMETHOD ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; + NS_IMETHOD ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentReplaced(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; }; // Bit values for StartLoadImage's aImageStatus diff --git a/layout/base/public/Makefile b/layout/base/public/Makefile index 7ee095837d6c..6c8c8d24684a 100644 --- a/layout/base/public/Makefile +++ b/layout/base/public/Makefile @@ -41,6 +41,7 @@ EXPORTS = \ nsIStyleSet.h \ nsIStyleSheet.h \ nsITextContent.h \ + nsIStyleFrameConstruction.h \ $(NULL) include $(DEPTH)/config/config.mk diff --git a/layout/base/public/makefile.win b/layout/base/public/makefile.win index 94293acd8c78..894679dcd2d8 100644 --- a/layout/base/public/makefile.win +++ b/layout/base/public/makefile.win @@ -39,6 +39,7 @@ EXPORTS = \ nsIStyleSet.h \ nsIStyleSheet.h \ nsITextContent.h \ + nsIStyleFrameConstruction.h \ $(NULL) MODULE=raptor diff --git a/layout/base/public/nsIDocument.h b/layout/base/public/nsIDocument.h index 706c54eac0dd..a9b9ecb11919 100644 --- a/layout/base/public/nsIDocument.h +++ b/layout/base/public/nsIDocument.h @@ -163,7 +163,8 @@ public: virtual void ContentChanged(nsIContent* aContent, nsISupports* aSubContent) = 0; - virtual void ContentAppended(nsIContent* aContainer) = 0; + virtual void ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; virtual void ContentInserted(nsIContent* aContainer, nsIContent* aChild, diff --git a/layout/base/public/nsIDocumentObserver.h b/layout/base/public/nsIDocumentObserver.h index 5cc18db60686..56715c03789e 100644 --- a/layout/base/public/nsIDocumentObserver.h +++ b/layout/base/public/nsIDocumentObserver.h @@ -98,9 +98,12 @@ public: * * @param aDocument The document being observed * @param aContainer the container that had a new child appended + * @param aNewIndexInContainer the index in the container of the first + * new child */ NS_IMETHOD ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer) = 0; + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; /** * Notification that content has been inserted. This method is called diff --git a/layout/base/public/nsIFrame.h b/layout/base/public/nsIFrame.h index 2460db88b5c9..c89f8e240765 100644 --- a/layout/base/public/nsIFrame.h +++ b/layout/base/public/nsIFrame.h @@ -260,10 +260,29 @@ typedef PRBool nsDidReflowStatus; * * Frames are NOT reference counted. Use the DeleteFrame() member function * to delete a frame + * + * XXX This should probably be changed so it's consistent with the way nsIView + * (which is also not reference counted) is defined... */ class nsIFrame : private nsISupports { public: + /** + * Initialize the frame passing it its child frame list. + * + * This member function is called for all frames just after the frame is + * constructed. + * + * You should reflow the frames when you get your 'initial' reflow + * notification. + * + * XXX Should we also pass in the child count? + * + * @param aChildList list of child frames. May be NULL + * @see #Reflow() + */ + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList) = 0; + /** * QueryInterface() defined in nsISupports. This is the only member * function of nsISupports that is public. @@ -466,9 +485,12 @@ public: * FrameAppended incremental reflow command. You then handle the incremental * reflow command by creating frames for the appended content. */ + // XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) = 0; +#endif /** * This call is invoked when content is inserted in the content diff --git a/layout/base/public/nsIPresContext.h b/layout/base/public/nsIPresContext.h index 1b41a5bb39df..de7abb6fd6ae 100644 --- a/layout/base/public/nsIPresContext.h +++ b/layout/base/public/nsIPresContext.h @@ -26,6 +26,7 @@ struct nsFont; class nsIContent; +class nsIDocument; class nsIDeviceContext; class nsIFontMetrics; class nsIFrame; @@ -214,6 +215,35 @@ public: virtual nsIDeviceContext * GetDeviceContext() const = 0; NS_IMETHOD GetEventStateManager(nsIEventStateManager** aManager) = 0; + + /** + * Handles association of elements in the content model to frames. Finds the + * applicable construction rule, applies the action, and produces a sub-tree + * of frame objects. Can return nsnull. + */ + NS_IMETHOD ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) = 0; + + /** + * Notifications of content changes + */ + NS_IMETHOD ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; + NS_IMETHOD ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentReplaced(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; }; // Bit values for StartLoadImage's aImageStatus diff --git a/layout/base/public/nsIPresShell.h b/layout/base/public/nsIPresShell.h index 4565b938a9a7..ffdd8ea8a776 100644 --- a/layout/base/public/nsIPresShell.h +++ b/layout/base/public/nsIPresShell.h @@ -71,6 +71,15 @@ public: // Make shell stop being a document observer virtual void EndObservingDocument() = 0; + /** + * Perform the initial reflow. Constructs the frame for the root content + * object and then reflows the frame model into the specified width and + * height. + * + * The coordinates for aWidth and aHeight must be in standard nscoord's. + */ + NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight) = 0; + /** * Reflow the frame model into a new width and height. The * coordinates for aWidth and aHeight must be in standard nscoord's. diff --git a/layout/base/public/nsIReflowCommand.h b/layout/base/public/nsIReflowCommand.h index 23df544105af..fdd0356d88d5 100644 --- a/layout/base/public/nsIReflowCommand.h +++ b/layout/base/public/nsIReflowCommand.h @@ -102,6 +102,11 @@ public: */ NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const = 0; + /** + * Change the target of the reflow command. + */ + NS_IMETHOD SetTarget(nsIFrame* aTargetFrame) = 0; + /** * Get the type of reflow command. */ diff --git a/layout/base/public/nsIStyleFrameConstruction.h b/layout/base/public/nsIStyleFrameConstruction.h new file mode 100644 index 000000000000..4ff15c61c775 --- /dev/null +++ b/layout/base/public/nsIStyleFrameConstruction.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsIStyleFrameConstruction_h___ +#define nsIStyleFrameConstruction_h___ + +class nsIPresContext; +class nsIContent; +class nsIFrame; + +// IID for the nsIStyleSet interface {a6cf9066-15b3-11d2-932e-00805f8add32} +#define NS_ISTYLE_FRAME_CONSTRUCTION_IID \ +{0xa6cf9066, 0x15b3, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}} + +class nsIStyleFrameConstruction : public nsISupports { +public: + /** + * Handles association of elements in the content model to frames. Finds the + * applicable construction rule, applies the action, and produces a sub-tree + * of frame objects. Can return nsnull. + */ + NS_IMETHOD ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) = 0; + + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; +}; + +#endif /* nsIStyleFrameConstruction_h___ */ diff --git a/layout/base/public/nsIStyleSet.h b/layout/base/public/nsIStyleSet.h index f37934716ab2..3c9233629394 100644 --- a/layout/base/public/nsIStyleSet.h +++ b/layout/base/public/nsIStyleSet.h @@ -30,6 +30,7 @@ class nsIStyleContext; class nsIPresContext; class nsIContent; class nsIFrame; +class nsIDocument; // IID for the nsIStyleSet interface {e59396b0-b244-11d1-8031-006008159b5a} @@ -87,6 +88,36 @@ public: nsIFrame* aParentFrame, PRBool aForceUnique = PR_FALSE) = 0; + // Handles association of elements in the content model to frames. Finds the + // applicable construction rule, applies the action, and produces a sub-tree + // of frame objects. Can return nsnull. + NS_IMETHOD ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) = 0; + + // Notifications of changes to the content mpodel + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; + NS_IMETHOD ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + // xxx style rules enumeration virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) = 0; diff --git a/layout/base/public/nsPresContext.h b/layout/base/public/nsPresContext.h index 1b41a5bb39df..de7abb6fd6ae 100644 --- a/layout/base/public/nsPresContext.h +++ b/layout/base/public/nsPresContext.h @@ -26,6 +26,7 @@ struct nsFont; class nsIContent; +class nsIDocument; class nsIDeviceContext; class nsIFontMetrics; class nsIFrame; @@ -214,6 +215,35 @@ public: virtual nsIDeviceContext * GetDeviceContext() const = 0; NS_IMETHOD GetEventStateManager(nsIEventStateManager** aManager) = 0; + + /** + * Handles association of elements in the content model to frames. Finds the + * applicable construction rule, applies the action, and produces a sub-tree + * of frame objects. Can return nsnull. + */ + NS_IMETHOD ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) = 0; + + /** + * Notifications of content changes + */ + NS_IMETHOD ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) = 0; + NS_IMETHOD ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentReplaced(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) = 0; + NS_IMETHOD ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) = 0; }; // Bit values for StartLoadImage's aImageStatus diff --git a/layout/base/src/nsContainerFrame.cpp b/layout/base/src/nsContainerFrame.cpp index 6370054e631e..978786df66a0 100644 --- a/layout/base/src/nsContainerFrame.cpp +++ b/layout/base/src/nsContainerFrame.cpp @@ -55,6 +55,16 @@ nsContainerFrame::SizeOf(nsISizeOfHandler* aHandler) const return NS_OK; } +NS_IMETHODIMP +nsContainerFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + NS_PRECONDITION(nsnull == mFirstChild, "already initialized"); + + mFirstChild = aChildList; + mChildCount = LengthOf(mFirstChild); + return NS_OK; +} + NS_IMETHODIMP nsContainerFrame::DeleteFrame(nsIPresContext& aPresContext) { @@ -1239,6 +1249,8 @@ void nsContainerFrame::CheckContentOffsets() void nsContainerFrame::PreReflowCheck() { + // XXX CONSTRUCTION +#if 0 PRInt32 len = LengthOf(mFirstChild); NS_ASSERTION(len == mChildCount, "bad child count"); @@ -1249,10 +1261,13 @@ void nsContainerFrame::PreReflowCheck() CheckContentOffsets(); } VerifyLastIsComplete(); +#endif } void nsContainerFrame::PostReflowCheck(nsReflowStatus aStatus) { + // XXX CONSTRUCTION +#if 0 PRInt32 len = LengthOf(mFirstChild) ; NS_ASSERTION(len == mChildCount, "bad child count"); @@ -1263,6 +1278,7 @@ void nsContainerFrame::PostReflowCheck(nsReflowStatus aStatus) CheckContentOffsets(); } VerifyLastIsComplete(); +#endif } /** diff --git a/layout/base/src/nsContainerFrame.h b/layout/base/src/nsContainerFrame.h index a93248173cf6..2d58e28dd62a 100644 --- a/layout/base/src/nsContainerFrame.h +++ b/layout/base/src/nsContainerFrame.h @@ -107,6 +107,8 @@ class nsContainerFrame : public nsSplittableFrame public: NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const; + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); + NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext); /** * Default implementation is to use the content delegate to create a new diff --git a/layout/base/src/nsContentList.cpp b/layout/base/src/nsContentList.cpp index dcab6a5be31c..20792e7e395c 100644 --- a/layout/base/src/nsContentList.cpp +++ b/layout/base/src/nsContentList.cpp @@ -277,7 +277,8 @@ void nsContentList::PopulateSelf(nsIContent *aContent) NS_IMETHODIMP nsContentList::ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer) + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) { PRInt32 count; aContainer->ChildCount(count); diff --git a/layout/base/src/nsContentList.h b/layout/base/src/nsContentList.h index be8ef4dff473..3a373282dc88 100644 --- a/layout/base/src/nsContentList.h +++ b/layout/base/src/nsContentList.h @@ -69,7 +69,8 @@ public: nsIContent* aContent, nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer); + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); NS_IMETHOD ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, diff --git a/layout/base/src/nsDocument.cpp b/layout/base/src/nsDocument.cpp index 4e900605893e..90cf2ea6693b 100644 --- a/layout/base/src/nsDocument.cpp +++ b/layout/base/src/nsDocument.cpp @@ -507,12 +507,13 @@ void nsDocument::ContentChanged(nsIContent* aContent, } } -void nsDocument::ContentAppended(nsIContent* aContainer) +void nsDocument::ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer) { PRInt32 count = mObservers.Count(); for (PRInt32 i = 0; i < count; i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; - observer->ContentAppended(this, aContainer); + observer->ContentAppended(this, aContainer, aNewIndexInContainer); } } diff --git a/layout/base/src/nsDocument.h b/layout/base/src/nsDocument.h index 16abff60fd0c..bcb6dd37517c 100644 --- a/layout/base/src/nsDocument.h +++ b/layout/base/src/nsDocument.h @@ -140,7 +140,8 @@ public: virtual void ContentChanged(nsIContent* aContent, nsISupports* aSubContent); - virtual void ContentAppended(nsIContent* aContainer); + virtual void ContentAppended(nsIContent* aContainer, + PRInt32 aNewIndexInContainer); virtual void ContentInserted(nsIContent* aContainer, nsIContent* aChild, diff --git a/layout/base/src/nsFrame.cpp b/layout/base/src/nsFrame.cpp index 3e66843801cd..775715658fc3 100644 --- a/layout/base/src/nsFrame.cpp +++ b/layout/base/src/nsFrame.cpp @@ -289,6 +289,16 @@ nsrefcnt nsFrame::Release(void) ///////////////////////////////////////////////////////////////////////////// // nsIFrame +NS_IMETHODIMP nsFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + if (nsnull != aChildList) { + NS_ERROR("not a container"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + NS_METHOD nsFrame::DeleteFrame(nsIPresContext& aPresContext) { //XXX Why is this done in nsFrame instead of some frame class @@ -1172,12 +1182,15 @@ NS_METHOD nsFrame::Reflow(nsIPresContext& aPresContext, return NS_OK; } +// XXX CONSTRUCTION +#if 0 NS_METHOD nsFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) { return NS_OK; } +#endif NS_METHOD nsFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, diff --git a/layout/base/src/nsFrame.h b/layout/base/src/nsFrame.h index c082e955e06f..f78cdf8c3d39 100644 --- a/layout/base/src/nsFrame.h +++ b/layout/base/src/nsFrame.h @@ -105,6 +105,7 @@ public: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); // nsIFrame + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext); NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const; NS_IMETHOD GetContent(nsIContent*& aContent) const; @@ -152,9 +153,12 @@ public: nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); + // XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, diff --git a/layout/base/src/nsPresContext.cpp b/layout/base/src/nsPresContext.cpp index 8927b064b6e8..a0c417c25b95 100644 --- a/layout/base/src/nsPresContext.cpp +++ b/layout/base/src/nsPresContext.cpp @@ -551,3 +551,83 @@ nsPresContext::GetEventStateManager(nsIEventStateManager** aManager) return NS_OK; } +NS_IMETHODIMP +nsPresContext::ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ConstructFrame(this, aContent, aParentFrame, aFrameSubTree); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentAppended(this, aDocument, aContainer, aNewIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentInserted(this, aDocument, aContainer, aChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentReplaced(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentReplaced(this, aDocument, aContainer, aOldChild, + aNewChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +nsPresContext::ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ + nsIStyleSet* set = mShell->GetStyleSet(); + if (nsnull != set) { + nsresult rv = set->ContentRemoved(this, aDocument, aContainer, aChild, aIndexInContainer); + NS_RELEASE(set); + return rv; + } + + return NS_ERROR_UNEXPECTED; +} + diff --git a/layout/base/src/nsPresContext.h b/layout/base/src/nsPresContext.h index 156efe0873e9..af9ed6a53d7f 100644 --- a/layout/base/src/nsPresContext.h +++ b/layout/base/src/nsPresContext.h @@ -74,6 +74,27 @@ public: virtual nsIDeviceContext* GetDeviceContext() const; NS_IMETHOD GetEventStateManager(nsIEventStateManager** aManager); + NS_IMETHOD ConstructFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + + NS_IMETHOD ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); + NS_IMETHOD ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentReplaced(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + protected: nsPresContext(); virtual ~nsPresContext(); diff --git a/layout/base/src/nsPresShell.cpp b/layout/base/src/nsPresShell.cpp index 80d8eb790020..6c2bdd7e03df 100644 --- a/layout/base/src/nsPresShell.cpp +++ b/layout/base/src/nsPresShell.cpp @@ -163,7 +163,8 @@ public: nsIContent* aContent, nsISupports* aSubContent); NS_IMETHOD ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer); + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); NS_IMETHOD ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, @@ -198,6 +199,7 @@ public: NS_IMETHOD ExitReflowLock(); virtual void BeginObservingDocument(); virtual void EndObservingDocument(); + NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight); NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight); virtual nsIFrame* GetRootFrame(); virtual nsIFrame* FindFrameWithContent(nsIContent* aContent); @@ -447,6 +449,79 @@ PresShell::EndObservingDocument() } } +NS_IMETHODIMP +PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) +{ + NS_PRECONDITION(nsnull == mRootFrame, "unexpected root frame"); + + EnterReflowLock(); + + if (nsnull != mPresContext) { + nsRect r(0, 0, aWidth, aHeight); + mPresContext->SetVisibleArea(r); + } + + if (nsnull == mRootFrame) { + if (nsnull != mDocument) { + nsIContent* root = mDocument->GetRootContent(); + if (nsnull != root) { +// XXX CONSTRUCTION +#if 0 + nsIContentDelegate* cd = root->GetDelegate(mPresContext); + if (nsnull != cd) { + nsIStyleContext* rootSC = + mPresContext->ResolveStyleContextFor(root, nsnull); + nsresult rv = cd->CreateFrame(mPresContext, root, nsnull, + rootSC, mRootFrame); + NS_RELEASE(rootSC); + NS_RELEASE(cd); + + // Bind root frame to root view (and root window) + nsIView* rootView; + mViewManager->GetRootView(rootView); + mRootFrame->SetView(rootView); + } +#else + // Have style sheet processor construct a frame for the + // root content object + mPresContext->ConstructFrame(root, nsnull, mRootFrame); +#endif + NS_RELEASE(root); + } + } + } + + if (nsnull != mRootFrame) { + // Kick off a top-down reflow + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, + ("enter nsPresShell::InitialReflow: %d,%d", aWidth, aHeight)); +#ifdef NS_DEBUG + if (nsIFrame::GetVerifyTreeEnable()) { + mRootFrame->VerifyTree(); + } +#endif + nsRect bounds; + mPresContext->GetVisibleArea(bounds); + nsSize maxSize(bounds.width, bounds.height); + nsReflowMetrics desiredSize(nsnull); + nsReflowStatus status; + nsReflowState reflowState(mRootFrame, eReflowReason_Initial, maxSize); + + mRootFrame->Reflow(*mPresContext, desiredSize, reflowState, status); + mRootFrame->SizeTo(desiredSize.width, desiredSize.height); +#ifdef NS_DEBUG + if (nsIFrame::GetVerifyTreeEnable()) { + mRootFrame->VerifyTree(); + } +#endif + NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow")); + } + + ExitReflowLock(); + + return NS_OK; //XXX this needs to be real. MMP +} + NS_IMETHODIMP PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) { @@ -457,32 +532,8 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) mPresContext->SetVisibleArea(r); } - nsReflowReason reflowReason = eReflowReason_Resize; - - if (nsnull == mRootFrame) { - if (nsnull != mDocument) { - nsIContent* root = mDocument->GetRootContent(); - if (nsnull != root) { - nsIContentDelegate* cd = root->GetDelegate(mPresContext); - if (nsnull != cd) { - nsIStyleContext* rootSC = - mPresContext->ResolveStyleContextFor(root, nsnull); - nsresult rv = cd->CreateFrame(mPresContext, root, nsnull, - rootSC, mRootFrame); - NS_RELEASE(rootSC); - NS_RELEASE(cd); - reflowReason = eReflowReason_Initial; - - // Bind root frame to root view (and root window) - nsIView* rootView; - mViewManager->GetRootView(rootView); - mRootFrame->SetView(rootView); - } - NS_RELEASE(root); - } - } - } - + // If we don't have a root frame yet, that means we haven't had our initial + // reflow... if (nsnull != mRootFrame) { // Kick off a top-down reflow NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, @@ -497,7 +548,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) nsSize maxSize(bounds.width, bounds.height); nsReflowMetrics desiredSize(nsnull); nsReflowStatus status; - nsReflowState reflowState(mRootFrame, reflowReason, maxSize); + nsReflowState reflowState(mRootFrame, eReflowReason_Resize, maxSize); mRootFrame->Reflow(*mPresContext, desiredSize, reflowState, status); mRootFrame->SizeTo(desiredSize.width, desiredSize.height); @@ -663,35 +714,27 @@ PresShell::ContentChanged(nsIDocument *aDocument, NS_IMETHODIMP PresShell::ContentAppended(nsIDocument *aDocument, - nsIContent* aContainer) + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) { - NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); - EnterReflowLock(); - - nsIContent* parentContainer = aContainer; - while (nsnull != parentContainer) { - nsIFrame* frame = FindFrameWithContent(parentContainer); - if (nsnull != frame) { - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("PresShell::ContentAppended: container=%p[%s] frame=%p", - aContainer, ContentTag(aContainer, 0), frame)); - frame->ContentAppended(this, mPresContext, aContainer); - break; - } - parentContainer->GetParent(parentContainer); - } - + nsresult rv = mPresContext->ContentAppended(aDocument, aContainer, aNewIndexInContainer); ExitReflowLock(); - return NS_OK; + return rv; } NS_IMETHODIMP -PresShell::ContentInserted(nsIDocument *aDocument, - nsIContent* aContainer, - nsIContent* aChild, - PRInt32 aIndexInContainer) +PresShell::ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) { +#ifdef FRAME_CONSTRUCTION + EnterReflowLock(); + nsresult rv = mPresContext->ContentInserted(aDocument, aContainer, aChild, aIndexInContainer); + ExitReflowLock(); + return rv; +#else NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); EnterReflowLock(); @@ -708,15 +751,23 @@ PresShell::ContentInserted(nsIDocument *aDocument, ExitReflowLock(); return NS_OK; +#endif } NS_IMETHODIMP -PresShell::ContentReplaced(nsIDocument *aDocument, - nsIContent* aContainer, - nsIContent* aOldChild, - nsIContent* aNewChild, - PRInt32 aIndexInContainer) +PresShell::ContentReplaced(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) { +#ifdef FRAME_CONSTRUCTION + EnterReflowLock(); + nsresult rv = mPresContext->ContentReplaced(aDocument, aContainer, aOldChild, + aNewChild, aIndexInContainer); + ExitReflowLock(); + return rv; +#else NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); EnterReflowLock(); @@ -733,6 +784,7 @@ PresShell::ContentReplaced(nsIDocument *aDocument, ExitReflowLock(); return NS_OK; +#endif } // XXX keep this? @@ -755,6 +807,12 @@ PresShell::ContentHasBeenRemoved(nsIDocument *aDocument, nsIContent* aChild, PRInt32 aIndexInContainer) { +#ifdef FRAME_CONSTRUCTION + nsresult rv = mPresContext->ContentRemoved(aDocument, aContainer, + aChild, aIndexInContainer); + ProcessReflowCommands(); + return rv; +#else NS_PRECONDITION(nsnull != mRootFrame, "null root frame"); nsIFrame* frame = FindFrameWithContent(aContainer); @@ -766,6 +824,7 @@ PresShell::ContentHasBeenRemoved(nsIDocument *aDocument, aIndexInContainer); ProcessReflowCommands(); return NS_OK; +#endif } NS_IMETHODIMP diff --git a/layout/base/src/nsStyleSet.cpp b/layout/base/src/nsStyleSet.cpp index 25819769c79c..cdd7b99ffb74 100644 --- a/layout/base/src/nsStyleSet.cpp +++ b/layout/base/src/nsStyleSet.cpp @@ -22,8 +22,13 @@ #include "nsISupportsArray.h" #include "nsIFrame.h" #include "nsHashtable.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIContent.h" +#include "nsIStyleFrameConstruction.h" static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class ContextKey : public nsHashKey { public: @@ -207,6 +212,31 @@ public: nsIFrame* aParentFrame, PRBool aForceUnique = PR_FALSE); + NS_IMETHODIMP ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); + NS_IMETHOD ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + // xxx style rules enumeration virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); @@ -240,13 +270,15 @@ protected: nsISupportsArray* mDocSheets; nsISupportsArray* mBackstopSheets; nsHashtable mStyleContexts; + nsIStyleFrameConstruction* mFrameConstructor; }; StyleSetImpl::StyleSetImpl() : mOverrideSheets(nsnull), mDocSheets(nsnull), - mBackstopSheets(nsnull) + mBackstopSheets(nsnull), + mFrameConstructor(nsnull) { NS_INIT_REFCNT(); } @@ -262,6 +294,7 @@ StyleSetImpl::~StyleSetImpl() NS_IF_RELEASE(mOverrideSheets); NS_IF_RELEASE(mDocSheets); NS_IF_RELEASE(mBackstopSheets); + NS_IF_RELEASE(mFrameConstructor); mStyleContexts.Enumerate(ReleaseContext); } @@ -340,6 +373,9 @@ void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet) NS_PRECONDITION(nsnull != aSheet, "null arg"); if (EnsureArray(&mDocSheets)) { mDocSheets->AppendElement(aSheet); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -350,6 +386,9 @@ void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aAfterSheet); mDocSheets->InsertElementAt(aSheet, ++index); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -360,6 +399,9 @@ void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aBeforeSheet); mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0)); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -665,6 +707,67 @@ nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext, return result; } +NS_IMETHODIMP StyleSetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + return mFrameConstructor->ConstructFrame(aPresContext, aContent, + aParentFrame, aFrameSubTree); +} + +NS_IMETHODIMP StyleSetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + return mFrameConstructor->ContentAppended(aPresContext, aDocument, + aContainer, aNewIndexInContainer); +} + +NS_IMETHODIMP StyleSetImpl::ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentInserted(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentReplaced(aPresContext, aDocument, aContainer, + aOldChild, aNewChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentRemoved(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + // xxx style rules enumeration void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets) diff --git a/layout/css/layout/src/nsCSSBlockFrame.cpp b/layout/css/layout/src/nsCSSBlockFrame.cpp index fb308e23c893..bfd1d61dc20b 100644 --- a/layout/css/layout/src/nsCSSBlockFrame.cpp +++ b/layout/css/layout/src/nsCSSBlockFrame.cpp @@ -113,6 +113,7 @@ public: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); // nsIFrame + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext); NS_IMETHOD ChildCount(PRInt32& aChildCount) const; NS_IMETHOD ChildAt(PRInt32 aIndex, nsIFrame*& aFrame) const; @@ -129,9 +130,12 @@ public: NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); + // XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, @@ -267,6 +271,8 @@ protected: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); + nsresult AddNewFrames(nsIFrame*); + #ifdef NS_DEBUG PRBool IsChild(nsIFrame* aFrame); #endif @@ -281,6 +287,9 @@ protected: // Text run information nsCSSTextRun* mTextRuns; + // XXX TEMP + PRBool mHasBeenInitialized; + friend struct nsCSSBlockReflowState; }; @@ -502,7 +511,6 @@ LineData::Contains(nsIFrame* aFrame) const return PR_FALSE; } -#ifdef NS_DEBUG static PRInt32 LengthOf(nsIFrame* aFrame) { @@ -514,6 +522,7 @@ LengthOf(nsIFrame* aFrame) return result; } +#ifdef NS_DEBUG void LineData::Verify() { @@ -957,6 +966,7 @@ NS_NewCSSBlockFrame(nsIFrame** aInstancePtrResult, nsCSSBlockFrame::nsCSSBlockFrame(nsIContent* aContent, nsIFrame* aParent) : nsCSSBlockFrameSuper(aContent, aParent) { + mHasBeenInitialized = PR_FALSE; } nsCSSBlockFrame::~nsCSSBlockFrame() @@ -990,6 +1000,13 @@ nsCSSBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) return nsCSSBlockFrameSuper::QueryInterface(aIID, aInstancePtr); } +NS_IMETHODIMP +nsCSSBlockFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + mHasBeenInitialized = PR_TRUE; + return AddNewFrames(aChildList); +} + NS_IMETHODIMP nsCSSBlockFrame::DeleteFrame(nsIPresContext& aPresContext) { @@ -1620,6 +1637,110 @@ nsCSSBlockFrame::ComputeFinalSize(nsCSSBlockReflowState& aState, NS_ASSERTION(aDesiredRect.width < 1000000, "whoops"); } +nsresult +nsCSSBlockFrame::AddNewFrames(nsIFrame* aNewFrame) +{ + // Get our last line and then get its last child + nsIFrame* lastFrame; + LineData* lastLine = LastLine(mLines); + if (nsnull != lastLine) { + lastFrame = lastLine->LastChild(); + } else { + lastFrame = nsnull; + } + + // Add the new frames to the sibling list + if (nsnull != lastFrame) { + lastFrame->SetNextSibling(aNewFrame); + } + + // Make sure that new inlines go onto the end of the lastLine when + // the lastLine is mapping inline frames. + PRInt32 pendingInlines = 0; + if (nsnull != lastLine) { + if (!lastLine->IsBlock()) { + pendingInlines = 1; + } + } + + // Now create some lines for the new frames + nsresult rv; + for (nsIFrame* frame = aNewFrame; nsnull != frame; frame->GetNextSibling(frame)) { + // See if the child is a block or non-block + const nsStyleDisplay* kidDisplay; + rv = frame->GetStyleData(eStyleStruct_Display, + (const nsStyleStruct*&) kidDisplay); + if (NS_OK != rv) { + return rv; + } + const nsStylePosition* kidPosition; + rv = frame->GetStyleData(eStyleStruct_Position, + (const nsStyleStruct*&) kidPosition); + if (NS_OK != rv) { + return rv; + } + PRBool isBlock = + nsCSSLineLayout::TreatFrameAsBlock(kidDisplay, kidPosition); + + // If the child is an inline then add it to the lastLine (if it's + // an inline line, otherwise make a new line). If the child is a + // block then make a new line and put the child in that line. + if (isBlock) { + // If the previous line has pending inline data to be reflowed, + // do so now. + if (0 != pendingInlines) { + // Set this to true in case we don't end up reflowing all of the + // frames on the line (because they end up being pushed). + lastLine->SetLastContentIsComplete(); + lastLine->MarkDirty(); + pendingInlines = 0; + } + + // Create a line for the block + LineData* line = new LineData(frame, 1, + (LINE_IS_BLOCK | + LINE_LAST_CONTENT_IS_COMPLETE)); + if (nsnull == line) { + return NS_ERROR_OUT_OF_MEMORY; + } + if (nsnull == lastLine) { + mLines = line; + } + else { + lastLine->mNext = line; + } + lastLine = line; + } + else { + // Queue up the inlines for reflow later on + if (0 == pendingInlines) { + LineData* line = new LineData(frame, 0, 0); + if (nsnull == line) { + return NS_ERROR_OUT_OF_MEMORY; + } + if (nsnull == lastLine) { + mLines = line; + } + else { + lastLine->mNext = line; + } + lastLine = line; + } + lastLine->mChildCount++; + pendingInlines++; + } + } + + if (0 != pendingInlines) { + // Set this to true in case we don't end up reflowing all of the + // frames on the line (because they end up being pushed). + lastLine->SetLastContentIsComplete(); + lastLine->MarkDirty(); + } + + return NS_OK; +} + nsresult nsCSSBlockFrame::InitialReflow(nsCSSBlockReflowState& aState) { @@ -1629,11 +1750,17 @@ nsCSSBlockFrame::InitialReflow(nsCSSBlockReflowState& aState) return rv; } + // XXX CONSTRUCTION + // Temporary hack. If we haven't had Init() called then go ahead and create + // frames the old way. This is needed until tables get converted... + // Create new frames - if (nsnull == mNextInFlow) { - rv = CreateNewFrames(aState.mPresContext); - if (NS_OK != rv) { - return rv; + if (!mHasBeenInitialized) { + if (nsnull == mNextInFlow) { + rv = CreateNewFrames(aState.mPresContext); + if (NS_OK != rv) { + return rv; + } } } @@ -1651,12 +1778,25 @@ nsCSSBlockFrame::InitialReflow(nsCSSBlockReflowState& aState) nsresult nsCSSBlockFrame::FrameAppendedReflow(nsCSSBlockReflowState& aState) { + // XXX CONSTRUCTION +#if 0 // Create new frames for the appended content. Each line that is // impacted by this will be marked dirty. nsresult rv = CreateNewFrames(aState.mPresContext); if (NS_OK != rv) { return rv; } +#else + nsresult rv = NS_OK; + + // Get the first of the newly appended frames + nsIFrame* firstAppendedFrame; + aState.reflowCommand->GetChildFrame(firstAppendedFrame); + + // Add the new frames to the child list, and create new lines. Each + // impacted line will be marked dirty + AddNewFrames(firstAppendedFrame); +#endif // Generate text-run information rv = FindTextRuns(aState); @@ -3061,6 +3201,8 @@ nsCSSBlockFrame::DrainOverflowLines() return drained; } +// XXX CONSTRUCTION +#if 0 // XXX a copy of nsHTMLContainerFrame's NS_IMETHODIMP nsCSSBlockFrame::ContentAppended(nsIPresShell* aShell, @@ -3083,6 +3225,7 @@ nsCSSBlockFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } +#endif // XXX we assume that the insertion is really an assertion and never an append // XXX what about zero lines case diff --git a/layout/generic/nsHTMLFrame.cpp b/layout/generic/nsHTMLFrame.cpp index f460ff0c67f7..df15af3a06c7 100644 --- a/layout/generic/nsHTMLFrame.cpp +++ b/layout/generic/nsHTMLFrame.cpp @@ -42,6 +42,8 @@ class RootFrame : public nsContainerFrame { public: RootFrame(nsIContent* aContent); + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); + NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, @@ -93,6 +95,27 @@ RootFrame::RootFrame(nsIContent* aContent) { } +NS_IMETHODIMP +RootFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + // Construct the root content frame and set its style context + mFirstChild = new RootContentFrame(mContent, this); + mChildCount = 1; + nsIStyleContext* pseudoStyleContext = + aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::rootContentPseudo, this); + mFirstChild->SetStyleContext(&aPresContext, pseudoStyleContext); + NS_RELEASE(pseudoStyleContext); + + // Set the geometric and content parent for each of the child frames + for (nsIFrame* frame = aChildList; nsnull != frame; frame->GetNextSibling(frame)) { + frame->SetGeometricParent(mFirstChild); + frame->SetContentParent(mFirstChild); + } + + // Queue up the frames for the root content frame + return mFirstChild->Init(aPresContext, aChildList); +} + NS_IMETHODIMP RootFrame::Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, @@ -122,6 +145,8 @@ RootFrame::Reflow(nsIPresContext& aPresContext, aReflowState.reflowCommand->GetNext(next); NS_ASSERTION(next == mFirstChild, "unexpected next reflow command frame"); + // XXX CONSTRUCTION +#if 0 } else { // Do we have any children? if (nsnull == mFirstChild) { @@ -133,6 +158,7 @@ RootFrame::Reflow(nsIPresContext& aPresContext, mFirstChild->SetStyleContext(&aPresContext,style); NS_RELEASE(style); } +#endif } // Reflow our pseudo frame. It will choose whetever height its child frame @@ -353,12 +379,15 @@ RootContentFrame::Reflow(nsIPresContext& aPresContext, } else { nsReflowReason reflowReason = aReflowState.reason; + // XXX CONSTRUCTION +#if 0 // Do we have any children? if (nsnull == mFirstChild) { // No, create the first child frame reflowReason = eReflowReason_Initial; CreateFirstChild(&aPresContext); } +#endif // Resize our frames if (nsnull != mFirstChild) { diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index ad98c46f4472..1a3329f63e6a 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -282,6 +282,40 @@ nsresult NS_NewWBRFrame(nsIContent* aContent, nsIFrame* aParentFrame, nsIFrame*& aResult); +extern nsresult +NS_NewCSSInlineFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + nsIFrame* aParent); + +extern nsresult +NS_NewCSSBlockFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + nsIFrame* aParent); + +extern nsresult +NS_NewInputButtonFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputCheckboxFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputTextFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputRadioFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewHTMLSelectFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + // Everything below this line is obsolete... //---------------------------------------------------------------------- // XXX naming consistency puhleeze! diff --git a/layout/generic/nsHTMLReflowCommand.cpp b/layout/generic/nsHTMLReflowCommand.cpp index b0fe90e548e4..a2a6840cb96d 100644 --- a/layout/generic/nsHTMLReflowCommand.cpp +++ b/layout/generic/nsHTMLReflowCommand.cpp @@ -151,6 +151,12 @@ NS_IMETHODIMP nsHTMLReflowCommand::GetTarget(nsIFrame*& aTargetFrame) const return NS_OK; } +NS_IMETHODIMP nsHTMLReflowCommand::SetTarget(nsIFrame* aTargetFrame) +{ + mTargetFrame = aTargetFrame; + return NS_OK; +} + NS_IMETHODIMP nsHTMLReflowCommand::GetType(ReflowType& aReflowType) const { aReflowType = mType; diff --git a/layout/generic/nsHTMLReflowCommand.h b/layout/generic/nsHTMLReflowCommand.h index c1a3d41ac4b3..c289973e4408 100644 --- a/layout/generic/nsHTMLReflowCommand.h +++ b/layout/generic/nsHTMLReflowCommand.h @@ -46,6 +46,7 @@ public: const nsSize& aMaxSize); NS_IMETHOD GetNext(nsIFrame*& aNextFrame); NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const; + NS_IMETHOD SetTarget(nsIFrame* aTargetFrame); NS_IMETHOD GetType(ReflowType& aReflowType) const; NS_IMETHOD GetChildFrame(nsIFrame*& aChildFrame) const; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 2460db88b5c9..c89f8e240765 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -260,10 +260,29 @@ typedef PRBool nsDidReflowStatus; * * Frames are NOT reference counted. Use the DeleteFrame() member function * to delete a frame + * + * XXX This should probably be changed so it's consistent with the way nsIView + * (which is also not reference counted) is defined... */ class nsIFrame : private nsISupports { public: + /** + * Initialize the frame passing it its child frame list. + * + * This member function is called for all frames just after the frame is + * constructed. + * + * You should reflow the frames when you get your 'initial' reflow + * notification. + * + * XXX Should we also pass in the child count? + * + * @param aChildList list of child frames. May be NULL + * @see #Reflow() + */ + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList) = 0; + /** * QueryInterface() defined in nsISupports. This is the only member * function of nsISupports that is public. @@ -466,9 +485,12 @@ public: * FrameAppended incremental reflow command. You then handle the incremental * reflow command by creating frames for the appended content. */ + // XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) = 0; +#endif /** * This call is invoked when content is inserted in the content diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index 2340a74b1251..e268a62ce1da 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -175,6 +175,8 @@ nsPlaceholderFrame::Paint(nsIPresContext& aPresContext, return NS_OK; } +// XXX CONSTRUCTION +#if 0 NS_IMETHODIMP nsPlaceholderFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) @@ -188,6 +190,7 @@ NS_IMETHODIMP nsPlaceholderFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } +#endif NS_IMETHODIMP nsPlaceholderFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, diff --git a/layout/generic/nsPlaceholderFrame.h b/layout/generic/nsPlaceholderFrame.h index 6c88b1868c3a..9eec8d91455f 100644 --- a/layout/generic/nsPlaceholderFrame.h +++ b/layout/generic/nsPlaceholderFrame.h @@ -47,9 +47,12 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); +// XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, diff --git a/layout/html/base/src/nsAbsoluteFrame.cpp b/layout/html/base/src/nsAbsoluteFrame.cpp index f701bc6556e9..51dd76ac3541 100644 --- a/layout/html/base/src/nsAbsoluteFrame.cpp +++ b/layout/html/base/src/nsAbsoluteFrame.cpp @@ -95,6 +95,8 @@ NS_IMETHODIMP nsAbsoluteFrame::Reflow(nsIPresContext& aPresContext, return nsFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); } +// XXX CONSTRUCTION +#if 0 NS_IMETHODIMP nsAbsoluteFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) @@ -108,6 +110,7 @@ NS_IMETHODIMP nsAbsoluteFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } +#endif NS_IMETHODIMP nsAbsoluteFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, diff --git a/layout/html/base/src/nsAbsoluteFrame.h b/layout/html/base/src/nsAbsoluteFrame.h index ad362e4b1713..8a9a50f288eb 100644 --- a/layout/html/base/src/nsAbsoluteFrame.h +++ b/layout/html/base/src/nsAbsoluteFrame.h @@ -43,9 +43,12 @@ public: const nsReflowState& aReflowState, nsReflowStatus& aStatus); +// XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, diff --git a/layout/html/base/src/nsBodyFrame.cpp b/layout/html/base/src/nsBodyFrame.cpp index 4dcb6a734acd..519658d32ca7 100644 --- a/layout/html/base/src/nsBodyFrame.cpp +++ b/layout/html/base/src/nsBodyFrame.cpp @@ -86,6 +86,27 @@ nsBodyFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) ///////////////////////////////////////////////////////////////////////////// // nsIFrame +NS_IMETHODIMP +nsBodyFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + // Create a block frame and set its style context + NS_NewCSSBlockFrame(&mFirstChild, mContent, this); + mChildCount = 1; + nsIStyleContext* pseudoStyleContext = + aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo, this); + mFirstChild->SetStyleContext(&aPresContext, pseudoStyleContext); + NS_RELEASE(pseudoStyleContext); + + // Set the geometric and content parent for each of the child frames + for (nsIFrame* frame = aChildList; nsnull != frame; frame->GetNextSibling(frame)) { + frame->SetGeometricParent(mFirstChild); + frame->SetContentParent(mFirstChild); + } + + // Queue up the frames for the block frame + return mFirstChild->Init(aPresContext, aChildList); +} + NS_METHOD nsBodyFrame::Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, @@ -98,15 +119,20 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext& aPresContext, aStatus = NS_FRAME_COMPLETE; // initialize out parameter + // XXX CONSTRUCTION // Do we have any children? if (nsnull == mFirstChild) { - // No, create a pseudo block frame + // No, create a pseudo block frame. + // XXX Temp hack until all frame construction work is complete. This is needed + // in case the Init() member function wasn't called... NS_ASSERTION(eReflowReason_Initial == aReflowState.reason, "bad reason"); CreateColumnFrame(&aPresContext); } +#if 0 else { NS_ASSERTION(eReflowReason_Initial != aReflowState.reason, "bad reason"); } +#endif nsIFrame* reflowCmdTarget; nsIReflowCommand::ReflowType reflowCmdType; @@ -118,6 +144,27 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext& aPresContext, aReflowState.reflowCommand->GetTarget(reflowCmdTarget); aReflowState.reflowCommand->GetType(reflowCmdType); + // XXX CONSTRUCTION + if (this == reflowCmdTarget) { + NS_ASSERTION(nsIReflowCommand::FrameAppended == reflowCmdType, + "unexpected reflow command"); + + // Append reflow commands will be targeted at us. Reset the target and + // send the reflow command. + // XXX Would it be better to have the frame generate the reflow command + // that way it could correctly set the target? + reflowCmdTarget = mFirstChild; + aReflowState.reflowCommand->SetTarget(mFirstChild); + + // Reset the geometric and content parent for each of the child frames + nsIFrame* childList; + aReflowState.reflowCommand->GetChildFrame(childList); + for (nsIFrame* frame = childList; nsnull != frame; frame->GetNextSibling(frame)) { + frame->SetGeometricParent(mFirstChild); + frame->SetContentParent(mFirstChild); + } + } + // The reflow command should never be target for us #ifdef NS_DEBUG NS_ASSERTION(this != reflowCmdTarget, "bad reflow command target"); @@ -131,7 +178,7 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext& aPresContext, // positioned elements... nsIFrame* nextFrame; aReflowState.reflowCommand->GetNext(nextFrame); - if (mFirstChild != nextFrame) { + if ((nsnull != nextFrame) && (mFirstChild != nextFrame)) { NS_ASSERTION(this != nextFrame, "huh?"); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsBodyFrame::Reflow: reflowing frame=%p", @@ -296,6 +343,8 @@ NS_METHOD nsBodyFrame::Reflow(nsIPresContext& aPresContext, return NS_OK; } +// XXX CONSTRUCTION +#if 0 NS_METHOD nsBodyFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) @@ -306,6 +355,7 @@ NS_METHOD nsBodyFrame::ContentAppended(nsIPresShell* aShell, // reflow command return mFirstChild->ContentAppended(aShell, aPresContext, aContainer); } +#endif NS_METHOD nsBodyFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, @@ -1045,3 +1095,4 @@ NS_METHOD nsBodyFrame::VerifyTree() const return NS_OK; } + diff --git a/layout/html/base/src/nsBodyFrame.h b/layout/html/base/src/nsBodyFrame.h index 21ab357409e9..2b51a7397fba 100644 --- a/layout/html/base/src/nsBodyFrame.h +++ b/layout/html/base/src/nsBodyFrame.h @@ -38,14 +38,19 @@ public: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); + NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, nsReflowStatus& aStatus); +// XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, diff --git a/layout/html/base/src/nsHTMLAtoms.cpp b/layout/html/base/src/nsHTMLAtoms.cpp index aa8d1299c88e..dc4e0cae5889 100644 --- a/layout/html/base/src/nsHTMLAtoms.cpp +++ b/layout/html/base/src/nsHTMLAtoms.cpp @@ -107,6 +107,7 @@ nsIAtom* nsHTMLAtoms::id; nsIAtom* nsHTMLAtoms::iframe; nsIAtom* nsHTMLAtoms::img; nsIAtom* nsHTMLAtoms::index; +nsIAtom* nsHTMLAtoms::input; nsIAtom* nsHTMLAtoms::ismap; nsIAtom* nsHTMLAtoms::label; nsIAtom* nsHTMLAtoms::lang; @@ -171,6 +172,7 @@ nsIAtom* nsHTMLAtoms::rules; nsIAtom* nsHTMLAtoms::scheme; nsIAtom* nsHTMLAtoms::scope; nsIAtom* nsHTMLAtoms::scrolling; +nsIAtom* nsHTMLAtoms::select; nsIAtom* nsHTMLAtoms::selected; nsIAtom* nsHTMLAtoms::selectedindex; nsIAtom* nsHTMLAtoms::shape; @@ -189,6 +191,7 @@ nsIAtom* nsHTMLAtoms::tabstop; nsIAtom* nsHTMLAtoms::target; nsIAtom* nsHTMLAtoms::td; nsIAtom* nsHTMLAtoms::text; +nsIAtom* nsHTMLAtoms::textarea; nsIAtom* nsHTMLAtoms::th; nsIAtom* nsHTMLAtoms::title; nsIAtom* nsHTMLAtoms::top; @@ -304,6 +307,7 @@ void nsHTMLAtoms::AddrefAtoms() iframe = NS_NewAtom("IFRAME"); img = NS_NewAtom("IMG"); index = NS_NewAtom("INDEX"); + input = NS_NewAtom("INPUT"); ismap = NS_NewAtom("ISMAP"); label = NS_NewAtom("LABEL"); lang = NS_NewAtom("LANG"); @@ -367,6 +371,7 @@ void nsHTMLAtoms::AddrefAtoms() scheme = NS_NewAtom("SCHEME"); scope = NS_NewAtom("SCOPE"); scrolling = NS_NewAtom("SCROLLING"); + select = NS_NewAtom("SELECT"); selected = NS_NewAtom("SELECTED"); selectedindex = NS_NewAtom("SELECTEDINDEX"); shape = NS_NewAtom("SHAPE"); @@ -385,6 +390,7 @@ void nsHTMLAtoms::AddrefAtoms() target = NS_NewAtom("TARGET"); td = NS_NewAtom("TD"); text = NS_NewAtom("TEXT"); + textarea = NS_NewAtom("TEXTAREA"); th = NS_NewAtom("TH"); title = NS_NewAtom("TITLE"); top = NS_NewAtom("TOP"); @@ -493,6 +499,8 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(id); NS_RELEASE(iframe); NS_RELEASE(img); + NS_RELEASE(index); + NS_RELEASE(input); NS_RELEASE(ismap); NS_RELEASE(label); NS_RELEASE(lang); @@ -555,6 +563,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(scheme); NS_RELEASE(scope); NS_RELEASE(scrolling); + NS_RELEASE(select); NS_RELEASE(selected); NS_RELEASE(selectedindex); NS_RELEASE(shape); @@ -572,6 +581,7 @@ void nsHTMLAtoms::ReleaseAtoms() NS_RELEASE(target); NS_RELEASE(td); NS_RELEASE(text); + NS_RELEASE(textarea); NS_RELEASE(th); NS_RELEASE(top); NS_RELEASE(toppadding); diff --git a/layout/html/base/src/nsHTMLAtoms.h b/layout/html/base/src/nsHTMLAtoms.h index f7572d6f58ae..0a55c79afe29 100644 --- a/layout/html/base/src/nsHTMLAtoms.h +++ b/layout/html/base/src/nsHTMLAtoms.h @@ -134,6 +134,7 @@ public: static nsIAtom* iframe; static nsIAtom* img; static nsIAtom* index; + static nsIAtom* input; static nsIAtom* ismap; static nsIAtom* label; @@ -205,6 +206,7 @@ public: static nsIAtom* scheme; static nsIAtom* scope; static nsIAtom* scrolling; + static nsIAtom* select; static nsIAtom* selected; static nsIAtom* selectedindex; static nsIAtom* shape; @@ -224,6 +226,7 @@ public: static nsIAtom* target; static nsIAtom* td; static nsIAtom* text; + static nsIAtom* textarea; static nsIAtom* th; static nsIAtom* title; static nsIAtom* top; diff --git a/layout/html/base/src/nsHTMLContainer.cpp b/layout/html/base/src/nsHTMLContainer.cpp index 172c0c0817bb..0fa84fd6df46 100644 --- a/layout/html/base/src/nsHTMLContainer.cpp +++ b/layout/html/base/src/nsHTMLContainer.cpp @@ -203,7 +203,7 @@ nsHTMLContainer::AppendChildTo(nsIContent* aKid, PRBool aNotify) if (nsnull != doc) { aKid->SetDocument(doc); if (aNotify) { - doc->ContentAppended(this); + doc->ContentAppended(this, mChildren.Count() - 1); } } } diff --git a/layout/html/base/src/nsHTMLFrame.cpp b/layout/html/base/src/nsHTMLFrame.cpp index f460ff0c67f7..df15af3a06c7 100644 --- a/layout/html/base/src/nsHTMLFrame.cpp +++ b/layout/html/base/src/nsHTMLFrame.cpp @@ -42,6 +42,8 @@ class RootFrame : public nsContainerFrame { public: RootFrame(nsIContent* aContent); + NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList); + NS_IMETHOD Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, const nsReflowState& aReflowState, @@ -93,6 +95,27 @@ RootFrame::RootFrame(nsIContent* aContent) { } +NS_IMETHODIMP +RootFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList) +{ + // Construct the root content frame and set its style context + mFirstChild = new RootContentFrame(mContent, this); + mChildCount = 1; + nsIStyleContext* pseudoStyleContext = + aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::rootContentPseudo, this); + mFirstChild->SetStyleContext(&aPresContext, pseudoStyleContext); + NS_RELEASE(pseudoStyleContext); + + // Set the geometric and content parent for each of the child frames + for (nsIFrame* frame = aChildList; nsnull != frame; frame->GetNextSibling(frame)) { + frame->SetGeometricParent(mFirstChild); + frame->SetContentParent(mFirstChild); + } + + // Queue up the frames for the root content frame + return mFirstChild->Init(aPresContext, aChildList); +} + NS_IMETHODIMP RootFrame::Reflow(nsIPresContext& aPresContext, nsReflowMetrics& aDesiredSize, @@ -122,6 +145,8 @@ RootFrame::Reflow(nsIPresContext& aPresContext, aReflowState.reflowCommand->GetNext(next); NS_ASSERTION(next == mFirstChild, "unexpected next reflow command frame"); + // XXX CONSTRUCTION +#if 0 } else { // Do we have any children? if (nsnull == mFirstChild) { @@ -133,6 +158,7 @@ RootFrame::Reflow(nsIPresContext& aPresContext, mFirstChild->SetStyleContext(&aPresContext,style); NS_RELEASE(style); } +#endif } // Reflow our pseudo frame. It will choose whetever height its child frame @@ -353,12 +379,15 @@ RootContentFrame::Reflow(nsIPresContext& aPresContext, } else { nsReflowReason reflowReason = aReflowState.reason; + // XXX CONSTRUCTION +#if 0 // Do we have any children? if (nsnull == mFirstChild) { // No, create the first child frame reflowReason = eReflowReason_Initial; CreateFirstChild(&aPresContext); } +#endif // Resize our frames if (nsnull != mFirstChild) { diff --git a/layout/html/base/src/nsHTMLParts.h b/layout/html/base/src/nsHTMLParts.h index ad98c46f4472..1a3329f63e6a 100644 --- a/layout/html/base/src/nsHTMLParts.h +++ b/layout/html/base/src/nsHTMLParts.h @@ -282,6 +282,40 @@ nsresult NS_NewWBRFrame(nsIContent* aContent, nsIFrame* aParentFrame, nsIFrame*& aResult); +extern nsresult +NS_NewCSSInlineFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + nsIFrame* aParent); + +extern nsresult +NS_NewCSSBlockFrame(nsIFrame** aInstancePtrResult, + nsIContent* aContent, + nsIFrame* aParent); + +extern nsresult +NS_NewInputButtonFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputCheckboxFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputTextFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewInputRadioFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + +extern nsresult +NS_NewHTMLSelectFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aResult); + // Everything below this line is obsolete... //---------------------------------------------------------------------- // XXX naming consistency puhleeze! diff --git a/layout/html/base/src/nsHTMLReflowCommand.cpp b/layout/html/base/src/nsHTMLReflowCommand.cpp index b0fe90e548e4..a2a6840cb96d 100644 --- a/layout/html/base/src/nsHTMLReflowCommand.cpp +++ b/layout/html/base/src/nsHTMLReflowCommand.cpp @@ -151,6 +151,12 @@ NS_IMETHODIMP nsHTMLReflowCommand::GetTarget(nsIFrame*& aTargetFrame) const return NS_OK; } +NS_IMETHODIMP nsHTMLReflowCommand::SetTarget(nsIFrame* aTargetFrame) +{ + mTargetFrame = aTargetFrame; + return NS_OK; +} + NS_IMETHODIMP nsHTMLReflowCommand::GetType(ReflowType& aReflowType) const { aReflowType = mType; diff --git a/layout/html/base/src/nsHTMLReflowCommand.h b/layout/html/base/src/nsHTMLReflowCommand.h index c1a3d41ac4b3..c289973e4408 100644 --- a/layout/html/base/src/nsHTMLReflowCommand.h +++ b/layout/html/base/src/nsHTMLReflowCommand.h @@ -46,6 +46,7 @@ public: const nsSize& aMaxSize); NS_IMETHOD GetNext(nsIFrame*& aNextFrame); NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const; + NS_IMETHOD SetTarget(nsIFrame* aTargetFrame); NS_IMETHOD GetType(ReflowType& aReflowType) const; NS_IMETHOD GetChildFrame(nsIFrame*& aChildFrame) const; diff --git a/layout/html/base/src/nsPlaceholderFrame.cpp b/layout/html/base/src/nsPlaceholderFrame.cpp index 2340a74b1251..e268a62ce1da 100644 --- a/layout/html/base/src/nsPlaceholderFrame.cpp +++ b/layout/html/base/src/nsPlaceholderFrame.cpp @@ -175,6 +175,8 @@ nsPlaceholderFrame::Paint(nsIPresContext& aPresContext, return NS_OK; } +// XXX CONSTRUCTION +#if 0 NS_IMETHODIMP nsPlaceholderFrame::ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer) @@ -188,6 +190,7 @@ NS_IMETHODIMP nsPlaceholderFrame::ContentAppended(nsIPresShell* aShell, return NS_OK; } +#endif NS_IMETHODIMP nsPlaceholderFrame::ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, diff --git a/layout/html/base/src/nsPlaceholderFrame.h b/layout/html/base/src/nsPlaceholderFrame.h index 6c88b1868c3a..9eec8d91455f 100644 --- a/layout/html/base/src/nsPlaceholderFrame.h +++ b/layout/html/base/src/nsPlaceholderFrame.h @@ -47,9 +47,12 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); +// XXX CONSTRUCTION +#if 0 NS_IMETHOD ContentAppended(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer); +#endif NS_IMETHOD ContentInserted(nsIPresShell* aShell, nsIPresContext* aPresContext, nsIContent* aContainer, diff --git a/layout/html/content/src/nsGenericHTMLElement.cpp b/layout/html/content/src/nsGenericHTMLElement.cpp index 6867fa7932d6..6131b572a56c 100644 --- a/layout/html/content/src/nsGenericHTMLElement.cpp +++ b/layout/html/content/src/nsGenericHTMLElement.cpp @@ -3266,7 +3266,7 @@ nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify) if (nsnull != doc) { aKid->SetDocument(doc); if (aNotify) { - doc->ContentAppended(mContent); + doc->ContentAppended(mContent, mChildren->Count() - 1); } } } diff --git a/layout/html/content/src/nsHTMLGenericContent.cpp b/layout/html/content/src/nsHTMLGenericContent.cpp new file mode 100644 index 000000000000..b400630078a9 --- /dev/null +++ b/layout/html/content/src/nsHTMLGenericContent.cpp @@ -0,0 +1,2732 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsHTMLGenericContent.h" + +#include "nsIAtom.h" +#include "nsIContentDelegate.h" +#include "nsICSSParser.h" +#include "nsIDocument.h" +#include "nsIDOMAttribute.h" +#include "nsIDOMEventReceiver.h" +#include "nsIDOMNamedNodeMap.h" +#include "nsIEventListenerManager.h" +#include "nsIHTMLAttributes.h" +#include "nsIHTMLStyleSheet.h" +#include "nsIHTMLDocument.h" +#include "nsIHTMLContent.h" +#include "nsILinkHandler.h" +#include "nsIScriptContextOwner.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsISizeOfHandler.h" +#include "nsIStyleContext.h" +#include "nsIStyleRule.h" +#include "nsISupportsArray.h" +#include "nsIURL.h" +#include "nsStyleConsts.h" +#include "nsXIFConverter.h" +#include "nsFrame.h" + +#include "nsString.h" +#include "nsHTMLAtoms.h" +#include "nsDOMEventsIIDs.h" +#include "nsCSSBlockFrame.h" +#include "nsCSSInlineFrame.h" +#include "nsIEventStateManager.h" +#include "nsDOMEvent.h" +#include "nsIPrivateDOMEvent.h" +#include "prprf.h" + +// XXX todo: add in missing out-of-memory checks + +NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +NS_DEFINE_IID(kIDOMHTMLElementIID, NS_IDOMHTMLELEMENT_IID); +NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID); +NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); +NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); +NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); +//NS_DEFINE_IID(kIHTMLContentIID, NS_IHTMLCONTENT_IID); + +static NS_DEFINE_IID(kIContentDelegateIID, NS_ICONTENTDELEGATE_IID); +static NS_DEFINE_IID(kIDOMAttributeIID, NS_IDOMATTRIBUTE_IID); +static NS_DEFINE_IID(kIDOMNamedNodeMapIID, NS_IDOMNAMEDNODEMAP_IID); +static NS_DEFINE_IID(kIPrivateDOMEventIID, NS_IPRIVATEDOMEVENT_IID); +static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID); + +static nsIContentDelegate* gContentDelegate; + +/** + * THE html content delegate. There is exactly one instance of this + * class and it's used for all html content. It just turns around + * and asks the content object to create the frame. + */ +class ZContentDelegate : public nsIContentDelegate { +public: + ZContentDelegate(); + NS_DECL_ISUPPORTS + NS_IMETHOD CreateFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame*& aResult); +protected: + ~ZContentDelegate(); +}; + +// Attribute helper class used to wrap up an attribute with a dom +// object that implements nsIDOMAttribute and nsIDOMNode and +// nsIScriptObjectOwner +class DOMAttribute : public nsIDOMAttribute, public nsIScriptObjectOwner { +public: + DOMAttribute(const nsString &aName, const nsString &aValue); + ~DOMAttribute(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject); + NS_IMETHOD ResetScriptObject(); + + // nsIDOMAttribute interface + NS_IMETHOD GetSpecified(PRBool* aSpecified); + NS_IMETHOD SetSpecified(PRBool aSpecified); + NS_IMETHOD GetName(nsString& aReturn); + NS_IMETHOD GetValue(nsString& aReturn); + + // nsIDOMNode interface + NS_IMETHOD GetNodeName(nsString& aNodeName); + NS_IMETHOD GetNodeValue(nsString& aNodeValue); + NS_IMETHOD SetNodeValue(const nsString& aNodeValue); + NS_IMETHOD GetNodeType(PRInt32* aNodeType); + NS_IMETHOD GetParentNode(nsIDOMNode** aParentNode); + NS_IMETHOD GetChildNodes(nsIDOMNodeList** aChildNodes); + NS_IMETHOD GetHasChildNodes(PRBool* aHasChildNodes); + NS_IMETHOD GetFirstChild(nsIDOMNode** aFirstChild); + NS_IMETHOD GetLastChild(nsIDOMNode** aLastChild); + NS_IMETHOD GetPreviousSibling(nsIDOMNode** aPreviousSibling); + NS_IMETHOD GetNextSibling(nsIDOMNode** aNextSibling); + NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes); + NS_IMETHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, + nsIDOMNode** aReturn); + NS_IMETHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, + nsIDOMNode** aReturn); + NS_IMETHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn); + NS_IMETHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn); + NS_IMETHOD CloneNode(nsIDOMNode** aReturn); + NS_IMETHOD Equals(nsIDOMNode* aNode, PRBool aDeep, PRBool* aReturn); + +private: + nsString mName; + nsString mValue; + void* mScriptObject; +}; + +// Another helper class that implements the nsIDOMNamedNodeMap interface. +class DOMAttributeMap : public nsIDOMNamedNodeMap, + public nsIScriptObjectOwner +{ +public: + DOMAttributeMap(nsIHTMLContent &aContent); + virtual ~DOMAttributeMap(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject); + NS_IMETHOD ResetScriptObject(); + + // nsIDOMNamedNodeMap interface + NS_IMETHOD GetLength(PRUint32* aSize); + NS_IMETHOD GetNamedItem(const nsString& aName, nsIDOMNode** aReturn); + NS_IMETHOD SetNamedItem(nsIDOMNode* aNode); + NS_IMETHOD RemoveNamedItem(const nsString& aName, nsIDOMNode** aReturn); + NS_IMETHOD Item(PRUint32 aIndex, nsIDOMNode** aReturn); + +private: + nsIHTMLContent& mContent; + void* mScriptObject; +}; + +//---------------------------------------------------------------------- + +ZContentDelegate::ZContentDelegate() +{ + NS_INIT_REFCNT(); +} + +NS_IMPL_ISUPPORTS(ZContentDelegate, kIContentDelegateIID); + +ZContentDelegate::~ZContentDelegate() +{ +} + +NS_METHOD +ZContentDelegate::CreateFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame*& aResult) +{ + NS_PRECONDITION(nsnull != aContent, "null ptr"); + + // Make sure the content is html content + nsIHTMLContent* hc; + nsIFrame* frame = nsnull; + nsresult rv = aContent->QueryInterface(kIHTMLContentIID, (void**) &hc); + if (NS_OK != rv) { + // This means that *somehow* somebody which is not an html + // content object got ahold of this delegate and tried to + // create a frame with it. Give them back an nsFrame. + rv = nsFrame::NewFrame(&frame, aContent, aParentFrame); + if (NS_OK == rv) { + frame->SetStyleContext(aPresContext, aStyleContext); + } + } + else { + // Ask the content object to create the frame + rv = hc->CreateFrame(aPresContext, aParentFrame, aStyleContext, frame); + NS_RELEASE(hc); + } + aResult = frame; + return rv; +} + +//---------------------------------------------------------------------- + +DOMAttribute::DOMAttribute(const nsString& aName, const nsString& aValue) + : mName(aName), mValue(aValue) +{ + mRefCnt = 1; + mScriptObject = nsnull; +} + +DOMAttribute::~DOMAttribute() +{ +} + +nsresult +DOMAttribute::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDOMAttributeIID)) { + nsIDOMAttribute* tmp = this; + *aInstancePtr = (void*)tmp; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + nsIScriptObjectOwner* tmp = this; + *aInstancePtr = (void*)tmp; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + nsIDOMAttribute* tmp1 = this; + nsISupports* tmp2 = tmp1; + *aInstancePtr = (void*)tmp2; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(DOMAttribute) + +NS_IMPL_RELEASE(DOMAttribute) + +nsresult +DOMAttribute::GetScriptObject(nsIScriptContext *aContext, + void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + res = NS_NewScriptAttribute(aContext, this, nsnull, + (void **)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult +DOMAttribute::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +nsresult +DOMAttribute::GetName(nsString& aName) +{ + aName = mName; + return NS_OK; +} + +nsresult +DOMAttribute::GetValue(nsString& aValue) +{ + aValue = mValue; + return NS_OK; +} + +nsresult +DOMAttribute::GetSpecified(PRBool* aSpecified) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +DOMAttribute::SetSpecified(PRBool specified) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +DOMAttribute::GetNodeName(nsString& aNodeName) +{ + return GetName(aNodeName); +} + +NS_IMETHODIMP +DOMAttribute::GetNodeValue(nsString& aNodeValue) +{ + return GetValue(aNodeValue); +} + +NS_IMETHODIMP +DOMAttribute::SetNodeValue(const nsString& aNodeValue) +{ + // You can't actually do this, but we'll fail silently + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetNodeType(PRInt32* aNodeType) +{ + *aNodeType = (PRInt32)nsIDOMNode::ATTRIBUTE; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetParentNode(nsIDOMNode** aParentNode) +{ + *aParentNode = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetChildNodes(nsIDOMNodeList** aChildNodes) +{ + *aChildNodes = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetHasChildNodes(PRBool* aHasChildNodes) +{ + *aHasChildNodes = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetFirstChild(nsIDOMNode** aFirstChild) +{ + *aFirstChild = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetLastChild(nsIDOMNode** aLastChild) +{ + *aLastChild = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetPreviousSibling(nsIDOMNode** aPreviousSibling) +{ + *aPreviousSibling = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetNextSibling(nsIDOMNode** aNextSibling) +{ + *aNextSibling = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::GetAttributes(nsIDOMNamedNodeMap** aAttributes) +{ + *aAttributes = nsnull; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +DOMAttribute::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +DOMAttribute::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +DOMAttribute::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn) +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +DOMAttribute::CloneNode(nsIDOMNode** aReturn) +{ + DOMAttribute* newAttr = new DOMAttribute(mName, mValue); + if (nsnull == newAttr) { + return NS_ERROR_OUT_OF_MEMORY; + } + + *aReturn = newAttr; + return NS_OK; +} + +NS_IMETHODIMP +DOMAttribute::Equals(nsIDOMNode* aNode, PRBool aDeep, PRBool* aReturn) +{ + // XXX TBI + return NS_OK; +} + +//---------------------------------------------------------------------- + +DOMAttributeMap::DOMAttributeMap(nsIHTMLContent& aContent) + : mContent(aContent) +{ + mRefCnt = 1; + mContent.AddRef(); + mScriptObject = nsnull; +} + +DOMAttributeMap::~DOMAttributeMap() +{ + mContent.Release(); +} + +nsresult +DOMAttributeMap::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + if (aIID.Equals(kIDOMNamedNodeMapIID)) { + nsIDOMNamedNodeMap* tmp = this; + *aInstancePtr = (void*)tmp; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kIScriptObjectOwnerIID)) { + nsIScriptObjectOwner* tmp = this; + *aInstancePtr = (void*)tmp; + AddRef(); + return NS_OK; + } + if (aIID.Equals(kISupportsIID)) { + nsIDOMNamedNodeMap* tmp1 = this; + nsISupports* tmp2 = tmp1; + *aInstancePtr = (void*)tmp2; + AddRef(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(DOMAttributeMap) + +NS_IMPL_RELEASE(DOMAttributeMap) + +nsresult +DOMAttributeMap::GetScriptObject(nsIScriptContext *aContext, + void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + res = NS_NewScriptNamedNodeMap(aContext, this, nsnull, + (void**)&mScriptObject); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult +DOMAttributeMap::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +nsresult +DOMAttributeMap::GetNamedItem(const nsString &aAttrName, + nsIDOMNode** aAttribute) +{ + nsAutoString value; + mContent.GetAttribute(aAttrName, value); + *aAttribute = (nsIDOMNode *) new DOMAttribute(aAttrName, value); + return NS_OK; +} + +nsresult +DOMAttributeMap::SetNamedItem(nsIDOMNode *aNode) +{ + nsIDOMAttribute *attribute; + nsAutoString name, value; + nsresult err; + + if (NS_OK != (err = aNode->QueryInterface(kIDOMAttributeIID, + (void **)&attribute))) { + return err; + } + + attribute->GetName(name); + attribute->GetValue(value); + NS_RELEASE(attribute); + + mContent.SetAttribute(name, value, PR_TRUE); + return NS_OK; +} + +NS_IMETHODIMP +DOMAttributeMap::RemoveNamedItem(const nsString& aName, nsIDOMNode** aReturn) +{ + nsresult res = GetNamedItem(aName, aReturn); + if (NS_OK == res) { + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + mContent.UnsetAttribute(attr); + } + + return res; +} + +nsresult +DOMAttributeMap::Item(PRUint32 aIndex, nsIDOMNode** aReturn) +{ + nsresult res = NS_ERROR_FAILURE; + nsAutoString name, value; + nsISupportsArray *attributes = nsnull; + if (NS_OK == NS_NewISupportsArray(&attributes)) { + PRInt32 count; + mContent.GetAllAttributeNames(attributes, count); + if (count > 0) { + if ((PRInt32)aIndex < count) { + nsISupports *att = attributes->ElementAt(aIndex); + static NS_DEFINE_IID(kIAtom, NS_IATOM_IID); + nsIAtom *atName = nsnull; + if (nsnull != att && NS_OK == att->QueryInterface(kIAtom, (void**)&atName)) { + atName->ToString(name); + if (NS_CONTENT_ATTR_NOT_THERE != mContent.GetAttribute(name, value)) { + *aReturn = (nsIDOMNode *)new DOMAttribute(name, value); + res = NS_OK; + } + NS_RELEASE(atName); + } + } + } + NS_RELEASE(attributes); + } + + return res; +} + +nsresult +DOMAttributeMap::GetLength(PRUint32 *aLength) +{ + PRInt32 n; + nsresult rv = mContent.GetAttributeCount(n); + *aLength = PRUint32(n); + return rv; +} + +//---------------------------------------------------------------------- + +static nsresult EnsureWritableAttributes(nsIHTMLAttributes*& aAttributes, PRBool aCreate) +{ + nsresult result = NS_OK; + + if (nsnull == aAttributes) { + if (PR_TRUE == aCreate) { + result = NS_NewHTMLAttributes(&aAttributes); + if (NS_OK == result) { + aAttributes->AddContentRef(); + } + } + } + else { + PRInt32 contentRefCount; + aAttributes->GetContentRefCount(contentRefCount); + if (1 < contentRefCount) { + nsIHTMLAttributes* attrs; + result = aAttributes->Clone(&attrs); + if (NS_OK == result) { + aAttributes->ReleaseContentRef(); + NS_RELEASE(aAttributes); + aAttributes = attrs; + aAttributes->AddContentRef(); + } + } + } + return result; +} + +static void ReleaseAttributes(nsIHTMLAttributes*& aAttributes) +{ + aAttributes->ReleaseContentRef(); + NS_RELEASE(aAttributes); +} + + +nsHTMLGenericContent::nsHTMLGenericContent() +{ + mDocument = nsnull; + mParent = nsnull; + mAttributes = nsnull; + mTag = nsnull; + mContent = nsnull; + mScriptObject = nsnull; + mListenerManager = nsnull; + + // Create shared content delegate if this is the first html content + // object being created. + if (nsnull == gContentDelegate) { + gContentDelegate = new ZContentDelegate(); + } + + // Add a reference to the shared content delegate object + NS_ADDREF(gContentDelegate); +} + +nsHTMLGenericContent::~nsHTMLGenericContent() +{ + if (nsnull != mAttributes) { + ReleaseAttributes(mAttributes); + } + NS_IF_RELEASE(mTag); + NS_IF_RELEASE(mListenerManager); + // XXX what about mScriptObject? it's now safe to GC it... + + NS_PRECONDITION(nsnull != gContentDelegate, "null content delegate"); + if (nsnull != gContentDelegate) { + // Remove our reference to the shared content delegate object. If + // the last reference just went away, null out gContentDelegate. + nsrefcnt rc = gContentDelegate->Release(); + if (0 == rc) { + gContentDelegate = nsnull; + } + } +} + +void +nsHTMLGenericContent::Init(nsIHTMLContent* aOuterContentObject, + nsIAtom* aTag) +{ + NS_ASSERTION((nsnull == mContent) && (nsnull != aOuterContentObject), + "null ptr"); + mContent = aOuterContentObject; + mTag = aTag; + NS_IF_ADDREF(aTag); +} + +nsresult +nsHTMLGenericContent::GetNodeName(nsString& aNodeName) +{ + return GetTagName(aNodeName); +} + +nsresult +nsHTMLGenericContent::GetNodeValue(nsString& aNodeValue) +{ + aNodeValue.Truncate(); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetNodeValue(const nsString& aNodeValue) +{ + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetNodeType(PRInt32* aNodeType) +{ + *aNodeType = nsIDOMNode::ELEMENT; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetParentNode(nsIDOMNode** aParentNode) +{ + if (nsnull != mParent) { + nsresult res = mParent->QueryInterface(kIDOMNodeIID, (void**)aParentNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + return res; + } + else { + *aParentNode = nsnull; + } + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetPreviousSibling(nsIDOMNode** aNode) +{ + if (nsnull != mParent) { + PRInt32 pos; + mParent->IndexOf(mContent, pos); + if (pos > -1) { + nsIContent* prev; + mParent->ChildAt(--pos, prev); + if (nsnull != prev) { + nsresult res = prev->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + NS_RELEASE(prev); // balance the AddRef in ChildAt() + return res; + } + } + } + *aNode = nsnull; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetNextSibling(nsIDOMNode** aNextSibling) +{ + if (nsnull != mParent) { + PRInt32 pos; + mParent->IndexOf(mContent, pos); + if (pos > -1 ) { + nsIContent* prev; + mParent->ChildAt(++pos, prev); + if (nsnull != prev) { + nsresult res = prev->QueryInterface(kIDOMNodeIID,(void**)aNextSibling); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); + NS_RELEASE(prev); // balance the AddRef in ChildAt() + return res; + } + } + } + *aNextSibling = nsnull; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetAttributes(nsIDOMNamedNodeMap** aAttributes) +{ + NS_PRECONDITION(nsnull != aAttributes, "null pointer argument"); + if (nsnull != mAttributes) { + // XXX Should we create a new one every time or should we + // cache one after we create it? If we find that this is + // something that's called often, we might need to do the + // latter. + *aAttributes = new DOMAttributeMap(*mContent); + } + else { + *aAttributes = nsnull; + } + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetTagName(nsString& aTagName) +{ + aTagName.Truncate(); + if (nsnull != mTag) { + mTag->ToString(aTagName); + } + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetDOMAttribute(const nsString& aName, nsString& aReturn) +{ + GetAttribute(aName, aReturn); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetDOMAttribute(const nsString& aName, + const nsString& aValue) +{ + SetAttribute(aName, aValue, PR_TRUE); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::RemoveAttribute(const nsString& aName) +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + UnsetAttribute(attr); + NS_RELEASE(attr); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetAttributeNode(const nsString& aName, + nsIDOMAttribute** aReturn) +{ + nsAutoString value; + if (NS_CONTENT_ATTR_NOT_THERE != GetAttribute(aName, value)) { + *aReturn = new DOMAttribute(aName, value); + } + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetAttributeNode(nsIDOMAttribute* aAttribute) +{ + NS_PRECONDITION(nsnull != aAttribute, "null attribute"); + + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != aAttribute) { + nsAutoString name, value; + res = aAttribute->GetName(name); + if (NS_OK == res) { + res = aAttribute->GetValue(value); + if (NS_OK == res) { + SetAttribute(name, value, PR_TRUE); + } + } + } + return res; +} + +nsresult +nsHTMLGenericContent::RemoveAttributeNode(nsIDOMAttribute* aAttribute) +{ + NS_PRECONDITION(nsnull != aAttribute, "null attribute"); + + nsresult res = NS_ERROR_FAILURE; + + if (nsnull != aAttribute) { + nsAutoString name; + res = aAttribute->GetName(name); + if (NS_OK == res) { + nsAutoString upper; + name.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + UnsetAttribute(attr); + } + } + + return res; +} + +nsresult +nsHTMLGenericContent::GetElementsByTagName(const nsString& aTagname, + nsIDOMNodeList** aReturn) +{ + return NS_ERROR_NOT_IMPLEMENTED;/* XXX */ +} + +nsresult +nsHTMLGenericContent::Normalize() +{ + return NS_ERROR_NOT_IMPLEMENTED;/* XXX */ +} + +nsresult +nsHTMLGenericContent::GetId(nsString& aId) +{ + GetAttribute(nsHTMLAtoms::id, aId); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetId(const nsString& aId) +{ + SetAttr(nsHTMLAtoms::id, aId, eSetAttrNotify_Restart); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetTitle(nsString& aTitle) +{ + GetAttribute(nsHTMLAtoms::title, aTitle); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetTitle(const nsString& aTitle) +{ + SetAttr(nsHTMLAtoms::title, aTitle, eSetAttrNotify_None); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetLang(nsString& aLang) +{ + GetAttribute(nsHTMLAtoms::lang, aLang); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetLang(const nsString& aLang) +{ + SetAttr(nsHTMLAtoms::lang, aLang, eSetAttrNotify_Reflow); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetDir(nsString& aDir) +{ + GetAttribute(nsHTMLAtoms::dir, aDir); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetDir(const nsString& aDir) +{ + SetAttr(nsHTMLAtoms::dir, aDir, eSetAttrNotify_Reflow); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetClassName(nsString& aClassName) +{ + GetAttribute(nsHTMLAtoms::kClass, aClassName); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetClassName(const nsString& aClassName) +{ + SetAttr(nsHTMLAtoms::kClass, aClassName, eSetAttrNotify_Restart); + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetDocument(nsIDocument*& aResult) const +{ + aResult = mDocument; + NS_IF_ADDREF(mDocument); + return NS_OK; +} + +static nsIHTMLStyleSheet* GetAttrStyleSheet(nsIDocument* aDocument) +{ + nsIHTMLStyleSheet* sheet = nsnull; + nsIHTMLDocument* htmlDoc; + + if (nsnull != aDocument) { + if (NS_OK == aDocument->QueryInterface(kIHTMLDocumentIID, (void**)&htmlDoc)) { + htmlDoc->GetAttributeStyleSheet(&sheet); + } + } + NS_ASSERTION(nsnull != sheet, "can't get attribute style sheet"); + return sheet; +} + +nsresult +nsHTMLGenericContent::SetDocument(nsIDocument* aDocument) +{ + mDocument = aDocument; + + // Once the element is added to the doc tree we need to check if + // event handler were registered on it. Unfortunately, this means + // doing a GetAttribute for every type of handler. + if (nsnull != mAttributes) { + nsHTMLValue val; + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onclick, val)) + AddScriptEventListener(nsHTMLAtoms::onclick, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::ondblclick, val)) + AddScriptEventListener(nsHTMLAtoms::onclick, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmousedown, val)) + AddScriptEventListener(nsHTMLAtoms::onmousedown, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseup, val)) + AddScriptEventListener(nsHTMLAtoms::onmouseup, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseover, val)) + AddScriptEventListener(nsHTMLAtoms::onmouseover, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmouseout, val)) + AddScriptEventListener(nsHTMLAtoms::onmouseout, val, kIDOMMouseListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeydown, val)) + AddScriptEventListener(nsHTMLAtoms::onkeydown, val, kIDOMKeyListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeyup, val)) + AddScriptEventListener(nsHTMLAtoms::onkeyup, val, kIDOMKeyListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onkeypress, val)) + AddScriptEventListener(nsHTMLAtoms::onkeypress, val, kIDOMKeyListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onmousemove, val)) + AddScriptEventListener(nsHTMLAtoms::onmousemove, val, kIDOMMouseMotionListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onload, val)) + AddScriptEventListener(nsHTMLAtoms::onload, val, kIDOMLoadListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onunload, val)) + AddScriptEventListener(nsHTMLAtoms::onunload, val, kIDOMLoadListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onabort, val)) + AddScriptEventListener(nsHTMLAtoms::onabort, val, kIDOMLoadListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onerror, val)) + AddScriptEventListener(nsHTMLAtoms::onerror, val, kIDOMLoadListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onfocus, val)) + AddScriptEventListener(nsHTMLAtoms::onfocus, val, kIDOMFocusListenerIID); + if (NS_CONTENT_ATTR_HAS_VALUE == mAttributes->GetAttribute(nsHTMLAtoms::onblur, val)) + AddScriptEventListener(nsHTMLAtoms::onblur, val, kIDOMFocusListenerIID); + + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + sheet->SetAttributesFor(mTag, mAttributes); // sync attributes with sheet + } + + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetParent(nsIContent*& aResult) const +{ + NS_IF_ADDREF(mParent); + aResult = mParent; + return NS_OK;; +} + +nsresult +nsHTMLGenericContent::SetParent(nsIContent* aParent) +{ + mParent = aParent; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::IsSynthetic(PRBool& aResult) +{ + return PR_FALSE; +} + + +nsresult +nsHTMLGenericContent::GetTag(nsIAtom*& aResult) const +{ + NS_IF_ADDREF(mTag); + aResult = mTag; + return NS_OK; +} + +//void +//nsHTMLTagContent::SizeOfWithoutThis(nsISizeOfHandler* aHandler) const +//{ +// if (!aHandler->HaveSeen(mTag)) { +// mTag->SizeOf(aHandler); +// } +// if (!aHandler->HaveSeen(mAttributes)) { +// mAttributes->SizeOf(aHandler); +// } +//} + +nsresult +nsHTMLGenericContent::HandleDOMEvent(nsIPresContext& aPresContext, + nsEvent* aEvent, + nsIDOMEvent** aDOMEvent, + PRUint32 aFlags, + nsEventStatus& aEventStatus) +{ + nsresult ret = NS_OK; + + nsIDOMEvent* domEvent = nsnull; + if (DOM_EVENT_INIT == aFlags) { + nsIEventStateManager *manager; + if (NS_OK == aPresContext.GetEventStateManager(&manager)) { + manager->SetEventTarget(mContent); + NS_RELEASE(manager); + } + aDOMEvent = &domEvent; + } + + //Capturing stage + + //Local handling stage + if (nsnull != mListenerManager) { + mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aEventStatus); + } + + //Bubbling stage + if (DOM_EVENT_CAPTURE != aFlags && mParent != nsnull) { + ret = mParent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, + DOM_EVENT_BUBBLE, aEventStatus); + } + + if (DOM_EVENT_INIT == aFlags) { + // We're leaving the DOM event loop so if we created a DOM event, + // release here. + if (nsnull != *aDOMEvent) { + if (0 != (*aDOMEvent)->Release()) { + // Okay, so someone in the DOM loop (a listener, JS object) + // still has a ref to the DOM Event but the internal data + // hasn't been malloc'd. Force a copy of the data here so the + // DOM Event is still valid. + nsIPrivateDOMEvent *privateEvent; + if (NS_OK == (*aDOMEvent)->QueryInterface(kIPrivateDOMEventIID, (void**)&privateEvent)) { + privateEvent->DuplicatePrivateData(); + NS_RELEASE(privateEvent); + } + } + } + aDOMEvent = nsnull; + } + return ret; +} + +nsresult +nsHTMLGenericContent::SetAttribute(const nsString& aName, + const nsString& aValue, + PRBool aNotify) +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + nsresult rv = SetAttribute(attr, aValue, aNotify); + NS_RELEASE(attr); + return rv; +} + +nsresult +nsHTMLGenericContent::SetAttribute(nsIAtom* aAttribute, + const nsString& aValue, + PRBool aNotify) +{ + nsresult result = NS_OK; + if (nsHTMLAtoms::style == aAttribute) { + // XXX the style sheet language is a document property that + // should be used to lookup the style sheet parser to parse the + // attribute. + nsICSSParser* css; + result = NS_NewCSSParser(&css); + if (NS_OK != result) { + return result; + } + nsIStyleRule* rule; + result = css->ParseDeclarations(aValue, nsnull, rule); + if ((NS_OK == result) && (nsnull != rule)) { + result = SetAttribute(aAttribute, nsHTMLValue(rule), aNotify); + NS_RELEASE(rule); + } + NS_RELEASE(css); + } + else { + if (nsnull != mDocument) { // set attr via style sheet + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + result = sheet->SetAttributeFor(aAttribute, aValue, mTag, mAttributes); + } + else { // manage this ourselves and re-sync when we connect to doc + result = EnsureWritableAttributes(mAttributes, PR_TRUE); + if (nsnull != mAttributes) { + PRInt32 count; + result = mAttributes->SetAttribute(aAttribute, aValue, count); + if (0 == count) { + ReleaseAttributes(mAttributes); + } + } + } + } + return result; +} + +nsresult +nsHTMLGenericContent::SetAttribute(nsIAtom* aAttribute, + const nsHTMLValue& aValue, + PRBool aNotify) +{ + nsresult result = NS_OK; + if (nsnull != mDocument) { // set attr via style sheet + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + result = sheet->SetAttributeFor(aAttribute, aValue, mTag, mAttributes); + } + else { // manage this ourselves and re-sync when we connect to doc + result = EnsureWritableAttributes(mAttributes, PR_TRUE); + if (nsnull != mAttributes) { + PRInt32 count; + result = mAttributes->SetAttribute(aAttribute, aValue, count); + if (0 == count) { + ReleaseAttributes(mAttributes); + } + } + } + return result; +} + +nsresult +nsHTMLGenericContent::SetAttr(nsIAtom* aAttribute, + const nsString& aValue, + nsSetAttrNotify aNotify) +{ + // XXX cheesy code for now + return SetAttribute(aAttribute, aValue, PR_TRUE); +} + +nsresult +nsHTMLGenericContent::SetAttr(nsIAtom* aAttribute, + const nsHTMLValue& aValue, + nsSetAttrNotify aNotify) +{ + // XXX cheesy code for now + return SetAttribute(aAttribute, aValue, PR_TRUE); +} + +nsresult +nsHTMLGenericContent::UnsetAttribute(nsIAtom* aAttribute) +{ + nsresult result = NS_OK; + if (nsnull != mDocument) { // set attr via style sheet + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + result = sheet->UnsetAttributeFor(aAttribute, mTag, mAttributes); + } + else { // manage this ourselves and re-sync when we connect to doc + result = EnsureWritableAttributes(mAttributes, PR_FALSE); + if (nsnull != mAttributes) { + PRInt32 count; + result = mAttributes->UnsetAttribute(aAttribute, count); + if (0 == count) { + ReleaseAttributes(mAttributes); + } + } + } + return result; +} + +nsresult +nsHTMLGenericContent::GetAttribute(const nsString& aName, + nsString& aResult) const +{ + nsAutoString upper; + aName.ToUpperCase(upper); + nsIAtom* attr = NS_NewAtom(upper); + nsresult result = GetAttribute(attr, aResult); + NS_RELEASE(attr); + return result; +} + +nsresult +nsHTMLGenericContent::GetAttribute(nsIAtom *aAttribute, + nsString &aResult) const +{ + nsHTMLValue value; + nsresult result = GetAttribute(aAttribute, value); + + char cbuf[20]; + nscolor color; + if (NS_CONTENT_ATTR_HAS_VALUE == result) { + // Try subclass conversion routine first + if (NS_CONTENT_ATTR_HAS_VALUE == + mContent->AttributeToString(aAttribute, value, aResult)) { + return result; + } + + // Provide default conversions for most everything + switch (value.GetUnit()) { + case eHTMLUnit_Empty: + aResult.Truncate(); + break; + + case eHTMLUnit_String: + case eHTMLUnit_Null: + value.GetStringValue(aResult); + break; + + case eHTMLUnit_Integer: + aResult.Truncate(); + aResult.Append(value.GetIntValue(), 10); + break; + + case eHTMLUnit_Pixel: + aResult.Truncate(); + aResult.Append(value.GetPixelValue(), 10); + break; + + case eHTMLUnit_Percent: + aResult.Truncate(0); + aResult.Append(PRInt32(value.GetPercentValue() * 100.0f), 10); + aResult.Append('%'); + break; + + case eHTMLUnit_Color: + color = nscolor(value.GetColorValue()); + PR_snprintf(cbuf, sizeof(cbuf), "#%02x%02x%02x", + NS_GET_R(color), NS_GET_G(color), NS_GET_B(color)); + aResult.Truncate(0); + aResult.Append(cbuf); + break; + + default: + case eHTMLUnit_Enumerated: + NS_NOTREACHED("no default enumerated value to string conversion"); + result = NS_CONTENT_ATTR_NOT_THERE; + break; + } + } + return result; +} + +nsresult +nsHTMLGenericContent::GetAttribute(nsIAtom* aAttribute, + nsHTMLValue& aValue) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetAttribute(aAttribute, aValue); + } + aValue.Reset(); + return NS_CONTENT_ATTR_NOT_THERE; +} + +nsresult +nsHTMLGenericContent::GetAllAttributeNames(nsISupportsArray* aArray, + PRInt32& aCount) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetAllAttributeNames(aArray, aCount); + } + aCount = 0; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetAttributeCount(PRInt32& aCount) const +{ + if (nsnull != mAttributes) { + return mAttributes->Count(aCount); + } + aCount = 0; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetID(nsIAtom* aID) +{ + nsresult result = NS_OK; + if (nsnull != mDocument) { // set attr via style sheet + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + result = sheet->SetIDFor(aID, mTag, mAttributes); + } + else { // manage this ourselves and re-sync when we connect to doc + EnsureWritableAttributes(mAttributes, PRBool(nsnull != aID)); + if (nsnull != mAttributes) { + PRInt32 count; + result = mAttributes->SetID(aID, count); + if (0 == count) { + ReleaseAttributes(mAttributes); + } + } + } + return result; +} + +nsresult +nsHTMLGenericContent::GetID(nsIAtom*& aResult) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetID(aResult); + } + aResult = nsnull; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::SetClass(nsIAtom* aClass) +{ + nsresult result = NS_OK; + if (nsnull != mDocument) { // set attr via style sheet + nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument); + result = sheet->SetClassFor(aClass, mTag, mAttributes); + } + else { // manage this ourselves and re-sync when we connect to doc + EnsureWritableAttributes(mAttributes, PRBool(nsnull != aClass)); + if (nsnull != mAttributes) { + PRInt32 count; + result = mAttributes->SetClass(aClass, count); + if (0 == count) { + ReleaseAttributes(mAttributes); + } + } + } + return result; +} + +nsresult +nsHTMLGenericContent::GetClass(nsIAtom*& aResult) const +{ + if (nsnull != mAttributes) { + return mAttributes->GetClass(aResult); + } + aResult = nsnull; + return NS_OK; +} + +nsresult +nsHTMLGenericContent::GetStyleRule(nsIStyleRule*& aResult) +{ + nsIStyleRule* result = nsnull; + + if (nsnull != mAttributes) { + mAttributes->QueryInterface(kIStyleRuleIID, (void**)&result); + } + aResult = result; + return NS_OK; +} + +nsIContentDelegate* +nsHTMLGenericContent::GetDelegate(nsIPresContext* aCX) +{ + gContentDelegate->AddRef(); + return gContentDelegate; +} + +void +nsHTMLGenericContent::ListAttributes(FILE* out) const +{ + nsISupportsArray* attrs; + if (NS_OK == NS_NewISupportsArray(&attrs)) { + PRInt32 index, count; + GetAllAttributeNames(attrs, count); + for (index = 0; index < count; index++) { + // name + nsIAtom* attr = (nsIAtom*)attrs->ElementAt(index); + nsAutoString buffer; + attr->ToString(buffer); + + // value + nsAutoString value; + GetAttribute(buffer, value); + buffer.Append("="); + buffer.Append(value); + + fputs(" ", out); + fputs(buffer, out); + NS_RELEASE(attr); + } + NS_RELEASE(attrs); + } +} + +nsresult +nsHTMLGenericContent::List(FILE* out, PRInt32 aIndent) const +{ + NS_PRECONDITION(nsnull != mDocument, "bad content"); + + PRInt32 index; + for (index = aIndent; --index >= 0; ) fputs(" ", out); + + nsIAtom* tag; + GetTag(tag); + if (tag != nsnull) { + nsAutoString buf; + tag->ToString(buf); + fputs(buf, out); + NS_RELEASE(tag); + } + + ListAttributes(out); + + nsrefcnt r = mContent->AddRef() - 1; + mContent->Release(); + fprintf(out, " refcount=%d<", r); + + PRBool canHaveKids; + mContent->CanContainChildren(canHaveKids); + if (canHaveKids) { + fputs("\n", out); + PRInt32 kids; + mContent->ChildCount(kids); + for (index = 0; index < kids; index++) { + nsIContent* kid; + mContent->ChildAt(index, kid); + kid->List(out, aIndent + 1); + NS_RELEASE(kid); + } + for (index = aIndent; --index >= 0; ) fputs(" ", out); + } + fputs(">\n", out); + + return NS_OK; +} + +nsresult +nsHTMLGenericContent::ToHTML(FILE* out) const +{ + nsAutoString tmp; + nsresult rv = ToHTMLString(tmp); + fputs(tmp, out); + return rv; +} + +// XXX i18n: this is wrong (?) because we need to know the outgoing +// character set (I think) +static void +QuoteForHTML(const nsString& aValue, nsString& aResult) +{ + aResult.Truncate(); + const PRUnichar* cp = aValue.GetUnicode(); + const PRUnichar* end = aValue.GetUnicode() + aValue.Length(); + aResult.Append('"'); + while (cp < end) { + PRUnichar ch = *cp++; + if ((ch >= 0x20) && (ch <= 0x7f)) { + if (ch == '\"') { + aResult.Append("""); + } + else { + aResult.Append(ch); + } + } + else { + aResult.Append("&#"); + aResult.Append((PRInt32) ch, 10); + aResult.Append(';'); + } + } + aResult.Append('"'); +} + +nsresult +nsHTMLGenericContent::ToHTMLString(nsString& aBuf) const +{ + aBuf.Truncate(0); + aBuf.Append('<'); + + if (nsnull != mTag) { + nsAutoString tmp; + mTag->ToString(tmp); + aBuf.Append(tmp); + } else { + aBuf.Append("?NULL"); + } + + if (nsnull != mAttributes) { + nsISupportsArray* attrs; + nsresult rv = NS_NewISupportsArray(&attrs); + if (NS_OK == rv) { + PRInt32 i, n; + mAttributes->GetAllAttributeNames(attrs, n); + nsAutoString name, value, quotedValue; + for (i = 0; i < n; i++) { + nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i); + atom->ToString(name); + aBuf.Append(' '); + aBuf.Append(name); + value.Truncate(); + GetAttribute(name, value); + if (value.Length() > 0) { + aBuf.Append('='); + QuoteForHTML(value, quotedValue); + aBuf.Append(quotedValue); + } + } + NS_RELEASE(attrs); + } + } + + aBuf.Append('>'); + return NS_OK; +} + +//---------------------------------------------------------------------- + +// XXX this is REALLY temporary code + +extern nsresult NS_NewBRFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aNewFrame); +extern nsresult NS_NewHRFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aNewFrame); +extern nsresult NS_NewObjectFrame(nsIContent* aContent, nsIFrame* aParentFrame, + nsIFrame*& aNewFrame); + +nsresult +nsHTMLGenericContent::CreateFrame(nsIPresContext* aPresContext, + nsIFrame* aParentFrame, + nsIStyleContext* aStyleContext, + nsIFrame*& aResult) +{ + nsIFrame* frame = nsnull; + nsresult rv = NS_OK; + + // Handle specific frame types + if (mTag == nsHTMLAtoms::applet) { + rv = NS_NewObjectFrame(mContent, aParentFrame, frame); + } + else if (mTag == nsHTMLAtoms::br) { + rv = NS_NewBRFrame(mContent, aParentFrame, frame); + } + else if (mTag == nsHTMLAtoms::hr) { + rv = NS_NewHRFrame(mContent, aParentFrame, frame); + } + if (NS_OK != rv) { + return rv; + } + + // XXX add code in here to force the odd ones into the empty frame? + // AREA, HEAD, META, MAP, etc... + + if (nsnull == frame) { + // When there is no explicit frame to create, assume it's a + // container and let style dictate the rest. + const nsStyleDisplay* styleDisplay = (const nsStyleDisplay*) + aStyleContext->GetStyleData(eStyleStruct_Display); + + // Use style to choose what kind of frame to create + nsresult rv; + switch (styleDisplay->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + rv = NS_NewCSSBlockFrame(&frame, mContent, aParentFrame); + break; + + case NS_STYLE_DISPLAY_INLINE: + rv = NS_NewCSSInlineFrame(&frame, mContent, aParentFrame); + break; + + default: + // Create an empty frame for holding content that is not being + // reflowed. + rv = nsFrame::NewFrame(&frame, mContent, aParentFrame); + break; + } + if (NS_OK != rv) { + return rv; + } + } + + frame->SetStyleContext(aPresContext, aStyleContext); + aResult = frame; + return NS_OK; +} + +//---------------------------------------------------------------------- + +// nsIScriptObjectOwner implementation + +nsresult +nsHTMLGenericContent::GetScriptObject(nsIScriptContext* aContext, + void** aScriptObject) +{ + nsresult res = NS_OK; + if (nsnull == mScriptObject) { + nsIDOMElement* ele = nsnull; + mContent->QueryInterface(kIDOMElementIID, (void**) &ele); + res = NS_NewScriptElement(aContext, ele, mParent, (void**)&mScriptObject); + NS_RELEASE(ele); + } + *aScriptObject = mScriptObject; + return res; +} + +nsresult +nsHTMLGenericContent::ResetScriptObject() +{ + mScriptObject = nsnull; + return NS_OK; +} + +//---------------------------------------------------------------------- + +// nsIDOMEventReceiver implementation + +nsresult +nsHTMLGenericContent::GetListenerManager(nsIEventListenerManager** aResult) +{ + if (nsnull != mListenerManager) { + NS_ADDREF(mListenerManager); + *aResult = mListenerManager; + return NS_OK; + } + nsresult rv = NS_NewEventListenerManager(aResult); + if (NS_OK == rv) { + mListenerManager = *aResult; + NS_ADDREF(mListenerManager); + } + return rv; +} + +nsresult +nsHTMLGenericContent::GetNewListenerManager(nsIEventListenerManager** aResult) +{ + return NS_NewEventListenerManager(aResult); +} + +nsresult +nsHTMLGenericContent::AddEventListener(nsIDOMEventListener* aListener, + const nsIID& aIID) +{ + nsIEventListenerManager *manager; + + if (NS_OK == GetListenerManager(&manager)) { + manager->AddEventListener(aListener, aIID); + NS_RELEASE(manager); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +nsresult +nsHTMLGenericContent::RemoveEventListener(nsIDOMEventListener* aListener, + const nsIID& aIID) +{ + if (nsnull != mListenerManager) { + mListenerManager->RemoveEventListener(aListener, aIID); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +//---------------------------------------------------------------------- + +nsresult +nsHTMLGenericContent::AddScriptEventListener(nsIAtom* aAttribute, + nsHTMLValue& aValue, + REFNSIID aIID) +{ + nsresult ret = NS_OK; + nsIScriptContext* context; + nsIScriptContextOwner* owner; + + if (nsnull != mDocument) { + owner = mDocument->GetScriptContextOwner(); + if (NS_OK == owner->GetScriptContext(&context)) { + if (nsHTMLAtoms::body == mTag || nsHTMLAtoms::frameset == mTag) { + nsIDOMEventReceiver *receiver; + nsIScriptGlobalObject *global = context->GetGlobalObject(); + + if (nsnull != global && NS_OK == global->QueryInterface(kIDOMEventReceiverIID, (void**)&receiver)) { + nsIEventListenerManager *manager; + if (NS_OK == receiver->GetListenerManager(&manager)) { + nsIScriptObjectOwner *mObjectOwner; + if (NS_OK == global->QueryInterface(kIScriptObjectOwnerIID, (void**)&mObjectOwner)) { + nsString value; + aValue.GetStringValue(value); + ret = manager->AddScriptEventListener(context, mObjectOwner, aAttribute, value, aIID); + NS_RELEASE(mObjectOwner); + } + NS_RELEASE(manager); + } + NS_RELEASE(receiver); + } + NS_IF_RELEASE(global); + } + else { + nsIEventListenerManager *manager; + if (NS_OK == GetListenerManager(&manager)) { + nsString value; + aValue.GetStringValue(value); + nsIScriptObjectOwner* owner; + if (NS_OK == mContent->QueryInterface(kIScriptObjectOwnerIID, + (void**) &owner)) { + ret = manager->AddScriptEventListener(context, owner, + aAttribute, value, aIID); + NS_RELEASE(owner); + } + NS_RELEASE(manager); + } + } + NS_RELEASE(context); + } + NS_RELEASE(owner); + } + return ret; +} + +nsresult +nsHTMLGenericContent::AttributeToString(nsIAtom* aAttribute, + nsHTMLValue& aValue, + nsString& aResult) const +{ + if (nsHTMLAtoms::style == aAttribute) { + if (eHTMLUnit_ISupports == aValue.GetUnit()) { + nsIStyleRule* rule = (nsIStyleRule*) aValue.GetISupportsValue(); + // rule->ToString(str); + aResult = "XXX style rule ToString goes here"; + return NS_CONTENT_ATTR_HAS_VALUE; + } + } + aResult.Truncate(); + return NS_CONTENT_ATTR_NOT_THERE; +} + +PRBool +nsHTMLGenericContent::ParseEnumValue(const nsString& aValue, + EnumTable* aTable, + nsHTMLValue& aResult) +{ + while (nsnull != aTable->tag) { + if (aValue.EqualsIgnoreCase(aTable->tag)) { + aResult.SetIntValue(aTable->value, eHTMLUnit_Enumerated); + return PR_TRUE; + } + aTable++; + } + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::EnumValueToString(const nsHTMLValue& aValue, + EnumTable* aTable, + nsString& aResult) +{ + aResult.Truncate(0); + if (aValue.GetUnit() == eHTMLUnit_Enumerated) { + PRInt32 v = aValue.GetIntValue(); + while (nsnull != aTable->tag) { + if (aTable->value == v) { + aResult.Append(aTable->tag); + return PR_TRUE; + } + aTable++; + } + } + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ParseValueOrPercent(const nsString& aString, + nsHTMLValue& aResult, + nsHTMLUnit aValueUnit) +{ // XXX should vave min/max values? + nsAutoString tmp(aString); + tmp.CompressWhitespace(PR_TRUE, PR_TRUE); + PRInt32 ec, val = tmp.ToInteger(&ec); + if (NS_OK == ec) { + if (tmp.Last() == '%') {/* XXX not 100% compatible with ebina's code */ + if (val < 0) val = 0; + if (val > 100) val = 100; + aResult.SetPercentValue(float(val)/100.0f); + } else { + if (eHTMLUnit_Pixel == aValueUnit) { + aResult.SetPixelValue(val); + } + else { + aResult.SetIntValue(val, aValueUnit); + } + } + return PR_TRUE; + } + + // Illegal values are mapped to empty + aResult.SetEmptyValue(); + return PR_FALSE; +} + +/* used to parse attribute values that could be either: + * integer (n), + * percent (n%), + * or proportional (n*) + */ +void +nsHTMLGenericContent::ParseValueOrPercentOrProportional(const nsString& aString, + nsHTMLValue& aResult, + nsHTMLUnit aValueUnit) +{ // XXX should have min/max values? + nsAutoString tmp(aString); + tmp.CompressWhitespace(PR_TRUE, PR_TRUE); + PRInt32 ec, val = tmp.ToInteger(&ec); + if (tmp.Last() == '%') {/* XXX not 100% compatible with ebina's code */ + if (val < 0) val = 0; + if (val > 100) val = 100; + aResult.SetPercentValue(float(val)/100.0f); + } else if (tmp.Last() == '*') { + if (val < 0) val = 0; + aResult.SetIntValue(val, eHTMLUnit_Proportional); // proportional values are integers + } else { + if (eHTMLUnit_Pixel == aValueUnit) { + aResult.SetPixelValue(val); + } + else { + aResult.SetIntValue(val, aValueUnit); + } + } +} + +PRBool +nsHTMLGenericContent::ValueOrPercentToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + aResult.Truncate(0); + switch (aValue.GetUnit()) { + case eHTMLUnit_Integer: + aResult.Append(aValue.GetIntValue(), 10); + return PR_TRUE; + case eHTMLUnit_Pixel: + aResult.Append(aValue.GetPixelValue(), 10); + return PR_TRUE; + case eHTMLUnit_Percent: + aResult.Append(PRInt32(aValue.GetPercentValue() * 100.0f), 10); + aResult.Append('%'); + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ParseValue(const nsString& aString, PRInt32 aMin, + nsHTMLValue& aResult, nsHTMLUnit aValueUnit) +{ + PRInt32 ec, val = aString.ToInteger(&ec); + if (NS_OK == ec) { + if (val < aMin) val = aMin; + if (eHTMLUnit_Pixel == aValueUnit) { + aResult.SetPixelValue(val); + } + else { + aResult.SetIntValue(val, aValueUnit); + } + return PR_TRUE; + } + + // Illegal values are mapped to empty + aResult.SetEmptyValue(); + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ParseValue(const nsString& aString, PRInt32 aMin, + PRInt32 aMax, + nsHTMLValue& aResult, nsHTMLUnit aValueUnit) +{ + PRInt32 ec, val = aString.ToInteger(&ec); + if (NS_OK == ec) { + if (val < aMin) val = aMin; + if (val > aMax) val = aMax; + if (eHTMLUnit_Pixel == aValueUnit) { + aResult.SetPixelValue(val); + } + else { + aResult.SetIntValue(val, aValueUnit); + } + return PR_TRUE; + } + + // Illegal values are mapped to empty + aResult.SetEmptyValue(); + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ParseColor(const nsString& aString, + nsHTMLValue& aResult) +{ + if (aString.Length() > 0) { + nsAutoString colorStr (aString); + colorStr.CompressWhitespace(); + char cbuf[40]; + colorStr.ToCString(cbuf, sizeof(cbuf)); + nscolor color; + if (NS_ColorNameToRGB(cbuf, &color)) { + aResult.SetStringValue(colorStr); + return PR_TRUE; + } + if (NS_HexToRGB(cbuf, &color)) { + aResult.SetColorValue(color); + return PR_TRUE; + } + } + + // Illegal values are mapped to empty + aResult.SetEmptyValue(); + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ColorToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + if (aValue.GetUnit() == eHTMLUnit_Color) { + nscolor v = aValue.GetColorValue(); + char buf[10]; + PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x", + NS_GET_R(v), NS_GET_G(v), NS_GET_B(v)); + aResult.Truncate(0); + aResult.Append(buf); + return PR_TRUE; + } + if (aValue.GetUnit() == eHTMLUnit_String) { + aValue.GetStringValue(aResult); + return PR_TRUE; + } + if (aValue.GetUnit() == eHTMLUnit_Empty) { // was illegal + aResult.Truncate(); + return PR_TRUE; + } + return PR_FALSE; +} + +// XXX check all mappings against ebina's usage +static nsHTMLGenericContent::EnumTable kAlignTable[] = { + { "left", NS_STYLE_TEXT_ALIGN_LEFT }, + { "right", NS_STYLE_TEXT_ALIGN_RIGHT }, + { "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP }, + { "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE }, + { "center", NS_STYLE_TEXT_ALIGN_CENTER }, + { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM }, + { "top", NS_STYLE_VERTICAL_ALIGN_TOP }, + { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM }, + { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE }, + { 0 } +}; + +PRBool +nsHTMLGenericContent::ParseAlignValue(const nsString& aString, + nsHTMLValue& aResult) +{ + return ParseEnumValue(aString, kAlignTable, aResult); +} + +PRBool +nsHTMLGenericContent::AlignValueToString(const nsHTMLValue& aValue, + nsString& aResult) +{ + return EnumValueToString(aValue, kAlignTable, aResult); +} + +PRBool +nsHTMLGenericContent::ParseImageAttribute(nsIAtom* aAttribute, + const nsString& aString, + nsHTMLValue& aResult) +{ + if ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height)) { + ParseValueOrPercent(aString, aResult, eHTMLUnit_Pixel); + return PR_TRUE; + } + else if ((aAttribute == nsHTMLAtoms::hspace) || + (aAttribute == nsHTMLAtoms::vspace) || + (aAttribute == nsHTMLAtoms::border)) { + ParseValue(aString, 0, aResult, eHTMLUnit_Pixel); + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsHTMLGenericContent::ImageAttributeToString(nsIAtom* aAttribute, + const nsHTMLValue& aValue, + nsString& aResult) +{ + if ((aAttribute == nsHTMLAtoms::width) || + (aAttribute == nsHTMLAtoms::height) || + (aAttribute == nsHTMLAtoms::border) || + (aAttribute == nsHTMLAtoms::hspace) || + (aAttribute == nsHTMLAtoms::vspace)) { + return ValueOrPercentToString(aValue, aResult); + } + return PR_FALSE; +} + +void +nsHTMLGenericContent::MapImageAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) +{ + if (nsnull != mAttributes) { + nsHTMLValue value; + + float p2t = aPresContext->GetPixelsToTwips(); + nsStylePosition* pos = (nsStylePosition*) + aContext->GetMutableStyleData(eStyleStruct_Position); + nsStyleSpacing* spacing = (nsStyleSpacing*) + aContext->GetMutableStyleData(eStyleStruct_Spacing); + + // width: value + GetAttribute(nsHTMLAtoms::width, value); + if (value.GetUnit() == eHTMLUnit_Pixel) { + nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t); + pos->mWidth.SetCoordValue(twips); + } + else if (value.GetUnit() == eHTMLUnit_Percent) { + pos->mWidth.SetPercentValue(value.GetPercentValue()); + } + + // height: value + GetAttribute(nsHTMLAtoms::height, value); + if (value.GetUnit() == eHTMLUnit_Pixel) { + nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t); + pos->mHeight.SetCoordValue(twips); + } + else if (value.GetUnit() == eHTMLUnit_Percent) { + pos->mHeight.SetPercentValue(value.GetPercentValue()); + } + + // hspace: value + GetAttribute(nsHTMLAtoms::hspace, value); + if (value.GetUnit() == eHTMLUnit_Pixel) { + nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t); + spacing->mMargin.SetRight(nsStyleCoord(twips)); + } + else if (value.GetUnit() == eHTMLUnit_Percent) { + spacing->mMargin.SetRight(nsStyleCoord(value.GetPercentValue(), + eStyleUnit_Coord)); + } + + // vspace: value + GetAttribute(nsHTMLAtoms::vspace, value); + if (value.GetUnit() == eHTMLUnit_Pixel) { + nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t); + spacing->mMargin.SetBottom(nsStyleCoord(twips)); + } + else if (value.GetUnit() == eHTMLUnit_Percent) { + spacing->mMargin.SetBottom(nsStyleCoord(value.GetPercentValue(), + eStyleUnit_Coord)); + } + } +} + +void +nsHTMLGenericContent::MapImageAlignAttributeInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext) +{ + if (nsnull != mAttributes) { + nsHTMLValue value; + GetAttribute(nsHTMLAtoms::align, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) { + PRUint8 align = value.GetIntValue(); + nsStyleDisplay* display = (nsStyleDisplay*) + aContext->GetMutableStyleData(eStyleStruct_Display); + nsStyleText* text = (nsStyleText*) + aContext->GetMutableStyleData(eStyleStruct_Text); + nsStyleSpacing* spacing = (nsStyleSpacing*) + aContext->GetMutableStyleData(eStyleStruct_Spacing); + float p2t = aPresContext->GetPixelsToTwips(); + nsStyleCoord three(NSIntPixelsToTwips(3, p2t)); + switch (align) { + case NS_STYLE_TEXT_ALIGN_LEFT: + display->mFloats = NS_STYLE_FLOAT_LEFT; + spacing->mMargin.SetLeft(three); + spacing->mMargin.SetRight(three); + break; + case NS_STYLE_TEXT_ALIGN_RIGHT: + display->mFloats = NS_STYLE_FLOAT_RIGHT; + spacing->mMargin.SetLeft(three); + spacing->mMargin.SetRight(three); + break; + default: + text->mVerticalAlign.SetIntValue(align, eStyleUnit_Enumerated); + break; + } + } + } +} + +void +nsHTMLGenericContent::MapImageBorderAttributesInto(nsIStyleContext* aContext, + nsIPresContext* aPresContext, + nscolor aBorderColors[4]) +{ + if (nsnull != mAttributes) { + nsHTMLValue value; + + // border: pixels + GetAttribute(nsHTMLAtoms::border, value); + if (value.GetUnit() != eHTMLUnit_Pixel) { + if (nsnull == aBorderColors) { + return; + } + // If no border is defined and we are forcing a border, force + // the size to 2 pixels. + value.SetPixelValue(2); + } + + float p2t = aPresContext->GetPixelsToTwips(); + nscoord twips = NSIntPixelsToTwips(value.GetPixelValue(), p2t); + + // Fixup border-padding sums: subtract out the old size and then + // add in the new size. + nsStyleSpacing* spacing = (nsStyleSpacing*) + aContext->GetMutableStyleData(eStyleStruct_Spacing); + nsStyleCoord coord; + coord.SetCoordValue(twips); + spacing->mBorder.SetTop(coord); + spacing->mBorder.SetRight(coord); + spacing->mBorder.SetBottom(coord); + spacing->mBorder.SetLeft(coord); + spacing->mBorderStyle[0] = NS_STYLE_BORDER_STYLE_SOLID; + spacing->mBorderStyle[1] = NS_STYLE_BORDER_STYLE_SOLID; + spacing->mBorderStyle[2] = NS_STYLE_BORDER_STYLE_SOLID; + spacing->mBorderStyle[3] = NS_STYLE_BORDER_STYLE_SOLID; + + // Use supplied colors if provided, otherwise use color for border + // color + if (nsnull != aBorderColors) { + spacing->mBorderColor[0] = aBorderColors[0]; + spacing->mBorderColor[1] = aBorderColors[1]; + spacing->mBorderColor[2] = aBorderColors[2]; + spacing->mBorderColor[3] = aBorderColors[3]; + } + else { + // Color is inherited from "color" + const nsStyleColor* styleColor = (const nsStyleColor*) + aContext->GetStyleData(eStyleStruct_Color); + nscolor color = styleColor->mColor; + spacing->mBorderColor[0] = color; + spacing->mBorderColor[1] = color; + spacing->mBorderColor[2] = color; + spacing->mBorderColor[3] = color; + } + } +} + +void +nsHTMLGenericContent::TriggerLink(nsIPresContext& aPresContext, + const nsString& aBase, + const nsString& aURLSpec, + const nsString& aTargetSpec, + PRBool aClick) +{ + nsILinkHandler* handler; + if (NS_OK == aPresContext.GetLinkHandler(&handler) && (nsnull != handler)) { + // Resolve url to an absolute url + nsIURL* docURL = nsnull; + nsIDocument* doc; + if (NS_OK == GetDocument(doc)) { + docURL = doc->GetDocumentURL(); + NS_RELEASE(doc); + } + + nsAutoString absURLSpec; + if (aURLSpec.Length() > 0) { + nsresult rv = NS_MakeAbsoluteURL(docURL, aBase, aURLSpec, absURLSpec); + } + else { + absURLSpec = aURLSpec; + } + + if (nsnull != docURL) { + NS_RELEASE(docURL); + } + + // Now pass on absolute url to the click handler + if (aClick) { + handler->OnLinkClick(nsnull, absURLSpec, aTargetSpec); + } + else { + handler->OnOverLink(nsnull, absURLSpec, aTargetSpec); + } + NS_RELEASE(handler); + } +} + +//---------------------------------------------------------------------- + +nsHTMLGenericLeafContent::nsHTMLGenericLeafContent() +{ +} + +nsHTMLGenericLeafContent::~nsHTMLGenericLeafContent() +{ +} + +nsresult +nsHTMLGenericLeafContent::CopyInnerTo(nsIHTMLContent* aSrcContent, + nsHTMLGenericLeafContent* aDst) +{ + aDst->mContent = aSrcContent; + // XXX should the node's document be set? + // XXX copy attributes not yet impelemented + return NS_OK; +} + +nsresult +nsHTMLGenericLeafContent::Equals(nsIDOMNode* aNode, PRBool aDeep, + PRBool* aReturn) +{ + // XXX not yet implemented + *aReturn = PR_FALSE; + return NS_OK; +} + +nsresult +nsHTMLGenericLeafContent::BeginConvertToXIF(nsXIFConverter& aConverter) const +{ + nsresult rv = NS_OK; + if (nsnull != mTag) + { + nsAutoString name; + mTag->ToString(name); + aConverter.BeginLeaf(name); + } + + // Add all attributes to the convert + if (nsnull != mAttributes) + { + nsISupportsArray* attrs; + rv = NS_NewISupportsArray(&attrs); + if (NS_OK == rv) + { + PRInt32 i, n; + mAttributes->GetAllAttributeNames(attrs, n); + nsAutoString name, value; + for (i = 0; i < n; i++) + { + nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i); + atom->ToString(name); + + value.Truncate(); + GetAttribute(name, value); + + aConverter.AddHTMLAttribute(name,value); + } + NS_RELEASE(attrs); + } + } + return rv; +} + +nsresult +nsHTMLGenericLeafContent::ConvertContentToXIF(nsXIFConverter& aConverter) const +{ + return NS_OK; +} + +nsresult +nsHTMLGenericLeafContent::FinishConvertToXIF(nsXIFConverter& aConverter) const +{ + if (nsnull != mTag) + { + nsAutoString name; + mTag->ToString(name); + aConverter.EndLeaf(name); + } + return NS_OK; +} + +// XXX not really implemented (yet) +nsresult +nsHTMLGenericLeafContent::SizeOf(nsISizeOfHandler* aHandler) const +{ + aHandler->Add(sizeof(*this)); + return NS_OK; +} + +//---------------------------------------------------------------------- + +nsHTMLGenericContainerContent::nsHTMLGenericContainerContent() +{ +} + +nsHTMLGenericContainerContent::~nsHTMLGenericContainerContent() +{ + PRInt32 n = mChildren.Count(); + for (PRInt32 i = 0; i < n; i++) { + nsIContent* kid = (nsIContent*) mChildren.ElementAt(i); + NS_RELEASE(kid); + } +// if (nsnull != mChildNodes) { +// mChildNodes->ReleaseContent(); +// NS_RELEASE(mChildNodes); +// } +} + +nsresult +nsHTMLGenericContainerContent:: CopyInnerTo(nsIHTMLContent* aSrcContent, + nsHTMLGenericContainerContent* aDst) +{ + aDst->mContent = aSrcContent; + // XXX should the node's document be set? + // XXX copy attributes not yet impelemented + // XXX deep copy? + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::Equals(nsIDOMNode* aNode, PRBool aDeep, + PRBool* aReturn) +{ + // XXX not yet implemented + *aReturn = PR_FALSE; + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::GetChildNodes(nsIDOMNodeList** aChildNodes) +{ + *aChildNodes = nsnull; + return NS_OK; +// NS_PRECONDITION(nsnull != aChildNodes, "null pointer"); +// if (nsnull == mChildNodes) { +// mChildNodes = new nsDOMNodeList(this); +// NS_ADDREF(mChildNodes); +// } +// *aChildNodes = mChildNodes; +// NS_ADDREF(mChildNodes); +// return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::GetHasChildNodes(PRBool* aReturn) +{ + if (0 != mChildren.Count()) { + *aReturn = PR_TRUE; + } + else { + *aReturn = PR_FALSE; + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::GetFirstChild(nsIDOMNode** aNode) +{ + nsIContent *child = (nsIContent*) mChildren.ElementAt(0); + if (nsnull != child) { + nsresult res = child->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); // must be a DOM Node + return res; + } + aNode = nsnull; + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::GetLastChild(nsIDOMNode** aNode) +{ + nsIContent *child = (nsIContent*) mChildren.ElementAt(mChildren.Count()-1); + if (nsnull != child) { + nsresult res = child->QueryInterface(kIDOMNodeIID, (void**)aNode); + NS_ASSERTION(NS_OK == res, "Must be a DOM Node"); // must be a DOM Node + return res; + } + aNode = nsnull; + return NS_OK; +} + +static void +SetDocumentInChildrenOf(nsIContent* aContent, nsIDocument* aDocument) +{ + PRInt32 i, n; + aContent->ChildCount(n); + for (i = 0; i < n; i++) { + nsIContent* child; + aContent->ChildAt(i, child); + if (nsnull != child) { + child->SetDocument(aDocument); + SetDocumentInChildrenOf(child, aDocument); + } + } +} + +// XXX It's possible that newChild has already been inserted in the +// tree; if this is the case then we need to remove it from where it +// was before placing it in it's new home + +nsresult +nsHTMLGenericContainerContent::InsertBefore(nsIDOMNode* aNewChild, + nsIDOMNode* aRefChild, + nsIDOMNode** aReturn) +{ + if (nsnull == aNewChild) { + *aReturn = nsnull; + return NS_OK;/* XXX wrong error value */ + } + + // Get the nsIContent interface for the new content + nsIContent* newContent = nsnull; + nsresult res = aNewChild->QueryInterface(kIContentIID, (void**)&newContent); + NS_ASSERTION(NS_OK == res, "New child must be an nsIContent"); + if (NS_OK == res) { + if (nsnull == aRefChild) { + // Append the new child to the end + SetDocumentInChildrenOf(newContent, mDocument); + res = AppendChildTo(newContent, PR_TRUE); + } + else { + // Get the index of where to insert the new child + nsIContent* refContent = nsnull; + res = aRefChild->QueryInterface(kIContentIID, (void**)&refContent); + NS_ASSERTION(NS_OK == res, "Ref child must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos; + IndexOf(refContent, pos); + if (pos >= 0) { + SetDocumentInChildrenOf(newContent, mDocument); + res = InsertChildAt(newContent, pos, PR_TRUE); + } + NS_RELEASE(refContent); + } + } + NS_RELEASE(newContent); + + *aReturn = aNewChild; + NS_ADDREF(aNewChild); + } + else { + *aReturn = nsnull; + } + + return res; +} + +nsresult +nsHTMLGenericContainerContent::ReplaceChild(nsIDOMNode* aNewChild, + nsIDOMNode* aOldChild, + nsIDOMNode** aReturn) +{ + nsIContent* content = nsnull; + *aReturn = nsnull; + nsresult res = aOldChild->QueryInterface(kIContentIID, (void**)&content); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos; + IndexOf(content, pos); + if (pos >= 0) { + nsIContent* newContent = nsnull; + nsresult res = aNewChild->QueryInterface(kIContentIID, (void**)&newContent); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + res = ReplaceChildAt(newContent, pos, PR_TRUE); + NS_RELEASE(newContent); + } + *aReturn = aOldChild; + NS_ADDREF(aOldChild); + } + NS_RELEASE(content); + } + + return res; +} + +nsresult +nsHTMLGenericContainerContent::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) +{ + nsIContent* content = nsnull; + *aReturn = nsnull; + nsresult res = aOldChild->QueryInterface(kIContentIID, (void**)&content); + NS_ASSERTION(NS_OK == res, "Must be an nsIContent"); + if (NS_OK == res) { + PRInt32 pos; + IndexOf(content, pos); + if (pos >= 0) { + res = RemoveChildAt(pos, PR_TRUE); + *aReturn = aOldChild; + NS_ADDREF(aOldChild); + } + NS_RELEASE(content); + } + + return res; +} + +nsresult +nsHTMLGenericContainerContent::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn) +{ + return InsertBefore(aNewChild, nsnull, aReturn); +} + +nsresult +nsHTMLGenericContainerContent::SizeOf(nsISizeOfHandler* aHandler) const +{ + aHandler->Add(sizeof(*this)); + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::BeginConvertToXIF(nsXIFConverter& aConverter) const +{ + nsresult rv = NS_OK; + if (nsnull != mTag) + { + nsAutoString name; + mTag->ToString(name); + aConverter.BeginContainer(name); + } + + // Add all attributes to the convert + if (nsnull != mAttributes) + { + nsISupportsArray* attrs; + rv = NS_NewISupportsArray(&attrs); + if (NS_OK == rv) + { + PRInt32 i, n; + mAttributes->GetAllAttributeNames(attrs, n); + nsAutoString name, value; + for (i = 0; i < n; i++) + { + nsIAtom* atom = (nsIAtom*) attrs->ElementAt(i); + atom->ToString(name); + + value.Truncate(); + GetAttribute(name, value); + + aConverter.AddHTMLAttribute(name,value); + } + NS_RELEASE(attrs); + } + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::ConvertContentToXIF(nsXIFConverter& aConverter) const +{ + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::FinishConvertToXIF(nsXIFConverter& aConverter) const +{ + if (nsnull != mTag) + { + nsAutoString name; + mTag->ToString(name); + aConverter.EndContainer(name); + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::Compact() +{ + mChildren.Compact(); + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::CanContainChildren(PRBool& aResult) const +{ + aResult = PR_TRUE; + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::ChildCount(PRInt32& aCount) const +{ + aCount = mChildren.Count(); + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::ChildAt(PRInt32 aIndex, + nsIContent*& aResult) const +{ + nsIContent *child = (nsIContent*) mChildren.ElementAt(aIndex); + if (nsnull != child) { + NS_ADDREF(child); + } + aResult = child; + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::IndexOf(nsIContent* aPossibleChild, + PRInt32& aIndex) const +{ + NS_PRECONDITION(nsnull != aPossibleChild, "null ptr"); + aIndex = mChildren.IndexOf(aPossibleChild); + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::InsertChildAt(nsIContent* aKid, + PRInt32 aIndex, + PRBool aNotify) +{ + NS_PRECONDITION(nsnull != aKid, "null ptr"); + PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/ + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(mContent); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + if (aNotify) { + doc->ContentInserted(mContent, aKid, aIndex); + } + } + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::ReplaceChildAt(nsIContent* aKid, + PRInt32 aIndex, + PRBool aNotify) +{ + NS_PRECONDITION(nsnull != aKid, "null ptr"); + nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex); + PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex); + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(mContent); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + if (aNotify) { + doc->ContentReplaced(mContent, oldKid, aKid, aIndex); + } + } + oldKid->SetDocument(nsnull); + oldKid->SetParent(nsnull); + NS_RELEASE(oldKid); + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::AppendChildTo(nsIContent* aKid, PRBool aNotify) +{ + NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr"); + PRBool rv = mChildren.AppendElement(aKid); + if (rv) { + NS_ADDREF(aKid); + aKid->SetParent(mContent); + nsIDocument* doc = mDocument; + if (nsnull != doc) { + aKid->SetDocument(doc); + if (aNotify) { + doc->ContentAppended(mContent, mChildren.Count() - 1); + } + } + } + return NS_OK; +} + +nsresult +nsHTMLGenericContainerContent::RemoveChildAt(PRInt32 aIndex, PRBool aNotify) +{ + nsIContent* oldKid = (nsIContent*) mChildren.ElementAt(aIndex); + if (nsnull != oldKid ) { + nsIDocument* doc = mDocument; + if (aNotify) { + if (nsnull != doc) { + doc->ContentWillBeRemoved(mContent, oldKid, aIndex); + } + } + PRBool rv = mChildren.RemoveElementAt(aIndex); + if (aNotify) { + if (nsnull != doc) { + doc->ContentHasBeenRemoved(mContent, oldKid, aIndex); + } + } + oldKid->SetDocument(nsnull); + oldKid->SetParent(nsnull); + NS_RELEASE(oldKid); + } + + return NS_OK; +} diff --git a/layout/html/document/src/nsHTMLContentSink.cpp b/layout/html/document/src/nsHTMLContentSink.cpp index 107b2194bf0b..462063f3f437 100644 --- a/layout/html/document/src/nsHTMLContentSink.cpp +++ b/layout/html/document/src/nsHTMLContentSink.cpp @@ -170,6 +170,7 @@ public: nsIHTMLContent* mRoot; nsIHTMLContent* mBody; + PRInt32 mBodyChildCount; nsIHTMLContent* mFrameset; nsIHTMLContent* mHead; nsString* mTitle; @@ -1378,7 +1379,8 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) ("HTMLContentSink::DidBuildModel: layout final content")); // Reflow the last batch of content - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); ScrollToRef(); mDocument->EndLoad(); @@ -1391,7 +1393,8 @@ HTMLContentSink::WillInterrupt() SINK_TRACE(SINK_TRACE_CALLS, ("HTMLContentSink::WillInterrupt: this=%p", this)); if (mDirty && !mInMonolithicContainer) { - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); mDirty = PR_FALSE; } return NS_OK; @@ -1571,6 +1574,7 @@ HTMLContentSink::OpenBody(const nsIParserNode& aNode) return rv; } mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent; + mBodyChildCount = 0; NS_ADDREF(mBody); StartLayout(); @@ -1592,7 +1596,8 @@ HTMLContentSink::CloseBody(const nsIParserNode& aNode) if (didFlush) { // Trigger a reflow for the flushed text - mDocument->ContentAppended(mBody); + mDocument->ContentAppended(mBody, mBodyChildCount); + mBody->ChildCount(mBodyChildCount); } return NS_OK; @@ -1815,7 +1820,7 @@ HTMLContentSink::StartLayout() nsIPresContext* cx = shell->GetPresContext(); nsRect r; cx->GetVisibleArea(r); - shell->ResizeReflow(r.width, r.height); + shell->InitialReflow(r.width, r.height); NS_RELEASE(cx); // Now trigger a refresh diff --git a/layout/html/forms/src/nsInputButton.cpp b/layout/html/forms/src/nsInputButton.cpp index 9c026b52edbb..981fd987bc85 100644 --- a/layout/html/forms/src/nsInputButton.cpp +++ b/layout/html/forms/src/nsInputButton.cpp @@ -351,6 +351,18 @@ nsInputButton::GetAttributeMappingFunction(nsMapAttributesFunc& aMapFunc) const //---------------------------------------------------------------------- // nsInputButtonFrame Implementation +nsresult +NS_NewInputButtonFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsInputButtonFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + nsInputButtonFrame::nsInputButtonFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsInputFrame(aContent, aParentFrame) diff --git a/layout/html/forms/src/nsInputCheckbox.cpp b/layout/html/forms/src/nsInputCheckbox.cpp index 731d11c812a3..3836f64026f9 100644 --- a/layout/html/forms/src/nsInputCheckbox.cpp +++ b/layout/html/forms/src/nsInputCheckbox.cpp @@ -53,6 +53,18 @@ protected: nsSize& aDesiredWidgetSize); }; +nsresult +NS_NewInputCheckboxFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsInputCheckboxFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + nsInputCheckboxFrame::nsInputCheckboxFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsInputFrame(aContent, aParentFrame) { diff --git a/layout/html/forms/src/nsInputFile.cpp b/layout/html/forms/src/nsInputFile.cpp index 309df1d1942b..bc1711d1deab 100644 --- a/layout/html/forms/src/nsInputFile.cpp +++ b/layout/html/forms/src/nsInputFile.cpp @@ -36,6 +36,18 @@ PRInt32 nsInputFileFrame::gSpacing = 40; nsString* nsInputFile::gFILE_TYPE = new nsString("file"); +nsresult +NS_NewInputFileFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsInputFileFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + nsInputFileFrame::nsInputFileFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsHTMLContainerFrame(aContent, aParentFrame) { diff --git a/layout/html/forms/src/nsInputRadio.cpp b/layout/html/forms/src/nsInputRadio.cpp index d12b0a199746..1e9303296e43 100644 --- a/layout/html/forms/src/nsInputRadio.cpp +++ b/layout/html/forms/src/nsInputRadio.cpp @@ -57,6 +57,18 @@ protected: nsSize& aDesiredWidgetSize); }; +nsresult +NS_NewInputRadioFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsInputRadioFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + nsInputRadioFrame::nsInputRadioFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsInputFrame(aContent, aParentFrame) { diff --git a/layout/html/forms/src/nsInputText.cpp b/layout/html/forms/src/nsInputText.cpp index 8b67057932f4..0d5d8884b8fc 100644 --- a/layout/html/forms/src/nsInputText.cpp +++ b/layout/html/forms/src/nsInputText.cpp @@ -73,6 +73,18 @@ protected: nsSize& aDesiredWidgetSize); }; +nsresult +NS_NewInputTextFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsInputTextFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + nsInputTextFrame::nsInputTextFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsInputFrame(aContent, aParentFrame) diff --git a/layout/html/forms/src/nsSelect.cpp b/layout/html/forms/src/nsSelect.cpp index 81a3ce0f5c68..c5927c613cb8 100644 --- a/layout/html/forms/src/nsSelect.cpp +++ b/layout/html/forms/src/nsSelect.cpp @@ -163,6 +163,17 @@ protected: nsString* mContent; }; +nsresult +NS_NewHTMLSelectFrame(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame*& aResult) +{ + aResult = new nsSelectFrame(aContent, aParent); + if (nsnull == aResult) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} nsSelectFrame::nsSelectFrame(nsIContent* aContent, nsIFrame* aParentFrame) diff --git a/layout/html/style/src/nsHTMLStyleSheet.cpp b/layout/html/style/src/nsHTMLStyleSheet.cpp index d214750b6387..ff0a65eab4c9 100644 --- a/layout/html/style/src/nsHTMLStyleSheet.cpp +++ b/layout/html/style/src/nsHTMLStyleSheet.cpp @@ -35,10 +35,17 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsHTMLIIDs.h" +#include "nsIStyleFrameConstruction.h" +#include "nsHTMLParts.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsStyleConsts.h" +#include "nsTableOuterFrame.h" static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class HTMLAnchorRule : public nsIStyleRule { @@ -173,7 +180,8 @@ nsHashKey* AttributeKey::Clone(void) const // ----------------------------------------------------------- -class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet, + public nsIStyleFrameConstruction { public: void* operator new(size_t size); void* operator new(size_t size, nsIArena* aArena); @@ -217,6 +225,15 @@ public: NS_IMETHOD UnsetAttributeFor(nsIAtom* aAttribute, nsIHTMLContent* aContent, nsIHTMLAttributes*& aAttributes); + NS_IMETHOD ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); // XXX style rule enumerations @@ -239,6 +256,14 @@ protected: PRInt32 aAttrCount, nsIHTMLAttributes*& aAttributes); + nsresult ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent); + + nsresult CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame); + protected: PRUint32 mInHeap : 1; PRUint32 mRefCnt : 31; @@ -330,8 +355,13 @@ nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, AddRef(); return NS_OK; } + if (aIID.Equals(kIStyleFrameConstructionIID)) { + *aInstancePtrResult = (void*) ((nsIStyleFrameConstruction*)this); + AddRef(); + return NS_OK; + } if (aIID.Equals(kISupportsIID)) { - *aInstancePtrResult = (void*) ((nsISupports*)this); + *aInstancePtrResult = (void*) this; AddRef(); return NS_OK; } @@ -816,6 +846,316 @@ NS_IMETHODIMP HTMLStyleSheetImpl::UnsetAttributeFor(nsIAtom* aAttribute, } +nsresult HTMLStyleSheetImpl::ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent) +{ + nsIFrame* childList = nsnull; + nsIFrame* lastChildFrame = nsnull; + PRInt32 count; + aContent->ChildCount(count); + + for (PRInt32 i = 0; i < count; i++) { + nsIContent* childContent; + aContent->ChildAt(i, childContent); + + if (nsnull != childContent) { + nsIFrame* childFrame; + + // Construct a child frame + ConstructFrame(aPresContext, childContent, aFrame, childFrame); + + if (nsnull != childFrame) { + // Link the frame into the child list + if (nsnull == lastChildFrame) { + childList = childFrame; + } else { + lastChildFrame->SetNextSibling(childFrame); + } + lastChildFrame = childFrame; + } + + NS_RELEASE(childContent); + } + } + + // Initialize the frame giving it its child list. + // XXX Should we call Init(), or just return the child list and let the + // caller call Init()? + aFrame->Init(*aPresContext, childList); + return NS_OK; +} + +nsresult +HTMLStyleSheetImpl::CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame) +{ + nsresult rv; + + // Figure out which type of input frame to create + nsAutoString val; + if (NS_OK == aContent->GetAttribute(nsAutoString("type"), val)) { + if (val.EqualsIgnoreCase("submit")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("reset")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("button")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("checkbox")) { + rv = NS_NewInputCheckboxFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("file")) { + rv = NS_NewInputFileFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("hidden")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("image")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("password")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("radio")) { + rv = NS_NewInputRadioFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("text")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + } else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + + return rv; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + // Get the tag + nsIAtom* tag; + aContent->GetTag(tag); + + aFrameSubTree = nsnull; + + // Resolve the style context. + // XXX Cheesy hack for text + nsIStyleContext* styleContext; + if (nsnull == tag) { + styleContext = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::text, aParentFrame); + } else { + styleContext = aPresContext->ResolveStyleContextFor(aContent, aParentFrame); + } + + // Create a frame. + if (nsnull == aParentFrame) { + // This should only be the case for the root content object. + // XXX Add assertion... + nsIFrame* rootFrame; + + // Create the root frame and set its style context + NS_NewHTMLFrame(aContent, nsnull, rootFrame); + rootFrame->SetStyleContext(aPresContext, styleContext); + + // Bind root frame to root view (and root window) + nsIPresShell* presShell = aPresContext->GetShell(); + nsIViewManager* viewManager = presShell->GetViewManager(); + nsIView* rootView; + + NS_RELEASE(presShell); + viewManager->GetRootView(rootView); + rootFrame->SetView(rootView); + NS_RELEASE(viewManager); + + // Process the children + ProcessChildren(aPresContext, rootFrame, aContent); + + // Return the frame sub-tree + aFrameSubTree = rootFrame; + + } else { + nsIFrame* frame = nsnull; + nsresult rv = NS_OK; + + // Handle specific frame types + if (nsnull == tag) { + rv = NS_NewTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::applet == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::body == tag) { + rv = NS_NewBodyFrame(aContent, aParentFrame, frame); + + // Process the children + ProcessChildren(aPresContext, frame, aContent); + } + else if (nsHTMLAtoms::frameset == tag) { + rv = NS_NewHTMLFramesetFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::br == tag) { + rv = NS_NewBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::embed == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::hr == tag) { + rv = NS_NewHRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::img == tag) { + rv = NS_NewImageFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::object == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::spacer == tag) { + rv = NS_NewSpacerFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::wbr == tag) { + rv = NS_NewWBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::table == tag) { + rv = nsTableOuterFrame::NewFrame(&frame, aContent, aParentFrame); + } + else if (nsHTMLAtoms::input == tag) { + rv = CreateInputFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::textarea == tag) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::select == tag) { + rv = NS_NewHTMLSelectFrame(aContent, aParentFrame, frame); + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + + // XXX add code in here to force the odd ones into the empty frame? + // AREA, HEAD, META, MAP, etc... + + if (nsnull == frame) { + // When there is no explicit frame to create, assume it's a + // container and let style dictate the rest. + const nsStyleDisplay* styleDisplay = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + // Use style to choose what kind of frame to create + nsresult rv; + switch (styleDisplay->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + rv = NS_NewCSSBlockFrame(&frame, aContent, aParentFrame); + ProcessChildren(aPresContext, frame, aContent); + break; + + case NS_STYLE_DISPLAY_INLINE: + rv = NS_NewCSSInlineFrame(&frame, aContent, aParentFrame); + break; + + default: + // XXX Don't create a placeholder frame for content that's not + // displayed... +#if 0 + // Create an empty frame for holding content that is not being + // reflowed. + rv = nsFrame::NewFrame(&frame, aContent, aParentFrame); +#endif + break; + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + } + + if (nsnull != frame) { + frame->SetStyleContext(aPresContext, styleContext); + } + aFrameSubTree = frame; + } + + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return NS_OK; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + nsIPresShell* shell = aPresContext->GetShell(); + nsIContent* parentContainer = aContainer; + while (nsnull != parentContainer) { + nsIFrame* parentFrame = shell->FindFrameWithContent(parentContainer); + if (nsnull != parentFrame) { + // Get the parent frame's last-in-flow + nsIFrame* nextInFlow = parentFrame; + while (nsnull != nextInFlow) { + parentFrame->GetNextInFlow(nextInFlow); + if (nsnull != nextInFlow) { + parentFrame = nextInFlow; + } + } + + // Create some new frames + PRInt32 count; + nsIFrame* lastChildFrame = nsnull; + nsIFrame* firstAppendedFrame = nsnull; + + aContainer->ChildCount(count); + + for (PRInt32 i = aNewIndexInContainer; i < count; i++) { + nsIContent* child; + nsIFrame* frame; + + aContainer->ChildAt(i, child); + ConstructFrame(aPresContext, child, parentFrame, frame); + + // Link the frame into the child frame list + if (nsnull == lastChildFrame) { + firstAppendedFrame = frame; + } else { + lastChildFrame->SetNextSibling(frame); + } + + // XXX We should probably mark the frame as being dirty: that way the + // parent frame can easily identify the newly added frames. Either that + // or pass along in count in which case they must be contiguus... + lastChildFrame = frame; + } + + // Notify the parent frame with a reflow command, passing it the list of + // new frames. + nsIReflowCommand* reflowCmd; + nsresult result; + + result = NS_NewHTMLReflowCommand(&reflowCmd, parentFrame, + nsIReflowCommand::FrameAppended, + firstAppendedFrame); + if (NS_SUCCEEDED(result)) { + shell->AppendReflowCommand(reflowCmd); + } + break; + } + parentContainer->GetParent(parentContainer); + } + + NS_RELEASE(shell); + return NS_OK; +} void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const { diff --git a/layout/style/nsHTMLStyleSheet.cpp b/layout/style/nsHTMLStyleSheet.cpp index d214750b6387..ff0a65eab4c9 100644 --- a/layout/style/nsHTMLStyleSheet.cpp +++ b/layout/style/nsHTMLStyleSheet.cpp @@ -35,10 +35,17 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsHTMLIIDs.h" +#include "nsIStyleFrameConstruction.h" +#include "nsHTMLParts.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsStyleConsts.h" +#include "nsTableOuterFrame.h" static NS_DEFINE_IID(kIHTMLStyleSheetIID, NS_IHTML_STYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID); static NS_DEFINE_IID(kIStyleRuleIID, NS_ISTYLE_RULE_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class HTMLAnchorRule : public nsIStyleRule { @@ -173,7 +180,8 @@ nsHashKey* AttributeKey::Clone(void) const // ----------------------------------------------------------- -class HTMLStyleSheetImpl : public nsIHTMLStyleSheet { +class HTMLStyleSheetImpl : public nsIHTMLStyleSheet, + public nsIStyleFrameConstruction { public: void* operator new(size_t size); void* operator new(size_t size, nsIArena* aArena); @@ -217,6 +225,15 @@ public: NS_IMETHOD UnsetAttributeFor(nsIAtom* aAttribute, nsIHTMLContent* aContent, nsIHTMLAttributes*& aAttributes); + NS_IMETHOD ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); // XXX style rule enumerations @@ -239,6 +256,14 @@ protected: PRInt32 aAttrCount, nsIHTMLAttributes*& aAttributes); + nsresult ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent); + + nsresult CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame); + protected: PRUint32 mInHeap : 1; PRUint32 mRefCnt : 31; @@ -330,8 +355,13 @@ nsresult HTMLStyleSheetImpl::QueryInterface(const nsIID& aIID, AddRef(); return NS_OK; } + if (aIID.Equals(kIStyleFrameConstructionIID)) { + *aInstancePtrResult = (void*) ((nsIStyleFrameConstruction*)this); + AddRef(); + return NS_OK; + } if (aIID.Equals(kISupportsIID)) { - *aInstancePtrResult = (void*) ((nsISupports*)this); + *aInstancePtrResult = (void*) this; AddRef(); return NS_OK; } @@ -816,6 +846,316 @@ NS_IMETHODIMP HTMLStyleSheetImpl::UnsetAttributeFor(nsIAtom* aAttribute, } +nsresult HTMLStyleSheetImpl::ProcessChildren(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nsIContent* aContent) +{ + nsIFrame* childList = nsnull; + nsIFrame* lastChildFrame = nsnull; + PRInt32 count; + aContent->ChildCount(count); + + for (PRInt32 i = 0; i < count; i++) { + nsIContent* childContent; + aContent->ChildAt(i, childContent); + + if (nsnull != childContent) { + nsIFrame* childFrame; + + // Construct a child frame + ConstructFrame(aPresContext, childContent, aFrame, childFrame); + + if (nsnull != childFrame) { + // Link the frame into the child list + if (nsnull == lastChildFrame) { + childList = childFrame; + } else { + lastChildFrame->SetNextSibling(childFrame); + } + lastChildFrame = childFrame; + } + + NS_RELEASE(childContent); + } + } + + // Initialize the frame giving it its child list. + // XXX Should we call Init(), or just return the child list and let the + // caller call Init()? + aFrame->Init(*aPresContext, childList); + return NS_OK; +} + +nsresult +HTMLStyleSheetImpl::CreateInputFrame(nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrame) +{ + nsresult rv; + + // Figure out which type of input frame to create + nsAutoString val; + if (NS_OK == aContent->GetAttribute(nsAutoString("type"), val)) { + if (val.EqualsIgnoreCase("submit")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("reset")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("button")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("checkbox")) { + rv = NS_NewInputCheckboxFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("file")) { + rv = NS_NewInputFileFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("hidden")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("image")) { + rv = NS_NewInputButtonFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("password")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("radio")) { + rv = NS_NewInputRadioFrame(aContent, aParentFrame, aFrame); + } + else if (val.EqualsIgnoreCase("text")) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + } else { + rv = NS_NewInputTextFrame(aContent, aParentFrame, aFrame); + } + + return rv; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + // Get the tag + nsIAtom* tag; + aContent->GetTag(tag); + + aFrameSubTree = nsnull; + + // Resolve the style context. + // XXX Cheesy hack for text + nsIStyleContext* styleContext; + if (nsnull == tag) { + styleContext = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::text, aParentFrame); + } else { + styleContext = aPresContext->ResolveStyleContextFor(aContent, aParentFrame); + } + + // Create a frame. + if (nsnull == aParentFrame) { + // This should only be the case for the root content object. + // XXX Add assertion... + nsIFrame* rootFrame; + + // Create the root frame and set its style context + NS_NewHTMLFrame(aContent, nsnull, rootFrame); + rootFrame->SetStyleContext(aPresContext, styleContext); + + // Bind root frame to root view (and root window) + nsIPresShell* presShell = aPresContext->GetShell(); + nsIViewManager* viewManager = presShell->GetViewManager(); + nsIView* rootView; + + NS_RELEASE(presShell); + viewManager->GetRootView(rootView); + rootFrame->SetView(rootView); + NS_RELEASE(viewManager); + + // Process the children + ProcessChildren(aPresContext, rootFrame, aContent); + + // Return the frame sub-tree + aFrameSubTree = rootFrame; + + } else { + nsIFrame* frame = nsnull; + nsresult rv = NS_OK; + + // Handle specific frame types + if (nsnull == tag) { + rv = NS_NewTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::applet == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::body == tag) { + rv = NS_NewBodyFrame(aContent, aParentFrame, frame); + + // Process the children + ProcessChildren(aPresContext, frame, aContent); + } + else if (nsHTMLAtoms::frameset == tag) { + rv = NS_NewHTMLFramesetFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::br == tag) { + rv = NS_NewBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::embed == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::hr == tag) { + rv = NS_NewHRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::img == tag) { + rv = NS_NewImageFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::object == tag) { + rv = NS_NewObjectFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::spacer == tag) { + rv = NS_NewSpacerFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::wbr == tag) { + rv = NS_NewWBRFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::table == tag) { + rv = nsTableOuterFrame::NewFrame(&frame, aContent, aParentFrame); + } + else if (nsHTMLAtoms::input == tag) { + rv = CreateInputFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::textarea == tag) { + rv = NS_NewInputTextFrame(aContent, aParentFrame, frame); + } + else if (nsHTMLAtoms::select == tag) { + rv = NS_NewHTMLSelectFrame(aContent, aParentFrame, frame); + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + + // XXX add code in here to force the odd ones into the empty frame? + // AREA, HEAD, META, MAP, etc... + + if (nsnull == frame) { + // When there is no explicit frame to create, assume it's a + // container and let style dictate the rest. + const nsStyleDisplay* styleDisplay = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + // Use style to choose what kind of frame to create + nsresult rv; + switch (styleDisplay->mDisplay) { + case NS_STYLE_DISPLAY_BLOCK: + case NS_STYLE_DISPLAY_LIST_ITEM: + rv = NS_NewCSSBlockFrame(&frame, aContent, aParentFrame); + ProcessChildren(aPresContext, frame, aContent); + break; + + case NS_STYLE_DISPLAY_INLINE: + rv = NS_NewCSSInlineFrame(&frame, aContent, aParentFrame); + break; + + default: + // XXX Don't create a placeholder frame for content that's not + // displayed... +#if 0 + // Create an empty frame for holding content that is not being + // reflowed. + rv = nsFrame::NewFrame(&frame, aContent, aParentFrame); +#endif + break; + } + if (NS_OK != rv) { + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return rv; + } + } + + if (nsnull != frame) { + frame->SetStyleContext(aPresContext, styleContext); + } + aFrameSubTree = frame; + } + + NS_RELEASE(styleContext); + NS_IF_RELEASE(tag); + return NS_OK; +} + +NS_IMETHODIMP HTMLStyleSheetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + nsIPresShell* shell = aPresContext->GetShell(); + nsIContent* parentContainer = aContainer; + while (nsnull != parentContainer) { + nsIFrame* parentFrame = shell->FindFrameWithContent(parentContainer); + if (nsnull != parentFrame) { + // Get the parent frame's last-in-flow + nsIFrame* nextInFlow = parentFrame; + while (nsnull != nextInFlow) { + parentFrame->GetNextInFlow(nextInFlow); + if (nsnull != nextInFlow) { + parentFrame = nextInFlow; + } + } + + // Create some new frames + PRInt32 count; + nsIFrame* lastChildFrame = nsnull; + nsIFrame* firstAppendedFrame = nsnull; + + aContainer->ChildCount(count); + + for (PRInt32 i = aNewIndexInContainer; i < count; i++) { + nsIContent* child; + nsIFrame* frame; + + aContainer->ChildAt(i, child); + ConstructFrame(aPresContext, child, parentFrame, frame); + + // Link the frame into the child frame list + if (nsnull == lastChildFrame) { + firstAppendedFrame = frame; + } else { + lastChildFrame->SetNextSibling(frame); + } + + // XXX We should probably mark the frame as being dirty: that way the + // parent frame can easily identify the newly added frames. Either that + // or pass along in count in which case they must be contiguus... + lastChildFrame = frame; + } + + // Notify the parent frame with a reflow command, passing it the list of + // new frames. + nsIReflowCommand* reflowCmd; + nsresult result; + + result = NS_NewHTMLReflowCommand(&reflowCmd, parentFrame, + nsIReflowCommand::FrameAppended, + firstAppendedFrame); + if (NS_SUCCEEDED(result)) { + shell->AppendReflowCommand(reflowCmd); + } + break; + } + parentContainer->GetParent(parentContainer); + } + + NS_RELEASE(shell); + return NS_OK; +} void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const { diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 25819769c79c..cdd7b99ffb74 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -22,8 +22,13 @@ #include "nsISupportsArray.h" #include "nsIFrame.h" #include "nsHashtable.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIContent.h" +#include "nsIStyleFrameConstruction.h" static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); +static NS_DEFINE_IID(kIStyleFrameConstructionIID, NS_ISTYLE_FRAME_CONSTRUCTION_IID); class ContextKey : public nsHashKey { public: @@ -207,6 +212,31 @@ public: nsIFrame* aParentFrame, PRBool aForceUnique = PR_FALSE); + NS_IMETHODIMP ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree); + NS_IMETHOD ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer); + NS_IMETHOD ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer); + NS_IMETHOD ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer); + // xxx style rules enumeration virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); @@ -240,13 +270,15 @@ protected: nsISupportsArray* mDocSheets; nsISupportsArray* mBackstopSheets; nsHashtable mStyleContexts; + nsIStyleFrameConstruction* mFrameConstructor; }; StyleSetImpl::StyleSetImpl() : mOverrideSheets(nsnull), mDocSheets(nsnull), - mBackstopSheets(nsnull) + mBackstopSheets(nsnull), + mFrameConstructor(nsnull) { NS_INIT_REFCNT(); } @@ -262,6 +294,7 @@ StyleSetImpl::~StyleSetImpl() NS_IF_RELEASE(mOverrideSheets); NS_IF_RELEASE(mDocSheets); NS_IF_RELEASE(mBackstopSheets); + NS_IF_RELEASE(mFrameConstructor); mStyleContexts.Enumerate(ReleaseContext); } @@ -340,6 +373,9 @@ void StyleSetImpl::AppendDocStyleSheet(nsIStyleSheet* aSheet) NS_PRECONDITION(nsnull != aSheet, "null arg"); if (EnsureArray(&mDocSheets)) { mDocSheets->AppendElement(aSheet); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -350,6 +386,9 @@ void StyleSetImpl::InsertDocStyleSheetAfter(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aAfterSheet); mDocSheets->InsertElementAt(aSheet, ++index); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -360,6 +399,9 @@ void StyleSetImpl::InsertDocStyleSheetBefore(nsIStyleSheet* aSheet, if (EnsureArray(&mDocSheets)) { PRInt32 index = mDocSheets->IndexOf(aBeforeSheet); mDocSheets->InsertElementAt(aSheet, ((-1 < index) ? index : 0)); + if (nsnull == mFrameConstructor) { + aSheet->QueryInterface(kIStyleFrameConstructionIID, (void **)&mFrameConstructor); + } } } @@ -665,6 +707,67 @@ nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext, return result; } +NS_IMETHODIMP StyleSetImpl::ConstructFrame(nsIPresContext* aPresContext, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsIFrame*& aFrameSubTree) +{ + return mFrameConstructor->ConstructFrame(aPresContext, aContent, + aParentFrame, aFrameSubTree); +} + +NS_IMETHODIMP StyleSetImpl::ContentAppended(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) +{ + return mFrameConstructor->ContentAppended(aPresContext, aDocument, + aContainer, aNewIndexInContainer); +} + +NS_IMETHODIMP StyleSetImpl::ContentInserted(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentInserted(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentReplaced(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aOldChild, + nsIContent* aNewChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentReplaced(aPresContext, aDocument, aContainer, + aOldChild, aNewChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + +NS_IMETHODIMP StyleSetImpl::ContentRemoved(nsIPresContext* aPresContext, + nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) +{ +#if 0 + return mFrameConstructor->ContentRemoved(aPresContext, aDocument, aContainer, + aChild, aIndexInContainer); +#else + return NS_OK; +#endif +} + // xxx style rules enumeration void StyleSetImpl::List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets)