diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 56a6c1ae65f..2ca16f95a38 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -51,13 +51,17 @@ #include "nsPresContext.h" #include "nsILinkHandler.h" #include "nsIDocument.h" +#ifdef CSS_TABLES #include "nsTableFrame.h" #include "nsTableColGroupFrame.h" #include "nsTableColFrame.h" +#include "nsTableCellFrame.h" // to get IS_CELL_FRAME +#include "nsTableOuterFrame.h" +#include "nsTableRowGroupFrame.h" +#endif #include "nsIDOMHTMLDocument.h" #include "nsIDOMHTMLTableColElement.h" #include "nsIDOMHTMLTableCaptionElem.h" -#include "nsTableCellFrame.h" // to get IS_CELL_FRAME #include "nsHTMLParts.h" #include "nsIPresShell.h" #include "nsStyleSet.h" @@ -65,23 +69,23 @@ #include "nsIEventStateManager.h" #include "nsIScrollableView.h" #include "nsStyleConsts.h" -#include "nsTableOuterFrame.h" #include "nsIDOMXULElement.h" #include "nsHTMLContainerFrame.h" #include "nsINameSpaceManager.h" #include "nsLayoutAtoms.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMHTMLLegendElement.h" +#ifdef HTML_FORMS #include "nsIComboboxControlFrame.h" #include "nsIListControlFrame.h" #include "nsISelectControlFrame.h" #include "nsIRadioControlFrame.h" #include "nsICheckboxControlFrame.h" +#endif #include "nsIDOMCharacterData.h" #include "nsIDOMHTMLImageElement.h" #include "nsITextContent.h" #include "nsPlaceholderFrame.h" -#include "nsTableRowGroupFrame.h" #include "nsStyleChangeList.h" #include "nsIFormControl.h" #include "nsCSSAnonBoxes.h" @@ -1580,6 +1584,7 @@ nsCSSFrameConstructor::CreateInsertionPointChildren(nsFrameConstructorState &aSt return NS_OK; } +#ifdef CSS_TABLES static PRBool IsBorderCollapse(nsIFrame* aFrame) { @@ -1591,6 +1596,7 @@ PRBool IsBorderCollapse(nsIFrame* aFrame) NS_ASSERTION(PR_FALSE, "program error"); return PR_FALSE; } +#endif /** * Utility method, called from MoveChildrenTo(), that recursively @@ -1711,6 +1717,7 @@ MoveChildrenTo(nsFrameManager* aFrameManager, // ----------------------------------------------------------- +#ifdef CSS_TABLES // Structure used when creating table frames. struct nsTableCreator { virtual nsresult CreateTableOuterFrame(nsIFrame** aNewFrame); @@ -1778,6 +1785,7 @@ nsresult nsTableCreator::CreateTableCellInnerFrame(nsIFrame** aNewFrame) { return NS_NewTableCellInnerFrame(mPresShell, aNewFrame); } +#endif //MathML Mod - RBS #ifdef MOZ_MATHML @@ -2386,6 +2394,7 @@ nsCSSFrameConstructor::CreateGeneratedContentFrame(nsFrameConstructorState& aSta return PR_FALSE; } +#ifdef HTML_FORMS nsresult nsCSSFrameConstructor::CreateInputFrame(nsIContent *aContent, nsIFrame **aFrame, @@ -2444,6 +2453,7 @@ nsCSSFrameConstructor::CreateInputFrame(nsIContent *aContent, return NS_ERROR_INVALID_ARG; } } +#endif nsresult nsCSSFrameConstructor::CreateHTMLImageFrame(nsIContent* aContent, @@ -2473,6 +2483,7 @@ IsOnlyWhitespace(nsIContent* aContent) return onlyWhiteSpace; } +#ifdef CSS_TABLES /**************************************************** ** BEGIN TABLE SECTION ****************************************************/ @@ -3997,6 +4008,7 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsFrameConstructorState& aStat return rv; } +#endif static PRBool NeedFrameFor(nsIFrame* aParentFrame, @@ -4010,7 +4022,7 @@ NeedFrameFor(nsIFrame* aParentFrame, return PR_TRUE; } - +#ifdef CSS_TABLES nsresult nsCSSFrameConstructor::TableProcessChildren(nsFrameConstructorState& aState, nsIContent* aContent, @@ -4240,6 +4252,15 @@ nsCSSFrameConstructor::ConstructDocElementTableFrame(nsIContent* aDocElement return NS_OK; } +#else +inline nsresult +ProcessPseudoFrames(nsFrameConstructorState& aState, + nsFrameItems& aItems) +{ + return NS_OK; +} +#endif + static PRBool CheckOverflow(nsPresContext* aPresContext, const nsStyleDisplay* aDisplay) { @@ -4457,6 +4478,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState, PRBool docElemIsTable = display->mDisplay == NS_STYLE_DISPLAY_TABLE; +#ifdef CSS_TABLES if (docElemIsTable) { // if the document is a table then just populate it. rv = ConstructDocElementTableFrame(aDocElement, aParentFrame, &contentFrame, @@ -4466,6 +4488,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState, } styleContext = contentFrame->GetStyleContext(); } else { +#endif // otherwise build a box or a block #ifdef MOZ_XUL if (aDocElement->IsContentOfType(nsIContent::eXUL)) { @@ -4497,7 +4520,9 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState, // initialize the child InitAndRestoreFrame(aState, aDocElement, aParentFrame, styleContext, nsnull, contentFrame); +#ifdef CSS_TABLES } +#endif // set the primary frame aState.mFrameManager->SetPrimaryFrameFor(aDocElement, contentFrame); @@ -4891,6 +4916,7 @@ nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell, return rv; } +#ifdef HTML_FORMS nsresult nsCSSFrameConstructor::ConstructRadioControlFrame(nsIFrame** aNewFrame, nsIContent* aContent, @@ -5306,6 +5332,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState, return NS_OK; } +#endif nsresult nsCSSFrameConstructor::ConstructTextFrame(nsFrameConstructorState& aState, @@ -5418,6 +5445,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, } rv = NS_NewWBRFrame(mPresShell, &newFrame); } +#ifdef HTML_FORMS else if (nsHTMLAtoms::input == aTag) { // Make sure to keep IsSpecialHTMLContent in synch with this code rv = CreateInputFrame(aContent, &newFrame, aStyleContext); @@ -5451,6 +5479,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, addedToFrameList = PR_TRUE; } } +#endif else if (nsHTMLAtoms::object == aTag || nsHTMLAtoms::applet == aTag || nsHTMLAtoms::embed == aTag) { @@ -5490,6 +5519,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, #endif } } +#ifdef HTML_FORMS else if (nsHTMLAtoms::fieldset == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { ProcessPseudoFrames(aState, aFrameItems); @@ -5512,6 +5542,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, rv = NS_NewLegendFrame(mPresShell, &newFrame); isFloatContainer = PR_TRUE; } +#endif else if (nsHTMLAtoms::frameset == aTag) { NS_ASSERTION(!display->IsAbsolutelyPositioned() && !display->IsFloating(), "Framesets should not be positioned and should not float"); @@ -5547,6 +5578,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, } rv = NS_NewSpacerFrame(mPresShell, &newFrame); } +#ifdef HTML_FORMS else if (nsHTMLAtoms::button == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { ProcessPseudoFrames(aState, aFrameItems); @@ -5566,6 +5598,7 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, isReplaced = PR_TRUE; rv = NS_NewIsIndexFrame(mPresShell, &newFrame); } +#endif else if (nsHTMLAtoms::canvas == aTag) { if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { ProcessPseudoFrames(aState, aFrameItems); @@ -6539,7 +6572,9 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsFrameConstructorState& aSta { PRBool primaryFrameSet = PR_FALSE; nsIFrame* newFrame = nsnull; // the frame we construct +#ifdef CSS_TABLES nsTableCreator tableCreator(mPresShell); // Used to make table frames. +#endif PRBool addToHashTable = PR_TRUE; PRBool addedToFrameList = PR_FALSE; nsresult rv = NS_OK; @@ -6716,6 +6751,7 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsFrameConstructorState& aSta // Use the 'display' property to choose a frame type switch (aDisplay->mDisplay) { +#ifdef CSS_TABLES case NS_STYLE_DISPLAY_TABLE: { // XXXbz this isn't quite right, but checking for aHasPseudoParent here @@ -6808,9 +6844,29 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsFrameConstructorState& aSta } return rv; } +#endif default: +#ifdef CSS_TABLES NS_NOTREACHED("How did we get here?"); +#else + if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { + ProcessPseudoFrames(aState, aFrameItems); + } + // Create the inline frame + rv = NS_NewInlineFrame(mPresShell, &newFrame); + if (NS_SUCCEEDED(rv)) { // That worked so construct the inline and its children + // Note that we want to insert the inline after processing kids, since + // processing of kids may split the inline. + rv = ConstructInline(aState, aDisplay, aContent, + aParentFrame, aStyleContext, PR_FALSE, newFrame); + } + + // To keep the hash table small don't add inline frames (they're + // typically things like FONT and B), because we can quickly + // find them if we need to + addToHashTable = PR_FALSE; +#endif break; } } @@ -7579,16 +7635,20 @@ nsCSSFrameConstructor::PageBreakBefore(nsFrameConstructorState& aState, // See if page-break-before is set for all elements except row groups, rows, cells // (these are handled internally by tables) and construct a page break frame if so. +#ifdef CSS_TABLES if (NS_STYLE_DISPLAY_NONE != display->mDisplay && (NS_STYLE_DISPLAY_TABLE == display->mDisplay || !IsTableRelated(display->mDisplay, PR_TRUE))) { +#endif if (display->mBreakBefore) { ConstructPageBreakFrame(aState, aContent, aParentFrame, aStyleContext, aFrameItems); } return display->mBreakAfter; +#ifdef CSS_TABLES } return PR_FALSE; +#endif } nsresult @@ -7727,13 +7787,16 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsFrameConstructorState& aState, nsIFrame* adjParentFrame = aParentFrame; nsFrameItems* frameItems = &aFrameItems; PRBool pseudoParent = PR_FALSE; + nsresult rv; +#ifdef CSS_TABLES nsFrameConstructorSaveState pseudoSaveState; - nsresult rv = AdjustParentFrame(aContent, styleContext, adjParentFrame, - frameItems, aState, pseudoSaveState, - pseudoParent); + rv = AdjustParentFrame(aContent, styleContext, adjParentFrame, + frameItems, aState, pseudoSaveState, + pseudoParent); if (NS_FAILED(rv)) { return rv; } +#endif if (aContent->IsContentOfType(nsIContent::eTEXT)) return ConstructTextFrame(aState, aContent, adjParentFrame, styleContext, @@ -8802,6 +8865,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, } } +#ifdef HTML_FORMS // Here we have been notified that content has been appended so if // the select now has a single item we need to go in and removed // the dummy frame. @@ -8812,6 +8876,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, RemoveDummyFrameFromSelect(aContainer, childContent, sel); } } +#endif #ifdef DEBUG if (gReallyNoisyContentUpdates) { @@ -8828,6 +8893,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, } +#ifdef HTML_FORMS nsresult nsCSSFrameConstructor::AddDummyFrameToSelect(nsFrameConstructorState& aState, nsIFrame* aListFrame, @@ -8869,6 +8935,7 @@ nsCSSFrameConstructor::AddDummyFrameToSelect(nsFrameConstructorState& aState, return NS_ERROR_FAILURE; } +#endif // defined below static nsresult @@ -8877,6 +8944,7 @@ DeletingFrameSubtree(nsPresContext* aPresContext, nsFrameManager* aFrameManager, nsIFrame* aFrame); +#ifdef HTML_FORMS nsresult nsCSSFrameConstructor::RemoveDummyFrameFromSelect(nsIContent* aContainer, nsIContent* aChild, @@ -8914,6 +8982,7 @@ nsCSSFrameConstructor::RemoveDummyFrameFromSelect(nsIContent* aContainer, return NS_ERROR_FAILURE; } +#endif // Return TRUE if the insertion of aChild into aParent1,2 should force a reframe. aParent1 is // the special inline container which contains a block. aParentFrame is approximately aParent1's @@ -9476,12 +9545,15 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, } } } + +#ifdef HTML_FORMS // Here we have been notified that content has been insert // so if the select now has a single item // we need to go in and removed the dummy frame nsCOMPtr selectElement = do_QueryInterface(aContainer); if (selectElement) RemoveDummyFrameFromSelect(aContainer, aChild, selectElement); +#endif #ifdef DEBUG if (gReallyNoisyContentUpdates && parentFrame) { @@ -9739,6 +9811,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, frameManager->ClearUndisplayedContentIn(aChild, aContainer); } +#ifdef HTML_FORMS // When the last item is removed from a select, // we need to add a pseudo frame so select gets sized as the best it can // so here we see if it is a select and then we get the number of options @@ -9758,6 +9831,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, } } } +#endif #ifdef MOZ_XUL if (NotifyListBoxBody(presContext, aContainer, aChild, aIndexInContainer, @@ -10162,22 +10236,15 @@ nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame, } #endif - // Is it a box? If so we can coelesce. - if (aFrame->IsBoxFrame()) { - nsBoxLayoutState state(mPresShell->GetPresContext()); - aFrame->MarkStyleChange(state); - } - else { - // If the frame is part of a split block-in-inline hierarchy, then - // target the style-change reflow at the first ``normal'' ancestor - // so we're sure that the style change will propagate to any - // anonymously created siblings. - if (IsFrameSpecial(aFrame)) - aFrame = GetIBContainingBlockFor(aFrame); + // If the frame is part of a split block-in-inline hierarchy, then + // target the style-change reflow at the first ``normal'' ancestor + // so we're sure that the style change will propagate to any + // anonymously created siblings. + if (IsFrameSpecial(aFrame)) + aFrame = GetIBContainingBlockFor(aFrame); - // Target a style-change reflow at the frame. - mPresShell->AppendReflowCommand(aFrame, eReflowType_StyleChanged, nsnull); - } + aFrame->AddStateBits(NS_FRAME_IS_DIRTY); + mPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange); return NS_OK; } @@ -10669,6 +10736,7 @@ void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent, // when the image can not be displayed rv = aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::alt, aAltText); +#ifdef HTML_FORMS // If there's no "alt" attribute, and aContent is an input // element, then use the value of the "value" attribute if ((NS_CONTENT_ATTR_NOT_THERE == rv) && (nsHTMLAtoms::input == aTag)) { @@ -10682,8 +10750,10 @@ void nsCSSFrameConstructor::GetAlternateTextFor(nsIContent* aContent, "Submit", aAltText); } } +#endif } +#ifdef CSS_TABLES nsresult nsCSSFrameConstructor::CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, @@ -10824,6 +10894,7 @@ nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell, *aContinuingFrame = newFrame; return rv; } +#endif nsresult nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, @@ -10895,6 +10966,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, nsIFrame* pageContentFrame; rv = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame, newFrame, pageContentFrame); +#ifdef CSS_TABLES } else if (nsLayoutAtoms::tableOuterFrame == frameType) { rv = CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame, content, styleContext, &newFrame); @@ -10951,7 +11023,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, // Set the table cell's initial child list newFrame->SetInitialChildList(aPresContext, nsnull, continuingAreaFrame); } - +#endif } else if (nsLayoutAtoms::lineFrame == frameType) { rv = NS_NewFirstLineFrame(shell, &newFrame); if (NS_SUCCEEDED(rv)) { @@ -10987,6 +11059,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, if (!newFrame) return NS_ERROR_NULL_POINTER; newFrame->Init(aPresContext, content, aParentFrame, styleContext, aFrame); +#ifdef HTML_FORMS } else if (nsLayoutAtoms::fieldSetFrame == frameType) { rv = NS_NewFieldSetFrame(aPresContext->PresShell(), &newFrame, NS_BLOCK_SPACE_MGR); @@ -11006,6 +11079,7 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext, // Set the fieldset's initial child list newFrame->SetInitialChildList(aPresContext, nsnull, continuingAreaFrame); } +#endif } else { NS_ASSERTION(PR_FALSE, "unexpected frame type"); rv = NS_ERROR_UNEXPECTED; @@ -11611,6 +11685,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, } } +#ifdef CSS_TABLES if (aTableCreator) { // do special table child processing // if there is a caption child here, it gets recorded in aState.mPseudoFrames. nsIFrame* captionFrame; @@ -11618,6 +11693,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, aFrameItems, captionFrame); } else { +#endif // save the incoming pseudo frame state nsPseudoFrames priorPseudoFrames; aState.mPseudoFrames.Reset(&priorPseudoFrames); @@ -11640,7 +11716,9 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, // restore the incoming pseudo frame state aState.mPseudoFrames = priorPseudoFrames; +#ifdef CSS_TABLES } +#endif if (aCanHaveGeneratedContent) { // Probe for generated content after diff --git a/mozilla/layout/base/nsCSSFrameConstructor.h b/mozilla/layout/base/nsCSSFrameConstructor.h index 38cf4fd56a4..2a086116ce5 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.h +++ b/mozilla/layout/base/nsCSSFrameConstructor.h @@ -53,7 +53,6 @@ struct nsFrameItems; struct nsAbsoluteItems; struct nsTableCreator; class nsStyleContext; -struct nsTableList; struct nsStyleContent; struct nsStyleDisplay; class nsIPresShell; @@ -229,10 +228,12 @@ private: nsIFrame* aParentFrame, nsIFrame** aNewFrame); +#ifdef CSS_TABLES nsresult ConstructDocElementTableFrame(nsIContent* aDocElement, nsIFrame* aParentFrame, nsIFrame** aNewTableFrame, nsFrameConstructorState& aState); +#endif /** * CreateAttributeContent creates a single content/frame combination for an @@ -273,6 +274,7 @@ private: nsIFrame* aParentFrame, nsIFrame* aFrameList); +#ifdef CSS_TABLES // BEGIN TABLE SECTION /** * ConstructTableFrame will construct the outer and inner table frames and @@ -461,6 +463,7 @@ private: const nsStyleDisplay* GetDisplay(nsIFrame* aFrame); // END TABLE SECTION +#endif protected: static nsresult CreatePlaceholderFrameFor(nsIPresShell* aPresShell, @@ -473,6 +476,8 @@ protected: nsIFrame** aPlaceholderFrame); private: + +#ifdef HTML_FORMS // @param OUT aNewFrame the new radio control frame nsresult ConstructRadioControlFrame(nsIFrame** aNewFrame, nsIContent* aContent, @@ -506,6 +511,7 @@ private: nsFrameItems& aFrameItems, const nsStyleDisplay* aStyleDisplay, PRBool& aFrameHasBeenInitialized); +#endif nsresult ConstructTextFrame(nsFrameConstructorState& aState, nsIContent* aContent, @@ -648,20 +654,7 @@ private: nsIFrame** aFrame, nsStyleContext* aStyleContext); - // A function that can be invoked to create some sort of image frame. - typedef nsresult (* ImageFrameCreatorFunc)(nsIPresShell*, nsIFrame**); - - /** - * 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); - +#ifdef HTML_FORMS nsresult AddDummyFrameToSelect(nsFrameConstructorState& aState, nsIFrame* aListFrame, nsIFrame* aParentFrame, @@ -672,6 +665,7 @@ private: nsresult RemoveDummyFrameFromSelect(nsIContent* aContainer, nsIContent* aChild, nsIDOMHTMLSelectElement* aSelectElement); +#endif nsIFrame* GetFrameFor(nsIContent* aContent); @@ -712,6 +706,7 @@ private: FinishBuildingScrollFrame(nsIFrame* aScrollFrame, nsIFrame* aScrolledFrame); +#ifdef HTML_FORMS // InitializeSelectFrame puts scrollFrame in aFrameItems if aBuildCombobox is false nsresult InitializeSelectFrame(nsFrameConstructorState& aState, @@ -722,6 +717,7 @@ private: nsStyleContext* aStyleContext, PRBool aBuildCombobox, nsFrameItems& aFrameItems); +#endif nsresult MaybeRecreateFramesForContent(nsIContent* aContent); @@ -729,6 +725,7 @@ private: PRBool MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame, nsresult* aResult); +#ifdef CSS_TABLES nsresult CreateContinuingOuterTableFrame(nsIPresShell* aPresShell, nsPresContext* aPresContext, nsIFrame* aFrame, @@ -744,6 +741,7 @@ private: nsIContent* aContent, nsStyleContext* aStyleContext, nsIFrame** aContinuingFrame); +#endif //---------------------------------------- diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index bd8f5a0326b..762beed4520 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -2966,9 +2966,20 @@ NS_IMETHODIMP DocumentViewerImpl::SizeToContent() // Flush out all content and style updates. We can't use a resize reflow // because it won't change some sizes that a style change reflow will. mDocument->FlushPendingNotifications(Flush_Layout); - - NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, - NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); + + nsIFrame *root = presShell->GetRootFrame(); + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); + + nscoord prefWidth; + { + nsCOMPtr rcx; + presShell->CreateRenderingContext(root, getter_AddRefs(rcx)); + NS_ENSURE_TRUE(rcx, NS_ERROR_FAILURE); + prefWidth = root->GetPrefWidth(rcx); + } + + nsresult rv = presShell->ResizeReflow(prefWidth, NS_UNCONSTRAINEDSIZE); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr presContext; GetPresContext(getter_AddRefs(presContext)); diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index 562e28a63ee..7ad46a289ae 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -54,7 +54,6 @@ #include "nsISupports.h" #include "nsCoord.h" #include "nsEvent.h" -#include "nsReflowType.h" #include "nsCompatibility.h" #include "nsCOMArray.h" #include "nsFrameManagerBase.h" @@ -321,14 +320,20 @@ public: nsIFrame** aPlaceholderFrame) const = 0; /** - * Reflow commands + * Tell the pres shell that a frame is dirty (as indicated by bits) + * and needs Reflow. It's OK if this is an ancestor of the frame needing + * reflow as long as the ancestor chain between them doesn't cross a reflow + * root. */ - NS_IMETHOD AppendReflowCommand(nsIFrame* aTargetFrame, - nsReflowType aReflowType, - nsIAtom* aChildListName) = 0; - // XXXbz don't we need a child list name on this too? - NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, nsReflowType* aCmdType) = 0; - NS_IMETHOD CancelAllReflowCommands() = 0; + enum IntrinsicDirty { + eResize, // don't mark any intrinsic widths dirty + eTreeChange, // mark intrinsic widths dirty on aFrame and its ancestors + eStyleChange // Do eTreeChange, plus all of aFrame's descendants + }; + NS_IMETHOD FrameNeedsReflow(nsIFrame *aFrame, + IntrinsicDirty aIntrinsicDirty) = 0; + + NS_IMETHOD CancelAllPendingReflows() = 0; /** * Recreates the frames for a node @@ -635,7 +640,7 @@ public: #ifdef MOZ_REFLOW_PERF NS_IMETHOD DumpReflows() = 0; - NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) = 0; + NS_IMETHOD CountReflows(const char * aName, nsIFrame * aFrame) = 0; NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRenderingContext, nsPresContext * aPresContext, diff --git a/mozilla/layout/base/nsLayoutUtils.cpp b/mozilla/layout/base/nsLayoutUtils.cpp index cdc4d810afb..3d2adf6a325 100644 --- a/mozilla/layout/base/nsLayoutUtils.cpp +++ b/mozilla/layout/base/nsLayoutUtils.cpp @@ -538,3 +538,97 @@ nsLayoutUtils::IsInitialContainingBlock(nsIFrame* aFrame) return aFrame == aFrame->GetPresContext()->PresShell()->FrameConstructor()->GetInitialContainingBlock(); } + +static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord) +{ + return aCoord.GetUnit() == eStyleUnit_Coord + ? aCoord.GetCoordValue() + : aIfNotCoord; +} + +#undef DEBUG_INTRINSIC_WIDTH + +#ifdef DEBUG_INTRINSIC_WIDTH +static PRInt32 gNoiseIndent = 0; +#endif + +/* static */ nscoord +nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext, + nsIFrame *aFrame, + IntrinsicWidthType aType) +{ + NS_PRECONDITION(aFrame, "null frame"); + NS_PRECONDITION(aType == MIN_WIDTH || aType == PREF_WIDTH, "bad type"); + +#ifdef DEBUG_INTRINSIC_WIDTH + nsFrame::IndentBy(stdout, gNoiseIndent); + NS_STATIC_CAST(nsFrame*, aFrame)->ListTag(stdout); + printf(" %s intrinsic width for container:\n", + aType == MIN_WIDTH ? "min" : "pref"); +#endif + + const nsStylePosition *stylePos = aFrame->GetStylePosition(); + nscoord min = GetCoord(stylePos->mMinWidth, 0), + max = GetCoord(stylePos->mMaxWidth, nscoord_MAX); + + nscoord result; + if (min < max) { + const nsStyleCoord &styleWidth = stylePos->mWidth; + if (styleWidth.GetUnit() == eStyleUnit_Coord) { + result = styleWidth.GetCoordValue(); + // XXX If it's a percent, should we use 0 for min-width? + } else { +#ifdef DEBUG_INTRINSIC_WIDTH + ++gNoiseIndent; +#endif + if (aType == MIN_WIDTH) + result = aFrame->GetMinWidth(aRenderingContext); + else + result = aFrame->GetPrefWidth(aRenderingContext); +#ifdef DEBUG_INTRINSIC_WIDTH + --gNoiseIndent; + nsFrame::IndentBy(stdout, gNoiseIndent); + NS_STATIC_CAST(nsFrame*, aFrame)->ListTag(stdout); + printf(" %s intrinsic width from frame is %d.\n", + aType == MIN_WIDTH ? "min" : "pref", result); +#endif + } + + if (result > max) + result = max; + if (result < min) + result = min; + } else { + // width is determined by 'max-width' and 'min-width' + result = min; + } +#ifdef DEBUG_INTRINSIC_WIDTH + nsFrame::IndentBy(stdout, gNoiseIndent); + NS_STATIC_CAST(nsFrame*, aFrame)->ListTag(stdout); + printf(" %s intrinsic width for content box is %d.\n", + aType == MIN_WIDTH ? "min" : "pref", result); +#endif + + nsStyleCoord tmp; + + const nsStylePadding *stylePadding = aFrame->GetStylePadding(); + result += GetCoord(stylePadding->mPadding.GetLeft(tmp), 0); + result += GetCoord(stylePadding->mPadding.GetRight(tmp), 0); + + const nsStyleBorder *styleBorder = aFrame->GetStyleBorder(); + result += styleBorder->GetBorderWidth(NS_SIDE_LEFT); + result += styleBorder->GetBorderWidth(NS_SIDE_RIGHT); + + const nsStyleMargin *styleMargin = aFrame->GetStyleMargin(); + result += GetCoord(styleMargin->mMargin.GetLeft(tmp), 0); + result += GetCoord(styleMargin->mMargin.GetRight(tmp), 0); + +#ifdef DEBUG_INTRINSIC_WIDTH + nsFrame::IndentBy(stdout, gNoiseIndent); + NS_STATIC_CAST(nsFrame*, aFrame)->ListTag(stdout); + printf(" %s intrinsic width for container is %d twips.\n", + aType == MIN_WIDTH ? "min" : "pref", result); +#endif + + return result; +} diff --git a/mozilla/layout/base/nsLayoutUtils.h b/mozilla/layout/base/nsLayoutUtils.h index 8f996806255..8cdd92dc0d7 100644 --- a/mozilla/layout/base/nsLayoutUtils.h +++ b/mozilla/layout/base/nsLayoutUtils.h @@ -299,6 +299,16 @@ public: nsIWidget* aWidget, nsIntPoint aPt, nsIView* aView); + /** + * Get the contribution of aFrame to its containing block's intrinsic + * width. This considers the child's intrinsic width, its 'width', + * 'min-width', and 'max-width' properties, and its padding, border, + * and margin. + */ + enum IntrinsicWidthType { MIN_WIDTH, PREF_WIDTH }; + static nscoord IntrinsicForContainer(nsIRenderingContext *aRenderingContext, + nsIFrame *aFrame, + IntrinsicWidthType aType); }; #endif // nsLayoutUtils_h__ diff --git a/mozilla/layout/base/nsPresContext.cpp b/mozilla/layout/base/nsPresContext.cpp index 75f0524f858..cd57e560740 100644 --- a/mozilla/layout/base/nsPresContext.cpp +++ b/mozilla/layout/base/nsPresContext.cpp @@ -1316,11 +1316,10 @@ NS_NewPresContext(nsPresContext::nsPresContextType aType, #ifdef MOZ_REFLOW_PERF void -nsPresContext::CountReflows(const char * aName, - PRUint32 aType, nsIFrame * aFrame) +nsPresContext::CountReflows(const char * aName, nsIFrame * aFrame) { if (mShell) { - mShell->CountReflows(aName, aType, aFrame); + mShell->CountReflows(aName, aFrame); } } diff --git a/mozilla/layout/base/nsPresContext.h b/mozilla/layout/base/nsPresContext.h index 5da2a3db147..97a969a0dbf 100644 --- a/mozilla/layout/base/nsPresContext.h +++ b/mozilla/layout/base/nsPresContext.h @@ -614,7 +614,7 @@ public: #ifdef MOZ_REFLOW_PERF NS_HIDDEN_(void) CountReflows(const char * aName, - PRUint32 aType, nsIFrame * aFrame); + nsIFrame * aFrame); NS_HIDDEN_(void) PaintCount(const char * aName, nsIRenderingContext* aRendingContext, nsIFrame * aFrame, PRUint32 aColor); @@ -760,10 +760,10 @@ protected: #ifdef MOZ_REFLOW_PERF -#define DO_GLOBAL_REFLOW_COUNT(_name, _type) \ - aPresContext->CountReflows((_name), (_type), (nsIFrame*)this); +#define DO_GLOBAL_REFLOW_COUNT(_name) \ + aPresContext->CountReflows((_name), (nsIFrame*)this); #else -#define DO_GLOBAL_REFLOW_COUNT(_name, _type) +#define DO_GLOBAL_REFLOW_COUNT(_name) #endif // MOZ_REFLOW_PERF #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF) diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 7ed58929a41..a1cc198d985 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -66,7 +66,6 @@ #include "nsINameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816) #include "nsIServiceManager.h" #include "nsFrame.h" -#include "nsHTMLReflowCommand.h" #include "nsIViewManager.h" #include "nsCRT.h" #include "prlog.h" @@ -86,7 +85,6 @@ #include "nsContentUtils.h" #include "nsISelection.h" #include "nsISelectionController.h" -#include "nsReflowPath.h" #include "nsLayoutCID.h" #include "nsLayoutAtoms.h" #include "nsIDOMRange.h" @@ -258,7 +256,6 @@ ShowVerifyReflowFlags() class ReflowCountMgr; static const char kGrandTotalsStr[] = "Grand Totals"; -#define NUM_REFLOW_TYPES 5 // Counting Class class ReflowCounter { @@ -271,22 +268,22 @@ public: void DisplayDiffTotals(const char * aStr); void DisplayHTMLTotals(const char * aStr); - void Add(nsReflowReason aType) { mTotals[aType]++; } - void Add(nsReflowReason aType, PRUint32 aTotal) { mTotals[aType] += aTotal; } + void Add() { mTotal++; } + void Add(PRUint32 aTotal) { mTotal += aTotal; } void CalcDiffInTotals(); void SetTotalsCache(); void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; } - PRUint32 GetTotalByType(nsReflowReason aType) { if (aType >= eReflowReason_Initial && aType <= eReflowReason_Dirty) return mTotals[aType]; else return 0; } + PRUint32 GetTotal() { return mTotal; } protected: - void DisplayTotals(PRUint32 * aArray, const char * aTitle); - void DisplayHTMLTotals(PRUint32 * aArray, const char * aTitle); + void DisplayTotals(PRUint32 aTotal, const char * aTitle); + void DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle); - PRUint32 mTotals[NUM_REFLOW_TYPES]; - PRUint32 mCacheTotals[NUM_REFLOW_TYPES]; + PRUint32 mTotal; + PRUint32 mCacheTotal; ReflowCountMgr * mMgr; // weak reference (don't delete) }; @@ -328,7 +325,7 @@ public: void DisplayHTMLTotals(const char * aStr); void DisplayDiffsInTotals(const char * aStr); - void Add(const char * aName, nsReflowReason aType, nsIFrame * aFrame); + void Add(const char * aName, nsIFrame * aFrame); ReflowCounter * LookUp(const char * aName); void PaintCount(const char * aName, nsIRenderingContext* aRenderingContext, nsPresContext* aPresContext, nsIFrame * aFrame, PRUint32 aColor); @@ -345,8 +342,8 @@ public: void SetPaintFrameCounts(PRBool aVal) { mPaintFrameByFrameCounts = aVal; } protected: - void DisplayTotals(PRUint32 * aArray, PRUint32 * aDupArray, char * aTitle); - void DisplayHTMLTotals(PRUint32 * aArray, PRUint32 * aDupArray, char * aTitle); + void DisplayTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle); + void DisplayHTMLTotals(PRUint32 aTotal, PRUint32 * aDupArray, char * aTitle); PR_STATIC_CALLBACK(PRIntn) RemoveItems(PLHashEntry *he, PRIntn i, void *arg); PR_STATIC_CALLBACK(PRIntn) RemoveIndiItems(PLHashEntry *he, PRIntn i, void *arg); @@ -761,249 +758,6 @@ struct nsCallbackEventRequest nsCallbackEventRequest* next; }; - -// ---------------------------------------------------------------------------- - -/** - * Used to build and maintain the incremental reflow tree, and - * dispatch incremental reflows to individual reflow roots. - */ -class IncrementalReflow -{ -public: - ~IncrementalReflow(); - - /** - * Add a reflow command to the set of commands that are to be - * dispatched in the incremental reflow. - */ - enum AddCommandResult { - eEnqueued, // the command was successfully added - eTryLater, // the command could not be added; try again - eCancel, // the command was not added; delete it - eOOM // Out of memory. - }; - AddCommandResult - AddCommand(nsPresContext *aPresContext, - nsHTMLReflowCommand *aCommand); - - /** - * Dispatch the incremental reflow. - */ - void - Dispatch(nsPresContext *aPresContext, - nsHTMLReflowMetrics &aDesiredSize, - const nsSize &aMaxSize, - nsIRenderingContext &aRendContext); - -#ifdef NS_DEBUG - /** - * Dump the incremental reflow state. - */ - void - Dump(nsPresContext *aPresContext) const; -#endif - -protected: - /** - * The set of incremental reflow roots. - */ - nsAutoVoidArray mRoots; -}; - -IncrementalReflow::~IncrementalReflow() -{ - for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) - delete NS_STATIC_CAST(nsReflowPath *, mRoots[i]); -} - -void -IncrementalReflow::Dispatch(nsPresContext *aPresContext, - nsHTMLReflowMetrics &aDesiredSize, - const nsSize &aMaxSize, - nsIRenderingContext &aRendContext) -{ - for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) { - // Send an incremental reflow notification to the first frame in the - // path. - nsReflowPath *path = NS_STATIC_CAST(nsReflowPath *, mRoots[i]); - nsIFrame *first = path->mFrame; - - nsIFrame* root = aPresContext->PresShell()->FrameManager()->GetRootFrame(); - - first->WillReflow(aPresContext); - nsContainerFrame::PositionFrameView(first); - - // If the first frame in the path is the root of the frame - // hierarchy, then use all the available space. If it's simply a - // `reflow root', then use the first frame's size as the available - // space. - nsSize size; - if (first == root) - size = aMaxSize; - else - size = first->GetSize(); - - nsHTMLReflowState reflowState(aPresContext, first, path, - &aRendContext, size); - - nsReflowStatus status; - first->Reflow(aPresContext, aDesiredSize, reflowState, status); - - // If an incremental reflow is initiated at a frame other than the - // root frame, then its desired size had better not change! - NS_ASSERTION(first == root || - (aDesiredSize.width == size.width && aDesiredSize.height == size.height), - "non-root frame's desired size changed during an incremental reflow"); - - first->SetSize(nsSize(aDesiredSize.width, aDesiredSize.height)); - - nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, first, first->GetView(), - &aDesiredSize.mOverflowArea); - - first->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); - } -} - -IncrementalReflow::AddCommandResult -IncrementalReflow::AddCommand(nsPresContext *aPresContext, - nsHTMLReflowCommand *aCommand) -{ - nsIFrame *frame; - aCommand->GetTarget(frame); - NS_ASSERTION(frame != nsnull, "reflow command with no target"); - - // Construct the reflow path by walking up the through the frames' - // parent chain until we reach either a `reflow root' or the root - // frame in the frame hierarchy. - nsAutoVoidArray path; - do { - path.AppendElement(frame); - } while (!(frame->GetStateBits() & NS_FRAME_REFLOW_ROOT) && - (frame = frame->GetParent()) != nsnull); - - // Pop off the root, add it to the set if it's not there already. - PRInt32 lastIndex = path.Count() - 1; - nsIFrame *rootFrame = NS_STATIC_CAST(nsIFrame *, path[lastIndex]); - path.RemoveElementAt(lastIndex); - - // Prevent an incremental reflow from being posted inside a reflow - // root if the reflow root's container has not yet been reflowed. - // This can cause problems like bug 228156. - if (rootFrame->GetParent() && - (rootFrame->GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { - return eCancel; - } - - nsReflowPath *root = nsnull; - - PRInt32 i; - for (i = mRoots.Count() - 1; i >= 0; --i) { - nsReflowPath *r = NS_STATIC_CAST(nsReflowPath *, mRoots[i]); - if (r->mFrame == rootFrame) { - root = r; - break; - } - } - - if (! root) { - root = new nsReflowPath(rootFrame); - if (! root) - return eOOM; - - root->mReflowCommand = nsnull; - mRoots.AppendElement(root); - } - - // Now walk the path from the root to the leaf, adding to the reflow - // tree as necessary. - nsReflowPath *target = root; - for (i = path.Count() - 1; i >= 0; --i) { - nsIFrame *f = NS_STATIC_CAST(nsIFrame *, path[i]); - target = target->EnsureSubtreeFor(f); - - // Out of memory. Ugh. - if (! target) - return eOOM; - } - - // Place the reflow command in the leaf, if one isn't there already. - if (target->mReflowCommand) { - // XXXwaterson it's probably possible to have some notion of - // `promotion' here that would avoid any re-queuing; for example, - // promote a dirty reflow to a style changed. For now, let's punt - // and not worry about it. -#ifdef NS_DEBUG - if (gVerifyReflowFlags & VERIFY_REFLOW_NOISY_RC) - printf("requeuing command %p because %p was already scheduled " - "for the same frame", - (void*)aCommand, (void*)target->mReflowCommand); -#endif - - return eTryLater; - } - - target->mReflowCommand = aCommand; - return eEnqueued; -} - - -#ifdef NS_DEBUG -void -IncrementalReflow::Dump(nsPresContext *aPresContext) const -{ - for (PRInt32 i = mRoots.Count() - 1; i >= 0; --i) - NS_STATIC_CAST(nsReflowPath *, mRoots[i])->Dump(aPresContext, stdout, 0); -} -#endif - -// ---------------------------------------------------------------------------- - -struct ReflowCommandEntry : public PLDHashEntryHdr -{ - nsHTMLReflowCommand* mCommand; -}; - -PR_STATIC_CALLBACK(const void *) -ReflowCommandHashGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) -{ - ReflowCommandEntry *e = NS_STATIC_CAST(ReflowCommandEntry *, entry); - - return e->mCommand; -} - -PR_STATIC_CALLBACK(PLDHashNumber) -ReflowCommandHashHashKey(PLDHashTable *table, const void *key) -{ - const nsHTMLReflowCommand* command = - NS_STATIC_CAST(const nsHTMLReflowCommand*, key); - - // The target is going to be reasonably unique, if we shift out the - // always-zero low-order bits, the type comes from an enum and we just don't - // have that many types, and the child list name is either null or has the - // same high-order bits as all the other child list names. - return - (NS_PTR_TO_INT32(command->GetTarget()) >> 2) ^ - (command->Type() << 17) ^ - (NS_PTR_TO_INT32(command->GetChildListName()) << 20); -} - -PR_STATIC_CALLBACK(PRBool) -ReflowCommandHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, - const void *key) -{ - const ReflowCommandEntry *e = - NS_STATIC_CAST(const ReflowCommandEntry *, entry); - const nsHTMLReflowCommand *command = e->mCommand; - const nsHTMLReflowCommand *command2 = - NS_STATIC_CAST(const nsHTMLReflowCommand *, key); - - return - command->GetTarget() == command2->GetTarget() && - command->Type() == command2->Type() && - command->GetChildListName() == command2->GetChildListName(); -} - // ---------------------------------------------------------------------------- class PresShell : public nsIPresShell, public nsIViewObserver, @@ -1060,14 +814,8 @@ public: nsISupports** aResult) const; NS_IMETHOD GetPlaceholderFrameFor(nsIFrame* aFrame, nsIFrame** aPlaceholderFrame) const; - NS_IMETHOD AppendReflowCommand(nsIFrame* aTargetFrame, - nsReflowType aReflowType, - nsIAtom* aChildListName); - NS_IMETHOD CancelReflowCommand(nsIFrame* aTargetFrame, - nsReflowType* aCmdType); - void CancelReflowCommandInternal(nsIFrame* aTargetFrame, - nsReflowType* aCmdType); - NS_IMETHOD CancelAllReflowCommands(); + NS_IMETHOD FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty); + NS_IMETHOD CancelAllPendingReflows(); NS_IMETHOD IsSafeToFlush(PRBool& aIsSafeToFlush); NS_IMETHOD FlushPendingNotifications(mozFlushType aType); @@ -1248,7 +996,7 @@ public: #ifdef MOZ_REFLOW_PERF NS_IMETHOD DumpReflows(); - NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame); + NS_IMETHOD CountReflows(const char * aName, nsIFrame * aFrame); NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRenderingContext, nsPresContext* aPresContext, nsIFrame * aFrame, PRUint32 aColor); NS_IMETHOD SetPaintFrameCount(PRBool aOn); @@ -1275,15 +1023,12 @@ protected: void UnsuppressAndInvalidate(); - nsresult ReflowCommandAdded(nsHTMLReflowCommand* aRC); - nsresult ReflowCommandRemoved(nsHTMLReflowCommand* aRC); - - // This method should be called after reflow commands have been - // removed from the queue, but after the state in the presshell is - // such that it's safe to flush (i.e. mIsReflowing == PR_FALSE) - // If there are no load-created reflow commands and we blocked - // onload on the document, we'll unblock it. - void DoneRemovingReflowCommands(); + // This method should be called after mDirtyRoots has been emptied, + // but after the state in the presshell is such that it's safe to + // flush (i.e. mIsReflowing == PR_FALSE) If there are no load-created + // reflow commands and we blocked onload on the document, we'll + // unblock it. + void DoneRemovingDirtyRoots(); void WillCauseReflow() { ++mChangeNestCount; } nsresult DidCauseReflow(); @@ -1292,11 +1037,6 @@ protected: nsresult ClearReflowEventStatus(); void PostReflowEvent(); - // Note: when PR_FALSE is returned, AlreadyInQueue assumes the command will - // in fact be added to the queue. If it's not, it needs to be removed from - // mReflowCommandTable (AlreadyInQueue will insert it in that table). - PRBool AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand); - friend struct ReflowEvent; // Utility to determine if we're in the middle of a drag. @@ -1332,9 +1072,8 @@ protected: #ifdef DEBUG PRUint32 mUpdateCount; #endif - // normal reflow commands - nsVoidArray mReflowCommands; - PLDHashTable mReflowCommandTable; + // reflow roots that need to be reflowed, as both a queue and a hashtable + nsVoidArray mDirtyRoots; PRPackedBool mDocumentLoading; PRPackedBool mDocumentOnloadBlocked; @@ -1370,7 +1109,6 @@ protected: FrameArena mFrameArena; StackArena* mStackArena; nsCOMPtr mDragService; - PRInt32 mRCCreatedDuringLoad; // Counter to keep track of reflow commands created during doc // used for list of posted events and attribute changes. To be done // after reflow. @@ -1654,25 +1392,6 @@ PresShell::Init(nsIDocument* aDocument, NS_ADDREF(mPresContext); aPresContext->SetShell(this); - // Create our reflow command hashtable - static PLDHashTableOps reflowCommandOps = - { - PL_DHashAllocTable, - PL_DHashFreeTable, - ReflowCommandHashGetKey, - ReflowCommandHashHashKey, - ReflowCommandHashMatchEntry, - PL_DHashMoveEntryStub, - PL_DHashClearEntryStub, - PL_DHashFinalizeStub - }; - - if (!PL_DHashTableInit(&mReflowCommandTable, &reflowCommandOps, - nsnull, sizeof(ReflowCommandEntry), 16)) { - mReflowCommandTable.ops = nsnull; - return NS_ERROR_OUT_OF_MEMORY; - } - // Now we can initialize the style set. nsresult result = aStyleSet->Init(aPresContext); NS_ENSURE_SUCCESS(result, result); @@ -1879,18 +1598,13 @@ PresShell::Destroy() getter_AddRefs(eventQueue)); eventQueue->RevokeEvents(this); - CancelAllReflowCommands(); + CancelAllPendingReflows(); NS_ASSERTION(!mDocumentOnloadBlocked, - "CancelAllReflowCommands() didn't unblock onload?"); + "CancelAllPendingReflows() didn't unblock onload?"); KillResizeEventTimer(); - // Now that mReflowCommandTable won't be accessed anymore, finish it - if (mReflowCommandTable.ops) { - PL_DHashTableFinish(&mReflowCommandTable); - } - mHaveShutDown = PR_TRUE; return NS_OK; @@ -2687,6 +2401,9 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) // start batching widget changes mViewManager->BeginUpdateViewBatch(); + // XXX Do a full invalidate at the beginning so that invalidates along + // the way don't have region accumulation issues? + WillCauseReflow(); if (mPresContext) { @@ -2754,8 +2471,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) mIsReflowing = PR_TRUE; - nsHTMLReflowState reflowState(mPresContext, rootFrame, - eReflowReason_Initial, rcx, maxSize); + nsHTMLReflowState reflowState(mPresContext, rootFrame, rcx, maxSize); rootFrame->WillReflow(mPresContext); nsContainerFrame::PositionFrameView(rootFrame); rootFrame->Reflow(mPresContext, desiredSize, reflowState, status); @@ -2853,6 +2569,9 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) NS_ASSERTION(mViewManager, "Must have view manager"); mViewManager->BeginUpdateViewBatch(); + // XXX Do a full invalidate at the beginning so that invalidates along + // the way don't have region accumulation issues? + WillCauseReflow(); if (mCaret) @@ -2899,8 +2618,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) nsresult rv=CreateRenderingContext(rootFrame, &rcx); if (NS_FAILED(rv)) return rv; - nsHTMLReflowState reflowState(mPresContext, rootFrame, - eReflowReason_Resize, rcx, maxSize); + nsHTMLReflowState reflowState(mPresContext, rootFrame, rcx, maxSize); rootFrame->WillReflow(mPresContext); nsContainerFrame::PositionFrameView(rootFrame); @@ -3019,8 +2737,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) if (!mIgnoreFrameDestruction) { mFrameConstructor->NotifyDestroyingFrame(aFrame); - // Cancel any pending reflow commands targeted at this frame - CancelReflowCommandInternal(aFrame, nsnull); + mDirtyRoots.RemoveElement(aFrame); // Notify the frame manager FrameManager()->NotifyDestroyingFrame(aFrame); @@ -3316,6 +3033,10 @@ PresShell::StyleChangeReflow() nsIFrame* rootFrame = FrameManager()->GetRootFrame(); if (rootFrame) { + // Mark everything dirty + rootFrame->AddStateBits(NS_FRAME_IS_DIRTY); + FrameNeedsReflow(rootFrame, eStyleChange); + // Kick off a top-down reflow NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("enter nsPresShell::StyleChangeReflow")); @@ -3338,8 +3059,7 @@ PresShell::StyleChangeReflow() nsresult rv=CreateRenderingContext(rootFrame, &rcx); if (NS_FAILED(rv)) return rv; - nsHTMLReflowState reflowState(mPresContext, rootFrame, - eReflowReason_StyleChange, rcx, maxSize); + nsHTMLReflowState reflowState(mPresContext, rootFrame, rcx, maxSize); rootFrame->WillReflow(mPresContext); nsContainerFrame::PositionFrameView(rootFrame); @@ -3488,48 +3208,13 @@ PresShell::EndLoad(nsIDocument *aDocument) mDocumentLoading = PR_FALSE; } -// aReflowCommand is considered to be already in the queue if the -// frame it targets is targeted by a pre-existing reflow command in -// the queue. -PRBool -PresShell::AlreadyInQueue(nsHTMLReflowCommand* aReflowCommand) -{ - if (!mReflowCommandTable.ops) { - // We're already destroyed - NS_ERROR("We really shouldn't be posting reflow commands here"); - } - - ReflowCommandEntry* e = - NS_STATIC_CAST(ReflowCommandEntry*, - PL_DHashTableOperate(&mReflowCommandTable, aReflowCommand, - PL_DHASH_ADD)); - - if (!e) { - // We lie no matter what we say here - return PR_FALSE; - } - - // We're using the stub ClearEntry, which zeros out entries, so a - // non-null mCommand means we're in the queue already. - if (e->mCommand) { -#ifdef DEBUG - if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("*** PresShell::AlreadyInQueue(): Discarding reflow command: this=%p\n", (void*)this); - aReflowCommand->List(stdout); - } -#endif - return PR_TRUE; - } - - e->mCommand = aReflowCommand; - return PR_FALSE; -} - NS_IMETHODIMP -PresShell::AppendReflowCommand(nsIFrame* aTargetFrame, - nsReflowType aReflowType, - nsIAtom* aChildListName) +PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty) { + NS_PRECONDITION(aFrame->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN), + "frame not dirty"); + // If we've not yet done the initial reflow, then don't bother // enqueuing a reflow command yet. if (! mDidInitialReflow) @@ -3544,19 +3229,8 @@ PresShell::AppendReflowCommand(nsIFrame* aTargetFrame, if (mInVerifyReflow) { return NS_OK; } -#endif - - nsHTMLReflowCommand* command = new nsHTMLReflowCommand(aTargetFrame, - aReflowType, - aChildListName); - if (!command) { - return NS_ERROR_OUT_OF_MEMORY; - } - -#ifdef DEBUG if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("\nPresShell@%p: adding reflow command\n", (void*)this); - command->List(stdout); + printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame); if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) { printf("Current content model:\n"); nsIContent *rootContent = mDocument->GetRootContent(); @@ -3567,24 +3241,65 @@ PresShell::AppendReflowCommand(nsIFrame* aTargetFrame, } #endif - // Add the reflow command to the queue - nsresult rv = NS_OK; - if (!AlreadyInQueue(command)) { - if (mReflowCommands.AppendElement(command)) { - ReflowCommandAdded(command); - } else { - // Drop this command.... we're out of memory - PL_DHashTableOperate(&mReflowCommandTable, command, - PL_DHASH_REMOVE); - delete command; - rv = NS_ERROR_OUT_OF_MEMORY; + // Mark the intrinsic widths as dirty on the frame, all of its ancestors, + // and all of its descendants, if needed: + + if (aIntrinsicDirty != eResize) { + // Mark argument and all ancestors dirty (unless we hit a reflow root + // other than aFrame) + for (nsIFrame *a = aFrame; + a && (!(a->GetStateBits() & NS_FRAME_REFLOW_ROOT) || a == aFrame); + a = a->GetParent()) + a->MarkIntrinsicWidthsDirty(); + } + + if (aIntrinsicDirty == eStyleChange) { + // Mark all descendants dirty (using an nsVoidArray stack rather than + // recursion). + nsVoidArray stack; + stack.AppendElement(aFrame); + + while (stack.Count() != 0) { + nsIFrame *f = + NS_STATIC_CAST(nsIFrame*, stack.FastElementAt(stack.Count() - 1)); + stack.RemoveElementAt(stack.Count() - 1); + + PRInt32 childListIndex = 0; + nsIAtom *childListName; + do { + childListName = f->GetAdditionalChildListName(childListIndex++); + for (nsIFrame *kid = f->GetFirstChild(childListName); kid; + kid = kid->GetNextSibling()) { + kid->MarkIntrinsicWidthsDirty(); + stack.AppendElement(kid); + } + } while (childListName); } } - else { - // We're not going to process this reflow command. - delete command; + + // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty) up the + // tree until we reach either a frame that's already dirty or a reflow root. + nsIFrame *f = aFrame; + for (;;) { + if (((f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && f != aFrame) || + !f->GetParent()) { + // we've hit a reflow root or the root frame + NS_ASSERTION(mDirtyRoots.IndexOf(f) == -1, "ChildIsDirty lied"); + mDirtyRoots.AppendElement(f); + break; + } + + nsIFrame *child = f; + f = f->GetParent(); + if (f->ChildIsDirty(child)) { + // This frame was already marked dirty. + break; + } } + if (gAsyncReflowDuringDocLoad && mDocumentLoading && !mDummyLayoutRequest) + AddDummyLayoutRequest(); + // For async reflow during doc load, post a reflow event if we are not batching reflow commands. // For sync reflow during doc load, post a reflow event if we are not batching reflow commands // and the document is not loading. @@ -3596,7 +3311,7 @@ PresShell::AppendReflowCommand(nsIFrame* aTargetFrame, PostReflowEvent(); } - return rv; + return NS_OK; } @@ -3661,57 +3376,12 @@ PresShell::GetViewToScroll(nsLayoutUtils::Direction aDirection) return scrollView; } -void -PresShell::CancelReflowCommandInternal(nsIFrame* aTargetFrame, - nsReflowType* aCmdType) -{ - PRInt32 i, n = mReflowCommands.Count(); - for (i = 0; i < n; i++) { - nsHTMLReflowCommand* rc = (nsHTMLReflowCommand*) mReflowCommands.ElementAt(i); - if (rc && rc->GetTarget() == aTargetFrame && - (!aCmdType || rc->Type() == *aCmdType)) { -#ifdef DEBUG - if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("PresShell: removing rc=%p for frame ", (void*)rc); - nsFrame::ListTag(stdout, aTargetFrame); - printf("\n"); - } -#endif - mReflowCommands.RemoveElementAt(i); - ReflowCommandRemoved(rc); - delete rc; - n--; - i--; - } - } - - DoneRemovingReflowCommands(); -} - NS_IMETHODIMP -PresShell::CancelReflowCommand(nsIFrame* aTargetFrame, - nsReflowType* aCmdType) +PresShell::CancelAllPendingReflows() { - CancelReflowCommandInternal(aTargetFrame, aCmdType); - return NS_OK; -} + mDirtyRoots.Clear(); - -NS_IMETHODIMP -PresShell::CancelAllReflowCommands() -{ - PRInt32 n = mReflowCommands.Count(); - nsHTMLReflowCommand* rc; - PRInt32 i; - for (i = 0; i < n; i++) { - rc = NS_STATIC_CAST(nsHTMLReflowCommand*, mReflowCommands.ElementAt(i)); - ReflowCommandRemoved(rc); - delete rc; - } - NS_ASSERTION(n == mReflowCommands.Count(),"reflow command list changed during cancel!"); - mReflowCommands.Clear(); - - DoneRemovingReflowCommands(); + DoneRemovingDirtyRoots(); return NS_OK; } @@ -4732,7 +4402,7 @@ PresShell::UnsuppressPainting() // the reflows and get all the frames where we want them // before actually unlocking the painting. Otherwise // go ahead and unlock now. - if (mReflowCommands.Count() > 0) + if (mDirtyRoots.Count() > 0) mShouldUnsuppressPainting = PR_TRUE; else UnsuppressAndInvalidate(); @@ -6362,7 +6032,7 @@ PresShell::PostReflowEvent() getter_AddRefs(eventQueue)); if (eventQueue != mReflowEventQueue && !mIsDestroying && - !mIsReflowing && mReflowCommands.Count() > 0) { + !mIsReflowing && mDirtyRoots.Count() > 0) { ReflowEvent* ev = new ReflowEvent(NS_STATIC_CAST(nsIPresShell*, this)); if (NS_FAILED(eventQueue->PostEvent(ev))) { NS_ERROR("failed to post reflow event"); @@ -6414,7 +6084,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) MOZ_TIMER_DEBUGLOG(("Start: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_START(mReflowWatch); - if (0 != mReflowCommands.Count()) { + if (0 != mDirtyRoots.Count()) { nsHTMLReflowMetrics desiredSize(nsnull); nsIRenderingContext* rcx; nsIFrame* rootFrame = FrameManager()->GetRootFrame(); @@ -6429,15 +6099,6 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) printf("ProcessReflowCommands: begin incremental reflow\n"); } } - if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { - PRInt32 i, n = mReflowCommands.Count(); - printf("\nPresShell::ProcessReflowCommands: this=%p, count=%d\n", (void*)this, n); - for (i = 0; i < n; i++) { - nsHTMLReflowCommand* rc = (nsHTMLReflowCommand*) - mReflowCommands.ElementAt(i); - rc->List(stdout); - } - } #endif // If reflow is interruptible, then make a note of our deadline. @@ -6452,44 +6113,57 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) mIsReflowing = PR_TRUE; do { - // Coalesce the reflow commands into a tree. - IncrementalReflow reflow; - for (PRInt32 i = mReflowCommands.Count() - 1; i >= 0; --i) { - nsHTMLReflowCommand *command = - NS_STATIC_CAST(nsHTMLReflowCommand *, mReflowCommands[i]); + // Send an incremental reflow notification to the target frame. + PRInt32 idx = mDirtyRoots.Count() - 1; + nsIFrame *target = NS_STATIC_CAST(nsIFrame*, mDirtyRoots[idx]); + mDirtyRoots.RemoveElementAt(idx); - IncrementalReflow::AddCommandResult res = - reflow.AddCommand(mPresContext, command); - if (res == IncrementalReflow::eEnqueued || - res == IncrementalReflow::eCancel) { - // Remove the command from the queue. - mReflowCommands.RemoveElementAt(i); - ReflowCommandRemoved(command); - if (res == IncrementalReflow::eCancel) - delete command; - } - else { - // The reflow command couldn't be added to the tree; leave - // it in the queue, and we'll handle it next time. -#ifdef DEBUG - printf("WARNING: Couldn't add reflow command, so splitting.\n"); -#endif - } + if (!(target->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { + // It's not dirty anymore, which probably means the notification + // was posted in the middle of a reflow (perhaps with a reflow + // root in the middle). Don't do anything. + continue; } -#ifdef DEBUG - if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { - printf("Incremental reflow tree:\n"); - reflow.Dump(mPresContext); - } -#endif + nsIFrame* root = mPresContext->FrameManager()->GetRootFrame(); - // Dispatch an incremental reflow. - reflow.Dispatch(mPresContext, desiredSize, maxSize, *rcx); + target->WillReflow(mPresContext); + nsContainerFrame::PositionFrameView(target); + + // If the target frame is the root of the frame hierarchy, then + // use all the available space. If it's simply a `reflow root', + // then use the target frame's size as the available space. + nsSize size; + if (target == root) + size = maxSize; + else + size = target->GetSize(); + + nsHTMLReflowState reflowState(mPresContext, target, rcx, size); + + nsReflowStatus status; + target->Reflow(mPresContext, desiredSize, reflowState, status); + + // If an incremental reflow is initiated at a frame other than the + // root frame, then its desired size had better not change! + NS_ASSERTION(target == root || + (desiredSize.width == size.width && + desiredSize.height == size.height), + "non-root frame's desired size changed during an " + "incremental reflow"); + + target->SetSize(nsSize(desiredSize.width, desiredSize.height)); + + nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target, + target->GetView(), + &desiredSize.mOverflowArea); + + target->DidReflow(mPresContext, nsnull, NS_FRAME_REFLOW_FINISHED); // Keep going until we're out of reflow commands, or we've run // past our deadline. - } while (mReflowCommands.Count() && + } while (mDirtyRoots.Count() && (!aInterruptible || PR_IntervalNow() < deadline)); // XXXwaterson for interruptible reflow, examine the tree and @@ -6501,7 +6175,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) // If any new reflow commands were enqueued during the reflow, // schedule another reflow event to process them. - if (mReflowCommands.Count()) + if (mDirtyRoots.Count()) PostReflowEvent(); #ifdef DEBUG @@ -6532,7 +6206,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) ok ? "ok" : "failed"); } - if (0 != mReflowCommands.Count()) { + if (0 != mDirtyRoots.Count()) { printf("XXX yikes! reflow commands queued during verify-reflow\n"); } } @@ -6540,7 +6214,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) // If there are no more reflow commands in the queue, we'll want // to unblock onload. - DoneRemovingReflowCommands(); + DoneRemovingDirtyRoots(); DidDoReflow(); } @@ -6548,7 +6222,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible) MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this)); MOZ_TIMER_STOP(mReflowWatch); - if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) { + if (mShouldUnsuppressPainting && mDirtyRoots.Count() == 0) { // We only unlock if we're out of reflows. It's pointless // to unlock if reflows are still pending, since reflows // are just going to thrash the frames around some more. By @@ -6567,65 +6241,8 @@ PresShell::ClearReflowEventStatus() return NS_OK; } -nsresult -PresShell::ReflowCommandAdded(nsHTMLReflowCommand* aRC) -{ - - if (gAsyncReflowDuringDocLoad) { - NS_PRECONDITION(mRCCreatedDuringLoad >= 0, "PresShell's reflow command queue is in a bad state."); - if (mDocumentLoading) { - aRC->AddFlagBits(NS_RC_CREATED_DURING_DOCUMENT_LOAD); - mRCCreatedDuringLoad++; - -#ifdef PR_LOGGING - if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) { - nsIFrame* target; - aRC->GetTarget(target); - - nsIAtom* type = target->GetType(); - NS_ASSERTION(type, "frame didn't override GetType()"); - - nsAutoString typeStr(NS_LITERAL_STRING("unknown")); - if (type) - type->ToString(typeStr); - - PR_LOG(gLog, PR_LOG_DEBUG, - ("presshell=%p, ReflowCommandAdded(%p) target=%p[%s] mRCCreatedDuringLoad=%d\n", - this, aRC, target, NS_ConvertUCS2toUTF8(typeStr).get(), mRCCreatedDuringLoad)); - } -#endif - - if (!mDocumentOnloadBlocked) { - mDocument->BlockOnload(); - mDocumentOnloadBlocked = PR_TRUE; - } - } - } - return NS_OK; -} - -nsresult -PresShell::ReflowCommandRemoved(nsHTMLReflowCommand* aRC) -{ - NS_PRECONDITION(mReflowCommandTable.ops, "How did that happen?"); - - PL_DHashTableOperate(&mReflowCommandTable, aRC, PL_DHASH_REMOVE); - - if (gAsyncReflowDuringDocLoad) { - NS_PRECONDITION(mRCCreatedDuringLoad >= 0, "PresShell's reflow command queue is in a bad state."); - if (aRC->GetFlagBits() & NS_RC_CREATED_DURING_DOCUMENT_LOAD) { - mRCCreatedDuringLoad--; - - PR_LOG(gLog, PR_LOG_DEBUG, - ("presshell=%p, ReflowCommandRemoved(%p) mRCCreatedDuringLoad=%d\n", - this, aRC, mRCCreatedDuringLoad)); - } - } - return NS_OK; -} - void -PresShell::DoneRemovingReflowCommands() +PresShell::DoneRemovingDirtyRoots() { // We want to unblock here even if we're destroying, since onload // can well fire with no presentation in sight. So just check @@ -7431,10 +7048,10 @@ PresShell::DumpReflows() //------------------------------------------------------------- NS_IMETHODIMP -PresShell::CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) +PresShell::CountReflows(const char * aName, nsIFrame * aFrame) { if (mReflowCountMgr) { - mReflowCountMgr->Add(aName, (nsReflowReason)aType, aFrame); + mReflowCountMgr->Add(aName, aFrame); } return NS_OK; @@ -7481,81 +7098,59 @@ ReflowCounter::~ReflowCounter() //------------------------------------------------------------------ void ReflowCounter::ClearTotals() { - for (PRUint32 i=0;iLookUp(kGrandTotalsStr); printf("%25s\t", aTitle); - for (i=0;i 0) { - gTots->Add((nsReflowReason)i, aArray[i]); - } + printf("%d\t", aTotal); + if (gTots != this && aTotal > 0) { + gTots->Add(aTotal); } - printf("%d\n", total); } //------------------------------------------------------------------ -void ReflowCounter::DisplayHTMLTotals(PRUint32 * aArray, const char * aTitle) +void ReflowCounter::DisplayHTMLTotals(PRUint32 aTotal, const char * aTitle) { - // figure total - PRUint32 total = 0; - PRUint32 i; - for (i=0;i
%s
", aTitle); - for (i=0;i
"); - if (aArray[i]) { - fprintf(fd, "%d", aArray[i]); - } else { - fprintf(fd, " "); - } - fprintf(fd, "
"); - if (gTots != this && aArray[i] > 0) { - gTots->Add((nsReflowReason)i, aArray[i]); - } + fprintf(fd, "
%d
\n", aTotal); + + if (gTots != this && aTotal > 0) { + gTots->Add(aTotal); } - fprintf(fd, "
%d
\n", total); } //------------------------------------------------------------------ @@ -7614,7 +7201,7 @@ ReflowCounter * ReflowCountMgr::LookUp(const char * aName) } //------------------------------------------------------------------ -void ReflowCountMgr::Add(const char * aName, nsReflowReason aType, nsIFrame * aFrame) +void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame) { NS_ASSERTION(aName != nsnull, "Name shouldn't be null!"); @@ -7627,7 +7214,7 @@ void ReflowCountMgr::Add(const char * aName, nsReflowReason aType, nsIFrame * aF NS_ASSERTION(name != nsnull, "null ptr"); PL_HashTableAdd(mCounts, name, counter); } - counter->Add(aType); + counter->Add(); } if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) && @@ -7646,7 +7233,7 @@ void ReflowCountMgr::Add(const char * aName, nsReflowReason aType, nsIFrame * aF // this eliminates extra counts from super classes if (counter != nsnull && counter->mName.EqualsASCII(aName)) { counter->mCount++; - counter->mCounter.Add(aType, 1); + counter->mCounter.Add(1); } } } @@ -7772,14 +7359,8 @@ void ReflowCountMgr::DoGrandTotals() gTots->ClearTotals(); } - static const char * title[] = {"Init", "Incrm", "Resze", "Style", "Dirty", "Total"}; - printf("\t\t\t"); - PRUint32 i; - for (i=0;imName); for (PRInt32 i=0;imCount); - for (PRInt32 inx=0;inx<5;inx++) { - if (inx != 0) printf(","); - printf("%d", counter->mCounter.GetTotalByType(nsReflowReason(inx))); - } + printf("%d", counter->mCounter.GetTotal()); printf("]\n"); nsMemory::Free(name); } @@ -7827,10 +7405,7 @@ PRIntn ReflowCountMgr::DoSingleIndi(PLHashEntry *he, PRIntn i, void *arg) if (counter && !counter->mHasBeenOutput) { char * name = ToNewCString(counter->mName); printf("%s - %p [%d][", name, (void*)counter->mFrame, counter->mCount); - for (PRInt32 inx=0;inx<5;inx++) { - if (inx != 0) printf(","); - printf("%d", counter->mCounter.GetTotalByType(nsReflowReason(inx))); - } + printf("%d", counter->mCounter.GetTotal()); printf("]\n"); nsMemory::Free(name); } @@ -7879,10 +7454,9 @@ void ReflowCountMgr::DoGrandHTMLTotals() gTots->ClearTotals(); } - static const char * title[] = {"Class", "Init", "Incrm", "Resze", "Style", "Dirty", "Total"}; + static const char * title[] = {"Class", "Reflows"}; fprintf(mFD, ""); - PRUint32 i; - for (i=0;i
%s
", title[i]); } fprintf(mFD, "\n"); diff --git a/mozilla/layout/build/Makefile.in b/mozilla/layout/build/Makefile.in index f2d2b3a4cb3..2a294650803 100644 --- a/mozilla/layout/build/Makefile.in +++ b/mozilla/layout/build/Makefile.in @@ -117,9 +117,7 @@ EXPORTS = \ SHARED_LIBRARY_LIBS = \ $(DIST)/lib/$(LIB_PREFIX)gkbase_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkgeneric_s.$(LIB_SUFFIX) \ - $(DIST)/lib/$(LIB_PREFIX)gkforms_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkstyle_s.$(LIB_SUFFIX) \ - $(DIST)/lib/$(LIB_PREFIX)gktable_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkxulbase_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkconbase_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkconcvs_s.$(LIB_SUFFIX) \ @@ -143,6 +141,18 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifdef CSS_TABLES +SHARED_LIBRARY_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)gktable_s.$(LIB_SUFFIX) \ + $(NULL) +endif + +ifdef HTML_FORMS +SHARED_LIBRARY_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)gkforms_s.$(LIB_SUFFIX) \ + $(NULL) +endif + ifdef MOZ_XUL SHARED_LIBRARY_LIBS += \ $(DIST)/lib/$(LIB_PREFIX)gkxultree_s.$(LIB_SUFFIX) \ diff --git a/mozilla/layout/build/nsLayoutModule.cpp b/mozilla/layout/build/nsLayoutModule.cpp index 8904be47e0b..8f1038b2633 100644 --- a/mozilla/layout/build/nsLayoutModule.cpp +++ b/mozilla/layout/build/nsLayoutModule.cpp @@ -125,7 +125,9 @@ #include "nsStyleSet.h" #include "nsImageFrame.h" #include "nsILanguageAtomService.h" +#ifdef HTML_FORMS #include "nsTextControlFrame.h" +#endif #include "nsStyleSheetService.h" // view stuff @@ -429,7 +431,9 @@ Shutdown() nsGlobalWindow::ShutDown(); nsDOMClassInfo::ShutDown(); +#ifdef HTML_FORMS nsTextControlFrame::ShutDown(); +#endif nsXBLWindowKeyHandler::ShutDown(); nsAutoCopyListener::Shutdown(); } diff --git a/mozilla/layout/forms/Makefile.in b/mozilla/layout/forms/Makefile.in index e2520548304..ddbb661e282 100644 --- a/mozilla/layout/forms/Makefile.in +++ b/mozilla/layout/forms/Makefile.in @@ -43,8 +43,10 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk MODULE = layout +ifdef HTML_FORMS LIBRARY_NAME = gkforms_s LIBXUL_LIBRARY = 1 +endif REQUIRES = xpcom \ string \ @@ -82,6 +84,7 @@ EXPORTS = \ nsITextControlFrame.h \ $(NULL) +ifdef HTML_FORMS CPPSRCS = \ nsButtonFrameRenderer.cpp \ nsComboboxControlFrame.cpp \ @@ -100,6 +103,7 @@ CPPSRCS = \ nsIsIndexFrame.cpp \ nsSelectsAreaFrame.cpp \ $(NULL) +endif # we don't want the shared lib, but we want to force the creation of a static lib. FORCE_STATIC_LIB = 1 diff --git a/mozilla/layout/forms/nsComboboxControlFrame.cpp b/mozilla/layout/forms/nsComboboxControlFrame.cpp index 75fe5837016..01f5b088325 100644 --- a/mozilla/layout/forms/nsComboboxControlFrame.cpp +++ b/mozilla/layout/forms/nsComboboxControlFrame.cpp @@ -1824,7 +1824,8 @@ nsComboboxControlFrame::HandleRedisplayTextEvent() ActuallyDisplayText(PR_TRUE); mDisplayFrame->AddStateBits(NS_FRAME_IS_DIRTY); - ReflowDirtyChild(GetPresContext()->PresShell(), mDisplayFrame); + GetPresContext()->PresShell()->FrameNeedsReflow(mDisplayFrame, + nsIPresShell::eStyleChange); mInRedisplayText = PR_FALSE; } diff --git a/mozilla/layout/forms/nsFieldSetFrame.cpp b/mozilla/layout/forms/nsFieldSetFrame.cpp index 70a5456019f..724a82869ae 100644 --- a/mozilla/layout/forms/nsFieldSetFrame.cpp +++ b/mozilla/layout/forms/nsFieldSetFrame.cpp @@ -366,7 +366,7 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext, reflowContent = PR_TRUE; } else if (reason == eReflowReason_Dirty) { // if dirty then check dirty flags - if (GetStateBits() & NS_FRAME_IS_DIRTY) { + if (aReflowState.ShouldReflowAllKids()) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else { diff --git a/mozilla/layout/forms/nsFormControlHelper.cpp b/mozilla/layout/forms/nsFormControlHelper.cpp index b3f22c80d94..387ca1c5902 100644 --- a/mozilla/layout/forms/nsFormControlHelper.cpp +++ b/mozilla/layout/forms/nsFormControlHelper.cpp @@ -381,9 +381,6 @@ void nsFormControlHelper::StyleChangeReflow(nsPresContext* aPresContext, nsIFrame* aFrame) { - aPresContext->PresShell()->AppendReflowCommand(aFrame, - eReflowType_StyleChanged, - nsnull); + aPresContext->PresShell()-> + FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange); } - - diff --git a/mozilla/layout/forms/nsGfxButtonControlFrame.cpp b/mozilla/layout/forms/nsGfxButtonControlFrame.cpp index baf4fb206ee..1cb2d6a3a29 100644 --- a/mozilla/layout/forms/nsGfxButtonControlFrame.cpp +++ b/mozilla/layout/forms/nsGfxButtonControlFrame.cpp @@ -49,7 +49,6 @@ #include "nsIServiceManager.h" #include "nsIDOMNode.h" #include "nsLayoutAtoms.h" -#include "nsReflowPath.h" #include "nsAutoPtr.h" #include "nsStyleSet.h" #include "nsContentUtils.h" diff --git a/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp b/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp index c0aa90b60b4..3e6911c46ec 100644 --- a/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/mozilla/layout/forms/nsHTMLButtonControlFrame.cpp @@ -62,7 +62,6 @@ #include "nsFormControlFrame.h" #include "nsFrameManager.h" #include "nsINameSpaceManager.h" -#include "nsReflowPath.h" #include "nsIServiceManager.h" #include "nsIDOMHTMLButtonElement.h" #include "nsIDOMHTMLInputElement.h" diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp index 139c95125a5..e8dcbe59124 100644 --- a/mozilla/layout/forms/nsListControlFrame.cpp +++ b/mozilla/layout/forms/nsListControlFrame.cpp @@ -59,7 +59,6 @@ #include "nsIScrollableView.h" #include "nsIDOMHTMLOptGroupElement.h" #include "nsWidgetsCID.h" -#include "nsHTMLReflowCommand.h" #include "nsIPresShell.h" #include "nsHTMLParts.h" #include "nsIDOMEventReceiver.h" @@ -87,7 +86,6 @@ #include "nsISelectElement.h" #include "nsIPrivateDOMEvent.h" #include "nsCSSRendering.h" -#include "nsReflowPath.h" #include "nsITheme.h" #include "nsIDOMMouseListener.h" #include "nsIDOMMouseMotionListener.h" diff --git a/mozilla/layout/generic/Makefile.in b/mozilla/layout/generic/Makefile.in index eeb8fd4afb6..29d021eec8d 100644 --- a/mozilla/layout/generic/Makefile.in +++ b/mozilla/layout/generic/Makefile.in @@ -99,7 +99,6 @@ EXPORTS = \ nsIScrollableFrame.h \ nsIScrollableViewProvider.h \ nsIStatefulFrame.h \ - nsReflowType.h \ $(NULL) ifdef IBMBIDI @@ -131,7 +130,6 @@ CPPSRCS = \ nsHTMLCanvasFrame.cpp \ nsHTMLContainerFrame.cpp \ nsHTMLFrame.cpp \ - nsHTMLReflowCommand.cpp \ nsHTMLReflowState.cpp \ nsImageFrame.cpp \ nsImageMap.cpp \ @@ -144,7 +142,6 @@ CPPSRCS = \ nsPageContentFrame.cpp \ nsPageFrame.cpp \ nsPlaceholderFrame.cpp \ - nsReflowPath.cpp \ nsSelection.cpp \ nsSimplePageSequence.cpp \ nsSpaceManager.cpp \ diff --git a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp index e6626d282aa..5c78c1a63a8 100644 --- a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp @@ -37,7 +37,6 @@ #include "nsCOMPtr.h" #include "nsAbsoluteContainingBlock.h" #include "nsContainerFrame.h" -#include "nsReflowPath.h" #include "nsIViewManager.h" #include "nsLayoutAtoms.h" #include "nsIPresShell.h" @@ -84,10 +83,11 @@ nsAbsoluteContainingBlock::AppendFrames(nsIFrame* aDelegatingFrame, #endif mAbsoluteFrames.AppendFrames(nsnull, aFrameList); - // Generate a reflow command to reflow the dirty frames + aDelegatingFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + // no damage to intrinsic widths, since absolutely positioned frames can't + // change them return aDelegatingFrame->GetPresContext()->PresShell()-> - AppendReflowCommand(aDelegatingFrame, eReflowType_ReflowDirty, - GetChildListName()); + FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize); } nsresult @@ -102,10 +102,11 @@ nsAbsoluteContainingBlock::InsertFrames(nsIFrame* aDelegatingFrame, #endif mAbsoluteFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); - // Generate a reflow command to reflow the dirty frames + aDelegatingFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + // no damage to intrinsic widths, since absolutely positioned frames can't + // change them return aDelegatingFrame->GetPresContext()->PresShell()-> - AppendReflowCommand(aDelegatingFrame, eReflowType_ReflowDirty, - GetChildListName()); + FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize); } nsresult @@ -159,104 +160,33 @@ nsAbsoluteContainingBlock::Reflow(nsIFrame* aDelegatingFrame, const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - nsRect* aChildBounds, - PRBool aForceReflow, PRBool aCBWidthChanged, - PRBool aCBHeightChanged) + PRBool aCBHeightChanged, + nsRect* aChildBounds) { // Initialize OUT parameter if (aChildBounds) aChildBounds->SetRect(0, 0, 0, 0); - // Make a copy of the reflow state. If the reason is - // eReflowReason_Incremental (which should mean either that the target - // is the frame for which this is the absolute container or that the - // container changed size due to incremental reflow of its children), - // then change it to eReflowReason_Resize. - // XXXldb If the target is this frame, shouldn't we be setting it - // appropriately (which might mean to StyleChanged)? - nsHTMLReflowState reflowState(aReflowState); - if (eReflowReason_Incremental == reflowState.reason) { - reflowState.reason = eReflowReason_Resize; - } + PRBool reflowAll = aReflowState.ShouldReflowAllKids(); nsIFrame* kidFrame; for (kidFrame = mAbsoluteFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) { - if (!aForceReflow && - !FrameDependsOnContainer(kidFrame, aCBWidthChanged, aCBHeightChanged)) { - // Skip this frame, but add it in to the child bounds as needed - AddFrameToChildBounds(kidFrame, aChildBounds); - continue; + if (reflowAll || + (kidFrame->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) || + FrameDependsOnContainer(kidFrame, aCBWidthChanged, aCBHeightChanged)) { + // Reflow the frame + nsReflowStatus kidStatus; + ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState, aContainingBlockWidth, + aContainingBlockHeight, kidFrame, kidStatus); + } - nsReflowReason reason = reflowState.reason; - - nsFrameState kidState = kidFrame->GetStateBits(); - if (NS_FRAME_FIRST_REFLOW & kidState) { - // The frame has never had a reflow, so change the reason to eReflowReason_Initial - reason = eReflowReason_Initial; - - } else if (NS_FRAME_IS_DIRTY & kidState) { - // The frame is dirty so give it the correct reflow reason - reason = eReflowReason_Dirty; - } - - // Reflow the frame - nsReflowStatus kidStatus; - ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, reflowState, aContainingBlockWidth, - aContainingBlockHeight, kidFrame, reason, kidStatus); - AddFrameToChildBounds(kidFrame, aChildBounds); } return NS_OK; } -void -nsAbsoluteContainingBlock::CalculateChildBounds(nsPresContext* aPresContext, - nsRect& aChildBounds) -{ - // Initialize the OUT parameters - aChildBounds.SetRect(0, 0, 0, 0); - - for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f = f->GetNextSibling()) { - AddFrameToChildBounds(f, &aChildBounds); - } -} - -PRBool -nsAbsoluteContainingBlock::ReflowingAbsolutesOnly(nsIFrame* aDelegatingFrame, - const nsHTMLReflowState& aReflowState) -{ - // See if the reflow command is targeted at us. - nsReflowPath *path = aReflowState.path; - nsHTMLReflowCommand *command = path->mReflowCommand; - - if (command) { - // It's targeted at us. See if it's for the positioned child frames - if (GetChildListName() != command->GetChildListName()) { - // A reflow command is targeted directly at this block. - // The block will have to do a proper reflow. - return PR_FALSE; - } - } - - nsReflowPath::iterator iter = path->FirstChild(); - nsReflowPath::iterator end = path->EndChildren(); - - if (iter != end && mAbsoluteFrames.NotEmpty()) { - for ( ; iter != end; ++iter) { - // See if it's one of our absolutely positioned child frames - if (!mAbsoluteFrames.ContainsFrame(*iter)) { - // At least one of the frames along the reflow path wasn't - // absolutely positioned, so we'll need to deal with it in - // normal block reflow. - return PR_FALSE; - } - } - } - - return PR_TRUE; -} - static PRBool IsFixedPaddingSize(nsStyleUnit aUnit) { return aUnit == eStyleUnit_Coord || aUnit == eStyleUnit_Null; } @@ -364,69 +294,6 @@ nsAbsoluteContainingBlock::FrameDependsOnContainer(nsIFrame* f, return PR_FALSE; } -void -nsAbsoluteContainingBlock::IncrementalReflow(nsIFrame* aDelegatingFrame, - nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nscoord aContainingBlockWidth, - nscoord aContainingBlockHeight) -{ - // See if the reflow command is targeted at us. - nsReflowPath *path = aReflowState.path; - nsHTMLReflowCommand *command = path->mReflowCommand; - - if (command) { - // It's targeted at us. See if it's for the positioned child frames - if (GetChildListName() == command->GetChildListName()) { - // The only type of reflow command we expect is that we have dirty - // child frames to reflow - NS_ASSERTION(command->Type() == eReflowType_ReflowDirty, - "unexpected reflow type"); - - // Walk the positioned frames and reflow the dirty frames - for (nsIFrame* f = mAbsoluteFrames.FirstChild(); f; f = f->GetNextSibling()) { - nsFrameState frameState = f->GetStateBits(); - - if (frameState & NS_FRAME_IS_DIRTY) { - nsReflowStatus status; - nsReflowReason reason; - - reason = (frameState & NS_FRAME_FIRST_REFLOW) - ? eReflowReason_Initial - : eReflowReason_Dirty; - - ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState, - aContainingBlockWidth, aContainingBlockHeight, f, - reason, status); - } - } - } - } - - nsReflowPath::iterator iter = path->FirstChild(); - nsReflowPath::iterator end = path->EndChildren(); - - if (iter != end && mAbsoluteFrames.NotEmpty()) { - for ( ; iter != end; ++iter) { - // See if it's one of our absolutely positioned child frames - if (mAbsoluteFrames.ContainsFrame(*iter)) { - // Remove the next frame from the reflow path - nsReflowStatus kidStatus; - ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState, - aContainingBlockWidth, aContainingBlockHeight, *iter, - aReflowState.reason, kidStatus); - - // We don't need to invalidate anything because the frame - // should invalidate any area within its frame that needs - // repainting, and because it has a view if it changes size - // the view manager will damage the dirty area - - aReflowState.path->Remove(iter); - } - } - } -} - void nsAbsoluteContainingBlock::DestroyFrames(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext) @@ -449,7 +316,6 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, nsIFrame* aKidFrame, - nsReflowReason aReason, nsReflowStatus& aStatus) { #ifdef DEBUG @@ -464,16 +330,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat printf("%s ", NS_LossyConvertUCS2toASCII(name).get()); } } - printf("r=%d",aReflowState.reason); - if (aReflowState.reason == eReflowReason_Incremental) { - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - - if (command) { - // We're the target. - printf("(%d)", command->Type()); - } - } char width[16]; char height[16]; PrettyUC(aReflowState.availableWidth, width); @@ -490,187 +347,110 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat // Get the border values const nsMargin& border = aReflowState.mStyleBorder->GetBorder(); - nscoord availWidth = aReflowState.mComputedWidth; - enum { NOT_SHRINK_TO_FIT, SHRINK_TO_FIT_AVAILWIDTH, SHRINK_TO_FIT_MEW }; - PRUint32 situation = NOT_SHRINK_TO_FIT; - while (1) { - nsHTMLReflowMetrics kidDesiredSize(nsnull); - if (situation == NOT_SHRINK_TO_FIT && - !(aKidFrame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT)) { - // CSS2.1 10.3.7 width:auto and at least one of left/right is auto... - const nsStylePosition* stylePosition = aKidFrame->GetStylePosition(); - if (eStyleUnit_Auto == stylePosition->mWidth.GetUnit() && - (eStyleUnit_Auto == stylePosition->mOffset.GetLeftUnit() || - eStyleUnit_Auto == stylePosition->mOffset.GetRightUnit())) { - situation = SHRINK_TO_FIT_AVAILWIDTH; - if (aContainingBlockWidth != -1) { - availWidth = aContainingBlockWidth; - } else { - availWidth = aReflowState.mComputedWidth; - } - kidDesiredSize.mComputeMEW = PR_TRUE; - } + nsHTMLReflowMetrics kidDesiredSize(nsnull); + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, + nsSize(aReflowState.mComputedWidth, + NS_UNCONSTRAINEDSIZE), + aContainingBlockWidth, + aContainingBlockHeight); + + // Send the WillReflow() notification and position the frame + aKidFrame->WillReflow(aPresContext); + + // XXXldb We can simplify this if we come up with a better way to + // position views. + nscoord x; + if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) { + // Just use the current x-offset + x = aKidFrame->GetPosition().x; + } else { + x = border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left; + } + aKidFrame->SetPosition(nsPoint(x, border.top + + kidReflowState.mComputedOffsets.top + + kidReflowState.mComputedMargin.top)); + + // Position its view, but don't bother it doing it now if we haven't + // yet determined the left offset + if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left) { + nsContainerFrame::PositionFrameView(aKidFrame); + } + + // Do the reflow + rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); + + // If we're solving for 'left' or 'top', then compute it now that we know the + // width/height + if ((NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) || + (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) { + if (-1 == aContainingBlockWidth) { + // Get the containing block width/height + kidReflowState.ComputeContainingBlockRectangle(aPresContext, + &aReflowState, + aContainingBlockWidth, + aContainingBlockHeight); } - nsSize availSize(availWidth, NS_UNCONSTRAINEDSIZE); - nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, - availSize, aContainingBlockWidth, - aContainingBlockHeight, - aReason); - - if (situation == SHRINK_TO_FIT_MEW) { - situation = NOT_SHRINK_TO_FIT; // This is the last reflow - kidReflowState.mComputedWidth = PR_MIN(availWidth, kidReflowState.mComputedMaxWidth); - if (kidReflowState.mComputedWidth < kidReflowState.mComputedMinWidth) { - kidReflowState.mComputedWidth = kidReflowState.mComputedMinWidth; - } - } else if (situation == SHRINK_TO_FIT_AVAILWIDTH) { - NS_ASSERTION(availWidth != NS_UNCONSTRAINEDSIZE, - "shrink-to-fit: expected a constrained available width"); - PRInt32 maxWidth = availWidth - - (kidReflowState.mComputedMargin.left + kidReflowState.mComputedBorderPadding.left + - kidReflowState.mComputedBorderPadding.right + kidReflowState.mComputedMargin.right); - if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right) { - maxWidth -= kidReflowState.mComputedOffsets.right; - } - if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left) { - maxWidth -= kidReflowState.mComputedOffsets.left; - } - // The following also takes care of maxWidth<0 - if (kidReflowState.mComputedMaxWidth > maxWidth) { - kidReflowState.mComputedMaxWidth = PR_MAX(maxWidth, kidReflowState.mComputedMinWidth); - } - } - - // Send the WillReflow() notification and position the frame - aKidFrame->WillReflow(aPresContext); - - // XXXldb We can simplify this if we come up with a better way to - // position views. - nscoord x; if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) { - // Just use the current x-offset - x = aKidFrame->GetPosition().x; - } else { - x = border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left; + NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right, + "Can't solve for both left and right"); + kidReflowState.mComputedOffsets.left = aContainingBlockWidth - + kidReflowState.mComputedOffsets.right - + kidReflowState.mComputedMargin.right - + kidDesiredSize.width - + kidReflowState.mComputedMargin.left; } - aKidFrame->SetPosition(nsPoint(x, border.top + - kidReflowState.mComputedOffsets.top + - kidReflowState.mComputedMargin.top)); - - // Position its view, but don't bother it doing it now if we haven't - // yet determined the left offset - if (NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left) { - nsContainerFrame::PositionFrameView(aKidFrame); + if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top) { + kidReflowState.mComputedOffsets.top = aContainingBlockHeight - + kidReflowState.mComputedOffsets.bottom - + kidReflowState.mComputedMargin.bottom - + kidDesiredSize.height - + kidReflowState.mComputedMargin.top; } + } - // Do the reflow - rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus); + // Position the child relative to our padding edge + nsRect rect(border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left, + border.top + kidReflowState.mComputedOffsets.top + kidReflowState.mComputedMargin.top, + kidDesiredSize.width, kidDesiredSize.height); + aKidFrame->SetRect(rect); - if (situation == SHRINK_TO_FIT_AVAILWIDTH) { - // ...continued CSS2.1 10.3.7 width:auto and at least one of left/right is auto - availWidth -= kidReflowState.mComputedMargin.left + kidReflowState.mComputedMargin.right; + // Size and position the view and set its opacity, visibility, content + // transparency, and clip + nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, + aKidFrame->GetView(), + &kidDesiredSize.mOverflowArea); + aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED); - if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.right) { - NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.left, - "Can't solve for both left and right"); - availWidth -= kidReflowState.mComputedOffsets.left; - } else { - NS_ASSERTION(NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left, - "Expected to solve for left"); - availWidth -= kidReflowState.mComputedOffsets.right; - } - if (availWidth < 0) { - availWidth = 0; - } + // If the frame has visible overflow, then store it as a property on the + // frame. This allows us to be able to recover it without having to reflow + // the frame + if (aKidFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { + // Get the property (creating a rect struct if necessary) + nsRect* overflowArea = aKidFrame->GetOverflowAreaProperty(PR_TRUE); - // Shrink-to-fit: min(max(preferred minimum width, available width), preferred width). - // XXX this is not completely correct - see bug 201897 comment 56/58 and bug 268499. - if (kidDesiredSize.mMaxElementWidth > availWidth) { - aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED); - availWidth = PR_MAX(0, kidDesiredSize.mMaxElementWidth - - kidReflowState.mComputedBorderPadding.left - - kidReflowState.mComputedBorderPadding.right); - situation = SHRINK_TO_FIT_MEW; - aReason = eReflowReason_Resize; - continue; // Do a second reflow constrained to MEW. - } - } - - // If we're solving for 'left' or 'top', then compute it now that we know the - // width/height - if ((NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) || - (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) { - if (-1 == aContainingBlockWidth) { - // Get the containing block width/height - kidReflowState.ComputeContainingBlockRectangle(aPresContext, - &aReflowState, - aContainingBlockWidth, - aContainingBlockHeight); - } - - if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) { - NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.mComputedOffsets.right, - "Can't solve for both left and right"); - kidReflowState.mComputedOffsets.left = aContainingBlockWidth - - kidReflowState.mComputedOffsets.right - - kidReflowState.mComputedMargin.right - - kidDesiredSize.width - - kidReflowState.mComputedMargin.left; - } - if (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top) { - kidReflowState.mComputedOffsets.top = aContainingBlockHeight - - kidReflowState.mComputedOffsets.bottom - - kidReflowState.mComputedMargin.bottom - - kidDesiredSize.height - - kidReflowState.mComputedMargin.top; - } - } - - // Position the child relative to our padding edge - nsRect rect(border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left, - border.top + kidReflowState.mComputedOffsets.top + kidReflowState.mComputedMargin.top, - kidDesiredSize.width, kidDesiredSize.height); - aKidFrame->SetRect(rect); - - // Size and position the view and set its opacity, visibility, content - // transparency, and clip - nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, - aKidFrame->GetView(), - &kidDesiredSize.mOverflowArea); - aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED); - - // If the frame has visible overflow, then store it as a property on the - // frame. This allows us to be able to recover it without having to reflow - // the frame - if (aKidFrame->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) { - // Get the property (creating a rect struct if necessary) - nsRect* overflowArea = aKidFrame->GetOverflowAreaProperty(PR_TRUE); - - NS_ASSERTION(overflowArea, "should have created rect"); - if (overflowArea) { - *overflowArea = kidDesiredSize.mOverflowArea; - } + NS_ASSERTION(overflowArea, "should have created rect"); + if (overflowArea) { + *overflowArea = kidDesiredSize.mOverflowArea; } + } #ifdef DEBUG - if (nsBlockFrame::gNoisyReflow) { - nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); - printf("abs pos "); - if (nsnull != aKidFrame) { - nsIFrameDebug* frameDebug; - if (NS_SUCCEEDED(CallQueryInterface(aKidFrame, &frameDebug))) { - nsAutoString name; - frameDebug->GetFrameName(name); - printf("%s ", NS_LossyConvertUCS2toASCII(name).get()); - } + if (nsBlockFrame::gNoisyReflow) { + nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); + printf("abs pos "); + if (nsnull != aKidFrame) { + nsIFrameDebug* frameDebug; + if (NS_SUCCEEDED(CallQueryInterface(aKidFrame, &frameDebug))) { + nsAutoString name; + frameDebug->GetFrameName(name); + printf("%s ", NS_LossyConvertUCS2toASCII(name).get()); } - printf("%p rect=%d,%d,%d,%d", aKidFrame, rect.x, rect.y, rect.width, rect.height); - printf("\n"); } + printf("%p rect=%d,%d,%d,%d", aKidFrame, rect.x, rect.y, rect.width, rect.height); + printf("\n"); + } #endif - break; - } return rv; } diff --git a/mozilla/layout/generic/nsAbsoluteContainingBlock.h b/mozilla/layout/generic/nsAbsoluteContainingBlock.h index 376115c6345..6ed21e0b8a8 100644 --- a/mozilla/layout/generic/nsAbsoluteContainingBlock.h +++ b/mozilla/layout/generic/nsAbsoluteContainingBlock.h @@ -100,34 +100,20 @@ public: // placeholders for positioning and on whether the containing block // width or height changed. nsresult Reflow(nsIFrame* aDelegatingFrame, - nsPresContext* aPresContext, + nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, - nsRect* aChildBounds = nsnull, - PRBool aForceReflow = PR_TRUE, - PRBool aCBWidthChanged = PR_TRUE, - PRBool aCBHeightChanged = PR_TRUE); + PRBool aCBWidthChanged, + PRBool aCBHeightChanged, + nsRect* aChildBounds = nsnull); - // Called by the delegating frame to determine whether the - // incremental reflow is entirely targeted at absolute children - PRBool ReflowingAbsolutesOnly(nsIFrame* aDelegatingFrame, - const nsHTMLReflowState& aReflowState); - - // Called only for a reflow reason of eReflowReason_Incremental. - void IncrementalReflow(nsIFrame* aDelegatingFrame, - nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nscoord aContainingBlockWidth, - nscoord aContainingBlockHeight); void DestroyFrames(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext); PRBool HasAbsoluteFrames() {return mAbsoluteFrames.NotEmpty();} - void CalculateChildBounds(nsPresContext* aPresContext, nsRect& aChildBounds); - protected: // Returns PR_TRUE if the position of f depends on the position of // its placeholder or if the position or size of f depends on a @@ -141,7 +127,6 @@ protected: nscoord aContainingBlockWidth, nscoord aContainingBlockHeight, nsIFrame* aKidFrame, - nsReflowReason aReason, nsReflowStatus& aStatus); protected: diff --git a/mozilla/layout/generic/nsBRFrame.cpp b/mozilla/layout/generic/nsBRFrame.cpp index 740ae30834f..3539eebbc81 100644 --- a/mozilla/layout/generic/nsBRFrame.cpp +++ b/mozilla/layout/generic/nsBRFrame.cpp @@ -75,6 +75,12 @@ public: nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); virtual nsIAtom* GetType() const; protected: virtual ~BRFrame(); @@ -124,11 +130,8 @@ BRFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("BRFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("BRFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = 0; - } aMetrics.height = 0; // BR frames with height 0 are ignored in quirks // mode by nsLineLayout::VerticalAlignFrames . // However, it's not always 0. See below. @@ -188,11 +191,6 @@ BRFrame::Reflow(nsPresContext* aPresContext, // Warning: nsTextControlFrame::CalculateSizeStandard depends on // the following line, see bug 228752. aMetrics.width = 1; - - // Update max-element-width to keep us honest - if (aMetrics.mComputeMEW && aMetrics.width > aMetrics.mMaxElementWidth) { - aMetrics.mMaxElementWidth = aMetrics.width; - } } // Return our reflow status @@ -213,6 +211,36 @@ BRFrame::Reflow(nsPresContext* aPresContext, return NS_OK; } +/* virtual */ void +BRFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlineMinWidthData *aData) +{ + aData->Break(aRenderingContext); +} + +/* virtual */ void +BRFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlinePrefWidthData *aData) +{ + aData->Break(aRenderingContext); +} + +/* virtual */ nscoord +BRFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result = 0; + DISPLAY_MIN_WIDTH(this, result); + return result; +} + +/* virtual */ nscoord +BRFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result = 0; + DISPLAY_PREF_WIDTH(this, result); + return result; +} + nsIAtom* BRFrame::GetType() const { diff --git a/mozilla/layout/generic/nsBlockDebugFlags.h b/mozilla/layout/generic/nsBlockDebugFlags.h index 969889dc03d..c6ccbda85ad 100644 --- a/mozilla/layout/generic/nsBlockDebugFlags.h +++ b/mozilla/layout/generic/nsBlockDebugFlags.h @@ -43,7 +43,6 @@ #undef NOISY_FIRST_LETTER // enables debug output for first-letter specific layout #undef NOISY_MAX_ELEMENT_SIZE // enables debug output for max element size computation #undef NOISY_MAXIMUM_WIDTH // enables debug output for max width computation -#undef NOISY_KIDXMOST // enables debug output for aState.mKidXMost computation #undef NOISY_FLOAT // enables debug output for float reflow (the in/out metrics for the floated block) #undef NOISY_FLOAT_CLEARING #undef NOISY_FINAL_SIZE // enables debug output for desired width/height computation, once all children have been reflowed diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 42ad9764368..bc79a1d37fc 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -54,7 +54,6 @@ #include "nsFrameManager.h" #include "nsPresContext.h" #include "nsIPresShell.h" -#include "nsReflowPath.h" #include "nsStyleContext.h" #include "nsIView.h" #include "nsIFontMetrics.h" @@ -97,7 +96,7 @@ PRBool nsBlockFrame::gLamePaintMetrics; PRBool nsBlockFrame::gLameReflowMetrics; PRBool nsBlockFrame::gNoisy; PRBool nsBlockFrame::gNoisyDamageRepair; -PRBool nsBlockFrame::gNoisyMaxElementWidth; +PRBool nsBlockFrame::gNoisyIntrinsic; PRBool nsBlockFrame::gNoisyReflow; PRBool nsBlockFrame::gReallyNoisyReflow; PRBool nsBlockFrame::gNoisySpaceManager; @@ -114,7 +113,7 @@ struct BlockDebugFlags { static const BlockDebugFlags gFlags[] = { { "reflow", &nsBlockFrame::gNoisyReflow }, { "really-noisy-reflow", &nsBlockFrame::gReallyNoisyReflow }, - { "max-element-width", &nsBlockFrame::gNoisyMaxElementWidth }, + { "intrinsic", &nsBlockFrame::gNoisyIntrinsic }, { "space-manager", &nsBlockFrame::gNoisySpaceManager }, { "verify-lines", &nsBlockFrame::gVerifyLines }, { "damage-repair", &nsBlockFrame::gNoisyDamageRepair }, @@ -275,6 +274,8 @@ NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags } nsBlockFrame::nsBlockFrame() + : mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN) + , mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN) { #ifdef DEBUG InitDebugFlags(); @@ -569,6 +570,133 @@ static void ReparentFrame(nsIFrame* aFrame, nsIFrame* aOldParent, ////////////////////////////////////////////////////////////////////// // Reflow methods +#define LINE_REFLOW_OK 0 +#define LINE_REFLOW_STOP 1 +#define LINE_REFLOW_REDO 2 +// a frame was complete, but truncated and not at the top of a page +#define LINE_REFLOW_TRUNCATED 3 + +/* virtual */ void +nsBlockFrame::MarkIntrinsicWidthsDirty() +{ + mMinWidth = NS_INTRINSIC_WIDTH_UNKNOWN; + mPrefWidth = NS_INTRINSIC_WIDTH_UNKNOWN; +} + +/* virtual */ nscoord +nsBlockFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + DISPLAY_MIN_WIDTH(this, mMinWidth); + if (mMinWidth != NS_INTRINSIC_WIDTH_UNKNOWN) + return mMinWidth; + +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + ListTag(stdout); + printf(": GetMinWidth\n"); + } + AutoNoisyIndenter indent(gNoisyIntrinsic); +#endif + + PRInt32 lineNumber = 0; + InlineMinWidthData data; + for (line_iterator line = begin_lines(), line_end = end_lines(); + line != line_end; ++line, ++lineNumber) + { +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + printf("line %d (%s%s)\n", lineNumber, + line->IsBlock() ? "block" : "inline", + line->IsEmpty() ? ",empty" : ""); + } + AutoNoisyIndenter lineindent(gNoisyIntrinsic); +#endif + if (line->IsBlock()) { + data.Break(aRenderingContext); + data.currentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + line->mFirstChild, nsLayoutUtils::MIN_WIDTH); + data.Break(aRenderingContext); + } else { + + nsIFrame *kid = line->mFirstChild; + for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end; + ++i, kid = kid->GetNextSibling()) { + kid->AddInlineMinWidth(aRenderingContext, &data); + } + } +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + printf("min: [prevLines=%d currentLine=%d]\n", + data.prevLines, data.currentLine); + } +#endif + } + data.Break(aRenderingContext); + + mMinWidth = data.prevLines; + return mMinWidth; +} + +/* virtual */ nscoord +nsBlockFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + DISPLAY_PREF_WIDTH(this, mPrefWidth); + if (mPrefWidth != NS_INTRINSIC_WIDTH_UNKNOWN) + return mPrefWidth; + +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + ListTag(stdout); + printf(": GetPrefWidth\n"); + } + AutoNoisyIndenter indent(gNoisyIntrinsic); +#endif + + PRInt32 lineNumber = 0; + InlinePrefWidthData data; + for (line_iterator line = begin_lines(), line_end = end_lines(); + line != line_end; ++line, ++lineNumber) + { +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + printf("line %d (%s%s)\n", lineNumber, + line->IsBlock() ? "block" : "inline", + line->IsEmpty() ? ",empty" : ""); + } + AutoNoisyIndenter lineindent(gNoisyIntrinsic); +#endif + if (line->IsBlock()) { + data.Break(aRenderingContext); + data.currentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + line->mFirstChild, nsLayoutUtils::PREF_WIDTH); + data.Break(aRenderingContext); + } else { + + nsIFrame *kid = line->mFirstChild; + for (PRInt32 i = 0, i_end = line->GetChildCount(); i != i_end; + ++i, kid = kid->GetNextSibling()) { + kid->AddInlinePrefWidth(aRenderingContext, &data); + } + } +#ifdef DEBUG + if (gNoisyIntrinsic) { + IndentBy(stdout, gNoiseIndent); + printf("pref: [prevLines=%d currentLine=%d]\n", + data.prevLines, data.currentLine); + } +#endif + } + data.Break(aRenderingContext); + + mPrefWidth = data.prevLines; + return mPrefWidth; +} + static nsSize CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState, nsSize aFrameSize) @@ -630,30 +758,13 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsBlockFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsBlockFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); #ifdef DEBUG if (gNoisyReflow) { - nsCAutoString reflow; - reflow.Append(nsHTMLReflowState::ReasonToString(aReflowState.reason)); - - if (aReflowState.reason == eReflowReason_Incremental) { - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - - if (command) { - // We're the target. - reflow += " ("; - - reflow += kReflowCommandType[command->Type()]; - - reflow += ")"; - } - } - IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin %s reflow availSize=%d,%d computedSize=%d,%d\n", - reflow.get(), + printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } @@ -678,55 +789,6 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, if (NS_BLOCK_SPACE_MGR & mState) autoSpaceManager.CreateSpaceManagerFor(aPresContext, this); - // See if it's an incremental reflow command targeted only at - // absolute frames and we can skip ReflowDirtyLines(). - PRBool needToReflowLines = aMetrics.mComputeMEW || - // If we have lines with clearance, and the space manager already has - // floats, we need to check the positions of our lines with clearance - ((GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN) && - aReflowState.mSpaceManager->HasAnyFloats()) || - // The areas of any floats in this block or in blocks under us - // need to be put into the space manager --- unless we are our own - // space manager, in which case it doesn't matter. - !(GetStateBits() & NS_BLOCK_SPACE_MGR); - - if (mAbsoluteContainer.HasAbsoluteFrames() && - eReflowReason_Incremental == aReflowState.reason && - !needToReflowLines && - mAbsoluteContainer.ReflowingAbsolutesOnly(this, aReflowState)) { - nsSize containingBlockSize - = CalculateContainingBlockSizeForAbsolutes(aReflowState, GetSize()); - - mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, - containingBlockSize.width, - containingBlockSize.height); - - // Just return our current size as our desired size. - aMetrics.width = mRect.width; - aMetrics.height = mRect.height; - - // XXXbernd this should be revised when inline-blocks are implemented - if (GetFirstChild(nsnull)) - aMetrics.ascent = mAscent; - else - aMetrics.ascent = aMetrics.height; - - aMetrics.descent = aMetrics.height - aMetrics.ascent; - - // Whether or not we're complete hasn't changed - aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; - - // Factor the absolutely positioned child bounds into the overflow area - ComputeCombinedArea(aReflowState, aMetrics); - nsRect childBounds; - mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); - aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); - - FinishAndStoreOverflow(&aMetrics); - - return NS_OK; - } - // OK, some lines may be reflowed. Blow away any saved line cursor because // we may invalidate the nondecreasing combinedArea.y/yMost invariant, // and we may even delete the line with the line cursor. @@ -750,39 +812,33 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, (NS_BLOCK_MARGIN_ROOT & mState), (NS_BLOCK_MARGIN_ROOT & mState)); - // The condition for doing Bidi resolutions includes a test for the - // dirtiness flags, because blocks sometimes send a resize reflow - // even though they have dirty children, An example where this can - // occur is when adding lines to a text control (bugs 95228 and 95400 - // were caused by not doing Bidi resolution in these cases) - if (eReflowReason_Resize != aReflowState.reason || - mState & NS_FRAME_IS_DIRTY || mState & NS_FRAME_HAS_DIRTY_CHILDREN) { #ifdef IBMBIDI - if (! mLines.empty()) { - if (aPresContext->BidiEnabled()) { - nsBidiPresUtils* bidiUtils = aPresContext->GetBidiUtils(); - if (bidiUtils) { - PRBool forceReflow; - nsresult rc = bidiUtils->Resolve(aPresContext, this, - mLines.front()->mFirstChild, - forceReflow, - aReflowState.mFlags.mVisualBidiFormControl); - if (NS_SUCCEEDED(rc) && forceReflow) { - // Mark everything dirty - // XXXldb This should be done right. - for (line_iterator line = begin_lines(), line_end = end_lines(); - line != line_end; - ++line) - { - line->MarkDirty(); - } + // XXXldb Could this happen at frame construction time? + if (! mLines.empty()) { + if (aPresContext->BidiEnabled()) { + nsBidiPresUtils* bidiUtils = aPresContext->GetBidiUtils(); + if (bidiUtils) { + PRBool forceReflow; + nsresult rc = bidiUtils->Resolve(aPresContext, this, + mLines.front()->mFirstChild, + forceReflow, + aReflowState.mFlags.mVisualBidiFormControl); + if (NS_SUCCEEDED(rc) && forceReflow) { + // Mark everything dirty + // XXXldb This should be done right. + for (line_iterator line = begin_lines(), line_end = end_lines(); + line != line_end; + ++line) + { + line->MarkDirty(); } } } } -#endif // IBMBIDI - RenumberLists(aPresContext); } +#endif // IBMBIDI + + RenumberLists(aPresContext); nsresult rv = NS_OK; @@ -791,99 +847,22 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, // overflow line lists being cleared out between reflow passes. DrainOverflowLines(state); - switch (aReflowState.reason) { - case eReflowReason_Initial: -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": reflow=initial\n"); -#endif - rv = PrepareInitialReflow(state); - mState &= ~NS_FRAME_FIRST_REFLOW; - break; + // If we're not dirty (which means we'll mark everything dirty later) + // and our width has changed, mark the lines dirty that we need to + // mark dirty for a resize reflow. + if (aReflowState.mFlags.mIsResize) + PrepareResizeReflow(state); - case eReflowReason_Dirty: - // Do nothing; the dirty lines will already have been marked. - break; - - case eReflowReason_Incremental: { -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": reflow=incremental "); -#endif - nsReflowPath *path = aReflowState.path; - nsHTMLReflowCommand *command = path->mReflowCommand; - if (command) { -#ifdef NOISY_REFLOW_REASON - printf("type=%s ", kReflowCommandType[command->Type()]); -#endif - switch (command->Type()) { - case eReflowType_StyleChanged: - rv = PrepareStyleChangedReflow(state); - break; - case eReflowType_ReflowDirty: - // Do nothing; the dirty lines will already have been marked. - break; - case eReflowType_ContentChanged: - // Perform a full reflow. - rv = PrepareResizeReflow(state); - break; - default: - // We shouldn't get here. But, if we do, perform a full reflow. - NS_ERROR("unexpected reflow type"); - rv = PrepareResizeReflow(state); - break; - } - } - - if (path->FirstChild() != path->EndChildren()) { - // We're along the reflow path, but not necessarily the target - // of the reflow. -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(" next={ "); - - for (nsReflowPath::iterator iter = path->FirstChild(); - iter != path->EndChildren(); - ++iter) { - nsFrame::ListTag(stdout, *iter); - printf(" "); - } - - printf("}"); -#endif - - rv = PrepareChildIncrementalReflow(state); - } - -#ifdef NOISY_REFLOW_REASON - printf("\n"); -#endif - - break; - } - - case eReflowReason_StyleChange: - rv = PrepareStyleChangedReflow(state); - break; - - case eReflowReason_Resize: - default: -#ifdef NOISY_REFLOW_REASON - ListTag(stdout); - printf(": reflow=resize (%d)\n", aReflowState.reason); -#endif - rv = PrepareResizeReflow(state); - break; - } - - NS_ASSERTION(NS_SUCCEEDED(rv), "setting up reflow failed"); - if (NS_FAILED(rv)) return rv; + mState &= ~NS_FRAME_FIRST_REFLOW; // Now reflow... - rv = ReflowDirtyLines(state, PR_TRUE); + PRBool didSomething; + rv = ReflowDirtyLines(state, &didSomething); NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; + didSomething |= (GetStateBits() & NS_FRAME_IS_DIRTY) != 0; + // If the block is complete, put continuted floats in the closest ancestor // block that uses the same space manager and leave the block complete; this // allows subsequent lines on the page to be impacted by floats. If the @@ -969,14 +948,25 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, } } - // XXX_perf get rid of this! This is one of the things that makes - // incremental reflow O(N^2). - BuildFloatList(state); + if (didSomething) { + // XXX_perf get rid of this! This is one of the things that makes + // incremental reflow O(N^2). + BuildFloatList(state); - // Compute our final size - ComputeFinalSize(aReflowState, state, aMetrics); - nsRect currentOverflow = aMetrics.mOverflowArea; - FinishAndStoreOverflow(&aMetrics); + // Compute our final size + ComputeFinalSize(aReflowState, state, aMetrics); + } else { + // Just return our current size as our desired size. + aMetrics.width = mRect.width; + aMetrics.height = mRect.height; + aMetrics.ascent = mAscent; + aMetrics.descent = aMetrics.height - aMetrics.ascent; + + // Whether or not we're complete hasn't changed + aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; + } + + ComputeCombinedArea(aReflowState, aMetrics); // see if verifyReflow is enabled, and if so store off the space manager pointer #ifdef DEBUG @@ -1012,52 +1002,34 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, = CalculateContainingBlockSizeForAbsolutes(aReflowState, nsSize(aMetrics.width, aMetrics.height)); - PRBool forceAbsoluteReflow = PR_TRUE; - PRBool cbWidthChanged = PR_TRUE; - PRBool cbHeightChanged = PR_TRUE; - if (eReflowReason_Incremental == aReflowState.reason) { - // Do the incremental reflows ... would be nice to merge with - // the reflows below but that would be more work, and more risky - mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, - containingBlockSize.width, - containingBlockSize.height); - - // If a reflow was targeted at this block then we'd better - // reflow the absolutes. For example the borders and padding - // might have changed in a way that leaves the frame size the - // same but the padding edge has moved. - if (!aReflowState.path->mReflowCommand) { - // We don't have to force reflow of all the absolutes. - forceAbsoluteReflow = PR_FALSE; - - // We need to reflow those absolutes that depend on their - // placeholder position, or the containing block size in a - // direction in which the containing block size might have - // changed. So figure out whether our size changed. - cbWidthChanged = aMetrics.width != oldSize.width; - PRBool isRoot = !GetContent()->GetParent(); - // If isRoot and we have auto height, then we are the initial - // containing block and the containing block height is the - // viewport height, which can't change during incremental - // reflow. - cbHeightChanged = isRoot && NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight - ? PR_FALSE : aMetrics.height != oldSize.height; - } - } + // Mark frames that depend on changes we just made to this frame as dirty: + // Now we can assume that the padding edge hasn't moved. + // We need to reflow the absolutes if one of them depends on + // its placeholder position, or the containing block size in a + // direction in which the containing block size might have + // changed. + PRBool cbWidthChanged = aMetrics.width != oldSize.width; + PRBool isRoot = !GetContent()->GetParent(); + // If isRoot and we have auto height, then we are the initial + // containing block and the containing block height is the + // viewport height, which can't change during incremental + // reflow. + PRBool cbHeightChanged = + !(isRoot && NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) && + aMetrics.height != oldSize.height; rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, containingBlockSize.width, containingBlockSize.height, - &childBounds, - forceAbsoluteReflow, - cbWidthChanged, - cbHeightChanged); + cbWidthChanged, cbHeightChanged, + &childBounds); // Factor the absolutely positioned child bounds into the overflow area - aMetrics.mOverflowArea.UnionRect(currentOverflow, childBounds); - FinishAndStoreOverflow(&aMetrics); + aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); } + FinishAndStoreOverflow(&aMetrics); + // Determine if we need to repaint our border, background or outline CheckInvalidateSizeChange(aPresContext, aMetrics, aReflowState); @@ -1084,9 +1056,6 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, aMetrics.mOverflowArea.width, aMetrics.mOverflowArea.height); } - if (aMetrics.mComputeMEW) { - printf(" maxElementWidth=%d", aMetrics.mMaxElementWidth); - } printf("\n"); } @@ -1108,27 +1077,12 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, delta, perLineDelta, numLines, ectc - ctc); printf("%s\n", buf); } - if (gNoisyMaxElementWidth) { - if (aMetrics.mComputeMEW) { - IndentBy(stdout, gNoiseIndent); - printf("block %p returning with maxElementWidth=%d\n", - NS_STATIC_CAST(void*, this), - aMetrics.mMaxElementWidth); - } - } #endif NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return rv; } -static PRBool -HaveAutoWidth(const nsHTMLReflowState& aReflowState) -{ - return NS_UNCONSTRAINEDSIZE == aReflowState.mComputedWidth || - eStyleUnit_Auto == aReflowState.mStylePosition->mWidth.GetUnit(); -} - // XXXldb why do we check vertical and horizontal at the same time? Don't // we usually care about one or the other? @@ -1199,122 +1153,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, borderPadding.top, borderPadding.bottom); #endif - // XXXldb Handling min-width/max-width stuff after reflowing children - // seems wrong. But IIRC this function only does more than a little - // bit in rare cases (or something like that, I'm not really sure). - // What are those cases, and do we get the wrong behavior? - // Compute final width - nscoord maxElementWidth = 0; -#ifdef NOISY_KIDXMOST - printf("%p aState.mKidXMost=%d\n", this, aState.mKidXMost); -#endif - if (!HaveAutoWidth(aReflowState)) { - // Use style defined width - aMetrics.width = borderPadding.left + aReflowState.mComputedWidth + - borderPadding.right; - - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - if (GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Percent) { - // for percentage widths, |HaveAutoWidth| is sometimes true and - // sometimes false (XXXldb check that this is really true), and - // we want the max-element-width to be the same either way - // (i.e., whether it's an uncontsrained reflow or a fixed-width - // reflow). Thus, do the same thing we do below. - maxElementWidth = aState.mMaxElementWidth + - borderPadding.left + borderPadding.right; - } else { - // When style defines the width use it for the max-element-width - // because we can't shrink any smaller. - maxElementWidth = aMetrics.width; - } - } - } - else { - nscoord computedWidth; - - // XXX Misleading comment: - // There are two options here. We either shrink wrap around our - // contents or we fluff out to the maximum block width. Note: - // We always shrink wrap when given an unconstrained width. - if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) && - !aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && - !aState.GetFlag(BRS_SHRINKWRAPWIDTH)) { - // XXX Misleading comment: - // Set our width to the max width if we aren't already that - // wide. Note that the max-width has nothing to do with our - // contents (CSS2 section XXX) - // XXXldb In what cases do we reach this code? - computedWidth = borderPadding.left + aState.mContentArea.width + - borderPadding.right; - } else { - computedWidth = aState.mKidXMost; - if (NS_BLOCK_SPACE_MGR & mState) { - // Include the space manager's state to properly account for the - // extent of floated elements. - nscoord xmost; - if (aReflowState.mSpaceManager->XMost(xmost) && - computedWidth < xmost) - computedWidth = xmost; - } - computedWidth += borderPadding.right; - } - - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - // Add in border and padding dimensions to already computed - // max-element-width values. - maxElementWidth = aState.mMaxElementWidth + - borderPadding.left + borderPadding.right; - } - - // Apply min/max values - computedWidth -= borderPadding.left + borderPadding.right; - aReflowState.ApplyMinMaxConstraints(&computedWidth, nsnull); - computedWidth += borderPadding.left + borderPadding.right; - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - nscoord computedMinWidth = aReflowState.mComputedMinWidth + - borderPadding.left + borderPadding.right; - if (maxElementWidth < computedMinWidth && - GetStylePosition()->mMinWidth.GetUnit() != eStyleUnit_Percent) { - maxElementWidth = computedMinWidth; - } - } - aMetrics.width = computedWidth; - - // If we're shrink wrapping, then now that we know our final width we - // need to do horizontal alignment of the inline lines and make sure - // blocks are correctly sized and positioned. Any lines that need - // final adjustment will have been marked as dirty - if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) { - // If the parent reflow state is also shrink wrap width, then - // we don't need to do this, because it will reflow us after it - // calculates the final width - const nsHTMLReflowState *prs = aReflowState.parentReflowState; - if (!prs || NS_SHRINKWRAPWIDTH != prs->mComputedWidth) { - // XXX Is this only used on things that are already NS_BLOCK_SPACE_MGR - // and NS_BLOCK_MARGIN_ROOT? - nsHTMLReflowState reflowState(aReflowState); - - reflowState.mComputedWidth = aMetrics.width - borderPadding.left - - borderPadding.right; - reflowState.reason = eReflowReason_Resize; - reflowState.mSpaceManager->ClearRegions(); - -#ifdef DEBUG - nscoord oldDesiredWidth = aMetrics.width; -#endif - nsBlockReflowState state(reflowState, aState.mPresContext, this, - aMetrics, - aReflowState.mFlags.mHasClearance || (NS_BLOCK_MARGIN_ROOT & mState), - (NS_BLOCK_MARGIN_ROOT & mState)); - // Don't try to pull up any new content from our next in flow. Shrinkwrapping - // shouldn't make us shorter anyway. - ReflowDirtyLines(state, PR_FALSE); - aState.mY = state.mY; - NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width"); - } - } - } + aMetrics.width = borderPadding.left + aReflowState.mComputedWidth + + borderPadding.right; // Return bottom margin information // rbs says he hit this assertion occasionally (see bug 86947), so @@ -1428,65 +1269,12 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, aMetrics.ascent = aMetrics.height; aMetrics.descent = aMetrics.height - aMetrics.ascent; - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - // Store away the final value - aMetrics.mMaxElementWidth = maxElementWidth; -#ifdef DEBUG - if (gNoisyMaxElementWidth) { - IndentBy(stdout, gNoiseIndent); - printf ("nsBlockFrame::CFS: %p returning MEW %d\n", - NS_STATIC_CAST(void*, this), aMetrics.mMaxElementWidth); - } -#endif - } - #ifdef DEBUG_blocks if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) { ListTag(stdout); printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height); } - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH) && - (maxElementWidth > aMetrics.width))) { - ListTag(stdout); - printf(": WARNING: max-element-width:%d desired:%d,%d maxSize:%d,%d\n", - maxElementWidth, aMetrics.width, aMetrics.height, - aState.mReflowState.availableWidth, - aState.mReflowState.availableHeight); - } #endif -#ifdef DEBUG - if (gNoisyMaxElementWidth) { - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - IndentBy(stdout, gNoiseIndent); - if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) { - printf("PASS1 "); - } - ListTag(stdout); - printf(": max-element-width:%d desired:%d,%d maxSize:%d,%d\n", - maxElementWidth, aMetrics.width, aMetrics.height, - aState.mReflowState.availableWidth, - aState.mReflowState.availableHeight); - } - } -#endif - - // If we're requested to update our maximum width, then compute it - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { - if (!HaveAutoWidth(aReflowState) && - aReflowState.mStylePosition->mWidth.GetUnit() != eStyleUnit_Percent) { - aMetrics.mMaximumWidth = aMetrics.width; - } else { - // We need to add in for the right border/padding - // The maximum width in the reflow state includes the left - // border/padding but not the right. - aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right; - } -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockFrame::ComputeFinalSize block %p setting aMetrics.mMaximumWidth to %d\n", this, aMetrics.mMaximumWidth); -#endif - } - - ComputeCombinedArea(aReflowState, aMetrics); } void @@ -1521,270 +1309,6 @@ nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState, aMetrics.mOverflowArea = area; } -nsresult -nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState) -{ - PrepareResizeReflow(aState); - return NS_OK; -} - -nsresult -nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState) -{ - // XXXwaterson this is non-optimal. We'd rather do this in - // ReflowDirtyLines; however, I'm not quite ready to figure out how - // to deal with reflow path retargeting yet. - nsReflowPath *path = aState.mReflowState.path; - - nsReflowPath::iterator iter = path->FirstChild(); - nsReflowPath::iterator end = path->EndChildren(); - - for ( ; iter != end; ++iter) { - // Determine the line being impacted - line_iterator line = FindLineFor(*iter); - if (line == end_lines()) { - // This assertion actually fires on lots of pages - // (e.g., bugzilla, bugzilla query page), so limit it - // to a few people until we fix the problem causing it. - // - // I think waterson explained once why it was happening -- I think - // it has something to do with the interaction of the unconstrained - // reflow in multi-pass reflow with the reflow command's chain, but - // I don't remember the details. -#if defined(DEBUG_dbaron) || defined(DEBUG_waterson) - NS_NOTREACHED("We don't have a line for the target of the reflow. " - "Being inefficient"); -#endif - // This can't happen, but just in case it does... - PrepareResizeReflow(aState); - continue; - } - - if (line->IsInline()) { - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { - // We've been asked to compute the maximum width of the block - // frame, which ReflowLine() will handle by performing an - // unconstrained reflow on the line. If this incremental - // reflow is targeted at a continuing frame, we may have to - // retarget it, as the unconstrained reflow can destroy some - // of the continuations. This will allow the incremental - // reflow to arrive at the target frame during the first-pass - // unconstrained reflow. - nsIFrame *prevInFlow = (*iter)->GetPrevInFlow(); - if (prevInFlow) - RetargetInlineIncrementalReflow(iter, line, prevInFlow); - } - } - - // Mark this line dirty. We need to mark the previous line dirty - // if it is an inline line so that it can maybe pull up something - // from the just affected line. - MarkLineDirty(line); - } - return NS_OK; -} - -void -nsBlockFrame::RetargetInlineIncrementalReflow(nsReflowPath::iterator &aTarget, - line_iterator &aLine, - nsIFrame *aPrevInFlow) -{ - // To retarget the reflow, we'll walk back through the continuations - // until we reach the primary frame, or we reach a continuation that - // is preceded by a ``hard'' line break. - NS_ASSERTION(aLine->Contains(*aTarget), - "line doesn't contain the target of the incremental reflow"); - - // Now fix the iterator, keeping track of how many lines we walk - // back through. - PRInt32 lineCount = 0; - do { - // XXX this might happen if the block is split; e.g., - // printing or print preview. For now, panic. - NS_ASSERTION(aLine != begin_lines(), - "ran out of lines before we ran out of prev-in-flows"); - - // Is the previous line a ``hard'' break? If so, stop: these - // continuations will be preserved during an unconstrained reflow. - // XXXwaterson should this be `!= NS_STYLE_CLEAR_NONE'? - --aLine; - if (aLine->GetBreakTypeAfter() == NS_STYLE_CLEAR_LINE) - break; - - *aTarget = aPrevInFlow; - aPrevInFlow = aPrevInFlow->GetPrevInFlow(); - -#ifdef DEBUG - // Paranoia. Ensure that the prev-in-flow is really in the - // previous line. - line_iterator check = FindLineFor(*aTarget); - NS_ASSERTION(check == aLine, "prev-in-flow not in previous linebox"); -#endif - - ++lineCount; - } while (aPrevInFlow); - - if (lineCount > 0) { - // Fix any frames deeper in the reflow path. -#if 0 - // XXXwaterson fix me! we've got to recurse through the iterator's - // kids. This really shouldn't matter unless we want to implement - // `display: inline-block' or do XBL form controls. Why, you ask? - // Because what will happen is that inline frames will get flowed - // with a resize reflow, which will be sufficient to mask any - // glitches that would otherwise occur. However, as soon as boxes - // or blocks end up in the flow here (and aren't explicit reflow - // roots), they may optimize away the resize reflow. - - // Get the reflow path, which is stored as a stack (i.e., the next - // frame in the reflow is at the _end_ of the array). - nsVoidArray *path = aState.mReflowState.reflowCommand->GetPath(); - - for (PRInt32 i = path->Count() - 1; i >= 0; --i) { - nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, path->ElementAt(i)); - - // Stop if we encounter a non-inline frame in the reflow path. - const nsStyleDisplay* display = frame->GetStyleDisplay(); - - if (NS_STYLE_DISPLAY_INLINE != display->mDisplay) - break; - - // Walk back to the primary frame. - PRInt32 count = lineCount; - nsIFrame *prevInFlow; - do { - prevInFlow = frame->GetPrevInFlow(); - } while (--count >= 0 && prevInFlow && (frame = prevInFlow)); - - path->ReplaceElementAt(frame, i); - } -#else - NS_WARNING("blowing an incremental reflow targeted at a nested inline"); -#endif - } -} - -nsresult -nsBlockFrame::MarkLineDirty(line_iterator aLine) -{ - // Mark aLine dirty - aLine->MarkDirty(); -#ifdef DEBUG - if (gNoisyReflow) { - IndentBy(stdout, gNoiseIndent); - ListTag(stdout); - printf(": mark line %p dirty\n", NS_STATIC_CAST(void*, aLine.get())); - } -#endif - - // Mark previous line dirty if its an inline line so that it can - // maybe pullup something from the line just affected. - // XXX We don't need to do this if aPrevLine ends in a break-after... - if (aLine != mLines.front() && - aLine->IsInline() && - aLine.prev()->IsInline()) { - aLine.prev()->MarkDirty(); -#ifdef DEBUG - if (gNoisyReflow) { - IndentBy(stdout, gNoiseIndent); - ListTag(stdout); - printf(": mark prev-line %p dirty\n", - NS_STATIC_CAST(void*, aLine.prev().get())); - } -#endif - } - - return NS_OK; -} - -nsresult -nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState) -{ - if (nsnull == mBullet) { - // Don't bother if there is no bullet - return NS_OK; - } - const nsStyleList* styleList = GetStyleList(); - if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) { - if (mBullet && HaveOutsideBullet()) { - // We now have an inside bullet, but used to have an outside - // bullet. Adjust the frame line list - if (! mLines.empty()) { - // if we have a line already, then move the bullet to the front of the - // first line - nsIFrame* child = nsnull; - nsLineBox* firstLine = mLines.front(); - - // bullet should not have any siblings if it was an outside bullet - NS_ASSERTION(!mBullet->GetNextSibling(), "outside bullet should not have siblings"); - - // move bullet to front and chain the previous frames, and update the line count - child = firstLine->mFirstChild; - firstLine->mFirstChild = mBullet; - mBullet->SetNextSibling(child); - PRInt32 count = firstLine->GetChildCount(); - firstLine->SetChildCount(count+1); - // dirty it here in case the caller does not - firstLine->MarkDirty(); - } else { - // no prior lines, just create a new line for the bullet - nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE); - if (!line) { - return NS_ERROR_OUT_OF_MEMORY; - } - mLines.push_back(line); - } - } - mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } - else { - if (!HaveOutsideBullet()) { - // We now have an outside bullet, but used to have an inside - // bullet. Take the bullet frame out of the first lines frame - // list. - if ((! mLines.empty()) && (mBullet == mLines.front()->mFirstChild)) { - nsIFrame* next = mBullet->GetNextSibling(); - mBullet->SetNextSibling(nsnull); - PRInt32 count = mLines.front()->GetChildCount() - 1; - NS_ASSERTION(count >= 0, "empty line w/o bullet"); - mLines.front()->SetChildCount(count); - if (0 == count) { - nsLineBox* oldFront = mLines.front(); - mLines.pop_front(); - aState.FreeLineBox(oldFront); - if (! mLines.empty()) { - mLines.front()->MarkDirty(); - } - } - else { - mLines.front()->mFirstChild = next; - mLines.front()->MarkDirty(); - } - } - } - mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET; - } -#ifdef DEBUG - VerifyLines(PR_TRUE); -#endif - return NS_OK; -} - -nsresult -nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState) -{ - nsresult rv = UpdateBulletPosition(aState); - - // Mark everything dirty - for (line_iterator line = begin_lines(), line_end = end_lines(); - line != line_end; - ++line) - { - line->MarkDirty(); - } - return rv; -} - nsresult nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) { @@ -1795,10 +1319,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // is impacted by a float (bug 19579) aState.GetAvailableSpace(); - // See if this is a constrained resize reflow that is not impacted by floats - if ((! aState.IsImpactedByFloat()) && - (aState.mReflowState.reason == eReflowReason_Resize) && - (NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) { + if ((! aState.IsImpactedByFloat())) { // If the text is left-aligned, then we try and avoid reflowing the lines const nsStyleText* styleText = GetStyleText(); @@ -1819,8 +1340,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) const nsStyleText* styleText = GetStyleText(); IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": marking all lines dirty: reason=%d availWidth=%d textAlign=%d\n", - aState.mReflowState.reason, + printf(": marking all lines dirty: availWidth=%d textAlign=%d\n", aState.mReflowState.availableWidth, styleText->mTextAlign); } @@ -1828,24 +1348,11 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) #endif if (tryAndSkipLines) { - nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left; - - if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) { - if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedMaxWidth) { - newAvailWidth += aState.mReflowState.mComputedMaxWidth; - } - else { - newAvailWidth += aState.mReflowState.availableWidth; - } - } else { - if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedWidth) { - newAvailWidth += aState.mReflowState.mComputedWidth; - } - else { - newAvailWidth += aState.mReflowState.availableWidth; - } - } - NS_ASSERTION(NS_UNCONSTRAINEDSIZE != newAvailWidth, "bad math, newAvailWidth is infinite"); + nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left + + aState.mReflowState.mComputedWidth; + NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedBorderPadding.left && + NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedWidth, + "math on NS_UNCONSTRAINEDSIZE"); #ifdef DEBUG if (gNoisyReflow) { @@ -1863,6 +1370,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) // way we are here. if (line->IsBlock() || // XXXldb We need HasPercentageDescendant, not HasPercentageChild!!! + // ... but is that what ResizeReflowOptimizationDisabled does? line->HasPercentageChild() || line->HasFloats() || (line != mLines.back() && !line->HasBreakAfter()) || @@ -1906,19 +1414,46 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) return NS_OK; } + +nsresult +nsBlockFrame::MarkLineDirty(line_iterator aLine) +{ + // Mark aLine dirty + aLine->MarkDirty(); +#ifdef DEBUG + if (gNoisyReflow) { + IndentBy(stdout, gNoiseIndent); + ListTag(stdout); + printf(": mark line %p dirty\n", NS_STATIC_CAST(void*, aLine.get())); + } +#endif + + // Mark previous line dirty if its an inline line so that it can + // maybe pullup something from the line just affected. + // XXX We don't need to do this if aPrevLine ends in a break-after... + if (aLine != mLines.front() && + aLine->IsInline() && + aLine.prev()->IsInline()) { + aLine.prev()->MarkDirty(); +#ifdef DEBUG + if (gNoisyReflow) { + IndentBy(stdout, gNoiseIndent); + ListTag(stdout); + printf(": mark prev-line %p dirty\n", + NS_STATIC_CAST(void*, aLine.prev().get())); + } +#endif + } + + return NS_OK; +} + //---------------------------------------- nsBlockFrame::line_iterator nsBlockFrame::FindLineFor(nsIFrame* aFrame) { - // This assertion actually fires on lots of pages (e.g., bugzilla, - // bugzilla query page), so limit it to a few people until we fix the - // problem causing it. It's related to the similarly |#ifdef|ed - // assertion in |PrepareChildIncrementalReflow|. -#if defined(DEBUG_dbaron) || defined(DEBUG_waterson) NS_PRECONDITION(aFrame, "why pass a null frame?"); -#endif - line_iterator line = begin_lines(), line_end = end_lines(); for ( ; line != line_end; ++line) { @@ -2008,30 +1543,6 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState, } } -static void -DirtyLinesWithDirtyContinuations(const nsLineList::iterator& aLineStart, - const nsLineList::iterator& aLineEnd) -{ - // The line we're looking at right now - nsLineList::iterator line(aLineEnd); - - // Whether the line following the current one is dirty - PRBool nextLineDirty = PR_FALSE; - - while (line != aLineStart) { - --line; - - if (nextLineDirty && line->IsInline() && line->IsLineWrapped()) { - line->MarkDirty(); - // Note that nextLineDirty is already true and |line| will be the "next - // line" next time through this loop, and we just marked it dirty, so - // just leave nextLineDirty as true. - } else { - nextLineDirty = line->IsDirty(); - } - } -} - static void PlaceFrameView(nsIFrame* aFrame); static PRBool LineHasClear(nsLineBox* aLine) { @@ -2080,41 +1591,26 @@ static void DumpLine(const nsBlockReflowState& aState, nsLineBox* aLine, * Reflow the dirty lines */ nsresult -nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) +nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, + PRBool* aALineWasDirty) { nsresult rv = NS_OK; PRBool keepGoing = PR_TRUE; PRBool repositionViews = PR_FALSE; // should we really need this? PRBool foundAnyClears = PR_FALSE; + *aALineWasDirty = PR_FALSE; #ifdef DEBUG if (gNoisyReflow) { - if (aState.mReflowState.reason == eReflowReason_Incremental) { - IndentBy(stdout, gNoiseIndent); - ListTag(stdout); - printf(": incrementally reflowing dirty lines"); - - nsHTMLReflowCommand *command = aState.mReflowState.path->mReflowCommand; - if (command) { - printf(": type=%s(%d)", kReflowCommandType[command->Type()], - command->Type()); - } - } - else { - IndentBy(stdout, gNoiseIndent); - ListTag(stdout); - printf(": reflowing dirty lines"); - } + IndentBy(stdout, gNoiseIndent); + ListTag(stdout); + printf(": reflowing dirty lines"); printf(" computedWidth=%d\n", aState.mReflowState.mComputedWidth); } AutoNoisyIndenter indent(gNoisyReflow); #endif - // Check whether we need to do invalidation for the child block - PRBool doInvalidate = - aState.mReflowState.reason == eReflowReason_Incremental || - aState.mReflowState.reason == eReflowReason_Dirty || - aState.mReflowState.reason == eReflowReason_Resize; + PRBool selfDirty = (GetStateBits() & NS_FRAME_IS_DIRTY) != 0; // the amount by which we will slide the current line if it is not // dirty @@ -2131,12 +1627,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) line_iterator line = begin_lines(), line_end = end_lines(); - // If we're supposed to update our maximum width, then we'll also need to - // reflow any line if it's line wrapped and has a dirty continuing line. - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { - ::DirtyLinesWithDirtyContinuations(line, line_end); - } - if (line == line_end) mAscent=0; // there are no lines, reset the previously computed ascent @@ -2147,10 +1637,13 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) AutoNoisyIndenter indent2(gNoisyReflow); #endif + if (selfDirty) + line->MarkDirty(); + // This really sucks, but we have to look inside any blocks that have clear // elements inside them. // XXX what can we do smarter here? - if (line->IsBlock() && + if (!line->IsDirty() && line->IsBlock() && (line->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN)) { line->MarkDirty(); } @@ -2233,6 +1726,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) // Now repair the line and update |aState.mY| by calling // |ReflowLine| or |SlideLine|. if (line->IsDirty()) { + *aALineWasDirty = PR_TRUE; lastLineMovedUp = PR_TRUE; PRBool maybeReflowingForFirstTime = @@ -2247,10 +1741,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) // Reflow the dirty line. If it's an incremental reflow, then force // it to invalidate the dirty area if necessary - rv = ReflowLine(aState, line, &keepGoing, doInvalidate); - if (NS_FAILED(rv)) { - return rv; - } + rv = ReflowLine(aState, line, &keepGoing); + NS_ENSURE_SUCCESS(rv, rv); if (line->HasFloats()) { reflowedFloat = PR_TRUE; @@ -2325,18 +1817,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) // want to update mY, e.g. if they have clearance.) if (line->IsBlock() || !line->CachedIsEmpty()) { aState.mY = line->mBounds.YMost(); - - if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) { - // Mark the line as dirty so once we known the final shrink - // wrap width we can reflow the line to the correct size. - // It's OK to skip doing this for empty lines of inlines. - // XXX We don't always need to do this... - // XXX For inlines, we could record in the line box - // that HorzontalAlignFrames does not depend on the line width, - // and thus we don't have to mark it dirty here - line->MarkDirty(); - aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE); - } } needToRecoverState = PR_TRUE; @@ -2376,14 +1856,15 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) // -- the next in flow is not changing // -- and we cannot have added more space for its first line to be // pulled up into, - // -- and it's a not a resize reflow (so our width didn't change), + // -- it's an incremental reflow of a descendant // -- and we didn't reflow any floats (so the available space // didn't change) - if (!aState.mNextInFlow || !aTryPull || + // XXXldb We should also check that the first line of the next-in-flow + // isn't dirty. + if (!aState.mNextInFlow || (aState.mReflowState.mFlags.mNextInFlowUntouched && !lastLineMovedUp && - (aState.mReflowState.reason == eReflowReason_Incremental || - aState.mReflowState.reason == eReflowReason_Dirty) && + !(GetStateBits() & NS_FRAME_IS_DIRTY) && !reflowedFloat)) { if (aState.mNextInFlow) { aState.mReflowStatus |= NS_FRAME_NOT_COMPLETE; @@ -2473,11 +1954,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull) // line to be created; see SplitLine's callers for examples of // when this happens). while (line != end_lines()) { - rv = ReflowLine(aState, line, &keepGoing, doInvalidate); - if (NS_FAILED(rv)) { - NS_WARNING("Line reflow failed"); - return rv; - } + rv = ReflowLine(aState, line, &keepGoing); + NS_ENSURE_SUCCESS(rv, rv); DumpLine(aState, line, deltaY, -1); if (!keepGoing) { if (0 == line->GetChildCount()) { @@ -2579,8 +2057,7 @@ static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2, nsresult nsBlockFrame::ReflowLine(nsBlockReflowState& aState, line_iterator aLine, - PRBool* aKeepReflowGoing, - PRBool aDamageDirtyArea) + PRBool* aKeepReflowGoing) { nsresult rv = NS_OK; @@ -2606,153 +2083,61 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // of much confusion and bugs. Thus the following hack considers *both* // overflowArea and bounds. This should be considered a temporary hack // until we decide how it's really supposed to work. - if (aDamageDirtyArea) { - nsRect lineCombinedArea(aLine->GetCombinedArea()); - if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() || - oldBounds.TopLeft() != newBounds.TopLeft()) { - // The block has moved, and so to be safe we need to repaint - // XXX We need to improve on this... - nsRect dirtyRect; - dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea); + nsRect lineCombinedArea(aLine->GetCombinedArea()); + if (oldCombinedArea.TopLeft() != lineCombinedArea.TopLeft() || + oldBounds.TopLeft() != newBounds.TopLeft()) { + // The block has moved, and so to be safe we need to repaint + // XXX We need to improve on this... + nsRect dirtyRect; + dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea); #ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate 6 (%d, %d, %d, %d)\n", - this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); + printf("%p invalidate 6 (%d, %d, %d, %d)\n", + this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); #endif - Invalidate(dirtyRect); - } else { - nsRect combinedAreaHStrip, combinedAreaVStrip; - nsRect boundsHStrip, boundsVStrip; - GetRectDifferenceStrips(oldBounds, newBounds, - &boundsHStrip, &boundsVStrip); - GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea, - &combinedAreaHStrip, &combinedAreaVStrip); + Invalidate(dirtyRect); + } else { + nsRect combinedAreaHStrip, combinedAreaVStrip; + nsRect boundsHStrip, boundsVStrip; + GetRectDifferenceStrips(oldBounds, newBounds, + &boundsHStrip, &boundsVStrip); + GetRectDifferenceStrips(oldCombinedArea, lineCombinedArea, + &combinedAreaHStrip, &combinedAreaVStrip); #ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", - this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height); - printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n", - this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height); - printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n", - this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height); - printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n", - this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height); + printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", + this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height); + printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n", + this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height); + printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n", + this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height); + printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n", + this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height); #endif - // The first thing Invalidate does is check if the rect is empty, so - // don't bother doing that here. - Invalidate(boundsVStrip); - Invalidate(boundsHStrip); - Invalidate(combinedAreaVStrip); - Invalidate(combinedAreaHStrip); - } + // The first thing Invalidate does is check if the rect is empty, so + // don't bother doing that here. + Invalidate(boundsVStrip); + Invalidate(boundsHStrip); + Invalidate(combinedAreaVStrip); + Invalidate(combinedAreaHStrip); } } else { nsRect oldCombinedArea(aLine->GetCombinedArea()); aLine->SetLineWrapped(PR_FALSE); - // If we're supposed to update the maximum width, then we'll need to reflow - // the line with an unconstrained width (which will give us the new maximum - // width), then we'll reflow it again with the constrained width. - // We only do this if this is a beginning line, i.e., don't do this for - // lines associated with content that line wrapped (see ReflowDirtyLines() - // for details). - // XXX This approach doesn't work when floats are involved in which case - // we'll either need to recover the float state that applies to the - // unconstrained reflow or keep it around in a separate space manager... - PRBool isBeginningLine = aState.mCurrentLine == begin_lines() || - !aState.mCurrentLine.prev()->IsLineWrapped(); - // XXXldb Add &&!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) { - // First reflow the line with an unconstrained width. - nscoord oldY = aState.mY; - nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin); - PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH); - -#if defined(DEBUG_waterson) || defined(DEBUG_dbaron) - // XXXwaterson if oldUnconstrainedWidth was set, why do we need - // to do the second reflow, below? - - if (oldUnconstrainedWidth) - printf("*** oldUnconstrainedWidth was already set.\n" - "*** This code (%s:%d) could be optimized a lot!\n" - "+++ possibly doing an unnecessary second-pass unconstrained " - "reflow\n", - __FILE__, __LINE__); -#endif - - // When doing this we need to set the block reflow state's - // "mUnconstrainedWidth" variable to PR_TRUE so if we encounter - // a placeholder and then reflow its associated float we don't - // end up resetting the line's right edge and have it think the - // width is unconstrained... - aState.mSpaceManager->PushState(); - aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE); - ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE); - aState.mY = oldY; - aState.mPrevBottomMargin = oldPrevBottomMargin; - aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth); - aState.mSpaceManager->PopState(); - - // Update the line's maximum width - aLine->mMaximumWidth = aLine->mBounds.XMost(); -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n", - this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth); -#endif - aState.UpdateMaximumWidth(aLine->mMaximumWidth); - - // Now reflow the line again this time without having it compute - // the maximum width. - // We leave whether to compute max-element-width as-is, because - // making this call throws out the previous max-element-width - // information stored in the float cache. - nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH); - - aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE); - rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea); - aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth); - - } else { - rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea); - if (NS_SUCCEEDED(rv)) - { - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) - { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n", - this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth); -#endif - aState.UpdateMaximumWidth(aLine->mMaximumWidth); - } - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) - { -#ifdef DEBUG - if (gNoisyMaxElementWidth) { - IndentBy(stdout, gNoiseIndent); - printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaxElementWidth to %d\n", - NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine.get()), - aLine->mMaxElementWidth); - } -#endif - aState.UpdateMaxElementWidth(aLine->mMaxElementWidth); - } - } - } + rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing); // We don't really know what changed in the line, so use the union // of the old and new combined areas - if (aDamageDirtyArea) { - nsRect dirtyRect; - dirtyRect.UnionRect(oldCombinedArea, aLine->GetCombinedArea()); + nsRect dirtyRect; + dirtyRect.UnionRect(oldCombinedArea, aLine->GetCombinedArea()); #ifdef NOISY_BLOCK_INVALIDATE - printf("%p invalidate because %s is true (%d, %d, %d, %d)\n", - this, aDamageDirtyArea ? "aDamageDirtyArea" : "aLine->IsForceInvalidate", - dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); - if (aLine->IsForceInvalidate()) - printf(" dirty line is %p\n", NS_STATIC_CAST(void*, aLine.get()); + printf("%p invalidate (%d, %d, %d, %d)\n", + this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); + if (aLine->IsForceInvalidate()) + printf(" dirty line is %p\n", NS_STATIC_CAST(void*, aLine.get()); #endif - Invalidate(dirtyRect); - } + Invalidate(dirtyRect); } return rv; @@ -2765,7 +2150,6 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, nsresult nsBlockFrame::PullFrame(nsBlockReflowState& aState, line_iterator aLine, - PRBool aDamageDeletedLines, nsIFrame*& aFrameResult) { aFrameResult = nsnull; @@ -2775,8 +2159,7 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, #ifdef DEBUG PRBool retry = #endif - PullFrameFrom(aState, aLine, this, PR_FALSE, aLine.next(), - aDamageDeletedLines, aFrameResult); + PullFrameFrom(aState, aLine, this, PR_FALSE, aLine.next(), aFrameResult); NS_ASSERTION(!retry, "Shouldn't have to retry in the current block"); return NS_OK; } @@ -2790,8 +2173,7 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, // first normal lines, then overflow lines if (!nextInFlow->mLines.empty()) { if (PullFrameFrom(aState, aLine, nextInFlow, PR_FALSE, - nextInFlow->mLines.begin(), - aDamageDeletedLines, aFrameResult)) { + nextInFlow->mLines.begin(), aFrameResult)) { // try again with the same value of nextInFlow continue; } @@ -2801,8 +2183,7 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState, nsLineList* overflowLines = nextInFlow->GetOverflowLines(); if (overflowLines) { if (PullFrameFrom(aState, aLine, nextInFlow, PR_TRUE, - overflowLines->begin(), - aDamageDeletedLines, aFrameResult)) { + overflowLines->begin(), aFrameResult)) { // try again with the same value of nextInFlow continue; } @@ -2836,7 +2217,6 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState, nsBlockFrame* aFromContainer, PRBool aFromOverflowLine, nsLineList::iterator aFromLine, - PRBool aDamageDeletedLines, nsIFrame*& aFrameResult) { nsLineBox* fromLine = aFromLine; @@ -2881,9 +2261,7 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState, // Its bounds might need to be redrawn, though. // XXX WHY do we invalidate the bounds AND the combined area? doesn't // the combined area always enclose the bounds? - if (aDamageDeletedLines) { - Invalidate(fromLine->mBounds); - } + Invalidate(fromLine->mBounds); nsLineList* fromLineList = aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : &aFromContainer->mLines; @@ -3002,8 +2380,8 @@ nsBlockFrame::AttributeChanged(PRInt32 aNameSpaceID, // XXX Not sure if this is necessary anymore RenumberLists(presContext); - rv = presContext->PresShell()-> - AppendReflowCommand(this, eReflowType_ContentChanged, nsnull); + presContext->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } else if (nsHTMLAtoms::value == aAttribute) { const nsStyleDisplay* styleDisplay = GetStyleDisplay(); @@ -3030,8 +2408,8 @@ nsBlockFrame::AttributeChanged(PRInt32 aNameSpaceID, // XXX Not sure if this is necessary anymore blockParent->RenumberLists(presContext); - rv = presContext->PresShell()-> - AppendReflowCommand(blockParent, eReflowType_ContentChanged, nsnull); + presContext->PresShell()-> + FrameNeedsReflow(blockParent, nsIPresShell::eStyleChange); } } } @@ -3229,9 +2607,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Prepare the block reflow engine const nsStyleDisplay* display = frame->GetStyleDisplay(); - nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, - aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH), - aState.GetFlag(BRS_COMPUTEMAXWIDTH)); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState); PRUint8 breakType = display->mBreakType; // If a float split and its prev-in-flow was followed by a
, then combine @@ -3311,7 +2687,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // seems like a waste. And we do this for almost every block! nsSize availSpace(aState.mContentArea.width, NS_UNCONSTRAINEDSIZE); nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState, - frame, availSpace, eReflowReason_Resize); + frame, availSpace); if (treatWithClearance) { aState.mY += aState.mPrevBottomMargin.get(); @@ -3419,8 +2795,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // construct the html reflow state for the block. ReflowBlock // will initialize it nsHTMLReflowState blockHtmlRS(aState.mPresContext, aState.mReflowState, frame, - nsSize(availSpace.width, availSpace.height), - aState.mReflowState.reason, PR_TRUE); + nsSize(availSpace.width, availSpace.height)); blockHtmlRS.mFlags.mHasClearance = aLine->HasClearance(); if (mayNeedRetry) { @@ -3435,12 +2810,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, clearance, aState.IsAdjacentWithTop(), computedOffsets, blockHtmlRS, frameReflowStatus); - // Remove the frame from the reflow tree. - if (aState.mReflowState.path) - aState.mReflowState.path->RemoveChild(frame); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); if (mayNeedRetry) { if (clearanceFrame) { @@ -3494,21 +2864,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, } } - if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) { - // Mark the line as dirty so once we known the final shrink wrap width - // we can reflow the block to the correct size - // XXX We don't always need to do this... - aLine->MarkDirty(); - aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE); - } - if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) { - // Add the right margin to the line's bounds. That way it will be - // taken into account when we compute our shrink wrap size. - nscoord marginRight = brc.GetMargin().right; - if (marginRight != NS_UNCONSTRAINEDSIZE) { - aLine->mBounds.width += marginRight; - } - } aLine->SetCombinedArea(combinedArea); if (*aKeepReflowGoing) { // Some of the child block fit @@ -3522,17 +2877,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) { PRBool madeContinuation; rv = CreateContinuationFor(aState, nsnull, frame, madeContinuation); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsIFrame* nextFrame = frame->GetNextInFlow(); // Push continuation to a new line, but only if we actually made one. if (madeContinuation) { nsLineBox* line = aState.NewLineBox(nextFrame, 1, PR_TRUE); - if (nsnull == line) { - return NS_ERROR_OUT_OF_MEMORY; - } + NS_ENSURE_TRUE(line, NS_ERROR_OUT_OF_MEMORY); mLines.after_insert(aLine, line); } @@ -3599,21 +2951,6 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, aState.mPrevBottomMargin); #endif - // Post-process the "line" - nscoord maxElementWidth = 0; - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - maxElementWidth = brc.GetMaxElementWidth(); - } - // If we asked the block to update its maximum width, then record the - // updated value in the line, and update the current maximum width - if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) { - // The maximum width in the line box includes the left - // border/padding of this block, but not the right. - aLine->mMaximumWidth = brc.GetMaximumWidth() + availSpace.x; - aState.UpdateMaximumWidth(aLine->mMaximumWidth); - } - PostPlaceLine(aState, aLine, maxElementWidth); - // If the block frame that we just reflowed happens to be our // first block, then its computed ascent is ours if (frame == GetTopBlockChild(aState.mPresContext)) { @@ -3681,18 +3018,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, return rv; } -#define LINE_REFLOW_OK 0 -#define LINE_REFLOW_STOP 1 -#define LINE_REFLOW_REDO 2 -// a frame was complete, but truncated and not at the top of a page -#define LINE_REFLOW_TRUNCATED 3 - nsresult nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState, line_iterator aLine, - PRBool* aKeepReflowGoing, - PRBool aDamageDirtyArea, - PRBool aUpdateMaximumWidth) + PRBool* aKeepReflowGoing) { nsresult rv = NS_OK; *aKeepReflowGoing = PR_TRUE; @@ -3714,11 +3043,10 @@ nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState, nsLineLayout lineLayout(aState.mPresContext, aState.mReflowState.mSpaceManager, &aState.mReflowState, - aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)); + PR_FALSE); lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber); rv = DoReflowInlineFrames(aState, lineLayout, aLine, - aKeepReflowGoing, &lineReflowStatus, - aUpdateMaximumWidth, aDamageDirtyArea); + aKeepReflowGoing, &lineReflowStatus); lineLayout.EndLineReflow(); if (LINE_REFLOW_REDO == lineReflowStatus) { @@ -3769,54 +3097,53 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, nsLineLayout& aLineLayout, line_iterator aLine, PRBool* aKeepReflowGoing, - PRUint8* aLineReflowStatus, - PRBool aUpdateMaximumWidth, - PRBool aDamageDirtyArea) + PRUint8* aLineReflowStatus) { // Forget all of the floats on the line aLine->FreeFloats(aState.mFloatCacheFreeList); aState.mFloatCombinedArea.SetRect(0, 0, 0, 0); - // Setup initial coordinate system for reflowing the inline frames - // into. Apply a previous block frame's bottom margin first. - if (ShouldApplyTopMargin(aState, aLine)) { - aState.mY += aState.mPrevBottomMargin.get(); - } - aState.GetAvailableSpace(); - PRBool impactedByFloats = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE; - aLine->SetLineIsImpactedByFloat(impactedByFloats); + if (!aLineLayout.GetIntrinsicWidthPass()) { + // Setup initial coordinate system for reflowing the inline frames + // into. Apply a previous block frame's bottom margin first. + if (ShouldApplyTopMargin(aState, aLine)) { + aState.mY += aState.mPrevBottomMargin.get(); + } + aState.GetAvailableSpace(); + PRBool impactedByFloats = aState.IsImpactedByFloat() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloat(impactedByFloats); #ifdef REALLY_NOISY_REFLOW - printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", - this, impactedByFloats); + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloats); #endif - const nsMargin& borderPadding = aState.BorderPadding(); - nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; - nscoord availWidth = aState.mAvailSpaceRect.width; - nscoord availHeight; - if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) { - availHeight = NS_UNCONSTRAINEDSIZE; - } - else { - /* XXX get the height right! */ - availHeight = aState.mAvailSpaceRect.height; - } - if (aUpdateMaximumWidth) { - availWidth = NS_UNCONSTRAINEDSIZE; - } + const nsMargin& borderPadding = aState.BorderPadding(); + nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; + nscoord availWidth = aState.mAvailSpaceRect.width; + nscoord availHeight; + if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) { + availHeight = NS_UNCONSTRAINEDSIZE; + } + else { + /* XXX get the height right! */ + availHeight = aState.mAvailSpaceRect.height; + } #ifdef IBMBIDI - else { nscoord rightEdge = aState.mReflowState.mRightEdge; if ( (rightEdge != NS_UNCONSTRAINEDSIZE) && (availWidth < rightEdge) ) { availWidth = rightEdge; } - } #endif // IBMBIDI - aLineLayout.BeginLineReflow(x, aState.mY, - availWidth, availHeight, - impactedByFloats, - PR_FALSE /*XXX isTopOfPage*/); + aLineLayout.BeginLineReflow(x, aState.mY, + availWidth, availHeight, + impactedByFloats, + PR_FALSE /*XXX isTopOfPage*/); + } else { + aLineLayout.BeginLineReflow(0, 0, + NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, + PR_FALSE, PR_FALSE); + } // XXX Unfortunately we need to know this before reflowing the first // inline frame in the line. FIX ME. @@ -3846,9 +3173,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, } rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame, &lineReflowStatus); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); if (LINE_REFLOW_OK != lineReflowStatus) { // It is possible that one or more of next lines are empty // (because of DeleteNextInFlowChild). If so, delete them now @@ -3865,11 +3190,8 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, --aLine; if (LINE_REFLOW_TRUNCATED == lineReflowStatus) { - // Don't push any lines if we just want to calculate the maximum width - if (!aUpdateMaximumWidth) { - // Push the line with the truncated float - PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); - } + // Push the line with the truncated float + PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); } break; } @@ -3880,10 +3202,8 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, if (!isContinuingPlaceholders) { // Pull frames and reflow them until we can't while (LINE_REFLOW_OK == lineReflowStatus) { - rv = PullFrame(aState, aLine, aDamageDirtyArea, frame); - if (NS_FAILED(rv)) { - return rv; - } + rv = PullFrame(aState, aLine, frame); + NS_ENSURE_SUCCESS(rv, rv); if (nsnull == frame) { break; } @@ -3892,9 +3212,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, PRInt32 oldCount = aLine->GetChildCount(); rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame, &lineReflowStatus); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); if (aLine->GetChildCount() != oldCount) { // We just created a continuation for aFrame AND its going // to end up on this line (e.g. :first-letter @@ -3935,11 +3253,9 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // we placed the float but it was truncated so we need this line // to go to the next page/column. lineReflowStatus = LINE_REFLOW_TRUNCATED; - // Don't push any lines if we just want to calculate the maximum width - if (!aUpdateMaximumWidth) { - // Push the line that didn't fit - PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); - } + // Push the line that didn't fit + PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, + *aKeepReflowGoing); } } @@ -3958,7 +3274,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // If we are propagating out a break-before status then there is // no point in placing the line. if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) { - if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) { + if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing)) { UndoSplitPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line } } @@ -4020,18 +3336,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, } } - // If this is an incremental reflow, prune the child from the path - // so we don't incrementally reflow it again. - // XXX note that we don't currently have any incremental reflows - // that trace a path through an inline frame (thanks to reflow roots - // dealing with text inputs), but we may need to deal with this - // again, someday. - if (aState.mReflowState.path) - aState.mReflowState.path->RemoveChild(aFrame); - - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); #ifdef REALLY_NOISY_REFLOW_CHILD nsFrame::ListTag(stdout, aFrame); printf(": status=%x\n", frameReflowStatus); @@ -4082,9 +3387,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // It's not the first child on this line so go ahead and split // the line. We will see the frame again on the next-line. rv = SplitLine(aState, aLineLayout, aLine, aFrame); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); // If we're splitting the line because the frame didn't fit and it // was pushed, then mark the line as having word wrapped. We need to @@ -4115,8 +3418,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // frame may already have a continuation. PRBool madeContinuation; rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv, rv); if (!aLineLayout.GetLineEndsInBR()) { // Remember that the line has wrapped aLine->SetLineWrapped(PR_TRUE); @@ -4125,9 +3427,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // Split line, but after the frame just reflowed rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling()); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) { // Mark next line dirty in case SplitLine didn't end up @@ -4150,8 +3450,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, rv = (nsLayoutAtoms::placeholderFrame == frameType) ? SplitPlaceholder(aState, aFrame) : CreateContinuationFor(aState, aLine, aFrame, madeContinuation); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Remember that the line has wrapped if (!aLineLayout.GetLineEndsInBR()) { @@ -4173,9 +3472,7 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // Split line after the current frame *aLineReflowStatus = LINE_REFLOW_STOP; rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling()); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); // Mark next line dirty in case SplitLine didn't end up // pushing any frames. @@ -4210,9 +3507,7 @@ nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState, nsresult rv; nsIFrame* nextInFlow; rv = CreateNextInFlow(aState.mPresContext, this, aFrame, nextInFlow); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); if (nsnull != nextInFlow) { aMadeNewFrame = PR_TRUE; if (aLine) { @@ -4231,8 +3526,7 @@ nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState, { nsIFrame* nextInFlow; nsresult rv = CreateNextInFlow(aState.mPresContext, this, aPlaceholder, nextInFlow); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv, rv); if (!nextInFlow) { // Next in flow was not created because it already exists. @@ -4347,12 +3641,14 @@ PRBool nsBlockFrame::PlaceLine(nsBlockReflowState& aState, nsLineLayout& aLineLayout, line_iterator aLine, - PRBool* aKeepReflowGoing, - PRBool aUpdateMaximumWidth) + PRBool* aKeepReflowGoing) { // Trim extra white-space from the line before placing the frames aLineLayout.TrimTrailingWhiteSpace(); + if (aLineLayout.GetIntrinsicWidthPass()) + return PR_FALSE; + // Vertically align the frames on this line. // // According to the CSS2 spec, section 12.6.1, the "marker" box @@ -4376,25 +3672,13 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, aLineLayout.AddBulletFrame(mBullet, metrics); addedBullet = PR_TRUE; } - nscoord maxElementWidth; - aLineLayout.VerticalAlignLine(aLine, &maxElementWidth); + aLineLayout.VerticalAlignLine(aLine); // Our ascent is the ascent of our first line (but if this line is all // whitespace we'll correct things in |ReflowBlockFrame|). if (aLine == mLines.front()) { mAscent = aLine->mBounds.y + aLine->GetAscent(); } - // See if we're shrink wrapping the width - if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) { - // XXXldb Do we really still want to do this? - // When determining the line's width we also need to include any - // right floats that impact us. This represents the shrink wrap - // width of the line - if (aState.IsImpactedByFloat() && !aLine->IsLineWrapped()) { - NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state"); - aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost(); - } - } #ifdef DEBUG { static nscoord lastHeight = 0; @@ -4420,37 +3704,28 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign && !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine); - PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, - allowJustify, aState.GetFlag(BRS_SHRINKWRAPWIDTH)); + aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify); // XXX: not only bidi: right alignment can be broken after // RelativePositionFrames!!! // XXXldb Is something here considering relatively positioned frames at // other than their original positions? - if (!successful) { - // Mark the line dirty and then later once we've determined the width - // we can do the horizontal alignment - aLine->MarkDirty(); - aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE); - } #ifdef IBMBIDI // XXXldb Why don't we do this earlier? - else { - if (aState.mPresContext->BidiEnabled()) { - if (!aState.mPresContext->IsVisualMode()) { - nsBidiPresUtils* bidiUtils = aState.mPresContext->GetBidiUtils(); + if (aState.mPresContext->BidiEnabled()) { + if (!aState.mPresContext->IsVisualMode()) { + nsBidiPresUtils* bidiUtils = aState.mPresContext->GetBidiUtils(); - if (bidiUtils && bidiUtils->IsSuccessful() ) { - nsIFrame* nextInFlow = (aLine.next() != end_lines()) - ? aLine.next()->mFirstChild : nsnull; + if (bidiUtils && bidiUtils->IsSuccessful() ) { + nsIFrame* nextInFlow = (aLine.next() != end_lines()) + ? aLine.next()->mFirstChild : nsnull; - bidiUtils->ReorderFrames(aState.mPresContext, - aState.mReflowState.rendContext, - aLine->mFirstChild, nextInFlow, - aLine->GetChildCount() ); - } // bidiUtils - } // not visual mode - } // bidi enabled - } // successful + bidiUtils->ReorderFrames(aState.mPresContext, + aState.mReflowState.rendContext, + aLine->mFirstChild, nextInFlow, + aLine->GetChildCount() ); + } // bidiUtils + } // not visual mode + } // bidi enabled #endif // IBMBIDI nsRect combinedArea; @@ -4493,15 +3768,9 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // See if the line fit. If it doesn't we need to push it. Our first // line will always fit. - - // If we're just updating the maximum width then we don't care if it - // fits; we'll assume it does, so that the maximum width will get - // updated below. The line will be reflowed again and pushed then - // if necessary. if (mLines.front() != aLine && newY > aState.mBottomEdge && - aState.mBottomEdge != NS_UNCONSTRAINEDSIZE && - !aUpdateMaximumWidth) { + aState.mBottomEdge != NS_UNCONSTRAINEDSIZE) { // Push this line and all of it's children and anything else that // follows to our next-in-flow NS_ASSERTION((aState.mCurrentLine == aLine), "oops"); @@ -4521,31 +3790,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, aState.mY = newY; - // If we're reflowing the line just to incrementally update the - // maximum width, then don't post-place the line. It's doing work we - // don't need, and it will update things like aState.mKidXMost that - // we don't want updated... - if (aUpdateMaximumWidth) { - // However, we do need to update the max-element-width if requested - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - aState.UpdateMaxElementWidth(maxElementWidth); - // We also cache the max element width in the line. This is needed for - // incremental reflow - aLine->mMaxElementWidth = maxElementWidth; -#ifdef DEBUG - if (gNoisyMaxElementWidth) { - IndentBy(stdout, gNoiseIndent); - printf ("nsBlockFrame::PlaceLine: %p setting MEW for line %p to %d\n", - NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine.get()), - maxElementWidth); - } -#endif - } - - } else { - PostPlaceLine(aState, aLine, maxElementWidth); - } - // Add the already placed current-line floats to the line aLine->AppendFloats(aState.mCurrentLineFloats); @@ -4562,12 +3806,8 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, // push the line. XXX It may be better to put the float on the next line, but this // is not common enough to justify the complexity. Or maybe it is now... - // If we just want to calculate the maximum width, then don't push the line. - // We'll reflow it again and then it will get pushed if necessary. - if (!aUpdateMaximumWidth) { - nsIFrame* lastPlaceholder = aState.mOverflowPlaceholders.LastChild(); - PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); - } + nsIFrame* lastPlaceholder = aState.mOverflowPlaceholders.LastChild(); + PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing); } } @@ -4605,56 +3845,6 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState, return PR_FALSE; } -void -nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - nscoord aMaxElementWidth) -{ - // Update max-element-width - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - aState.UpdateMaxElementWidth(aMaxElementWidth); - // We also cache the max element width in the line. This is needed for - // incremental reflow - aLine->mMaxElementWidth = aMaxElementWidth; -#ifdef DEBUG - if (gNoisyMaxElementWidth) { - IndentBy(stdout, gNoiseIndent); - printf ("nsBlockFrame::PostPlaceLine: %p setting line %p MEW %d\n", - NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine), - aMaxElementWidth); - } -#endif - } - - // If this is an unconstrained reflow, then cache the line width in the - // line. We'll need this during incremental reflow if we're asked to - // calculate the maximum width - if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockFrame::PostPlaceLine during UC Reflow of block %p line %p caching max width %d\n", - NS_STATIC_CAST(void*, this), NS_STATIC_CAST(void*, aLine), - aLine->mBounds.XMost()); -#endif - aLine->mMaximumWidth = aLine->mBounds.XMost(); - } - - // Update xmost - nscoord xmost = aLine->mBounds.XMost(); - -#ifdef DEBUG - if (CRAZY_WIDTH(xmost)) { - ListTag(stdout); - printf(": line=%p xmost=%d\n", NS_STATIC_CAST(void*, aLine), xmost); - } -#endif - if (xmost > aState.mKidXMost) { - aState.mKidXMost = xmost; -#ifdef NOISY_KIDXMOST - printf("%p PostPlaceLine aState.mKidXMost=%d\n", this, aState.mKidXMost); -#endif - } -} - void nsBlockFrame::PushLines(nsBlockReflowState& aState, nsLineList::iterator aLineBefore) @@ -5015,6 +4205,8 @@ nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState) } // Now join the line lists into mLines + NS_ASSERTION(!overflowLines, "This code shouldn't be needed anymore " + "(tell dbaron if you see this)"); if (overflowLines) { if (!overflowLines->empty()) { // Join the line lists @@ -5218,8 +4410,9 @@ nsBlockFrame::AppendFrames(nsIAtom* aListName, #endif nsresult rv = AddFrames(aFrameList, lastKid); if (NS_SUCCEEDED(rv)) { - // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient? + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return rv; } @@ -5261,8 +4454,9 @@ nsBlockFrame::InsertFrames(nsIAtom* aListName, if (aListName != nsLayoutAtoms::nextBidi) #endif // IBMBIDI if (NS_SUCCEEDED(rv)) { - // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient? + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return rv; } @@ -5507,7 +4701,7 @@ nsBlockFrame::RemoveFrame(nsIAtom* aListName, } #ifdef IBMBIDI else if (nsLayoutAtoms::nextBidi == aListName) { - // Skip the call to |ReflowDirtyChild| below by returning now. + // Skip the call to |FrameNeedsReflow| below by returning now. return DoRemoveFrame(aOldFrame); } #endif // IBMBIDI @@ -5516,8 +4710,9 @@ nsBlockFrame::RemoveFrame(nsIAtom* aListName, } if (NS_SUCCEEDED(rv)) { - // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient? + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return rv; } @@ -5805,6 +5000,7 @@ nsBlockFrame::DeleteNextInFlowChild(nsPresContext* aPresContext, //////////////////////////////////////////////////////////////////////// // Float support + nsresult nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, nsPlaceholderFrame* aPlaceholder, @@ -5826,44 +5022,30 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, // Compute the available width. By default, assume the width of the // containing block. nscoord availWidth; - if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) { - availWidth = NS_UNCONSTRAINEDSIZE; + const nsStyleDisplay* floatDisplay = floatFrame->GetStyleDisplay(); + + if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay || + eCompatibility_NavQuirks != aState.mPresContext->CompatibilityMode() ) { + availWidth = aState.mContentArea.width; } else { - const nsStyleDisplay* floatDisplay = floatFrame->GetStyleDisplay(); - - if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay || - eCompatibility_NavQuirks != aState.mPresContext->CompatibilityMode() ) { - availWidth = aState.mContentArea.width; - } - else { - // This quirk matches the one in nsBlockReflowState::FlowAndPlaceFloat - // give tables only the available space - // if they can shrink we may not be constrained to place - // them in the next line - availWidth = aState.mAvailSpaceRect.width; - // round down to twips per pixel so that we fit - // needed when prev. float has procentage width - // (maybe is a table flaw that makes table chose to round up - // but i don't want to change that, too risky) - nscoord twp = aState.mPresContext->IntScaledPixelsToTwips(1); - availWidth -= availWidth % twp; - } + // This quirk matches the one in nsBlockReflowState::FlowAndPlaceFloat + // give tables only the available space + // if they can shrink we may not be constrained to place + // them in the next line + availWidth = aState.mAvailSpaceRect.width; + // round down to twips per pixel so that we fit + // needed when prev. float has procentage width + // (maybe is a table flaw that makes table chose to round up + // but i don't want to change that, too risky) + nscoord twp = aState.mPresContext->IntScaledPixelsToTwips(1); + availWidth -= availWidth % twp; } + nscoord availHeight = NS_UNCONSTRAINEDSIZE == aState.mContentArea.height ? NS_UNCONSTRAINEDSIZE : PR_MAX(0, aState.mContentArea.height - aState.mY); - // If the float's width is automatic, we can't let the float's - // width shrink below its maxElementWidth. - const nsStylePosition* position = floatFrame->GetStylePosition(); - PRBool isAutoWidth = (eStyleUnit_Auto == position->mWidth.GetUnit()); - - // We'll need to compute the max element size if either 1) we're - // auto-width or 2) the state wanted us to compute it anyway. - PRBool computeMaxElementWidth = - isAutoWidth || aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH); - nsRect availSpace(aState.BorderPadding().left, aState.BorderPadding().top, availWidth, availHeight); @@ -5872,13 +5054,10 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, // initialize it. nsHTMLReflowState floatRS(aState.mPresContext, aState.mReflowState, floatFrame, - nsSize(availSpace.width, availSpace.height), - aState.mReflowState.reason); + nsSize(availSpace.width, availSpace.height)); // Setup a block reflow state to reflow the float. - nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState, - computeMaxElementWidth, - aState.GetFlag(BRS_COMPUTEMAXWIDTH)); + nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState); // Reflow the float PRBool isAdjacentWithTop = aState.IsAdjacentWithTop(); @@ -5928,43 +5107,6 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; } - if (NS_SUCCEEDED(rv) && isAutoWidth) { - nscoord maxElementWidth = brc.GetMaxElementWidth(); - if (maxElementWidth > availSpace.width) { - // The float's maxElementWidth is larger than the available - // width. Reflow it again, this time pinning the width to the - // maxElementWidth. - availSpace.width = maxElementWidth; - // construct the html reflow state for the float. - // ReflowBlock will initialize it. - nsHTMLReflowState redoFloatRS(aState.mPresContext, aState.mReflowState, - floatFrame, - nsSize(availSpace.width, availSpace.height), - aState.mReflowState.reason); - - clearanceFrame = nsnull; - do { - nsCollapsingMargin marginMEW; - PRBool mayNeedRetry = PR_FALSE; - nsBlockReflowContext::ComputeCollapsedTopMargin(redoFloatRS, &marginMEW, clearanceFrame, &mayNeedRetry); - - if (mayNeedRetry && !clearanceFrame) { - redoFloatRS.mDiscoveredClearance = &clearanceFrame; - // We don't need to push the space manager state because the - // the block has its own space manager that will be - // destroyed and recreated - } else { - redoFloatRS.mDiscoveredClearance = nsnull; - } - - rv = brc.ReflowBlock(availSpace, PR_TRUE, marginMEW, - 0, isAdjacentWithTop, - aFloatCache->mOffsets, redoFloatRS, - aReflowStatus); - } while (NS_SUCCEEDED(rv) && clearanceFrame); - } - } - if (floatFrame->GetType() == nsLayoutAtoms::letterFrame) { // We never split floating first letters; an incomplete state for // such frames simply means that there is more content to be @@ -5973,10 +5115,6 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, aReflowStatus = NS_FRAME_COMPLETE; } - // Remove the float from the reflow tree. - if (aState.mReflowState.path) - aState.mReflowState.path->RemoveChild(floatFrame); - if (NS_FAILED(rv)) { return rv; } @@ -6012,19 +5150,6 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState, floatFrame->DidReflow(aState.mPresContext, &floatRS, NS_FRAME_REFLOW_FINISHED); - // If we computed it, then stash away the max-element-width for later - if (aState.GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { - nscoord mew = brc.GetMaxElementWidth() + - aFloatCache->mMargins.left + aFloatCache->mMargins.right; - - // This is all we need to do to include the float - // max-element-width since we don't require that we end up with - // content next to floats. - aState.UpdateMaxElementWidth(mew); // fix for bug 13553 - - // Allow the float width to be restored in state recovery. - aFloatCache->mMaxElementWidth = mew; - } #ifdef NOISY_FLOAT printf("end ReflowFloat %p, sized to %d,%d\n", floatFrame, metrics.width, metrics.height); @@ -6881,91 +6006,36 @@ nsBlockFrame::GetFrameForPoint(const nsPoint& aPoint, return nsnull; } -NS_IMETHODIMP -nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) +/* virtual */ PRBool +nsBlockFrame::ChildIsDirty(nsIFrame* aChild) { -#ifdef DEBUG - if (gNoisyReflow) { - IndentBy(stdout, gNoiseIndent); - ListTag(stdout); - printf(": ReflowDirtyChild ("); - if (aChild) - nsFrame::ListTag(stdout, aChild); - else - printf("null"); - printf(")\n"); - } - AutoNoisyIndenter indent(gNoisyReflow); -#endif - - if (aChild) { - // See if the child is absolutely positioned - if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - const nsStyleDisplay* disp = aChild->GetStyleDisplay(); - - if (disp->IsAbsolutelyPositioned()) { - // Generate a reflow command to reflow our dirty absolutely - // positioned child frames. - // XXX Note that we don't currently try and coalesce the reflow commands, - // although we should. We can't use the NS_FRAME_HAS_DIRTY_CHILDREN - // flag, because that's used to indicate whether in-flow children are - // dirty... - nsresult rv = aPresShell-> - AppendReflowCommand(this, eReflowType_ReflowDirty, - mAbsoluteContainer.GetChildListName()); - -#ifdef DEBUG - if (gNoisyReflow) { - IndentBy(stdout, gNoiseIndent); - printf("scheduled reflow command for absolutely positioned frame\n"); - } -#endif - - return rv; - } + // See if the child is absolutely positioned + if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW && + aChild->GetStyleDisplay()->IsAbsolutelyPositioned()) { + // do nothing + } else if (aChild == mBullet && HaveOutsideBullet()) { + // The bullet lives in the first line, unless the first line has + // height 0 and there is a second line, in which case it lives + // in the second line. + line_iterator bulletLine = begin_lines(); + if (bulletLine != end_lines() && bulletLine->mBounds.height == 0 && + bulletLine != mLines.back()) { + bulletLine = bulletLine.next(); } - - if (aChild == mBullet && HaveOutsideBullet()) { - // The bullet lives in the first line, unless the first line has - // height 0 and there is a second line, in which case it lives - // in the second line. - line_iterator bulletLine = begin_lines(); - if (bulletLine != end_lines() && bulletLine->mBounds.height == 0 && - bulletLine != mLines.back()) { - bulletLine = bulletLine.next(); - } - - if (bulletLine != end_lines()) { - MarkLineDirty(bulletLine); - } - // otherwise we have an empty line list, and ReflowDirtyLines - // will handle reflowing the bullet. - } else { - // Mark the line containing the child frame dirty. - line_iterator fline = FindLineFor(aChild); - if (fline != end_lines()) - MarkLineDirty(fline); + + if (bulletLine != end_lines()) { + MarkLineDirty(bulletLine); } + // otherwise we have an empty line list, and ReflowDirtyLines + // will handle reflowing the bullet. + } else { + // Mark the line containing the child frame dirty. + line_iterator fline = FindLineFor(aChild); + if (fline != end_lines()) + MarkLineDirty(fline); } - // Either generate a reflow command to reflow the dirty child or - // coalesce this reflow request with an existing reflow command - if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) { - // If this is the first dirty child, - // post a dirty children reflow command targeted at yourself - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - aPresShell->AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull); - -#ifdef DEBUG - if (gNoisyReflow) { - IndentBy(stdout, gNoiseIndent); - printf("scheduled reflow command targeted at self\n"); - } -#endif - } - - return NS_OK; + return nsBlockFrameSuper::ChildIsDirty(aChild); } ////////////////////////////////////////////////////////////////////// @@ -7199,7 +6269,8 @@ nsBlockFrame::RenumberLists(nsPresContext* aPresContext) // Get to first-in-flow nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow(); - RenumberListsInBlock(aPresContext, block, &ordinal, 0); + if (RenumberListsInBlock(aPresContext, block, &ordinal, 0)) + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); } PRBool @@ -7319,25 +6390,8 @@ nsBlockFrame::ReflowBullet(nsBlockReflowState& aState, // XXXwaterson Should this look just like the logic in // nsBlockReflowContext::ReflowBlock and nsLineLayout::ReflowFrame? const nsHTMLReflowState &rs = aState.mReflowState; - nsReflowReason reason = rs.reason; - if (reason == eReflowReason_Incremental) { - if (! rs.path->HasChild(mBullet)) { - // An incremental reflow not explicitly destined to (or through) - // the child should be treated as a resize... - reason = eReflowReason_Resize; - } - - // ...unless its an incremental `style changed' reflow targeted at - // the block, in which case, we propagate that to its children. - nsHTMLReflowCommand *command = rs.path->mReflowCommand; - if (command) { - if (command->Type() == eReflowType_StyleChanged) - reason = eReflowReason_StyleChange; - } - } - nsHTMLReflowState reflowState(aState.mPresContext, rs, - mBullet, availSize, reason); + mBullet, availSize); nsReflowStatus status; mBullet->WillReflow(aState.mPresContext); mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status); diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index 6dd2dbee1d7..75fe91c0e3c 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -42,7 +42,6 @@ #include "nsHTMLParts.h" #include "nsAbsoluteContainingBlock.h" #include "nsLineBox.h" -#include "nsReflowPath.h" #include "nsCSSPseudoElements.h" #include "nsStyleSet.h" @@ -209,7 +208,7 @@ public: NS_IMETHOD HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus); - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); + virtual PRBool ChildIsDirty(nsIFrame* aChild); NS_IMETHOD IsVisibleForPainting(nsPresContext * aPresContext, nsIRenderingContext& aRenderingContext, @@ -219,7 +218,10 @@ public: virtual PRBool IsEmpty(); virtual PRBool IsSelfEmpty(); - // nsIHTMLReflow + virtual void MarkIntrinsicWidthsDirty(); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); + NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -393,49 +395,13 @@ protected: // Remove a float, abs, rel positioned frame from the appropriate block's list static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame); - /** set up the conditions necessary for an initial reflow */ - nsresult PrepareInitialReflow(nsBlockReflowState& aState); - - /** set up the conditions necessary for an styleChanged reflow */ - nsresult PrepareStyleChangedReflow(nsBlockReflowState& aState); - - /** set up the conditions necessary for an incremental reflow. - * the primary task is to mark the minimumly sufficient lines dirty. - */ - nsresult PrepareChildIncrementalReflow(nsBlockReflowState& aState); - - /** - * Retarget an inline incremental reflow from continuing frames that - * will be destroyed. - * - * @param aState |aState.mNextRCFrame| contains the next frame in - * the reflow path; this will be ``rewound'' to either the target - * frame's primary frame, or to the first continuation frame after a - * ``hard break''. In other words, it will be set to the closest - * continuation which will not be destroyed by the unconstrained - * reflow. The remaining frames in the reflow path for - * |aState.mReflowState.reflowCommand| will be altered similarly. - * - * @param aLine is initially the line box that contains the target - * frame. It will be ``rewound'' in lockstep with - * |aState.mNextRCFrame|. - * - * @param aPrevInFlow points to the target frame's prev-in-flow. - */ - void RetargetInlineIncrementalReflow(nsReflowPath::iterator &aFrame, - line_iterator &aLine, - nsIFrame *aPrevInFlow); - /** set up the conditions necessary for an resize reflow * the primary task is to mark the minimumly sufficient lines dirty. */ nsresult PrepareResizeReflow(nsBlockReflowState& aState); - /** reflow all lines that have been marked dirty. - * @param aTryPull set this to PR_TRUE if you want to try pulling content from - * our next in flow while there is room. - */ - nsresult ReflowDirtyLines(nsBlockReflowState& aState, PRBool aTryPull); + /** reflow all lines that have been marked dirty */ + nsresult ReflowDirtyLines(nsBlockReflowState& aState, PRBool* aALineWasDirty); //---------------------------------------- // Methods for line reflow @@ -445,20 +411,16 @@ protected: * @param aLine the line to reflow. can contain a single block frame * or contain 1 or more inline frames. * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines - * @param aDamageDirtyArea if PR_TRUE, do extra work to mark the changed areas as damaged for painting - * this indicates that frames may have changed size, for example */ nsresult ReflowLine(nsBlockReflowState& aState, line_iterator aLine, - PRBool* aKeepReflowGoing, - PRBool aDamageDirtyArea = PR_FALSE); + PRBool* aKeepReflowGoing); // Return PR_TRUE if aLine gets pushed. PRBool PlaceLine(nsBlockReflowState& aState, nsLineLayout& aLineLayout, line_iterator aLine, - PRBool* aKeepReflowGoing, - PRBool aUpdateMaximumWidth); + PRBool* aKeepReflowGoing); /** * Mark |aLine| dirty, and, if necessary because of possible @@ -466,11 +428,6 @@ protected: */ nsresult MarkLineDirty(line_iterator aLine); - // XXX blech - void PostPlaceLine(nsBlockReflowState& aState, - nsLineBox* aLine, - nscoord aMaxElementWidth); - // XXX where to go PRBool ShouldJustifyLine(nsBlockReflowState& aState, line_iterator aLine); @@ -491,17 +448,13 @@ protected: nsresult ReflowInlineFrames(nsBlockReflowState& aState, line_iterator aLine, - PRBool* aKeepLineGoing, - PRBool aDamageDirtyArea, - PRBool aUpdateMaximumWidth = PR_FALSE); + PRBool* aKeepLineGoing); nsresult DoReflowInlineFrames(nsBlockReflowState& aState, nsLineLayout& aLineLayout, line_iterator aLine, PRBool* aKeepReflowGoing, - PRUint8* aLineReflowStatus, - PRBool aUpdateMaximumWidth, - PRBool aDamageDirtyArea); + PRUint8* aLineReflowStatus); nsresult ReflowInlineFrame(nsBlockReflowState& aState, nsLineLayout& aLineLayout, @@ -538,7 +491,6 @@ protected: nsresult PullFrame(nsBlockReflowState& aState, line_iterator aLine, - PRBool aDamageDeletedLine, nsIFrame*& aFrameResult); PRBool PullFrameFrom(nsBlockReflowState& aState, @@ -546,7 +498,6 @@ protected: nsBlockFrame* aFromContainer, PRBool aFromOverflowLine, nsLineList::iterator aFromLine, - PRBool aDamageDeletedLines, nsIFrame*& aFrameResult); void PushLines(nsBlockReflowState& aState, @@ -588,8 +539,6 @@ protected: static PRBool FrameStartsCounterScope(nsIFrame* aFrame); - nsresult UpdateBulletPosition(nsBlockReflowState& aState); - void ReflowBullet(nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); @@ -641,6 +590,8 @@ protected: // Ascent of our first line to support 'vertical-align: baseline' in table-cells nscoord mAscent; + nscoord mMinWidth, mPrefWidth; + nsLineList mLines; // List of all floats in this block @@ -662,7 +613,7 @@ public: static PRBool gLameReflowMetrics; static PRBool gNoisy; static PRBool gNoisyDamageRepair; - static PRBool gNoisyMaxElementWidth; + static PRBool gNoisyIntrinsic; static PRBool gNoisyReflow; static PRBool gReallyNoisyReflow; static PRBool gNoisySpaceManager; diff --git a/mozilla/layout/generic/nsBlockReflowContext.cpp b/mozilla/layout/generic/nsBlockReflowContext.cpp index 40d99d4728a..850f0309900 100644 --- a/mozilla/layout/generic/nsBlockReflowContext.cpp +++ b/mozilla/layout/generic/nsBlockReflowContext.cpp @@ -44,7 +44,6 @@ #include "nsFrameManager.h" #include "nsIContent.h" #include "nsStyleContext.h" -#include "nsHTMLReflowCommand.h" #include "nsHTMLContainerFrame.h" #include "nsBlockFrame.h" #include "nsLineBox.h" @@ -65,19 +64,14 @@ #endif nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentRS, - PRBool aComputeMaxElementWidth, - PRBool aComputeMaximumWidth) + const nsHTMLReflowState& aParentRS) : mPresContext(aPresContext), mOuterReflowState(aParentRS), - mMetrics(aComputeMaxElementWidth), - mComputeMaximumWidth(aComputeMaximumWidth) + mMetrics() { mStyleBorder = nsnull; mStyleMargin = nsnull; mStylePadding = nsnull; - if (mComputeMaximumWidth) - mMetrics.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; } static nsIFrame* DescendIntoBlockLevelFrame(nsIFrame* aFrame) @@ -164,9 +158,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS, // generational collapse is required we need to compute the // child blocks margin and so in so that we can look into // it. For its margins to be computed we need to have a reflow - // state for it. Since the reflow reason is irrelevant, we'll - // arbitrarily make it a `resize' to avoid the path-plucking - // behavior if we're in an incremental reflow. + // state for it. // We may have to construct an extra reflow state here if // we drilled down through a block wrapper. At the moment @@ -178,8 +170,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS, "Can only drill through one level of block wrapper"); nsSize availSpace(aRS.mComputedWidth, aRS.mComputedHeight); outerReflowState = new nsHTMLReflowState(prescontext, - aRS, frame, - availSpace, eReflowReason_Resize); + aRS, frame, availSpace); if (!outerReflowState) goto done; } @@ -188,7 +179,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS, outerReflowState->mComputedHeight); nsHTMLReflowState innerReflowState(prescontext, *outerReflowState, kid, - availSpace, eReflowReason_Resize); + availSpace); // Record that we're being optimistic by assuming the kid // has no clearance if (kid->GetStyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) { @@ -222,160 +213,6 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS, return dirtiedLine; } -struct nsBlockHorizontalAlign { - nscoord mXOffset; // left edge - nscoord mLeftMargin; - nscoord mRightMargin; -}; - -// Given the width of the block frame and a suggested x-offset calculate -// the actual x-offset taking into account horizontal alignment. Also returns -// the actual left and right margin -void -nsBlockReflowContext::AlignBlockHorizontally(nscoord aWidth, - nsBlockHorizontalAlign &aAlign) -{ - // Initialize OUT parameters - aAlign.mLeftMargin = mMargin.left; - aAlign.mRightMargin = mMargin.right; - - // Get style unit associated with the left and right margins - nsStyleUnit leftUnit = mStyleMargin->mMargin.GetLeftUnit(); - nsStyleUnit rightUnit = mStyleMargin->mMargin.GetRightUnit(); - - // Apply post-reflow horizontal alignment. When a block element - // doesn't use it all of the available width then we need to - // align it using the text-align property. - if (NS_UNCONSTRAINEDSIZE != mSpace.width && - NS_UNCONSTRAINEDSIZE != mOuterReflowState.mComputedWidth) { - // It is possible that the object reflowed was given a - // constrained width and ended up picking a different width - // (e.g. a table width a set width that ended up larger - // because its contents required it). When this happens we - // need to recompute auto margins because the reflow state's - // computations are no longer valid. - if (aWidth != mComputedWidth) { - if (eStyleUnit_Auto == leftUnit) { - aAlign.mXOffset = mSpace.x; - aAlign.mLeftMargin = 0; - } - if (eStyleUnit_Auto == rightUnit) { - aAlign.mRightMargin = 0; - } - } - - // Compute how much remaining space there is, and in special - // cases apply it (normally we should get zero here because of - // the logic in nsHTMLReflowState). - nscoord remainingSpace = mSpace.XMost() - (aAlign.mXOffset + aWidth + - aAlign.mRightMargin); - if (remainingSpace > 0) { - // The block/table frame didn't use all of the available - // space. Synthesize margins for its horizontal placement. - if (eStyleUnit_Auto == leftUnit) { - if (eStyleUnit_Auto == rightUnit) { - // When both margins are auto, we center the block - aAlign.mXOffset += remainingSpace / 2; - } - else { - // When the left margin is auto we right align the block - aAlign.mXOffset += remainingSpace; - } - } - else if (eStyleUnit_Auto != rightUnit) { - // The block/table doesn't have auto margins. - - // For normal (non-table) blocks we don't get here because - // nsHTMLReflowState::CalculateBlockSideMargins handles this. - // (I think there may be an exception to that, though...) - - // We use a special value of the text-align property for - // HTML alignment (the CENTER element and DIV ALIGN=...) - // since it acts on blocks and tables rather than just - // being a text-align. - // So, check the text-align value from the parent to see if - // it has one of these special values. - const nsStyleText* styleText = mOuterReflowState.mStyleText; - if (styleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) { - aAlign.mXOffset += remainingSpace; - } else if (styleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER) { - aAlign.mXOffset += remainingSpace / 2; - } else if (styleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT) { - // If we don't have a special text-align value indicating - // HTML alignment, then use the CSS rules. - - // When neither margin is auto then the block is said to - // be over constrained, Depending on the direction, choose - // which margin to treat as auto. - PRUint8 direction = mOuterReflowState.mStyleVisibility->mDirection; - if (NS_STYLE_DIRECTION_RTL == direction) { - // The left margin becomes auto - aAlign.mXOffset += remainingSpace; - } - //else { - // The right margin becomes auto which is a no-op - //} - } - } - } - } -} - -static void -ComputeShrinkwrapMargins(const nsStyleMargin* aStyleMargin, nscoord aWidth, - nsMargin& aMargin, nscoord& aXToUpdate) -{ - nscoord boxWidth = aWidth; - float leftPct = 0.0, rightPct = 0.0; - const nsStyleSides& margin = aStyleMargin->mMargin; - - if (eStyleUnit_Percent == margin.GetLeftUnit()) { - nsStyleCoord coord; - leftPct = margin.GetLeft(coord).GetPercentValue(); - } else { - boxWidth += aMargin.left; - } - - if (eStyleUnit_Percent == margin.GetRightUnit()) { - nsStyleCoord coord; - rightPct = margin.GetRight(coord).GetPercentValue(); - } else { - boxWidth += aMargin.right; - } - - // The total shrink wrap width "sww" (i.e., the width that the - // containing block needs to be to shrink-wrap this block) is - // calculated by the expression: - // sww = bw + (mp * sww) - // where "bw" is the box width (frame width plus margins that aren't - // percentage based) and "mp" are the total margin percentages (i.e., - // the left percentage value plus the right percentage value). - // Solving for "sww" gives: - // sww = bw / (1 - mp) - // Note that this is only well defined for "mp" less than 100% and - // greater than -100% (XXXldb but we only accept 0 to 100%). - - float marginPct = leftPct + rightPct; - if (marginPct >= 1.0) { - // Ignore the right percentage and just use the left percentage - // XXX Pay attention to direction property... - marginPct = leftPct; - rightPct = 0.0; - } - - if ((marginPct > 0.0) && (marginPct < 1.0)) { - double shrinkWrapWidth = float(boxWidth) / (1.0 - marginPct); - - if (eStyleUnit_Percent == margin.GetLeftUnit()) { - aMargin.left = NSToCoordFloor((float)(shrinkWrapWidth * leftPct)); - aXToUpdate += aMargin.left; - } - if (eStyleUnit_Percent == margin.GetRightUnit()) { - aMargin.right = NSToCoordFloor((float)(shrinkWrapWidth * rightPct)); - } - } -} - static void nsPointDtor(void *aFrame, nsIAtom *aPropertyName, void *aPropertyValue, void *aDtorData) @@ -398,48 +235,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, mFrame = aFrameRS.frame; mSpace = aSpace; - // Get reflow reason set correctly. It's possible that a child was - // created and then it was decided that it could not be reflowed - // (for example, a block frame that isn't at the start of a - // line). In this case the reason will be wrong so we need to check - // the frame state. - aFrameRS.reason = eReflowReason_Resize; - if (NS_FRAME_FIRST_REFLOW & mFrame->GetStateBits()) { - aFrameRS.reason = eReflowReason_Initial; - } - else if (mOuterReflowState.reason == eReflowReason_Incremental) { - // If the frame we're about to reflow is on the reflow path, then - // propagate the reflow as `incremental' so it unwinds correctly - // to the target frames below us. - PRBool frameIsOnReflowPath = mOuterReflowState.path->HasChild(mFrame); - if (frameIsOnReflowPath) - aFrameRS.reason = eReflowReason_Incremental; - - // But...if the incremental reflow command is a StyleChanged - // reflow and its target is the current block, change the reason - // to `style change', so that it propagates through the entire - // subtree. - nsHTMLReflowCommand* rc = mOuterReflowState.path->mReflowCommand; - if (rc) { - nsReflowType type; - rc->GetType(type); - if (type == eReflowType_StyleChanged) - aFrameRS.reason = eReflowReason_StyleChange; - else if (type == eReflowType_ReflowDirty && - (mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) && - !frameIsOnReflowPath) { - aFrameRS.reason = eReflowReason_Dirty; - } - } - } - else if (mOuterReflowState.reason == eReflowReason_StyleChange) { - aFrameRS.reason = eReflowReason_StyleChange; - } - else if (mOuterReflowState.reason == eReflowReason_Dirty) { - if (mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) - aFrameRS.reason = eReflowReason_Dirty; - } - const nsStyleDisplay* display = mFrame->GetStyleDisplay(); aComputedOffsets = aFrameRS.mComputedOffsets; @@ -518,23 +313,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, mX = x; mY = y; - // If it's an auto-width table, then it doesn't behave like other blocks - // XXX why not for a floating table too? - if (aFrameRS.mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE && - !aFrameRS.mStyleDisplay->IsFloating()) { - // If this isn't the table's initial reflow, then use its existing - // width to determine where it will be placed horizontally - if (aFrameRS.reason != eReflowReason_Initial) { - nsBlockHorizontalAlign align; - - align.mXOffset = x; - AlignBlockHorizontally(mFrame->GetSize().width, align); - // Don't reset "mX". because PlaceBlock() will recompute the - // x-offset and expects "mX" to be at the left margin edge - x = align.mXOffset; - } - } - // Compute the translation to be used for adjusting the spacemanagager // coordinate system for the frame. The spacemanager coordinates are // inside the callers border+padding, but the x/y coordinates @@ -565,43 +343,9 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, mMetrics.height = nscoord(0xdeadbeef); mMetrics.ascent = nscoord(0xdeadbeef); mMetrics.descent = nscoord(0xdeadbeef); - if (mMetrics.mComputeMEW) { - mMetrics.mMaxElementWidth = nscoord(0xdeadbeef); - } #endif mOuterReflowState.mSpaceManager->Translate(tx, ty); - - // See if this is the child's initial reflow and we are supposed to - // compute our maximum width - if (mComputeMaximumWidth && (eReflowReason_Initial == aFrameRS.reason)) { - mOuterReflowState.mSpaceManager->PushState(); - - nscoord oldAvailableWidth = aFrameRS.availableWidth; - nscoord oldComputedWidth = aFrameRS.mComputedWidth; - - aFrameRS.availableWidth = NS_UNCONSTRAINEDSIZE; - // XXX Is this really correct? This means we don't compute the - // correct maximum width if the element's width is determined by - // its 'width' style - aFrameRS.mComputedWidth = NS_UNCONSTRAINEDSIZE; - rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus); - - // Update the reflow metrics with the maximum width - mMetrics.mMaximumWidth = mMetrics.width; -#ifdef NOISY_REFLOW - printf("*** nsBlockReflowContext::ReflowBlock block %p returning max width %d\n", - mFrame, mMetrics.mMaximumWidth); -#endif - // The second reflow is just as a resize reflow with the constrained - // width - aFrameRS.availableWidth = oldAvailableWidth; - aFrameRS.mComputedWidth = oldComputedWidth; - aFrameRS.reason = eReflowReason_Resize; - - mOuterReflowState.mSpaceManager->PopState(); - } - rv = mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus); mOuterReflowState.mSpaceManager->Translate(-tx, -ty); @@ -612,24 +356,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, nsFrame::ListTag(stdout, mFrame); printf(" metrics=%d,%d!\n", mMetrics.width, mMetrics.height); } - if (mMetrics.mComputeMEW && - (nscoord(0xdeadbeef) == mMetrics.mMaxElementWidth)) { - printf("nsBlockReflowContext: "); - nsFrame::ListTag(stdout, mFrame); - printf(" didn't set max-element-size!\n"); - } -#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE - // Note: there are common reflow situations where this *correctly* - // occurs; so only enable this debug noise when you really need to - // analyze in detail. - if (mMetrics.mComputeMEW && - (mMetrics.mMaxElementWidth > mMetrics.width)) { - printf("nsBlockReflowContext: "); - nsFrame::ListTag(stdout, mFrame); - printf(": WARNING: maxElementWidth=%d > metrics=%d\n", - mMetrics.mMaxElementWidth, mMetrics.width); - } -#endif if ((mMetrics.width == nscoord(0xdeadbeef)) || (mMetrics.height == nscoord(0xdeadbeef)) || (mMetrics.ascent == nscoord(0xdeadbeef)) || @@ -642,20 +368,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, } } #endif -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) { - if (mMetrics.mComputeMEW) { - printf(" "); - nsFrame::ListTag(stdout, mFrame); - printf(": maxElementSize=%d wh=%d,%d\n", - mMetrics.mMaxElementWidth, - mMetrics.width, mMetrics.height); - } - } - } -#endif if (!(NS_FRAME_OUTSIDE_CHILDREN & mFrame->GetStateBits())) { // Provide overflow area for child that doesn't have any @@ -665,13 +377,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, mMetrics.mOverflowArea.height = mMetrics.height; } - // Now that frame has been reflowed at least one time make sure that - // the NS_FRAME_FIRST_REFLOW bit is cleared so that never give it an - // initial reflow reason again. - if (eReflowReason_Initial == aFrameRS.reason) { - mFrame->RemoveStateBits(NS_FRAME_FIRST_REFLOW); - } - if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus) || (mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { // If frame is complete and has a next-in-flow, we need to delete @@ -693,13 +398,6 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace, } } - // If the block is shrink wrapping its width, then see if we have percentage - // based margins. If so, we can calculate them now that we know the shrink - // wrap width - if (NS_SHRINKWRAPWIDTH == aFrameRS.mComputedWidth) { - ComputeShrinkwrapMargins(aFrameRS.mStyleMargin, mMetrics.width, mMargin, mX); - } - return rv; } @@ -784,64 +482,6 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState, } } - if (!empty) - { - // Adjust the max-element-size in the metrics to take into - // account the margins around the block element. - // Do not allow auto margins to impact the max-element size - // since they are springy and don't really count! - if (mMetrics.mComputeMEW) { - nsMargin maxElemMargin; - const nsStyleSides &styleMargin = mStyleMargin->mMargin; - nsStyleCoord coord; - if (styleMargin.GetLeftUnit() == eStyleUnit_Coord) - maxElemMargin.left = styleMargin.GetLeft(coord).GetCoordValue(); - else - maxElemMargin.left = 0; - if (styleMargin.GetRightUnit() == eStyleUnit_Coord) - maxElemMargin.right = styleMargin.GetRight(coord).GetCoordValue(); - else - maxElemMargin.right = 0; - - nscoord dummyXOffset; - // Base the margins on the max-element size - ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaxElementWidth, - maxElemMargin, dummyXOffset); - - mMetrics.mMaxElementWidth += maxElemMargin.left + maxElemMargin.right; - } - - // do the same for the maximum width - if (mComputeMaximumWidth) { - nsMargin maxWidthMargin; - const nsStyleSides &styleMargin = mStyleMargin->mMargin; - nsStyleCoord coord; - if (styleMargin.GetLeftUnit() == eStyleUnit_Coord) - maxWidthMargin.left = styleMargin.GetLeft(coord).GetCoordValue(); - else - maxWidthMargin.left = 0; - if (styleMargin.GetRightUnit() == eStyleUnit_Coord) - maxWidthMargin.right = styleMargin.GetRight(coord).GetCoordValue(); - else - maxWidthMargin.right = 0; - - nscoord dummyXOffset; - // Base the margins on the maximum width - ComputeShrinkwrapMargins(mStyleMargin, mMetrics.mMaximumWidth, - maxWidthMargin, dummyXOffset); - - mMetrics.mMaximumWidth += maxWidthMargin.left + maxWidthMargin.right; - } - } - - // Calculate the actual x-offset and left and right margin - nsBlockHorizontalAlign align; - align.mXOffset = x; - AlignBlockHorizontally(mMetrics.width, align); - x = align.mXOffset; - mMargin.left = align.mLeftMargin; - mMargin.right = align.mRightMargin; - aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance, mMetrics.width, mMetrics.height); diff --git a/mozilla/layout/generic/nsBlockReflowContext.h b/mozilla/layout/generic/nsBlockReflowContext.h index a547cc3ece0..dd22f2275eb 100644 --- a/mozilla/layout/generic/nsBlockReflowContext.h +++ b/mozilla/layout/generic/nsBlockReflowContext.h @@ -57,9 +57,7 @@ struct nsBlockHorizontalAlign; class nsBlockReflowContext { public: nsBlockReflowContext(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentRS, - PRBool aComputeMaxElementWidth, - PRBool aComputeMaximumWidth); + const nsHTMLReflowState& aParentRS); ~nsBlockReflowContext() { } nsresult ReflowBlock(const nsRect& aSpace, @@ -80,8 +78,6 @@ public: nsRect& aCombinedRect, nsReflowStatus aReflowStatus); - void AlignBlockHorizontally(nscoord aWidth, nsBlockHorizontalAlign&); - nsCollapsingMargin& GetCarriedOutBottomMargin() { return mMetrics.mCarriedOutBottomMargin; } @@ -98,14 +94,6 @@ public: return mMetrics; } - nscoord GetMaxElementWidth() const { - return mMetrics.mMaxElementWidth; - } - - nscoord GetMaximumWidth() const { - return mMetrics.mMaximumWidth; - } - /** * Computes the collapsed top margin for a block whose reflow state is in aRS. * The computed margin is added into aMargin. @@ -141,7 +129,6 @@ protected: nscoord mX, mY; nsHTMLReflowMetrics mMetrics; nsCollapsingMargin mTopMargin; - PRPackedBool mComputeMaximumWidth; }; #endif /* nsBlockReflowContext_h___ */ diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 684394258c9..0a69c173293 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -105,29 +105,10 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPresContext = aPresContext; mNextInFlow = NS_STATIC_CAST(nsBlockFrame*, mBlock->GetNextInFlow()); - mKidXMost = 0; - // Compute content area width (the content area is inside the border - // and padding) - if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) { - mContentArea.width = aReflowState.mComputedWidth; - } - else { - if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { - mContentArea.width = NS_UNCONSTRAINEDSIZE; - SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE); - } - else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) { - // Choose a width based on the content (shrink wrap width) up - // to the maximum width - mContentArea.width = aReflowState.mComputedMaxWidth; - SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE); - } - else { - nscoord lr = borderPadding.left + borderPadding.right; - mContentArea.width = PR_MAX(0, aReflowState.availableWidth - lr); - } - } + NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth, + "no unconstrained widths should be present anymore"); + mContentArea.width = aReflowState.mComputedWidth; // Compute content area height. Unlike the width, if we have a // specified style height we ignore it since extra content is @@ -155,18 +136,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState, mPrevChild = nsnull; mCurrentLine = aFrame->end_lines(); - SetFlag(BRS_COMPUTEMAXELEMENTWIDTH, aMetrics.mComputeMEW); -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - printf("BRS: setting compute-MEW to %d\n", aMetrics.mComputeMEW); - } -#endif - mMaxElementWidth = 0; - SetFlag(BRS_COMPUTEMAXWIDTH, - (NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH))); - mMaximumWidth = 0; - mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext, aReflowState.rendContext, aReflowState.frame); @@ -244,10 +213,8 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, // The child block will flow around the float. Therefore // give it all of the available space. aResult.x = borderPadding.left; - aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH) - ? NS_UNCONSTRAINEDSIZE - : mContentArea.width; - break; + aResult.width = mContentArea.width; + break; case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { @@ -270,22 +237,17 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, } // determine width - if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) { - aResult.width = NS_UNCONSTRAINEDSIZE; - } - else { - if (mBand.GetRightFloatCount()) { - if (mBand.GetLeftFloatCount()) { - aResult.width = mAvailSpaceRect.width + m.left + m.right; - } - else { - aResult.width = mAvailSpaceRect.width + m.right; - } + if (mBand.GetRightFloatCount()) { + if (mBand.GetLeftFloatCount()) { + aResult.width = mAvailSpaceRect.width + m.left + m.right; } else { - aResult.width = mAvailSpaceRect.width + m.left; + aResult.width = mAvailSpaceRect.width + m.right; } } + else { + aResult.width = mAvailSpaceRect.width + m.left; + } } break; @@ -304,9 +266,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, // doesn't matter therefore give the block element all of the // available space since it will flow around the float itself. aResult.x = borderPadding.left; - aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH) - ? NS_UNCONSTRAINEDSIZE - : mContentArea.width; + aResult.width = mContentArea.width; } } else { @@ -484,54 +444,6 @@ nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine, // Make the line being recovered the current line mCurrentLine = aLine; - // Recover mKidXMost and mMaxElementWidth - nscoord xmost = aLine->mBounds.XMost(); - // If we're shrink-wrapping, then include the right margin in the xmost - // so that shrink-wrapping includes it. - if (GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsBlock()) { - nsHTMLReflowState blockHtmlRS(mPresContext, mReflowState, aLine->mFirstChild, - nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), - mReflowState.reason, PR_TRUE); - xmost += blockHtmlRS.mComputedMargin.right; - } - if (xmost > mKidXMost) { -#ifdef DEBUG - if (CRAZY_WIDTH(xmost)) { - nsFrame::ListTag(stdout, mBlock); - printf(": WARNING: xmost:%d\n", xmost); - } -#endif -#ifdef NOISY_KIDXMOST - printf("%p RecoverState block %p aState.mKidXMost=%d\n", this, mBlock, xmost); -#endif - mKidXMost = xmost; - } - if (GetFlag(BRS_COMPUTEMAXELEMENTWIDTH)) { -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaxElementWidth); - } -#endif - UpdateMaxElementWidth(aLine->mMaxElementWidth); - - // Recover the float MEWs for floats in this line (but not in - // blocks within it, since their MEWs are already part of the block's - // MEW). - if (aLine->HasFloats()) { - for (nsFloatCache* fc = aLine->GetFirstFloat(); fc; fc = fc->Next()) - UpdateMaxElementWidth(fc->mMaxElementWidth); - } - } - - // If computing the maximum width, then update mMaximumWidth - if (GetFlag(BRS_COMPUTEMAXWIDTH)) { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaximumWidth); -#endif - UpdateMaximumWidth(aLine->mMaximumWidth); - } - // Place floats for this line into the space manager if (aLine->HasFloats() || aLine->IsBlock()) { // Undo border/padding translation since the nsFloatCache's @@ -599,8 +511,8 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout, // Allocate a nsFloatCache for the float nsFloatCache* fc = mFloatCacheFreeList.Alloc(); fc->mPlaceholder = aPlaceholder; - fc->mIsCurrentLineFloat = aLineLayout.CanPlaceFloatNow(); - fc->mMaxElementWidth = 0; + fc->mIsCurrentLineFloat = !aLineLayout.GetIntrinsicWidthPass() && + aLineLayout.CanPlaceFloatNow(); PRBool placed; @@ -630,7 +542,7 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout, // Pass on updated available space to the current inline reflow engine GetAvailableSpace(mY, forceFit); aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY, - GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width, + mAvailSpaceRect.width, mAvailSpaceRect.height, isLeftFloat, aPlaceholder->GetOutOfFlowFrame()); @@ -658,41 +570,6 @@ nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout, return placed; } -void -nsBlockReflowState::UpdateMaxElementWidth(nscoord aMaxElementWidth) -{ -#ifdef DEBUG - nscoord oldWidth = mMaxElementWidth; -#endif - if (aMaxElementWidth > mMaxElementWidth) { - mMaxElementWidth = aMaxElementWidth; - } -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - if (mMaxElementWidth != oldWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) { - printf("PASS1 "); - } - nsFrame::ListTag(stdout, mBlock); - printf(": old max-element-width=%d new=%d\n", - oldWidth, mMaxElementWidth); - } - } -#endif -} - -void -nsBlockReflowState::UpdateMaximumWidth(nscoord aMaximumWidth) -{ - if (aMaximumWidth > mMaximumWidth) { -#ifdef NOISY_MAXIMUM_WIDTH - printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth); -#endif - mMaximumWidth = aMaximumWidth; - } -} - PRBool nsBlockReflowState::CanPlaceFloat(const nsSize& aFloatSize, PRUint8 aFloats, PRBool aForceFit) @@ -946,20 +823,13 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, } else { isLeftFloat = PR_FALSE; - if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.width) { - if (!keepFloatOnSameLine) { - floatX = mAvailSpaceRect.XMost() - floatSize.width; - } - else { - // this is the IE quirk (see few lines above) - // the table is keept in the same line: don't let it overlap the previous float - floatX = mAvailSpaceRect.x; - } - } + if (!keepFloatOnSameLine) { + floatX = mAvailSpaceRect.XMost() - floatSize.width; + } else { - // For unconstrained reflows, pretend that a right float is - // instead a left float. This will make us end up with the - // correct unconstrained width, and we'll place it later. + // this is the IE quirk (see few lines above) + // the table is kept in the same line: don't let it overlap the + // previous float floatX = mAvailSpaceRect.x; } } @@ -1050,16 +920,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsFloatCache* aFloatCache, // reflow, and since there's no need to change the code that was // necessary back when the float was positioned relative to // NS_UNCONSTRAINEDSIZE. - if (isLeftFloat || - !GetFlag(BRS_UNCONSTRAINEDWIDTH) || - !GetFlag(BRS_SHRINKWRAPWIDTH)) { - mFloatCombinedArea.UnionRect(combinedArea, mFloatCombinedArea); - } else if (GetFlag(BRS_SHRINKWRAPWIDTH)) { - // Mark the line dirty so we come back and re-place the float once - // the shrink wrap width is determined - mCurrentLine->MarkDirty(); - SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE); - } + mFloatCombinedArea.UnionRect(combinedArea, mFloatCombinedArea); // Now restore mY mY = saveY; diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 0d97882ce2d..cabe31fdb70 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -48,16 +48,11 @@ class nsBlockFrame; // block reflow state flags -#define BRS_UNCONSTRAINEDWIDTH 0x00000001 -#define BRS_UNCONSTRAINEDHEIGHT 0x00000002 -#define BRS_SHRINKWRAPWIDTH 0x00000004 -#define BRS_NEEDRESIZEREFLOW 0x00000008 -#define BRS_ISTOPMARGINROOT 0x00000020 // Is this frame a root for top/bottom margin collapsing? -#define BRS_ISBOTTOMMARGINROOT 0x00000040 -#define BRS_APPLYTOPMARGIN 0x00000080 // See ShouldApplyTopMargin -#define BRS_COMPUTEMAXELEMENTWIDTH 0x00000100 -#define BRS_COMPUTEMAXWIDTH 0x00000200 -#define BRS_ISFIRSTINFLOW 0x00000400 +#define BRS_UNCONSTRAINEDHEIGHT 0x00000001 +#define BRS_ISTOPMARGINROOT 0x00000002 // Is this frame a root for top/bottom margin collapsing? +#define BRS_ISBOTTOMMARGINROOT 0x00000004 +#define BRS_APPLYTOPMARGIN 0x00000008 // See ShouldApplyTopMargin +#define BRS_ISFIRSTINFLOW 0x00000010 #define BRS_LASTFLAG BRS_ISFIRSTINFLOW class nsBlockReflowState { @@ -123,10 +118,6 @@ public: return mReflowState.mComputedMargin; } - void UpdateMaxElementWidth(nscoord aMaxElementWidth); - - void UpdateMaximumWidth(nscoord aMaximumWidth); - // Reconstruct the previous bottom margin that goes above |aLine|. void ReconstructMarginAbove(nsLineList::iterator aLine); @@ -204,9 +195,6 @@ public: // The available space within the current band. nsRect mAvailSpaceRect; - // The maximum x-most of each line - nscoord mKidXMost; - // The combined area of all floats placed so far nsRect mFloatCombinedArea; @@ -244,11 +232,6 @@ public: // being N^2. nsFloatCacheFreeList mBelowCurrentLineFloats; - nscoord mMaxElementWidth; - - // maximum width includes the left border/padding but not the right - nscoord mMaximumWidth; - nscoord mMinLineHeight; PRInt32 mLineNumber; diff --git a/mozilla/layout/generic/nsBulletFrame.cpp b/mozilla/layout/generic/nsBulletFrame.cpp index ca33280b00b..b2f5a80a28f 100644 --- a/mozilla/layout/generic/nsBulletFrame.cpp +++ b/mozilla/layout/generic/nsBulletFrame.cpp @@ -44,7 +44,6 @@ #include "nsPresContext.h" #include "nsIPresShell.h" #include "nsIDocument.h" -#include "nsReflowPath.h" #include "nsIRenderingContext.h" #include "nsILoadGroup.h" #include "nsIURL.h" @@ -1389,7 +1388,7 @@ nsBulletFrame::GetListItemText(const nsStyleList& aListStyle, void nsBulletFrame::GetDesiredSize(nsPresContext* aCX, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext *aRenderingContext, nsHTMLReflowMetrics& aMetrics) { // Reset our padding. If we need it, we'll set it below. @@ -1403,73 +1402,9 @@ nsBulletFrame::GetDesiredSize(nsPresContext* aCX, mImageRequest->GetImageStatus(&status); if (status & imgIRequest::STATUS_SIZE_AVAILABLE && !(status & imgIRequest::STATUS_ERROR)) { - nscoord widthConstraint = NS_INTRINSICSIZE; - nscoord heightConstraint = NS_INTRINSICSIZE; - PRBool fixedContentWidth = PR_FALSE; - PRBool fixedContentHeight = PR_FALSE; - - nscoord minWidth, maxWidth, minHeight, maxHeight; - - // Determine whether the image has fixed content width - widthConstraint = aReflowState.mComputedWidth; - minWidth = aReflowState.mComputedMinWidth; - maxWidth = aReflowState.mComputedMaxWidth; - if (widthConstraint != NS_INTRINSICSIZE) { - fixedContentWidth = PR_TRUE; - } - - // Determine whether the image has fixed content height - heightConstraint = aReflowState.mComputedHeight; - minHeight = aReflowState.mComputedMinHeight; - maxHeight = aReflowState.mComputedMaxHeight; - if (heightConstraint != NS_UNCONSTRAINEDSIZE) { - fixedContentHeight = PR_TRUE; - } - - PRBool haveComputedSize = PR_FALSE; - PRBool needIntrinsicImageSize = PR_FALSE; - - nscoord newWidth=0, newHeight=0; - if (fixedContentWidth) { - newWidth = MINMAX(widthConstraint, minWidth, maxWidth); - if (fixedContentHeight) { - newHeight = MINMAX(heightConstraint, minHeight, maxHeight); - haveComputedSize = PR_TRUE; - } else { - // We have a width, and an auto height. Compute height from - // width once we have the intrinsic image size. - if (mIntrinsicSize.height != 0) { - newHeight = (mIntrinsicSize.height * newWidth) / mIntrinsicSize.width; - haveComputedSize = PR_TRUE; - } else { - newHeight = 0; - needIntrinsicImageSize = PR_TRUE; - } - } - } else if (fixedContentHeight) { - // We have a height, and an auto width. Compute width from height - // once we have the intrinsic image size. - newHeight = MINMAX(heightConstraint, minHeight, maxHeight); - if (mIntrinsicSize.width != 0) { - newWidth = (mIntrinsicSize.width * newHeight) / mIntrinsicSize.height; - haveComputedSize = PR_TRUE; - } else { - newWidth = 0; - needIntrinsicImageSize = PR_TRUE; - } - } else { - // auto size the image - if (mIntrinsicSize.width == 0 && mIntrinsicSize.height == 0) - needIntrinsicImageSize = PR_TRUE; - else - haveComputedSize = PR_TRUE; - - newWidth = mIntrinsicSize.width; - newHeight = mIntrinsicSize.height; - } - - mComputedSize.width = newWidth; - mComputedSize.height = newHeight; + // auto size the image + mComputedSize.width = mIntrinsicSize.width; + mComputedSize.height = mIntrinsicSize.height; #if 0 // don't do scaled images in bullets if (mComputedSize == mIntrinsicSize) { @@ -1588,8 +1523,8 @@ nsBulletFrame::GetDesiredSize(nsPresContext* aCX, case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: GetListItemText(*myList, text); fm->GetHeight(aMetrics.height); - aReflowState.rendContext->SetFont(fm); - aReflowState.rendContext->GetWidth(text, aMetrics.width); + aRenderingContext->SetFont(fm); + aRenderingContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); @@ -1603,11 +1538,11 @@ nsBulletFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsBulletFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsBulletFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); // Get the base size - GetDesiredSize(aPresContext, aReflowState, aMetrics); + GetDesiredSize(aPresContext, aReflowState.rendContext, aMetrics); // Add in the border and padding; split the top/bottom between the // ascent and descent to make things look nice @@ -1617,14 +1552,29 @@ nsBulletFrame::Reflow(nsPresContext* aPresContext, aMetrics.ascent += borderPadding.top; aMetrics.descent += borderPadding.bottom; - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = aMetrics.width; - } aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return NS_OK; } +/* virtual */ nscoord +nsBulletFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_MIN_WIDTH(this, metrics.width); + GetDesiredSize(GetPresContext(), aRenderingContext, metrics); + return metrics.width; +} + +/* virtual */ nscoord +nsBulletFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_PREF_WIDTH(this, metrics.width); + GetDesiredSize(GetPresContext(), aRenderingContext, metrics); + return metrics.width; +} + NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) @@ -1658,7 +1608,7 @@ NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest, NS_ASSERTION(mParent, "No parent to pass the reflow request up to."); if (mParent) { mState |= NS_FRAME_IS_DIRTY; - mParent->ReflowDirtyChild(shell, this); + shell->FrameNeedsReflow(this, nsIPresShell::eStyleChange); } } } diff --git a/mozilla/layout/generic/nsBulletFrame.h b/mozilla/layout/generic/nsBulletFrame.h index af3cf6b2c29..f183ede890b 100644 --- a/mozilla/layout/generic/nsBulletFrame.h +++ b/mozilla/layout/generic/nsBulletFrame.h @@ -71,6 +71,8 @@ public: nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); // nsBulletFrame PRInt32 SetListItemOrdinal(PRInt32 aNextOrdinal, PRBool* aChanged); @@ -98,7 +100,7 @@ public: protected: void GetDesiredSize(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext *aRenderingContext, nsHTMLReflowMetrics& aMetrics); void GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup); diff --git a/mozilla/layout/generic/nsColumnSetFrame.cpp b/mozilla/layout/generic/nsColumnSetFrame.cpp index 4088a2bbd2c..47bbd2e9609 100644 --- a/mozilla/layout/generic/nsColumnSetFrame.cpp +++ b/mozilla/layout/generic/nsColumnSetFrame.cpp @@ -46,7 +46,6 @@ #include "nsLayoutAtoms.h" #include "nsStyleConsts.h" #include "nsCOMPtr.h" -#include "nsReflowPath.h" class nsColumnSetFrame : public nsHTMLContainerFrame { public: @@ -123,7 +122,6 @@ protected: */ PRBool ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, - nsReflowReason aReason, nsReflowStatus& aStatus, const ReflowConfig& aConfig, PRBool aLastColumnUnbounded, @@ -337,14 +335,13 @@ static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) { PRBool nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, - nsReflowReason aKidReason, nsReflowStatus& aStatus, const ReflowConfig& aConfig, PRBool aUnboundedLastColumn, nsCollapsingMargin* aBottomMarginCarriedOut) { PRBool allFit = PR_TRUE; PRBool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; - PRBool shrinkingHeightOnly = aKidReason == eReflowReason_Resize && + PRBool shrinkingHeightOnly = !(GetStateBits() & (NS_FRAME_IS_DIRTY|NS_FRAME_HAS_DIRTY_CHILDREN)) && mLastBalanceHeight > aConfig.mColMaxHeight; #ifdef DEBUG_roc @@ -362,15 +359,14 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, // We need a way to do an incremental reflow and be sure availableHeight // changes are taken account of! Right now I think block frames with absolute // children might exit early. - NS_ASSERTION(aKidReason != eReflowReason_Incremental, - "incremental reflow should not have changed the balance height"); + //NS_ASSERTION(aKidReason != eReflowReason_Incremental, + // "incremental reflow should not have changed the balance height"); } // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; nsRect contentRect(0, 0, 0, 0); - aDesiredSize.mMaxElementWidth = 0; nsRect overflowRect(0, 0, 0, 0); nsIFrame* child = mFrames.FirstChild(); @@ -401,11 +397,10 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, // skip if the next column is dirty, because the next column's first line(s) // might be pullable back to this column. We can't skip if it's the last child // because we need to obtain the bottom margin. - PRBool skipIncremental = aKidReason == eReflowReason_Incremental + PRBool skipIncremental = !(GetStateBits() & NS_FRAME_IS_DIRTY) && !(child->GetStateBits() & NS_FRAME_IS_DIRTY) && child->GetNextSibling() - && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY) - && !aDesiredSize.mComputeMEW; + && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY); // If we need to pull up content from the prev-in-flow then this is not just // a height shrink. The prev in flow will have set the dirty bit. PRBool skipResizeHeightShrink = shrinkingHeightOnly @@ -432,23 +427,12 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, availSize.height = GetAvailableContentHeight(aReflowState); } - nsReflowReason tmpReason = aKidReason; - if (reflowNext && aKidReason == eReflowReason_Incremental - && !(child->GetStateBits() & NS_FRAME_IS_DIRTY)) { - // If this frame was not being incrementally reflowed but was - // just reflowed because the previous frame wants us to - // reflow, then force this child to reflow its dirty lines! - // XXX what we should really do here is add the child block to - // the incremental reflow path! Currently I think if there's an - // incremental reflow targeted only at the absolute frames of a - // column, then the column will be dirty BUT reflowing it will - // not reflow any lines affected by the prev-in-flow! - tmpReason = eReflowReason_Dirty; - } + if (reflowNext) + child->AddStateBits(NS_FRAME_IS_DIRTY); nsHTMLReflowState kidReflowState(GetPresContext(), aReflowState, child, availSize, availSize.width, - aReflowState.mComputedHeight, tmpReason); + aReflowState.mComputedHeight); kidReflowState.mFlags.mIsTopOfPage = PR_TRUE; #ifdef DEBUG_roc @@ -458,12 +442,13 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, // Note if the column's next in flow is not being changed by this incremental reflow. // This may allow the current column to avoid trying to pull lines from the next column. - if (child->GetNextSibling() && aKidReason == eReflowReason_Incremental && + if (child->GetNextSibling() && + !(GetStateBits() & NS_FRAME_IS_DIRTY) && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) { kidReflowState.mFlags.mNextInFlowUntouched = PR_TRUE; } - nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); + nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags); // XXX it would be cool to consult the space manager for the // previous block to figure out the region of floats from the @@ -495,11 +480,6 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, FinishReflowChild(child, GetPresContext(), &kidReflowState, kidDesiredSize, childOrigin.x, childOrigin.y, 0); - - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = PR_MAX(aDesiredSize.mMaxElementWidth, - kidDesiredSize.mMaxElementWidth); - } } contentRect.UnionRect(contentRect, child->GetRect()); @@ -531,9 +511,6 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, } kidNextInFlow->AddStateBits(NS_BLOCK_SPACE_MGR); - - // Do an initial reflow if we're going to reflow this thing. - aKidReason = eReflowReason_Initial; } if (columnCount >= aConfig.mBalanceColCount) { @@ -617,11 +594,6 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, aDesiredSize.width = contentSize.width + borderPadding.left + borderPadding.right; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; - aDesiredSize.mMaximumWidth = aDesiredSize.width; - if (aDesiredSize.mComputeMEW) { - // add in padding. - aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right; - } overflowRect.UnionRect(overflowRect, nsRect(0, 0, aDesiredSize.width, aDesiredSize.height)); aDesiredSize.mOverflowArea = overflowRect; @@ -686,44 +658,13 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; //------------ Handle Incremental Reflow ----------------- - nsReflowReason kidReason = aReflowState.reason; - - if ( aReflowState.reason == eReflowReason_Incremental ) { - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - - // Dirty any frames on the incremental reflow path - nsReflowPath *path = aReflowState.path; - nsReflowPath::iterator iter = path->FirstChild(); - nsReflowPath::iterator end = path->EndChildren(); - for ( ; iter != end; ++iter) { - (*iter)->AddStateBits(NS_FRAME_IS_DIRTY); - } - - // See if it's targeted at us - if (command) { - switch (command->Type()) { - - case eReflowType_StyleChanged: - kidReason = eReflowReason_StyleChange; - break; - - // if its a dirty type then reflow us with a dirty reflow - case eReflowType_ReflowDirty: - kidReason = eReflowReason_Dirty; - break; - - default: - NS_ERROR("Unexpected Reflow Type"); - } - } - } ReflowConfig config = ChooseColumnStrategy(aReflowState); PRBool isBalancing = config.mBalanceColCount < PR_INT32_MAX; @@ -737,22 +678,10 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, nsIFrame* nextInFlow = GetNextInFlow(); PRBool unboundedLastColumn = isBalancing && nextInFlow; nsCollapsingMargin carriedOutBottomMargin; - PRBool feasible = ReflowChildren(aDesiredSize, aReflowState, kidReason, + PRBool feasible = ReflowChildren(aDesiredSize, aReflowState, aStatus, config, unboundedLastColumn, &carriedOutBottomMargin); if (isBalancing) { - if (feasible || - // All children were reflowed as necessary, so we can go ahead - // and do resize reflows from now on - kidReason != eReflowReason_StyleChange) { - // Any non-stylechange reflow can be followed by resize - // reflows. But a stylechange reflow demands that all children - // be reflowed, which may not have happened yet; some of them - // might just have been pushed to an overflow list. So we have to - // keep doing stylechange reflows. - kidReason = eReflowReason_Resize; - } - nscoord availableContentHeight = GetAvailableContentHeight(aReflowState); // Termination of the algorithm below is guaranteed because @@ -848,8 +777,9 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, config.mColMaxHeight = nextGuess; unboundedLastColumn = PR_FALSE; + AddStateBits(NS_FRAME_IS_DIRTY); feasible = ReflowChildren(aDesiredSize, aReflowState, - kidReason, aStatus, config, PR_FALSE, + aStatus, config, PR_FALSE, &carriedOutBottomMargin); } @@ -866,7 +796,8 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, config.mColMaxHeight = knownFeasibleHeight; } if (!skip) { - ReflowChildren(aDesiredSize, aReflowState, eReflowReason_Resize, + AddStateBits(NS_FRAME_IS_DIRTY); + ReflowChildren(aDesiredSize, aReflowState, aStatus, config, PR_FALSE, &carriedOutBottomMargin); } } diff --git a/mozilla/layout/generic/nsContainerFrame.cpp b/mozilla/layout/generic/nsContainerFrame.cpp index 32c81fb54b6..27bc5e2e165 100644 --- a/mozilla/layout/generic/nsContainerFrame.cpp +++ b/mozilla/layout/generic/nsContainerFrame.cpp @@ -371,18 +371,13 @@ nsContainerFrame::ReplaceFrame(nsIAtom* aListName, return rv; } -NS_IMETHODIMP -nsContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) +/* virtual */ PRBool +nsContainerFrame::ChildIsDirty(nsIFrame* aChild) { - // The container frame always generates a reflow command - // targeted at its child - // Note that even if this flag is already set, we still need to reflow the - // child because the frame may have more than one child - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - aPresShell->AppendReflowCommand(aChild, eReflowType_ReflowDirty, nsnull); - - return NS_OK; + PRBool result = + (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0; + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + return result; } PRBool @@ -866,14 +861,6 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, nsresult result; -#ifdef DEBUG -#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = nscoord(0xdeadbeef); - } -#endif -#endif - // Send the WillReflow() notification, and position the child frame // and its view if requested aKidFrame->WillReflow(aPresContext); @@ -890,17 +877,6 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); -#ifdef DEBUG -#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE - if (aDesiredSize.mComputeMEW && - (nscoord(0xdeadbeef) == aDesiredSize.mMaxElementWidth)) { - printf("nsContainerFrame: "); - nsFrame::ListTag(stdout, aKidFrame); - printf(" didn't set max-element-width!\n"); - } -#endif -#endif - // If the reflow was successful and the child frame is complete, delete any // next-in-flows if (NS_SUCCEEDED(result) && NS_FRAME_IS_COMPLETE(aStatus)) { diff --git a/mozilla/layout/generic/nsContainerFrame.h b/mozilla/layout/generic/nsContainerFrame.h index 431bacc1b9a..904db0e1aba 100644 --- a/mozilla/layout/generic/nsContainerFrame.h +++ b/mozilla/layout/generic/nsContainerFrame.h @@ -75,7 +75,7 @@ public: NS_IMETHOD ReplaceFrame(nsIAtom* aListName, nsIFrame* aOldFrame, nsIFrame* aNewFrame); - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); + virtual PRBool ChildIsDirty(nsIFrame* aChild); virtual PRBool IsLeaf() const; diff --git a/mozilla/layout/generic/nsFirstLetterFrame.cpp b/mozilla/layout/generic/nsFirstLetterFrame.cpp index 11a672dce8e..728f51cbe5b 100644 --- a/mozilla/layout/generic/nsFirstLetterFrame.cpp +++ b/mozilla/layout/generic/nsFirstLetterFrame.cpp @@ -227,7 +227,7 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aReflowStatus) { - DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aReflowStatus); nsresult rv = NS_OK; @@ -254,8 +254,7 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, // only time that the first-letter-frame is not reflowing in a // line context is when its floating. nsHTMLReflowState rs(aPresContext, aReflowState, kid, availSize); - nsLineLayout ll(aPresContext, nsnull, &aReflowState, - aMetrics.mComputeMEW); + nsLineLayout ll(aPresContext, nsnull, &aReflowState, PR_FALSE); ll.BeginLineReflow(0, 0, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, PR_FALSE, PR_TRUE); rs.mLineLayout = ≪ @@ -274,8 +273,7 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, ll->BeginSpan(this, &aReflowState, bp.left, availSize.width); ll->ReflowFrame(kid, aReflowStatus, &aMetrics, pushedFrame); nsSize size; - ll->EndSpan(this, size, - aMetrics.mComputeMEW ? &aMetrics.mMaxElementWidth : nsnull); + ll->EndSpan(this, size); } // Place and size the child and update the output metrics @@ -285,9 +283,6 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext, aMetrics.height += tb; aMetrics.ascent += bp.top; aMetrics.descent += bp.bottom; - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth += lr; - } // Create a continuation or remove existing continuations based on // the reflow completion status. diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 7b1e4242655..b9815c7e98e 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -47,7 +47,6 @@ #include "nsString.h" #include "nsReadableUtils.h" #include "nsStyleContext.h" -#include "nsReflowPath.h" #include "nsIView.h" #include "nsIViewManager.h" #include "nsIScrollableFrame.h" @@ -136,7 +135,6 @@ struct nsBoxLayoutMetrics PRPackedBool mIncludeOverflow; PRPackedBool mWasCollapsed; - PRPackedBool mStyleChange; }; struct nsContentAndOffset @@ -2072,7 +2070,127 @@ nsFrame::GetFrameForPoint(const nsPoint& aPoint, // Resize and incremental reflow -// nsIHTMLReflow member functions +/* virtual */ void +nsFrame::MarkIntrinsicWidthsDirty() +{ + // This version is meant only for what used to be box-to-block adaptors. + // It should not be called by other derived classes. + if (IsBoxWrapped()) { + nsBoxLayoutMetrics *metrics = BoxMetrics(); + + SizeNeedsRecalc(metrics->mPrefSize); + SizeNeedsRecalc(metrics->mMinSize); + SizeNeedsRecalc(metrics->mMaxSize); + SizeNeedsRecalc(metrics->mBlockPrefSize); + SizeNeedsRecalc(metrics->mBlockMinSize); + CoordNeedsRecalc(metrics->mFlex); + CoordNeedsRecalc(metrics->mAscent); + } +} + +/* virtual */ nscoord +nsFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ +#ifdef DEBUG + nsAutoString frameName; + GetFrameName(frameName); + NS_NOTREACHED(nsCAutoString(NS_ConvertUTF16toUTF8(frameName) + + nsDependentCString(" frame didn't implement GetMinWidth")).get()); +#endif + nscoord result = 0; + DISPLAY_MIN_WIDTH(this, result); + return 0; +} + +/* virtual */ nscoord +nsFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ +#ifdef DEBUG + nsAutoString frameName; + GetFrameName(frameName); + NS_NOTREACHED(nsCAutoString(NS_ConvertUTF16toUTF8(frameName) + + nsDependentCString(" frame didn't implement GetPrefWidth")).get()); +#endif + nscoord result = 0; + DISPLAY_PREF_WIDTH(this, result); + return 0; +} + +/* virtual */ void +nsFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlineMinWidthData *aData) +{ + aData->skipWhitespace = PR_FALSE; + aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + this, nsLayoutUtils::MIN_WIDTH); +} + +/* virtual */ void +nsFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlinePrefWidthData *aData) +{ + aData->trailingWhitespace = 0; + aData->skipWhitespace = PR_FALSE; + aData->currentLine += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + this, nsLayoutUtils::PREF_WIDTH); +} + +void +nsIFrame::InlineMinWidthData::Break(nsIRenderingContext *aRenderingContext) +{ + prevLines = PR_MAX(prevLines, currentLine); + currentLine = 0; + + for (PRInt32 i = 0, i_end = floats.Count(); i != i_end; ++i) { + nsIFrame *floatFrame = NS_STATIC_CAST(nsIFrame*, floats[i]); + nscoord float_min = + nsLayoutUtils::IntrinsicForContainer(aRenderingContext, floatFrame, + nsLayoutUtils::MIN_WIDTH); + if (float_min > prevLines) + prevLines = float_min; + } + floats.Clear(); +} + +void +nsIFrame::InlinePrefWidthData::Break(nsIRenderingContext *aRenderingContext) +{ + if (floats.Count() != 0) { + // preferred widths accumulated for floats that have already + // been cleared past + nscoord floats_done = 0, + // preferred widths accumulated for floats that have not yet + // been cleared past + floats_cur = 0; + + for (PRInt32 i = 0, i_end = floats.Count(); i != i_end; ++i) { + nsIFrame *floatFrame = NS_STATIC_CAST(nsIFrame*, floats[i]); + const nsStyleDisplay *floatDisp = floatFrame->GetStyleDisplay(); + if (floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT || + floatDisp->mBreakType == NS_STYLE_CLEAR_RIGHT || + floatDisp->mBreakType == NS_STYLE_CLEAR_LEFT_AND_RIGHT) { + if (floats_cur > floats_done) + floats_done = floats_cur; + floats_cur = 0; + } + + floats_cur += + nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + floatFrame, nsLayoutUtils::PREF_WIDTH); + } + + if (floats_cur > floats_done) + floats_done = floats_cur; + + currentLine += floats_done; + + floats.Clear(); + } + + currentLine -= trailingWhitespace; + prevLines = PR_MAX(prevLines, currentLine); + currentLine = trailingWhitespace = 0; +} NS_IMETHODIMP nsFrame::WillReflow(nsPresContext* aPresContext) @@ -2101,17 +2219,14 @@ nsFrame::DidReflow(nsPresContext* aPresContext, NS_FRAME_HAS_DIRTY_CHILDREN); } - // Notify the percent height observer if this is an initial or resize reflow (XXX - // it should probably be any type of reflow, but this would need further testing) - // and there is a percent height but no computed height. The observer may be able to - // initiate another reflow with a computed height. This happens in the case where a table - // cell has no computed height but can fabricate one when the cell height is known. - if (aReflowState && (aReflowState->mPercentHeightObserver) && // an observer - ((eReflowReason_Initial == aReflowState->reason) || // initial or resize reflow - (eReflowReason_Resize == aReflowState->reason)) && + // Notify the percent height observer if there is a percent height + // but no computed height. The observer may be able to initiate + // another reflow with a computed height. This happens in the case + // where a table cell has no computed height but can fabricate one + // when the cell height is known. + if (aReflowState && aReflowState->mPercentHeightObserver && ((NS_UNCONSTRAINEDSIZE == aReflowState->mComputedHeight) || // no computed height (0 == aReflowState->mComputedHeight)) && - aReflowState->mStylePosition && // percent height (eStyleUnit_Percent == aReflowState->mStylePosition->mHeight.GetUnit())) { nsIFrame* prevInFlow = GetPrevInFlow(); @@ -2138,14 +2253,11 @@ nsFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsFrame"); aDesiredSize.width = 0; aDesiredSize.height = 0; aDesiredSize.ascent = 0; aDesiredSize.descent = 0; - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = 0; - } aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; @@ -2625,9 +2737,6 @@ nsFrame::IsFrameTreeTooDeep(const nsHTMLReflowState& aReflowState, aMetrics.mOverflowArea.y = 0; aMetrics.mOverflowArea.width = 0; aMetrics.mOverflowArea.height = 0; - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = 0; - } return PR_TRUE; } mState &= ~NS_FRAME_IS_UNFLOWABLE; @@ -4233,11 +4342,12 @@ nsIView* nsIFrame::GetClosestView(nsPoint* aOffset) const } -NS_IMETHODIMP -nsFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) +/* virtual */ PRBool +nsFrame::ChildIsDirty(nsIFrame* aChild) { - NS_ASSERTION(0, "nsFrame::ReflowDirtyChild() should never be called."); - return NS_ERROR_NOT_IMPLEMENTED; + NS_NOTREACHED("should never be called on a frame that doesn't inherit from " + "nsContainerFrame"); + return PR_FALSE; } @@ -4703,34 +4813,6 @@ void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui, } } -PRBool -nsFrame::HasStyleChange() -{ - return BoxMetrics()->mStyleChange; -} - -void -nsFrame::SetStyleChangeFlag(PRBool aDirty) -{ - nsBox::SetStyleChangeFlag(aDirty); - BoxMetrics()->mStyleChange = PR_TRUE; -} - -NS_IMETHODIMP -nsFrame::NeedsRecalc() -{ - nsBoxLayoutMetrics *metrics = BoxMetrics(); - - SizeNeedsRecalc(metrics->mPrefSize); - SizeNeedsRecalc(metrics->mMinSize); - SizeNeedsRecalc(metrics->mMaxSize); - SizeNeedsRecalc(metrics->mBlockPrefSize); - SizeNeedsRecalc(metrics->mBlockMinSize); - CoordNeedsRecalc(metrics->mFlex); - CoordNeedsRecalc(metrics->mAscent); - return NS_OK; -} - NS_IMETHODIMP nsFrame::GetOverflow(nsSize& aOverflow) { @@ -4763,28 +4845,16 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) // The min height on the other hand is fairly easy we need to get the largest // line height. This can be done with the line iterator. - // if we do have a reflow state + // if we do have a rendering context nsresult rv = NS_OK; - const nsHTMLReflowState* reflowState = aState.GetReflowState(); - if (reflowState) { + nsIRenderingContext* rendContext = aState.GetRenderingContext(); + if (rendContext) { nsPresContext* presContext = aState.PresContext(); - nsReflowStatus status = NS_FRAME_COMPLETE; - nsHTMLReflowMetrics desiredSize(PR_FALSE); - nsReflowReason reason; - - // See if we an set the max element size and return the reflow states new reason. Sometimes reflow states need to - // be changed. Incremental dirty reflows targeted at us can be converted to Resize if we are not dirty. So make sure - // we look at the reason returned. - nsReflowPath *path = nsnull; - PRBool canSetMaxElementWidth = CanSetMaxElementWidth(aState, reason, &path); - - NS_ASSERTION(reason != eReflowReason_Incremental || path, - "HandleIncrementalReflow should have changed the reason to dirty."); // If we don't have any HTML constraints and its a resize, then nothing in the block // could have changed, so no refresh is necessary. nsBoxLayoutMetrics* metrics = BoxMetrics(); - if (!DoesNeedRecalc(metrics->mBlockPrefSize) && reason == eReflowReason_Resize) + if (!DoesNeedRecalc(metrics->mBlockPrefSize)) return NS_OK; // get the old rect. @@ -4792,92 +4862,53 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) // the rect we plan to size to. nsRect rect(oldRect); - - // if we can set the maxElementSize then - // tell the metrics we want it. And also tell it we want - // to compute the max width. This will allow us to get the min width and the pref width. - if (canSetMaxElementWidth) { - desiredSize.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; - desiredSize.mComputeMEW = PR_TRUE; - } else { - // if we can't set the maxElementSize. Then we must reflow - // uncontrained. - rect.width = NS_UNCONSTRAINEDSIZE; - rect.height = NS_UNCONSTRAINEDSIZE; - } - // Create a child reflow state, fix-up the reason and the - // incremental reflow path. - nsHTMLReflowState childReflowState(*reflowState); - childReflowState.reason = reason; - childReflowState.path = path; + nsMargin bp(0,0,0,0); + GetBorderAndPadding(bp); + + metrics->mBlockPrefSize.width = GetPrefWidth(rendContext) + bp.LeftRight(); + metrics->mBlockMinSize.width = GetMinWidth(rendContext) + bp.LeftRight(); // do the nasty. - rv = BoxReflow(aState, - presContext, - desiredSize, - childReflowState, - status, - rect.x, - rect.y, - rect.width, - rect.height); + nsHTMLReflowMetrics desiredSize; + rv = BoxReflow(aState, presContext, desiredSize, rendContext, + rect.x, rect.y, + metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE); nsRect newRect = GetRect(); // make sure we draw any size change - if (reason == eReflowReason_Incremental && (oldRect.width != newRect.width || oldRect.height != newRect.height)) { - newRect.x = 0; - newRect.y = 0; - Redraw(aState, &newRect); + if (oldRect.width != newRect.width || oldRect.height != newRect.height) { + newRect.x = 0; + newRect.y = 0; + Redraw(aState, &newRect); } - // if someone asked the nsBoxLayoutState to get the max size lets handle that. - nscoord* stateMaxElementWidth = aState.GetMaxElementWidth(); - - // the max element size is the largest height and width - if (stateMaxElementWidth) { - if (metrics->mBlockMinSize.width > *stateMaxElementWidth) - *stateMaxElementWidth = metrics->mBlockMinSize.width; - } - metrics->mBlockMinSize.height = 0; - // if we can use the maxElmementSize then lets use it - // if not then just use the desired. - if (canSetMaxElementWidth) { - metrics->mBlockPrefSize.width = desiredSize.mMaximumWidth; - metrics->mBlockMinSize.width = desiredSize.mMaxElementWidth; - // ok we need the max ascent of the items on the line. So to do this - // ask the block for its line iterator. Get the max ascent. - nsCOMPtr lines = do_QueryInterface(NS_STATIC_CAST(nsIFrame*, this)); - if (lines) - { - metrics->mBlockMinSize.height = 0; - int count = 0; - nsIFrame* firstFrame = nsnull; - PRInt32 framesOnLine; - nsRect lineBounds; - PRUint32 lineFlags; + // ok we need the max ascent of the items on the line. So to do this + // ask the block for its line iterator. Get the max ascent. + nsCOMPtr lines = do_QueryInterface(NS_STATIC_CAST(nsIFrame*, this)); + if (lines) + { + metrics->mBlockMinSize.height = 0; + int count = 0; + nsIFrame* firstFrame = nsnull; + PRInt32 framesOnLine; + nsRect lineBounds; + PRUint32 lineFlags; - do { - lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags); - - if (lineBounds.height > metrics->mBlockMinSize.height) - metrics->mBlockMinSize.height = lineBounds.height; + do { + lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds, &lineFlags); - count++; - } while(firstFrame); - } + if (lineBounds.height > metrics->mBlockMinSize.height) + metrics->mBlockMinSize.height = lineBounds.height; - metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height; - } else { - metrics->mBlockPrefSize.width = desiredSize.width; - metrics->mBlockPrefSize.height = desiredSize.height; - // this sucks. We could not get the width. - metrics->mBlockMinSize.width = 0; - metrics->mBlockMinSize.height = desiredSize.height; + count++; + } while(firstFrame); } + metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height; + metrics->mBlockAscent = desiredSize.ascent; #ifdef DEBUG_adaptor @@ -4895,6 +4926,7 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) NS_IMETHODIMP nsFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); // If the size is cached, and there are no HTML constraints that we might // be depending on, then we just return the cached size. nsBoxLayoutMetrics *metrics = BoxMetrics(); @@ -4935,6 +4967,7 @@ nsFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) NS_IMETHODIMP nsFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); // Don't use the cache if we have HTMLReflowState constraints --- they might have changed nsBoxLayoutMetrics *metrics = BoxMetrics(); if (!DoesNeedRecalc(metrics->mMinSize)) { @@ -4970,6 +5003,7 @@ nsFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize) NS_IMETHODIMP nsFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_MAX_SIZE(this, aSize); // Don't use the cache if we have HTMLReflowState constraints --- they might have changed nsBoxLayoutMetrics *metrics = BoxMetrics(); if (!DoesNeedRecalc(metrics->mMaxSize)) { @@ -5044,27 +5078,16 @@ nsFrame::DoLayout(nsBoxLayoutState& aState) { nsRect ourRect(mRect); - const nsHTMLReflowState* reflowState = aState.GetReflowState(); + nsIRenderingContext* rendContext = aState.GetRenderingContext(); nsPresContext* presContext = aState.PresContext(); - nsReflowStatus status = NS_FRAME_COMPLETE; nsHTMLReflowMetrics desiredSize(PR_FALSE); nsresult rv = NS_OK; - if (reflowState) { + if (rendContext) { - nscoord* currentMEW = aState.GetMaxElementWidth(); - - if (currentMEW) { - desiredSize.mComputeMEW = PR_TRUE; - } - - rv = BoxReflow(aState, presContext, desiredSize, *reflowState, status, + rv = BoxReflow(aState, presContext, desiredSize, rendContext, ourRect.x, ourRect.y, ourRect.width, ourRect.height); - if (currentMEW && desiredSize.mMaxElementWidth > *currentMEW) { - *currentMEW = desiredSize.mMaxElementWidth; - } - PRBool collapsed = PR_FALSE; IsCollapsed(aState, collapsed); if (collapsed) { @@ -5102,38 +5125,18 @@ nsFrame::DoLayout(nsBoxLayoutState& aState) return rv; } -// Truncate the reflow path by pruning the subtree containing the -// specified frame. This ensures that we don't accidentally -// incrementally reflow a frame twice. -// XXXwaterson We could be more efficient by remembering the parent in -// FindReflowPathFor. -static void -PruneReflowPathFor(nsIFrame *aFrame, nsReflowPath *aReflowPath) -{ - nsReflowPath::iterator iter, end = aReflowPath->EndChildren(); - for (iter = aReflowPath->FirstChild(); iter != end; ++iter) { - if (*iter == aFrame) { - aReflowPath->Remove(iter); - break; - } - - PruneReflowPathFor(aFrame, iter.get()); - } -} - nsresult -nsFrame::BoxReflow(nsBoxLayoutState& aState, +nsFrame::BoxReflow(nsBoxLayoutState& aState, nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus, + nsIRenderingContext* aRenderingContext, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aMoveFrame) { - DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor"); #ifdef DEBUG_REFLOW nsAdaptorAddIndents(); @@ -5153,27 +5156,13 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, */ nsBoxLayoutMetrics *metrics = BoxMetrics(); - aStatus = NS_FRAME_COMPLETE; + nsReflowStatus status = NS_FRAME_COMPLETE; PRBool redrawAfterReflow = PR_FALSE; - PRBool needsReflow = PR_FALSE; PRBool redrawNow = PR_FALSE; - nsReflowReason reason; - nsReflowPath *path = nsnull; - HandleIncrementalReflow(aState, - aReflowState, - reason, - &path, - redrawNow, - needsReflow, - redrawAfterReflow, - aMoveFrame); - - // If the NS_REFLOW_CALC_MAX_WIDTH flag is set on the nsHTMLReflowMetrics, - // then we need to do a reflow so that aDesiredSize.mMaximumWidth will be set - // correctly. - needsReflow = needsReflow || (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH); + PRBool needsReflow = + (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0; if (redrawNow) Redraw(aState); @@ -5195,10 +5184,8 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, aDesiredSize.height = metrics->mLastSize.height; // remove the margin. The rect of our child does not include it but our calculated size does. - nscoord calcWidth = aWidth; - nscoord calcHeight = aHeight; // don't reflow if we are already the right size - if (metrics->mLastSize.width == calcWidth && metrics->mLastSize.height == calcHeight) + if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight) needsReflow = PR_FALSE; else needsReflow = PR_TRUE; @@ -5236,71 +5223,24 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, size.width = 0; } - // Create with a reason of resize, and then change the `reason' - // and `path' appropriately (since for incremental reflow, we'll - // be mangling it so completely). - nsHTMLReflowState reflowState(aPresContext, aReflowState, this, - nsSize(size.width, NS_INTRINSICSIZE), - eReflowReason_Resize); - reflowState.reason = reason; - reflowState.path = path; + // XXX Is it OK that this reflow state has no parent reflow state? + // (It used to have a bogus parent, skipping all the boxes). + nsHTMLReflowState reflowState(aPresContext, this, aRenderingContext, + nsSize(aWidth, NS_INTRINSICSIZE)); - // XXX this needs to subtract out the border and padding of mFrame since it is content size + // mComputedWidth and mComputedHeight are content-box, not + // border-box reflowState.mComputedWidth = size.width; reflowState.mComputedHeight = size.height; - // if we were marked for style change. - // 1) see if we are just supposed to do a resize if so convert to a style change. Kill 2 birds - // with 1 stone. - // 2) If the command is incremental. See if its style change. If it is everything is ok if not - // we need to do a second reflow with the style change. - // XXXwaterson This logic seems _very_ squirrely. - if (metrics->mStyleChange) { - if (reflowState.reason == eReflowReason_Resize) { - // maxElementSize does not work on style change reflows. - // so remove it if set. - // XXXwaterson why doesn't MES computation work with a style change reflow? - aDesiredSize.mComputeMEW = PR_FALSE; - - reflowState.reason = eReflowReason_StyleChange; - } - else if (reason == eReflowReason_Incremental) { - PRBool reflowChild = PR_TRUE; - - if (path->mReflowCommand && - path->FirstChild() == path->EndChildren() && - path->mReflowCommand->Type() == eReflowType_StyleChanged) { - // There's an incremental reflow targeted directly at our - // frame, and our frame only (i.e., none of our descendants - // are targets). - reflowChild = PR_FALSE; - } - - if (reflowChild) { -#ifdef DEBUG_waterson - printf("*** nsBoxToBlockAdaptor::Reflow: performing extra reflow on child frame\n"); -#endif - -#ifdef DEBUG_REFLOW - nsAdaptorAddIndents(); - printf("Size=(%d,%d)\n",reflowState.mComputedWidth, reflowState.mComputedHeight); - nsAdaptorAddIndents(); - nsAdaptorPrintReason(reflowState); - printf("\n"); -#endif - - WillReflow(aPresContext); - Reflow(aPresContext, aDesiredSize, reflowState, aStatus); - DidReflow(aPresContext, &reflowState, NS_FRAME_REFLOW_FINISHED); - reflowState.mComputedWidth = aDesiredSize.width - (border.left + border.right); - reflowState.availableWidth = reflowState.mComputedWidth; - reflowState.reason = eReflowReason_StyleChange; - reflowState.path = nsnull; - } - } - - metrics->mStyleChange = PR_FALSE; - } + // Box layout calls SetRect before Layout, whereas non-box layout + // calls SetRect after Reflow. + // XXX Perhaps we should be doing this by twiddling the rect back to + // mLastSize before calling Reflow and then switching it back, but + // I'm not sure mLastSize is guaranteed to be what it was before + // LayoutChildAt changed it. + if (metrics->mLastSize != GetSize()) + reflowState.mFlags.mIsResize = PR_TRUE; #ifdef DEBUG_REFLOW nsAdaptorAddIndents(); @@ -5313,9 +5253,9 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, // place the child and reflow WillReflow(aPresContext); - Reflow(aPresContext, aDesiredSize, reflowState, aStatus); + Reflow(aPresContext, aDesiredSize, reflowState, status); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); + NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status"); // Save the ascent. (bug 103925) PRBool isCollapsed = PR_FALSE; @@ -5350,16 +5290,15 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, { reflowState.mComputedWidth = aDesiredSize.width - (border.left + border.right); reflowState.availableWidth = reflowState.mComputedWidth; - reflowState.reason = eReflowReason_Resize; - reflowState.path = nsnull; DidReflow(aPresContext, &reflowState, NS_FRAME_REFLOW_FINISHED); #ifdef DEBUG_REFLOW nsAdaptorAddIndents(); nsAdaptorPrintReason(reflowState); printf("\n"); #endif + AddStateBits(NS_FRAME_IS_DIRTY); WillReflow(aPresContext); - Reflow(aPresContext, aDesiredSize, reflowState, aStatus); + Reflow(aPresContext, aDesiredSize, reflowState, status); if (GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN) aDesiredSize.height = aDesiredSize.mOverflowArea.YMost(); @@ -5390,12 +5329,6 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, aDesiredSize.ascent = metrics->mBlockAscent; } - // Clip the path we just reflowed, so that we don't incrementally - // reflow it again: subsequent reflows will be treated as resize - // reflows. - if (path) - PruneReflowPathFor(path->mFrame, aReflowState.path); - #ifdef DEBUG_REFLOW if (aHeight != NS_INTRINSICSIZE && aDesiredSize.height != aHeight) { @@ -5424,124 +5357,9 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, gIndent2--; #endif - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; } -// Look for aFrame in the specified reflow path's tree, returning the -// reflow path node corresponding to the frame if we find it. -static nsReflowPath * -FindReflowPathFor(nsIFrame *aFrame, nsReflowPath *aReflowPath) -{ - nsReflowPath::iterator iter, end = aReflowPath->EndChildren(); - for (iter = aReflowPath->FirstChild(); iter != end; ++iter) { - if (*iter == aFrame) - return iter.get(); - - nsReflowPath *subtree = FindReflowPathFor(aFrame, iter.get()); - if (subtree) - return subtree; - } - - return nsnull; -} - -void -nsFrame::HandleIncrementalReflow(nsBoxLayoutState& aState, - const nsHTMLReflowState& aReflowState, - nsReflowReason& aReason, - nsReflowPath** aReflowPath, - PRBool& aRedrawNow, - PRBool& aNeedsReflow, - PRBool& aRedrawAfterReflow, - PRBool& aMoveFrame) -{ - nsFrameState childState = GetStateBits(); - - aReason = aReflowState.reason; - - // handle or different types of reflow - switch(aReason) - { - // if the child we are reflowing is the child we popped off the incremental - // reflow chain then we need to reflow it no matter what. - // if its not the child we got from the reflow chain then this child needs reflow - // because as a side effect of the incremental child changing size it needs to be resized. - // This will happen a lot when a box that contains 2 children with different flexibilities - // if on child gets bigger the other is affected because it is proprotional to the first. - // so it might need to be resized. But we don't need to reflow it. If it is already the - // needed size then we will do nothing. - case eReflowReason_Incremental: { - - // Grovel through the reflow path's children to find the path - // that corresponds to the current frame. If we can't find a - // child, then we'll convert the reflow to a dirty reflow, - // below. - nsReflowPath *path = FindReflowPathFor(this, aReflowState.path); - if (path) { - aNeedsReflow = PR_TRUE; - - // Return the path that we've found so that HTML incremental - // reflow can proceed normally. - if (aReflowPath) - *aReflowPath = path; - - // if we hit the target then we have used up the chain. - // next time a layout - break; - } - - // fall into dirty if the incremental child was use. It should be treated as a - } - - // if its dirty then see if the child we want to reflow is dirty. If it is then - // mark it as needing to be reflowed. - case eReflowReason_Dirty: { - // XXX nsBlockFrames don't seem to be able to handle a reason of Dirty. So we - // send down a resize instead. If we did send down the dirty we would have wrapping problems. If you - // look at the main page it will initially come up ok but will have a unneeded horizontal - // scrollbar if you resize it will fix it self. The real fix is to fix block frame but - // this will fix it for beta3. - if (childState & NS_FRAME_FIRST_REFLOW) - aReason = eReflowReason_Initial; - else - aReason = eReflowReason_Resize; - - // get the frame state to see if it needs reflow - aNeedsReflow = BoxMetrics()->mStyleChange || (childState & NS_FRAME_IS_DIRTY) || (childState & NS_FRAME_HAS_DIRTY_CHILDREN); - - // but of course by definition dirty reflows are supposed to redraw so - // lets signal that we need to do that. We want to do it after as well because - // the object may have changed size. - if (aNeedsReflow) { - aRedrawNow = PR_TRUE; - aRedrawAfterReflow = PR_TRUE; - //printf("Redrawing!!!/n"); - } - - } break; - - // if the a resize reflow then it doesn't need to be reflowed. Only if the size is different - // from the new size would we actually do a reflow - case eReflowReason_Resize: - // blocks sometimes send resizes even when its children are dirty! We need to make sure we - // repair in these cases. So check the flags here. - aNeedsReflow = BoxMetrics()->mStyleChange || (childState & NS_FRAME_IS_DIRTY) || (childState & NS_FRAME_HAS_DIRTY_CHILDREN); - break; - - // if its an initial reflow we must place the child. - // otherwise we might think it was already placed when it wasn't - case eReflowReason_Initial: - aMoveFrame = PR_TRUE; - aNeedsReflow = PR_TRUE; - break; - - default: - aNeedsReflow = PR_TRUE; - - } -} - PRBool nsFrame::GetWasCollapsed(nsBoxLayoutState& aState) { @@ -5554,40 +5372,6 @@ nsFrame::SetWasCollapsed(nsBoxLayoutState& aState, PRBool aCollapsed) BoxMetrics()->mWasCollapsed = aCollapsed; } -PRBool -nsFrame::CanSetMaxElementWidth(nsBoxLayoutState& aState, nsReflowReason& aReason, nsReflowPath **aReflowPath) -{ - PRBool redrawAfterReflow = PR_FALSE; - PRBool needsReflow = PR_FALSE; - PRBool redrawNow = PR_FALSE; - PRBool move = PR_TRUE; - const nsHTMLReflowState* reflowState = aState.GetReflowState(); - - HandleIncrementalReflow(aState, - *reflowState, - aReason, - aReflowPath, - redrawNow, - needsReflow, - redrawAfterReflow, - move); - - // only incremental reflows can handle maxelementsize being set. - if (reflowState->reason == eReflowReason_Incremental) { - nsReflowPath *path = *aReflowPath; - if (path && path->mReflowCommand && - path->mReflowCommand->Type() == eReflowType_StyleChanged) { - // MaxElement doesn't work on style change reflows.. :-( - // XXXwaterson why? - return PR_FALSE; - } - - return PR_TRUE; - } - - return PR_FALSE; -} - nsBoxLayoutMetrics* nsFrame::BoxMetrics() const { @@ -5639,13 +5423,12 @@ nsFrame::InitBoxMetrics(PRBool aClear) nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics(); SetProperty(nsLayoutAtoms::boxMetricsProperty, metrics, DeleteBoxMetrics); - NeedsRecalc(); + nsFrame::MarkIntrinsicWidthsDirty(); metrics->mBlockAscent = 0; metrics->mLastSize.SizeTo(0, 0); metrics->mOverflow.SizeTo(0, 0); metrics->mIncludeOverflow = PR_TRUE; metrics->mWasCollapsed = PR_FALSE; - metrics->mStyleChange = PR_FALSE; } // Box layout debugging @@ -5800,6 +5583,61 @@ DR_cookie::~DR_cookie() nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue); } +MOZ_DECL_CTOR_COUNTER(DR_layout_cookie) + +DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame) + : mFrame(aFrame) +{ + MOZ_COUNT_CTOR(DR_layout_cookie); + mValue = nsFrame::DisplayLayoutEnter(mFrame); +} + +DR_layout_cookie::~DR_layout_cookie() +{ + MOZ_COUNT_DTOR(DR_layout_cookie); + nsFrame::DisplayLayoutExit(mFrame, mValue); +} + +MOZ_DECL_CTOR_COUNTER(DR_intrinsic_width_cookie) + +DR_intrinsic_width_cookie::DR_intrinsic_width_cookie( + nsIFrame* aFrame, + const char* aType, + nscoord& aResult) + : mFrame(aFrame) + , mType(aType) + , mResult(aResult) +{ + MOZ_COUNT_CTOR(DR_intrinsic_width_cookie); + mValue = nsFrame::DisplayIntrinsicWidthEnter(mFrame, mType); +} + +DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie() +{ + MOZ_COUNT_DTOR(DR_intrinsic_width_cookie); + nsFrame::DisplayIntrinsicWidthExit(mFrame, mType, mResult, mValue); +} + +MOZ_DECL_CTOR_COUNTER(DR_intrinsic_size_cookie) + +DR_intrinsic_size_cookie::DR_intrinsic_size_cookie( + nsIFrame* aFrame, + const char* aType, + nsSize& aResult) + : mFrame(aFrame) + , mType(aType) + , mResult(aResult) +{ + MOZ_COUNT_CTOR(DR_intrinsic_size_cookie); + mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType); +} + +DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie() +{ + MOZ_COUNT_DTOR(DR_intrinsic_size_cookie); + nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue); +} + struct DR_FrameTypeInfo; struct DR_FrameTreeNode; struct DR_Rule; @@ -5816,7 +5654,7 @@ struct DR_State DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName); void InitFrameTypeTable(); DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame, - const nsHTMLReflowState& aReflowState); + const nsHTMLReflowState* aReflowState); void FindMatchingRule(DR_FrameTreeNode& aNode); PRBool RuleMatches(DR_Rule& aRule, DR_FrameTreeNode& aNode); @@ -5840,7 +5678,7 @@ struct DR_State PRInt32 mCount; nsVoidArray mWildRules; PRInt32 mAssert; - PRInt32 mIndentStart; + PRInt32 mIndent; PRBool mIndentUndisplayedFrames; nsVoidArray mFrameTypeTable; PRBool mDisplayPixelErrors; @@ -5949,7 +5787,7 @@ struct DR_FrameTreeNode MOZ_DECL_CTOR_COUNTER(DR_State) DR_State::DR_State() -: mInited(PR_FALSE), mActive(PR_FALSE), mCount(0), mAssert(-1), mIndentStart(0), +: mInited(PR_FALSE), mActive(PR_FALSE), mCount(0), mAssert(-1), mIndent(0), mIndentUndisplayedFrames(PR_FALSE), mDisplayPixelErrors(PR_FALSE) { MOZ_COUNT_CTOR(DR_State); @@ -5969,7 +5807,7 @@ void DR_State::Init() env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START"); if (env) { if (GetNumber(env, num)) - mIndentStart = num; + mIndent = num; else printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env); } @@ -6285,21 +6123,19 @@ void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode) } } } - - if (aNode.mParent) { - aNode.mIndent = aNode.mParent->mIndent; - if (aNode.mDisplay || mIndentUndisplayedFrames) { - aNode.mIndent++; - } - } } DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame, - const nsHTMLReflowState& aReflowState) + const nsHTMLReflowState* aReflowState) { // find the frame of the parent reflow state (usually just the parent of aFrame) - const nsHTMLReflowState* parentRS = aReflowState.parentReflowState; - nsIFrame* parentFrame = (parentRS) ? parentRS->frame : nsnull; + nsIFrame* parentFrame; + if (aReflowState) { + const nsHTMLReflowState* parentRS = aReflowState->parentReflowState; + parentFrame = (parentRS) ? parentRS->frame : nsnull; + } else { + parentFrame = aFrame->GetParent(); + } // find the parent tree node leaf DR_FrameTreeNode* parentNode = nsnull; @@ -6313,6 +6149,12 @@ DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame, } DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode); FindMatchingRule(*newNode); + + newNode->mIndent = mIndent; + if (newNode->mDisplay || mIndentUndisplayedFrames) { + ++mIndent; + } + if (lastLeaf && (lastLeaf == parentNode)) { mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Count() - 1); } @@ -6346,6 +6188,10 @@ void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode) if ((0 == numLeaves) || (aNode.mParent != (DR_FrameTreeNode*)mFrameTreeLeaves.ElementAt(numLeaves - 1))) { mFrameTreeLeaves.AppendElement(aNode.mParent); } + + if (aNode.mDisplay || mIndentUndisplayedFrames) { + --mIndent; + } // delete the tree node delete &aNode; } @@ -6375,26 +6221,7 @@ static void DisplayReflowEnterPrint(nsPresContext* aPresContext, DR_state->PrettyUC(aReflowState.availableWidth, width); DR_state->PrettyUC(aReflowState.availableHeight, height); - if (aReflowState.path && aReflowState.path->mReflowCommand) { - const char *incr_reason; - switch(aReflowState.path->mReflowCommand->Type()) { - case eReflowType_ContentChanged: - incr_reason = "incr. (Content)"; - break; - case eReflowType_StyleChanged: - incr_reason = "incr. (Style)"; - break; - case eReflowType_ReflowDirty: - incr_reason = "incr. (Dirty)"; - break; - default: - incr_reason = "incr. (Unknown)"; - } - printf("r=%d %s a=%s,%s ", aReflowState.reason, incr_reason, width, height); - } - else { - printf("r=%d a=%s,%s ", aReflowState.reason, width, height); - } + printf("Reflow a=%s,%s ", width, height); DR_state->PrettyUC(aReflowState.mComputedWidth, width); DR_state->PrettyUC(aReflowState.mComputedHeight, height); @@ -6431,13 +6258,60 @@ void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext, NS_ASSERTION(aFrame, "invalid call"); - DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aReflowState); + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowState); if (treeNode) { DisplayReflowEnterPrint(aPresContext, aFrame, aReflowState, *treeNode, PR_FALSE); } return treeNode; } +void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame) +{ + if (!DR_state->mInited) DR_state->Init(); + if (!DR_state->mActive) return nsnull; + + NS_ASSERTION(aFrame, "invalid call"); + + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull); + if (treeNode && treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + printf("Layout\n"); + } + return treeNode; +} + +void* nsFrame::DisplayIntrinsicWidthEnter(nsIFrame* aFrame, + const char* aType) +{ + if (!DR_state->mInited) DR_state->Init(); + if (!DR_state->mActive) return nsnull; + + NS_ASSERTION(aFrame, "invalid call"); + + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull); + if (treeNode && treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + printf("Get%sWidth\n", aType); + } + return treeNode; +} + +void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame, + const char* aType) +{ + if (!DR_state->mInited) DR_state->Init(); + if (!DR_state->mActive) return nsnull; + + NS_ASSERTION(aFrame, "invalid call"); + + DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nsnull); + if (treeNode && treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + printf("Get%sSize\n", aType); + } + return treeNode; +} + void nsFrame::DisplayReflowExit(nsPresContext* aPresContext, nsIFrame* aFrame, nsHTMLReflowMetrics& aMetrics, @@ -6459,16 +6333,8 @@ void nsFrame::DisplayReflowExit(nsPresContext* aPresContext, char y[16]; DR_state->PrettyUC(aMetrics.width, width); DR_state->PrettyUC(aMetrics.height, height); - printf("d=%s,%s ", width, height); + printf("Reflow d=%s,%s ", width, height); - if (aMetrics.mComputeMEW) { - DR_state->PrettyUC(aMetrics.mMaxElementWidth, width); - printf("me=%s ", width); - } - if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - DR_state->PrettyUC(aMetrics.mMaximumWidth, width); - printf("m=%s ", width); - } if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { printf("status=0x%x", aStatus); } @@ -6494,15 +6360,69 @@ void nsFrame::DisplayReflowExit(nsPresContext* aPresContext, float p2t = aPresContext->ScaledPixelsToTwips(); CheckPixelError(aMetrics.width, p2t); CheckPixelError(aMetrics.height, p2t); - if (aMetrics.mComputeMEW) - CheckPixelError(aMetrics.mMaxElementWidth, p2t); - if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) - CheckPixelError(aMetrics.mMaximumWidth, p2t); } } DR_state->DeleteTreeNode(*treeNode); } +void nsFrame::DisplayLayoutExit(nsIFrame* aFrame, + void* aFrameTreeNode) +{ + if (!DR_state->mActive) return; + + NS_ASSERTION(aFrame, "non-null frame required"); + if (!aFrameTreeNode) return; + + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; + if (treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + nsRect rect = aFrame->GetRect(); + printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height); + } + DR_state->DeleteTreeNode(*treeNode); +} + +void nsFrame::DisplayIntrinsicWidthExit(nsIFrame* aFrame, + const char* aType, + nscoord aResult, + void* aFrameTreeNode) +{ + if (!DR_state->mActive) return; + + NS_ASSERTION(aFrame, "non-null frame required"); + if (!aFrameTreeNode) return; + + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; + if (treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + printf("Get%sWidth=%d\n", aType, aResult); + } + DR_state->DeleteTreeNode(*treeNode); +} + +void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame, + const char* aType, + nsSize aResult, + void* aFrameTreeNode) +{ + if (!DR_state->mActive) return; + + NS_ASSERTION(aFrame, "non-null frame required"); + if (!aFrameTreeNode) return; + + DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode; + if (treeNode->mDisplay) { + DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent); + + char width[16]; + char height[16]; + DR_state->PrettyUC(aResult.width, width); + DR_state->PrettyUC(aResult.height, height); + printf("Get%sSize=%s,%s\n", aType, width, height); + } + DR_state->DeleteTreeNode(*treeNode); +} + /* static */ void nsFrame::DisplayReflowStartup() { diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index c3d93144005..e65cf10f265 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -47,7 +47,6 @@ #endif #include "nsIPresShell.h" -#include "nsHTMLReflowCommand.h" #include "nsIFrameSelection.h" #include "nsHTMLReflowState.h" #include "nsHTMLReflowMetrics.h" @@ -253,7 +252,7 @@ public: NS_IMETHOD PeekOffsetParagraph(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos); NS_IMETHOD GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const; - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); + virtual PRBool ChildIsDirty(nsIFrame* aChild); #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); @@ -272,7 +271,14 @@ public: virtual PRBool IsEmpty(); virtual PRBool IsSelfEmpty(); - // nsIHTMLReflow + virtual void MarkIntrinsicWidthsDirty(); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); + NS_IMETHOD WillReflow(nsPresContext* aPresContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -329,7 +335,6 @@ public: NS_IMETHOD GetAscent(nsBoxLayoutState& aBoxLayoutState, nscoord& aAscent); NS_IMETHOD SetIncludeOverflow(PRBool aInclude); NS_IMETHOD GetOverflow(nsSize& aOverflow); - NS_IMETHOD NeedsRecalc(); //-------------------------------------------------- // Additional methods @@ -434,11 +439,26 @@ public: static void* DisplayReflowEnter(nsPresContext* aPresContext, nsIFrame* aFrame, const nsHTMLReflowState& aReflowState); + static void* DisplayLayoutEnter(nsIFrame* aFrame); + static void* DisplayIntrinsicWidthEnter(nsIFrame* aFrame, + const char* aType); + static void* DisplayIntrinsicSizeEnter(nsIFrame* aFrame, + const char* aType); static void DisplayReflowExit(nsPresContext* aPresContext, nsIFrame* aFrame, nsHTMLReflowMetrics& aMetrics, PRUint32 aStatus, void* aFrameTreeNode); + static void DisplayLayoutExit(nsIFrame* aFrame, + void* aFrameTreeNode); + static void DisplayIntrinsicWidthExit(nsIFrame* aFrame, + const char* aType, + nscoord aResult, + void* aFrameTreeNode); + static void DisplayIntrinsicSizeExit(nsIFrame* aFrame, + const char* aType, + nsSize aResult, + void* aFrameTreeNode); static void DisplayReflowStartup(); static void DisplayReflowShutdown(); @@ -511,8 +531,6 @@ protected: #ifdef DEBUG_LAYOUT virtual void GetBoxName(nsAutoString& aName); #endif - virtual PRBool HasStyleChange(); - virtual void SetStyleChangeFlag(PRBool aDirty); virtual PRBool GetWasCollapsed(nsBoxLayoutState& aState); virtual void SetWasCollapsed(nsBoxLayoutState& aState, PRBool aWas); @@ -524,27 +542,13 @@ private: nsresult BoxReflow(nsBoxLayoutState& aState, nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus, + nsIRenderingContext* aRenderingContext, nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aMoveFrame = PR_TRUE); - void HandleIncrementalReflow(nsBoxLayoutState& aState, - const nsHTMLReflowState& aReflowState, - nsReflowReason& aReason, - nsReflowPath** aReflowPath, - PRBool& aRedrawNow, - PRBool& aNeedReflow, - PRBool& aRedrawAfterReflow, - PRBool& aMoveFrame); - - PRBool CanSetMaxElementWidth(nsBoxLayoutState& aState, - nsReflowReason& aReason, - nsReflowPath **aReflowPath); - NS_IMETHODIMP RefreshSizeCache(nsBoxLayoutState& aState); protected: @@ -571,16 +575,64 @@ protected: nsReflowStatus& mStatus; void* mValue; }; + + struct DR_layout_cookie { + DR_layout_cookie(nsIFrame* aFrame); + ~DR_layout_cookie(); + + nsIFrame* mFrame; + void* mValue; + }; + + struct DR_intrinsic_width_cookie { + DR_intrinsic_width_cookie(nsIFrame* aFrame, const char* aType, + nscoord& aResult); + ~DR_intrinsic_width_cookie(); + + nsIFrame* mFrame; + const char* mType; + nscoord& mResult; + void* mValue; + }; + + struct DR_intrinsic_size_cookie { + DR_intrinsic_size_cookie(nsIFrame* aFrame, const char* aType, + nsSize& aResult); + ~DR_intrinsic_size_cookie(); + + nsIFrame* mFrame; + const char* mType; + nsSize& mResult; + void* mValue; + }; #define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status) \ DR_cookie dr_cookie(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status); #define DISPLAY_REFLOW_CHANGE() \ dr_cookie.Change(); +#define DISPLAY_LAYOUT(dr_frame) \ + DR_layout_cookie dr_cookie(dr_frame); +#define DISPLAY_MIN_WIDTH(dr_frame, dr_result) \ + DR_intrinsic_width_cookie dr_cookie(dr_frame, "Min", dr_result) +#define DISPLAY_PREF_WIDTH(dr_frame, dr_result) \ + DR_intrinsic_width_cookie dr_cookie(dr_frame, "Pref", dr_result) +#define DISPLAY_PREF_SIZE(dr_frame, dr_result) \ + DR_intrinsic_size_cookie dr_cookie(dr_frame, "Pref", dr_result) +#define DISPLAY_MIN_SIZE(dr_frame, dr_result) \ + DR_intrinsic_size_cookie dr_cookie(dr_frame, "Min", dr_result) +#define DISPLAY_MAX_SIZE(dr_frame, dr_result) \ + DR_intrinsic_size_cookie dr_cookie(dr_frame, "Max", dr_result) #else #define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status) #define DISPLAY_REFLOW_CHANGE() +#define DISPLAY_LAYOUT(dr_frame) PR_BEGIN_MACRO PR_END_MACRO +#define DISPLAY_MIN_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO +#define DISPLAY_PREF_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO +#define DISPLAY_PREF_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO +#define DISPLAY_MIN_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO +#define DISPLAY_MAX_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO #endif // End Display Reflow Debugging diff --git a/mozilla/layout/generic/nsFrameFrame.cpp b/mozilla/layout/generic/nsFrameFrame.cpp index 5e0902095b3..f4d215da40c 100644 --- a/mozilla/layout/generic/nsFrameFrame.cpp +++ b/mozilla/layout/generic/nsFrameFrame.cpp @@ -123,6 +123,9 @@ public: NS_IMETHOD Destroy(nsPresContext* aPresContext); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); + NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -334,18 +337,40 @@ nsSubDocumentFrame::GetType() const return nsLayoutAtoms::subDocumentFrame; } +/* virtual */ nscoord +nsSubDocumentFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + return nsSubDocumentFrame::GetPrefWidth(aRenderingContext); +} + +/* virtual */ nscoord +nsSubDocumentFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + // XUL frames don't have a default 300px width + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + if (mContent->IsContentOfType(nsIContent::eXUL) || + // XXX Should we really treat percentages differently on iframes than + // other things? + GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Percent) + result = 0; + else + result = NSIntPixelsToTwips(300, GetPresContext()->ScaledPixelsToTwips()); + return result; +} + NS_IMETHODIMP nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, - ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d reason=%d", - aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason)); + ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d", + aReflowState.availableWidth, aReflowState.availableHeight)); aStatus = NS_FRAME_COMPLETE; @@ -373,33 +398,6 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, vm->ResizeView(mInnerView, nsRect(0, 0, innerSize.width, innerSize.height), PR_TRUE); } - if (aDesiredSize.mComputeMEW) { - nscoord defaultAutoWidth = NSIntPixelsToTwips(300, aPresContext->ScaledPixelsToTwips()); - if (mContent->IsContentOfType(nsIContent::eXUL)) { - // XUL frames don't have a default 300px width - defaultAutoWidth = 0; - } - nsStyleUnit widthUnit = GetStylePosition()->mWidth.GetUnit(); - switch (widthUnit) { - case eStyleUnit_Percent: - // if our width is percentage, then we can shrink until - // there's nothing left but our borders - aDesiredSize.mMaxElementWidth = border.left + border.right; - break; - case eStyleUnit_Auto: - aDesiredSize.mMaxElementWidth = PR_MAX(PR_MIN(defaultAutoWidth, - aReflowState.mComputedMaxWidth), - aReflowState.mComputedMinWidth) + - border.left + border.right; - break; - default: - // If our width is set by style to some fixed length, - // then our actual width is our minimum width - aDesiredSize.mMaxElementWidth = aDesiredSize.width; - break; - } - } - // Determine if we need to repaint our border, background or outline CheckInvalidateSizeChange(aPresContext, aDesiredSize, aReflowState); @@ -427,9 +425,8 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, } } - // printf("OuterFrame::Reflow DONE %X (%d,%d), MEW=%d(%d)\n", this, - // aDesiredSize.width, aDesiredSize.height, aDesiredSize.mMaxElementWidth, - // aDesiredSize.mComputeMEW); + // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this, + // aDesiredSize.width, aDesiredSize.height); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x", diff --git a/mozilla/layout/generic/nsFrameSetFrame.cpp b/mozilla/layout/generic/nsFrameSetFrame.cpp index 2c3e04080b3..79da6d48c27 100644 --- a/mozilla/layout/generic/nsFrameSetFrame.cpp +++ b/mozilla/layout/generic/nsFrameSetFrame.cpp @@ -977,7 +977,7 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); nsIPresShell *shell = aPresContext->PresShell(); nsStyleSet *styleSet = shell->StyleSet(); @@ -991,7 +991,7 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, nscoord height = (aDesiredSize.height <= aReflowState.availableHeight) ? aDesiredSize.height : aReflowState.availableHeight; - PRBool firstTime = (eReflowReason_Initial == aReflowState.reason); + PRBool firstTime = (GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; if (firstTime) { nsContentUtils::RegisterPrefCallback(kFrameResizePref, FrameResizePrefCallback, this); @@ -1248,10 +1248,6 @@ nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext, mChildBorderColors = nsnull; } - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = aDesiredSize.width; - } - aStatus = NS_FRAME_COMPLETE; mDrag.UnSet(); @@ -1630,7 +1626,7 @@ nsHTMLFramesetBorderFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBorderFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBorderFrame"); GetDesiredSize(aPresContext, aReflowState, aDesiredSize); aStatus = NS_FRAME_COMPLETE; return NS_OK; @@ -1811,7 +1807,7 @@ nsHTMLFramesetBlankFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBlankFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBlankFrame"); GetDesiredSize(aPresContext, aReflowState, aDesiredSize); aStatus = NS_FRAME_COMPLETE; return NS_OK; diff --git a/mozilla/layout/generic/nsGfxScrollFrame.cpp b/mozilla/layout/generic/nsGfxScrollFrame.cpp index 68086e00d6c..163b6b4f76c 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.cpp +++ b/mozilla/layout/generic/nsGfxScrollFrame.cpp @@ -38,7 +38,6 @@ #include "nsCOMPtr.h" #include "nsHTMLParts.h" #include "nsPresContext.h" -#include "nsReflowType.h" #include "nsIDeviceContext.h" #include "nsPageFrame.h" #include "nsViewsCID.h" @@ -77,6 +76,7 @@ #include "nsPresState.h" #include "nsIGlobalHistory2.h" #include "nsDocShellCID.h" +#include "nsLayoutUtils.h" #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif @@ -260,7 +260,6 @@ struct ScrollReflowState { const nsHTMLReflowState& mReflowState; nsBoxLayoutState mBoxState; nsGfxScrollFrameInner::ScrollbarStyles mStyles; - nsReflowReason mNewReason; nsMargin mComputedBorder; // === Filled in when TryLayout succeeds === @@ -270,21 +269,15 @@ struct ScrollReflowState { nsSize mInsideBorderSize; // Taken from kid metrics; ascent from the inner-border top edge nscoord mAscent; - // Taken from kid metrics; does not include our border widths, - // does include vertical scrollbar if present - nscoord mMaxElementWidth; - // Taken from kid metrics; does not include our border widths, - // does include vertical scrollbar if present - nscoord mMaximumWidth; // Whether we decided to show the horizontal scrollbar PRPackedBool mShowHScrollbar; // Whether we decided to show the vertical scrollbar PRPackedBool mShowVScrollbar; ScrollReflowState(nsIScrollableFrame* aFrame, - const nsHTMLReflowState& aState, nsHTMLReflowMetrics& aMetrics) : + const nsHTMLReflowState& aState) : mReflowState(aState), - mBoxState(aState.frame->GetPresContext(), aState, aMetrics), + mBoxState(aState.frame->GetPresContext(), aState.rendContext), mStyles(aFrame->GetScrollbarStyles()) { } }; @@ -425,48 +418,6 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowState* aState, } aState->mScrollPortRect = nsRect(scrollPortOrigin, scrollPortSize); aState->mAscent = aKidMetrics.ascent; - if (aKidMetrics.mComputeMEW) { - // XXXBernd the following code is controversial see bug 295459 and bug - // 234593, however to get the main customer of MEW - tables happy. It - // seems to be necessary - // It looks at the MEW as the minimum width that the parent has to give its - // children so that the childs margin box can layout its content without - // overflowing the parents content box. If the child has a fixed width - // the MEW will be allways this width regardless whether it makes the grand - // children overflow the child. Please notice that fixed widths for table - // related frames are not covered by this as they mean more a min-width. - // - // This means for scrolling boxes that if the width is auto or percent - // their content box can be squeezed down to 0, as they will either create - // a scrollbar so that content of the scrollframe will not leak out or it - // will cut the content at the frame boundaries. - - // The width of the vertical scrollbar comes out of the budget for the - // content width (see above where we include the scrollbar width before - // we call ComputeInsideBorderSize, which overrides the given - // width with the style computed width if there is one). So allow - // the vertical scrollbar width to be overridden by style information - // here, too. - nscoord minContentWidth = - aState->mReflowState.AdjustIntrinsicMinContentWidthForStyle(vScrollbarActualWidth); - aState->mMaxElementWidth = minContentWidth + - aState->mReflowState.mComputedPadding.LeftRight(); - // borders get added on the way out of Reflow() - } - if (aKidMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - // We need to do what we did above: include the vertical scrollbar width in the - // content width before applying style. - nscoord kidMaxWidth = aKidMetrics.mMaximumWidth; - if (kidMaxWidth != NS_UNCONSTRAINEDSIZE) { - nscoord kidContentMaxWidth = kidMaxWidth - - aState->mReflowState.mComputedPadding.LeftRight() + vScrollbarActualWidth; - NS_ASSERTION(kidContentMaxWidth >= 0, "max-width didn't include padding?"); - kidMaxWidth = aState->mReflowState.mComputedPadding.LeftRight() + - aState->mReflowState.AdjustIntrinsicContentWidthForStyle(kidContentMaxWidth); - } - aState->mMaximumWidth = kidMaxWidth; - // borders get added on the way out of Reflow() - } return PR_TRUE; } @@ -505,10 +456,11 @@ nsHTMLScrollFrame::ReflowScrolledFrame(const ScrollReflowState& aState, availWidth -= availWidth % twp; } + if (!aFirstPass) + mInner.mScrolledFrame->AddStateBits(NS_FRAME_IS_DIRTY); nsHTMLReflowState kidReflowState(GetPresContext(), aState.mReflowState, mInner.mScrolledFrame, - nsSize(availWidth, NS_UNCONSTRAINEDSIZE), - aFirstPass ? aState.mNewReason : eReflowReason_Resize); + nsSize(availWidth, NS_UNCONSTRAINEDSIZE)); if (IsRTLTextControl()) { kidReflowState.mRightEdge = mInner.GetScrolledSize().width; @@ -555,7 +507,7 @@ nsHTMLScrollFrame::GuessVScrollbarNeeded(const ScrollReflowState& aState) // If this is the initial reflow, guess PR_FALSE because usually // we have very little content by then. - if (aState.mReflowState.reason == eReflowReason_Initial) + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) return PR_FALSE; if (mInner.mIsRoot) { @@ -636,7 +588,7 @@ nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState, // That didn't work. Try the other setting for the vertical scrollbar. // But don't try to show a scrollbar if we know there can't be one. if (currentlyUsingVScrollbar || canHaveVerticalScrollbar) { - nsHTMLReflowMetrics kidRetrySize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); + nsHTMLReflowMetrics kidRetrySize(aDesiredSize.mFlags); rv = ReflowScrolledFrame(*aState, !currentlyUsingVScrollbar, &kidRetrySize, PR_FALSE); if (NS_FAILED(rv)) @@ -709,16 +661,60 @@ nsHTMLScrollFrame::IsRTLTextControl() return PR_FALSE; } +/* virtual */ nscoord +nsHTMLScrollFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + // XXX Might this make us count padding/border/margin twice? + result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + mInner.mScrolledFrame, nsLayoutUtils::MIN_WIDTH); + + nsGfxScrollFrameInner::ScrollbarStyles ss = GetScrollbarStyles(); + if (ss.mVertical == NS_STYLE_OVERFLOW_SCROLL && // ideal? + mInner.mVScrollbarBox) { + nsBoxLayoutState bls(GetPresContext()); + nsSize vScrollbarMinSize(0, 0); + GetScrollbarMetrics(bls, mInner.mVScrollbarBox, + &vScrollbarMinSize, nsnull, PR_TRUE); + result += vScrollbarMinSize.width; + } + + return result; +} + +/* virtual */ nscoord +nsHTMLScrollFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + // XXX Might this make us count padding/border/margin twice? + result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, + mInner.mScrolledFrame, nsLayoutUtils::PREF_WIDTH); + + nsGfxScrollFrameInner::ScrollbarStyles ss = GetScrollbarStyles(); + if (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN && // ideal? + mInner.mVScrollbarBox) { + nsBoxLayoutState bls(GetPresContext()); + nsSize vScrollbarMinSize(0, 0); + GetScrollbarMetrics(bls, mInner.mVScrollbarBox, + &vScrollbarMinSize, nsnull, PR_TRUE); + result += vScrollbarMinSize.width; + } + + return result; +} + NS_IMETHODIMP nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsHTMLScrollFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsHTMLScrollFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); - ScrollReflowState state(this, aReflowState, aDesiredSize); + ScrollReflowState state(this, aReflowState); // sanity check: ensure that if we have no scrollbar, we treat it // as hidden. if (!mInner.mVScrollbarBox || mInner.mNeverHasVerticalScrollbar) @@ -731,49 +727,19 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, PRBool reflowHScrollbar = PR_TRUE; PRBool reflowVScrollbar = PR_TRUE; PRBool reflowScrollCorner = PR_TRUE; - nsReflowReason reason = aReflowState.reason; + if (!aReflowState.ShouldReflowAllKids()) { + #define NEEDS_REFLOW(frame_) \ + ((frame_) && \ + ((frame_)->GetStateBits() & \ + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0) - if (reason == eReflowReason_Incremental) { - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - // See if it's targeted at us - if (command) { - nsReflowType reflowType; - command->GetType(reflowType); + reflowContents = NEEDS_REFLOW(mInner.mScrolledFrame); + reflowHScrollbar = NEEDS_REFLOW(mInner.mHScrollbarBox); + reflowVScrollbar = NEEDS_REFLOW(mInner.mVScrollbarBox); + reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox); - switch (reflowType) { - case eReflowType_StyleChanged: - reason = eReflowReason_StyleChange; - break; - - case eReflowType_ReflowDirty: - reason = eReflowReason_Dirty; - break; - - default: - NS_ERROR("Unexpected Reflow Type"); - } - } else { - reflowContents = PR_FALSE; - reflowHScrollbar = PR_FALSE; - reflowVScrollbar = PR_FALSE; - reflowScrollCorner = PR_FALSE; - - nsReflowPath::iterator iter = aReflowState.path->FirstChild(); - nsReflowPath::iterator end = aReflowState.path->EndChildren(); - - for ( ; iter != end; ++iter) { - if (*iter == mInner.mScrolledFrame) - reflowContents = PR_TRUE; - else if (*iter == mInner.mHScrollbarBox) - reflowHScrollbar = PR_TRUE; - else if (*iter == mInner.mVScrollbarBox) - reflowVScrollbar = PR_TRUE; - else if (*iter == mInner.mScrollCornerBox) - reflowScrollCorner = PR_TRUE; - } - } + #undef NEEDS_REFLOW } - state.mNewReason = reason; nsRect oldScrollAreaBounds = mInner.mScrollableView->View()->GetBounds(); nsRect oldScrolledAreaBounds = mInner.mScrolledFrame->GetView()->GetBounds(); @@ -796,7 +762,7 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, // XXX the way this works, we can never get narrower even when content // is deleted, because the XMost of the frame's overflow area is always // at least the right edge. But it looks like it has always worked this way. - nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); + nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags); rv = ReflowScrolledFrame(state, state.mShowVScrollbar, &kidDesiredSize, PR_FALSE); if (NS_FAILED(rv)) @@ -815,7 +781,7 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, nsRect newScrollAreaBounds = mInner.mScrollableView->View()->GetBounds(); nsRect newScrolledAreaBounds = mInner.mScrolledFrame->GetView()->GetBounds(); if (reflowHScrollbar || reflowVScrollbar || reflowScrollCorner || - reason != eReflowReason_Incremental || + (GetStateBits() & NS_FRAME_IS_DIRTY) || didHaveHScrollbar != state.mShowHScrollbar || didHaveVScrollbar != state.mShowVScrollbar || oldScrollAreaBounds != newScrollAreaBounds || @@ -840,16 +806,6 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, aDesiredSize.height = state.mInsideBorderSize.height + state.mComputedBorder.TopBottom(); aDesiredSize.ascent = state.mAscent + state.mComputedBorder.top; - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = state.mMaxElementWidth + - state.mComputedBorder.LeftRight(); - } - if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = state.mMaximumWidth; - if (aDesiredSize.mMaximumWidth != NS_UNCONSTRAINEDSIZE) { - aDesiredSize.mMaximumWidth += state.mComputedBorder.LeftRight(); - } - } aDesiredSize.descent = aDesiredSize.height - aDesiredSize.ascent; aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); @@ -952,7 +908,8 @@ NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool aIsR nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, PRBool aIsRoot) : nsBoxFrame(aShell, aIsRoot), mInner(this, aIsRoot), - mMaxElementWidth(0) + mHorizontalOverflow(PR_FALSE), + mVerticalOverflow(PR_FALSE) { SetLayoutManager(nsnull); } @@ -1235,42 +1192,28 @@ nsXULScrollFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize) return NS_OK; } -NS_IMETHODIMP -nsXULScrollFrame::Reflow(nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) +#if 0 // XXXldb I don't think this is even needed +/* virtual */ nscoord +nsXULScrollFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) { - DO_GLOBAL_REFLOW_COUNT("nsXULScrollFrame", aReflowState.reason); - DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); - - // if there is a max element request then set it to -1 so we can see if it gets set - if (aDesiredSize.mComputeMEW) - { - aDesiredSize.mMaxElementWidth = -1; - } - - nsresult rv = nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - if (aDesiredSize.mComputeMEW) - { - nsStyleUnit widthUnit = GetStylePosition()->mWidth.GetUnit(); - if (widthUnit == eStyleUnit_Percent || widthUnit == eStyleUnit_Auto) { - nsMargin border = aReflowState.mComputedBorderPadding; - aDesiredSize.mMaxElementWidth = border.right + border.left; + nsStyleUnit widthUnit = GetStylePosition()->mWidth.GetUnit(); + if (widthUnit == eStyleUnit_Percent || widthUnit == eStyleUnit_Auto) { + nsMargin border = aReflowState.mComputedBorderPadding; + aDesiredSize.mMaxElementWidth = border.right + border.left; + mMaxElementWidth = aDesiredSize.mMaxElementWidth; + } else { + NS_NOTYETIMPLEMENTED("Use the info from the scrolled frame"); +#if 0 + // if not set then use the cached size. If set then set it. + if (aDesiredSize.mMaxElementWidth == -1) + aDesiredSize.mMaxElementWidth = mMaxElementWidth; + else mMaxElementWidth = aDesiredSize.mMaxElementWidth; - } else { - // if not set then use the cached size. If set then set it. - if (aDesiredSize.mMaxElementWidth == -1) - aDesiredSize.mMaxElementWidth = mMaxElementWidth; - else - mMaxElementWidth = aDesiredSize.mMaxElementWidth; - } +#endif } - - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); - return rv; + return 0; } +#endif NS_IMETHODIMP_(nsrefcnt) nsXULScrollFrame::AddRef(void) @@ -2016,54 +1959,6 @@ nsXULScrollFrame::AddRemoveScrollbar(PRBool& aHasScrollbar, nscoord& aXY, return PR_FALSE; } -/** - * When reflowing a HTML document where the content model is being created - * The nsGfxScrollFrame will get an Initial reflow when the body is opened by the content sink. - * But there isn't enough content to really reflow very much of the document - * so it never needs to do layout for the scrollbars - * - * So later other reflows happen and these are Incremental reflows, and then the scrollbars - * get reflowed. The important point here is that when they reflowed the ReflowState inside the - * BoxLayoutState contains an "Incremental" reason and never a "Initial" reason. - * - * When it reflows for Print Preview, the content model is already full constructed and it lays - * out the entire document at that time. When it returns back here it discovers it needs scrollbars - * and this is a problem because the ReflowState inside the BoxLayoutState still has a "Initial" - * reason and if it does a Layout it is essentially asking everything to reflow yet again with - * an "Initial" reason. This causes a lot of problems especially for tables. - * - * The solution for this is to change the ReflowState's reason from Initial to Resize and let - * all the frames do what is necessary for a resize refow. Now, we only need to do this when - * it is doing PrintPreview and we need only do it for HTML documents and NOT chrome. - * - */ -void -nsXULScrollFrame::AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, PRBool& aSetBack) -{ - aSetBack = PR_FALSE; - PRBool isChrome; - PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(aState, isChrome); - if (isInitialPP && !isChrome) { - // I know you shouldn't, but we cast away the "const" here - nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState(); - reflowState->reason = eReflowReason_Resize; - aSetBack = PR_TRUE; - } -} - -/** - * Sets reflow state back to Initial when we are done. - */ -void -nsXULScrollFrame::AdjustReflowStateBack(nsBoxLayoutState& aState, PRBool aSetBack) -{ - // I know you shouldn't, but we cast away the "const" here - nsHTMLReflowState* reflowState = (nsHTMLReflowState*)aState.GetReflowState(); - if (aSetBack && reflowState->reason == eReflowReason_Resize) { - reflowState->reason = eReflowReason_Initial; - } -} - void nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState, const nsRect& aRect) { @@ -2250,11 +2145,7 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState) // ok layout at the right size if (needsLayout) { nsBoxLayoutState resizeState(aState); - resizeState.SetLayoutReason(nsBoxLayoutState::Resize); - PRBool setBack; - AdjustReflowStateForPrintPreview(aState, setBack); LayoutScrollArea(resizeState, scrollAreaRect); - AdjustReflowStateBack(aState, setBack); needsLayout = PR_FALSE; } } @@ -2297,11 +2188,7 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState) // we only need to set the rect. The inner child stays the same size. if (needsLayout) { nsBoxLayoutState resizeState(aState); - resizeState.SetLayoutReason(nsBoxLayoutState::Resize); - PRBool setBack; - AdjustReflowStateForPrintPreview(aState, setBack); LayoutScrollArea(resizeState, scrollAreaRect); - AdjustReflowStateBack(aState, setBack); needsLayout = PR_FALSE; } @@ -2337,7 +2224,7 @@ nsXULScrollFrame::Layout(nsBoxLayoutState& aState) // we only need to set the rect. The inner child stays the same size. if (needsLayout) { nsBoxLayoutState resizeState(aState); - resizeState.SetLayoutReason(nsBoxLayoutState::Resize); + mInner.mScrolledFrame->AddStateBits(NS_FRAME_IS_DIRTY); LayoutScrollArea(resizeState, scrollAreaRect); } @@ -2446,20 +2333,20 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState, } // may need to update fixed position children of the viewport, - // if the client area changed size because of some dirty reflow - // (if the reflow is initial or resize, the fixed children will - // be re-laid out anyway) - if (aOldScrollArea.Size() != aScrollArea.Size() - && nsBoxLayoutState::Dirty == aState.LayoutReason() && + // if the client area changed size because of an incremental + // reflow of a descendant. (If the outer frame is dirty, the fixed + // children will be re-laid out anyway) + if (aOldScrollArea.Size() != aScrollArea.Size() && + !(mOuter->GetStateBits() & NS_FRAME_IS_DIRTY) && mIsRoot) { - // Usually there are no fixed children, so don't do anything unless there's - // at least one fixed child nsIFrame* parentFrame = mOuter->GetParent(); - if (parentFrame->GetFirstChild(nsLayoutAtoms::fixedList)) { - // force a reflow of the fixed children + for (nsIFrame *fixedChild = + parentFrame->GetFirstChild(nsLayoutAtoms::fixedList); + fixedChild; fixedChild = fixedChild->GetNextSibling()) { + // force a reflow of the fixed child + // XXX Will this work given where we currently are in reflow? mOuter->GetPresContext()->PresShell()-> - AppendReflowCommand(parentFrame, eReflowType_UserDefined, - nsLayoutAtoms::fixedList); + FrameNeedsReflow(fixedChild, nsIPresShell::eResize); } } } diff --git a/mozilla/layout/generic/nsGfxScrollFrame.h b/mozilla/layout/generic/nsGfxScrollFrame.h index 738d191eeee..35410e9bab8 100644 --- a/mozilla/layout/generic/nsGfxScrollFrame.h +++ b/mozilla/layout/generic/nsGfxScrollFrame.h @@ -206,6 +206,9 @@ public: PRBool IsRTLTextControl(); void PlaceScrollArea(const ScrollReflowState& aState); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); + NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -341,10 +344,10 @@ public: nsIAtom* aListName, nsIFrame* aChildList); - NS_IMETHOD Reflow(nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus); + // XXXldb Is this actually used? +#if 0 + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); +#endif // Because there can be only one child frame, these two function return // NS_ERROR_FAILURE @@ -475,7 +478,8 @@ protected: private: friend class nsGfxScrollFrameInner; nsGfxScrollFrameInner mInner; - nscoord mMaxElementWidth; + PRPackedBool mHorizontalOverflow; + PRPackedBool mVerticalOverflow; }; #endif /* nsGfxScrollFrame_h___ */ diff --git a/mozilla/layout/generic/nsHTMLCanvasFrame.cpp b/mozilla/layout/generic/nsHTMLCanvasFrame.cpp index 3a23587a767..c5c91ce7efd 100644 --- a/mozilla/layout/generic/nsHTMLCanvasFrame.cpp +++ b/mozilla/layout/generic/nsHTMLCanvasFrame.cpp @@ -71,13 +71,31 @@ nsHTMLCanvasFrame::~nsHTMLCanvasFrame() ? (_max) \ : (_value))) +/* virtual */ nscoord +nsHTMLCanvasFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + float p2t = GetPresContext()->PixelsToTwips(); + nscoord result = NSIntPixelsToTwips(mCanvasSize.width, p2t); + DISPLAY_MIN_WIDTH(this, result); + return result; +} + +/* virtual */ nscoord +nsHTMLCanvasFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + float p2t = GetPresContext()->PixelsToTwips(); + nscoord result = NSIntPixelsToTwips(mCanvasSize.width, p2t); + DISPLAY_PREF_WIDTH(this, result); + return result; +} + NS_IMETHODIMP nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsHTMLCanvasFrame::Reflow: availSize=%d,%d", @@ -134,13 +152,6 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, aMetrics.ascent = aMetrics.height; aMetrics.descent = 0; - if (aMetrics.mComputeMEW) { - aMetrics.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit()); - } - - if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aMetrics.mMaximumWidth = aMetrics.width; - } aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height); FinishAndStoreOverflow(&aMetrics); diff --git a/mozilla/layout/generic/nsHTMLCanvasFrame.h b/mozilla/layout/generic/nsHTMLCanvasFrame.h index a1402a8e7f2..3411bc2a2ff 100644 --- a/mozilla/layout/generic/nsHTMLCanvasFrame.h +++ b/mozilla/layout/generic/nsHTMLCanvasFrame.h @@ -58,6 +58,8 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/generic/nsHTMLContainerFrame.cpp b/mozilla/layout/generic/nsHTMLContainerFrame.cpp index f8cf8440f25..7b1b431df32 100644 --- a/mozilla/layout/generic/nsHTMLContainerFrame.cpp +++ b/mozilla/layout/generic/nsHTMLContainerFrame.cpp @@ -59,7 +59,6 @@ #include "nsCOMPtr.h" #include "nsIDeviceContext.h" #include "nsIFontMetrics.h" -#include "nsReflowPath.h" #include "nsCSSFrameConstructor.h" NS_IMETHODIMP diff --git a/mozilla/layout/generic/nsHTMLFrame.cpp b/mozilla/layout/generic/nsHTMLFrame.cpp index a4288734d6f..38597b1b4cf 100644 --- a/mozilla/layout/generic/nsHTMLFrame.cpp +++ b/mozilla/layout/generic/nsHTMLFrame.cpp @@ -39,7 +39,6 @@ #include "nsHTMLContainerFrame.h" #include "nsCSSRendering.h" #include "nsIDocument.h" -#include "nsReflowPath.h" #include "nsPresContext.h" #include "nsStyleContext.h" #include "nsViewsCID.h" @@ -105,6 +104,8 @@ public: NS_IMETHOD RemoveFrame(nsIAtom* aListName, nsIFrame* aOldFrame); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -299,9 +300,8 @@ CanvasFrame::AppendFrames(nsIAtom* aListName, #endif mFrames.AppendFrame(nsnull, aFrameList); - // Generate a reflow command to reflow the newly inserted frame - rv = GetPresContext()->PresShell()-> - AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return rv; @@ -347,9 +347,8 @@ CanvasFrame::RemoveFrame(nsIAtom* aListName, // Remove the frame and destroy it mFrames.DestroyFrame(GetPresContext(), aOldFrame); - // Generate a reflow command so we get reflowed - rv = GetPresContext()->PresShell()-> - AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } else { rv = NS_ERROR_FAILURE; } @@ -450,51 +449,43 @@ CanvasFrame::Paint(nsPresContext* aPresContext, return rv; } +/* virtual */ nscoord +CanvasFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetMinWidth(aRenderingContext); + return result; +} + +/* virtual */ nscoord +CanvasFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext); + return result; +} + NS_IMETHODIMP CanvasFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("CanvasFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("CanvasFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("CanvasFrame::Reflow"); - //NS_PRECONDITION(!aDesiredSize.mComputeMEW, "unexpected request"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; - PRBool isStyleChange = PR_FALSE; - PRBool isDirtyChildReflow = PR_FALSE; - - // Check for an incremental reflow - if (eReflowReason_Incremental == aReflowState.reason) { - // See if we're the target frame - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - if (command) { - // Get the reflow type - switch (command->Type()) { - case eReflowType_ReflowDirty: - isDirtyChildReflow = PR_TRUE; - break; - - case eReflowType_StyleChanged: - // Remember it's a style change so we can set the reflow reason below - isStyleChange = PR_TRUE; - break; - - default: - NS_ASSERTION(PR_FALSE, "unexpected reflow command type"); - } - } - else { -#ifdef DEBUG - nsReflowPath::iterator iter = aReflowState.path->FirstChild(); - NS_ASSERTION(*iter == mFrames.FirstChild(), "unexpected next reflow command frame"); -#endif - } - } - // Reflow our one and only child frame nsHTMLReflowMetrics kidDesiredSize(nsnull); if (mFrames.IsEmpty()) { @@ -504,24 +495,13 @@ CanvasFrame::Reflow(nsPresContext* aPresContext, } else { nsIFrame* kidFrame = mFrames.FirstChild(); - - nsReflowReason reason; - if (isDirtyChildReflow) { - // Note: the only reason the frame would be dirty would be if it had - // just been inserted or appended - reason = eReflowReason_Initial; - } else if (isStyleChange) { - reason = eReflowReason_StyleChange; - } else { - reason = aReflowState.reason; - } + PRBool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; // We must specify an unconstrained available height, because constrained // is only for when we're paginated... nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(aReflowState.availableWidth, - NS_UNCONSTRAINEDSIZE), - reason); + NS_UNCONSTRAINEDSIZE)); // Reflow the frame ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, @@ -535,7 +515,7 @@ CanvasFrame::Reflow(nsPresContext* aPresContext, // If the child frame was just inserted, then we're responsible for making sure // it repaints - if (isDirtyChildReflow) { + if (kidDirty) { // But we have a new child, which will affect our background, so // invalidate our whole rect. // Note: Even though we request to be sized to our child's size, our diff --git a/mozilla/layout/generic/nsHTMLParts.h b/mozilla/layout/generic/nsHTMLParts.h index 737c30ebb32..d118bfa1d0d 100644 --- a/mozilla/layout/generic/nsHTMLParts.h +++ b/mozilla/layout/generic/nsHTMLParts.h @@ -39,8 +39,6 @@ #include "nscore.h" #include "nsISupports.h" -#include "nsReflowType.h" -class nsHTMLReflowCommand; class nsIAtom; class nsNodeInfoManager; class nsIContent; diff --git a/mozilla/layout/generic/nsHTMLReflowMetrics.h b/mozilla/layout/generic/nsHTMLReflowMetrics.h index ab65a8895f9..c5a290415e8 100644 --- a/mozilla/layout/generic/nsHTMLReflowMetrics.h +++ b/mozilla/layout/generic/nsHTMLReflowMetrics.h @@ -47,9 +47,8 @@ //---------------------------------------------------------------------- // Option flags -#define NS_REFLOW_CALC_MAX_WIDTH 0x0001 #ifdef MOZ_MATHML -#define NS_REFLOW_CALC_BOUNDING_METRICS 0x0002 +#define NS_REFLOW_CALC_BOUNDING_METRICS 0x0001 #endif /** @@ -140,12 +139,6 @@ struct nsHTMLReflowMetrics { nscoord width, height; // [OUT] desired width and height nscoord ascent, descent; // [OUT] ascent and descent information - nscoord mMaxElementWidth; // [OUT] - - // Used for incremental reflow. If the NS_REFLOW_CALC_MAX_WIDTH flag is set, - // then the caller is requesting that you update and return your maximum width - nscoord mMaximumWidth; // [OUT] - #ifdef MOZ_MATHML // Metrics that _exactly_ enclose the text to allow precise MathML placements. // If the NS_REFLOW_CALC_BOUNDING_METRICS flag is set, then the caller is @@ -175,13 +168,7 @@ struct nsHTMLReflowMetrics { // used by tables to optimize common cases PRPackedBool mNothingChanged; - // Should we compute mMaxElementWidth? - PRPackedBool mComputeMEW; - - nsHTMLReflowMetrics(PRBool aComputeMEW, PRUint32 aFlags = 0) { - mComputeMEW = aComputeMEW; - mMaxElementWidth = 0; - mMaximumWidth = 0; + nsHTMLReflowMetrics(PRUint32 aFlags = 0) { mFlags = aFlags; mOverflowArea.x = 0; mOverflowArea.y = 0; @@ -199,24 +186,8 @@ struct nsHTMLReflowMetrics { ascent = descent = 0; } - /** - * set the maxElementWidth to the desired width. If the frame has a percent - * width specification it can be shrinked to 0 if the containing frame shrinks - * so we need to report 0 otherwise the incr. reflow will fail - * @param aWidthUnit - the width unit from the corresponding reflowstate - */ - void SetMEWToActualWidth(nsStyleUnit aWidthUnit) { - if (aWidthUnit != eStyleUnit_Percent) { - mMaxElementWidth = width; - } else { - mMaxElementWidth = 0; - } - } - nsHTMLReflowMetrics& operator=(const nsHTMLReflowMetrics& aOther) { - mMaxElementWidth = aOther.mMaxElementWidth; - mMaximumWidth = aOther.mMaximumWidth; mFlags = aOther.mFlags; mCarriedOutBottomMargin = aOther.mCarriedOutBottomMargin; mOverflowArea.x = aOther.mOverflowArea.x; diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 6741eaf7e7d..265d57caafa 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -78,23 +78,10 @@ enum eNormalLineHeightControl { static eNormalLineHeightControl sNormalLineHeightControl = eUninitialized; #endif -#ifdef DEBUG -const char* -nsHTMLReflowState::ReasonToString(nsReflowReason aReason) -{ - static const char* reasons[] = { - "initial", "incremental", "resize", "style-change", "dirty" - }; - - return reasons[aReason]; -} -#endif - // Initialize a root reflow state with a rendering context to // use for measuring things. -nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, +nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, nsIFrame* aFrame, - nsReflowReason aReason, nsIRenderingContext* aRenderingContext, const nsSize& aAvailableSpace) : mReflowDepth(0) @@ -102,8 +89,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context"); parentReflowState = nsnull; frame = aFrame; - reason = aReason; - path = nsnull; availableWidth = aAvailableSpace.width; availableHeight = aAvailableSpace.height; rendContext = aRenderingContext; @@ -123,40 +108,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, #endif } -// Initialize a root reflow state for an incremental -// reflow. -nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, - nsIFrame* aFrame, - nsReflowPath* aReflowPath, - nsIRenderingContext* aRenderingContext, - const nsSize& aAvailableSpace) - : mReflowDepth(0) -{ - NS_PRECONDITION(nsnull != aRenderingContext, "no rendering context"); - - reason = eReflowReason_Incremental; - path = aReflowPath; - parentReflowState = nsnull; - frame = aFrame; - availableWidth = aAvailableSpace.width; - availableHeight = aAvailableSpace.height; - rendContext = aRenderingContext; - mSpaceManager = nsnull; - mLineLayout = nsnull; - mFlags.mSpecialHeightReflow = PR_FALSE; - mFlags.mIsTopOfPage = PR_FALSE; - mFlags.mNextInFlowUntouched = PR_FALSE; - mFlags.mHasClearance = PR_FALSE; - mDiscoveredClearance = nsnull; - mPercentHeightObserver = nsnull; - mPercentHeightReflowInitiator = nsnull; - Init(aPresContext); -#ifdef IBMBIDI - mFlags.mVisualBidiFormControl = IsBidiFormControl(aPresContext); - mRightEdge = NS_UNCONSTRAINEDSIZE; -#endif // IBMBIDI -} - static PRBool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent) { nsIFrame* frameNext = aFrame->GetNextInFlow(); @@ -167,27 +118,22 @@ static PRBool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent) // Initialize a reflow state for a child frames reflow. Some state // is copied from the parent reflow state; the remaining state is // computed. -nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, +nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, const nsHTMLReflowState& aParentReflowState, nsIFrame* aFrame, const nsSize& aAvailableSpace, - nsReflowReason aReason, + nscoord aContainingBlockWidth, + nscoord aContainingBlockHeight, PRBool aInit) : mReflowDepth(aParentReflowState.mReflowDepth + 1), mFlags(aParentReflowState.mFlags) { parentReflowState = &aParentReflowState; frame = aFrame; - reason = aReason; - if (reason == eReflowReason_Incremental) { - // If the child frame isn't along the reflow path, then convert - // the incremental reflow to a dirty reflow. - path = aParentReflowState.path->GetSubtreeFor(aFrame); - if (! path) - reason = eReflowReason_Dirty; - } - else - path = nsnull; + + // If the parent is dirty, then the child is as well. + frame->AddStateBits(parentReflowState->frame->GetStateBits() & + NS_FRAME_IS_DIRTY); availableWidth = aAvailableSpace.width; availableHeight = aAvailableSpace.height; @@ -206,7 +152,7 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; if (aInit) { - Init(aPresContext); + Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); } #ifdef IBMBIDI @@ -216,102 +162,6 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, #endif // IBMBIDI } -// Same as the previous except that the reason is taken from the -// parent's reflow state. -nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentReflowState, - nsIFrame* aFrame, - const nsSize& aAvailableSpace) - : mReflowDepth(aParentReflowState.mReflowDepth + 1), - mFlags(aParentReflowState.mFlags) -{ - parentReflowState = &aParentReflowState; - frame = aFrame; - reason = aParentReflowState.reason; - if (reason == eReflowReason_Incremental) { - // If the child frame isn't along the reflow path, then convert - // the incremental reflow to a dirty reflow. - path = aParentReflowState.path->GetSubtreeFor(aFrame); - if (! path) - reason = eReflowReason_Dirty; - } - else - path = nsnull; - - availableWidth = aAvailableSpace.width; - availableHeight = aAvailableSpace.height; - - rendContext = aParentReflowState.rendContext; - mSpaceManager = aParentReflowState.mSpaceManager; - mLineLayout = aParentReflowState.mLineLayout; - mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && - CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); - mFlags.mHasClearance = PR_FALSE; - mDiscoveredClearance = nsnull; - mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && - aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) - ? aParentReflowState.mPercentHeightObserver : nsnull; - mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; - - Init(aPresContext); - -#ifdef IBMBIDI - mFlags.mVisualBidiFormControl = (aParentReflowState.mFlags.mVisualBidiFormControl) ? - PR_TRUE : IsBidiFormControl(aPresContext); - mRightEdge = aParentReflowState.mRightEdge; -#endif // IBMBIDI -} - -// Version that species the containing block width and height -nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentReflowState, - nsIFrame* aFrame, - const nsSize& aAvailableSpace, - nscoord aContainingBlockWidth, - nscoord aContainingBlockHeight, - nsReflowReason aReason) - : mReflowDepth(aParentReflowState.mReflowDepth + 1), - mFlags(aParentReflowState.mFlags) -{ - parentReflowState = &aParentReflowState; - frame = aFrame; - reason = aReason; - if (reason == eReflowReason_Incremental) { - // If the child frame isn't along the reflow path, then convert - // the incremental reflow to a dirty reflow. - path = aParentReflowState.path->GetSubtreeFor(aFrame); - if (! path) - reason = eReflowReason_Dirty; - } - else - path = nsnull; - - availableWidth = aAvailableSpace.width; - availableHeight = aAvailableSpace.height; - - rendContext = aParentReflowState.rendContext; - mSpaceManager = aParentReflowState.mSpaceManager; - mLineLayout = aParentReflowState.mLineLayout; - mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && - CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); - mFlags.mHasClearance = PR_FALSE; - mDiscoveredClearance = nsnull; - mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && - aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) - ? aParentReflowState.mPercentHeightObserver : nsnull; - mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; - - Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); - -#ifdef IBMBIDI - mFlags.mVisualBidiFormControl = (aParentReflowState.mFlags.mVisualBidiFormControl) ? - PR_TRUE : IsBidiFormControl(aPresContext); - mRightEdge = aParentReflowState.mRightEdge; -#endif // IBMBIDI -} - void nsHTMLReflowState::Init(nsPresContext* aPresContext, nscoord aContainingBlockWidth, @@ -335,6 +185,10 @@ nsHTMLReflowState::Init(nsPresContext* aPresContext, InitFrameType(); InitCBReflowState(); InitConstraints(aPresContext, aContainingBlockWidth, aContainingBlockHeight, aBorder, aPadding); + + mFlags.mIsResize = !(frame->GetStateBits() & NS_FRAME_IS_DIRTY) && + frame->GetSize().width != + mComputedWidth + mComputedBorderPadding.LeftRight(); } void nsHTMLReflowState::InitCBReflowState() @@ -753,6 +607,7 @@ nsHTMLReflowState::CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWid // We have to compute the left and right values if (eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit()) { + // XXX FIXME (or does CalculateBlockSideMargins do this?) margin.left = 0; // just ignore } else { ComputeHorizontalValue(aContainingBlockWidth, @@ -761,6 +616,7 @@ nsHTMLReflowState::CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWid margin.left); } if (eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit()) { + // XXX FIXME (or does CalculateBlockSideMargins do this?) margin.right = 0; // just ignore } else { ComputeHorizontalValue(aContainingBlockWidth, @@ -1163,13 +1019,27 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext, // At this point we know that at least one of 'left', 'width', and 'right' // is 'auto', but not all three. Examine the various combinations if (widthIsAuto) { + nscoord availWidth = containingBlockWidth - mComputedOffsets.left - + mComputedMargin.left - mComputedBorderPadding.left - + mComputedBorderPadding.right - + mComputedMargin.right - mComputedOffsets.right; + if (availWidth < 0) + availWidth = 0; + if (leftIsAuto || rightIsAuto) { if (NS_FRAME_IS_REPLACED(mFrameType)) { // For a replaced element we use the intrinsic size mComputedWidth = NS_INTRINSICSIZE; } else { // The width is shrink-to-fit - mComputedWidth = NS_SHRINKWRAPWIDTH; + nscoord prefWidth = frame->GetPrefWidth(rendContext); + if (prefWidth < availWidth) { + mComputedWidth = prefWidth; + } else { + nscoord minWidth = frame->GetMinWidth(rendContext); + mComputedWidth = PR_MAX(minWidth, availWidth); + } + AdjustComputedWidth(PR_FALSE); } if (leftIsAuto) { @@ -1180,22 +1050,14 @@ nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext, } else { // Only 'width' is 'auto' so just solve for 'width' - PRInt32 autoWidth = containingBlockWidth - mComputedOffsets.left - - mComputedMargin.left - mComputedBorderPadding.left - - mComputedBorderPadding.right - - mComputedMargin.right - mComputedOffsets.right; - - if (autoWidth < 0) { - autoWidth = 0; - } - mComputedWidth = autoWidth; + mComputedWidth = availWidth; AdjustComputedWidth(PR_FALSE); - if (autoWidth != mComputedWidth) { + if (availWidth != mComputedWidth) { // Re-calculate any 'auto' margin values since the computed width // was adjusted by a 'min-width' or 'max-width'. - PRInt32 availMarginSpace = autoWidth - mComputedWidth; + PRInt32 availMarginSpace = availWidth - mComputedWidth; if (eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit()) { if (eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit()) { @@ -1855,48 +1717,29 @@ nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext, } else if (NS_CSS_FRAME_TYPE_FLOATING == mFrameType) { // Floating non-replaced element. First calculate the computed width if (eStyleUnit_Auto == widthUnit) { - if ((NS_UNCONSTRAINEDSIZE == aContainingBlockWidth) && - (eStyleUnit_Percent == mStylePosition->mWidth.GetUnit())) { - // The element has a percentage width, but since the containing - // block width is unconstrained we set 'widthUnit' to 'auto' - // above. However, we want the element to be unconstrained, too - mComputedWidth = NS_UNCONSTRAINEDSIZE; - - } else if (NS_STYLE_DISPLAY_TABLE == mStyleDisplay->mDisplay) { - // It's an outer table because an inner table is not positioned - // shrink wrap its width since the outer table is anonymous - mComputedWidth = NS_SHRINKWRAPWIDTH; - + nscoord availWidth = ((eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) + ? availableWidth + : aContainingBlockWidth) - + mComputedMargin.left - + mComputedBorderPadding.left - + mComputedBorderPadding.right - + mComputedMargin.right; + if (availWidth < 0) + availWidth = 0; + nscoord prefWidth = frame->GetPrefWidth(rendContext); + if (prefWidth < availWidth) { + mComputedWidth = prefWidth; } else { - NS_ASSERTION(eStyleUnit_Auto == mStylePosition->mWidth.GetUnit(), - "How did we get here?"); - // The CSS2 spec says the computed width should be 0; however, that's - // not what Nav and IE do and even the spec doesn't really want that - // to happen. - // - // Instead, have the element shrink wrap its width - mComputedWidth = NS_SHRINKWRAPWIDTH; - - // Limit the width to the available width. This factors in - // other floats that impact this float. - // XXX It's possible that this should be quirks-only. Probable, in fact. - nscoord widthFromCB = availableWidth; - if (NS_UNCONSTRAINEDSIZE != widthFromCB) { - widthFromCB -= mComputedBorderPadding.left + mComputedBorderPadding.right + - mComputedMargin.left + mComputedMargin.right; - } - if (mComputedMaxWidth > widthFromCB) { - mComputedMaxWidth = widthFromCB; - } + nscoord minWidth = frame->GetMinWidth(rendContext); + mComputedWidth = PR_MAX(minWidth, availWidth); } - } else { ComputeHorizontalValue(aContainingBlockWidth, widthUnit, mStylePosition->mWidth, mComputedWidth); } // Take into account minimum and maximum sizes - AdjustComputedWidth(PR_TRUE); + AdjustComputedWidth(eStyleUnit_Auto != widthUnit); // Now calculate the computed height if (eStyleUnit_Auto == heightUnit) { @@ -2002,50 +1845,32 @@ nsHTMLReflowState::ComputeBlockBoxData(nsPresContext* aPresContext, // for margin-left and margin-right become 0, and the sum of the // areas must equal the width of the content-area of the parent // element. - if (NS_UNCONSTRAINEDSIZE == availableWidth) { - // During pass1 table reflow, auto side margin values are - // uncomputable (== 0). - mComputedWidth = NS_UNCONSTRAINEDSIZE; - } else if (NS_SHRINKWRAPWIDTH == aContainingBlockWidth) { - // The containing block should shrink wrap its width, so have - // the child block do the same - mComputedWidth = NS_UNCONSTRAINEDSIZE; - - // Let its content area be as wide as the containing block's max width - // minus any margin and border/padding - nscoord maxWidth = cbrs->mComputedMaxWidth; - if (NS_UNCONSTRAINEDSIZE != maxWidth) { - maxWidth -= mComputedMargin.left + mComputedBorderPadding.left + - mComputedMargin.right + mComputedBorderPadding.right; - } - if (maxWidth < mComputedMaxWidth) { - mComputedMaxWidth = maxWidth; - } - - } else { - // tables act like replaced elements regarding mComputedWidth - nsIAtom* fType = frame->GetType(); - if (nsLayoutAtoms::tableOuterFrame == fType) { - mComputedWidth = 0; // XXX temp fix for trees - } else if ((nsLayoutAtoms::tableFrame == fType) || - (nsLayoutAtoms::tableCaptionFrame == fType)) { - mComputedWidth = NS_SHRINKWRAPWIDTH; - if (eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit()) { - mComputedMargin.left = NS_AUTOMARGIN; - } - if (eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit()) { - mComputedMargin.right = NS_AUTOMARGIN; - } + // tables act like replaced elements regarding mComputedWidth + nsIAtom* fType = frame->GetType(); + if (nsLayoutAtoms::tableOuterFrame == fType) { + mComputedWidth = 0; // XXX temp fix for trees + } else if ((nsLayoutAtoms::tableFrame == fType) || + (nsLayoutAtoms::tableCaptionFrame == fType)) { + // The width is shrink-to-fit + // XXX We need to subtract border and padding from available width. + nscoord prefWidth = frame->GetPrefWidth(rendContext); + if (prefWidth < availableWidth) { + mComputedWidth = prefWidth; } else { - mComputedWidth = availableWidth - mComputedMargin.left - - mComputedMargin.right - mComputedBorderPadding.left - - mComputedBorderPadding.right; - mComputedWidth = PR_MAX(mComputedWidth, 0); + nscoord minWidth = frame->GetMinWidth(rendContext); + mComputedWidth = PR_MAX(minWidth, availableWidth); } - - AdjustComputedWidth(PR_FALSE); - CalculateBlockSideMargins(cbrs->mComputedWidth, mComputedWidth); + // XXX This is probably quite wrong for captions and for tables + // with captions. We need to do more of this on the outer frame. + } else { + mComputedWidth = availableWidth - mComputedMargin.left - + mComputedMargin.right - mComputedBorderPadding.left - + mComputedBorderPadding.right; + mComputedWidth = PR_MAX(mComputedWidth, 0); } + + AdjustComputedWidth(PR_FALSE); + CalculateBlockSideMargins(cbrs->mComputedWidth, mComputedWidth); } } else { ComputeHorizontalValue(aContainingBlockWidth, aWidthUnit, @@ -2096,7 +1921,10 @@ nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth, // compute against... if (NS_UNCONSTRAINEDSIZE == aComputedWidth || NS_UNCONSTRAINEDSIZE == aAvailWidth) + { + NS_NOTREACHED("this shouldn't happen anymore"); return; + } nscoord sum = mComputedMargin.left + mComputedBorderPadding.left + aComputedWidth + mComputedBorderPadding.right + mComputedMargin.right; @@ -2107,34 +1935,16 @@ nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth, // Determine the left and right margin values. The width value // remains constant while we do this. - PRBool isTable = mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE || - mStyleDisplay->mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION; - // Calculate how much space is available for margins nscoord availMarginSpace = aAvailWidth - sum; - // XXXldb Should this be quirks-mode only? And why captions? - if (isTable) - // XXXldb Why does this break things so badly if this is changed to - // availMarginSpace += mComputedBorderPadding.left + - // mComputedBorderPadding.right; - availMarginSpace = aAvailWidth - aComputedWidth; - // If the available margin space is negative, then don't follow the // usual overconstraint rules. if (availMarginSpace < 0) { - if (!isTable) { - if (mStyleVisibility->mDirection == NS_STYLE_DIRECTION_LTR) { - mComputedMargin.right += availMarginSpace; - } else { - mComputedMargin.left += availMarginSpace; - } + if (mStyleVisibility->mDirection == NS_STYLE_DIRECTION_LTR) { + mComputedMargin.right += availMarginSpace; } else { - mComputedMargin.left = 0; - mComputedMargin.right = 0; - if (mStyleVisibility->mDirection == NS_STYLE_DIRECTION_RTL) { - mComputedMargin.left = availMarginSpace; - } + mComputedMargin.left += availMarginSpace; } return; } @@ -2145,7 +1955,7 @@ nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth, eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit(); PRBool isAutoRightMargin = eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit(); - if (!isAutoLeftMargin && !isAutoRightMargin && !isTable) { + if (!isAutoLeftMargin && !isAutoRightMargin) { // Neither margin is 'auto' so we're over constrained. Use the // 'direction' property of the parent to tell which margin to // ignore diff --git a/mozilla/layout/generic/nsHTMLReflowState.h b/mozilla/layout/generic/nsHTMLReflowState.h index afa22186210..e3d3dc8c80b 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.h +++ b/mozilla/layout/generic/nsHTMLReflowState.h @@ -39,10 +39,9 @@ #include "nsMargin.h" #include "nsStyleCoord.h" +#include "nsIFrame.h" -class nsIFrame; class nsPresContext; -class nsReflowPath; class nsIRenderingContext; class nsSpaceManager; class nsLineLayout; @@ -64,23 +63,6 @@ struct nsHypotheticalBox; */ #define NS_UNCONSTRAINEDSIZE NS_MAXSIZE -/** - * The reason the frame is being reflowed. - * - * XXX Should probably be a #define so it can be extended for specialized - * reflow interfaces... - * - * @see nsHTMLReflowState - */ -enum nsReflowReason { - eReflowReason_Initial = 0, // initial reflow of a newly created frame - eReflowReason_Incremental = 1, // an incremental change has occured. see the reflow command for details - eReflowReason_Resize = 2, // general request to determine a desired size - eReflowReason_StyleChange = 3, // request to reflow because of a style change. Note: you must reflow - // all your child frames - eReflowReason_Dirty = 4 // request to reflow because you and/or your children are dirty -}; - /** * CSS Frame type. Included as part of the reflow state. */ @@ -115,7 +97,6 @@ typedef PRUint32 nsCSSFrameType; ((_ft) & ~NS_CSS_FRAME_TYPE_REPLACED) #define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE -#define NS_SHRINKWRAPWIDTH NS_UNCONSTRAINEDSIZE #define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE #define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE #define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE @@ -124,7 +105,10 @@ typedef PRUint32 nsCSSFrameType; // at least update AdjustComputedHeight/Width and test ad nauseum /** - * Reflow state passed to a frame during reflow. + * State passed to a frame during reflow or intrinsic size calculation. + * + * XXX Refactor so only a base class (nsSizingState?) is used for intrinsic + * size calculation. * * @see nsIFrame#Reflow() */ @@ -136,17 +120,6 @@ struct nsHTMLReflowState { // the frame being reflowed nsIFrame* frame; - // the reason for the reflow - nsReflowReason reason; - - // the incremental reflow path, when the reflow reason is - // eReflowReason_Incremental. Specifically, this corresponds to the - // portion of the incremental reflow path from `frame' down. Note - // that it is safe to assume that this is non-null: we maintain the - // invariant that it contains a valid nsReflowPath pointer when - // reason == eReflowReason_Incremental. - nsReflowPath *path; - // the available width in which to reflow the frame. The space // represents the amount of room for the frame's border, padding, // and content area (not the margin area. The parent frame deals @@ -189,9 +162,6 @@ struct nsHTMLReflowState { // // For block-level frames, the computed width is based on the width of the // containing block, the margin/border/padding areas, and the min/max width. - // A value of NS_SHRINKWRAPWIDTH means that you should choose a width based - // on your content. The width may be as large as the specified maximum width - // (see mComputedMaxWidth). nscoord mComputedWidth; // The computed height specifies the frame's content height, and it does @@ -265,6 +235,7 @@ struct nsHTMLReflowState { PRUint16 mBlinks:1; // Keep track of text-decoration: blink PRUint16 mVisualBidiFormControl:1; // Keep track of descendants of form controls on Visual Bidi pages PRUint16 mHasClearance:1; // Block has clearance + PRUint16 mIsResize:1; // Is frame (a) not dirty and (b) a different width than before? } mFlags; #ifdef IBMBIDI @@ -274,8 +245,6 @@ struct nsHTMLReflowState { #ifdef DEBUG // hook for attaching debug info (e.g. tables may attach a timer during reflow) void* mDebugHook; - - static const char* ReasonToString(nsReflowReason aReason); #endif // Note: The copy constructor is written by the compiler automatically. You @@ -284,47 +253,24 @@ struct nsHTMLReflowState { // Initialize a root reflow state with a rendering context to // use for measuring things. - nsHTMLReflowState(nsPresContext* aPresContext, + nsHTMLReflowState(nsPresContext* aPresContext, nsIFrame* aFrame, - nsReflowReason aReason, - nsIRenderingContext* aRenderingContext, - const nsSize& aAvailableSpace); - - // Initialize a root reflow state for an incremental - // reflow. - nsHTMLReflowState(nsPresContext* aPresContext, - nsIFrame* aFrame, - nsReflowPath* aReflowPath, nsIRenderingContext* aRenderingContext, const nsSize& aAvailableSpace); // Initialize a reflow state for a child frames reflow. Some state // is copied from the parent reflow state; the remaining state is // computed. - nsHTMLReflowState(nsPresContext* aPresContext, + nsHTMLReflowState(nsPresContext* aPresContext, const nsHTMLReflowState& aParentReflowState, nsIFrame* aFrame, const nsSize& aAvailableSpace, - nsReflowReason aReason, + // These two are used by absolute positioning code + // two override default containing block w & h: + nscoord aContainingBlockWidth = -1, + nscoord aContainingBlockHeight = -1, PRBool aInit = PR_TRUE); - // Same as the previous except that the reason is taken from the - // parent's reflow state. - nsHTMLReflowState(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentReflowState, - nsIFrame* aFrame, - const nsSize& aAvailableSpace); - - // Used when you want to override the default containing block - // width and height. Used by absolute positioning code - nsHTMLReflowState(nsPresContext* aPresContext, - const nsHTMLReflowState& aParentReflowState, - nsIFrame* aFrame, - const nsSize& aAvailableSpace, - nscoord aContainingBlockWidth, - nscoord aContainingBlockHeight, - nsReflowReason aReason); - // This method initializes various data members. It is automatically // called by the various constructors void Init(nsPresContext* aPresContext, @@ -402,6 +348,10 @@ struct nsHTMLReflowState { */ void ApplyMinMaxConstraints(nscoord* aContentWidth, nscoord* aContentHeight) const; + PRBool ShouldReflowAllKids() const { + return (frame->GetStateBits() & NS_FRAME_IS_DIRTY) || mFlags.mIsResize; + } + protected: void InitCBReflowState(); diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index 177635039b4..31aba340056 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -124,6 +124,8 @@ typedef PRUint32 nsSplittableType; #define NS_FRAME_IS_NOT_SPLITTABLE(type)\ (0 == ((type) & NS_FRAME_SPLITTABLE)) +#define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN + //---------------------------------------------------------------------- /** @@ -170,13 +172,22 @@ typedef PRUint32 nsFrameState; #define NS_FRAME_SELECTED_CONTENT 0x00000200 // If this bit is set, then the frame is dirty and needs to be reflowed. -// This bit is set when the frame is first created +// This bit is set when the frame is first created. +// This bit is cleared by DidReflow after the required call to Reflow has +// finished. #define NS_FRAME_IS_DIRTY 0x00000400 // If this bit is set then the frame is unflowable. #define NS_FRAME_IS_UNFLOWABLE 0x00000800 -// If this bit is set, the frame has dirty children. +// If this bit is set, either: +// 1. the frame has children that have either NS_FRAME_IS_DIRTY or +// NS_FRAME_HAS_DIRTY_CHILDREN, or +// 2. the frame has had descendants removed. +// It means that Reflow needs to be called, but that Reflow will not +// do as much work as it would if NS_FRAME_IS_DIRTY were set. +// This bit is cleared by DidReflow after the required call to Reflow has +// finished. #define NS_FRAME_HAS_DIRTY_CHILDREN 0x00001000 // If this bit is set, the frame has an associated view @@ -878,6 +889,117 @@ public: return NS_CONST_CAST(nsIFrame*, this); } + + /** + * Mark any stored intrinsic width information as dirty (requiring + * re-calculation). Note that this should generally not be called + * directly; nsPresShell::FrameNeedsReflow will call it instead. + */ + virtual void MarkIntrinsicWidthsDirty() = 0; + + /** + * Get the intrinsic minimum width of the frame. + * + * This is *not* affected by the CSS 'min-width', 'width', and + * 'max-width' properties on this frame, but it is affected by the + * values of those properties on this frame's descendants. + * + * The value returned should **NOT** include the space required for + * padding and border. + * + * Note that many frames will cache the result of this function call + * unless MarkIntrinsicWidthsDirty is called. + * + * It is not acceptable for a frame to mark itself dirty when this + * method is called. + */ + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext) = 0; + + /** + * Get the intrinsic width of the frame. + * + * Otherwise, all the comments for |GetMinWidth| above apply. + */ + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext) = 0; + + /** + * |InlineIntrinsicWidth| represents the intrinsic width information + * in inline layout. Code that determines the intrinsic width of a + * region of inline layout accumulates the result into this structure. + * This pattern is needed because we need to maintain state + * information about whitespace (for both collapsing and trimming). + */ + struct InlineIntrinsicWidthData { + InlineIntrinsicWidthData() + : prevLines(0), currentLine(0), skipWhitespace(PR_TRUE) {} + + // The maximum intrinsic width for all previous lines. + nscoord prevLines; + + // The maximum intrinsic width for the current line. At a line + // break (mandatory for preferred width; allowed for minimum width), + // the caller should call |Break()|. + nscoord currentLine; + + // True if initial collapsable whitespace should be skipped. This + // should be true at the beginning of a block and when the last text + // ended with whitespace. + PRBool skipWhitespace; + + // Floats encountered in the lines. + nsVoidArray floats; // of nsIFrame* + }; + + struct InlineMinWidthData : public InlineIntrinsicWidthData { + void Break(nsIRenderingContext *aRenderingContext); + }; + + struct InlinePrefWidthData : public InlineIntrinsicWidthData { + // This contains the width of the trimmable whitespace at the end of + // |currentLine|; it is zero if there is no such whitespace. + nscoord trailingWhitespace; + + InlinePrefWidthData() + : trailingWhitespace(0) {} + + void Break(nsIRenderingContext *aRenderingContext); + }; + + /** + * Add the intrinsic minimum width of a frame in a way suitable for + * use in inline layout to an |InlineIntrinsicWidthData| object that + * represents the intrinsic width information of all the previous + * frames in the inline layout region. + * + * All *allowed* breakpoints within the frame determine what counts as + * a line for the |InlineIntrinsicWidthData|. This means that + * |aData->trailingWhitespace| will always be zero (unlike for + * AddInlinePrefWidth). + * + * All the comments for |GetMinWidth| apply, except that this function + * is responsible for adding padding, border, and margin and for + * considering the effects of 'width', 'min-width', and 'max-width'. + * + * This may be called on any frame. For frames that do not + * participate in line breaking, the result will simply append the + * result of |GetMinWidth| to the current line. + */ + virtual void + AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData) = 0; + + /** + * Get the intrinsic width of a frame in a way suitable for + * use in inline layout. + * + * All the comments for |GetInlinePrefWidth| apply, except that this + * fills in an |InlineIntrinsicWidthData| structure based on using all + * *mandatory* breakpoints within the frame. + */ + virtual void + AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData) = 0; + /** * Pre-reflow hook. Before a frame is reflowed this method will be called. * This call will always be invoked at least once before a subsequent Reflow @@ -890,23 +1012,29 @@ public: NS_IMETHOD WillReflow(nsPresContext* aPresContext) = 0; /** - * The frame is given a maximum size and asked for its desired size. - * This is the frame's opportunity to reflow its children. + * The frame is given an available size and asked for its desired + * size. This is the frame's opportunity to reflow its children. + * + * If the frame has the NS_FRAME_IS_DIRTY bit set then it is + * responsible for completely reflowing itself and all of its + * descendants. + * + * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit + * set, then it is responsible for reflowing at least those + * children that have NS_FRAME_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY + * set. + * + * If a difference in available size from the previous reflow causes + * the frame's size to change, it should reflow descendants as needed. * * @param aDesiredSize out parameter where you should return the * desired size and ascent/descent info. You should include any * space you want for border/padding in the desired size you return. * - * It's okay to return a desired size that exceeds the max + * It's okay to return a desired size that exceeds the avail * size if that's the smallest you can be, i.e. it's your * minimum size. * - * maxElementSize is an optional parameter for returning your - * maximum element size. If may be null in which case you - * don't have to compute a maximum element size. The - * maximum element size must be less than or equal to your - * desired size. - * * For an incremental reflow you are responsible for invalidating * any area within your frame that needs repainting (including * borders). If your new desired size is different than your current @@ -1205,12 +1333,20 @@ public: NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval)=0; /** - * Called by a child frame on a parent frame to tell the parent frame that the child needs - * to be reflowed. The parent should either propagate the request to its parent frame or - * handle the request by generating a eReflowType_ReflowDirtyChildren reflow command. + * Called to tell a frame that one of its child frames is dirty (i.e., + * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit + * set). This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on + * the frame, and may do other work. + * + * @return PR_TRUE if the frame was already marked as dirty (i.e., the + * caller does not need to continue making calls up the + * ancestor chain) + * PR_FALSE if the frame was not already marked as dirty + * (which means it's the callers responsibility to call + * this->GetParent()->ChildIsDirty() or add to the set of + * reflow roots that need reflow) */ - - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) = 0; + virtual PRBool ChildIsDirty(nsIFrame* aChild) = 0; /** * Called to retrieve this frame's accessible. @@ -1394,10 +1530,6 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel)) NS_IMETHOD SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect, PRBool aRemoveOverflowArea = PR_FALSE)=0; NS_HIDDEN_(nsresult) Layout(nsBoxLayoutState& aBoxLayoutState); - nsresult IsDirty(PRBool& aIsDirty) { aIsDirty = (mState & NS_FRAME_IS_DIRTY) != 0; return NS_OK; } - nsresult HasDirtyChildren(PRBool& aIsDirty) { aIsDirty = (mState & NS_FRAME_HAS_DIRTY_CHILDREN) != 0; return NS_OK; } - NS_IMETHOD MarkDirty(nsBoxLayoutState& aState)=0; - NS_HIDDEN_(nsresult) MarkDirtyChildren(nsBoxLayoutState& aState); nsresult GetChildBox(nsIBox** aBox) { // box layout ends at box-wrapped frames, so don't allow these frames @@ -1438,12 +1570,8 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel)) { aIsNormal = IsNormalDirection(); return NS_OK; } NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState, const nsRect* aRect = nsnull, PRBool aImmediate = PR_FALSE); - NS_IMETHOD NeedsRecalc()=0; - NS_IMETHOD RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild)=0; NS_IMETHOD RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIBox* aChild)=0; NS_IMETHOD GetMouseThrough(PRBool& aMouseThrough)=0; - NS_IMETHOD MarkChildrenStyleChange()=0; - NS_IMETHOD MarkStyleChange(nsBoxLayoutState& aState)=0; NS_IMETHOD SetIncludeOverflow(PRBool aInclude) = 0; NS_IMETHOD GetOverflow(nsSize& aOverflow) = 0; diff --git a/mozilla/layout/generic/nsImageFrame.cpp b/mozilla/layout/generic/nsImageFrame.cpp index 66a95b7702a..72a274fd370 100644 --- a/mozilla/layout/generic/nsImageFrame.cpp +++ b/mozilla/layout/generic/nsImageFrame.cpp @@ -539,8 +539,9 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) NS_ASSERTION(mParent, "No parent to pass the reflow request up to."); NS_ASSERTION(presShell, "No PresShell."); if (mParent && presShell) { - mState |= NS_FRAME_IS_DIRTY; - mParent->ReflowDirtyChild(presShell, NS_STATIC_CAST(nsIFrame*, this)); + AddStateBits(NS_FRAME_IS_DIRTY); + presShell->FrameNeedsReflow(NS_STATIC_CAST(nsIFrame*, this), + nsIPresShell::eStyleChange); } } @@ -642,8 +643,9 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, if (!(mState & IMAGE_SIZECONSTRAINED) && intrinsicSizeChanged) { NS_ASSERTION(mParent, "No parent to pass the reflow request up to."); if (mParent && presShell) { - mState |= NS_FRAME_IS_DIRTY; - mParent->ReflowDirtyChild(presShell, NS_STATIC_CAST(nsIFrame*, this)); + AddStateBits(NS_FRAME_IS_DIRTY); + presShell->FrameNeedsReflow(NS_STATIC_CAST(nsIFrame*, this), + nsIPresShell::eStyleChange); } } else { nsSize s = GetSize(); @@ -687,9 +689,7 @@ nsImageFrame::FrameChanged(imgIContainer *aContainer, : (_value))) void -nsImageFrame::GetDesiredSize(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredSize) +nsImageFrame::EnsureIntrinsicSize(nsPresContext* aPresContext) { // if mIntrinsicSize.width and height are 0, then we should // check to see if the size is already known by the image container. @@ -724,6 +724,14 @@ nsImageFrame::GetDesiredSize(nsPresContext* aPresContext, RecalculateTransform(nsnull); } } +} + +void +nsImageFrame::GetDesiredSize(nsPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredSize) +{ + EnsureIntrinsicSize(aPresContext); // Handle intrinsic sizes and their interaction with // {min-,max-,}{width,height} according to the rules in @@ -910,13 +918,41 @@ nsImageFrame::GetContinuationOffset(nscoord* aWidth) const return offset; } +/* virtual */ nscoord +nsImageFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + nsPresContext *presContext = GetPresContext(); + EnsureIntrinsicSize(presContext); + // convert from normal twips to scaled twips (printing...) + float t2st = presContext->TwipsToPixels() * + presContext->ScaledPixelsToTwips(); + result = NSToCoordRound(float(mIntrinsicSize.width) * t2st); + return result; +} + +/* virtual */ nscoord +nsImageFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + nsPresContext *presContext = GetPresContext(); + EnsureIntrinsicSize(presContext); + // convert from normal twips to scaled twips (printing...) + float t2st = presContext->TwipsToPixels() * + presContext->ScaledPixelsToTwips(); + result = NSToCoordRound(float(mIntrinsicSize.width) * t2st); + return result; +} + NS_IMETHODIMP nsImageFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsImageFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsImageFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsImageFrame::Reflow: availSize=%d,%d", @@ -933,7 +969,9 @@ nsImageFrame::Reflow(nsPresContext* aPresContext, mState &= ~IMAGE_SIZECONSTRAINED; } - if (aReflowState.reason == eReflowReason_Initial) { + // XXXldb These two bits are almost exact opposites (except in the + // middle of the initial reflow); remove IMAGE_GOTINITIALREFLOW. + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { mState |= IMAGE_GOTINITIALREFLOW; } @@ -982,13 +1020,6 @@ nsImageFrame::Reflow(nsPresContext* aPresContext, aMetrics.ascent = aMetrics.height; aMetrics.descent = 0; - if (aMetrics.mComputeMEW) { - aMetrics.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit()); - } - - if (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aMetrics.mMaximumWidth = aMetrics.width; - } aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height); FinishAndStoreOverflow(&aMetrics); @@ -1709,8 +1740,10 @@ nsImageFrame::AttributeChanged(PRInt32 aNameSpaceID, } if (nsHTMLAtoms::alt == aAttribute) { - mState |= NS_FRAME_IS_DIRTY; - mParent->ReflowDirtyChild(GetPresContext()->PresShell(), (nsIFrame*) this); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()->FrameNeedsReflow( + NS_STATIC_CAST(nsIFrame*, this), + nsIPresShell::eStyleChange); } return NS_OK; diff --git a/mozilla/layout/generic/nsImageFrame.h b/mozilla/layout/generic/nsImageFrame.h index fc2843a5efa..5ff803705e4 100644 --- a/mozilla/layout/generic/nsImageFrame.h +++ b/mozilla/layout/generic/nsImageFrame.h @@ -99,6 +99,8 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -156,6 +158,7 @@ protected: virtual ~nsImageFrame(); + void EnsureIntrinsicSize(nsPresContext* aPresContext); virtual void GetDesiredSize(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsHTMLReflowMetrics& aDesiredSize); diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index b756d82659a..6ff305d87ff 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -47,7 +47,6 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLayoutAtoms.h" #include "nsCSSAnonBoxes.h" -#include "nsReflowPath.h" #include "nsAutoPtr.h" #include "nsFrameManager.h" #ifdef ACCESSIBILITY @@ -189,7 +188,9 @@ nsInlineFrame::AppendFrames(nsIAtom* aListName, mFrames.AppendFrames(this, aFrameList); // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return NS_OK; } @@ -213,7 +214,9 @@ nsInlineFrame::InsertFrames(nsIAtom* aListName, if (nsnull == aListName) #endif // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return NS_OK; } @@ -265,7 +268,9 @@ nsInlineFrame::RemoveFrame(nsIAtom* aListName, if (generateReflowCommand) { // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } } @@ -290,7 +295,9 @@ nsInlineFrame::ReplaceFrame(nsIAtom* aListName, mFrames.ReplaceFrame(this, aOldFrame, aNewFrame, PR_TRUE); // Ask the parent frame to reflow me. - ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return retval ? NS_OK : NS_ERROR_FAILURE; } @@ -330,13 +337,81 @@ nsInlineFrame::Paint(nsPresContext* aPresContext, ////////////////////////////////////////////////////////////////////// // Reflow methods +static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord) +{ + return aCoord.GetUnit() == eStyleUnit_Coord + ? aCoord.GetCoordValue() + : aIfNotCoord; +} + +void +nsInlineFrame::DoInlineIntrinsicWidth(nsIRenderingContext *aRenderingContext, + InlineIntrinsicWidthData *aData, + nsLayoutUtils::IntrinsicWidthType aType) +{ + if (mPrevInFlow) + return; // Already added. + + NS_PRECONDITION(aType == nsLayoutUtils::MIN_WIDTH || + aType == nsLayoutUtils::PREF_WIDTH, "bad type"); + + PRUint8 startSide, endSide; + // XXX set these correctly! (not trivial, and GetSkipSides() and + // maybe some reflow logic needs this too, and should all be fixed at + // once) + startSide = NS_SIDE_LEFT; + endSide = NS_SIDE_RIGHT; + + const nsStylePadding *stylePadding = GetStylePadding(); + const nsStyleBorder *styleBorder = GetStyleBorder(); + const nsStyleMargin *styleMargin = GetStyleMargin(); + nsStyleCoord tmp; + + aData->currentLine += + GetCoord(stylePadding->mPadding.Get(startSide, tmp), 0) + + styleBorder->GetBorderWidth(startSide) + + GetCoord(styleMargin->mMargin.Get(startSide, tmp), 0); + + for (nsInlineFrame *nif = this; nif; + nif = (nsInlineFrame*) nif->mNextInFlow) { + for (nsIFrame *kid = nif->mFrames.FirstChild(); kid; + kid = kid->GetNextSibling()) { + if (aType == nsLayoutUtils::MIN_WIDTH) + kid->AddInlineMinWidth(aRenderingContext, + NS_STATIC_CAST(InlineMinWidthData*, aData)); + else + kid->AddInlinePrefWidth(aRenderingContext, + NS_STATIC_CAST(InlinePrefWidthData*, aData)); + } + } + + aData->currentLine += + GetCoord(stylePadding->mPadding.Get(endSide, tmp), 0) + + styleBorder->GetBorderWidth(endSide) + + GetCoord(styleMargin->mMargin.Get(endSide, tmp), 0); +} + +/* virtual */ void +nsInlineFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlineMinWidthData *aData) +{ + DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::MIN_WIDTH); +} + +/* virtual */ void +nsInlineFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlinePrefWidthData *aData) +{ + DoInlineIntrinsicWidth(aRenderingContext, aData, nsLayoutUtils::PREF_WIDTH); +} + NS_IMETHODIMP nsInlineFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsInlineFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsInlineFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); if (nsnull == aReflowState.mLineLayout) { return NS_ERROR_INVALID_ARG; @@ -355,7 +430,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, prevOverflowFrames, prevInFlow, this); - if (aReflowState.reason == eReflowReason_Initial) { + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { // If it's the initial reflow, then our child list must be empty, so // just set the child list rather than calling InsertFrame(). This avoids // having to get the last child frame in the list. @@ -376,7 +451,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, // It's also possible that we have an overflow list for ourselves #ifdef DEBUG - if (aReflowState.reason == eReflowReason_Initial) { + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { // If it's our initial reflow, then we should not have an overflow list. // However, add an assertion in case we get reflowed more than once with // the initial reflow reason @@ -384,7 +459,7 @@ nsInlineFrame::Reflow(nsPresContext* aPresContext, NS_ASSERTION(!overflowFrames, "overflow list is not empty for initial reflow"); } #endif - if (aReflowState.reason != eReflowReason_Initial) { + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { nsIFrame* overflowFrames = GetOverflowFrames(aPresContext, PR_TRUE); if (overflowFrames) { NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); @@ -443,30 +518,6 @@ nsInlineFrame::CanContinueTextRun(PRBool& aContinueTextRun) const return NS_OK; } -NS_IMETHODIMP -nsInlineFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) -{ - // The inline container frame does not handle the reflow - // request. It passes it up to its parent container. - - // If you don't already have dirty children, - if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) { - if (mParent) { - // Record that you are dirty and have dirty children - mState |= NS_FRAME_IS_DIRTY; - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - // Pass the reflow request up to the parent - mParent->ReflowDirtyChild(aPresShell, this); - } - else { - NS_ERROR("No parent to pass the reflow request up to."); - } - } - - return NS_OK; -} - nsresult nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -574,8 +625,7 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, // that are empty we force to empty so that things like collapsed // whitespace in an inline element don't affect the line-height. nsSize size; - lineLayout->EndSpan(this, size, - aMetrics.mComputeMEW ? &aMetrics.mMaxElementWidth : nsnull); + lineLayout->EndSpan(this, size); if ((0 == size.height) && (0 == size.width) && ((nsnull != mPrevInFlow) || (nsnull != mNextInFlow))) { // This is a continuation of a previous inline. Therefore make @@ -584,9 +634,6 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, aMetrics.height = 0; aMetrics.ascent = 0; aMetrics.descent = 0; - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = 0; - } } else { // Compute final width @@ -634,9 +681,6 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext, ListTag(stdout); printf(": metrics=%d,%d ascent=%d descent=%d\n", aMetrics.width, aMetrics.height, aMetrics.ascent, aMetrics.descent); - if (aMetrics.mComputeMEW) { - printf(" maxElementWidth %d\n", aMetrics.mMaxElementWidth); - } #endif return rv; @@ -822,6 +866,11 @@ nsInlineFrame::PushFrames(nsPresContext* aPresContext, PRIntn nsInlineFrame::GetSkipSides() const { + // XXX This is wrong for RTL (see bug 299063). (Bidi cases will be + // fun, even once we fix bug 299065 and split inlines into multiple + // continuations.) + // DoInlineIntrinsicWidth needs to be fixed as well (and they should + // be fixed at the same time). PRIntn skip = 0; if (nsnull != mPrevInFlow) { nsInlineFrame* prev = (nsInlineFrame*) mPrevInFlow; @@ -1215,20 +1264,13 @@ nsPositionedInlineFrame::Reflow(nsPresContext* aPresContext, nscoord containingBlockHeight = aDesiredSize.height - computedBorder.TopBottom(); - // Do any incremental reflows ... would be nice to merge with - // the reflows below but that would be more work, and more risky - if (eReflowReason_Incremental == aReflowState.reason) { - mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState, - containingBlockWidth, - containingBlockHeight); - } - // Factor the absolutely positioned child bounds into the overflow area // Don't include this frame's bounds, nor its inline descendants' bounds, // and don't store the overflow property. // That will all be done by nsLineLayout::RelativePositionFrames. rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, containingBlockWidth, containingBlockHeight, + PR_TRUE, PR_TRUE, // XXX could be optimized &aDesiredSize.mOverflowArea); } diff --git a/mozilla/layout/generic/nsInlineFrame.h b/mozilla/layout/generic/nsInlineFrame.h index 5797a8ba8f1..e01335b2a02 100644 --- a/mozilla/layout/generic/nsInlineFrame.h +++ b/mozilla/layout/generic/nsInlineFrame.h @@ -41,6 +41,7 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLineLayout.h" #include "nsLayoutAtoms.h" +#include "nsLayoutUtils.h" class nsAnonymousBlockFrame; @@ -89,7 +90,6 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); #ifdef ACCESSIBILITY NS_IMETHODIMP GetAccessible(nsIAccessible** aAccessible); @@ -104,6 +104,10 @@ public: virtual PRBool IsSelfEmpty(); // nsIHTMLReflow overrides + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -136,6 +140,10 @@ protected: virtual PRIntn GetSkipSides() const; + void DoInlineIntrinsicWidth(nsIRenderingContext *aRenderingContext, + InlineIntrinsicWidthData *aData, + nsLayoutUtils::IntrinsicWidthType aType); + nsresult ReflowFrames(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, InlineReflowState& rs, diff --git a/mozilla/layout/generic/nsLeafFrame.cpp b/mozilla/layout/generic/nsLeafFrame.cpp index 2434b5a090c..4fc08331f3e 100644 --- a/mozilla/layout/generic/nsLeafFrame.cpp +++ b/mozilla/layout/generic/nsLeafFrame.cpp @@ -60,13 +60,39 @@ nsLeafFrame::Paint(nsPresContext* aPresContext, return NS_OK; } +/* virtual */ nscoord +nsLeafFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_MIN_WIDTH(this, metrics.width); + // XXX We really don't want to construct a reflow state here. This + // will probably cause problems, like setting dirty bits. + nsHTMLReflowState rs(GetPresContext(), this, aRenderingContext, + nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)); + GetDesiredSize(GetPresContext(), rs, metrics); + return metrics.width; +} + +/* virtual */ nscoord +nsLeafFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_PREF_WIDTH(this, metrics.width); + // XXX We really don't want to construct a reflow state here. This + // will probably cause problems, like setting dirty bits. + nsHTMLReflowState rs(GetPresContext(), this, aRenderingContext, + nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)); + GetDesiredSize(GetPresContext(), rs, metrics); + return metrics.width; +} + NS_IMETHODIMP nsLeafFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsLeafFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsLeafFrame"); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsLeafFrame::Reflow: aMaxSize=%d,%d", aReflowState.availableWidth, aReflowState.availableHeight)); @@ -80,9 +106,6 @@ nsLeafFrame::Reflow(nsPresContext* aPresContext, GetDesiredSize(aPresContext, aReflowState, aMetrics); nsMargin borderPadding; AddBordersAndPadding(aPresContext, aReflowState, aMetrics, borderPadding); - if (aMetrics.mComputeMEW) { - aMetrics.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit()); - } aStatus = NS_FRAME_COMPLETE; NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, diff --git a/mozilla/layout/generic/nsLeafFrame.h b/mozilla/layout/generic/nsLeafFrame.h index b7034c33395..8dff4c6a6d4 100644 --- a/mozilla/layout/generic/nsLeafFrame.h +++ b/mozilla/layout/generic/nsLeafFrame.h @@ -54,6 +54,8 @@ public: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/generic/nsLineBox.cpp b/mozilla/layout/generic/nsLineBox.cpp index c8253974980..68684b29006 100644 --- a/mozilla/layout/generic/nsLineBox.cpp +++ b/mozilla/layout/generic/nsLineBox.cpp @@ -56,8 +56,6 @@ MOZ_DECL_CTOR_COUNTER(nsLineBox) nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock) : mFirstChild(aFrame), mBounds(0, 0, 0, 0), - mMaxElementWidth(0), - mMaximumWidth(-1), mData(nsnull) { MOZ_COUNT_CTOR(nsLineBox); @@ -213,9 +211,6 @@ nsLineBox::List(FILE* out, PRInt32 aIndent) const if (IsBlock() && !GetCarriedOutBottomMargin().IsZero()) { fprintf(out, "bm=%d ", GetCarriedOutBottomMargin().get()); } - if (0 != mMaxElementWidth) { - fprintf(out, "mew=%d ", mMaxElementWidth); - } fprintf(out, "{%d,%d,%d,%d} ", mBounds.x, mBounds.y, mBounds.width, mBounds.height); if (mData) { diff --git a/mozilla/layout/generic/nsLineBox.h b/mozilla/layout/generic/nsLineBox.h index f8abcff1088..75416bea4db 100644 --- a/mozilla/layout/generic/nsLineBox.h +++ b/mozilla/layout/generic/nsLineBox.h @@ -83,9 +83,6 @@ public: // the containing block frame. nsRect mCombinedArea; - // The float's max-element-width. - nscoord mMaxElementWidth; - protected: nsFloatCache* mNext; @@ -449,9 +446,6 @@ public: nsIFrame* mFirstChild; nsRect mBounds; - nscoord mMaxElementWidth; // width part of max-element-size - nscoord mMaximumWidth; // maximum width (needed for incremental reflow of tables) - // includes the left border/padding but not the right struct FlagBits { PRUint32 mDirty : 1; diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 23d114c9ef3..779560265c8 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -56,7 +56,6 @@ #include "nsIRenderingContext.h" #include "nsLayoutAtoms.h" #include "nsPlaceholderFrame.h" -#include "nsReflowPath.h" #include "nsIDocument.h" #include "nsIHTMLDocument.h" #include "nsIContent.h" @@ -152,16 +151,18 @@ MOZ_DECL_CTOR_COUNTER(nsLineLayout) nsLineLayout::nsLineLayout(nsPresContext* aPresContext, nsSpaceManager* aSpaceManager, const nsHTMLReflowState* aOuterReflowState, - PRBool aComputeMaxElementWidth) + PRBool aIntrinsicWidthPass) : mPresContext(aPresContext), mSpaceManager(aSpaceManager), mBlockReflowState(aOuterReflowState), mBlockRS(nsnull),/* XXX temporary */ mMinLineHeight(0), - mComputeMaxElementWidth(aComputeMaxElementWidth), + mIntrinsicWidthPass(aIntrinsicWidthPass), mTextIndent(0), mWordFrames(0) { + NS_ASSERTION(!aSpaceManager == aIntrinsicWidthPass, + "space manager should be present iff not doing intrinsic widths"); MOZ_COUNT_CTOR(nsLineLayout); // Stash away some style data that we need @@ -550,9 +551,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame, } void -nsLineLayout::EndSpan(nsIFrame* aFrame, - nsSize& aSizeResult, - nscoord* aMaxElementWidth) +nsLineLayout::EndSpan(nsIFrame* aFrame, nsSize& aSizeResult) { NS_ASSERTION(mSpanDepth > 0, "end-span without begin-span"); #ifdef NOISY_REFLOW @@ -563,7 +562,6 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, PerSpanData* psd = mCurrentSpan; nscoord width = 0; nscoord maxHeight = 0; - nscoord maxElementWidth = 0; if (nsnull != psd->mLastFrame) { width = psd->mX - psd->mLeftEdge; PerFrameData* pfd = psd->mFirstFrame; @@ -581,39 +579,12 @@ nsLineLayout::EndSpan(nsIFrame* aFrame, if (pfd->mBounds.height > maxHeight) maxHeight = pfd->mBounds.height; // Compute max-element-width if necessary - if (aMaxElementWidth) { - nscoord mw = pfd->mMaxElementWidth; - // add only fixed margins to the MEW - if (pfd->mMargin.left) { - if (pfd->mFrame->GetStyleMargin()->mMargin.GetLeftUnit() == - eStyleUnit_Coord) - mw += pfd->mMargin.left; - } - if (pfd->mMargin.right) { - if (pfd->mFrame->GetStyleMargin()->mMargin.GetRightUnit() == - eStyleUnit_Coord) - mw += pfd->mMargin.right; - } - if (maxElementWidth < mw) { - maxElementWidth = mw; - } - } } pfd = pfd->mNext; } } aSizeResult.width = width; aSizeResult.height = maxHeight; - if (aMaxElementWidth) { - if (psd->mNoWrap) { - // When we have a non-breakable span, it's max-element-width - // width is its entire width. - *aMaxElementWidth = width; - } - else { - *aMaxElementWidth = maxElementWidth; - } - } mSpanDepth--; mCurrentSpan->mReflowState = nsnull; // no longer valid so null it out! @@ -846,69 +817,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // columns, but it's not clear how to handle that anyway availSize.height = NS_UNCONSTRAINEDSIZE; - // Get reflow reason set correctly. It's possible that a child was - // created and then it was decided that it could not be reflowed - // (for example, a block frame that isn't at the start of a - // line). In this case the reason will be wrong so we need to check - // the frame state. - const nsHTMLReflowState* rs = psd->mReflowState; - nsReflowReason reason = eReflowReason_Resize; - if (NS_FRAME_FIRST_REFLOW & aFrame->GetStateBits()) { - reason = eReflowReason_Initial; - } - else if (rs->reason == eReflowReason_Initial && - mBlockReflowState->reason == eReflowReason_StyleChange) { - // The frame we're about to reflow is an _old_ frame that was - // pushed inside a _new_ parent (overflow). - - // So we propagate the same 'style change' that led to creating - // the new overflow parent to which this frame is now the child - reason = eReflowReason_StyleChange; - } - else if (rs->reason == eReflowReason_Incremental) { // XXX - // XXXwaterson (above) previously used mBlockReflowState rather - // than psd->mReflowState. - - // If the frame we're about to reflow is on the reflow path, then - // propagate the reflow as `incremental' so it unwinds correctly - // to the target frames below us. - PRBool frameIsOnReflowPath = rs->path->HasChild(aFrame); - if (frameIsOnReflowPath) - reason = eReflowReason_Incremental; - - // But...if the incremental reflow command is a StyleChanged - // reflow and its target is the current span, change the reason - // to `style change', so that it propagates through the entire - // subtree. - nsHTMLReflowCommand* rc = rs->path->mReflowCommand; - if (rc) { - nsReflowType type = rc->Type(); - if (type == eReflowType_StyleChanged) { - nsIFrame* parentFrame = psd->mFrame - ? psd->mFrame->mFrame - : mBlockReflowState->frame; - if (rc->GetTarget() == parentFrame) { - reason = eReflowReason_StyleChange; - } - } - else if (type == eReflowType_ReflowDirty && - (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY) && - !frameIsOnReflowPath) { - reason = eReflowReason_Dirty; - } - } - } - else if (rs->reason == eReflowReason_StyleChange) { - reason = eReflowReason_StyleChange; - } - else if (rs->reason == eReflowReason_Dirty) { - if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY) - reason = eReflowReason_Dirty; - } - // Setup reflow state for reflowing the frame nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState, - aFrame, availSize, reason); + aFrame, availSize); reflowState.mLineLayout = this; reflowState.mFlags.mIsTopOfPage = GetFlag(LL_ISTOPOFPAGE); SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE); @@ -966,19 +877,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, // parents border/padding is inside the parent // frame. Therefore we have to subtract out the parents // border+padding before translating. - nsHTMLReflowMetrics metrics(mComputeMaxElementWidth); + nsHTMLReflowMetrics metrics; #ifdef DEBUG metrics.width = nscoord(0xdeadbeef); metrics.height = nscoord(0xdeadbeef); metrics.ascent = nscoord(0xdeadbeef); metrics.descent = nscoord(0xdeadbeef); - if (mComputeMaxElementWidth) { - metrics.mMaxElementWidth = nscoord(0xdeadbeef); - } #endif nscoord tx = x - psd->mReflowState->mComputedBorderPadding.left; nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top; - mSpaceManager->Translate(tx, ty); + if (!mIntrinsicWidthPass) + mSpaceManager->Translate(tx, ty); #ifdef IBMBIDI PRInt32 start, end; @@ -1010,7 +919,10 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, if (outOfFlowFrame) { nsPlaceholderFrame* placeholder = NS_STATIC_CAST(nsPlaceholderFrame*, aFrame); PRBool didPlace; - if (eReflowReason_Incremental == reason) { + // XXXldb What is this test supposed to be? + if (!(aFrame->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { + // incremental reflow of child didPlace = InitFloat(placeholder, aReflowStatus); } else { @@ -1063,7 +975,8 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, } } - mSpaceManager->Translate(-tx, -ty); + if (!mIntrinsicWidthPass) + mSpaceManager->Translate(-tx, -ty); NS_ASSERTION(metrics.width>=0, "bad width"); NS_ASSERTION(metrics.height>=0,"bad height"); @@ -1079,24 +992,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsFrame::ListTag(stdout, aFrame); printf(" metrics=%d,%d!\n", metrics.width, metrics.height); } - if (mComputeMaxElementWidth && - (nscoord(0xdeadbeef) == metrics.mMaxElementWidth)) { - printf("nsLineLayout: "); - nsFrame::ListTag(stdout, aFrame); - printf(" didn't set max-element-width!\n"); - } -#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE - // Note: there are common reflow situations where this *correctly* - // occurs; so only enable this debug noise when you really need to - // analyze in detail. - if (mComputeMaxElementWidth && - (metrics.mMaxElementWidth > metrics.width)) { - printf("nsLineLayout: "); - nsFrame::ListTag(stdout, aFrame); - printf(": WARNING: maxElementWidth=%d > metrics=%d\n", - metrics.mMaxElementWidth, metrics.width); - } -#endif if ((metrics.width == nscoord(0xdeadbeef)) || (metrics.height == nscoord(0xdeadbeef)) || (metrics.ascent == nscoord(0xdeadbeef)) || @@ -1108,20 +1003,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, } } #endif -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) { - if (mComputeMaxElementWidth) { - printf(" "); - nsFrame::ListTag(stdout, aFrame); - printf(": maxElementWidth=%d wh=%d,%d,\n", - metrics.mMaxElementWidth, - metrics.width, metrics.height); - } - } - } -#endif // Unlike with non-inline reflow, the overflow area here does *not* // include the accumulation of the frame's bounds and its inline @@ -1132,9 +1013,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, pfd->mBounds.width = metrics.width; pfd->mBounds.height = metrics.height; - if (mComputeMaxElementWidth) { - pfd->mMaxElementWidth = metrics.mMaxElementWidth; - } // Size the frame, but |RelativePositionFrames| will size the view. aFrame->SetSize(nsSize(metrics.width, metrics.height)); @@ -1513,9 +1391,6 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame, // Note: y value will be updated during vertical alignment pfd->mBounds = aFrame->GetRect(); pfd->mCombinedArea = aMetrics.mOverflowArea; - if (mComputeMaxElementWidth) { - pfd->mMaxElementWidth = aMetrics.width; - } } return rv; } @@ -1615,8 +1490,7 @@ PRBool IsPercentageAwareFrame(nsPresContext *aPresContext, nsIFrame *aFrame) void -nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox, - nscoord* aMaxElementWidthResult) +nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox) { // Synthesize a PerFrameData for the block frame PerFrameData rootPFD; @@ -1687,95 +1561,7 @@ nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox, // frames we find. // XXX PERFORMANCE: set a bit per-span to avoid the extra work // (propagate it upward too) - PerFrameData* pfd = psd->mFirstFrame; - nscoord maxElementWidth = 0; - PRBool prevFrameAccumulates = PR_FALSE; - nscoord accumulatedWidth = 0; -#ifdef HACK_MEW - PRBool strictMode = InStrictMode(); - PRBool inUnconstrainedTable = InUnconstrainedTableCell(*mBlockReflowState); -#endif -#ifdef DEBUG - int frameCount = 0; -#endif - - nscoord indent = mTextIndent; // Used for the first frame. - - while (nsnull != pfd) { - - // Compute max-element-width if necessary - if (mComputeMaxElementWidth) { - - nscoord mw = pfd->mMaxElementWidth + indent; - // add only fixed margins to the MEW - if (pfd->mMargin.left) { - if (pfd->mFrame->GetStyleMargin()->mMargin.GetLeftUnit() == - eStyleUnit_Coord) - mw += pfd->mMargin.left; - } - if (pfd->mMargin.right) { - if (pfd->mFrame->GetStyleMargin()->mMargin.GetRightUnit() == - eStyleUnit_Coord) - mw += pfd->mMargin.right; - } - - // Zero |indent| after including the 'text-indent' only for the - // frame that is indented. - indent = 0; - - if (psd->mNoWrap) { - maxElementWidth += mw; - } - else { - -#ifdef HACK_MEW - -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) - frameCount++; -#endif - // if in Quirks mode and in a table cell with an unconstrained width, then emulate an IE - // quirk to keep consecutive images from breaking the line - // - see bugs 54565, 32191, and their many dups - // XXX - reconsider how textFrame text measurement happens and have it take into account - // image frames as well, thus eliminating the need for this code - if (!strictMode && inUnconstrainedTable ) { - - nscoord imgSizes = AccumulateImageSizes(*mPresContext, *pfd->mFrame); - PRBool curFrameAccumulates = (imgSizes > 0) || - (pfd->mMaxElementWidth == pfd->mBounds.width && - pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)); - // NOTE: we check for the maxElementWidth == the boundsWidth to detect when - // a textframe has whitespace in it and thus should not be used as the basis - // for accumulating the image width - // - this is to handle images in a text run - - if(prevFrameAccumulates && curFrameAccumulates) { - accumulatedWidth += mw; - } else { - accumulatedWidth = mw; - } - // now update the prevFrame - prevFrameAccumulates = curFrameAccumulates; - -#ifdef DEBUG - if (nsBlockFrame::gNoisyMaxElementWidth) { - nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); - printf("(%d) last frame's MEW=%d | Accumulated MEW=%d\n", frameCount, mw, accumulatedWidth); - } -#endif - - mw = accumulatedWidth; - } - -#endif // HACK_MEW - - // and finally reset the max element width - if (maxElementWidth < mw) { - maxElementWidth = mw; - } - } - } + for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { PerSpanData* span = pfd->mSpan; #ifdef DEBUG NS_ASSERTION(0xFF != pfd->mVerticalAlign, "umr"); @@ -1824,7 +1610,6 @@ nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox, if (IsPercentageAwareFrame(mPresContext, pfd->mFrame)) aLineBox->DisableResizeReflowOptimization(); } - pfd = pfd->mNext; } // Fill in returned line-box and max-element-width data @@ -1833,15 +1618,13 @@ nsLineLayout::VerticalAlignLine(nsLineBox* aLineBox, aLineBox->mBounds.width = psd->mX - psd->mLeftEdge; aLineBox->mBounds.height = lineHeight; mFinalLineHeight = lineHeight; - *aMaxElementWidthResult = maxElementWidth; aLineBox->SetAscent(baselineY - mTopEdge); #ifdef NOISY_VERTICAL_ALIGN printf( - " [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d mew=%d\n", + " [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n", aLineBox->mBounds.x, aLineBox->mBounds.y, aLineBox->mBounds.width, aLineBox->mBounds.height, - mFinalLineHeight, aLineBox->GetAscent(), - *aMaxElementWidthResult); + mFinalLineHeight, aLineBox->GetAscent()); #endif // Undo root-span mFrame pointer to prevent brane damage later on... @@ -2643,9 +2426,6 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd, if (deltaWidth) { pfd->mBounds.width -= deltaWidth; - if (0 == pfd->mBounds.width) { - pfd->mMaxElementWidth = 0; - } // See if the text frame has already been placed in its parent if (psd != mRootSpan) { @@ -2775,20 +2555,20 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState return deltaX; } -PRBool +void nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, - PRBool aAllowJustify, - PRBool aShrinkWrapWidth) + PRBool aAllowJustify) { PerSpanData* psd = mRootSpan; nscoord availWidth = psd->mRightEdge; if (NS_UNCONSTRAINEDSIZE == availWidth) { + NS_NOTREACHED("This shouldn't be called anymore"); // Don't bother horizontal aligning on pass1 table reflow #ifdef NOISY_HORIZONTAL_ALIGN nsFrame::ListTag(stdout, mBlockReflowState->frame); printf(": skipping horizontal alignment in pass1 table reflow\n"); #endif - return PR_TRUE; + return; } availWidth -= psd->mLeftEdge; nscoord remainingWidth = availWidth - aLineBounds.width; @@ -2830,17 +2610,15 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, // frames in the line. If it is the last line then if the // direction is right-to-left then we right-align the frames. if (aAllowJustify) { - if (!aShrinkWrapWidth) { - PRInt32 numSpaces; - PRInt32 numLetters; + PRInt32 numSpaces; + PRInt32 numLetters; - ComputeJustificationWeights(psd, &numSpaces, &numLetters); + ComputeJustificationWeights(psd, &numSpaces, &numLetters); - if (numSpaces > 0) { - FrameJustificationState state = { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 }; + if (numSpaces > 0) { + FrameJustificationState state = { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 }; - ApplyFrameJustification(psd, &state); - } + ApplyFrameJustification(psd, &state); } } else if (NS_STYLE_DIRECTION_RTL == psd->mDirection) { @@ -2876,11 +2654,6 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, if (0 != dx) #endif { - // If we need to move the frames but we're shrink wrapping, then - // we need to wait until the final width is known - if (aShrinkWrapWidth) { - return PR_FALSE; - } for (PerFrameData* pfd = psd->mFirstFrame; pfd #ifdef IBMBIDI && bulletPfd != pfd @@ -2903,10 +2676,6 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, !psd->mChangedFrameDirection) { psd->mChangedFrameDirection = PR_TRUE; - /* Assume that all frames have been right aligned.*/ - if (aShrinkWrapWidth) { - return PR_FALSE; - } PerFrameData* pfd = psd->mFirstFrame; PRUint32 maxX = psd->mRightEdge; while (nsnull != pfd) { @@ -2918,8 +2687,6 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds, } #endif // ndef IBMBIDI } - - return PR_TRUE; } void diff --git a/mozilla/layout/generic/nsLineLayout.h b/mozilla/layout/generic/nsLineLayout.h index 30022312820..77180561d13 100644 --- a/mozilla/layout/generic/nsLineLayout.h +++ b/mozilla/layout/generic/nsLineLayout.h @@ -62,7 +62,7 @@ public: nsLineLayout(nsPresContext* aPresContext, nsSpaceManager* aSpaceManager, const nsHTMLReflowState* aOuterReflowState, - PRBool aComputeMaxElementWidth); + PRBool aIntrinsicWidthPass); ~nsLineLayout(); class ArenaDeque : public nsDeque @@ -92,6 +92,8 @@ public: return mLineNumber; } + PRBool GetIntrinsicWidthPass() const { return mIntrinsicWidthPass; } + void BeginLineReflow(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aImpactedByFloats, @@ -108,8 +110,7 @@ public: nscoord aLeftEdge, nscoord aRightEdge); - void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult, - nscoord* aMaxElementWidth); + void EndSpan(nsIFrame* aFrame, nsSize& aSizeResult); PRInt32 GetCurrentSpanCount() const; @@ -131,14 +132,11 @@ public: PushFrame(aFrame); } - void VerticalAlignLine(nsLineBox* aLineBox, - nscoord* aMaxElementWidthResult); + void VerticalAlignLine(nsLineBox* aLineBox); PRBool TrimTrailingWhiteSpace(); - PRBool HorizontalAlignFrames(nsRect& aLineBounds, - PRBool aAllowJustify, - PRBool aShrinkWrapWidth); + void HorizontalAlignFrames(nsRect& aLineBounds, PRBool aAllowJustify); /** * Handle all the relative positioning in the line, compute the @@ -300,7 +298,7 @@ protected: nsBlockReflowState* mBlockRS;/* XXX hack! */ nsCompatibility mCompatMode; nscoord mMinLineHeight; - PRPackedBool mComputeMaxElementWidth; + PRPackedBool mIntrinsicWidthPass; PRUint8 mTextAlign; PRUint8 mPlacedFloats; @@ -355,7 +353,6 @@ protected: // From metrics nscoord mAscent, mDescent; nsRect mBounds; - nscoord mMaxElementWidth; nsRect mCombinedArea; // From reflow-state diff --git a/mozilla/layout/generic/nsObjectFrame.cpp b/mozilla/layout/generic/nsObjectFrame.cpp index 9822529757f..310e34c45db 100644 --- a/mozilla/layout/generic/nsObjectFrame.cpp +++ b/mozilla/layout/generic/nsObjectFrame.cpp @@ -798,6 +798,43 @@ nsObjectFrame::CreateWidget(nscoord aWidth, #define EMBED_DEF_WIDTH 240 #define EMBED_DEF_HEIGHT 200 +/* virtual */ nscoord +nsObjectFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + // XXX Add DISPLAY_MIN_WIDTH(this, result) after merging. + + if (IsHidden(PR_FALSE)) + return 0; + + nsIFrame * child = mFrames.FirstChild(); + if (IsBroken() && !child) { + nsHTMLReflowMetrics metrics; + nsHTMLReflowState rs(GetPresContext(), this, aRenderingContext, + nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)); + CreateDefaultFrames(GetPresContext(), metrics, rs); + child = mFrames.FirstChild(); + + // XXX SizeAnchor stuff + } + + if (child) + return child->GetMinWidth(aRenderingContext); + + nsIAtom *atom = mContent->Tag(); + if (atom == nsHTMLAtoms::applet || atom == nsHTMLAtoms::embed) { + float p2t = GetPresContext()->ScaledPixelsToTwips(); + return NSIntPixelsToTwips(EMBED_DEF_WIDTH, p2t); + } + + return 0; +} + +/* virtual */ nscoord +nsObjectFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + return nsObjectFrame::GetMinWidth(aRenderingContext); +} + void nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, @@ -810,9 +847,6 @@ nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext, aMetrics.descent = 0; if (IsHidden(PR_FALSE)) { - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = 0; - } return; } @@ -871,10 +905,6 @@ nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext, // ascent aMetrics.ascent = aMetrics.height; - - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = aMetrics.width; - } } nsresult @@ -930,7 +960,7 @@ nsObjectFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsObjectFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsObjectFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); nsresult rv = NS_OK; @@ -963,15 +993,6 @@ nsObjectFrame::Reflow(nsPresContext* aPresContext, // Set the child's content width and height SizeAnchor(child->GetContent(), width, height); - - // SizeAnchor() is seriously evil as it ends up setting an - // attribute (through the style changes that it does) while - // we're in reflow. This is also seriously evil, as it pulls - // that reflow command out of the reflow queue, as leaving it - // there can get us into infinite loops while reflowing object - // frames for missing plugins. - nsReflowType reflowType(eReflowType_StyleChanged); - aPresContext->PresShell()->CancelReflowCommand(child, &reflowType); } } @@ -2844,8 +2865,8 @@ nsObjectFrame::PluginNotAvailable(const char *aMimeType) mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - GetParent()->ReflowDirtyChild(mContent->GetDocument()->GetShellAt(0), - this); + mContent->GetDocument()->GetShellAt(0)-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } } diff --git a/mozilla/layout/generic/nsObjectFrame.h b/mozilla/layout/generic/nsObjectFrame.h index 8083da64640..5cd560de627 100644 --- a/mozilla/layout/generic/nsObjectFrame.h +++ b/mozilla/layout/generic/nsObjectFrame.h @@ -67,6 +67,8 @@ public: nsIFrame* aParent, nsStyleContext* aContext, nsIFrame* aPrevInFlow); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/generic/nsPageContentFrame.cpp b/mozilla/layout/generic/nsPageContentFrame.cpp index 41af17f2dcb..b19b78755c4 100644 --- a/mozilla/layout/generic/nsPageContentFrame.cpp +++ b/mozilla/layout/generic/nsPageContentFrame.cpp @@ -76,11 +76,11 @@ NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; // initialize out parameter - if (eReflowReason_Incremental != aReflowState.reason) { + if (GetStateBits() & NS_FRAME_IS_DIRTY) { // Resize our frame allowing it only to be as big as we are // XXX Pay attention to the page's border and padding... if (mFrames.NotEmpty()) { @@ -133,8 +133,10 @@ NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext, #endif } // Reflow our fixed frames - mFixedContainer.Reflow(this, aPresContext, aReflowState, aReflowState.availableWidth, - aReflowState.availableHeight); + mFixedContainer.Reflow(this, aPresContext, aReflowState, + aReflowState.availableWidth, + aReflowState.availableHeight, + PR_TRUE, PR_TRUE); // XXX could be optimized // Return our desired size aDesiredSize.width = aReflowState.availableWidth; diff --git a/mozilla/layout/generic/nsPageFrame.cpp b/mozilla/layout/generic/nsPageFrame.cpp index e89bed39eab..a2c8b181aad 100644 --- a/mozilla/layout/generic/nsPageFrame.cpp +++ b/mozilla/layout/generic/nsPageFrame.cpp @@ -139,11 +139,11 @@ NS_IMETHODIMP nsPageFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsPageFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsPageFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; // initialize out parameter - if (eReflowReason_Incremental != aReflowState.reason) { + if (GetStateBits() & NS_FRAME_IS_DIRTY) { // Do we have any children? // XXX We should use the overflow list instead... nsIFrame* firstFrame = mFrames.FirstChild(); @@ -737,9 +737,6 @@ nsPageBreakFrame::GetDesiredSize(nsPresContext* aPresContext, aDesiredSize.height -= aDesiredSize.height % onePixel; } - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = onePixel; - } aDesiredSize.ascent = 0; aDesiredSize.descent = 0; } @@ -751,7 +748,7 @@ nsPageBreakFrame::Reflow(nsPresContext* aPresContext, nsReflowStatus& aStatus) { NS_PRECONDITION(aPresContext, "null pres context"); - DO_GLOBAL_REFLOW_COUNT("nsTableFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsTableFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; diff --git a/mozilla/layout/generic/nsPlaceholderFrame.cpp b/mozilla/layout/generic/nsPlaceholderFrame.cpp index dd0b658a27c..bad8f6a2eee 100644 --- a/mozilla/layout/generic/nsPlaceholderFrame.cpp +++ b/mozilla/layout/generic/nsPlaceholderFrame.cpp @@ -66,21 +66,45 @@ nsPlaceholderFrame::~nsPlaceholderFrame() { } +/* virtual */ void +nsPlaceholderFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlineMinWidthData *aData) +{ + // Override AddInlineMinWith so that *nothing* happens. In + // particular, we don't want to set aData->skipWhitespace to false. + + // ...but push floats onto the list + if (mOutOfFlowFrame->GetStyleDisplay()->mFloats != NS_STYLE_FLOAT_NONE) + aData->floats.AppendElement(mOutOfFlowFrame); +} + +/* virtual */ void +nsPlaceholderFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlinePrefWidthData *aData) +{ + // Override AddInlinePrefWith so that *nothing* happens. In + // particular, we don't want to zero out |aData->trailingWhitespace|, + // since nsLineLayout skips placeholders when trimming trailing + // whitespace, and we don't want to set aData->skipWhitespace to + // false. + + // ...but push floats onto the list + if (mOutOfFlowFrame->GetStyleDisplay()->mFloats != NS_STYLE_FLOAT_NONE) + aData->floats.AppendElement(mOutOfFlowFrame); +} + NS_IMETHODIMP nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aDesiredSize.width = 0; aDesiredSize.height = 0; aDesiredSize.ascent = 0; aDesiredSize.descent = 0; - if (aDesiredSize.mComputeMEW) { - aDesiredSize.mMaxElementWidth = 0; - } aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); diff --git a/mozilla/layout/generic/nsPlaceholderFrame.h b/mozilla/layout/generic/nsPlaceholderFrame.h index 44cfa87c016..71bf17a0864 100644 --- a/mozilla/layout/generic/nsPlaceholderFrame.h +++ b/mozilla/layout/generic/nsPlaceholderFrame.h @@ -60,6 +60,10 @@ public: void SetOutOfFlowFrame(nsIFrame* aFrame) {mOutOfFlowFrame = aFrame;} // nsIHTMLReflow overrides + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/generic/nsSimplePageSequence.cpp b/mozilla/layout/generic/nsSimplePageSequence.cpp index 5174492e50f..8b01c567b96 100644 --- a/mozilla/layout/generic/nsSimplePageSequence.cpp +++ b/mozilla/layout/generic/nsSimplePageSequence.cpp @@ -223,18 +223,15 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsSimplePageSequenceFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("nsSimplePageSequenceFrame::Reflow"); aStatus = NS_FRAME_COMPLETE; // we're always complete - // absolutely ignore all other types of reflows + // absolutely ignore all other reflows // we only want to have done the Initial Reflow - if (eReflowReason_Resize == aReflowState.reason || - eReflowReason_Incremental == aReflowState.reason || - eReflowReason_StyleChange == aReflowState.reason || - eReflowReason_Dirty == aReflowState.reason) { + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Return our desired size aDesiredSize.height = mSize.height; aDesiredSize.width = mSize.width; @@ -354,130 +351,120 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, nsSize reflowPageSize(0,0); - // See if it's an incremental reflow command - if (eReflowReason_Incremental == aReflowState.reason) { - // XXX Skip Incremental reflow, - // in fact, all we want is the initial reflow - y = mRect.height; - } else { - // XXX Part of Temporary fix for Bug 127263 - nsPageFrame::SetCreateWidget(PR_TRUE); + // XXX Part of Temporary fix for Bug 127263 + nsPageFrame::SetCreateWidget(PR_TRUE); - nsReflowReason reflowReason = aReflowState.reason; + SetPageSizes(pageSize, margin); - SetPageSizes(pageSize, margin); + // Tile the pages vertically + nsHTMLReflowMetrics kidSize(nsnull); + for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) { + // Reflow the page + // The availableHeight always comes in NS_UNCONSTRAINEDSIZE, so we need to check + // the "adjusted rect" to see if that is being reflowed NS_UNCONSTRAINEDSIZE or not + // When it is NS_UNCONSTRAINEDSIZE it means we are reflowing a single page + // to print selection. So this means we want to use NS_UNCONSTRAINEDSIZE without altering it + nsRect actualRect; + nsRect adjRect; + aPresContext->GetPageDim(&actualRect, &adjRect); + nscoord avHeight; + if (adjRect.height == NS_UNCONSTRAINEDSIZE) { + avHeight = NS_UNCONSTRAINEDSIZE; + } else { + avHeight = pageSize.height+deadSpaceMargin.top+deadSpaceMargin.bottom+shadowSize.height+extraMargin.top+extraMargin.bottom; + } + nsSize availSize(pageSize.width+deadSpaceMargin.right+deadSpaceMargin.left+shadowSize.width+extraMargin.right+extraMargin.left, + avHeight); + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, + availSize); + nsReflowStatus status; - // Tile the pages vertically - nsHTMLReflowMetrics kidSize(nsnull); - for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) { - // Reflow the page - // The availableHeight always comes in NS_UNCONSTRAINEDSIZE, so we need to check - // the "adjusted rect" to see if that is being reflowed NS_UNCONSTRAINEDSIZE or not - // When it is NS_UNCONSTRAINEDSIZE it means we are reflowing a single page - // to print selection. So this means we want to use NS_UNCONSTRAINEDSIZE without altering it - nsRect actualRect; - nsRect adjRect; - aPresContext->GetPageDim(&actualRect, &adjRect); - nscoord avHeight; - if (adjRect.height == NS_UNCONSTRAINEDSIZE) { - avHeight = NS_UNCONSTRAINEDSIZE; - } else { - avHeight = pageSize.height+deadSpaceMargin.top+deadSpaceMargin.bottom+shadowSize.height+extraMargin.top+extraMargin.bottom; - } - nsSize availSize(pageSize.width+deadSpaceMargin.right+deadSpaceMargin.left+shadowSize.width+extraMargin.right+extraMargin.left, - avHeight); - nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, - availSize, reflowReason); - nsReflowStatus status; + kidReflowState.mComputedWidth = kidReflowState.availableWidth; + //kidReflowState.mComputedHeight = kidReflowState.availableHeight; + PR_PL(("AV W: %d H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight)); - kidReflowState.mComputedWidth = kidReflowState.availableWidth; - //kidReflowState.mComputedHeight = kidReflowState.availableHeight; - PR_PL(("AV W: %d H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight)); + // Set the shared data into the page frame before reflow + nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, kidFrame); + pf->SetSharedPageData(mPageData); - // Set the shared data into the page frame before reflow - nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, kidFrame); - pf->SetSharedPageData(mPageData); + // Place and size the page. If the page is narrower than our + // max width then center it horizontally + ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status); - // Place and size the page. If the page is narrower than our - // max width then center it horizontally - ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, x, y, 0, status); + reflowPageSize.SizeTo(kidSize.width, kidSize.height); - reflowPageSize.SizeTo(kidSize.width, kidSize.height); + FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0); + y += kidSize.height; - FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0); - y += kidSize.height; - - // XXX Temporary fix for Bug 127263 - // This tells the nsPageFrame class to stop creating clipping widgets - // once we reach the 32k boundary for positioning - if (nsPageFrame::GetCreateWidget()) { - float t2p; - t2p = aPresContext->TwipsToPixels(); - nscoord xp = NSTwipsToIntPixels(x, t2p); - nscoord yp = NSTwipsToIntPixels(y, t2p); - nsPageFrame::SetCreateWidget(xp < 0x8000 && yp < 0x8000); - } - - // Leave a slight gap between the pages - y += deadSpaceGap; - - // Is the page complete? - nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); - - if (NS_FRAME_IS_COMPLETE(status)) { - NS_ASSERTION(nsnull == kidNextInFlow, "bad child flow list"); - } else if (nsnull == kidNextInFlow) { - // The page isn't complete and it doesn't have a next-in-flow, so - // create a continuing page - nsIFrame* continuingPage; - CreateContinuingPageFrame(aPresContext, kidFrame, &continuingPage); - - // Add it to our child list - kidFrame->SetNextSibling(continuingPage); - reflowReason = eReflowReason_Initial; - } - - // Get the next page - kidFrame = kidFrame->GetNextSibling(); + // XXX Temporary fix for Bug 127263 + // This tells the nsPageFrame class to stop creating clipping widgets + // once we reach the 32k boundary for positioning + if (nsPageFrame::GetCreateWidget()) { + float t2p; + t2p = aPresContext->TwipsToPixels(); + nscoord xp = NSTwipsToIntPixels(x, t2p); + nscoord yp = NSTwipsToIntPixels(y, t2p); + nsPageFrame::SetCreateWidget(xp < 0x8000 && yp < 0x8000); } - // Get Total Page Count - nsIFrame* page; - PRInt32 pageTot = 0; - for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { - pageTot++; + // Leave a slight gap between the pages + y += deadSpaceGap; + + // Is the page complete? + nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); + + if (NS_FRAME_IS_COMPLETE(status)) { + NS_ASSERTION(nsnull == kidNextInFlow, "bad child flow list"); + } else if (nsnull == kidNextInFlow) { + // The page isn't complete and it doesn't have a next-in-flow, so + // create a continuing page + nsIFrame* continuingPage; + CreateContinuingPageFrame(aPresContext, kidFrame, &continuingPage); + + // Add it to our child list + kidFrame->SetNextSibling(continuingPage); } - // Set Page Number Info - PRInt32 pageNum = 1; - for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { - nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, page); - if (pf != nsnull) { - pf->SetPageNumInfo(pageNum, pageTot); - } - pageNum++; - } - - // Create current Date/Time String - if (!mDateFormatter) - mDateFormatter = do_CreateInstance(kDateTimeFormatCID); -#ifndef WINCE - NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE); - - nsAutoString formattedDateString; - time_t ltime; - time( <ime ); - if (NS_SUCCEEDED(mDateFormatter->FormatTime(nsnull /* nsILocale* locale */, - kDateFormatShort, - kTimeFormatNoSeconds, - ltime, - formattedDateString))) { - PRUnichar * uStr = ToNewUnicode(formattedDateString); - SetDateTimeStr(uStr); // memory will be freed - } -#endif + // Get the next page + kidFrame = kidFrame->GetNextSibling(); } + // Get Total Page Count + nsIFrame* page; + PRInt32 pageTot = 0; + for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { + pageTot++; + } + + // Set Page Number Info + PRInt32 pageNum = 1; + for (page = mFrames.FirstChild(); page; page = page->GetNextSibling()) { + nsPageFrame * pf = NS_STATIC_CAST(nsPageFrame*, page); + if (pf != nsnull) { + pf->SetPageNumInfo(pageNum, pageTot); + } + pageNum++; + } + + // Create current Date/Time String + if (!mDateFormatter) + mDateFormatter = do_CreateInstance(kDateTimeFormatCID); +#ifndef WINCE + NS_ENSURE_TRUE(mDateFormatter, NS_ERROR_FAILURE); + + nsAutoString formattedDateString; + time_t ltime; + time( <ime ); + if (NS_SUCCEEDED(mDateFormatter->FormatTime(nsnull /* nsILocale* locale */, + kDateFormatShort, + kTimeFormatNoSeconds, + ltime, + formattedDateString))) { + PRUnichar * uStr = ToNewUnicode(formattedDateString); + SetDateTimeStr(uStr); // memory will be freed + } +#endif + // Return our desired size aDesiredSize.height = y; aDesiredSize.width = reflowPageSize.width+deadSpaceMargin.right+shadowSize.width+extraMargin.right+extraMargin.left; diff --git a/mozilla/layout/generic/nsSpacerFrame.cpp b/mozilla/layout/generic/nsSpacerFrame.cpp index 4532c6f91cc..bcdfda98c45 100644 --- a/mozilla/layout/generic/nsSpacerFrame.cpp +++ b/mozilla/layout/generic/nsSpacerFrame.cpp @@ -53,6 +53,8 @@ public: friend nsresult NS_NewSpacerFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); // nsIHTMLReflow + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -63,6 +65,7 @@ public: protected: SpacerFrame(); virtual ~SpacerFrame(); + void GetDesiredSize(nsHTMLReflowMetrics& aMetrics, nsSize aPercentBase); }; nsresult @@ -88,16 +91,52 @@ SpacerFrame::~SpacerFrame() { } +/* virtual */ nscoord +SpacerFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_MIN_WIDTH(this, metrics.width); + GetDesiredSize(metrics, nsSize(0, 0)); + return metrics.width; +} + +/* virtual */ nscoord +SpacerFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nsHTMLReflowMetrics metrics; + DISPLAY_PREF_WIDTH(this, metrics.width); + GetDesiredSize(metrics, nsSize(0, 0)); + return metrics.width; +} + NS_IMETHODIMP SpacerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("SpacerFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("SpacerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); aStatus = NS_FRAME_COMPLETE; + nsSize percentBase(aReflowState.availableWidth, aReflowState.availableHeight); + if (percentBase.width == NS_UNCONSTRAINEDSIZE) + percentBase.width = 0; + if (percentBase.height == NS_UNCONSTRAINEDSIZE) + percentBase.height = 0; + + if (GetType() == TYPE_LINE) + aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_COMPLETE); + + GetDesiredSize(aMetrics, percentBase); + + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); + return NS_OK; +} + +void +SpacerFrame::GetDesiredSize(nsHTMLReflowMetrics& aMetrics, nsSize aPercentBase) +{ // By default, we have no area aMetrics.width = 0; aMetrics.height = 0; @@ -112,9 +151,8 @@ SpacerFrame::Reflow(nsPresContext* aPresContext, break; case TYPE_LINE: - aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_COMPLETE); if (eStyleUnit_Coord == position->mHeight.GetUnit()) { - aMetrics.width = position->mHeight.GetCoordValue(); + aMetrics.height = position->mHeight.GetCoordValue(); } aMetrics.ascent = aMetrics.height; break; @@ -127,11 +165,8 @@ SpacerFrame::Reflow(nsPresContext* aPresContext, } else if (eStyleUnit_Percent == unit) { - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) - { - float factor = position->mWidth.GetPercentValue(); - aMetrics.width = NSToCoordRound (factor * aReflowState.availableWidth); - } + float factor = position->mWidth.GetPercentValue(); + aMetrics.width = NSToCoordRound(factor * aPercentBase.width); } // height @@ -141,11 +176,8 @@ SpacerFrame::Reflow(nsPresContext* aPresContext, } else if (eStyleUnit_Percent == unit) { - if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) - { - float factor = position->mHeight.GetPercentValue(); - aMetrics.width = NSToCoordRound (factor * aReflowState.availableHeight); - } + float factor = position->mHeight.GetPercentValue(); + aMetrics.width = NSToCoordRound(factor * aPercentBase.height); } // accent aMetrics.ascent = aMetrics.height; @@ -157,13 +189,6 @@ SpacerFrame::Reflow(nsPresContext* aPresContext, if (!aMetrics.width) aMetrics.width = 1; if (!aMetrics.height) aMetrics.height = 1; } - - if (aMetrics.mComputeMEW) { - aMetrics.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit()); - } - - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); - return NS_OK; } PRUint8 diff --git a/mozilla/layout/generic/nsTextFrame.cpp b/mozilla/layout/generic/nsTextFrame.cpp index 590f8707ccf..93021d4e828 100644 --- a/mozilla/layout/generic/nsTextFrame.cpp +++ b/mozilla/layout/generic/nsTextFrame.cpp @@ -574,6 +574,11 @@ public: return NS_OK; } virtual nsIFrame* GetFirstInFlow() const; + + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); protected: nsIFrame* mPrevInFlow; @@ -652,6 +657,32 @@ nsContinuingTextFrame::GetFirstInFlow() const return firstInFlow; } +// XXX Do we want to do all the work for the first-in-flow or do the +// work for each part? (Be careful of first-letter / first-line, though, +// especially first-line!) Doing all the work on the first-in-flow has +// the advantage of avoiding the potential for incremental reflow bugs, +// but depends on our maintining the frame tree in reasonable ways even +// for edge cases (block-within-inline splits, nextBidi, etc.) + +// XXX We really need to make :first-letter happen during frame +// construction. + +/* virtual */ void +nsContinuingTextFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData) +{ + // Do nothing, since the first-in-flow accounts for everything. + return; +} + +/* virtual */ void +nsContinuingTextFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData) +{ + // Do nothing, since the first-in-flow accounts for everything. + return; +} + inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB) { if (colorA == colorB) @@ -1206,11 +1237,8 @@ nsTextFrame::CharacterDataChanged(nsPresContext* aPresContext, } // Ask the parent frame to reflow me. - nsIPresShell *shell = aPresContext->GetPresShell(); - if (shell && mParent) { - mParent->ReflowDirtyChild(shell, targetTextFrame); - } - + aPresContext->GetPresShell()->FrameNeedsReflow(targetTextFrame, + nsIPresShell::eStyleChange); return NS_OK; } @@ -2736,18 +2764,18 @@ nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext, } inline void -nsTextFrame::MeasureSmallCapsText(const nsHTMLReflowState& aReflowState, +nsTextFrame::MeasureSmallCapsText(nsIRenderingContext* aRenderingContext, TextStyle& aTextStyle, PRUnichar* aWord, PRInt32 aWordLength, PRBool aIsEndOfFrame, nsTextDimensions* aDimensionsResult) { - nsIRenderingContext& rc = *aReflowState.rendContext; aDimensionsResult->Clear(); - GetTextDimensions(rc, aTextStyle, aWord, aWordLength, aIsEndOfFrame, aDimensionsResult); + GetTextDimensions(*aRenderingContext, aTextStyle, aWord, aWordLength, + aIsEndOfFrame, aDimensionsResult); if (aTextStyle.mLastFont != aTextStyle.mNormalFont) { - rc.SetFont(aTextStyle.mNormalFont); + aRenderingContext->SetFont(aTextStyle.mNormalFont); aTextStyle.mLastFont = aTextStyle.mNormalFont; } } @@ -4771,7 +4799,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, PRInt32 prevOffset = -1; PRInt32 column = mColumn; PRInt32 prevColumn = column; - nscoord prevMaxWordWidth = 0, prevAscent = 0, prevDescent = 0; + nscoord prevAscent = 0, prevDescent = 0; PRInt32 lastWordLen = 0; PRUnichar* lastWordPtr = nsnull; PRBool endsInWhitespace = PR_FALSE; @@ -4791,7 +4819,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, PRUint32 hints = 0; aReflowState.rendContext->GetHints(hints); if (hints & NS_RENDERING_HINT_FAST_MEASURE) { - measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted && + measureTextRuns = !aTs.mPreformatted && !aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing && aTextData.mWrapping; } @@ -4885,7 +4913,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, if (firstWordDone) { // The first word has been processed, and 2nd word is seen // we can set it be breakable here after. - aTextData.mCanBreakBefore = PR_TRUE; + aTextData.mCanBreakBefore = PR_TRUE; } } else { if (textRun.IsBuffering()) { @@ -4924,7 +4952,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, } if (aTextData.mSkipWhitespace) { aTextData.mOffset += contentLen; - aTextData.mSkipWhitespace = PR_FALSE; + aTextData.mSkipWhitespace = PR_FALSE; // XXXldb Eh? if (wasTransformed) { // As long as there were no discarded characters, then don't consider @@ -4998,6 +5026,8 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, firstThing = PR_FALSE; aTextData.mSkipWhitespace = PR_FALSE; + // XXX :first-letter should be handled during frame construction + // (and it has a good bit in common with nextBidi) if (aTextData.mFirstLetterOK) { if (IsPunctuationMark(firstChar)) { if (contentLen > 1) @@ -5026,7 +5056,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, } else { if (aTs.mSmallCaps) { - MeasureSmallCapsText(aReflowState, aTs, bp2, wordLen, PR_FALSE, &dimensions); + MeasureSmallCapsText(aReflowState.rendContext, aTs, bp2, wordLen, PR_FALSE, &dimensions); } else { // Measure just the one word @@ -5064,14 +5094,10 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, // The text will not fit. break; } - prevMaxWordWidth = aTextData.mMaxWordWidth; prevAscent = aTextData.mAscent; prevDescent = aTextData.mDescent; aTextData.mX += dimensions.width; - if (dimensions.width > aTextData.mMaxWordWidth) { - aTextData.mMaxWordWidth = dimensions.width; - } if (aTextData.mAscent < dimensions.ascent) { aTextData.mAscent = dimensions.ascent; } @@ -5108,116 +5134,116 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, MeasureTextRun: #if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) // see if we have implementation for GetTextDimensions() - if (hints & NS_RENDERING_HINT_FAST_MEASURE) { - PRInt32 numCharsFit; - // These calls can return numCharsFit not positioned at a break in the textRun. Beware. - if (aTx.TransformedTextIsAscii()) { - aReflowState.rendContext->GetTextDimensions((char*)aTx.GetWordBuffer(), textRun.mTotalNumChars, - maxWidth - aTextData.mX, - textRun.mBreaks, textRun.mNumSegments, - dimensions, numCharsFit, lastWordDimensions); - } else { - aReflowState.rendContext->GetTextDimensions(aTx.GetWordBuffer(), textRun.mTotalNumChars, - maxWidth - aTextData.mX, - textRun.mBreaks, textRun.mNumSegments, - dimensions, numCharsFit, lastWordDimensions); - } - // See how much of the text fit - if ((0 != aTextData.mX) && aTextData.mWrapping && (aTextData.mX + dimensions.width > maxWidth)) { - // None of the text fits -#ifdef IBMBIDI - nextBidi = nsnull; -#endif // IBMBIDI - break; - } - - // Find the index of the last segment that fit - PRInt32 lastSegment; - if (numCharsFit >= textRun.mTotalNumChars) { // fast path, normal case - NS_ASSERTION(numCharsFit == textRun.mTotalNumChars, "shouldn't overshoot"); - lastSegment = textRun.mNumSegments - 1; - } else { - for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ; - NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment"); - // now we have textRun.mBreaks[lastSegment] >= numCharsFit - /* O'Callahan XXX: This snippet together with the snippet below prevents mail from loading - Justification seems to work just fine without these changes. - We get into trouble in a case where lastSegment gets set to -1 - - if (textRun.mBreaks[lastSegment] > numCharsFit) { - // NOTE: this segment did not actually fit! - lastSegment--; + if (hints & NS_RENDERING_HINT_FAST_MEASURE) { + PRInt32 numCharsFit; + // These calls can return numCharsFit not positioned at a break in the textRun. Beware. + if (aTx.TransformedTextIsAscii()) { + aReflowState.rendContext->GetTextDimensions((char*)aTx.GetWordBuffer(), textRun.mTotalNumChars, + maxWidth - aTextData.mX, + textRun.mBreaks, textRun.mNumSegments, + dimensions, numCharsFit, lastWordDimensions); + } else { + aReflowState.rendContext->GetTextDimensions(aTx.GetWordBuffer(), textRun.mTotalNumChars, + maxWidth - aTextData.mX, + textRun.mBreaks, textRun.mNumSegments, + dimensions, numCharsFit, lastWordDimensions); } - */ - } - - /* O'Callahan XXX: This snippet together with the snippet above prevents mail from loading - - if (lastSegment < 0) { - // no segments fit - break; - } else */ - if (lastSegment == 0) { - // Only one segment fit - prevColumn = column; - prevOffset = aTextData.mOffset; - } else { - // The previous state is for the next to last word - // NOTE: The textRun data are relative to the last updated column and offset! - prevColumn = column + textRun.mBreaks[lastSegment - 1]; - prevOffset = aTextData.mOffset + textRun.mSegments[lastSegment - 1].ContentLen(); - } - - aTextData.mX += dimensions.width; - if (aTextData.mAscent < dimensions.ascent) { - aTextData.mAscent = dimensions.ascent; - } - if (aTextData.mDescent < dimensions.descent) { - aTextData.mDescent = dimensions.descent; - } - // this is where to backup if line-breaking happens to push the last word - prevAscent = aTextData.mAscent; - prevDescent = aTextData.mDescent; - // we can now consider the last word since we know where to backup - if (aTextData.mAscent < lastWordDimensions.ascent) { - aTextData.mAscent = lastWordDimensions.ascent; - } - if (aTextData.mDescent < lastWordDimensions.descent) { - aTextData.mDescent = lastWordDimensions.descent; - } - - column += numCharsFit; - aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen(); - endsInWhitespace = textRun.mSegments[lastSegment].IsWhitespace(); - - // If all the text didn't fit, then we're done - if (numCharsFit != textRun.mTotalNumChars) { + // See how much of the text fit + if ((0 != aTextData.mX) && aTextData.mWrapping && (aTextData.mX + dimensions.width > maxWidth)) { + // None of the text fits #ifdef IBMBIDI - nextBidi = nsnull; + nextBidi = nsnull; #endif // IBMBIDI - break; - } + break; + } + + // Find the index of the last segment that fit + PRInt32 lastSegment; + if (numCharsFit >= textRun.mTotalNumChars) { // fast path, normal case + NS_ASSERTION(numCharsFit == textRun.mTotalNumChars, "shouldn't overshoot"); + lastSegment = textRun.mNumSegments - 1; + } else { + for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ; + NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment"); + // now we have textRun.mBreaks[lastSegment] >= numCharsFit + /* O'Callahan XXX: This snippet together with the snippet below prevents mail from loading + Justification seems to work just fine without these changes. + We get into trouble in a case where lastSegment gets set to -1 + + if (textRun.mBreaks[lastSegment] > numCharsFit) { + // NOTE: this segment did not actually fit! + lastSegment--; + } + */ + } + + /* O'Callahan XXX: This snippet together with the snippet above prevents mail from loading + + if (lastSegment < 0) { + // no segments fit + break; + } else */ + if (lastSegment == 0) { + // Only one segment fit + prevColumn = column; + prevOffset = aTextData.mOffset; + } else { + // The previous state is for the next to last word + // NOTE: The textRun data are relative to the last updated column and offset! + prevColumn = column + textRun.mBreaks[lastSegment - 1]; + prevOffset = aTextData.mOffset + textRun.mSegments[lastSegment - 1].ContentLen(); + } + + aTextData.mX += dimensions.width; + if (aTextData.mAscent < dimensions.ascent) { + aTextData.mAscent = dimensions.ascent; + } + if (aTextData.mDescent < dimensions.descent) { + aTextData.mDescent = dimensions.descent; + } + // this is where to backup if line-breaking happens to push the last word + prevAscent = aTextData.mAscent; + prevDescent = aTextData.mDescent; + // we can now consider the last word since we know where to backup + if (aTextData.mAscent < lastWordDimensions.ascent) { + aTextData.mAscent = lastWordDimensions.ascent; + } + if (aTextData.mDescent < lastWordDimensions.descent) { + aTextData.mDescent = lastWordDimensions.descent; + } + + column += numCharsFit; + aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen(); + endsInWhitespace = textRun.mSegments[lastSegment].IsWhitespace(); + + // If all the text didn't fit, then we're done + if (numCharsFit != textRun.mTotalNumChars) { +#ifdef IBMBIDI + nextBidi = nsnull; +#endif // IBMBIDI + break; + } #ifdef IBMBIDI - if (nextBidi && (mContentLength <= 0) ) { - break; - } + if (nextBidi && (mContentLength <= 0) ) { + break; + } #endif // IBMBIDI - if (nsnull == bp2) { - // No more text so we're all finished. Advance the offset in case the last - // call to GetNextWord() discarded characters - aTextData.mOffset += contentLen; - break; + if (nsnull == bp2) { + // No more text so we're all finished. Advance the offset in case the last + // call to GetNextWord() discarded characters + aTextData.mOffset += contentLen; + break; + } + + // Reset the number of text run segments + textRun.Reset(); + + // Estimate the remaining number of characters we think will fit + estimatedNumChars = EstimateNumChars(maxWidth - aTextData.mX, + aTs.mAveCharWidth); } - - // Reset the number of text run segments - textRun.Reset(); - - // Estimate the remaining number of characters we think will fit - estimatedNumChars = EstimateNumChars(maxWidth - aTextData.mX, - aTs.mAveCharWidth); - } #else /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) */ int unused = -1; #endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) */ @@ -5306,7 +5332,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, lastWordDimensions.width = aTextData.mX; } else if (aTs.mSmallCaps) { - MeasureSmallCapsText(aReflowState, aTs, pWordBuf, + MeasureSmallCapsText(aReflowState.rendContext, aTs, pWordBuf, lastWordLen, PR_FALSE, &lastWordDimensions); } else { @@ -5318,7 +5344,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, } nsTextDimensions wordDimensions = ComputeTotalWordDimensions(aPresContext, lineLayout, - aReflowState, next, + aReflowState.rendContext, next, lastWordDimensions, pWordBuf, lastWordLen, @@ -5330,9 +5356,6 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, // joined word is large than it's pieces, the right effect // will occur from the perspective of the container // reflowing this frame) - if (wordDimensions.width > aTextData.mMaxWordWidth) { - aTextData.mMaxWordWidth = wordDimensions.width; - } // Now that we now that we will retain the last word, we should // account for its ascent and descent if (aTextData.mAscent < lastWordDimensions.ascent) { @@ -5351,7 +5374,6 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, // The fully joined word won't fit. We need to reduce our // size by lastWordDimensions aTextData.mX -= lastWordDimensions.width; - aTextData.mMaxWordWidth = prevMaxWordWidth; aTextData.mOffset = prevOffset; column = prevColumn; if (aTextData.mMeasureText) { @@ -5365,7 +5387,7 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, // our remaining text could have got shorter. // } #ifdef DEBUG_WORD_WRAPPING - printf(" x=%d maxWordWidth=%d len=%d\n", aTextData.mX, aTextData.mMaxWordWidth, + printf(" x=%d len=%d\n", aTextData.mX, aTextData.mOffset - startingOffset); #endif lineLayout.ForgetWordFrames(); @@ -5409,13 +5431,207 @@ nsTextFrame::MeasureText(nsPresContext* aPresContext, return rs; } +/* virtual */ void +nsTextFrame::MarkIntrinsicWidthsDirty() +{ + // Clear the TEXT_OPTIMIZE_RESIZE for the next time around. It'll get + // reset late in Reflow. + RemoveStateBits(TEXT_OPTIMIZE_RESIZE); +} + +// XXX This should really share more code with the first half of MeasureText. +/* virtual */ void +nsTextFrame::AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlineMinWidthData *aData) +{ + nsresult rv; + + nsPresContext *presContext = GetPresContext(); + TextStyle ts(presContext, *aRenderingContext, mStyleContext); + if (!ts.mFont->mSize) + // XXX If font size is zero, we still need to figure out whether we've + // got non-whitespace text and whether we end in whitespace. + return; + + PRBool forceArabicShaping = (ts.mSmallCaps || + (0 != ts.mWordSpacing) || + (0 != ts.mLetterSpacing) || + ts.mJustifying); + nsTextTransformer tx(mContent->GetOwnerDoc()->GetLineBreaker(), nsnull, + presContext); + // Keep the text in ascii if possible. Note that if we're measuring small + // caps text then transform to Unicode because the helper function only + // accepts Unicode text + rv = tx.Init(this, mContent, mContentOffset, forceArabicShaping, + !ts.mSmallCaps); + if (NS_FAILED(rv)) { + NS_NOTREACHED("failure initializing text transformer"); + return; + } + + for (;;) { + union { + char* bp1; + PRUnichar* bp2; + }; + PRInt32 wordLen, contentLen; +#ifdef IBMBIDI + // Is this right for this purpose? + wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1; +#endif // IBMBIDI + PRBool isWhitespace, wasTransformed; + // XXX Is !aData->skipWhitespace the right criterion for when the + // text transformer should capitalize the first letter? + bp2 = tx.GetNextWord(!aData->skipWhitespace, &wordLen, &contentLen, + &isWhitespace, &wasTransformed); + if (!bp2) + break; + // XXX Watch mContentLength! + + if (isWhitespace) { + const nsStyleText *styleText = GetStyleText(); + if (styleText->CanBreakAtWhiteSpace()) { + aData->Break(aRenderingContext); + } else if (!aData->skipWhitespace) { + PRUnichar firstChar; + if (tx.TransformedTextIsAscii()) { + firstChar = *bp1; + } else { + firstChar = *bp2; + } + if ('\t' == firstChar) { + // XXX Need to track column! + wordLen = 8; + // Apply word spacing to every space derived from a tab + aData->currentLine += + (ts.mSpaceWidth + ts.mWordSpacing + ts.mLetterSpacing)*wordLen; + } else { + // Apply word spacing to every space, if there's more than one + aData->currentLine += + wordLen*(ts.mWordSpacing + ts.mLetterSpacing + ts.mSpaceWidth);// XXX simplistic + } + } + } else { + nsTextDimensions dimensions; + if (ts.mSmallCaps) { + MeasureSmallCapsText(aRenderingContext, ts, bp2, wordLen, PR_FALSE, + &dimensions); + } else { + if (tx.TransformedTextIsAscii()) { + aRenderingContext->GetTextDimensions(bp1, wordLen, dimensions); + } else { + aRenderingContext->GetTextDimensions(bp2, wordLen, dimensions); + } + dimensions.width += ts.mLetterSpacing * wordLen; + } + + aData->currentLine += dimensions.width; + aData->skipWhitespace = PR_FALSE; + } + } +} + +/* virtual */ void +nsTextFrame::AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + nsIFrame::InlinePrefWidthData *aData) +{ + nsresult rv; + + nsPresContext *presContext = GetPresContext(); + TextStyle ts(presContext, *aRenderingContext, mStyleContext); + if (!ts.mFont->mSize) + // XXX If font size is zero, we still need to figure out whether we've + // got non-whitespace text and whether we end in whitespace. + return; + + PRBool forceArabicShaping = (ts.mSmallCaps || + (0 != ts.mWordSpacing) || + (0 != ts.mLetterSpacing) || + ts.mJustifying); + nsTextTransformer tx(mContent->GetOwnerDoc()->GetLineBreaker(), nsnull, + presContext); + // Keep the text in ascii if possible. Note that if we're measuring small + // caps text then transform to Unicode because the helper function only + // accepts Unicode text + rv = tx.Init(this, mContent, mContentOffset, forceArabicShaping, + !ts.mSmallCaps); + if (NS_FAILED(rv)) { + NS_NOTREACHED("failure initializing text transformer"); + return; + } + + for (;;) { + union { + char* bp1; + PRUnichar* bp2; + }; + PRInt32 wordLen = -1, contentLen; +#ifdef IBMBIDI + // Is this right for this purpose? + wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1; +#endif // IBMBIDI + PRBool isWhitespace, wasTransformed; + // XXX Is !aData->skipWhitespace the right criterion for when the + // text transformer should capitalize the first letter? + bp2 = tx.GetNextWord(!aData->skipWhitespace, &wordLen, &contentLen, + &isWhitespace, &wasTransformed); + if (!bp2) + break; + // XXX Watch mContentLength! + + if (isWhitespace) { + PRUnichar firstChar; + if (tx.TransformedTextIsAscii()) { + firstChar = *bp1; + } else { + firstChar = *bp2; + } + if ('\n' == firstChar) { + aData->Break(aRenderingContext); + } else if (!aData->skipWhitespace) { + nscoord width; + if ('\t' == firstChar) { + // XXX Need to track column! + wordLen = 8; + // Apply word spacing to every space derived from a tab + width = + (ts.mSpaceWidth + ts.mWordSpacing + ts.mLetterSpacing)*wordLen; + } else { + // Apply word spacing to every space, if there's more than one + width = + wordLen*(ts.mWordSpacing + ts.mLetterSpacing + ts.mSpaceWidth);// XXX simplistic + } + aData->currentLine += width; + aData->trailingWhitespace += width; + } + } else { + nsTextDimensions dimensions; + if (ts.mSmallCaps) { + MeasureSmallCapsText(aRenderingContext, ts, bp2, wordLen, PR_FALSE, + &dimensions); + } else { + if (tx.TransformedTextIsAscii()) { + aRenderingContext->GetTextDimensions(bp1, wordLen, dimensions); + } else { + aRenderingContext->GetTextDimensions(bp2, wordLen, dimensions); + } + dimensions.width += ts.mLetterSpacing * wordLen; + } + + aData->currentLine += dimensions.width; + aData->skipWhitespace = PR_FALSE; + aData->trailingWhitespace = 0; + } + } +} + NS_IMETHODIMP nsTextFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsTextFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsTextFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); #ifdef NOISY_REFLOW ListTag(stdout); @@ -5434,9 +5650,6 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, aMetrics.height = 0; aMetrics.ascent = 0; aMetrics.descent = 0; - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = 0; - } #ifdef MOZ_MATHML if (NS_REFLOW_CALC_BOUNDING_METRICS & aMetrics.mFlags) aMetrics.mBoundingMetrics.Clear(); @@ -5474,6 +5687,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, (hints & NS_RENDERING_HINT_ARABIC_SHAPING) == NS_RENDERING_HINT_ARABIC_SHAPING) || (eCharType_RightToLeft == charType && (hints & NS_RENDERING_HINT_BIDI_REORDERING) == NS_RENDERING_HINT_BIDI_REORDERING)) { + // XXXldb This needs to happen before |Reflow|. aPresContext->SetIsBidiSystem(PR_TRUE); } } @@ -5495,8 +5709,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, } } - PRBool wrapping = (NS_STYLE_WHITESPACE_NORMAL == ts.mText->mWhiteSpace) || - (NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == ts.mText->mWhiteSpace); + PRBool wrapping = ts.mText->CanBreakAtWhiteSpace(); // Set whitespace skip flag PRBool skipWhitespace = PR_FALSE; @@ -5542,8 +5755,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, PRBool measureText = PR_TRUE; // We can avoid actually measuring the text if: - // - this is a resize reflow - // - we're not dirty (see CharacterDataChanged() function) + // - intrinsic widths haven't been marked dirty (which clears + // TEXT_OPTIMIZE_RESIZE) // - we don't have a next in flow // - the previous reflow successfully reflowed all text in the // available space @@ -5555,43 +5768,38 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // we're not wrapping text and we're at the same column as before (this is // an issue for preformatted tabbed text only) // - AND we aren't justified (in which case the frame width has already been tweaked and can't be used) - if ((eReflowReason_Resize == aReflowState.reason) && - (0 == (mState & NS_FRAME_IS_DIRTY))) { - - nscoord realWidth = mRect.width; - if (mState & TEXT_TRIMMED_WS) { - // NOTE: Trailing whitespace includes word and letter spacing! - realWidth += ts.mSpaceWidth + ts.mWordSpacing + ts.mLetterSpacing; - } - if (!mNextInFlow && - (mState & TEXT_OPTIMIZE_RESIZE) && - !aMetrics.mComputeMEW && - (lastTimeWeSkippedLeadingWS == skipWhitespace) && - ((wrapping && (maxWidth >= realWidth)) || - (!wrapping && (prevColumn == column))) && + nscoord realWidth = mRect.width; + if (mState & TEXT_TRIMMED_WS) { + // NOTE: Trailing whitespace includes word and letter spacing! + realWidth += ts.mSpaceWidth + ts.mWordSpacing + ts.mLetterSpacing; + } + if (!mNextInFlow && + (mState & TEXT_OPTIMIZE_RESIZE) && + !lineLayout.GetIntrinsicWidthPass() && + (lastTimeWeSkippedLeadingWS == skipWhitespace) && + ((wrapping && (maxWidth >= realWidth)) || + (!wrapping && (prevColumn == column))) && #ifdef IBMBIDI - (0 == (mState & NS_FRAME_IS_BIDI) ) && + (0 == (mState & NS_FRAME_IS_BIDI) ) && #endif // IBMBIDI - !ts.mJustifying) { - // We can skip measuring of text and use the value from our - // previous reflow - measureText = PR_FALSE; + !ts.mJustifying) { + // We can skip measuring of text and use the value from our + // previous reflow + measureText = PR_FALSE; #ifdef NOISY_REFLOW - printf(" => measureText=%s wrapping=%s skipWhitespace=%s", - measureText ? "yes" : "no", - wrapping ? "yes" : "no", - skipWhitespace ? "yes" : "no"); - printf(" realWidth=%d maxWidth=%d\n", - realWidth, maxWidth); + printf(" => measureText=%s wrapping=%s skipWhitespace=%s", + measureText ? "yes" : "no", + wrapping ? "yes" : "no", + skipWhitespace ? "yes" : "no"); + printf(" realWidth=%d maxWidth=%d\n", + realWidth, maxWidth); #endif - } } // Local state passed to the routines that do the actual text measurement TextReflowData textData(startingOffset, wrapping, skipWhitespace, measureText, inWord, lineLayout.GetFirstLetterStyleOK(), - lineLayout.LineIsBreakable(), aMetrics.mComputeMEW, - PR_FALSE); + lineLayout.LineIsBreakable(), PR_FALSE); // Measure the text // MeasureText may set TEXT_TRIMMED_WS flag, so don't clear after the call @@ -5625,12 +5833,6 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, aMetrics.height = aMetrics.ascent + aMetrics.descent; } mAscent = aMetrics.ascent; - if (!wrapping) { - textData.mMaxWordWidth = textData.mX; - } - if (aMetrics.mComputeMEW) { - aMetrics.mMaxElementWidth = textData.mMaxWordWidth; - } // Set content offset and length mContentOffset = startingOffset; @@ -5828,7 +6030,7 @@ RevertSpacesToNBSP(PRUnichar* aBuffer, PRInt32 aWordLen) nsTextDimensions nsTextFrame::ComputeTotalWordDimensions(nsPresContext* aPresContext, nsLineLayout& aLineLayout, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext* aRenderingContext, nsIFrame* aNextFrame, const nsTextDimensions& aBaseDimensions, PRUnichar* aWordBuf, @@ -5858,7 +6060,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsPresContext* aPresContext, nsTextDimensions moreDimensions; moreDimensions = ComputeWordFragmentDimensions(aPresContext, aLineLayout, - aReflowState, + aRenderingContext, aNextFrame, content, tc, &stop, newWordBuf, @@ -5882,8 +6084,13 @@ nsTextFrame::ComputeTotalWordDimensions(nsPresContext* aPresContext, if(newWordBuf) { moreDimensions = +<<<<<<< nsTextFrame.cpp ComputeWordFragmentDimensions(aPresContext, aLineLayout, aReflowState, +======= + ComputeWordFragmentDimensions(aPresContext, aLineBreaker, + aLineLayout, aRenderingContext, +>>>>>>> 1.513.2.2 aNextFrame, content, tc, &stop, newWordBuf, aWordLen, newWordBufSize, aCanBreakBefore); @@ -5929,7 +6136,7 @@ nsTextFrame::ComputeTotalWordDimensions(nsPresContext* aPresContext, nsTextDimensions nsTextFrame::ComputeWordFragmentDimensions(nsPresContext* aPresContext, nsLineLayout& aLineLayout, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext* aRenderingContext, nsIFrame* aNextFrame, nsIContent* aContent, nsITextContent* aText, @@ -6026,20 +6233,19 @@ nsTextFrame::ComputeWordFragmentDimensions(nsPresContext* aPresContext, // Measure the piece of text. Note that we have to select the // appropriate font into the text first because the rendering // context has our font in it, not the font that aText is using. - nsIRenderingContext& rc = *aReflowState.rendContext; nsCOMPtr oldfm; - rc.GetFontMetrics(*getter_AddRefs(oldfm)); + aRenderingContext->GetFontMetrics(*getter_AddRefs(oldfm)); - TextStyle ts(aLineLayout.mPresContext, rc, sc); + TextStyle ts(aLineLayout.mPresContext, *aRenderingContext, sc); if (ts.mSmallCaps) { - MeasureSmallCapsText(aReflowState, ts, bp, wordLen, PR_FALSE, &dimensions); + MeasureSmallCapsText(aRenderingContext, ts, bp, wordLen, PR_FALSE, &dimensions); } else { - rc.GetTextDimensions(bp, wordLen, dimensions); + aRenderingContext->GetTextDimensions(bp, wordLen, dimensions); // NOTE: Don't forget to add letter spacing for the word fragment! dimensions.width += wordLen*ts.mLetterSpacing; } - rc.SetFont(oldfm); + aRenderingContext->SetFont(oldfm); #ifdef DEBUG_WORD_WRAPPING nsAutoString tmp(bp, wordLen); diff --git a/mozilla/layout/generic/nsTextFrame.h b/mozilla/layout/generic/nsTextFrame.h index 35f8a0991ab..f9b8bb1236c 100644 --- a/mozilla/layout/generic/nsTextFrame.h +++ b/mozilla/layout/generic/nsTextFrame.h @@ -155,6 +155,11 @@ public: #endif // nsIHTMLReflow + virtual void MarkIntrinsicWidthsDirty(); + virtual void AddInlineMinWidth(nsIRenderingContext *aRenderingContext, + InlineMinWidthData *aData); + virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext, + InlinePrefWidthData *aData); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, @@ -207,7 +212,6 @@ public: struct TextReflowData { PRInt32 mX; // OUT PRInt32 mOffset; // IN/OUT How far along we are in the content - nscoord mMaxWordWidth; // OUT nscoord mAscent; // OUT nscoord mDescent; // OUT PRPackedBool mWrapping; // IN @@ -216,7 +220,6 @@ public: PRPackedBool mInWord; // IN PRPackedBool mFirstLetterOK; // IN PRPackedBool mCanBreakBefore; // IN - PRPackedBool mComputeMaxWordWidth; // IN PRPackedBool mTrailingSpaceTrimmed; // IN/OUT TextReflowData(PRInt32 aStartingOffset, @@ -226,11 +229,9 @@ public: PRBool aInWord, PRBool aFirstLetterOK, PRBool aCanBreakBefore, - PRBool aComputeMaxWordWidth, PRBool aTrailingSpaceTrimmed) : mX(0), mOffset(aStartingOffset), - mMaxWordWidth(0), mAscent(0), mDescent(0), mWrapping(aWrapping), @@ -239,7 +240,6 @@ public: mInWord(aInWord), mFirstLetterOK(aFirstLetterOK), mCanBreakBefore(aCanBreakBefore), - mComputeMaxWordWidth(aComputeMaxWordWidth), mTrailingSpaceTrimmed(aTrailingSpaceTrimmed) {} }; @@ -284,7 +284,7 @@ public: nscoord aWidth, SelectionDetails *aDetails = nsnull); - void MeasureSmallCapsText(const nsHTMLReflowState& aReflowState, + void MeasureSmallCapsText(nsIRenderingContext* aRenderingContext, TextStyle& aStyle, PRUnichar* aWord, PRInt32 aWordLength, @@ -340,7 +340,7 @@ public: nsTextDimensions ComputeTotalWordDimensions(nsPresContext* aPresContext, nsLineLayout& aLineLayout, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext* aRenderingContext, nsIFrame* aNextFrame, const nsTextDimensions& aBaseDimensions, PRUnichar* aWordBuf, @@ -350,7 +350,7 @@ public: nsTextDimensions ComputeWordFragmentDimensions(nsPresContext* aPresContext, nsLineLayout& aLineLayout, - const nsHTMLReflowState& aReflowState, + nsIRenderingContext* aRenderingContext, nsIFrame* aNextFrame, nsIContent* aContent, nsITextContent* aText, diff --git a/mozilla/layout/generic/nsViewportFrame.cpp b/mozilla/layout/generic/nsViewportFrame.cpp index 6db0b646d47..f2d6aa66300 100644 --- a/mozilla/layout/generic/nsViewportFrame.cpp +++ b/mozilla/layout/generic/nsViewportFrame.cpp @@ -42,7 +42,6 @@ #include "nsIScrollableFrame.h" #include "nsIDeviceContext.h" #include "nsPresContext.h" -#include "nsReflowPath.h" #include "nsIPresShell.h" nsresult @@ -176,6 +175,36 @@ ViewportFrame::GetFirstChild(nsIAtom* aListName) const return nsContainerFrame::GetFirstChild(aListName); } +/* virtual */ nscoord +ViewportFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetMinWidth(aRenderingContext); + + // XXXldb Deal with mFixedContainer (matters for SizeToContent)! + + return result; +} + +/* virtual */ nscoord +ViewportFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext); + + // XXXldb Deal with mFixedContainer (matters for SizeToContent)! + + return result; +} + nsPoint ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const { @@ -204,10 +233,9 @@ ViewportFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("ViewportFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("ViewportFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); - NS_PRECONDITION(!aDesiredSize.mComputeMEW, "unexpected request"); // Initialize OUT parameters aStatus = NS_FRAME_COMPLETE; @@ -222,8 +250,9 @@ ViewportFrame::Reflow(nsPresContext* aPresContext, if (mFrames.NotEmpty()) { // Deal with a non-incremental reflow or an incremental reflow // targeted at our one-and-only principal child frame. - if (eReflowReason_Incremental != aReflowState.reason || - aReflowState.path->HasChild(mFrames.FirstChild())) { + if (aReflowState.ShouldReflowAllKids() || + (mFrames.FirstChild()->GetStateBits() & + (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { // Reflow our one-and-only principal child frame nsIFrame* kidFrame = mFrames.FirstChild(); nsHTMLReflowMetrics kidDesiredSize(nsnull); @@ -243,24 +272,18 @@ ViewportFrame::Reflow(nsPresContext* aPresContext, } } - // If we were flowed initially at both an unconstrained width and height, - // this is a hint that we should return our child's intrinsic size. - if ((eReflowReason_Initial == aReflowState.reason || - eReflowReason_Resize == aReflowState.reason) && - aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE && - aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) { - aDesiredSize.width = kidRect.width; - aDesiredSize.height = kidRect.height; - aDesiredSize.ascent = kidRect.height; - aDesiredSize.descent = 0; - } - else { - // Return the max size as our desired size - aDesiredSize.width = aReflowState.availableWidth; - aDesiredSize.height = aReflowState.availableHeight; - aDesiredSize.ascent = aReflowState.availableHeight; - aDesiredSize.descent = 0; - } + NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE, + "shouldn't happen anymore"); + + // Return the max size as our desired size + aDesiredSize.width = aReflowState.availableWidth; + // Being flowed initially at an unconstrained height means we should + // return our child's intrinsic size. + aDesiredSize.height = aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE + ? aReflowState.availableHeight + : kidRect.height; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; // Make a copy of the reflow state and change the computed width and height // to reflect the available space for the fixed items @@ -275,34 +298,14 @@ ViewportFrame::Reflow(nsPresContext* aPresContext, "scrollbars in odd positions"); #endif - nsReflowType reflowType = eReflowType_ContentChanged; - if (aReflowState.path) { - // XXXwaterson this is more restrictive than the previous code - // was: it insists that the UserDefined reflow be targeted at - // _this_ frame. - nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; - if (command) - command->GetType(reflowType); - } - - if (reflowType != eReflowType_UserDefined && - aReflowState.reason == eReflowReason_Incremental) { - // Incremental reflow - mFixedContainer.IncrementalReflow(this, aPresContext, reflowState, - reflowState.mComputedWidth, - reflowState.mComputedHeight); - } - // Just reflow all the fixed-pos frames. rv = mFixedContainer.Reflow(this, aPresContext, reflowState, reflowState.mComputedWidth, - reflowState.mComputedHeight); + reflowState.mComputedHeight, + PR_TRUE, PR_TRUE); // XXX could be optimized - // If this is an initial reflow, resize reflow, or style change reflow - // then do a repaint - if ((eReflowReason_Initial == aReflowState.reason) || - (eReflowReason_Resize == aReflowState.reason) || - (eReflowReason_StyleChange == aReflowState.reason)) { + // If we were dirty then do a repaint + if (GetStateBits() & NS_FRAME_IS_DIRTY) { nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height); Invalidate(damageRect, PR_FALSE); } diff --git a/mozilla/layout/generic/nsViewportFrame.h b/mozilla/layout/generic/nsViewportFrame.h index 736498153e4..1f7efac3395 100644 --- a/mozilla/layout/generic/nsViewportFrame.h +++ b/mozilla/layout/generic/nsViewportFrame.h @@ -40,7 +40,6 @@ #include "nsContainerFrame.h" #include "nsLayoutAtoms.h" #include "nsPresContext.h" -#include "nsReflowPath.h" #include "nsIPresShell.h" #include "nsAbsoluteContainingBlock.h" @@ -88,6 +87,8 @@ public: virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const; + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/html/tests/Makefile.in b/mozilla/layout/html/tests/Makefile.in index 62d308fa706..b0404a3ccd9 100644 --- a/mozilla/layout/html/tests/Makefile.in +++ b/mozilla/layout/html/tests/Makefile.in @@ -67,9 +67,7 @@ LIBS = \ $(LIBS_DIR) \ $(DIST)/lib/$(LIB_PREFIX)gkconhtmlcon_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkconhtmldoc_s.$(LIB_SUFFIX) \ - $(DIST)/lib/$(LIB_PREFIX)gkforms_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkstyle_s.$(LIB_SUFFIX) \ - $(DIST)/lib/$(LIB_PREFIX)gktable_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkbase_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkgeneric_s.$(LIB_SUFFIX) \ $(DIST)/lib/$(LIB_PREFIX)gkconbase_s.$(LIB_SUFFIX) \ @@ -84,6 +82,14 @@ LIBS = \ $(MOZ_COMPONENT_LIBS) \ $(NULL) +ifdef CSS_TABLES +LIBS += $(DIST)/lib/$(LIB_PREFIX)gktable_s.$(LIB_SUFFIX) +endif + +ifdef HTML_FORMS +LIBS += $(DIST)/lib/$(LIB_PREFIX)gkforms_s.$(LIB_SUFFIX) +endif + include $(topsrcdir)/config/config.mk include $(topsrcdir)/config/rules.mk diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp index f709e1c4e1d..347ec601a88 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.cpp @@ -1018,31 +1018,6 @@ nsMathMLContainerFrame::AttributeChanged(PRInt32 aNameSpaceID, return ReflowDirtyChild(GetPresContext()->PresShell(), nsnull); } -// We are an inline frame, so we handle dirty request like nsInlineFrame -NS_IMETHODIMP -nsMathMLContainerFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) -{ - // The inline container frame does not handle the reflow - // request. It passes it up to its parent container. - - // If you don't already have dirty children, - if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) { - if (mParent) { - // Record that you are dirty and have dirty children - mState |= NS_FRAME_IS_DIRTY; - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; - - // Pass the reflow request up to the parent - mParent->ReflowDirtyChild(aPresShell, (nsIFrame*) this); - } - else { - NS_ASSERTION(0, "No parent to pass the reflow request up to."); - } - } - - return NS_OK; -} - NS_IMETHODIMP nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h index e919fb1bbbb..99071988619 100644 --- a/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h +++ b/mozilla/layout/mathml/base/src/nsMathMLContainerFrame.h @@ -147,10 +147,6 @@ public: nsIFrame* aOldFrame, nsIFrame* aNewFrame); - NS_IMETHODIMP - ReflowDirtyChild(nsIPresShell* aPresShell, - nsIFrame* aChild); - NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index 56fc3661bb9..68fee5add01 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -502,3 +502,7 @@ marquee[direction="up"], marquee[direction="down"] { } } + + +/* XXX TEMPORARY! */ +table { display: none; } diff --git a/mozilla/layout/style/nsStyleContext.cpp b/mozilla/layout/style/nsStyleContext.cpp index c6afa7e2ed2..9b8b29d732d 100644 --- a/mozilla/layout/style/nsStyleContext.cpp +++ b/mozilla/layout/style/nsStyleContext.cpp @@ -495,6 +495,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther) DO_STRUCT_DIFFERENCE(Table); DO_STRUCT_DIFFERENCE(Background); DO_STRUCT_DIFFERENCE(UIReset); + DO_STRUCT_DIFFERENCE(List); // If the quotes implementation is ever going to change we might not need // a framechange here and a reflow should be sufficient. See bug 35768. DO_STRUCT_DIFFERENCE(Quotes); @@ -510,7 +511,6 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther) DO_STRUCT_DIFFERENCE(Margin); DO_STRUCT_DIFFERENCE(Padding); DO_STRUCT_DIFFERENCE(Border); - DO_STRUCT_DIFFERENCE(List); DO_STRUCT_DIFFERENCE(Position); DO_STRUCT_DIFFERENCE(Text); DO_STRUCT_DIFFERENCE(TextReset); diff --git a/mozilla/layout/style/nsStyleStruct.cpp b/mozilla/layout/style/nsStyleStruct.cpp index c7a2a756449..31c3dd594b4 100644 --- a/mozilla/layout/style/nsStyleStruct.cpp +++ b/mozilla/layout/style/nsStyleStruct.cpp @@ -601,8 +601,9 @@ nsStyleList::nsStyleList(const nsStyleList& aSource) nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const { - if (mListStylePosition == aOther.mListStylePosition && - EqualImages(mListStyleImage, aOther.mListStyleImage) && + if (mListStylePosition != aOther.mListStylePosition) + return NS_STYLE_HINT_FRAMECHANGE; + if (EqualImages(mListStyleImage, aOther.mListStyleImage) && mListStyleType == aOther.mListStyleType) { if (mImageRegion == aOther.mImageRegion) return NS_STYLE_HINT_NONE; @@ -617,7 +618,7 @@ nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const /* static */ nsChangeHint nsStyleList::MaxDifference() { - return NS_STYLE_HINT_REFLOW; + return NS_STYLE_HINT_FRAMECHANGE; } #endif diff --git a/mozilla/layout/style/nsStyleStruct.h b/mozilla/layout/style/nsStyleStruct.h index 5ef8563b292..89283389e9a 100644 --- a/mozilla/layout/style/nsStyleStruct.h +++ b/mozilla/layout/style/nsStyleStruct.h @@ -742,6 +742,11 @@ struct nsStyleText : public nsStyleStruct { return mWhiteSpace == NS_STYLE_WHITESPACE_PRE || mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP; } + + PRBool CanBreakAtWhiteSpace() const { + return mWhiteSpace == NS_STYLE_WHITESPACE_NORMAL || + mWhiteSpace == NS_STYLE_WHITESPACE_MOZ_PRE_WRAP; + } }; struct nsStyleVisibility : public nsStyleStruct { diff --git a/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 78e36dd0fde..1b20dc9e4e4 100644 --- a/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -165,7 +165,10 @@ protected: void TransformPoint(float& x, float& y); void TransformVector(float& x, float& y); - PRBool mIsDirty; + PRBool IsDirty() { + return (GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0; + } + nsCOMPtr mX; nsCOMPtr mY; nsCOMPtr mWidth; @@ -201,7 +204,7 @@ NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIF } nsSVGForeignObjectFrame::nsSVGForeignObjectFrame() - : mIsDirty(PR_TRUE), mPropagateTransform(PR_TRUE) + : mPropagateTransform(PR_TRUE) { } @@ -312,6 +315,11 @@ nsSVGForeignObjectFrame::Init(nsPresContext* aPresContext, nsStyleContext* aContext, nsIFrame* aPrevInFlow) { + // A layout change inside a foreign object can never affect anything + // outside of it. Or at least that's how we implement it, whether + // or not it's really true. + AddStateBits(NS_FRAME_REFLOW_ROOT); + nsresult rv; rv = nsSVGForeignObjectFrameBase::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); @@ -475,7 +483,7 @@ nsSVGForeignObjectFrame::PaintSVG(nsISVGRendererCanvas* canvas, const nsRect& dirtyRectTwips, PRBool ignoreFilter) { - if (mIsDirty) { + if (IsDirty()) { nsCOMPtr region = DoReflow(); } @@ -611,7 +619,7 @@ nsSVGForeignObjectFrame::NotifyRedrawSuspended() NS_IMETHODIMP nsSVGForeignObjectFrame::NotifyRedrawUnsuspended() { - if (mIsDirty) { + if (IsDirty()) { nsCOMPtr dirtyRegion = DoReflow(); if (dirtyRegion) { nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame(); @@ -774,7 +782,7 @@ void nsSVGForeignObjectFrame::Update() printf("**nsSVGForeignObjectFrame::Update()\n"); #endif - mIsDirty = PR_TRUE; + AddStateBits(NS_FRAME_IS_DIRTY); nsISVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame(); if (!outerSVGFrame) { @@ -812,8 +820,7 @@ nsSVGForeignObjectFrame::DoReflow() NS_ASSERTION(presShell, "null presShell"); presShell->CreateRenderingContext(this,getter_AddRefs(renderingContext)); - // XXX we always pass this off as an initial reflow. is that a problem? - nsHTMLReflowState reflowState(presContext, this, eReflowReason_Initial, + nsHTMLReflowState reflowState(presContext, this, renderingContext, availableSpace); nsSpaceManager* spaceManager = new nsSpaceManager(presShell, this); @@ -831,8 +838,6 @@ nsSVGForeignObjectFrame::DoReflow() SetSize(nsSize(desiredSize.width, desiredSize.height)); DidReflow(presContext, &reflowState, NS_FRAME_REFLOW_FINISHED); - mIsDirty = PR_FALSE; - nsCOMPtr area_after = GetCoveredRegion(); nsISVGRendererRegion *dirtyRegion; area_before->Combine(area_after, &dirtyRegion); diff --git a/mozilla/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/mozilla/layout/svg/base/src/nsSVGOuterSVGFrame.cpp index 4b0d2934a4c..776c81feaf2 100644 --- a/mozilla/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -53,7 +53,6 @@ #include "nsISVGValue.h" #include "nsISVGValueObserver.h" #include "nsHTMLParts.h" -#include "nsReflowPath.h" #include "nsISVGRenderer.h" #include "nsISVGRendererRegion.h" #include "nsIServiceManager.h" @@ -415,47 +414,6 @@ nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext, } #endif - // check whether this reflow request is targeted at us or a child - // frame (e.g. a foreignObject): - if (aReflowState.reason == eReflowReason_Incremental) { - nsReflowPath::iterator iter = aReflowState.path->FirstChild(); - nsReflowPath::iterator end = aReflowState.path->EndChildren(); - - for ( ; iter != end; ++iter) { - // The actual target of this reflow is one of our child - // frames. Since SVG as such doesn't use reflow, this will - // probably be the child of a . Some HTML|XUL - // content frames target reflow events at themselves when they - // need to be redrawn in response to e.g. a style change. For - // correct visual updating, we must make sure the reflow - // reaches its intended target. - - // Since it is an svg frame (probably an nsSVGForeignObjectFrame), - // we might as well pass in our aDesiredSize and aReflowState - // objects - they are ignored by svg frames: - nsSize availSpace(0, 0); // XXXwaterson probably wrong! - nsHTMLReflowState state(aPresContext, aReflowState, *iter, availSpace); - (*iter)->Reflow (aPresContext, - aDesiredSize, - state, - aStatus); - - // XXX do we really have to return our metrics although we're - // not affected by the reflow? Is there a way of telling our - // parent that we don't want anything changed? - aDesiredSize.width = mRect.width; - aDesiredSize.height = mRect.height; - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; - } - - if (! aReflowState.path->mReflowCommand) { - // We're not the target of the incremental reflow, so just bail. - aStatus = NS_FRAME_COMPLETE; - return NS_OK; - } - } - // SVG CR 20001102: When the SVG content is embedded inline within // a containing document, and that document is styled using CSS, // then if there are CSS positioning properties specified on the @@ -1096,9 +1054,8 @@ void nsSVGOuterSVGFrame::InitiateReflow() { mNeedsReflow = PR_FALSE; - // Generate a reflow command to reflow ourselves nsIPresShell* presShell = GetPresContext()->PresShell(); - presShell->AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull); + presShell->FrameNeedsReflow(this, nsIPresShell::eStyleChange); // XXXbz why is this synchronously flushing reflows, exactly? If it // needs to, why is it not using the presshell's reflow batching // instead of hacking its own? diff --git a/mozilla/layout/tables/Makefile.in b/mozilla/layout/tables/Makefile.in index 3e61024c6ee..27e21b26062 100644 --- a/mozilla/layout/tables/Makefile.in +++ b/mozilla/layout/tables/Makefile.in @@ -43,8 +43,10 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk MODULE = layout +ifdef CSS_TABLES LIBRARY_NAME = gktable_s LIBXUL_LIBRARY = 1 +endif REQUIRES = xpcom \ string \ @@ -68,6 +70,7 @@ EXPORTS = \ nsITableLayout.h \ $(NULL) +ifdef CSS_TABLES CPPSRCS = \ BasicTableLayoutStrategy.cpp \ FixedTableLayoutStrategy.cpp \ @@ -84,6 +87,7 @@ CPPSRCS = \ # we don't want the shared lib, but we want to force the creation of a static lib. FORCE_STATIC_LIB = 1 +endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index c6358bc89bf..1f6f0c371b3 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -41,7 +41,6 @@ #include "nsTableFrame.h" #include "nsTableRowGroupFrame.h" #include "nsTablePainter.h" -#include "nsReflowPath.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" #include "nsPresContext.h" diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index f0d8759267a..3869627d0b3 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -38,7 +38,6 @@ #include "nsTableColFrame.h" #include "nsTableFrame.h" #include "nsIDOMHTMLTableColElement.h" -#include "nsReflowPath.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" #include "nsPresContext.h" diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 2551cfaad00..3337263460b 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -62,7 +62,6 @@ #include "nsIView.h" #include "nsHTMLAtoms.h" #include "nsCSSAnonBoxes.h" -#include "nsHTMLReflowCommand.h" #include "nsLayoutAtoms.h" #include "nsIDeviceContext.h" #include "nsIPresShell.h" @@ -70,7 +69,6 @@ #include "nsIDOMHTMLElement.h" #include "nsIDOMHTMLBodyElement.h" #include "nsIScrollableFrame.h" -#include "nsHTMLReflowCommand.h" #include "nsFrameManager.h" #include "nsCSSRendering.h" #include "nsLayoutErrors.h" @@ -345,8 +343,7 @@ nsTableFrame::AppendDirtyReflowCommand(nsIFrame* aFrame) { aFrame->AddStateBits(NS_FRAME_IS_DIRTY); // mark the table frame as dirty - return aFrame->GetPresContext()->PresShell()-> - AppendReflowCommand(aFrame, eReflowType_ReflowDirty, nsnull); + return aPresShell->FrameNeedsReflow(aFrame, nsIPresShell::eStyleChange); } // Make sure any views are positioned properly diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp index 497ed2736a3..ea069566a63 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.cpp +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp @@ -37,7 +37,6 @@ * ***** END LICENSE BLOCK ***** */ #include "nsTableOuterFrame.h" #include "nsTableFrame.h" -#include "nsHTMLReflowCommand.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" #include "nsPresContext.h" @@ -234,11 +233,9 @@ nsTableOuterFrame::AppendFrames(nsIAtom* aListName, // Insert the caption frame into the child list mCaptionFrame = aFrameList; - // Reflow the new caption frame. It's already marked dirty, so generate a reflow - // command that tells us to reflow our dirty child frames - rv = GetPresContext()-> - PresShell()->AppendReflowCommand(this, eReflowType_ReflowDirty, - nsnull); + // Reflow the new caption frame. It's already marked dirty, so + // just tell the pres shell. + aPresShell.FrameNeedsReflow(mCaptionFrame, nsIPresShell::eStyleChange); } } else { @@ -286,9 +283,8 @@ nsTableOuterFrame::RemoveFrame(nsIAtom* aListName, } // Generate a reflow command so we get reflowed - GetPresContext()->PresShell()->AppendReflowCommand(this, - eReflowType_ReflowDirty, - nsnull); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); // is this right? + aPresShell.FrameNeedsReflow(this, nsIPresShell::eStyleChange); return NS_OK; } diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 9fcaadca10f..135f7ea4356 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -46,7 +46,6 @@ #include "nsTableFrame.h" #include "nsTableCellFrame.h" #include "nsIView.h" -#include "nsReflowPath.h" #include "nsCSSRendering.h" #include "nsLayoutAtoms.h" #include "nsHTMLParts.h" diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index e52067c4a9a..2a1fea0d9aa 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -45,7 +45,6 @@ #include "nsStyleConsts.h" #include "nsIContent.h" #include "nsIView.h" -#include "nsReflowPath.h" #include "nsIDeviceContext.h" #include "nsHTMLAtoms.h" #include "nsIPresShell.h" diff --git a/mozilla/layout/xtf/src/Makefile.in b/mozilla/layout/xtf/src/Makefile.in index 829108891dd..f77433ccef3 100644 --- a/mozilla/layout/xtf/src/Makefile.in +++ b/mozilla/layout/xtf/src/Makefile.in @@ -52,6 +52,7 @@ REQUIRES = xpcom \ content \ gfx \ widget \ + view \ dom \ locale \ necko \ diff --git a/mozilla/layout/xul/base/src/grid/nsGrid.cpp b/mozilla/layout/xul/base/src/grid/nsGrid.cpp index 0ada9083c02..758911c0850 100644 --- a/mozilla/layout/xul/base/src/grid/nsGrid.cpp +++ b/mozilla/layout/xul/base/src/grid/nsGrid.cpp @@ -1359,68 +1359,6 @@ nsGrid::GetColumnCount(PRInt32 aIsHorizontal) return GetRowCount(!aIsHorizontal); } -/** - * This is called if a child in a row became dirty. This happens if the child gets bigger or smaller - * in some way. - */ -void -nsGrid::RowChildIsDirty(nsBoxLayoutState& aState, PRInt32 aRowIndex, PRInt32 aColumnIndex, PRBool aIsHorizontal) -{ - // if we are already dirty do nothing. - if (mNeedsRebuild || mMarkingDirty) - return; - - NeedsRebuild(aState); - - // This code does not work with trees when rows are - // dynamically inserted, the cache values are invalid. - /* - mMarkingDirty = PR_TRUE; - - // index out of range. Rebuild it all - if (aRowIndex >= GetRowCount(aIsHorizontal) || aColumnIndex >= GetColumnCount(aIsHorizontal)) - { - NeedsRebuild(aState); - return; - } - - // dirty our 2 outer nsGridRows. (one for columns and one for rows) - // we need to do this because the rows and column we are given may be Extra ones - // and may not have any Box associated with them. If you dirtied them then - // corresponding nsGridRowGroup around them would never get dirty. So lets just - // do it manually here. - - if (mRowBox) - mRowBox->MarkDirty(aState); - - if (mColumnBox) - mColumnBox->MarkDirty(aState); - - // dirty just our row and column that we were given - nsGridRow* row = GetRowAt(aRowIndex, aIsHorizontal); - row->MarkDirty(aState); - - nsGridRow* column = GetColumnAt(aColumnIndex, aIsHorizontal); - column->MarkDirty(aState); - - - mMarkingDirty = PR_FALSE; - */ -} - -/** - * The row became dirty. This happens if the row's borders change or children inside it - * force it to change size - */ -void -nsGrid::RowIsDirty(nsBoxLayoutState& aState, PRInt32 aIndex, PRBool aIsHorizontal) -{ - if (mMarkingDirty) - return; - - NeedsRebuild(aState); -} - /* * A cell in the given row or columns at the given index has had a child added or removed */ diff --git a/mozilla/layout/xul/base/src/grid/nsGrid.h b/mozilla/layout/xul/base/src/grid/nsGrid.h index 6c1fe57aa29..abd1bacc0b8 100644 --- a/mozilla/layout/xul/base/src/grid/nsGrid.h +++ b/mozilla/layout/xul/base/src/grid/nsGrid.h @@ -75,8 +75,6 @@ public: nsresult GetMaxRowHeight(nsBoxLayoutState& aBoxLayoutState, PRInt32 aRowIndex, nscoord& aHeight, PRBool aIsHorizontal = PR_TRUE); void GetRowOffsets(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aTop, nscoord& aBottom, PRBool aIsHorizontal = PR_TRUE); - void RowChildIsDirty(nsBoxLayoutState& aBoxLayoutState, PRInt32 aRowIndex, PRInt32 aColumnIndex, PRBool aIsHorizontal = PR_TRUE); - void RowIsDirty(nsBoxLayoutState& aBoxLayoutState, PRInt32 aIndex, PRBool aIsHorizontal = PR_TRUE); void RowAddedOrRemoved(nsBoxLayoutState& aBoxLayoutState, PRInt32 aIndex, PRBool aIsHorizontal = PR_TRUE); void CellAddedOrRemoved(nsBoxLayoutState& aBoxLayoutState, PRInt32 aIndex, PRBool aIsHorizontal = PR_TRUE); void DirtyRows(nsIBox* aRowBox, nsBoxLayoutState& aState); @@ -129,9 +127,11 @@ private: nsGridRow* mColumns; // the first in the that implements the tag. + // XXXldb This should be called mRowsBox nsIBox* mRowBox; // the first in the that implements the tag. + // XXXldb This should be called mColumnsBox nsIBox* mColumnBox; // a flag that is false tells us to rebuild the who grid diff --git a/mozilla/layout/xul/base/src/grid/nsGridLayout2.cpp b/mozilla/layout/xul/base/src/grid/nsGridLayout2.cpp index 142b3cffe05..a25fc9ebead 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridLayout2.cpp +++ b/mozilla/layout/xul/base/src/grid/nsGridLayout2.cpp @@ -73,6 +73,17 @@ nsGridLayout2::Layout(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState) return rv; } +NS_IMETHODIMP +nsGridLayout2::IntrinsicWidthsDirty(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState) +{ + nsresult rv = nsStackLayout::IntrinsicWidthsDirty(aBox, aBoxLayoutState); + // XXXldb We really don't need to do all the work that NeedsRebuild + // does; we just need to mark intrinsic widths dirty on the + // (row/column)(s/-groups). + mGrid.NeedsRebuild(aBoxLayoutState); + return rv; +} + NS_IMETHODIMP nsGridLayout2::GetGrid(nsIBox* aBox, nsGrid** aGrid, PRInt32* aIndex, nsGridRowLayout* aRequestor) { diff --git a/mozilla/layout/xul/base/src/grid/nsGridLayout2.h b/mozilla/layout/xul/base/src/grid/nsGridLayout2.h index a4d9fffccbe..df871f4a94a 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridLayout2.h +++ b/mozilla/layout/xul/base/src/grid/nsGridLayout2.h @@ -62,6 +62,7 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_IMETHOD Layout(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState); + NS_IMETHOD IntrinsicWidthsDirty(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState); NS_IMETHOD CastToRowGroupLayout(nsGridRowGroupLayout** aRowGroup); NS_IMETHOD CastToGridLayout(nsGridLayout2** aGrid); diff --git a/mozilla/layout/xul/base/src/grid/nsGridRow.cpp b/mozilla/layout/xul/base/src/grid/nsGridRow.cpp index ca5e8012dc4..7f49a28e427 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRow.cpp +++ b/mozilla/layout/xul/base/src/grid/nsGridRow.cpp @@ -44,6 +44,7 @@ #include "nsGridRow.h" #include "nsIFrame.h" +#include "nsBoxLayoutState.h" nsGridRow::nsGridRow():mIsBogus(PR_FALSE), mBox(nsnull), @@ -90,8 +91,10 @@ nsGridRow::MarkDirty(nsBoxLayoutState& aState) mTop = -1; mBottom = -1; - if (mBox) - mBox->MarkDirty(aState); + if (mBox) { + mBox->AddStateBits(NS_FRAME_IS_DIRTY); + aState.PresShell()->FrameNeedsReflow(mBox, nsIPresShell::eTreeChange); + } } PRBool diff --git a/mozilla/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp b/mozilla/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp index e11fdcd0f89..63ae774c4cd 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp +++ b/mozilla/layout/xul/base/src/grid/nsGridRowGroupLayout.cpp @@ -195,7 +195,10 @@ nsGridRowGroupLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState) { if (aBox) { // mark us dirty - aBox->MarkDirty(aState); + aBox->AddStateBits(NS_FRAME_IS_DIRTY); + // XXXldb We probably don't want to walk up the ancestor chain + // calling MarkIntrinsicWidthsDirty for every row group. + aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange); nsIBox* child = nsnull; aBox->GetChildBox(&child); nsIBox* deepChild = child; diff --git a/mozilla/layout/xul/base/src/grid/nsGridRowLayout.h b/mozilla/layout/xul/base/src/grid/nsGridRowLayout.h index 43523f26e74..e659c17e94f 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRowLayout.h +++ b/mozilla/layout/xul/base/src/grid/nsGridRowLayout.h @@ -53,6 +53,8 @@ class nsBoxLayoutState; class nsIPresShell; class nsGrid; +// XXXldb This needs a name that indicates that it's a base class for +// both row and rows (row-group). class nsGridRowLayout : public nsSprocketLayout, public nsIGridPart { diff --git a/mozilla/layout/xul/base/src/grid/nsGridRowLeafFrame.h b/mozilla/layout/xul/base/src/grid/nsGridRowLeafFrame.h index b2877774653..66e18a384e5 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRowLeafFrame.h +++ b/mozilla/layout/xul/base/src/grid/nsGridRowLeafFrame.h @@ -48,6 +48,8 @@ #include "nsBoxFrame.h" +// XXXldb This needs a better name that indicates that it's for any grid +// row. class nsGridRowLeafFrame : public nsBoxFrame { public: diff --git a/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp b/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp index 90549e96c48..605291576fe 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp +++ b/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.cpp @@ -132,37 +132,6 @@ nsGridRowLeafLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState, nsSize& } } -NS_IMETHODIMP -nsGridRowLeafLayout::ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild) -{ - nsGrid* grid = nsnull; - PRInt32 index = 0; - GetGrid(aBox, &grid, &index); - PRInt32 isHorizontal = IsHorizontal(aBox); - - if (grid) { - PRInt32 columnIndex = -1; - aBox->GetIndexOf(aChild, &columnIndex); - grid->RowChildIsDirty(aState, index, columnIndex, isHorizontal); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsGridRowLeafLayout::BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState) -{ - nsGrid* grid = nsnull; - PRInt32 index = 0; - GetGrid(aBox, &grid, &index); - PRInt32 isHorizontal = IsHorizontal(aBox); - - if (grid) - grid->RowIsDirty(aState, index, isHorizontal); - - return NS_OK; -} - /** If a child is added or removed or changes size */ NS_IMETHODIMP @@ -374,7 +343,10 @@ nsGridRowLeafLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState) { if (aBox) { // mark us dirty - aBox->MarkDirty(aState); + aBox->AddStateBits(NS_FRAME_IS_DIRTY); + // XXXldb We probably don't want to walk up the ancestor chain + // calling MarkIntrinsicWidthsDirty for every row. + aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange); } return NS_OK; diff --git a/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.h b/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.h index 7e67735b02e..6ca82e8bb9a 100644 --- a/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.h +++ b/mozilla/layout/xul/base/src/grid/nsGridRowLeafLayout.h @@ -48,6 +48,8 @@ #include "nsGridRowLayout.h" #include "nsCOMPtr.h" +// XXXldb This needs a better name that indicates that it's for any grid +// row. class nsGridRowLeafLayout : public nsGridRowLayout { public: @@ -58,8 +60,6 @@ public: NS_IMETHOD GetMinSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); NS_IMETHOD GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); NS_IMETHOD CastToGridRowLeaf(nsGridRowLeafLayout** aGridRowLeaf); - NS_IMETHOD ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild); - NS_IMETHOD BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState); NS_IMETHOD ChildAddedOrRemoved(nsIBox* aBox, nsBoxLayoutState& aState); NS_IMETHOD Layout(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState); NS_IMETHOD CountRowsColumns(nsIBox* aBox, PRInt32& aRowCount, PRInt32& aComputedColumnCount); diff --git a/mozilla/layout/xul/base/src/nsBox.cpp b/mozilla/layout/xul/base/src/nsBox.cpp index fd2e519504d..23556db3025 100644 --- a/mozilla/layout/xul/base/src/nsBox.cpp +++ b/mozilla/layout/xul/base/src/nsBox.cpp @@ -177,24 +177,7 @@ nsBox::BeginLayout(nsBoxLayoutState& aState) #ifdef DEBUG_LAYOUT nsBoxAddIndents(); - - nsAutoString reason; - switch(aState.LayoutReason()) - { - case nsBoxLayoutState::Dirty: - reason.AssignLiteral("Dirty"); - break; - case nsBoxLayoutState::Initial: - reason.AssignLiteral("Initial"); - break; - case nsBoxLayoutState::Resize: - reason.AssignLiteral("Resize"); - break; - } - - char ch[100]; - reason.ToCString(ch,100); - printf("%s Layout: ", ch); + printf("Layout: "); DumpBox(stdout); printf("\n"); gIndent++; @@ -202,8 +185,19 @@ nsBox::BeginLayout(nsBoxLayoutState& aState) // mark ourselves as dirty so no child under us // can post an incremental layout. + // XXXldb Is this still needed? mState |= NS_FRAME_HAS_DIRTY_CHILDREN; + if (GetStateBits() & NS_FRAME_IS_DIRTY) + { + // If the parent is dirty, all the children are dirty (nsHTMLReflowState + // does this too). + nsIFrame* box; + for (GetChildBox(&box); box; box->GetNextBox(&box)) + box->AddStateBits(NS_FRAME_IS_DIRTY); + } + + #ifdef DEBUG_LAYOUT PropagateDebug(aState); #endif @@ -267,156 +261,6 @@ nsBox::Shutdown() NS_IF_RELEASE(gTheme); } -NS_IMETHODIMP -nsBox::MarkDirty(nsBoxLayoutState& aState) -{ - // only reflow if we aren't already dirty. - if (GetStateBits() & NS_FRAME_IS_DIRTY) { -#ifdef DEBUG_COELESCED - Coelesced(); -#endif - return NS_OK; - } - - AddStateBits(NS_FRAME_IS_DIRTY); - - NeedsRecalc(); - - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->BecameDirty(this, aState); - - if (GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) { -#ifdef DEBUG_COELESCED - Coelesced(); -#endif - return NS_OK; - } - - nsIBox* parent = nsnull; - GetParentBox(&parent); - if (parent) - return parent->RelayoutDirtyChild(aState, this); - else { - return GetParent()->ReflowDirtyChild(aState.PresShell(), this); - } -} - -nsresult -nsIFrame::MarkDirtyChildren(nsBoxLayoutState& aState) -{ - return RelayoutDirtyChild(aState, nsnull); -} - -NS_IMETHODIMP -nsBox::MarkStyleChange(nsBoxLayoutState& aState) -{ - NeedsRecalc(); - - if (HasStyleChange()) - return NS_OK; - - // iterate through all children making them dirty - MarkChildrenStyleChange(); - - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->BecameDirty(this, aState); - - nsIBox* parent = nsnull; - GetParentBox(&parent); - if (parent) - return parent->RelayoutDirtyChild(aState, this); - else { - /* - aState.PresShell()->AppendReflowCommand(this, eReflowType_StyleChanged, - nsnull); - return NS_OK; - */ - return GetParent()->ReflowDirtyChild(aState.PresShell(), this); - } - - return NS_OK; -} - -PRBool -nsBox::HasStyleChange() -{ - PRBool aDirty = PR_FALSE; - IsDirty(aDirty); - return aDirty; -} - -void -nsBox::SetStyleChangeFlag(PRBool aDirty) -{ - NeedsRecalc(); - AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); -} - -NS_IMETHODIMP -nsBox::MarkChildrenStyleChange() -{ - // only reflow if we aren't already dirty. - if (HasStyleChange()) { -#ifdef DEBUG_COELESCED - printf("StyleChange reflows coelesced=%d\n", ++StyleCoelesced); -#endif - return NS_OK; - } - - SetStyleChangeFlag(PR_TRUE); - - nsIBox* child = nsnull; - GetChildBox(&child); - while(child) - { - child->MarkChildrenStyleChange(); - child->GetNextBox(&child); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsBox::RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild) -{ - if (aChild != nsnull) { - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->ChildBecameDirty(this, aState, aChild); - } - - // if we are not dirty mark ourselves dirty and tell our parent we are dirty too. - if (!(GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) { - // Mark yourself as dirty and needing to be recalculated - AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - - if (GetStateBits() & NS_FRAME_REFLOW_ROOT) { - aState.PresShell()->AppendReflowCommand(this, eReflowType_ReflowDirty, - nsnull); - return NS_OK; - } - - NeedsRecalc(); - - nsIBox* parentBox = nsnull; - GetParentBox(&parentBox); - if (parentBox) - return parentBox->RelayoutDirtyChild(aState, this); - return GetParent()->ReflowDirtyChild(aState.PresShell(), this); - } else { -#ifdef DEBUG_COELESCED - Coelesced(); -#endif - } - - return NS_OK; -} - NS_IMETHODIMP nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIBox* aChild) { @@ -623,12 +467,6 @@ nsIFrame::GetParentBox(nsIBox** aParent) return NS_OK; } -NS_IMETHODIMP -nsBox::NeedsRecalc() -{ - return NS_OK; -} - void nsBox::SizeNeedsRecalc(nsSize& aSize) { @@ -686,6 +524,7 @@ nsBox::GetLayoutManager(nsIBoxLayout** aLayout) NS_IMETHODIMP nsBox::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); aSize.width = 0; aSize.height = 0; @@ -710,6 +549,7 @@ nsBox::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) NS_IMETHODIMP nsBox::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); aSize.width = 0; aSize.height = 0; @@ -733,6 +573,7 @@ nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) NS_IMETHODIMP nsBox::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_MAX_SIZE(this, aSize); aSize.width = NS_INTRINSICSIZE; aSize.height = NS_INTRINSICSIZE; @@ -795,6 +636,8 @@ nsresult nsIFrame::Layout(nsBoxLayoutState& aState) { nsBox *box = NS_STATIC_CAST(nsBox*, this); + DISPLAY_LAYOUT(box); + box->BeginLayout(aState); box->DoLayout(aState); @@ -827,9 +670,7 @@ nsBox::SyncLayout(nsBoxLayoutState& aState) */ - PRBool dirty = PR_FALSE; - IsDirty(dirty); - if (dirty || aState.LayoutReason() == nsBoxLayoutState::Initial) + if (GetStateBits() & NS_FRAME_IS_DIRTY) Redraw(aState); RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY @@ -919,12 +760,6 @@ nsIFrame::Redraw(nsBoxLayoutState& aState, if (aState.PaintingDisabled()) return NS_OK; - const nsHTMLReflowState* s = aState.GetReflowState(); - if (s) { - if (s->reason != eReflowReason_Incremental) - return NS_OK; - } - nsRect damageRect(0,0,0,0); if (aDamageRect) damageRect = *aDamageRect; @@ -1002,9 +837,9 @@ nsIBox::AddCSSMinSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize) nsITheme *theme = aState.PresContext()->GetTheme(); if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) { nsSize size; - const nsHTMLReflowState* reflowState = aState.GetReflowState(); - if (reflowState) { - theme->GetMinimumWidgetSize(reflowState->rendContext, aBox, + nsIRenderingContext* rendContext = aState.GetRenderingContext(); + if (rendContext) { + theme->GetMinimumWidgetSize(rendContext, aBox, display->mAppearance, &size, &canOverride); float p2t = aState.PresContext()->ScaledPixelsToTwips(); if (size.width) { diff --git a/mozilla/layout/xul/base/src/nsBox.h b/mozilla/layout/xul/base/src/nsBox.h index 507156cb7c4..fc9d41c425f 100644 --- a/mozilla/layout/xul/base/src/nsBox.h +++ b/mozilla/layout/xul/base/src/nsBox.h @@ -70,8 +70,6 @@ public: NS_IMETHOD SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect, PRBool aRemoveOverflowArea = PR_FALSE); - NS_IMETHOD MarkDirty(nsBoxLayoutState& aState); - NS_IMETHOD GetBorder(nsMargin& aBorderAndPadding); NS_IMETHOD GetPadding(nsMargin& aBorderAndPadding); NS_IMETHOD GetMargin(nsMargin& aMargin); @@ -83,14 +81,10 @@ public: NS_IMETHOD GetHAlign(Halignment& aAlign); - NS_IMETHOD NeedsRecalc(); - NS_IMETHOD RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild); NS_IMETHOD RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIBox* aChild); NS_IMETHOD GetMouseThrough(PRBool& aMouseThrough); - NS_IMETHOD MarkChildrenStyleChange(); - NS_IMETHOD MarkStyleChange(nsBoxLayoutState& aState); #ifdef DEBUG_LAYOUT NS_IMETHOD GetInset(nsMargin& aInset); NS_IMETHOD GetDebugBoxAt(const nsPoint& aPoint, nsIBox** aBox); @@ -145,9 +139,6 @@ protected: virtual void ListBox(nsAutoString& aResult); #endif - virtual PRBool HasStyleChange(); - virtual void SetStyleChangeFlag(PRBool aDirty); - virtual PRBool GetWasCollapsed(nsBoxLayoutState& aState); virtual void SetWasCollapsed(nsBoxLayoutState& aState, PRBool aWas); virtual PRBool GetDefaultFlex(PRInt32& aFlex); diff --git a/mozilla/layout/xul/base/src/nsBoxFrame.cpp b/mozilla/layout/xul/base/src/nsBoxFrame.cpp index e9771b8de55..5ccd39d1d38 100644 --- a/mozilla/layout/xul/base/src/nsBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsBoxFrame.cpp @@ -167,8 +167,6 @@ nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* a } SetLayoutManager(layout); - - NeedsRecalc(); } nsBoxFrame::~nsBoxFrame() @@ -197,7 +195,7 @@ nsBoxFrame::SetInitialChildList(nsPresContext* aPresContext, nsresult r = nsContainerFrame::SetInitialChildList(aPresContext, aListName, aChildList); if (r == NS_OK) { // initialize our list of infos. - nsBoxLayoutState state(aPresContext->PresShell()); + nsBoxLayoutState state(aPresContext); CheckBoxOrder(state); if (mLayoutManager) mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild()); @@ -222,6 +220,8 @@ nsBoxFrame::Init(nsPresContext* aPresContext, nsresult rv = nsContainerFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + MarkIntrinsicWidthsDirty(); + // see if we need a widget. Get our parent. Querty interface the parent we are given. if (aParent && aParent->IsBoxFrame()) { PRBool needsWidget = PR_FALSE; @@ -670,31 +670,6 @@ nsBoxFrame::GetInitialAutoStretch(PRBool& aStretch) return PR_TRUE; } - -NS_IMETHODIMP -nsBoxFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild) -{ - // if we receive a ReflowDirtyChild it is because there is an HTML frame - // just inside us. So must find the adaptor that contains the child and - // tell it that things are dirty. - nsBoxLayoutState state(aPresShell->GetPresContext()); - - nsIBox* box = nsnull; - GetChildBox(&box); - while (box) - { - if (box == aChild) { - box->MarkDirty(state); - return RelayoutDirtyChild(state, box); - } - - box->GetNextBox(&box); - } - - NS_ERROR("Could not find an adaptor!"); - return NS_OK; -} - NS_IMETHODIMP nsBoxFrame::DidReflow(nsPresContext* aPresContext, const nsHTMLReflowState* aReflowState, @@ -720,32 +695,48 @@ static void printSize(char * aDesc, nscoord aSize) } #endif -/** - * Returns PR_TRUE when the reflow reason is "Initial" and doing Print Preview - * when returning PR_FALSE aIsChrome's value is indeterminate - * aIsChrome - Returns PR_TRUE when document is chrome, otherwise PR_FALSE - */ -PRBool -nsBoxFrame::IsInitialReflowForPrintPreview(nsBoxLayoutState& aState, - PRBool& aIsChrome) +/* virtual */ nscoord +nsBoxFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) { - aIsChrome = PR_FALSE; - const nsHTMLReflowState* reflowState = aState.GetReflowState(); - if (reflowState->reason == eReflowReason_Initial) { - // See if we are doing Print Preview - if (aState.PresContext()->Type() == nsPresContext::eContext_PrintPreview) { - // Now, get the current URI to see if we doing chrome - nsIPresShell *presShell = aState.PresShell(); - if (!presShell) return PR_FALSE; - nsIDocument *doc = presShell->GetDocument(); - if (!doc) return PR_FALSE; - nsIURI *uri = doc->GetDocumentURI(); - if (!uri) return PR_FALSE; - uri->SchemeIs("chrome", &aIsChrome); - return PR_TRUE; - } - } - return PR_FALSE; + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + + nsBoxLayoutState state(GetPresContext(), aRenderingContext); + nsSize minSize(0,0); + GetMinSize(state, minSize); + + // GetMinSize returns border-box width, and we want to return content + // width. Since Reflow uses the reflow state's border and padding, we + // actually just want to subtract what GetMinSize added, which is the + // result of GetBorderAndPadding. + nsMargin bp; + GetBorderAndPadding(bp); + + result = minSize.width - bp.LeftRight(); + + return result; +} + +/* virtual */ nscoord +nsBoxFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + + nsBoxLayoutState state(GetPresContext(), aRenderingContext); + nsSize prefSize(0,0); + GetPrefSize(state, prefSize); + + // GetPrefSize returns border-box width, and we want to return content + // width. Since Reflow uses the reflow state's border and padding, we + // actually just want to subtract what GetPrefSize added, which is the + // result of GetBorderAndPadding. + nsMargin bp; + GetBorderAndPadding(bp); + + result = prefSize.width - bp.LeftRight(); + + return result; } NS_IMETHODIMP @@ -757,28 +748,14 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, // If you make changes to this method, please keep nsLeafBoxFrame::Reflow // in sync, if the changes are applicable there. - DO_GLOBAL_REFLOW_COUNT("nsBoxFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsBoxFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_ASSERTION(aReflowState.mComputedWidth >=0 && aReflowState.mComputedHeight >= 0, "Computed Size < 0"); #ifdef DO_NOISY_REFLOW printf("\n-------------Starting BoxFrame Reflow ----------------------------\n"); - printf("%p ** nsBF::Reflow %d R: ", this, myCounter++); - switch (aReflowState.reason) { - case eReflowReason_Initial: - printf("Ini");break; - case eReflowReason_Incremental: - printf("Inc");break; - case eReflowReason_Resize: - printf("Rsz");break; - case eReflowReason_StyleChange: - printf("Sty");break; - case eReflowReason_Dirty: - printf("Drt "); - break; - default:printf("%d", aReflowState.reason);break; - } + printf("%p ** nsBF::Reflow %d ", this, myCounter++); printSize("AW", aReflowState.availableWidth); printSize("AH", aReflowState.availableHeight); @@ -792,11 +769,8 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; // create the layout state - nsBoxLayoutState state(aPresContext, aReflowState, aDesiredSize); + nsBoxLayoutState state(aPresContext, aReflowState.rendContext); - // coelesce reflows if we are root. - state.HandleReflow(this); - nsSize computedSize(aReflowState.mComputedWidth,aReflowState.mComputedHeight); nsMargin m; @@ -806,7 +780,9 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, nsSize prefSize(0,0); // if we are told to layout intrinic then get our preferred size. - if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) { + NS_ASSERTION(computedSize.width != NS_INTRINSICSIZE, + "computed width should always be computed"); + if (computedSize.height == NS_INTRINSICSIZE) { nsSize minSize(0,0); nsSize maxSize(0,0); GetPrefSize(state, prefSize); @@ -816,11 +792,7 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, } // get our desiredSize - if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) { - computedSize.width = prefSize.width; - } else { - computedSize.width += m.left + m.right; - } + computedSize.width += m.left + m.right; if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) { computedSize.height = prefSize.height; @@ -857,15 +829,7 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, // getting the ascent could be a lot of work. Don't get it if // we are the root. The viewport doesn't care about it. if (!(mState & NS_STATE_IS_ROOT)) { - // Only call GetAscent when not doing Initial reflow while in PP - // or when it is Initial reflow while in PP and a chrome doc - // If called again with initial reflow it crashes because the - // frames are fully constructed (I think). - PRBool isChrome; - PRBool isInitialPP = IsInitialReflowForPrintPreview(state, isChrome); - if (!isInitialPP || (isInitialPP && isChrome)) { - GetAscent(state, ascent); - } + GetAscent(state, ascent); } aDesiredSize.width = mRect.width; @@ -880,24 +844,6 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, aDesiredSize.mOverflowArea = *overflowArea; } - if(aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = prefSize.width; - } - - // max sure the max element size reflects - // our min width - nscoord* maxElementWidth = state.GetMaxElementWidth(); - if (maxElementWidth) - { - nsSize minSize(0,0); - GetMinSize(state, minSize); - if (aReflowState.mStylePosition->mWidth.GetUnit() == eStyleUnit_Percent || - (mRect.width > minSize.width && - aReflowState.mComputedWidth == NS_INTRINSICSIZE)) - *maxElementWidth = minSize.width; - else - *maxElementWidth = mRect.width; - } #ifdef DO_NOISY_REFLOW { printf("%p ** nsBF(done) W:%d H:%d ", this, aDesiredSize.width, aDesiredSize.height); @@ -918,6 +864,7 @@ nsBoxFrame::Reflow(nsPresContext* aPresContext, NS_IMETHODIMP nsBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); if (!DoesNeedRecalc(mPrefSize)) { aSize = mPrefSize; return NS_OK; @@ -995,6 +942,7 @@ nsBoxFrame::GetAscent(nsBoxLayoutState& aBoxLayoutState, nscoord& aAscent) NS_IMETHODIMP nsBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); if (!DoesNeedRecalc(mMinSize)) { aSize = mMinSize; return NS_OK; @@ -1035,6 +983,7 @@ nsBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) NS_IMETHODIMP nsBoxFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_MAX_SIZE(this, aSize); if (!DoesNeedRecalc(mMaxSize)) { aSize = mMaxSize; return NS_OK; @@ -1139,22 +1088,26 @@ nsBoxFrame::SetDebug(nsBoxLayoutState& aState, PRBool aDebug) SetDebugOnChildList(aState, mFirstChild, aDebug); - NeedsRecalc(); + MarkIntrinsicWidthsDirty(); } return NS_OK; } #endif -NS_IMETHODIMP -nsBoxFrame::NeedsRecalc() +/* virtual */ void +nsBoxFrame::MarkIntrinsicWidthsDirty() { SizeNeedsRecalc(mPrefSize); SizeNeedsRecalc(mMinSize); SizeNeedsRecalc(mMaxSize); CoordNeedsRecalc(mFlex); CoordNeedsRecalc(mAscent); - return NS_OK; + + if (mLayoutManager) { + nsBoxLayoutState state(GetPresContext()); + mLayoutManager->IntrinsicWidthsDirty(this, state); + } } NS_IMETHODIMP @@ -1176,8 +1129,9 @@ nsBoxFrame::RemoveFrame(nsIAtom* aListName, aOldFrame->Destroy(presContext); // mark us dirty and generate a reflow command - MarkDirtyChildren(state); - MarkDirty(state); + mState |= NS_FRAME_HAS_DIRTY_CHILDREN; + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return NS_OK; } @@ -1202,9 +1156,9 @@ nsBoxFrame::InsertFrames(nsIAtom* aListName, SetDebugOnChildList(state, mFrames.FirstChild(), PR_TRUE); #endif - // mark us dirty and generate a reflow command - MarkDirtyChildren(state); - MarkDirty(state); + mState |= NS_FRAME_HAS_DIRTY_CHILDREN; + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return NS_OK; } @@ -1229,8 +1183,9 @@ nsBoxFrame::AppendFrames(nsIAtom* aListName, SetDebugOnChildList(state, mFrames.FirstChild(), PR_TRUE); #endif - MarkDirtyChildren(state); - MarkDirty(state); + mState |= NS_FRAME_HAS_DIRTY_CHILDREN; + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return NS_OK; } @@ -1342,16 +1297,19 @@ nsBoxFrame::AttributeChanged(PRInt32 aNameSpaceID, UpdateMouseThrough(); } - nsBoxLayoutState state(GetPresContext()); - MarkDirty(state); + mState |= NS_FRAME_IS_DIRTY; + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } else if (aAttribute == nsXULAtoms::ordinal) { - nsBoxLayoutState state(GetPresContext()->PresShell()); + nsBoxLayoutState state(GetPresContext()); nsIBox* parent; GetParentBox(&parent); parent->RelayoutChildAtOrdinal(state, this); - parent->MarkDirty(state); + mState |= NS_FRAME_IS_DIRTY; + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } // If the accesskey changed, register for the new value // The old value has been unregistered in nsXULElement::SetAttr @@ -1367,23 +1325,6 @@ nsBoxFrame::AttributeChanged(PRInt32 aNameSpaceID, static PRInt32 StyleCoelesced = 0; #endif -PRBool -nsBoxFrame::HasStyleChange() -{ - return mState & NS_STATE_STYLE_CHANGE; -} - -void -nsBoxFrame::SetStyleChangeFlag(PRBool aDirty) -{ - nsBox::SetStyleChangeFlag(aDirty); - - if (aDirty) - mState |= (NS_STATE_STYLE_CHANGE); - else - mState &= ~NS_STATE_STYLE_CHANGE; -} - #ifdef DEBUG_LAYOUT void nsBoxFrame::GetDebugPref(nsPresContext* aPresContext) @@ -1550,15 +1491,7 @@ nsBoxFrame::PaintChildren(nsPresContext* aPresContext, // if we have dirty children or we are dirty // place a green border around us. - PRBool dirty = PR_FALSE; - IsDirty(dirty); - PRBool dirtyc = PR_FALSE; - HasDirtyChildren(dirtyc); - - if (dirty || dirtyc) { - IsDirty(dirty); - HasDirtyChildren(dirty); - + if (GetStateBits & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) { nsRect dirtyr(inner); aRenderingContext.SetColor(NS_RGB(0,255,0)); aRenderingContext.DrawRect(dirtyr); @@ -1992,12 +1925,7 @@ nsBoxFrame::PaintDebug(nsIBox* aBox, // if we have dirty children or we are dirty // place a green border around us. - PRBool dirty = PR_FALSE; - IsDirty(dirty); - PRBool dirtyc = PR_FALSE; - HasDirtyChildren(dirty); - - if (dirty || dirtyc) { + if (GetStateBits & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) { nsRect dirtyr(inner); aRenderingContext.SetColor(NS_RGB(0,255,0)); aRenderingContext.DrawRect(dirtyr); @@ -2645,14 +2573,7 @@ nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIBox* aBox, const nsRect& nsRect oldRect(aBox->GetRect()); aBox->SetBounds(aState, aRect); - PRBool dirty = PR_FALSE; - PRBool dirtyChildren = PR_FALSE; - aBox->IsDirty(dirty); - aBox->HasDirtyChildren(dirtyChildren); - - PRBool layout = PR_TRUE; - if (!(dirty || dirtyChildren) && aState.LayoutReason() != nsBoxLayoutState::Initial) - layout = PR_FALSE; + PRBool layout = (aBox->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0; if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height)) { return aBox->Layout(aState); diff --git a/mozilla/layout/xul/base/src/nsBoxFrame.h b/mozilla/layout/xul/base/src/nsBoxFrame.h index d45800d794e..2529a3da8f3 100644 --- a/mozilla/layout/xul/base/src/nsBoxFrame.h +++ b/mozilla/layout/xul/base/src/nsBoxFrame.h @@ -113,7 +113,6 @@ public: #endif NS_IMETHOD GetVAlign(Valignment& aAlign); NS_IMETHOD GetHAlign(Halignment& aAlign); - NS_IMETHOD NeedsRecalc(); NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState); NS_IMETHOD GetMouseThrough(PRBool& aMouseThrough); @@ -130,8 +129,6 @@ public: nsIFrame::Cursor& aCursor); - NS_IMETHOD ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild); - NS_IMETHOD Init(nsPresContext* aPresContext, nsIContent* aContent, nsIFrame* aParent, @@ -143,6 +140,9 @@ public: nsIAtom* aAttribute, PRInt32 aModType); + virtual void MarkIntrinsicWidthsDirty(); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -189,10 +189,6 @@ public: nsFramePaintLayer aWhichLayer, PRUint32 aFlags = 0); - - // returns true if it is an Initial Reflow and doing Print Preview - static PRBool IsInitialReflowForPrintPreview(nsBoxLayoutState& aState, PRBool& aIsChrome); - nsIBox* GetBoxAt(PRInt32 aIndex) { return mFrames.FrameAt(aIndex); } PRInt32 GetChildCount() { return mFrames.GetLength(); } @@ -210,9 +206,6 @@ protected: virtual void GetBoxName(nsAutoString& aName); #endif - virtual PRBool HasStyleChange(); - virtual void SetStyleChangeFlag(PRBool aDirty); - virtual PRBool GetWasCollapsed(nsBoxLayoutState& aState); virtual void SetWasCollapsed(nsBoxLayoutState& aState, PRBool aWas); diff --git a/mozilla/layout/xul/base/src/nsBoxLayout.cpp b/mozilla/layout/xul/base/src/nsBoxLayout.cpp index 5176ad1556b..f9b2cbbeae2 100644 --- a/mozilla/layout/xul/base/src/nsBoxLayout.cpp +++ b/mozilla/layout/xul/base/src/nsBoxLayout.cpp @@ -200,13 +200,7 @@ nsBoxLayout::ChildrenSet(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildL } NS_IMETHODIMP -nsBoxLayout::ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsBoxLayout::BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState) +nsBoxLayout::IntrinsicWidthsDirty(nsIBox* aBox, nsBoxLayoutState& aState) { return NS_OK; } diff --git a/mozilla/layout/xul/base/src/nsBoxLayout.h b/mozilla/layout/xul/base/src/nsBoxLayout.h index 78e957e0799..327ea13182c 100644 --- a/mozilla/layout/xul/base/src/nsBoxLayout.h +++ b/mozilla/layout/xul/base/src/nsBoxLayout.h @@ -61,8 +61,7 @@ public: NS_IMETHOD ChildrenAppended(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList); NS_IMETHOD ChildrenRemoved(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList); NS_IMETHOD ChildrenSet(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList); - NS_IMETHOD ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild); - NS_IMETHOD BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState); + NS_IMETHOD IntrinsicWidthsDirty(nsIBox* aBox, nsBoxLayoutState& aState); virtual void GetParentLayout(nsIBox* aBox, nsIBoxLayout** aParent); virtual void AddBorderAndPadding(nsIBox* aBox, nsSize& aSize); diff --git a/mozilla/layout/xul/base/src/nsBoxLayoutState.cpp b/mozilla/layout/xul/base/src/nsBoxLayoutState.cpp index f347d5934bd..c123a019ee4 100644 --- a/mozilla/layout/xul/base/src/nsBoxLayoutState.cpp +++ b/mozilla/layout/xul/base/src/nsBoxLayoutState.cpp @@ -43,250 +43,22 @@ // #include "nsBoxLayoutState.h" -#include "nsReflowPath.h" -#include "nsBoxFrame.h" -#include "nsHTMLAtoms.h" -#include "nsXULAtoms.h" -#include "nsIContent.h" -#include "nsPresContext.h" -nsBoxLayoutState::nsBoxLayoutState(nsPresContext* aPresContext):mPresContext(aPresContext), - mReflowState(nsnull), - mType(Dirty), - mMaxElementWidth(nsnull), - mLayoutFlags(0), - mPaintingDisabled(PR_FALSE) +nsBoxLayoutState::nsBoxLayoutState(nsPresContext* aPresContext, + nsIRenderingContext* aRenderingContext) + : mPresContext(aPresContext) + , mRenderingContext(aRenderingContext) + , mLayoutFlags(0) + , mPaintingDisabled(PR_FALSE) { NS_ASSERTION(mPresContext, "PresContext must be non-null"); } nsBoxLayoutState::nsBoxLayoutState(const nsBoxLayoutState& aState) + : mPresContext(aState.mPresContext) + , mRenderingContext(aState.mRenderingContext) + , mLayoutFlags(aState.mLayoutFlags) + , mPaintingDisabled(aState.mPaintingDisabled) { - mPresContext = aState.mPresContext; - mType = aState.mType; - mReflowState = aState.mReflowState; - mMaxElementWidth = aState.mMaxElementWidth; - mLayoutFlags = aState.mLayoutFlags; - mPaintingDisabled = aState.mPaintingDisabled; - NS_ASSERTION(mPresContext, "PresContext must be non-null"); } - -nsBoxLayoutState::nsBoxLayoutState(nsIPresShell* aShell):mReflowState(nsnull), - mType(Dirty), - mMaxElementWidth(nsnull), - mLayoutFlags(0), - mPaintingDisabled(PR_FALSE) -{ - mPresContext = aShell->GetPresContext(); - NS_ASSERTION(mPresContext, "PresContext must be non-null"); -} - -nsBoxLayoutState::nsBoxLayoutState(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredSize):mPresContext(aPresContext), - mReflowState(&aReflowState), - mType(Dirty), - mMaxElementWidth(nsnull), - mLayoutFlags(0), - mPaintingDisabled(PR_FALSE) - - - -{ - if (aDesiredSize.mComputeMEW) - mMaxElementWidth = &aDesiredSize.mMaxElementWidth; - NS_ASSERTION(mPresContext, "PresContext must be non-null"); -} - -void -nsBoxLayoutState::HandleReflow(nsIBox* aRootBox) -{ - switch(mReflowState->reason) - { - case eReflowReason_Incremental: - { - // XXXwaterson according to evaughan's prior comment here, - // the target ought not to be a box frame. This makes some - // of the logic in `Unwind' confusing. - Unwind(mReflowState->path, aRootBox); - mType = Dirty; - break; - } - - case eReflowReason_Dirty: - mType = Dirty; - break; - - // if the a resize reflow then it doesn't need to be reflowed. Only if the size is different - // from the new size would we actually do a reflow - case eReflowReason_Resize: - mType = Resize; - break; - - // if its an initial reflow we must place the child. - // otherwise we might think it was already placed when it wasn't - case eReflowReason_Initial: - mType = Initial; - break; - - case eReflowReason_StyleChange: - // printf("STYLE CHANGE REFLOW. Blowing away all box caches!!\n"); - aRootBox->MarkChildrenStyleChange(); - // fall through to dirty - - default: - mType = Dirty; - } -} - - -void -nsBoxLayoutState::Unwind(nsReflowPath* aReflowPath, nsIBox* aRootBox) -{ - // If incremental, unwind the reflow path, updating dirty bits - // appropriately. We recursively descend through the reflow tree, - // clearing the NS_FRAME_HAS_DIRTY_CHILDREN bit on each frame until - // we reach a target frame. When we reach a target frame, we set the - // NS_FRAME_HAS_DIRTY_CHILDREN bit on the root box's frame, and then - // call the target box's MarkDirty method. This will reset the - // NS_FRAME_HAS_DIRTY_CHILDREN bit on each box on the path back to - // root, as well as initialize each box correctly for a dirty - // layout. - nsReflowPath::iterator iter = aReflowPath->FirstChild(); - nsReflowPath::iterator end = aReflowPath->EndChildren(); - - for ( ; iter != end; ++iter) { - // Get the box for the given frame. - PRBool isAdaptor = PR_FALSE; - nsIBox* ibox = GetBoxForFrame(*iter, isAdaptor); - if (! ibox) { - NS_ERROR("This should not happen! We should always get a box"); - continue; - } - - // Clear the dirty-children bit. This will be re-set by MarkDirty - // once we reach a target. - (*iter)->RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - - if (isAdaptor) { - // It's nested HTML. Mark the root box's frame with - // NS_FRAME_HAS_DIRTY_CHILDREN so MarkDirty won't walk off the - // top of the box hierarchy and schedule another reflow command. - aRootBox->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - - // Clear the frame's dirty bit so that MarkDirty doesn't - // optimize the layout away. - (*iter)->RemoveStateBits(NS_FRAME_IS_DIRTY); - - // Mark the adaptor dirty. - ibox->MarkDirty(*this); - - // We are done and we did not coelesce. - continue; - } - - // Is the box frame the target? - // XXXwaterson according to the evaughan's previous comments in - // HandleReflow, it ought to never be. Yet here we are. - nsHTMLReflowCommand *command = iter.get()->mReflowCommand; - if (command) { - // Mark the root box's frame with NS_FRAME_HAS_DIRTY_CHILDREN so - // that MarkDirty won't walk off the top of the box hierarchy - // and schedule another reflow command. - aRootBox->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - - // The target is a box. Mark it dirty, generating a new reflow - // command targeted at us and coelesce out this one. - nsReflowType type; - command->GetType(type); - - if (type == eReflowType_StyleChanged) { - ibox->MarkStyleChange(*this); - - // could be a visiblity change. Like collapse so we need to dirty - // parent so it gets redrawn. But be carefull we - // don't want to just mark dirty that would notify the - // box and it would notify its layout manager. This would - // be really bad for grid because it would blow away - // all is cached infomation for is colums and rows. Because the - // our parent is most likely a rows or columns and it will think - // its child is getting bigger or something. - nsIBox* parent; - ibox->GetParentBox(&parent); - if (parent) { - parent->AddStateBits(NS_FRAME_IS_DIRTY); - } - - } - else - ibox->MarkDirty(*this); - } - - // Recursively unwind the reflow path. - Unwind(iter.get(), aRootBox); - } -} - -nsIBox* -nsBoxLayoutState::GetBoxForFrame(nsIFrame* aFrame, PRBool& aIsAdaptor) -{ - if (aFrame && !aFrame->IsBoxFrame()) - aIsAdaptor = PR_TRUE; - - return aFrame; -} - -/* -void -nsBoxLayoutState::DirtyAllChildren(nsBoxLayoutState& aState, nsIBox* aBox) -{ - aBox->MarkDirty(aState); - - nsIBox* first = nsnull; - aBox->GetChildBox(&first); - if (first) - aBox->MarkDirtyChildren(aState); - - while(first) - { - DirtyAllChildren(aState, first); - first->GetNextBox(&first); - } -} -*/ - -void* -nsBoxLayoutState::Allocate(size_t sz, nsIPresShell* aPresShell) -{ - // Check the recycle list first. - void* result = aPresShell->AllocateFrame(sz); - - if (result) { - memset(result, 0, sz); - } - - return result; -} - -// Overridden to prevent the global delete from being called, since the memory -// came out of an nsIArena instead of the global delete operator's heap. -void -nsBoxLayoutState::Free(void* aPtr, size_t sz) -{ - // Don't let the memory be freed, since it will be recycled - // instead. Don't call the global operator delete. - - // Stash the size of the object in the first four bytes of the - // freed up memory. The Destroy method can then use this information - // to recycle the object. - size_t* szPtr = (size_t*)aPtr; - *szPtr = sz; -} - -void -nsBoxLayoutState::RecycleFreedMemory(nsIPresShell* aShell, void* aMem) -{ - size_t* sz = (size_t*)aMem; - aShell->FreeFrame(*sz, aMem); -} diff --git a/mozilla/layout/xul/base/src/nsBoxLayoutState.h b/mozilla/layout/xul/base/src/nsBoxLayoutState.h index 3da44d9c0de..818c97918c8 100644 --- a/mozilla/layout/xul/base/src/nsBoxLayoutState.h +++ b/mozilla/layout/xul/base/src/nsBoxLayoutState.h @@ -49,9 +49,8 @@ #include "nsCOMPtr.h" #include "nsPresContext.h" #include "nsIPresShell.h" -#include "nsHTMLReflowState.h" -class nsReflowState; +class nsIRenderingContext; class nsCalculatedBoxInfo; struct nsHTMLReflowMetrics; class nsString; @@ -60,24 +59,11 @@ class nsHTMLReflowCommand; class nsBoxLayoutState { public: - enum eBoxLayoutReason { - Dirty, - Resize, - Initial - }; - - nsBoxLayoutState(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredSize) NS_HIDDEN; - nsBoxLayoutState(nsPresContext* aPresContext) NS_HIDDEN; - nsBoxLayoutState(nsIPresShell* aShell) NS_HIDDEN; + nsBoxLayoutState(nsPresContext* aPresContext, nsIRenderingContext* aRenderingContext = nsnull) NS_HIDDEN; nsBoxLayoutState(const nsBoxLayoutState& aState) NS_HIDDEN; - NS_HIDDEN_(void) HandleReflow(nsIBox* aRootBox); - - nsPresContext* PresContext() { return mPresContext; } - nsIPresShell* PresShell() { return mPresContext->PresShell(); } - nscoord* GetMaxElementWidth() { return mReflowState ? mMaxElementWidth : nsnull; } + nsPresContext* PresContext() const { return mPresContext; } + nsIPresShell* PresShell() const { return mPresContext->PresShell(); } PRUint32 LayoutFlags() const { return mLayoutFlags; } void SetLayoutFlags(PRUint32 aFlags) { mLayoutFlags = aFlags; } @@ -86,14 +72,11 @@ public: void SetPaintingDisabled(PRBool aDisable) { mPaintingDisabled = aDisable; } PRBool PaintingDisabled() const { return mPaintingDisabled; } - eBoxLayoutReason LayoutReason() { return mType; } - void SetLayoutReason(eBoxLayoutReason aReason) { mType = aReason; } - const nsHTMLReflowState* GetReflowState() { return mReflowState; } - - static NS_HIDDEN_(void*) Allocate(size_t sz, nsIPresShell* aPresShell); - static NS_HIDDEN_(void) Free(void* aPtr, size_t sz); - static NS_HIDDEN_(void) RecycleFreedMemory(nsIPresShell* aPresShell, - void* mem); + // The rendering context may be null for specialized uses of + // nsBoxLayoutState and should be null-checked before it is used. + // However, passing a null rendering context to the constructor when + // doing box layout or intrinsic size calculation will cause bugs. + nsIRenderingContext* GetRenderingContext() const { return mRenderingContext; } nsresult PushStackMemory() { return PresShell()->PushStackMemory(); } nsresult PopStackMemory() { return PresShell()->PopStackMemory(); } @@ -101,14 +84,8 @@ public: { return PresShell()->AllocateStackMemory(aSize, aResult); } private: - //void DirtyAllChildren(nsBoxLayoutState& aState, nsIBox* aBox); - NS_HIDDEN_(void) Unwind(nsReflowPath* aReflowPath, nsIBox* aRootBox); - NS_HIDDEN_(nsIBox*) GetBoxForFrame(nsIFrame* aFrame, PRBool& aIsAdaptor); - nsCOMPtr mPresContext; - const nsHTMLReflowState* mReflowState; - nscoord* mMaxElementWidth; - eBoxLayoutReason mType; + nsIRenderingContext *mRenderingContext; PRUint32 mLayoutFlags; PRBool mPaintingDisabled; }; diff --git a/mozilla/layout/xul/base/src/nsIBoxLayout.h b/mozilla/layout/xul/base/src/nsIBoxLayout.h index ec611c28167..305e5e4c87e 100644 --- a/mozilla/layout/xul/base/src/nsIBoxLayout.h +++ b/mozilla/layout/xul/base/src/nsIBoxLayout.h @@ -69,8 +69,7 @@ public: NS_IMETHOD ChildrenAppended(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList)=0; NS_IMETHOD ChildrenRemoved(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList)=0; NS_IMETHOD ChildrenSet(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChildList)=0; - NS_IMETHOD ChildBecameDirty(nsIBox* aBox, nsBoxLayoutState& aState, nsIBox* aChild)=0; - NS_IMETHOD BecameDirty(nsIBox* aBox, nsBoxLayoutState& aState)=0; + NS_IMETHOD IntrinsicWidthsDirty(nsIBox* aBox, nsBoxLayoutState& aState)=0; }; #endif diff --git a/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp b/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp index effa6ff0484..1b01a0e6be6 100644 --- a/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsImageBoxFrame.cpp @@ -254,8 +254,9 @@ nsImageBoxFrame::AttributeChanged(PRInt32 aNameSpaceID, if (aAttribute == nsHTMLAtoms::src) { UpdateImage(); - nsBoxLayoutState state(GetPresContext()); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } else if (aAttribute == nsXULAtoms::validate) UpdateLoadFlags(); @@ -270,7 +271,7 @@ nsImageBoxFrame::nsImageBoxFrame(nsIPresShell* aShell) : mIntrinsicSize(0,0), mLoadFlags(nsIRequest::LOAD_NORMAL) { - NeedsRecalc(); + MarkIntrinsicWidthsDirty(); } nsImageBoxFrame::~nsImageBoxFrame() @@ -278,11 +279,10 @@ nsImageBoxFrame::~nsImageBoxFrame() } -NS_IMETHODIMP -nsImageBoxFrame::NeedsRecalc() +/* virtual */ void +nsImageBoxFrame::MarkIntrinsicWidthsDirty() { SizeNeedsRecalc(mImageSize); - return NS_OK; } NS_METHOD @@ -520,6 +520,7 @@ nsImageBoxFrame::GetImageSize() NS_IMETHODIMP nsImageBoxFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); if (DoesNeedRecalc(mImageSize)) { GetImageSize(); } @@ -545,6 +546,7 @@ nsImageBoxFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) NS_IMETHODIMP nsImageBoxFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); // An image can always scale down to (0,0). aSize.width = aSize.height = 0; AddBorderAndPadding(aSize); @@ -594,8 +596,9 @@ NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request, mIntrinsicSize.SizeTo(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t)); - nsBoxLayoutState state(presContext); - this->MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); return NS_OK; } @@ -619,8 +622,9 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request, else { // Fire an onerror DOM event. mIntrinsicSize.SizeTo(0, 0); - nsBoxLayoutState state(GetPresContext()); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); FireDOMEvent(mContent, NS_IMAGE_ERROR); } diff --git a/mozilla/layout/xul/base/src/nsImageBoxFrame.h b/mozilla/layout/xul/base/src/nsImageBoxFrame.h index 103b358f15e..ff90d4746dd 100644 --- a/mozilla/layout/xul/base/src/nsImageBoxFrame.h +++ b/mozilla/layout/xul/base/src/nsImageBoxFrame.h @@ -70,7 +70,7 @@ public: NS_IMETHOD GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); NS_IMETHOD GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); NS_IMETHOD GetAscent(nsBoxLayoutState& aBoxLayoutState, nscoord& aAscent); - NS_IMETHOD NeedsRecalc(); + virtual void MarkIntrinsicWidthsDirty(); friend nsresult NS_NewImageBoxFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame); diff --git a/mozilla/layout/xul/base/src/nsLeafBoxFrame.cpp b/mozilla/layout/xul/base/src/nsLeafBoxFrame.cpp index 99bb389d592..a3f3b01605c 100644 --- a/mozilla/layout/xul/base/src/nsLeafBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsLeafBoxFrame.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -197,24 +197,47 @@ nsLeafBoxFrame::GetFrameForPoint(const nsPoint& aPoint, return this; } -NS_IMETHODIMP -nsLeafBoxFrame::DidReflow(nsPresContext* aPresContext, - const nsHTMLReflowState* aReflowState, - nsDidReflowStatus aStatus) +/* virtual */ nscoord +nsLeafBoxFrame::GetMinWidth(nsIRenderingContext *aRenderingContext) { - PRBool isDirty = mState & NS_FRAME_IS_DIRTY; - PRBool hasDirtyChildren = mState & NS_FRAME_HAS_DIRTY_CHILDREN; - nsresult rv = nsFrame::DidReflow(aPresContext, aReflowState, aStatus); - if (isDirty) - mState |= NS_FRAME_IS_DIRTY; + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + nsBoxLayoutState state(GetPresContext(), aRenderingContext); + nsSize minSize(0,0); + GetMinSize(state, minSize); - if (hasDirtyChildren) - mState |= NS_FRAME_HAS_DIRTY_CHILDREN; + // GetMinSize returns border-box width, and we want to return content + // width. Since Reflow uses the reflow state's border and padding, we + // actually just want to subtract what GetMinSize added, which is the + // result of GetBorderAndPadding. + nsMargin bp; + GetBorderAndPadding(bp); - return rv; + result = minSize.width - bp.LeftRight(); + return result; } +/* virtual */ nscoord +nsLeafBoxFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + nsBoxLayoutState state(GetPresContext(), aRenderingContext); + nsSize prefSize(0,0); + GetPrefSize(state, prefSize); + + // GetPrefSize returns border-box width, and we want to return content + // width. Since Reflow uses the reflow state's border and padding, we + // actually just want to subtract what GetPrefSize added, which is the + // result of GetBorderAndPadding. + nsMargin bp; + GetBorderAndPadding(bp); + + result = prefSize.width - bp.LeftRight(); + + return result; +} NS_IMETHODIMP nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, @@ -227,7 +250,7 @@ nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, // class hierarchy. If you make changes here, please keep // nsBoxFrame::Reflow in sync. - DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_ASSERTION(aReflowState.mComputedWidth >=0 && aReflowState.mComputedHeight >= 0, "Computed Size < 0"); @@ -262,11 +285,8 @@ nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; // create the layout state - nsBoxLayoutState state(aPresContext, aReflowState, aDesiredSize); + nsBoxLayoutState state(aPresContext, aReflowState.rendContext); - // coelesce reflows if we are root. - state.HandleReflow(this); - nsSize computedSize(aReflowState.mComputedWidth,aReflowState.mComputedHeight); nsMargin m; @@ -331,16 +351,7 @@ nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, // get the ascent nscoord ascent = mRect.height; - - // Only call GetAscent when not doing Initial reflow while in PP - // or when it is Initial reflow while in PP and a chrome doc - // If called again with initial reflow it crashes because the - // frames are fully constructed (I think). - PRBool isChrome; - PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(state, isChrome); - if (!isInitialPP || (isInitialPP && isChrome)) { - GetAscent(state, ascent); - } + GetAscent(state, ascent); aDesiredSize.width = mRect.width; aDesiredSize.height = mRect.height; @@ -354,24 +365,6 @@ nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, aDesiredSize.mOverflowArea = *overflowArea; } - // max sure the max element size reflects - // our min width - nscoord* maxElementWidth = state.GetMaxElementWidth(); - if (maxElementWidth) - { - nsSize minSize(0,0); - GetMinSize(state, minSize); - - if (mRect.width > minSize.width) { - if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) { - *maxElementWidth = minSize.width; - } else { - *maxElementWidth = mRect.width; - } - } else { - *maxElementWidth = mRect.width; - } - } #ifdef DO_NOISY_REFLOW { printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.width, aDesiredSize.height); @@ -413,7 +406,7 @@ nsLeafBoxFrame::CharacterDataChanged(nsPresContext* aPresContext, nsIContent* aChild, PRBool aAppend) { - NeedsRecalc(); + MarkIntrinsicWidthsDirty(); return nsLeafFrame::CharacterDataChanged(aPresContext, aChild, aAppend); } @@ -447,10 +440,10 @@ nsLeafBoxFrame::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent) return nsBox::GetAscent(aState, aAscent); } -NS_IMETHODIMP -nsLeafBoxFrame::NeedsRecalc() +/* virtual */ void +nsLeafBoxFrame::MarkIntrinsicWidthsDirty() { - return nsBox::NeedsRecalc(); + return; } NS_IMETHODIMP @@ -459,18 +452,6 @@ nsLeafBoxFrame::DoLayout(nsBoxLayoutState& aState) return nsBox::DoLayout(aState); } -PRBool -nsLeafBoxFrame::HasStyleChange() -{ - return nsBox::HasStyleChange(); -} - -void -nsLeafBoxFrame::SetStyleChangeFlag(PRBool aDirty) -{ - nsBox::SetStyleChangeFlag(aDirty); -} - PRBool nsLeafBoxFrame::GetWasCollapsed(nsBoxLayoutState& aState) { diff --git a/mozilla/layout/xul/base/src/nsLeafBoxFrame.h b/mozilla/layout/xul/base/src/nsLeafBoxFrame.h index 6f3be8a8b31..2cbda582db4 100644 --- a/mozilla/layout/xul/base/src/nsLeafBoxFrame.h +++ b/mozilla/layout/xul/base/src/nsLeafBoxFrame.h @@ -56,13 +56,17 @@ public: NS_IMETHOD GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize); NS_IMETHOD GetFlex(nsBoxLayoutState& aState, nscoord& aFlex); NS_IMETHOD GetAscent(nsBoxLayoutState& aState, nscoord& aAscent); - NS_IMETHOD NeedsRecalc(); #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif // nsIHTMLReflow overrides + + virtual void MarkIntrinsicWidthsDirty(); + virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext); + virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext); + NS_IMETHOD Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, @@ -72,10 +76,6 @@ public: nsIContent* aChild, PRBool aAppend); - NS_IMETHOD DidReflow(nsPresContext* aPresContext, - const nsHTMLReflowState* aReflowState, - nsDidReflowStatus aStatus); - NS_IMETHOD Init(nsPresContext* aPresContext, nsIContent* aContent, nsIFrame* aParent, @@ -94,9 +94,6 @@ public: protected: - virtual PRBool HasStyleChange(); - virtual void SetStyleChangeFlag(PRBool aDirty); - virtual PRBool GetWasCollapsed(nsBoxLayoutState& aState); virtual void SetWasCollapsed(nsBoxLayoutState& aState, PRBool aWas); diff --git a/mozilla/layout/xul/base/src/nsListBoxBodyFrame.cpp b/mozilla/layout/xul/base/src/nsListBoxBodyFrame.cpp index 73bf2fd0bbf..d94c839282d 100644 --- a/mozilla/layout/xul/base/src/nsListBoxBodyFrame.cpp +++ b/mozilla/layout/xul/base/src/nsListBoxBodyFrame.cpp @@ -319,8 +319,9 @@ nsListBoxBodyFrame::AttributeChanged(PRInt32 aNameSpaceID, value.AppendInt(rowHeight*count); mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::minheight, value, PR_FALSE); - nsBoxLayoutState state(presContext); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } } else @@ -332,11 +333,10 @@ nsListBoxBodyFrame::AttributeChanged(PRInt32 aNameSpaceID, /////////// nsIBox /////////////// -NS_IMETHODIMP -nsListBoxBodyFrame::NeedsRecalc() +/* virtual */ void +nsListBoxBodyFrame::MarkIntrinsicWidthsDirty() { mStringWidth = -1; - return nsBoxFrame::NeedsRecalc(); } /////////// nsBox /////////////// @@ -506,8 +506,9 @@ nsListBoxBodyFrame::ReflowFinished(nsIPresShell* aPresShell, PRBool* aFlushFlag) // if the row height changed then mark everything as a style change. // That will dirty the entire listbox if (mRowHeightWasSet) { - nsBoxLayoutState state(mPresContext); - MarkStyleChange(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); PRInt32 pos = mCurrentIndex * mRowHeight; if (mYPosition != pos) mAdjustScroll = PR_TRUE; @@ -789,8 +790,7 @@ nsListBoxBodyFrame::ComputeIntrinsicWidth(nsBoxLayoutState& aBoxLayoutState) nsIContent *child = listbox->GetChildAt(i); if (child->Tag() == nsXULAtoms::listitem) { - nsPresContext* presContext = aBoxLayoutState.PresContext(); - nsIRenderingContext* rendContext = aBoxLayoutState.GetReflowState()->rendContext; + nsIRenderingContext* rendContext = aBoxLayoutState.GetRenderingContext(); if (rendContext) { nsAutoString value; PRUint32 textCount = child->GetChildCount(); @@ -940,7 +940,9 @@ nsListBoxBodyFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta) mYPosition = mCurrentIndex*mRowHeight; mScrolling = PR_TRUE; - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eResize); // Flush calls CreateRows // XXXbz there has to be a better way to do this than flushing! mPresContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow); @@ -1068,7 +1070,9 @@ nsListBoxBodyFrame::DestroyRows(PRInt32& aRowsToLose) mTopFrame = childFrame = nextFrame; } - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } void @@ -1089,7 +1093,9 @@ nsListBoxBodyFrame::ReverseDestroyRows(PRInt32& aRowsToLose) mBottomFrame = childFrame = prevFrame; } - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } // @@ -1233,7 +1239,9 @@ nsListBoxBodyFrame::ContinueReflow(nscoord height) currFrame = nextFrame; } - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } return PR_FALSE; } @@ -1249,7 +1257,9 @@ nsListBoxBodyFrame::ListBoxAppendFrames(nsIFrame* aFrameList) mFrames.AppendFrames(nsnull, aFrameList); if (mLayoutManager) mLayoutManager->ChildrenAppended(this, state, aFrameList); - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return NS_OK; } @@ -1262,7 +1272,9 @@ nsListBoxBodyFrame::ListBoxInsertFrames(nsIFrame* aPrevFrame, nsIFrame* aFrameLi mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList); if (mLayoutManager) mLayoutManager->ChildrenInserted(this, state, aPrevFrame, aFrameList); - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); return NS_OK; } @@ -1302,8 +1314,9 @@ nsListBoxBodyFrame::OnContentInserted(nsPresContext* aPresContext, nsIContent* a } CreateRows(); - nsBoxLayoutState state(aPresContext); - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } // @@ -1370,7 +1383,9 @@ nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext, nsIFrame* aChi RemoveChildFrame(state, aChildFrame); } - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); } void diff --git a/mozilla/layout/xul/base/src/nsListBoxBodyFrame.h b/mozilla/layout/xul/base/src/nsListBoxBodyFrame.h index eda80c1f22e..b1a3b6b9be3 100644 --- a/mozilla/layout/xul/base/src/nsListBoxBodyFrame.h +++ b/mozilla/layout/xul/base/src/nsListBoxBodyFrame.h @@ -89,7 +89,7 @@ public: // nsIBox NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState); - NS_IMETHOD NeedsRecalc(); + virtual void MarkIntrinsicWidthsDirty(); virtual nsSize GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState); NS_IMETHOD GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); diff --git a/mozilla/layout/xul/base/src/nsListBoxLayout.cpp b/mozilla/layout/xul/base/src/nsListBoxLayout.cpp index 5bc7f8e8eb5..49554c475a9 100644 --- a/mozilla/layout/xul/base/src/nsListBoxLayout.cpp +++ b/mozilla/layout/xul/base/src/nsListBoxLayout.cpp @@ -196,23 +196,18 @@ nsListBoxLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState) body->GetChildBox(&box); // if the reason is resize or initial we must relayout. - PRBool relayout = (aState.LayoutReason() == nsBoxLayoutState::Resize || aState.LayoutReason() == nsBoxLayoutState::Initial); nscoord rowHeight = body->GetRowHeightTwips(); while (box) { // If this box is dirty or if it has dirty children, we // call layout on it. - PRBool dirty = PR_FALSE; - PRBool dirtyChildren = PR_FALSE; - box->IsDirty(dirty); - box->HasDirtyChildren(dirtyChildren); - nsRect childRect(box->GetRect()); box->GetMargin(margin); // relayout if we must or we are dirty or some of our children are dirty // or the client area is wider than us - if (relayout || dirty || dirtyChildren || childRect.width < clientRect.width) { + // XXXldb There should probably be a resize check here too! + if ((box->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) || childRect.width < clientRect.width) { childRect.x = 0; childRect.y = yOffset; childRect.width = clientRect.width; diff --git a/mozilla/layout/xul/base/src/nsListItemFrame.cpp b/mozilla/layout/xul/base/src/nsListItemFrame.cpp index 735c56affd2..beaca51e33b 100644 --- a/mozilla/layout/xul/base/src/nsListItemFrame.cpp +++ b/mozilla/layout/xul/base/src/nsListItemFrame.cpp @@ -70,6 +70,7 @@ nsListItemFrame::~nsListItemFrame() nsresult nsListItemFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); nsresult rv = nsBoxFrame::GetPrefSize(aState, aSize); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/layout/xul/base/src/nsMenuFrame.cpp b/mozilla/layout/xul/base/src/nsMenuFrame.cpp index c587f48be3d..f2d024a4ae6 100644 --- a/mozilla/layout/xul/base/src/nsMenuFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuFrame.cpp @@ -303,12 +303,9 @@ nsMenuFrame::SetInitialChildList(nsPresContext* aPresContext, nsIAtom* nsMenuFrame::GetAdditionalChildListName(PRInt32 aIndex) const { - // don't expose the child frame list, it slows things down -#if 0 if (NS_MENU_POPUP_LIST_INDEX == aIndex) { return nsLayoutAtoms::popupList; } -#endif return nsnull; } @@ -811,17 +808,17 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag) popupAlign.AssignLiteral("topleft"); } - nsBoxLayoutState state(mPresContext); - // if height never set we need to do an initial reflow. if (mLastPref.height == -1) { - menuPopup->MarkDirty(state); - + menuPopup->AddStateBits(NS_FRAME_IS_DIRTY); + mPresContext->PresShell()-> + FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange); mPresContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow); } nsRect curRect(menuPopup->GetRect()); + nsBoxLayoutState state(mPresContext); menuPopup->SetBounds(state, nsRect(0,0,mLastPref.width, mLastPref.height)); nsIView* view = menuPopup->GetView(); @@ -835,7 +832,9 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag) // if the height is different then reflow. It might need scrollbars force a reflow if (curRect.height != newHeight || mLastPref.height != newHeight) { - menuPopup->MarkDirty(state); + menuPopup->AddStateBits(NS_FRAME_IS_DIRTY); + mPresContext->PresShell()-> + FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange); mPresContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow); } @@ -962,6 +961,7 @@ nsMenuFrame::IsSizedToPopup(nsIContent* aContent, PRBool aRequireAlways) NS_IMETHODIMP nsMenuFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); nsresult rv = nsBoxFrame::GetMinSize(aBoxLayoutState, aSize); if (IsSizedToPopup(mContent, PR_TRUE)) @@ -1049,23 +1049,6 @@ nsMenuFrame::DoLayout(nsBoxLayoutState& aState) return rv; } -NS_IMETHODIMP -nsMenuFrame::MarkChildrenStyleChange() -{ - nsresult rv = nsBoxFrame::MarkChildrenStyleChange(); - if (NS_FAILED(rv)) - return rv; - - nsIFrame* popupChild = mPopupFrames.FirstChild(); - - if (popupChild) { - NS_ASSERTION(popupChild->IsBoxFrame(), "popupChild is not box!!"); - return popupChild->MarkChildrenStyleChange(); - } - - return rv; -} - #ifdef DEBUG_LAYOUT NS_IMETHODIMP nsMenuFrame::SetDebug(nsBoxLayoutState& aState, PRBool aDebug) @@ -1844,8 +1827,9 @@ nsMenuFrame::RemoveFrame(nsIAtom* aListName, // Go ahead and remove this frame. nsPresContext* presContext = GetPresContext(); mPopupFrames.DestroyFrame(presContext, aOldFrame); - nsBoxLayoutState state(presContext); - rv = MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + presContext->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange); + rv = NS_OK; } else { rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame); } @@ -1865,11 +1849,14 @@ nsMenuFrame::InsertFrames(nsIAtom* aListName, NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!"); mPopupFrames.InsertFrames(nsnull, nsnull, aFrameList); - nsBoxLayoutState state(GetPresContext()); #ifdef DEBUG_LAYOUT + nsBoxLayoutState state(GetPresContext()); SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG); #endif - rv = MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); + rv = NS_OK; } else { rv = nsBoxFrame::InsertFrames(aListName, aPrevFrame, aFrameList); } @@ -1891,11 +1878,14 @@ nsMenuFrame::AppendFrames(nsIAtom* aListName, NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!"); mPopupFrames.AppendFrames(nsnull, aFrameList); - nsBoxLayoutState state(GetPresContext()); #ifdef DEBUG_LAYOUT + nsBoxLayoutState state(GetPresContext()); SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG); #endif - rv = MarkDirtyChildren(state); + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); + rv = NS_OK; } else { rv = nsBoxFrame::AppendFrames(aListName, aFrameList); } @@ -1951,6 +1941,7 @@ nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize) NS_IMETHODIMP nsMenuFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); nsresult rv = nsBoxFrame::GetPrefSize(aState, aSize); // If we are using sizetopopup="always" then diff --git a/mozilla/layout/xul/base/src/nsMenuFrame.h b/mozilla/layout/xul/base/src/nsMenuFrame.h index c779d04e77e..9cfd08c3730 100644 --- a/mozilla/layout/xul/base/src/nsMenuFrame.h +++ b/mozilla/layout/xul/base/src/nsMenuFrame.h @@ -153,7 +153,6 @@ public: virtual nsIFrame *GetMenuChild() { return mPopupFrames.FirstChild(); } NS_IMETHOD GetRadioGroupName(nsString &aName) { aName = mGroupName; return NS_OK; }; NS_IMETHOD GetMenuType(nsMenuType &aType) { aType = mType; return NS_OK; }; - NS_IMETHOD MarkChildrenStyleChange(); NS_IMETHOD MarkAsGenerated(); // nsIScrollableViewProvider methods diff --git a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp index 2f259b8c7aa..5f549e590ff 100644 --- a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -234,138 +234,6 @@ nsMenuPopupFrame::Init(nsPresContext* aPresContext, return rv; } -NS_IMETHODIMP -nsMenuPopupFrame::MarkStyleChange(nsBoxLayoutState& aState) -{ - NeedsRecalc(); - - if (HasStyleChange()) - return NS_OK; - - // iterate through all children making them dirty - MarkChildrenStyleChange(); - - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->BecameDirty(this, aState); - - nsIFrame* parent = GetParent(); - nsIMenuFrame* menuFrame; - CallQueryInterface(parent, &menuFrame); - - if (menuFrame) - return parent->RelayoutDirtyChild(aState, this); - else { - nsIPopupSetFrame* popupSet = GetPopupSetFrame(mPresContext); - NS_ASSERTION(popupSet, "popup frame created without a popup set or menu"); - if (popupSet) { - nsIFrame *frame; - CallQueryInterface(popupSet, &frame); - if (frame->IsBoxFrame()) { - nsBoxLayoutState state(mPresContext); - frame->MarkDirtyChildren(state); // Mark the popupset as dirty. - } - else { - return frame->GetParent()->ReflowDirtyChild(aState.PresShell(), frame); - } - } - } - return NS_OK; -} - -NS_IMETHODIMP -nsMenuPopupFrame::MarkDirty(nsBoxLayoutState& aState) -{ - NeedsRecalc(); - - // only reflow if we aren't already dirty. - if (GetStateBits() & NS_FRAME_IS_DIRTY) { -#ifdef DEBUG_COELESCED - Coelesced(); -#endif - return NS_OK; - } - - AddStateBits(NS_FRAME_IS_DIRTY); - - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->BecameDirty(this, aState); - - if (GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) { -#ifdef DEBUG_COELESCED - Coelesced(); -#endif - return NS_OK; - } - - nsIFrame* parent = GetParent(); - nsIMenuFrame* menuFrame; - CallQueryInterface(parent, &menuFrame); - - if (menuFrame) - return parent->RelayoutDirtyChild(aState, this); - else { - nsIPopupSetFrame* popupSet = GetPopupSetFrame(mPresContext); - NS_ASSERTION(popupSet, "popup frame created without a popup set or menu"); - if (popupSet) { - nsIFrame *frame; - CallQueryInterface(popupSet, &frame); - if (frame->IsBoxFrame()) { - nsBoxLayoutState state(mPresContext); - frame->MarkDirtyChildren(state); // Mark the popupset as dirty. - } - else { - return frame->GetParent()->ReflowDirtyChild(aState.PresShell(), frame); - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsMenuPopupFrame::RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild) -{ - if (aChild != nsnull) { - nsCOMPtr layout; - GetLayoutManager(getter_AddRefs(layout)); - if (layout) - layout->ChildBecameDirty(this, aState, aChild); - } - - // if we are not dirty mark ourselves dirty and tell our parent we are dirty too. - if (!(GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) { - // Mark yourself as dirty and needing to be recalculated - AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); - NeedsRecalc(); - - nsIFrame* parent = GetParent(); - nsIMenuFrame* menuFrame; - CallQueryInterface(parent, &menuFrame); - - if (menuFrame) - return parent->RelayoutDirtyChild(aState, this); - else { - nsIPopupSetFrame* popupSet = GetPopupSetFrame(mPresContext); - NS_ASSERTION(popupSet, "popup frame created without a popup set or menu"); - nsIFrame *frame = nsnull; - if (popupSet) - CallQueryInterface(popupSet, &frame); - if (frame && frame->IsBoxFrame()) { - nsBoxLayoutState state(mPresContext); - frame->MarkDirtyChildren(state); // Mark the popupset as dirty. - } - else - return nsBox::RelayoutDirtyChild(aState, aChild); - } - } - - return NS_OK; -} - void nsMenuPopupFrame::GetLayoutFlags(PRUint32& aFlags) { diff --git a/mozilla/layout/xul/base/src/nsMenuPopupFrame.h b/mozilla/layout/xul/base/src/nsMenuPopupFrame.h index ba530dd62b2..cc53fc78dc7 100644 --- a/mozilla/layout/xul/base/src/nsMenuPopupFrame.h +++ b/mozilla/layout/xul/base/src/nsMenuPopupFrame.h @@ -136,10 +136,6 @@ public: virtual nsIFrame* GetFrameForPoint(const nsPoint& aPoint, nsFramePaintLayer aWhichLayer); - NS_IMETHOD MarkStyleChange(nsBoxLayoutState& aState); - NS_IMETHOD MarkDirty(nsBoxLayoutState& aState); - NS_IMETHOD RelayoutDirtyChild(nsBoxLayoutState& aState, nsIBox* aChild); - void GetViewOffset(nsIView* aView, nsPoint& aPoint); static void GetRootViewForPopup(nsIFrame* aStartFrame, PRBool aStopAtViewManagerRoot, diff --git a/mozilla/layout/xul/base/src/nsNativeScrollbarFrame.cpp b/mozilla/layout/xul/base/src/nsNativeScrollbarFrame.cpp index 1e19d98b3f2..e037fc22323 100644 --- a/mozilla/layout/xul/base/src/nsNativeScrollbarFrame.cpp +++ b/mozilla/layout/xul/base/src/nsNativeScrollbarFrame.cpp @@ -270,6 +270,7 @@ nsNativeScrollbarFrame::AttributeChanged(PRInt32 aNameSpaceID, NS_IMETHODIMP nsNativeScrollbarFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); float p2t = 0.0; p2t = aState.PresContext()->PixelsToTwips(); diff --git a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp index 0df97cdc27c..6eee96789bf 100644 --- a/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp +++ b/mozilla/layout/xul/base/src/nsPopupSetFrame.cpp @@ -531,8 +531,8 @@ nsPopupSetFrame::OpenPopup(nsPopupFrameList* aEntry, PRBool aActivateFlag) OnDestroyed(aEntry->mPopupContent); } - nsBoxLayoutState state(mPresContext); - MarkDirtyChildren(state); // Mark ourselves dirty. + AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); + mPresContext->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange); } void diff --git a/mozilla/layout/xul/base/src/nsProgressMeterFrame.cpp b/mozilla/layout/xul/base/src/nsProgressMeterFrame.cpp index 87ee03cf2d9..28c51099d37 100644 --- a/mozilla/layout/xul/base/src/nsProgressMeterFrame.cpp +++ b/mozilla/layout/xul/base/src/nsProgressMeterFrame.cpp @@ -136,8 +136,10 @@ nsProgressMeterFrame::AttributeChanged(PRInt32 aNameSpaceID, barChild->GetContent()->SetAttr(kNameSpaceID_None, nsXULAtoms::flex, leftFlex, PR_TRUE); remainderChild->GetContent()->SetAttr(kNameSpaceID_None, nsXULAtoms::flex, rightFlex, PR_TRUE); - nsBoxLayoutState state(GetPresContext()); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eTreeChange); + } return NS_OK; } diff --git a/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp b/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp index 39462773471..c8206e55627 100644 --- a/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsRootBoxFrame.cpp @@ -107,7 +107,7 @@ public: virtual nsIAtom* GetType() const; #ifdef DEBUG - NS_IMETHOD GetFrameName(nsString& aResult) const; + NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif nsIFrame* mPopupSetFrame; @@ -216,7 +216,7 @@ nsRootBoxFrame::Reflow(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { - DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame", aReflowState.reason); + DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame"); #ifdef DEBUG_REFLOW gReflows++; @@ -340,7 +340,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame) #ifdef DEBUG NS_IMETHODIMP -nsRootBoxFrame::GetFrameName(nsString& aResult) const +nsRootBoxFrame::GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult); } diff --git a/mozilla/layout/xul/base/src/nsSliderFrame.cpp b/mozilla/layout/xul/base/src/nsSliderFrame.cpp index 59457f5e810..0564826582b 100644 --- a/mozilla/layout/xul/base/src/nsSliderFrame.cpp +++ b/mozilla/layout/xul/base/src/nsSliderFrame.cpp @@ -54,7 +54,6 @@ #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" #include "nsIPresShell.h" -#include "nsStyleChangeList.h" #include "nsCSSRendering.h" #include "nsHTMLAtoms.h" #include "nsIDOMEventReceiver.h" @@ -271,8 +270,9 @@ nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID, aAttribute == nsXULAtoms::pageincrement || aAttribute == nsXULAtoms::increment) { - nsBoxLayoutState state(GetPresContext()); - MarkDirtyChildren(state); + AddStateBits(NS_FRAME_IS_DIRTY); + GetPresContext()->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } return rv; diff --git a/mozilla/layout/xul/base/src/nsSplitterFrame.cpp b/mozilla/layout/xul/base/src/nsSplitterFrame.cpp index d0ca7e77042..a9da1b3a513 100644 --- a/mozilla/layout/xul/base/src/nsSplitterFrame.cpp +++ b/mozilla/layout/xul/base/src/nsSplitterFrame.cpp @@ -598,11 +598,8 @@ nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext, nsGUIEvent* aEvent) /* nsIPresShell *shell = aPresContext->PresShell(); - shell->AppendReflowCommand(mOuter->mParent, eReflowType_StyleChanged, - nsnull); - mOuter->mState |= NS_FRAME_IS_DIRTY; - mOuter->mParent->ReflowDirtyChild(shell, mOuter); + shell->FrameNeedsReflow(mOuter, nsIPresShell::eStyleChange); */ mDidDrag = PR_TRUE; } @@ -998,8 +995,9 @@ nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext) aPresContext->PresShell()->FlushPendingNotifications(Flush_Display); } else { - nsBoxLayoutState state(aPresContext); - mOuter->MarkDirty(state); + mOuter->AddStateBits(NS_FRAME_IS_DIRTY); + aPresContext->PresShell()-> + FrameNeedsReflow(mOuter, nsIPresShell::eTreeChange); } } @@ -1096,7 +1094,8 @@ nsSplitterFrameInner::SetPreferredSize(nsBoxLayoutState& aState, nsIBox* aChildB return; content->SetAttr(kNameSpaceID_None, attribute, prefValue, PR_TRUE); - aChildBox->MarkDirty(aState); + aChildBox->AddStateBits(NS_FRAME_IS_DIRTY); + aState.PresShell()->FrameNeedsReflow(aChildBox, nsIPresShell::eStyleChange); } diff --git a/mozilla/layout/xul/base/src/nsSprocketLayout.cpp b/mozilla/layout/xul/base/src/nsSprocketLayout.cpp index 3f96fd697c4..5417b238693 100644 --- a/mozilla/layout/xul/base/src/nsSprocketLayout.cpp +++ b/mozilla/layout/xul/base/src/nsSprocketLayout.cpp @@ -492,11 +492,7 @@ nsSprocketLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState) layout = PR_FALSE; } else { // Always perform layout if we are dirty or have dirty children - PRBool dirty = PR_FALSE; - PRBool dirtyChildren = PR_FALSE; - child->IsDirty(dirty); - child->HasDirtyChildren(dirtyChildren); - if (!(dirty || dirtyChildren) && aState.LayoutReason() != nsBoxLayoutState::Initial) + if (!(child->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) layout = PR_FALSE; } diff --git a/mozilla/layout/xul/base/src/nsStackFrame.cpp b/mozilla/layout/xul/base/src/nsStackFrame.cpp index 2343ee9ab21..4b9926bcdc7 100644 --- a/mozilla/layout/xul/base/src/nsStackFrame.cpp +++ b/mozilla/layout/xul/base/src/nsStackFrame.cpp @@ -52,7 +52,6 @@ #include "nsHTMLAtoms.h" #include "nsHTMLParts.h" #include "nsIPresShell.h" -#include "nsStyleChangeList.h" #include "nsCSSRendering.h" #include "nsIViewManager.h" #include "nsBoxLayoutState.h" diff --git a/mozilla/layout/xul/base/src/nsStackLayout.cpp b/mozilla/layout/xul/base/src/nsStackLayout.cpp index 8fcb9f2dbf2..399243a386a 100644 --- a/mozilla/layout/xul/base/src/nsStackLayout.cpp +++ b/mozilla/layout/xul/base/src/nsStackLayout.cpp @@ -280,13 +280,7 @@ nsStackLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState) PRBool sizeChanged = (oldRect != childRect); // only lay out dirty children or children whose sizes have changed - PRBool isDirty = PR_FALSE; - PRBool hasDirtyChildren = PR_FALSE; - - child->IsDirty(isDirty); - child->HasDirtyChildren(hasDirtyChildren); - - if (sizeChanged || isDirty || hasDirtyChildren) { + if (sizeChanged || (child->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { // add in the child's margin nsMargin margin; child->GetMargin(margin); diff --git a/mozilla/layout/xul/base/src/nsTextBoxFrame.cpp b/mozilla/layout/xul/base/src/nsTextBoxFrame.cpp index b2947392d8c..e135f8ecdda 100644 --- a/mozilla/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTextBoxFrame.cpp @@ -134,8 +134,9 @@ nsTextBoxFrame::AttributeChanged(PRInt32 aNameSpaceID, UpdateAttributes(presContext, aAttribute, aResize, aRedraw); if (aResize) { - nsBoxLayoutState state(presContext); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + presContext->PresShell()-> + FrameNeedsReflow(this, nsIPresShell::eStyleChange); } else if (aRedraw) { nsBoxLayoutState state(presContext); Redraw(state); @@ -152,7 +153,7 @@ nsTextBoxFrame::AttributeChanged(PRInt32 aNameSpaceID, nsTextBoxFrame::nsTextBoxFrame(nsIPresShell* aShell):nsLeafBoxFrame(aShell), mCropType(CropRight),mAccessKeyInfo(nsnull) { mState |= NS_STATE_NEED_LAYOUT; - NeedsRecalc(); + MarkIntrinsicWidthsDirty(); } nsTextBoxFrame::~nsTextBoxFrame() @@ -804,11 +805,10 @@ nsTextBoxFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState) return nsLeafBoxFrame::DoLayout(aBoxLayoutState); } -NS_IMETHODIMP -nsTextBoxFrame::NeedsRecalc() +/* virtual */ void +nsTextBoxFrame::MarkIntrinsicWidthsDirty() { mNeedsRecalc = PR_TRUE; - return NS_OK; } void @@ -831,12 +831,7 @@ nsTextBoxFrame::CalcTextSize(nsBoxLayoutState& aBoxLayoutState) { nsSize size; nsPresContext* presContext = aBoxLayoutState.PresContext(); - const nsHTMLReflowState* rstate = aBoxLayoutState.GetReflowState(); - if (!rstate) - return; - - nsIRenderingContext* rendContext = rstate->rendContext; - + nsIRenderingContext* rendContext = aBoxLayoutState.GetRenderingContext(); if (rendContext) { GetTextSize(presContext, *rendContext, mTitle, size, mAscent); @@ -852,6 +847,7 @@ nsTextBoxFrame::CalcTextSize(nsBoxLayoutState& aBoxLayoutState) NS_IMETHODIMP nsTextBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_PREF_SIZE(this, aSize); CalcTextSize(aBoxLayoutState); aSize = mTextSize; @@ -869,6 +865,7 @@ nsTextBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) NS_IMETHODIMP nsTextBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize) { + DISPLAY_MIN_SIZE(this, aSize); CalcTextSize(aBoxLayoutState); aSize = mTextSize; diff --git a/mozilla/layout/xul/base/src/nsTextBoxFrame.h b/mozilla/layout/xul/base/src/nsTextBoxFrame.h index 58448849cc5..776f7234a00 100644 --- a/mozilla/layout/xul/base/src/nsTextBoxFrame.h +++ b/mozilla/layout/xul/base/src/nsTextBoxFrame.h @@ -52,7 +52,7 @@ public: NS_IMETHOD GetMinSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize); NS_IMETHOD GetAscent(nsBoxLayoutState& aBoxLayoutState, nscoord& aAscent); NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState); - NS_IMETHOD NeedsRecalc(); + virtual void MarkIntrinsicWidthsDirty(); enum CroppingStyle { CropNone, CropLeft, CropRight, CropCenter }; diff --git a/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp b/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp index 50957c1d216..7013eeb9d21 100644 --- a/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp +++ b/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp @@ -1476,8 +1476,8 @@ nsTreeBodyFrame::MarkDirtyIfSelect() // XXX optimize this more mStringWidth = -1; - nsBoxLayoutState state(mPresContext); - MarkDirty(state); + AddStateBits(NS_FRAME_IS_DIRTY); + mPresContext->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange); } } @@ -2235,9 +2235,9 @@ nsTreeBodyFrame::Paint(nsPresContext* aPresContext, mPageLength = mInnerBox.height/mRowHeight; if (oldPageCount != mPageLength || mHorzWidth != CalcHorzWidth()) { - // Schedule a ResizeReflow that will update our info properly. - nsBoxLayoutState state(mPresContext); - MarkDirty(state); + // Schedule a ResizeReflow that will update our page count properly. + AddStateBits(NS_FRAME_IS_DIRTY); + aPresContext->PresShell()->FrameNeedsReflow(this, nsIPresShell::eResize); } #ifdef DEBUG