/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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/MPL/ * * 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.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * construction of a frame tree that is nearly isomorphic to the content * tree and updating of that tree in response to dynamic changes */ #ifndef nsCSSFrameConstructor_h___ #define nsCSSFrameConstructor_h___ #include "nsCOMPtr.h" #include "nsILayoutHistoryState.h" #include "nsIXBLService.h" #include "nsQuoteList.h" #include "nsCounterManager.h" #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsThreadUtils.h" #include "nsPageContentFrame.h" class nsIDocument; struct nsFrameItems; struct nsAbsoluteItems; class nsStyleContext; struct nsStyleContent; struct nsStyleDisplay; class nsIPresShell; class nsVoidArray; class nsFrameManager; class nsIDOMHTMLSelectElement; class nsPresContext; class nsStyleChangeList; class nsIFrame; struct nsFindFrameHint { nsIFrame *mPrimaryFrameForPrevSibling; // weak ref to the primary frame for the content for which we need a frame nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { } }; typedef void (PR_CALLBACK nsLazyFrameConstructionCallback) (nsIContent* aContent, nsIFrame* aFrame, void* aArg); class nsFrameConstructorState; class nsFrameConstructorSaveState; class nsCSSFrameConstructor { public: nsCSSFrameConstructor(nsIDocument *aDocument, nsIPresShell* aPresShell); ~nsCSSFrameConstructor(void) { } // Maintain global objects - gXBLService static nsIXBLService * GetXBLService(); static void ReleaseGlobals() { NS_IF_RELEASE(gXBLService); } // get the alternate text for a content node static void GetAlternateTextFor(nsIContent* aContent, nsIAtom* aTag, // content object's tag nsXPIDLString& aAltText); private: // These are not supported and are not implemented! nsCSSFrameConstructor(const nsCSSFrameConstructor& aCopy); nsCSSFrameConstructor& operator=(const nsCSSFrameConstructor& aCopy); public: // XXXbz this method needs to actually return errors! nsresult ConstructRootFrame(nsIContent* aDocElement, nsIFrame** aNewFrame); nsresult ReconstructDocElementHierarchy(); nsresult ContentAppended(nsIContent* aContainer, PRInt32 aNewIndexInContainer); nsresult ContentInserted(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer, nsILayoutHistoryState* aFrameState); nsresult ContentRemoved(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer, PRBool* aDidReconstruct); nsresult CharacterDataChanged(nsIContent* aContent, PRBool aAppend); nsresult ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2, PRInt32 aStateMask); // Process the children of aContent and indicate that frames should be // created for them. This is used for lazily built content such as that // inside popups so that it is only created when the popup is opened. // If aIsSynch is true, this method constructs the frames synchronously. // aCallback will be called with three arguments, the first is the value // of aContent, the second is aContent's primary frame, and the third is // the value of aArg. // aCallback will always be called even if the children of aContent had // been generated earlier. nsresult AddLazyChildren(nsIContent* aContent, nsLazyFrameConstructionCallback* aCallback, void* aArg, PRBool aIsSynch = PR_FALSE); // Should be called when a frame is going to be destroyed and // WillDestroyFrameTree hasn't been called yet. void NotifyDestroyingFrame(nsIFrame* aFrame); nsresult AttributeChanged(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, PRUint32 aStateMask); void BeginUpdate() { ++mUpdateCount; } void EndUpdate(); void RecalcQuotesAndCounters(); void WillDestroyFrameTree(); // Note: It's the caller's responsibility to make sure to wrap a // ProcessRestyledFrames call in a view update batch. // This function does not call ProcessAttachedQueue() on the binding manager. // If the caller wants that to happen synchronously, it needs to handle that // itself. nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray); private: // Note: It's the caller's responsibility to make sure to wrap a // ProcessOneRestyle call in a view update batch. // This function does not call ProcessAttachedQueue() on the binding manager. // If the caller wants that to happen synchronously, it needs to handle that // itself. void ProcessOneRestyle(nsIContent* aContent, nsReStyleHint aRestyleHint, nsChangeHint aChangeHint); public: // Restyling for a ContentInserted (notification after insertion) or // for a CharacterDataChanged. |aContainer| must be non-null; when // the container is null, no work is needed. void RestyleForInsertOrChange(nsIContent* aContainer, nsIContent* aChild); // This would be the same as RestyleForInsertOrChange if we got the // notification before the removal. However, we get it after, so we // have to use the index. |aContainer| must be non-null; when the // container is null, no work is needed. void RestyleForRemove(nsIContent* aContainer, nsIContent* aOldChild, PRInt32 aIndexInContainer); // Same for a ContentAppended. |aContainer| must be non-null; when // the container is null, no work is needed. void RestyleForAppend(nsIContent* aContainer, PRInt32 aNewIndexInContainer); // Note: It's the caller's responsibility to make sure to wrap a // ProcessPendingRestyles call in a view update batch. // This function does not call ProcessAttachedQueue() on the binding manager. // If the caller wants that to happen synchronously, it needs to handle that // itself. void ProcessPendingRestyles(); void RebuildAllStyleData(nsChangeHint aExtraHint); void PostRestyleEvent(nsIContent* aContent, nsReStyleHint aRestyleHint, nsChangeHint aMinChangeHint); /** * Asynchronously clear style data from the root frame downwards and ensure * it will all be rebuilt. This is safe to call anytime; it will schedule * a restyle and take effect next time style changes are flushed. * This method is used to recompute the style data when some change happens * outside of any style rules, like a color preference change or a change * in a system font size, or to fix things up when an optimization in the * style data has become invalid. We assume that the root frame will not * need to be reframed. */ void PostRebuildAllStyleDataEvent(); // Request to create a continuing frame nsresult CreateContinuingFrame(nsPresContext* aPresContext, nsIFrame* aFrame, nsIFrame* aParentFrame, nsIFrame** aContinuingFrame, PRBool aIsFluid = PR_TRUE); // Copy over fixed frames from aParentFrame's prev-in-flow nsresult ReplicateFixedFrames(nsPageContentFrame* aParentFrame); // Request to find the primary frame associated with a given content object. // This is typically called by the pres shell when there is no mapping in // the pres shell hash table nsresult FindPrimaryFrameFor(nsFrameManager* aFrameManager, nsIContent* aContent, nsIFrame** aFrame, nsFindFrameHint* aHint); // Get the XBL insertion point for a child nsresult GetInsertionPoint(nsIFrame* aParentFrame, nsIContent* aChildContent, nsIFrame** aInsertionPoint, PRBool* aMultiple = nsnull); nsresult CreateListBoxContent(nsPresContext* aPresContext, nsIFrame* aParentFrame, nsIFrame* aPrevFrame, nsIContent* aChild, nsIFrame** aResult, PRBool aIsAppend, PRBool aIsScrollbar, nsILayoutHistoryState* aFrameState); nsresult RemoveMappingsForFrameSubtree(nsIFrame* aRemovedFrame); nsIFrame* GetInitialContainingBlock() { return mInitialContainingBlock; } nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; } private: nsresult ReconstructDocElementHierarchyInternal(); nsresult ReinsertContent(nsIContent* aContainer, nsIContent* aChild); nsresult ConstructPageFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, nsIFrame* aParentFrame, nsIFrame* aPrevPageFrame, nsIFrame*& aPageFrame, nsIFrame*& aPageContentFrame); void DoContentStateChanged(nsIContent* aContent, PRInt32 aStateMask); /* aMinHint is the minimal change that should be made to the element */ void RestyleElement(nsIContent* aContent, nsIFrame* aPrimaryFrame, nsChangeHint aMinHint); void RestyleLaterSiblings(nsIContent* aContent); nsresult InitAndRestoreFrame (const nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIFrame* aPrevInFlow, nsIFrame* aNewFrame, PRBool aAllowCounters = PR_TRUE); already_AddRefed ResolveStyleContext(nsIFrame* aParentFrame, nsIContent* aContent); nsresult ConstructFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsFrameItems& aFrameItems); nsresult ConstructDocElementFrame(nsFrameConstructorState& aState, nsIContent* aDocElement, nsIFrame* aParentFrame, nsIFrame** aNewFrame); nsresult ConstructDocElementTableFrame(nsIContent* aDocElement, nsIFrame* aParentFrame, nsIFrame** aNewTableFrame, nsFrameConstructorState& aState); /** * CreateAttributeContent creates a single content/frame combination for an * |attr(foo)| generated content. * * @param aParentContent the parent content for the generated content * @param aParentFrame the parent frame for the generated frame * @param aAttrNamespace the namespace of the attribute in question * @param aAttrName the localname of the attribute * @param aStyleContext the style context to use * @param aGeneratedContent the array of generated content to append the * created content to. * @param [out] aNewContent the content node we create * @param [out] aNewFrame the new frame we create */ nsresult CreateAttributeContent(nsIContent* aParentContent, nsIFrame* aParentFrame, PRInt32 aAttrNamespace, nsIAtom* aAttrName, nsStyleContext* aStyleContext, nsCOMArray& aGeneratedContent, nsIContent** aNewContent, nsIFrame** aNewFrame); nsresult CreateGeneratedFrameFor(nsIFrame* aParentFrame, nsIContent* aContent, nsStyleContext* aStyleContext, const nsStyleContent* aStyleContent, PRUint32 aContentIndex, nsCOMArray& aGeneratedContent, nsIFrame** aFrame); PRBool CreateGeneratedContentFrame(nsFrameConstructorState& aState, nsIFrame* aFrame, nsIContent* aContent, nsStyleContext* aStyleContext, nsIAtom* aPseudoElement, nsIFrame** aResult); // This method can change aFrameList: it can chop off the end and // put it in a special sibling of aParentFrame. It can also change // aState by moving some floats out of it. nsresult AppendFrames(nsFrameConstructorState& aState, nsIContent* aContainer, nsIFrame* aParentFrame, nsFrameItems& aFrameList, nsIFrame* aAfterFrame); // BEGIN TABLE SECTION /** * ConstructTableFrame will construct the outer and inner table frames and * return them. Unless aIsPseudo is PR_TRUE, it will put the inner frame in * the child list of the outer frame, and will put any pseudo frames it had * to create into aChildItems. The newly-created outer frame will either be * in aChildItems or a descendant of a pseudo in aChildItems (unless it's * positioned or floated, in which case its placeholder will be in * aChildItems). */ nsresult ConstructTableFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aContentParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewOuterFrame, nsIFrame*& aNewInnerFrame); nsresult ConstructTableCaptionFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, nsFrameItems& aChildItems, nsIFrame*& aNewFrame, PRBool& aIsPseudoParent); nsresult ConstructTableRowGroupFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewFrame, PRBool& aIsPseudoParent); nsresult ConstructTableColGroupFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewFrame, PRBool& aIsPseudoParent); nsresult ConstructTableRowFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewFrame, PRBool& aIsPseudoParent); nsresult ConstructTableColFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParent, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewFrame, PRBool& aIsPseudoParent); nsresult ConstructTableCellFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, PRInt32 aNameSpaceID, PRBool aIsPseudo, nsFrameItems& aChildItems, nsIFrame*& aNewCellOuterFrame, nsIFrame*& aNewCellInnerFrame, PRBool& aIsPseudoParent); nsresult CreatePseudoTableFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame* aParentFrameIn = nsnull); nsresult CreatePseudoRowGroupFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame* aParentFrameIn = nsnull); nsresult CreatePseudoColGroupFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame* aParentFrameIn = nsnull); nsresult CreatePseudoRowFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame* aParentFrameIn = nsnull); nsresult CreatePseudoCellFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame* aParentFrameIn = nsnull); nsresult GetPseudoTableFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame& aParentFrameIn); nsresult GetPseudoColGroupFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame& aParentFrameIn); nsresult GetPseudoRowGroupFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame& aParentFrameIn); nsresult GetPseudoRowFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame& aParentFrameIn); nsresult GetPseudoCellFrame(PRInt32 aNameSpaceID, nsFrameConstructorState& aState, nsIFrame& aParentFrameIn); nsresult GetParentFrame(PRInt32 aNameSpaceID, nsIFrame& aParentFrameIn, nsIAtom* aChildFrameType, nsFrameConstructorState& aState, nsIFrame*& aParentFrame, PRBool& aIsPseudoParent); /** * Function to adjust aParentFrame and aFrameItems to deal with table * pseudo-frames that may have to be inserted. * @param aState the nsFrameConstructorState we're using. * @param aChildContent the content node we want to construct a frame for * @param aParentFrame the frame we think should be the parent. This will be * adjusted to point to a pseudo-frame if needed. * @param aTag tag that would be used for frame construction * @param aNameSpaceID namespace that will be used for frame construction * @param aChildStyle the style context for aChildContent * @param aFrameItems the framelist we think we need to put the child frame * into. If we have to construct pseudo-frames, we'll modify the * pointer to point to the list the child frame should go into. * @param aSaveState the nsFrameConstructorSaveState we can use for pushing a * float containing block if we have to do it. * @param aSuppressFrame whether we should not create a frame below this * parent * @param aCreatedPseudo whether we had to create a pseudo-parent * @return NS_OK on success, NS_ERROR_OUT_OF_MEMORY and such as needed. */ // XXXbz this function should really go away once we rework pseudo-frame // handling to be better. This should simply be part of the job of // GetGeometricParent, and stuff like the frameitems and parent frame should // be kept track of in the state... nsresult AdjustParentFrame(nsFrameConstructorState& aState, nsIContent* aChildContent, nsIFrame* & aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aChildStyle, nsFrameItems* & aFrameItems, nsFrameConstructorSaveState& aSaveState, PRBool& aSuppressFrame, PRBool& aCreatedPseudo); const nsStyleDisplay* GetDisplay(nsIFrame* aFrame); // END TABLE SECTION protected: static nsresult CreatePlaceholderFrameFor(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* aFrame, nsStyleContext* aStyleContext, nsIFrame* aParentFrame, nsIFrame* aPrevInFlow, nsIFrame** aPlaceholderFrame); private: // @param OUT aNewFrame the new radio control frame nsresult ConstructRadioControlFrame(nsIFrame** aNewFrame, nsIContent* aContent, nsStyleContext* aStyleContext); // @param OUT aNewFrame the new checkbox control frame nsresult ConstructCheckboxControlFrame(nsIFrame** aNewFrame, nsIContent* aContent, nsStyleContext* aStyleContext); // ConstructButtonFrame puts the new frame in aFrameItems and // handles the kids of the button. nsresult ConstructButtonFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, nsStyleContext* aStyleContext, nsIFrame** aNewFrame, const nsStyleDisplay* aStyleDisplay, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); // ConstructSelectFrame puts the new frame in aFrameItems and // handles the kids of the select. nsresult ConstructSelectFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, nsStyleContext* aStyleContext, nsIFrame*& aNewFrame, const nsStyleDisplay* aStyleDisplay, PRBool& aFrameHasBeenInitialized, nsFrameItems& aFrameItems); // ConstructFieldSetFrame puts the new frame in aFrameItems and // handles the kids of the fieldset nsresult ConstructFieldSetFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, nsStyleContext* aStyleContext, nsIFrame*& aNewFrame, nsFrameItems& aFrameItems, const nsStyleDisplay* aStyleDisplay, PRBool& aFrameHasBeenInitialized); nsresult ConstructTextFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aPseudoParent); nsresult ConstructPageBreakFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems); // Construct a page break frame if page-break-before:always is set in aStyleContext // and add it to aFrameItems. Return true if page-break-after:always is set on aStyleContext. // Don't do this for row groups, rows or cell, because tables handle those internally. PRBool PageBreakBefore(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems); nsresult ConstructHTMLFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); nsresult ConstructFrameInternal( nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aXBLBaseTag); nsresult CreateAnonymousFrames(nsIAtom* aTag, nsFrameConstructorState& aState, nsIContent* aParent, nsIFrame* aNewFrame, PRBool aAppendToExisting, nsFrameItems& aChildItems, PRBool aIsRoot = PR_FALSE); nsresult CreateAnonymousFrames(nsFrameConstructorState& aState, nsIContent* aParent, nsIDocument* aDocument, nsIFrame* aNewFrame, PRBool aAppendToExisting, nsFrameItems& aChildItems); //MathML Mod - RBS #ifdef MOZ_MATHML /** * Takes the frames in aBlockItems and wraps them in a new anonymous block * frame whose content is aContent and whose parent will be aParentFrame. * The anonymous block is added to aNewItems and aBlockItems is cleared. */ nsresult FlushAccumulatedBlock(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsFrameItems* aBlockItems, nsFrameItems* aNewItems); nsresult ConstructMathMLFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); #endif nsresult ConstructXULFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aXBLBaseTag, PRBool aHasPseudoParent, PRBool* aHaltProcessing); // XTF #ifdef MOZ_XTF nsresult ConstructXTFFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); #endif // SVG - rods #ifdef MOZ_SVG nsresult TestSVGConditions(nsIContent* aContent, PRBool& aHasRequiredExtensions, PRBool& aHasRequiredFeatures, PRBool& aHasSystemLanguage); nsresult SVGSwitchProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aFrame, nsFrameItems& aFrameItems); nsresult ConstructSVGFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, PRInt32 aNameSpaceID, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aHasPseudoParent, PRBool* aHaltProcessing); #endif nsresult ConstructFrameByDisplayType(nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay, nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aTag, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); nsresult ProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aFrame, PRBool aCanHaveGeneratedContent, nsFrameItems& aFrameItems, PRBool aParentIsBlock); // @param OUT aFrame the newly created frame nsresult CreateInputFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, nsIAtom* aTag, nsStyleContext* aStyleContext, nsIFrame** aFrame, const nsStyleDisplay* aStyleDisplay, PRBool& aFrameHasBeenInitialized, PRBool& aAddedToFrameList, nsFrameItems& aFrameItems, PRBool aHasPseudoParent); // A function that can be invoked to create some sort of image frame. typedef nsIFrame* (* ImageFrameCreatorFunc)(nsIPresShell*, nsStyleContext*); /** * CreateHTMLImageFrame will do some tests on aContent, and if it determines * that the content should get an image frame it'll create one via aFunc and * return it in *aFrame. Note that if this content node isn't supposed to * have an image frame this method will return NS_OK and set *aFrame to null. */ nsresult CreateHTMLImageFrame(nsIContent* aContent, nsStyleContext* aStyleContext, ImageFrameCreatorFunc aFunc, nsIFrame** aFrame); nsIFrame* GetFrameFor(nsIContent* aContent); /** * These two functions are used when we start frame creation from a non-root * element. They should recreate the same state that we would have * arrived at if we had built frames from the root frame to aFrame. * Therefore, any calls to PushFloatContainingBlock and * PushAbsoluteContainingBlock during frame construction should get * corresponding logic in these functions. */ public: nsIFrame* GetAbsoluteContainingBlock(nsIFrame* aFrame); private: nsIFrame* GetFloatContainingBlock(nsIFrame* aFrame); nsIContent* PropagateScrollToViewport(); // Build a scroll frame: // Calls BeginBuildingScrollFrame, InitAndRestoreFrame, and then FinishBuildingScrollFrame. // Sets the primary frame for the content to the output aNewFrame. // @param aNewFrame the created scrollframe --- output only nsresult BuildScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsStyleContext* aContentStyle, nsIFrame* aScrolledFrame, nsIFrame* aParentFrame, nsIFrame* aContentParentFrame, nsIFrame*& aNewFrame, nsStyleContext*& aScrolledChildStyle); // Builds the initial ScrollFrame already_AddRefed BeginBuildingScrollFrame(nsFrameConstructorState& aState, nsIContent* aContent, nsStyleContext* aContentStyle, nsIFrame* aParentFrame, nsIFrame* aContentParentFrame, nsIAtom* aScrolledPseudo, PRBool aIsRoot, nsIFrame*& aNewFrame); // Completes the building of the scrollframe: // Creates a view for the scrolledframe and makes it the child of the scrollframe. void FinishBuildingScrollFrame(nsIFrame* aScrollFrame, nsIFrame* aScrolledFrame); // InitializeSelectFrame puts scrollFrame in aFrameItems if aBuildCombobox is false nsresult InitializeSelectFrame(nsFrameConstructorState& aState, nsIFrame* scrollFrame, nsIFrame* scrolledFrame, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, PRBool aBuildCombobox, nsFrameItems& aFrameItems); nsresult MaybeRecreateFramesForContent(nsIContent* aContent); nsresult RecreateFramesForContent(nsIContent* aContent); // If removal of aFrame from the frame tree requires reconstruction of some // containing block (either of aFrame or of its parent) due to {ib} splits, // recreate the relevant containing block. The return value indicates // whether this happened. If this method returns true, *aResult is the // return value of ReframeContainingBlock. If this method returns false, the // value of *aResult is no affected. aFrame and aResult must not be null. // aFrame must be the result of a GetPrimaryFrameFor() call (which means its // parent is also not null). PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult); nsresult CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, nsIFrame* aFrame, nsIFrame* aParentFrame, nsIContent* aContent, nsStyleContext* aStyleContext, nsIFrame** aContinuingFrame); nsresult CreateContinuingTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, nsIFrame* aFrame, nsIFrame* aParentFrame, nsIContent* aContent, nsStyleContext* aStyleContext, nsIFrame** aContinuingFrame); //---------------------------------------- // Methods support creating block frames and their children already_AddRefed GetFirstLetterStyle(nsIContent* aContent, nsStyleContext* aStyleContext); already_AddRefed GetFirstLineStyle(nsIContent* aContent, nsStyleContext* aStyleContext); PRBool ShouldHaveFirstLetterStyle(nsIContent* aContent, nsStyleContext* aStyleContext); // Check whether a given block has first-letter style. Make sure to // only pass in blocks! And don't pass in null either. PRBool HasFirstLetterStyle(nsIFrame* aBlockFrame); PRBool ShouldHaveFirstLineStyle(nsIContent* aContent, nsStyleContext* aStyleContext); void ShouldHaveSpecialBlockStyle(nsIContent* aContent, nsStyleContext* aStyleContext, PRBool* aHaveFirstLetterStyle, PRBool* aHaveFirstLineStyle); // |aContentParentFrame| should be null if it's really the same as // |aParentFrame|. // @param aFrameItems where we want to put the block in case it's in-flow. // @param aNewFrame an in/out parameter. On input it is the block to be // constructed. On output it is reset to the outermost // frame constructed (e.g. if we need to wrap the block in an // nsColumnSetFrame. // @param aParentFrame is the desired parent for the (possibly wrapped) // block // @param aContentParent is the parent the block would have if it // were in-flow nsresult ConstructBlock(nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay, nsIContent* aContent, nsIFrame* aParentFrame, nsIFrame* aContentParentFrame, nsStyleContext* aStyleContext, nsIFrame** aNewFrame, nsFrameItems& aFrameItems, PRBool aAbsPosContainer); nsresult ConstructInline(nsFrameConstructorState& aState, const nsStyleDisplay* aDisplay, nsIContent* aContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, PRBool aIsPositioned, nsIFrame* aNewFrame); /** * Move an already-constructed framelist into the inline frame at * the tail end of an {ib} split. Creates said inline if it doesn't * already exist. * * @param aState the frame construction state we're using right now. * @param aExistingEndFrame if non-null, the already-existing end frame. * @param aIsPositioned Whether the end frame should be positioned. * @param aContent the content node for this {ib} split. * @param aStyleContext the style context to use for the new frame * @param aFramesToMove The frame list to move over * @param aBlockPart the block part of the {ib} split. * @param aTargetState if non-null, the target state to pass to * MoveChildrenTo for float reparenting. * XXXbz test float reparenting? * * @note aIsPositioned, aContent, aStyleContext, are * only used if aExistingEndFrame is null. */ nsIFrame* MoveFramesToEndOfIBSplit(nsFrameConstructorState& aState, nsIFrame* aExistingEndFrame, PRBool aIsPositioned, nsIContent* aContent, nsStyleContext* aStyleContext, nsIFrame* aFramesToMove, nsIFrame* aBlockPart, nsFrameConstructorState* aTargetState); nsresult ProcessInlineChildren(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aFrame, PRBool aCanHaveGeneratedContent, nsFrameItems& aFrameItems, PRBool* aKidsAllInline); // Determine whether we need to wipe out what we just did and start over // because we're doing something like adding block kids to an inline frame // (and therefore need an {ib} split). If aIsAppend is true, aPrevSibling is // ignored. Otherwise it may be used to determine whether to reframe when // inserting into the block of an {ib} split. // @return PR_TRUE if we reconstructed the containing block, PR_FALSE // otherwise PRBool WipeContainingBlock(nsFrameConstructorState& aState, nsIFrame* aContainingBlock, nsIFrame* aFrame, const nsFrameItems& aFrameList, PRBool aIsAppend, nsIFrame* aPrevSibling); nsresult ReframeContainingBlock(nsIFrame* aFrame); nsresult StyleChangeReflow(nsIFrame* aFrame); /** Helper function that searches the immediate child frames * (and their children if the frames are "special") * for a frame that maps the specified content object * * @param aParentFrame the primary frame for aParentContent * @param aContent the content node for which we seek a frame * @param aParentContent the parent for aContent * @param aHint an optional hint used to make the search for aFrame faster */ nsIFrame* FindFrameWithContent(nsFrameManager* aFrameManager, nsIFrame* aParentFrame, nsIContent* aParentContent, nsIContent* aContent, nsFindFrameHint* aHint); //---------------------------------------- // Methods support :first-letter style void CreateFloatingLetterFrame(nsFrameConstructorState& aState, nsIFrame* aBlockFrame, nsIContent* aTextContent, nsIFrame* aTextFrame, nsIContent* aBlockContent, nsIFrame* aParentFrame, nsStyleContext* aStyleContext, nsFrameItems& aResult); nsresult CreateLetterFrame(nsFrameConstructorState& aState, nsIFrame* aBlockFrame, nsIContent* aTextContent, nsIFrame* aParentFrame, nsFrameItems& aResult); nsresult WrapFramesInFirstLetterFrame(nsFrameConstructorState& aState, nsIContent* aBlockContent, nsIFrame* aBlockFrame, nsFrameItems& aBlockFrames); nsresult WrapFramesInFirstLetterFrame(nsFrameConstructorState& aState, nsIFrame* aBlockFrame, nsIFrame* aParentFrame, nsIFrame* aParentFrameList, nsIFrame** aModifiedParent, nsIFrame** aTextFrame, nsIFrame** aPrevFrame, nsFrameItems& aLetterFrame, PRBool* aStopLooking); nsresult RecoverLetterFrames(nsFrameConstructorState& aState, nsIFrame* aBlockFrame); // nsresult RemoveLetterFrames(nsPresContext* aPresContext, nsIPresShell* aPresShell, nsFrameManager* aFrameManager, nsIFrame* aBlockFrame); // Recursive helper for RemoveLetterFrames nsresult RemoveFirstLetterFrames(nsPresContext* aPresContext, nsIPresShell* aPresShell, nsFrameManager* aFrameManager, nsIFrame* aFrame, PRBool* aStopLooking); // Special remove method for those pesky floating first-letter frames nsresult RemoveFloatingFirstLetterFrames(nsPresContext* aPresContext, nsIPresShell* aPresShell, nsFrameManager* aFrameManager, nsIFrame* aBlockFrame, PRBool* aStopLooking); // Capture state for the frame tree rooted at the frame associated with the // content object, aContent nsresult CaptureStateForFramesOf(nsIContent* aContent, nsILayoutHistoryState* aHistoryState); // Capture state for the frame tree rooted at aFrame. nsresult CaptureStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aHistoryState); //---------------------------------------- // Methods support :first-line style nsresult WrapFramesInFirstLineFrame(nsFrameConstructorState& aState, nsIContent* aBlockContent, nsIFrame* aBlockFrame, nsFrameItems& aFrameItems); nsresult AppendFirstLineFrames(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aBlockFrame, nsFrameItems& aFrameItems); nsresult InsertFirstLineFrames(nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aBlockFrame, nsIFrame** aParentFrame, nsIFrame* aPrevSibling, nsFrameItems& aFrameItems); nsresult RemoveFixedItems(const nsFrameConstructorState& aState); // Find the right frame to use for aContent when looking for sibling // frames for aTargetContent. If aPrevSibling is true, this // will look for last continuations, etc, as necessary. This calls // IsValidSibling as needed; if that returns false it returns null. // // @param aTargetContentDisplay the CSS display enum for aTargetContent if // already known, UNSET_DISPLAY otherwise. nsIFrame* FindFrameForContentSibling(nsIContent* aContent, nsIContent* aTargetContent, PRUint8& aTargetContentDisplay, PRBool aPrevSibling); // Find the ``rightmost'' frame for the content immediately preceding // aIndexInContainer, following continuations if necessary. nsIFrame* FindPreviousSibling(nsIContent* aContainer, PRInt32 aIndexInContainer, nsIContent* aChild); // Find the frame for the content node immediately following aIndexInContainer. nsIFrame* FindNextSibling(nsIContent* aContainer, PRInt32 aIndexInContainer, nsIContent* aChild); // see if aContent and aSibling are legitimate siblings due to restrictions // imposed by table columns // XXXbz this code is generally wrong, since the frame for aContent // may be constructed based on tag, not based on aDisplay! PRBool IsValidSibling(nsIFrame* aSibling, nsIContent* aContent, PRUint8& aDisplay); /** * Find the ``rightmost'' frame for the anonymous content immediately * preceding aChild, following continuation if necessary. */ nsIFrame* FindPreviousAnonymousSibling(nsIContent* aContainer, nsIContent* aChild); /** * Find the frame for the anonymous content immediately following * aChild. */ nsIFrame* FindNextAnonymousSibling(nsIContent* aContainer, nsIContent* aChild); void QuotesDirty() { NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news"); mQuotesDirty = PR_TRUE; } void CountersDirty() { NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news"); mCountersDirty = PR_TRUE; } public: struct RestyleData; friend struct RestyleData; struct RestyleData { nsReStyleHint mRestyleHint; // What we want to restyle nsChangeHint mChangeHint; // The minimal change hint for "self" }; struct RestyleEnumerateData : public RestyleData { nsCOMPtr mContent; }; class RestyleEvent; friend class RestyleEvent; class RestyleEvent : public nsRunnable { public: NS_DECL_NSIRUNNABLE RestyleEvent(nsCSSFrameConstructor *aConstructor) : mConstructor(aConstructor) { NS_PRECONDITION(aConstructor, "Must have a constructor!"); } void Revoke() { mConstructor = nsnull; } private: nsCSSFrameConstructor *mConstructor; }; friend class nsFrameConstructorState; private: class LazyGenerateChildrenEvent; friend class LazyGenerateChildrenEvent; // See comments of nsCSSFrameConstructor::AddLazyChildren() class LazyGenerateChildrenEvent : public nsRunnable { public: NS_DECL_NSIRUNNABLE LazyGenerateChildrenEvent(nsIContent *aContent, nsIPresShell *aPresShell, nsLazyFrameConstructionCallback* aCallback, void* aArg) : mContent(aContent), mPresShell(aPresShell), mCallback(aCallback), mArg(aArg) {} private: nsCOMPtr mContent; nsCOMPtr mPresShell; nsLazyFrameConstructionCallback* mCallback; void* mArg; }; nsIDocument* mDocument; // Weak ref nsIPresShell* mPresShell; // Weak ref nsIFrame* mInitialContainingBlock; nsIFrame* mFixedContainingBlock; nsIFrame* mDocElementContainingBlock; nsIFrame* mGfxScrollFrame; nsIFrame* mPageSequenceFrame; nsQuoteList mQuoteList; nsCounterManager mCounterManager; PRUint16 mUpdateCount; PRPackedBool mQuotesDirty : 1; PRPackedBool mCountersDirty : 1; PRPackedBool mInitialContainingBlockIsAbsPosContainer : 1; PRPackedBool mIsDestroyingFrameTree : 1; PRPackedBool mRebuildAllStyleData : 1; nsRevocableEventPtr mRestyleEvent; nsCOMPtr mTempFrameTreeState; nsDataHashtable mPendingRestyles; static nsIXBLService * gXBLService; }; #endif /* nsCSSFrameConstructor_h___ */