gfx3DMatrix nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame* aAncestor, nsIFrame **aOutAncestor) { NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!"); /* Set the ancestor to be the outer frame. */ *aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this); NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?"); if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { return gfx3DMatrix::From2D(gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); } /* Return the matrix back to the root, factoring in the x and y offsets. */ return gfx3DMatrix::From2D(GetCanvasTMForChildren()); }
void nsSelectsAreaFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsListControlFrame* list = GetEnclosingListFrame(this); NS_ASSERTION(list, "Must have an nsListControlFrame! Frame constructor is " "broken"); bool isInDropdownMode = list->IsInDropDownMode(); // See similar logic in nsListControlFrame::Reflow and // nsListControlFrame::ReflowAsDropdown. We need to match it here. nscoord oldHeight; if (isInDropdownMode) { // Store the height now in case it changes during // nsBlockFrame::Reflow for some odd reason. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { oldHeight = GetSize().height; } else { oldHeight = NS_UNCONSTRAINEDSIZE; } } nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); // Check whether we need to suppress scrollbar updates. We want to do that if // we're in a possible first pass and our height of a row has changed. if (list->MightNeedSecondPass()) { nscoord newHeightOfARow = list->CalcHeightOfARow(); // We'll need a second pass if our height of a row changed. For // comboboxes, we'll also need it if our height changed. If we're going // to do a second pass, suppress scrollbar updates for this pass. if (newHeightOfARow != mHeightOfARow || (isInDropdownMode && (oldHeight != aDesiredSize.Height() || oldHeight != GetSize().height))) { mHeightOfARow = newHeightOfARow; list->SetSuppressScrollbarUpdate(true); } } }
nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) { PRUint16 fillRule, mask; // check if we're a clipPath - cheaper than IsClipChild(), and we shouldn't // get in here for other nondisplay children if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { NS_ASSERTION(IsClipChild(), "should be in clipPath but we're not"); mask = HITTEST_MASK_FILL; fillRule = GetClipRule(); } else { mask = GetHittestMask(); if (!mask || (!(mask & HITTEST_MASK_FORCE_TEST) && !mRect.Contains(aPoint))) return nsnull; fillRule = GetStyleSVG()->mFillRule; } PRBool isHit = PR_FALSE; gfxContext context(nsSVGUtils::GetThebesComputationalSurface()); GeneratePath(&context); gfxPoint userSpacePoint = context.DeviceToUser(gfxPoint(PresContext()->AppUnitsToGfxUnits(aPoint.x), PresContext()->AppUnitsToGfxUnits(aPoint.y))); if (fillRule == NS_STYLE_FILL_RULE_EVENODD) context.SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); else context.SetFillRule(gfxContext::FILL_RULE_WINDING); if (mask & HITTEST_MASK_FILL) isHit = context.PointInFill(userSpacePoint); if (!isHit && (mask & HITTEST_MASK_STROKE)) { SetupCairoStrokeHitGeometry(&context); isHit = context.PointInStroke(userSpacePoint); } if (isHit && nsSVGUtils::HitTestClip(this, aPoint)) return this; return nsnull; }
NS_IMETHODIMP nsSVGForeignObjectFrame::UpdateCoveredRegion() { if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) return NS_ERROR_FAILURE; float x, y, w, h; static_cast<nsSVGForeignObjectElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &w, &h, nsnull); // If mRect's width or height are negative, reflow blows up! We must clamp! if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; // GetCanvasTM includes the x,y translation mRect = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext()); return NS_OK; }
gfxMatrix nsSVGGFrame::GetCanvasTM(uint32_t aFor) { if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { if ((aFor == FOR_PAINTING && NS_SVGDisplayListPaintingEnabled()) || (aFor == FOR_HIT_TESTING && NS_SVGDisplayListHitTestingEnabled())) { return nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(this); } } if (!mCanvasTM) { NS_ASSERTION(mParent, "null parent"); nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent); nsSVGGraphicElement *content = static_cast<nsSVGGraphicElement*>(mContent); gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM(aFor)); mCanvasTM = new gfxMatrix(tm); } return *mCanvasTM; }
gfxRect nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace) { NS_ASSERTION(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), "Should not be calling this on a non-display child"); nsSVGForeignObjectElement *content = static_cast<nsSVGForeignObjectElement*>(mContent); float x, y, w, h; content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull); if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; if (aToBBoxUserspace.IsSingular()) { // XXX ReportToConsole return gfxRect(0.0, 0.0, 0.0, 0.0); } return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h)); }
void GLSTATE_DECL __glstate_ClearStencil (GLint c) { GLcontext *g = GetCurrentContext(); GLstencilstate *s = &(g->stencil); GLstatebits *stateb = GetStateBits(); GLstencilbits *sb = &(stateb->stencil); /*ECHECK*/ if (g->current.beginend) if (__glerror(__LINE__, __FILE__, GL_INVALID_OPERATION, "glClearStencil called in begin/end")) return; /*ECHECK*/ s->clearvalue = c; sb->clearvalue = g->nbitID; sb->dirty = g->nbitID; }
NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request, imgIContainer *image) { NS_ENSURE_ARG_POINTER(image); // Ensure the animation (if any) is started image->StartAnimation(); nscoord w, h; image->GetWidth(&w); image->GetHeight(&h); mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w), nsPresContext::CSSPixelsToAppUnits(h)); if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); } return NS_OK; }
void nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot) { nsIFrame* oof = mOutOfFlowFrame; if (oof) { // Unregister out-of-flow frame nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager(); fm->UnregisterPlaceholderFrame(this); mOutOfFlowFrame = nullptr; // If aDestructRoot is not an ancestor of the out-of-flow frame, // then call RemoveFrame on it here. // Also destroy it here if it's a popup frame. (Bug 96291) if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) || !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) { ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof); fm->RemoveFrame(listId, oof); } // else oof will be destroyed by its parent } nsFrame::DestroyFrom(aDestructRoot); }
NS_IMETHODIMP nsSVGForeignObjectFrame::InitialUpdate() { NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, "Yikes! We've been called already! Hopefully we weren't called " "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); UpdateCoveredRegion(); // Make sure to not allow interrupts if we're not being reflown as a root nsPresContext::InterruptPreventer noInterrupts(PresContext()); DoReflow(); NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "We don't actually participate in reflow"); // Do unset the various reflow bits, though. mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); return NS_OK; }
void GLSTATE_DECL __glstate_StencilMask (GLuint mask) { GLcontext *g = GetCurrentContext(); GLstencilstate *s = &(g->stencil); GLstatebits *stateb = GetStateBits(); GLstencilbits *sb = &(stateb->stencil); /*ECHECK*/ if (g->current.beginend) if (__glerror(__LINE__, __FILE__, GL_INVALID_OPERATION, "glStencilMask called in begin/end")) return; /*ECHECK*/ s->mask = mask; sb->writemask = g->nbitID; sb->dirty = g->nbitID; }
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint) { if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) return nsnull; nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return nsnull; float x, y, width, height; static_cast<nsSVGElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); gfxMatrix tm = GetCanvasTM().Invert(); if (tm.IsSingular()) return nsnull; // Convert aPoint from app units in canvas space to user space: gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel(); pt = tm.Transform(pt); if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt)) return nsnull; // Convert pt to app units in *local* space: pt = pt * nsPresContext::AppUnitsPerCSSPixel(); nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y)); nsIFrame *frame = nsLayoutUtils::GetFrameForPoint(kid, point); if (frame && nsSVGUtils::HitTestClip(this, aPoint)) return frame; return nsnull; }
void GLSTATE_DECL __glstate_StencilFunc(GLenum func, GLint ref, GLuint mask) { GLcontext *g = GetCurrentContext(); GLstencilstate *s = &(g->stencil); GLstatebits *stateb = GetStateBits(); GLstencilbits *sb = &(stateb->stencil); /*ECHECK*/ if (g->current.beginend) if (__glerror(__LINE__, __FILE__, GL_INVALID_OPERATION, "glStencilFunc called in begin/end")) return; if (func != GL_NEVER && func != GL_LESS && func != GL_LEQUAL && func != GL_GREATER && func != GL_GEQUAL && func != GL_EQUAL && func != GL_NOTEQUAL && func != GL_ALWAYS) if (__glerror(__LINE__, __FILE__, GL_INVALID_ENUM, "glStencilFunc called with bogu func: %d", func)) return; /*ECHECK*/ s->func = func; s->ref = ref; s->mask = mask; sb->func = g->nbitID; sb->dirty = g->nbitID; }
NS_IMETHODIMP nsSVGDisplayContainerFrame::InitialUpdate() { NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW, "Yikes! We've been called already! Hopefully we weren't called " "before our nsSVGOuterSVGFrame's initial Reflow()!!!"); for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { SVGFrame->InitialUpdate(); } } NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW), "We don't actually participate in reflow"); // Do unset the various reflow bits, though. mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); return NS_OK; }
NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request, imgIContainer *image) { NS_ENSURE_ARG_POINTER(image); // Ensure the animation (if any) is started. Note: There is no // corresponding call to Decrement for this. This Increment will be // 'cleaned up' by the Request when it is destroyed, but only then. request->IncrementAnimationConsumers(); nscoord w, h; image->GetWidth(&w); image->GetHeight(&h); mIntrinsicSize.SizeTo(nsPresContext::CSSPixelsToAppUnits(w), nsPresContext::CSSPixelsToAppUnits(h)); if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { PresContext()->PresShell()-> FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); } return NS_OK; }
NS_METHOD nsTableOuterFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aOuterRS, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame"); DISPLAY_REFLOW(aPresContext, this, aOuterRS, aDesiredSize, aStatus); nsresult rv = NS_OK; PRUint8 captionSide = GetCaptionSide(); // Initialize out parameters aDesiredSize.width = aDesiredSize.height = 0; aStatus = NS_FRAME_COMPLETE; if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(aPresContext); } // Use longs to get more-aligned space. #define LONGS_IN_HTMLRS \ ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long)) long captionRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *captionRS = static_cast<nsHTMLReflowState*>((void*)captionRSSpace); long innerRSSpace[LONGS_IN_HTMLRS]; nsHTMLReflowState *innerRS = static_cast<nsHTMLReflowState*>((void*) innerRSSpace); nsRect origInnerRect = InnerTableFrame()->GetRect(); nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect(); PRBool innerFirstReflow = (InnerTableFrame()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; nsRect origCaptionRect; nsRect origCaptionVisualOverflow; PRBool captionFirstReflow; if (mCaptionFrames.NotEmpty()) { origCaptionRect = mCaptionFrames.FirstChild()->GetRect(); origCaptionVisualOverflow = mCaptionFrames.FirstChild()->GetVisualOverflowRect(); captionFirstReflow = (mCaptionFrames.FirstChild()->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; } // ComputeAutoSize has to match this logic. if (captionSide == NO_SIDE) { // We don't have a caption. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT || captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) { // nsTableCaptionFrame::ComputeAutoSize takes care of making side // captions small. Compute the caption's size first, and tell the // table to fit in what's left. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedWidth()); nscoord innerAvailWidth = aOuterRS.ComputedWidth() - (captionRS->ComputedWidth() + captionRS->mComputedMargin.LeftRight() + captionRS->mComputedBorderPadding.LeftRight()); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, innerAvailWidth); } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) { // Compute the table's size first, and then prevent the caption from // being wider unless it has to be. // // Note that CSS 2.1 (but not 2.0) says: // The width of the anonymous box is the border-edge width of the // table box inside it // We don't actually make our anonymous box that width (if we did, // it would break 'auto' margins), but this effectively does that. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); // It's good that CSS 2.1 says not to include margins, since we // can't, since they already been converted so they exactly // fill the available width (ignoring the margin on one side if // neither are auto). (We take advantage of that later when we call // GetCaptionOrigin, though.) nscoord innerBorderWidth = innerRS->ComputedWidth() + innerRS->mComputedBorderPadding.LeftRight(); OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, innerBorderWidth); } else { NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE || captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE, "unexpected caption-side"); // Size the table and the caption independently. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRS, captionRSSpace, aOuterRS.ComputedWidth()); OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRS, innerRSSpace, aOuterRS.ComputedWidth()); } // First reflow the caption. nsHTMLReflowMetrics captionMet; nsSize captionSize; nsMargin captionMargin; if (mCaptionFrames.NotEmpty()) { nsReflowStatus capStatus; // don't let the caption cause incomplete rv = OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(), *captionRS, captionMet, capStatus); if (NS_FAILED(rv)) return rv; captionSize.width = captionMet.width; captionSize.height = captionMet.height; captionMargin = captionRS->mComputedMargin; // Now that we know the height of the caption, reduce the available height // for the table frame if we are height constrained and the caption is above // or below the inner table. if (NS_UNCONSTRAINEDSIZE != aOuterRS.availableHeight) { nscoord captionHeight = 0; switch (captionSide) { case NS_STYLE_CAPTION_SIDE_TOP: case NS_STYLE_CAPTION_SIDE_BOTTOM: { captionHeight = captionSize.height + captionMargin.TopBottom(); break; } case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE: { nsCollapsingMargin belowCaptionMargin; belowCaptionMargin.Include(captionMargin.bottom); belowCaptionMargin.Include(innerRS->mComputedMargin.top); captionHeight = captionSize.height + captionMargin.top + belowCaptionMargin.get(); break; } case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE: { nsCollapsingMargin aboveCaptionMargin; aboveCaptionMargin.Include(captionMargin.top); aboveCaptionMargin.Include(innerRS->mComputedMargin.bottom); captionHeight = captionSize.height + captionMargin.bottom + aboveCaptionMargin.get(); break; } } innerRS->availableHeight = NS_MAX(0, innerRS->availableHeight - captionHeight); } } else { captionSize.SizeTo(0,0); captionMargin.SizeTo(0,0,0,0); } // Then, now that we know how much to reduce the width of the inner // table to account for side captions, reflow the inner table. nsHTMLReflowMetrics innerMet; rv = OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRS, innerMet, aStatus); if (NS_FAILED(rv)) return rv; nsSize innerSize; innerSize.width = innerMet.width; innerSize.height = innerMet.height; nsMargin innerMargin = innerRS->mComputedMargin; nsSize containSize = GetContainingBlockSize(aOuterRS); // Now that we've reflowed both we can place them. // XXXldb Most of the input variables here are now uninitialized! // XXX Need to recompute inner table's auto margins for the case of side // captions. (Caption's are broken too, but that should be fixed earlier.) if (mCaptionFrames.NotEmpty()) { nsPoint captionOrigin; GetCaptionOrigin(captionSide, containSize, innerSize, innerMargin, captionSize, captionMargin, captionOrigin); FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, captionRS, captionMet, captionOrigin.x, captionOrigin.y, 0); captionRS->~nsHTMLReflowState(); } // XXX If the height is constrained then we need to check whether // everything still fits... nsPoint innerOrigin; GetInnerOrigin(captionSide, containSize, captionSize, captionMargin, innerSize, innerMargin, innerOrigin); FinishReflowChild(InnerTableFrame(), aPresContext, innerRS, innerMet, innerOrigin.x, innerOrigin.y, 0); innerRS->~nsHTMLReflowState(); nsTableFrame::InvalidateFrame(InnerTableFrame(), origInnerRect, origInnerVisualOverflow, innerFirstReflow); if (mCaptionFrames.NotEmpty()) { nsTableFrame::InvalidateFrame(mCaptionFrames.FirstChild(), origCaptionRect, origCaptionVisualOverflow, captionFirstReflow); } UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin); // Return our desired rect NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize); return rv; }
NS_IMETHODIMP nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { NS_PRECONDITION(aPresContext->IsRootPaginatedDocument(), "A Page Sequence is only for real pages"); 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 // Don't do incremental reflow until we've taught tables how to do // it right in paginated mode. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Return our desired size aDesiredSize.height = mSize.height * PresContext()->GetPrintPreviewScale(); aDesiredSize.width = mSize.width * PresContext()->GetPrintPreviewScale(); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); return NS_OK; } PRBool isPrintPreview = aPresContext->Type() == nsPresContext::eContext_PrintPreview; // See if we can get a Print Settings from the Context if (!mPageData->mPrintSettings && aPresContext->Medium() == nsGkAtoms::print) { mPageData->mPrintSettings = aPresContext->GetPrintSettings(); } // now get out margins & edges if (mPageData->mPrintSettings) { nsIntMargin unwriteableTwips; mPageData->mPrintSettings->GetUnwriteableMarginInTwips(unwriteableTwips); NS_ASSERTION(unwriteableTwips.left >= 0 && unwriteableTwips.top >= 0 && unwriteableTwips.right >= 0 && unwriteableTwips.bottom >= 0, "Unwriteable twips should be non-negative"); nsIntMargin marginTwips; mPageData->mPrintSettings->GetMarginInTwips(marginTwips); mMargin = aPresContext->CSSTwipsToAppUnits(marginTwips + unwriteableTwips); PRInt16 printType; mPageData->mPrintSettings->GetPrintRange(&printType); mPrintRangeType = printType; nsIntMargin edgeTwips; mPageData->mPrintSettings->GetEdgeInTwips(edgeTwips); // sanity check the values. three inches are sometimes needed PRInt32 inchInTwips = NS_INCHES_TO_INT_TWIPS(3.0); edgeTwips.top = NS_MIN(NS_MAX(edgeTwips.top, 0), inchInTwips); edgeTwips.bottom = NS_MIN(NS_MAX(edgeTwips.bottom, 0), inchInTwips); edgeTwips.left = NS_MIN(NS_MAX(edgeTwips.left, 0), inchInTwips); edgeTwips.right = NS_MIN(NS_MAX(edgeTwips.right, 0), inchInTwips); mPageData->mEdgePaperMargin = aPresContext->CSSTwipsToAppUnits(edgeTwips + unwriteableTwips); } // *** Special Override *** // If this is a sub-sdoc (meaning it doesn't take the whole page) // and if this Document is in the upper left hand corner // we need to suppress the top margin or it will reflow too small nsSize pageSize = aPresContext->GetPageSize(); mPageData->mReflowSize = pageSize; // If we're printing a selection, we need to reflow with // unconstrained height, to make sure we'll get to the selection // even if it's beyond the first page of content. if (nsIPrintSettings::kRangeSelection == mPrintRangeType) { mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE; } mPageData->mReflowMargin = mMargin; // Compute the size of each page and the x coordinate that each page will // be placed at nscoord extraThreshold = NS_MAX(pageSize.width, pageSize.height)/10; PRInt32 gapInTwips = nsContentUtils::GetIntPref("print.print_extra_margin"); gapInTwips = NS_MAX(0, gapInTwips); nscoord extraGap = aPresContext->CSSTwipsToAppUnits(gapInTwips); extraGap = NS_MIN(extraGap, extraThreshold); // clamp to 1/10 of the largest dim of the page nscoord deadSpaceGap = 0; if (isPrintPreview) { GetDeadSpaceValue(&gapInTwips); deadSpaceGap = aPresContext->CSSTwipsToAppUnits(gapInTwips); } nsMargin extraMargin(0,0,0,0); nsSize shadowSize(0,0); if (aPresContext->IsScreen()) { extraMargin.SizeTo(extraGap, extraGap, extraGap, extraGap); nscoord fourPixels = nsPresContext::CSSPixelsToAppUnits(4); shadowSize.SizeTo(fourPixels, fourPixels); } mPageData->mShadowSize = shadowSize; mPageData->mExtraMargin = extraMargin; const nscoord x = deadSpaceGap; nscoord y = deadSpaceGap;// Running y-offset for each page nsSize availSize(pageSize.width + shadowSize.width + extraMargin.LeftRight(), pageSize.height + shadowSize.height + extraMargin.TopBottom()); // Tile the pages vertically nsHTMLReflowMetrics kidSize; for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) { // Set the shared data into the page frame before reflow nsPageFrame * pf = static_cast<nsPageFrame*>(kidFrame); pf->SetSharedPageData(mPageData); // Reflow the page nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize); nsReflowStatus status; kidReflowState.SetComputedWidth(kidReflowState.availableWidth); //kidReflowState.SetComputedHeight(kidReflowState.availableHeight); PR_PL(("AV W: %d H: %d\n", kidReflowState.availableWidth, kidReflowState.availableHeight)); // 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); FinishReflowChild(kidFrame, aPresContext, nsnull, kidSize, x, y, 0); y += kidSize.height; // Leave a slight gap between the pages y += deadSpaceGap; // Is the page complete? nsIFrame* kidNextInFlow = kidFrame->GetNextInFlow(); if (NS_FRAME_IS_FULLY_COMPLETE(status)) { NS_ASSERTION(!kidNextInFlow, "bad child flow list"); } else if (!kidNextInFlow) { // The page isn't complete and it doesn't have a next-in-flow, so // create a continuing page. nsIFrame* continuingPage; nsresult rv = aPresContext->PresShell()->FrameConstructor()-> CreateContinuingFrame(aPresContext, kidFrame, this, &continuingPage); if (NS_FAILED(rv)) { break; } // Add it to our child list mFrames.InsertFrame(nsnull, kidFrame, continuingPage); } // 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 = static_cast<nsPageFrame*>(page); if (pf != nsnull) { pf->SetPageNumInfo(pageNum, pageTot); } pageNum++; } // Create current Date/Time String if (!mDateFormatter) mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID); 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 } // Return our desired size // Adjustr the reflow size by PrintPreviewScale so the scrollbars end up the // correct size nscoord w = (x + availSize.width + deadSpaceGap); aDesiredSize.height = y * PresContext()->GetPrintPreviewScale(); // includes page heights and dead space aDesiredSize.width = w * PresContext()->GetPrintPreviewScale(); aDesiredSize.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aDesiredSize); // cache the size so we can set the desired size // for the other reflows that happen mSize.width = w; mSize.height = y; NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
PRBool nsSVGForeignObjectFrame::GetMatrixPropagation() { return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0; }
PRBool nsSVGPathGeometryFrame::GetMatrixPropagation() { return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0; }
void nsSVGForeignObjectFrame::DoReflow() { NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)-> GetStateBits() & NS_FRAME_FIRST_REFLOW), "Calling InitialUpdate too early - must not call DoReflow!!!"); // Skip reflow if we're zero-sized, unless this is our first reflow. if (IsDisabled() && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) return; if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) return; nsPresContext *presContext = PresContext(); nsIFrame* kid = GetFirstChild(nsnull); if (!kid) return; // initiate a synchronous reflow here and now: nsSize availableSpace(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); nsIPresShell* presShell = presContext->PresShell(); NS_ASSERTION(presShell, "null presShell"); nsRefPtr<nsRenderingContext> renderingContext = presShell->GetReferenceRenderingContext(); if (!renderingContext) return; nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*> (mContent); float width = fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO); float height = fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO); // Clamp height & width to be non-negative (to match UpdateCoveredRegion). width = NS_MAX(width, 0.0f); height = NS_MAX(height, 0.0f); nsSize size(nsPresContext::CSSPixelsToAppUnits(width), nsPresContext::CSSPixelsToAppUnits(height)); mInReflow = PR_TRUE; nsHTMLReflowState reflowState(presContext, kid, renderingContext, nsSize(size.width, NS_UNCONSTRAINEDSIZE)); nsHTMLReflowMetrics desiredSize; nsReflowStatus status; // We don't use size.height above because that tells the child to do // page/column breaking at that height. NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) && reflowState.mComputedMargin == nsMargin(0, 0, 0, 0), "style system should ensure that :-moz-svg-foreign content " "does not get styled"); NS_ASSERTION(reflowState.ComputedWidth() == size.width, "reflow state made child wrong size"); reflowState.SetComputedHeight(size.height); ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, status); NS_ASSERTION(size.width == desiredSize.width && size.height == desiredSize.height, "unexpected size"); FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); mInReflow = PR_FALSE; FlushDirtyRegion(0); }
void nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags) { NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), "Must be NS_STATE_SVG_NONDISPLAY_CHILD!"); NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED), "Invalidation logic may need adjusting"); bool needNewBounds = false; // i.e. mRect or visual overflow rect bool needReflow = false; bool needNewCanvasTM = false; if (aFlags & COORD_CONTEXT_CHANGED) { nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*>(mContent); // Coordinate context changes affect mCanvasTM if we have a // percentage 'x' or 'y' if (fO->mLengthAttributes[nsSVGForeignObjectElement::X].IsPercentage() || fO->mLengthAttributes[nsSVGForeignObjectElement::Y].IsPercentage()) { needNewBounds = true; needNewCanvasTM = true; } // Our coordinate context's width/height has changed. If we have a // percentage width/height our dimensions will change so we must reflow. if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() || fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) { needNewBounds = true; needReflow = true; } } if (aFlags & TRANSFORM_CHANGED) { needNewBounds = true; // needed if it was _our_ transform that changed needNewCanvasTM = true; // In an ideal world we would reflow when our CTM changes. This is because // glyph metrics do not necessarily scale uniformly with change in scale // and, as a result, CTM changes may require text to break at different // points. The problem would be how to keep performance acceptable when // e.g. the transform of an ancestor is animated. // We also seem to get some sort of infinite loop post bug 421584 if we // reflow. } if (needNewBounds && !(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) { nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this); } // If we're called while the PresShell is handling reflow events then we // must have been called as a result of the NotifyViewportChange() call in // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow // at this point (i.e. during reflow) because it could confuse the // PresShell and prevent it from reflowing us properly in future. Besides // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us // synchronously, so there's no need. if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) { RequestReflow(nsIPresShell::eResize); } if (needNewCanvasTM) { // Do this after calling InvalidateAndScheduleBoundsUpdate in case we // change the code and it needs to use it. mCanvasTM = nsnull; } }
NS_IMETHODIMP CVE_2013_1732_firefox12_0_nsBlockFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsBlockFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); #ifdef DEBUG if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.ComputedWidth(), aReflowState.ComputedHeight()); } AutoNoisyIndenter indent(gNoisy); PRTime start = LL_ZERO; // Initialize these variablies to silence the compiler. PRInt32 ctc = 0; // We only use these if they are set (gLameReflowMetrics). if (gLameReflowMetrics) { start = PR_Now(); ctc = nsLineBox::GetCtorCount(); } #endif const nsHTMLReflowState *reflowState = &aReflowState; nsAutoPtr<nsHTMLReflowState> mutableReflowState; // If we have non-auto height, we're clipping our kids and we fit, // make sure our kids fit too. if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE && aReflowState.ComputedHeight() != NS_AUTOHEIGHT && ApplyOverflowClipping(this, aReflowState.mStyleDisplay)) { nsMargin heightExtras = aReflowState.mComputedBorderPadding; if (GetSkipSides() & NS_SIDE_TOP) { heightExtras.top = 0; } else { // Bottom margin never causes us to create continuations, so we // don't need to worry about whether it fits in its entirety. heightExtras.top += aReflowState.mComputedMargin.top; } if (GetEffectiveComputedHeight(aReflowState) + heightExtras.TopBottom() <= aReflowState.availableHeight) { mutableReflowState = new nsHTMLReflowState(aReflowState); mutableReflowState->availableHeight = NS_UNCONSTRAINEDSIZE; reflowState = mutableReflowState; } } // See comment below about oldSize. Use *only* for the // abs-pos-containing-block-size-change optimization! nsSize oldSize = GetSize(); // Should we create a float manager? nsAutoFloatManager autoFloatManager(const_cast<nsHTMLReflowState&>(*reflowState)); // XXXldb If we start storing the float manager in the frame rather // than keeping it around only during reflow then we should create it // only when there are actually floats to manage. Otherwise things // like tables will gain significant bloat. bool needFloatManager = nsBlockFrame::BlockNeedsFloatManager(this); if (needFloatManager) autoFloatManager.CreateFloatManager(aPresContext); // OK, some lines may be reflowed. Blow away any saved line cursor // because we may invalidate the nondecreasing // overflowArea.VisualOverflow().y/yMost invariant, and we may even // delete the line with the line cursor. ClearLineCursor(); if (IsFrameTreeTooDeep(*reflowState, aMetrics, aStatus)) { return NS_OK; } bool marginRoot = BlockIsMarginRoot(this); nsBlockReflowState state(*reflowState, aPresContext, this, aMetrics, marginRoot, marginRoot, needFloatManager); #ifdef IBMBIDI if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION) static_cast<nsBlockFrame*>(GetFirstContinuation())->ResolveBidi(); #endif // IBMBIDI if (RenumberLists(aPresContext)) { AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); } nsresult rv = NS_OK; // ALWAYS drain overflow. We never want to leave the previnflow's // overflow lines hanging around; block reflow depends on the // overflow line lists being cleared out between reflow passes. DrainOverflowLines(); // Handle paginated overflow (see nsContainerFrame.h) nsOverflowAreas ocBounds; nsReflowStatus ocStatus = NS_FRAME_COMPLETE; if (GetPrevInFlow()) { ReflowOverflowContainerChildren(aPresContext, *reflowState, ocBounds, 0, ocStatus); } // Now that we're done cleaning up our overflow container lists, we can // give |state| its nsOverflowContinuationTracker. nsOverflowContinuationTracker tracker(aPresContext, this, false); state.mOverflowTracker = &tracker; // Drain & handle pushed floats DrainPushedFloats(state); nsOverflowAreas fcBounds; nsReflowStatus fcStatus = NS_FRAME_COMPLETE; rv = ReflowPushedFloats(state, fcBounds, fcStatus); NS_ENSURE_SUCCESS(rv, rv); // 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 (reflowState->mFlags.mHResize) PrepareResizeReflow(state); mState &= ~NS_FRAME_FIRST_REFLOW; // Now reflow... rv = ReflowDirtyLines(state); NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed"); if (NS_FAILED(rv)) return rv; NS_MergeReflowStatusInto(&state.mReflowStatus, ocStatus); NS_MergeReflowStatusInto(&state.mReflowStatus, fcStatus); // If we end in a BR with clear and affected floats continue, // we need to continue, too. if (NS_UNCONSTRAINEDSIZE != reflowState->availableHeight && NS_FRAME_IS_COMPLETE(state.mReflowStatus) && state.mFloatManager->ClearContinues(FindTrailingClear())) { NS_FRAME_SET_INCOMPLETE(state.mReflowStatus); } if (!NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) { if (GetOverflowLines() || GetPushedFloats()) { state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW; } #ifdef DEBUG_kipp ListTag(stdout); printf(": block is not fully complete\n"); #endif } CheckFloats(state); // Place the "marker" (bullet) frame if it is placed next to a block // child. // // According to the CSS2 spec, section 12.6.1, the "marker" box // participates in the height calculation of the list-item box's // first line box. // // There are exactly two places a bullet can be placed: near the // first or second line. It's only placed on the second line in a // rare case: an empty first line followed by a second line that // contains a block (example: <LI>\n<P>... ). This is where // the second case can happen. if (mBullet && HaveOutsideBullet() && !mLines.empty() && (mLines.front()->IsBlock() || (0 == mLines.front()->mBounds.height && mLines.front() != mLines.back() && mLines.begin().next()->IsBlock()))) { // Reflow the bullet nsHTMLReflowMetrics metrics; // XXX Use the entire line when we fix bug 25888. nsLayoutUtils::LinePosition position; bool havePosition = nsLayoutUtils::GetFirstLinePosition(this, &position); nscoord lineTop = havePosition ? position.mTop : reflowState->mComputedBorderPadding.top; ReflowBullet(state, metrics, lineTop); NS_ASSERTION(!BulletIsEmpty() || metrics.height == 0, "empty bullet took up space"); if (havePosition && !BulletIsEmpty()) { // We have some lines to align the bullet with. // Doing the alignment using the baseline will also cater for // bullets that are placed next to a child block (bug 92896) // Tall bullets won't look particularly nice here... nsRect bbox = mBullet->GetRect(); bbox.y = position.mBaseline - metrics.ascent; mBullet->SetRect(bbox); } // Otherwise just leave the bullet where it is, up against our top padding. } // Compute our final size nscoord bottomEdgeOfChildren; ComputeFinalSize(*reflowState, state, aMetrics, &bottomEdgeOfChildren); nsRect areaBounds = nsRect(0, 0, aMetrics.width, aMetrics.height); ComputeOverflowAreas(areaBounds, reflowState->mStyleDisplay, bottomEdgeOfChildren, aMetrics.mOverflowAreas); // Factor overflow container child bounds into the overflow area aMetrics.mOverflowAreas.UnionWith(ocBounds); // Factor pushed float child bounds into the overflow area aMetrics.mOverflowAreas.UnionWith(fcBounds); // Let the absolutely positioned container reflow any absolutely positioned // child frames that need to be reflowed, e.g., elements with a percentage // based width/height // We want to do this under either of two conditions: // 1. If we didn't do the incremental reflow above. // 2. If our size changed. // Even though it's the padding edge that's the containing block, we // can use our rect (the border edge) since if the border style // changed, the reflow would have been targeted at us so we'd satisfy // condition 1. // XXX checking oldSize is bogus, there are various reasons we might have // reflowed but our size might not have been changed to what we // asked for (e.g., we ended up being pushed to a new page) // When WillReflowAgainForClearance is true, we will reflow again without // resetting the size. Because of this, we must not reflow our abs-pos children // in that situation --- what we think is our "new size" // will not be our real new size. This also happens to be more efficient. if (HasAbsolutelyPositionedChildren()) { nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock(); bool haveInterrupt = aPresContext->HasPendingInterrupt(); if (reflowState->WillReflowAgainForClearance() || haveInterrupt) { // Make sure that when we reflow again we'll actually reflow all the abs // pos frames that might conceivably depend on our size (or all of them, // if we're dirty right now and interrupted; in that case we also need // to mark them all with NS_FRAME_IS_DIRTY). Sadly, we can't do much // better than that, because we don't really know what our size will be, // and it might in fact not change on the followup reflow! if (haveInterrupt && (GetStateBits() & NS_FRAME_IS_DIRTY)) { absoluteContainer->MarkAllFramesDirty(); } else { absoluteContainer->MarkSizeDependentFramesDirty(); } } else { nsSize containingBlockSize = CalculateContainingBlockSizeForAbsolutes(*reflowState, nsSize(aMetrics.width, aMetrics.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. bool cbWidthChanged = aMetrics.width != oldSize.width; bool 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. bool cbHeightChanged = !(isRoot && NS_UNCONSTRAINEDSIZE == reflowState->ComputedHeight()) && aMetrics.height != oldSize.height; absoluteContainer->Reflow(this, aPresContext, *reflowState, state.mReflowStatus, containingBlockSize.width, containingBlockSize.height, true, cbWidthChanged, cbHeightChanged, &aMetrics.mOverflowAreas); //XXXfr Why isn't this rv (and others in this file) checked/returned? } } // Determine if we need to repaint our border, background or outline CheckInvalidateSizeChange(aMetrics); FinishAndStoreOverflow(&aMetrics); // Clear the float manager pointer in the block reflow state so we // don't waste time translating the coordinate system back on a dead // float manager. if (needFloatManager) state.mFloatManager = nsnull; aStatus = state.mReflowStatus; #ifdef DEBUG // Between when we drain pushed floats and when we complete reflow, // we're allowed to have multiple continuations of the same float on // our floats list, since a first-in-flow might get pushed to a later // continuation of its containing block. But it's not permitted // outside that time. nsLayoutUtils::AssertNoDuplicateContinuations(this, mFloats); if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d", aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ", aMetrics.width, aMetrics.height, aMetrics.mCarriedOutBottomMargin.get()); if (HasOverflowAreas()) { printf(" overflow-vis={%d,%d,%d,%d}", aMetrics.VisualOverflow().x, aMetrics.VisualOverflow().y, aMetrics.VisualOverflow().width, aMetrics.VisualOverflow().height); printf(" overflow-scr={%d,%d,%d,%d}", aMetrics.ScrollableOverflow().x, aMetrics.ScrollableOverflow().y, aMetrics.ScrollableOverflow().width, aMetrics.ScrollableOverflow().height); } printf("\n"); } if (gLameReflowMetrics) { PRTime end = PR_Now(); PRInt32 ectc = nsLineBox::GetCtorCount(); PRInt32 numLines = mLines.size(); if (!numLines) numLines = 1; PRTime delta, perLineDelta, lines; LL_I2L(lines, numLines); LL_SUB(delta, end, start); LL_DIV(perLineDelta, delta, lines); ListTag(stdout); char buf[400]; PR_snprintf(buf, sizeof(buf), ": %lld elapsed (%lld per line) (%d lines; %d new lines)", delta, perLineDelta, numLines, ectc - ctc); printf("%s\n", buf); } #endif NS_FRAME_SET_TRUNCATION(aStatus, (*reflowState), aMetrics); return rv; }
bool nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus, const ReflowConfig& aConfig, bool aUnboundedLastColumn, nsCollapsingMargin* aBottomMarginCarriedOut, ColumnBalanceData& aColData) { aColData.Reset(); bool allFit = true; bool RTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; bool shrinkingHeightOnly = !NS_SUBTREE_DIRTY(this) && mLastBalanceHeight > aConfig.mColMaxHeight; #ifdef DEBUG_roc printf("*** Doing column reflow pass: mLastBalanceHeight=%d, mColMaxHeight=%d, RTL=%d\n, mBalanceColCount=%d, mColWidth=%d, mColGap=%d\n", mLastBalanceHeight, aConfig.mColMaxHeight, RTL, aConfig.mBalanceColCount, aConfig.mColWidth, aConfig.mColGap); #endif DrainOverflowColumns(); if (mLastBalanceHeight != aConfig.mColMaxHeight) { mLastBalanceHeight = aConfig.mColMaxHeight; // XXX Seems like this could fire if incremental reflow pushed the column set // down so we reflow incrementally with a different available height. // 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"); } // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; nsRect contentRect(0, 0, 0, 0); nsOverflowAreas overflowRects; nsIFrame* child = mFrames.FirstChild(); nsPoint childOrigin = nsPoint(borderPadding.left, borderPadding.top); // For RTL, figure out where the last column's left edge should be. Since the // columns might not fill the frame exactly, we need to account for the // slop. Otherwise we'll waste time moving the columns by some tiny // amount unnecessarily. nscoord targetX = borderPadding.left; if (RTL) { nscoord availWidth = aReflowState.availableWidth; if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) { availWidth = aReflowState.ComputedWidth(); } if (availWidth != NS_INTRINSICSIZE) { childOrigin.x += availWidth - aConfig.mColWidth; targetX += aConfig.mExpectedWidthLeftOver; #ifdef DEBUG_roc printf("*** childOrigin.x = %d\n", childOrigin.x); #endif } } int columnCount = 0; int contentBottom = 0; bool reflowNext = false; while (child) { // Try to skip reflowing the child. We can't skip if the child is dirty. We also can't // 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. We can't skip // if this is the last column and we're supposed to assign unbounded // height to it, because that could change the available height from // the last time we reflowed it and we should try to pull all the // content from its next sibling. (Note that it might be the last // column, but not be the last child because the desired number of columns // has changed.) bool skipIncremental = !aReflowState.ShouldReflowAllKids() && !NS_SUBTREE_DIRTY(child) && child->GetNextSibling() && !(aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) && !NS_SUBTREE_DIRTY(child->GetNextSibling()); // 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. // Check the overflow rect YMost instead of just the child's content height. The child // may have overflowing content that cares about the available height boundary. // (It may also have overflowing content that doesn't care about the available height // boundary, but if so, too bad, this optimization is defeated.) // We want scrollable overflow here since this is a calculation that // affects layout. bool skipResizeHeightShrink = shrinkingHeightOnly && child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight; nscoord childContentBottom = 0; if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) { // This child does not need to be reflowed, but we may need to move it MoveChildTo(this, child, childOrigin); // If this is the last frame then make sure we get the right status nsIFrame* kidNext = child->GetNextSibling(); if (kidNext) { aStatus = (kidNext->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) ? NS_FRAME_OVERFLOW_INCOMPLETE : NS_FRAME_NOT_COMPLETE; } else { aStatus = mLastFrameStatus; } childContentBottom = nsLayoutUtils::CalculateContentBottom(child); #ifdef DEBUG_roc printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n", columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus); #endif } else { nsSize availSize(aConfig.mColWidth, aConfig.mColMaxHeight); if (aUnboundedLastColumn && columnCount == aConfig.mBalanceColCount - 1) { availSize.height = GetAvailableContentHeight(aReflowState); } if (reflowNext) child->AddStateBits(NS_FRAME_IS_DIRTY); nsHTMLReflowState kidReflowState(PresContext(), aReflowState, child, availSize, availSize.width, aReflowState.ComputedHeight()); kidReflowState.mFlags.mIsTopOfPage = PR_TRUE; kidReflowState.mFlags.mTableIsSplittable = PR_FALSE; #ifdef DEBUG_roc printf("*** Reflowing child #%d %p: availHeight=%d\n", columnCount, (void*)child,availSize.height); #endif // 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() && !(GetStateBits() & NS_FRAME_IS_DIRTY) && !(child->GetNextSibling()->GetStateBits() & NS_FRAME_IS_DIRTY)) { kidReflowState.mFlags.mNextInFlowUntouched = PR_TRUE; } nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags); // XXX it would be cool to consult the float manager for the // previous block to figure out the region of floats from the // previous column that extend into this column, and subtract // that region from the new float manager. So you could stick a // really big float in the first column and text in following // columns would flow around it. // Reflow the frame ReflowChild(child, PresContext(), kidDesiredSize, kidReflowState, childOrigin.x + kidReflowState.mComputedMargin.left, childOrigin.y + kidReflowState.mComputedMargin.top, 0, aStatus); reflowNext = (aStatus & NS_FRAME_REFLOW_NEXTINFLOW) != 0; #ifdef DEBUG_roc printf("*** Reflowed child #%d %p: status = %d, desiredSize=%d,%d\n", columnCount, (void*)child, aStatus, kidDesiredSize.width, kidDesiredSize.height); #endif NS_FRAME_TRACE_REFLOW_OUT("Column::Reflow", aStatus); *aBottomMarginCarriedOut = kidDesiredSize.mCarriedOutBottomMargin; FinishReflowChild(child, PresContext(), &kidReflowState, kidDesiredSize, childOrigin.x, childOrigin.y, 0); childContentBottom = nsLayoutUtils::CalculateContentBottom(child); if (childContentBottom > aConfig.mColMaxHeight) { allFit = PR_FALSE; } if (childContentBottom > availSize.height) { aColData.mMaxOverflowingHeight = NS_MAX(childContentBottom, aColData.mMaxOverflowingHeight); } } contentRect.UnionRect(contentRect, child->GetRect()); ConsiderChildOverflow(overflowRects, child); contentBottom = NS_MAX(contentBottom, childContentBottom); aColData.mLastHeight = childContentBottom; aColData.mSumHeight += childContentBottom; // Build a continuation column if necessary nsIFrame* kidNextInFlow = child->GetNextInFlow(); if (NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)) { NS_ASSERTION(!kidNextInFlow, "next in flow should have been deleted"); child = nsnull; break; } else { ++columnCount; // Make sure that the column has a next-in-flow. If not, we must // create one to hold the overflowing stuff, even if we're just // going to put it on our overflow list and let *our* // next in flow handle it. if (!kidNextInFlow) { NS_ASSERTION(aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "We have to create a continuation, but the block doesn't want us to reflow it?"); // We need to create a continuing column nsresult rv = CreateNextInFlow(PresContext(), child, kidNextInFlow); if (NS_FAILED(rv)) { NS_NOTREACHED("Couldn't create continuation"); child = nsnull; break; } } // Make sure we reflow a next-in-flow when it switches between being // normal or overflow container if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { if (!(kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = PR_TRUE; kidNextInFlow->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } else if (kidNextInFlow->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; reflowNext = PR_TRUE; kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } if (columnCount >= aConfig.mBalanceColCount) { // No more columns allowed here. Stop. aStatus |= NS_FRAME_REFLOW_NEXTINFLOW; kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY); // Move any of our leftover columns to our overflow list. Our // next-in-flow will eventually pick them up. const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child); if (continuationColumns.NotEmpty()) { SetOverflowFrames(PresContext(), continuationColumns); } child = nsnull; break; } } if (PresContext()->HasPendingInterrupt()) { // Stop the loop now while |child| still points to the frame that bailed // out. We could keep going here and condition a bunch of the code in // this loop on whether there's an interrupt, or even just keep going and // trying to reflow the blocks (even though we know they'll interrupt // right after their first line), but stopping now is conceptually the // simplest (and probably fastest) thing. break; } // Advance to the next column child = child->GetNextSibling(); if (child) { if (!RTL) { childOrigin.x += aConfig.mColWidth + aConfig.mColGap; } else { childOrigin.x -= aConfig.mColWidth + aConfig.mColGap; } #ifdef DEBUG_roc printf("*** NEXT CHILD ORIGIN.x = %d\n", childOrigin.x); #endif } } if (PresContext()->CheckForInterrupt(this) && (GetStateBits() & NS_FRAME_IS_DIRTY)) { // Mark all our kids starting with |child| dirty // Note that this is a CheckForInterrupt call, not a HasPendingInterrupt, // because we might have interrupted while reflowing |child|, and since // we're about to add a dirty bit to |child| we need to make sure that // |this| is scheduled to have dirty bits marked on it and its ancestors. // Otherwise, when we go to mark dirty bits on |child|'s ancestors we'll // bail out immediately, since it'll already have a dirty bit. for (; child; child = child->GetNextSibling()) { child->AddStateBits(NS_FRAME_IS_DIRTY); } } // If we're doing RTL, we need to make sure our last column is at the left-hand side of the frame. if (RTL && childOrigin.x != targetX) { overflowRects.Clear(); contentRect = nsRect(0, 0, 0, 0); PRInt32 deltaX = targetX - childOrigin.x; #ifdef DEBUG_roc printf("*** CHILDORIGIN.x = %d, targetX = %d, DELTAX = %d\n", childOrigin.x, targetX, deltaX); #endif for (child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { MoveChildTo(this, child, child->GetPosition() + nsPoint(deltaX, 0)); ConsiderChildOverflow(overflowRects, child); contentRect.UnionRect(contentRect, child->GetRect()); } } aColData.mMaxHeight = contentBottom; contentRect.height = NS_MAX(contentRect.height, contentBottom); mLastFrameStatus = aStatus; // contentRect included the borderPadding.left,borderPadding.top of the child rects contentRect -= nsPoint(borderPadding.left, borderPadding.top); nsSize contentSize = nsSize(contentRect.XMost(), contentRect.YMost()); // Apply computed and min/max values if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) { contentSize.height = aReflowState.ComputedHeight(); } else { if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) { contentSize.height = NS_MIN(aReflowState.mComputedMaxHeight, contentSize.height); } if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) { contentSize.height = NS_MAX(aReflowState.mComputedMinHeight, contentSize.height); } } if (aReflowState.ComputedWidth() != NS_INTRINSICSIZE) { contentSize.width = aReflowState.ComputedWidth(); } else { if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) { contentSize.width = NS_MIN(aReflowState.mComputedMaxWidth, contentSize.width); } if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) { contentSize.width = NS_MAX(aReflowState.mComputedMinWidth, contentSize.width); } } aDesiredSize.height = borderPadding.top + contentSize.height + borderPadding.bottom; aDesiredSize.width = contentSize.width + borderPadding.left + borderPadding.right; aDesiredSize.mOverflowAreas = overflowRects; aDesiredSize.UnionOverflowAreasWithDesiredBounds(); #ifdef DEBUG_roc printf("*** DONE PASS feasible=%d\n", allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus)); #endif return allFit && NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus); }
NS_IMETHODIMP nsPageContentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); aStatus = NS_FRAME_COMPLETE; // initialize out parameter nsresult rv = NS_OK; if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) { nsresult rv = aPresContext->PresShell()->FrameConstructor() ->ReplicateFixedFrames(this); NS_ENSURE_SUCCESS(rv, rv); } // Set our size up front, since some parts of reflow depend on it // being already set. Note that the computed height may be // unconstrained; that's ok. Consumers should watch out for that. SetSize(nsSize(aReflowState.availableWidth, aReflowState.availableHeight)); // A PageContentFrame must always have one child: the canvas frame. // 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()) { nsIFrame* frame = mFrames.FirstChild(); nsSize maxSize(aReflowState.availableWidth, aReflowState.availableHeight); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize); kidReflowState.SetComputedHeight(aReflowState.availableHeight); mPD->mPageContentSize = aReflowState.availableWidth; // Reflow the page content area rv = ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus); NS_ENSURE_SUCCESS(rv, rv); // The document element's background should cover the entire canvas, so // take into account the combined area and any space taken up by // absolutely positioned elements nsMargin padding(0,0,0,0); // XXXbz this screws up percentage padding (sets padding to zero // in the percentage padding case) kidReflowState.mStylePadding->GetPadding(padding); // This is for shrink-to-fit, and therefore we want to use the // scrollable overflow, since the purpose of shrink to fit is to // make the content that ought to be reachable (represented by the // scrollable overflow) fit in the page. if (frame->HasOverflowAreas()) { // The background covers the content area and padding area, so check // for children sticking outside the child frame's padding edge nscoord xmost = aDesiredSize.ScrollableOverflow().XMost(); if (xmost > aDesiredSize.width) { mPD->mPageContentXMost = xmost + kidReflowState.mStyleBorder->GetActualBorderWidth(NS_SIDE_RIGHT) + padding.right; } } // Place and size the child FinishReflowChild(frame, aPresContext, &kidReflowState, aDesiredSize, 0, 0, 0); NS_ASSERTION(aPresContext->IsDynamic() || !NS_FRAME_IS_FULLY_COMPLETE(aStatus) || !frame->GetNextInFlow(), "bad child flow list"); } // Reflow our fixed frames nsReflowStatus fixedStatus = NS_FRAME_COMPLETE; mFixedContainer.Reflow(this, aPresContext, aReflowState, fixedStatus, aReflowState.availableWidth, aReflowState.availableHeight, PR_FALSE, PR_TRUE, PR_TRUE, // XXX could be optimized nsnull /* ignore overflow */); NS_ASSERTION(NS_FRAME_IS_COMPLETE(fixedStatus), "fixed frames can be truncated, but not incomplete"); // Return our desired size aDesiredSize.width = aReflowState.availableWidth; if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) { aDesiredSize.height = aReflowState.availableHeight; } FinishAndStoreOverflow(&aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
nsIFrame* nsSplittableFrame::GetPrevInFlow() const { return (GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? mPrevContinuation : nullptr; }
void nsMenuFrame::BuildAcceleratorText() { nsAutoString accelText; if ((GetStateBits() & NS_STATE_ACCELTEXT_IS_DERIVED) == 0) { mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText); if (!accelText.IsEmpty()) return; } // accelText is definitely empty here. // Now we're going to compute the accelerator text, so remember that we did. AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED); // If anything below fails, just leave the accelerator text blank. nsWeakFrame weakFrame(this); mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, PR_FALSE); ENSURE_TRUE(weakFrame.IsAlive()); // See if we have a key node and use that instead. nsAutoString keyValue; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyValue); if (keyValue.IsEmpty()) return; // Turn the document into a DOM document so we can use getElementById nsIDocument *document = mContent->GetDocument(); if (!document) return; nsIContent *keyElement = document->GetElementById(keyValue); if (!keyElement) { #ifdef DEBUG nsAutoString label; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label); nsAutoString msg = NS_LITERAL_STRING("Key '") + keyValue + NS_LITERAL_STRING("' of menu item '") + label + NS_LITERAL_STRING("' could not be found"); NS_WARNING(NS_ConvertUTF16toUTF8(msg).get()); #endif return; } // get the string to display as accelerator text // check the key element's attributes in this order: // |keytext|, |key|, |keycode| nsAutoString accelString; keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keytext, accelString); if (accelString.IsEmpty()) { keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, accelString); if (!accelString.IsEmpty()) { ToUpperCase(accelString); } else { nsAutoString keyCode; keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, keyCode); ToUpperCase(keyCode); nsresult rv; nsCOMPtr<nsIStringBundleService> bundleService = mozilla::services::GetStringBundleService(); if (bundleService) { nsCOMPtr<nsIStringBundle> bundle; rv = bundleService->CreateBundle("chrome://global/locale/keys.properties", getter_AddRefs(bundle)); if (NS_SUCCEEDED(rv) && bundle) { nsXPIDLString keyName; rv = bundle->GetStringFromName(keyCode.get(), getter_Copies(keyName)); if (keyName) accelString = keyName; } } // nothing usable found, bail if (accelString.IsEmpty()) return; } } static PRInt32 accelKey = 0; if (!accelKey) { // Compiled-in defaults, in case we can't get LookAndFeel -- // command for mac, control for all other platforms. #ifdef XP_MACOSX accelKey = nsIDOMKeyEvent::DOM_VK_META; #else accelKey = nsIDOMKeyEvent::DOM_VK_CONTROL; #endif // Get the accelerator key value from prefs, overriding the default: accelKey = nsContentUtils::GetIntPref("ui.key.accelKey", accelKey); } nsAutoString modifiers; keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiers); char* str = ToNewCString(modifiers); char* newStr; char* token = nsCRT::strtok(str, ", \t", &newStr); while (token) { if (PL_strcmp(token, "shift") == 0) accelText += *gShiftText; else if (PL_strcmp(token, "alt") == 0) accelText += *gAltText; else if (PL_strcmp(token, "meta") == 0) accelText += *gMetaText; else if (PL_strcmp(token, "control") == 0) accelText += *gControlText; else if (PL_strcmp(token, "accel") == 0) { switch (accelKey) { case nsIDOMKeyEvent::DOM_VK_META: accelText += *gMetaText; break; case nsIDOMKeyEvent::DOM_VK_ALT: accelText += *gAltText; break; case nsIDOMKeyEvent::DOM_VK_CONTROL: default: accelText += *gControlText; break; } } accelText += *gModifierSeparator; token = nsCRT::strtok(newStr, ", \t", &newStr); } nsMemory::Free(str); accelText += accelString; mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accelText, PR_FALSE); }
NS_IMETHODIMP nsInlineFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsInlineFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); if (nsnull == aReflowState.mLineLayout) { return NS_ERROR_INVALID_ARG; } PRBool lazilySetParentPointer = PR_FALSE; nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame(); // Check for an overflow list with our prev-in-flow nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow(); if (nsnull != prevInFlow) { nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames()); if (prevOverflowFrames) { // When pushing and pulling frames we need to check for whether any // views need to be reparented. nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, *prevOverflowFrames, prevInFlow, this); // Check if we should do the lazilySetParentPointer optimization. // Only do it in simple cases where we're being reflowed for the // first time, nothing (e.g. bidi resolution) has already given // us children, and there's no next-in-flow, so all our frames // will be taken from prevOverflowFrames. if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() && !GetNextInFlow()) { // If our child list is empty, just put the new frames into it. // Note that we don't set the parent pointer for the new frames. Instead wait // to do this until we actually reflow the frame. If the overflow list contains // thousands of frames this is a big performance issue (see bug #5588) mFrames.SetFrames(*prevOverflowFrames); lazilySetParentPointer = PR_TRUE; } else { // Assign all floats to our block if necessary if (lineContainer && lineContainer->GetPrevContinuation()) { ReparentFloatsForInlineChild(lineContainer, prevOverflowFrames->FirstChild(), PR_TRUE); } // Insert the new frames at the beginning of the child list // and set their parent pointer mFrames.InsertFrames(this, nsnull, *prevOverflowFrames); } } } // It's also possible that we have an overflow list for ourselves #ifdef DEBUG 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 nsFrameList* overflowFrames = GetOverflowFrames(); NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(), "overflow list is not empty for initial reflow"); } #endif if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames()); if (overflowFrames) { NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); // Because we lazily set the parent pointer of child frames we get from // our prev-in-flow's overflow list, it's possible that we have not set // the parent pointer for these frames. mFrames.AppendFrames(this, *overflowFrames); } } if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } // Set our own reflow state (additional state above and beyond // aReflowState) InlineReflowState irs; irs.mPrevFrame = nsnull; irs.mLineContainer = lineContainer; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); irs.mSetParentPointer = lazilySetParentPointer; nsresult rv; if (mFrames.IsEmpty()) { // Try to pull over one frame before starting so that we know // whether we have an anonymous block or not. PRBool complete; (void) PullOneFrame(aPresContext, irs, &complete); } rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); // Note: the line layout code will properly compute our // overflow-rect state for us. NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return rv; }
nsresult nsBox::SyncLayout(nsBoxLayoutState& aState) { /* PRBool collapsed = PR_FALSE; IsCollapsed(aState, collapsed); if (collapsed) { CollapseChild(aState, this, PR_TRUE); return NS_OK; } */ if (GetStateBits() & NS_FRAME_IS_DIRTY) Redraw(aState); RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW); nsPresContext* presContext = aState.PresContext(); PRUint32 flags = 0; GetLayoutFlags(flags); PRUint32 stateFlags = aState.LayoutFlags(); flags |= stateFlags; nsRect rect(nsPoint(0, 0), GetSize()); if (ComputesOwnOverflowArea()) { rect = GetOverflowRect(); } else { if (!DoesClipChildren() && !IsCollapsed(aState)) { // See if our child frames caused us to overflow after being laid // out. If so, store the overflow area. This normally can't happen // in XUL, but it can happen with the CSS 'outline' property and // possibly with other exotic stuff (e.g. relatively positioned // frames in HTML inside XUL). nsIFrame* box = GetChildBox(); while (box) { nsRect bounds = box->GetOverflowRect() + box->GetPosition(); rect.UnionRect(rect, bounds); box = box->GetNextBox(); } } FinishAndStoreOverflow(&rect, GetSize()); } nsIView* view = GetView(); if (view) { // Make sure the frame's view is properly sized and positioned and has // things like opacity correct nsHTMLContainerFrame::SyncFrameViewAfterReflow( presContext, this, view, &rect, flags); } return NS_OK; }
NS_IMETHODIMP nsFieldSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame", aReflowState.reason); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; // Should we create a space manager? nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState)); // XXXldb If we start storing the space manager in the frame rather // than keeping it around only during reflow then we should create it // only when there are actually floats to manage. Otherwise things // like tables will gain significant bloat. if (NS_BLOCK_SPACE_MGR & mState) autoSpaceManager.CreateSpaceManagerFor(aPresContext, this); //------------ Handle Incremental Reflow ----------------- PRBool reflowContent = PR_TRUE; PRBool reflowLegend = PR_TRUE; nsReflowReason reason = aReflowState.reason; if (reason == eReflowReason_Incremental) { nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; // See if it's targeted at us if (command) { nsReflowType reflowType; command->GetType(reflowType); switch (reflowType) { case eReflowType_StyleChanged: reason = eReflowReason_StyleChange; break; case eReflowType_ReflowDirty: reason = eReflowReason_Dirty; break; default: NS_ERROR("Unexpected Reflow Type"); } } else { reflowContent = PR_FALSE; reflowLegend = PR_FALSE; nsReflowPath::iterator iter = aReflowState.path->FirstChild(); nsReflowPath::iterator end = aReflowState.path->EndChildren(); for ( ; iter != end; ++iter) { if (*iter == mLegendFrame) reflowLegend = PR_TRUE; else if (*iter == mContentFrame) reflowContent = PR_TRUE; } } } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else if (reason == eReflowReason_Dirty) { // if dirty then check dirty flags if (GetStateBits() & NS_FRAME_IS_DIRTY) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else { if (reflowContent) { reflowContent = mContentFrame ? (mContentFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } if (reflowLegend) { reflowLegend = mLegendFrame ? (mLegendFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } } } // availSize could have unconstrained values, don't perform any addition on them nsSize availSize(aReflowState.mComputedWidth, aReflowState.availableHeight); // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; const nsMargin &padding = aReflowState.mComputedPadding; nsMargin border = borderPadding - padding; if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = borderPadding.left + borderPadding.right; } // Figure out how big the legend is if there is one. // get the legend's margin nsMargin legendMargin(0,0,0,0); // reflow the legend only if needed if (mLegendFrame) { const nsStyleMargin* marginStyle = mLegendFrame->GetStyleMargin(); marginStyle->GetMargin(legendMargin); if (reflowLegend) { nsHTMLReflowState legendReflowState(aPresContext, aReflowState, mLegendFrame, nsSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE), reason); // always give the legend as much size as it needs legendReflowState.mComputedWidth = NS_INTRINSICSIZE; legendReflowState.mComputedHeight = NS_INTRINSICSIZE; nsHTMLReflowMetrics legendDesiredSize(0,0); ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); #ifdef NOISY_REFLOW printf(" returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height); if (legendDesiredSize.mComputeMEW) printf(" and maxEW %d\n", legendDesiredSize.mMaxElementWidth); #endif // figure out the legend's rectangle mLegendRect.width = legendDesiredSize.width + legendMargin.left + legendMargin.right; mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom; mLegendRect.x = borderPadding.left; mLegendRect.y = 0; nscoord oldSpace = mLegendSpace; mLegendSpace = 0; if (mLegendRect.height > border.top) { // center the border on the legend mLegendSpace = mLegendRect.height - border.top; } else { mLegendRect.y = (border.top - mLegendRect.height)/2; } // if the legend space changes then we need to reflow the // content area as well. if (mLegendSpace != oldSpace) { if (reflowContent == PR_FALSE || reason == eReflowReason_Dirty) { reflowContent = PR_TRUE; reason = eReflowReason_Resize; } } // if we are contrained then remove the legend from our available height. if (NS_INTRINSICSIZE != availSize.height) { if (availSize.height >= mLegendSpace) availSize.height -= mLegendSpace; } // don't get any smaller than the legend if (NS_INTRINSICSIZE != availSize.width) { if (availSize.width < mLegendRect.width) availSize.width = mLegendRect.width; } FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState, legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); } } else { mLegendRect.Empty(); mLegendSpace = 0; } nsRect contentRect; // reflow the content frame only if needed if (mContentFrame) { if (reflowContent) { availSize.width = aReflowState.mComputedWidth; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame, availSize, reason); nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); // Reflow the frame ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState, borderPadding.left + kidReflowState.mComputedMargin.left, borderPadding.top + mLegendSpace + kidReflowState.mComputedMargin.top, 0, aStatus); // set the rect. make sure we add the margin back in. contentRect.SetRect(borderPadding.left,borderPadding.top + mLegendSpace,kidDesiredSize.width ,kidDesiredSize.height); if (aReflowState.mComputedHeight != NS_INTRINSICSIZE && borderPadding.top + mLegendSpace+kidDesiredSize.height > aReflowState.mComputedHeight) { kidDesiredSize.height = aReflowState.mComputedHeight-(borderPadding.top + mLegendSpace); } FinishReflowChild(mContentFrame, aPresContext, &kidReflowState, kidDesiredSize, contentRect.x, contentRect.y, 0); if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = kidDesiredSize.mMaxElementWidth; if (eStyleUnit_Coord == aReflowState.mStylePosition->mWidth.GetUnit() && NS_INTRINSICSIZE != aReflowState.mComputedWidth) aDesiredSize.mMaxElementWidth = aReflowState.mComputedWidth; if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()) aDesiredSize.mMaxElementWidth = 0; aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right; } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aDesiredSize.mMaximumWidth = kidDesiredSize.mMaximumWidth + borderPadding.left + borderPadding.right; } NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); } else { // if we don't need to reflow just get the old size contentRect = mContentFrame->GetRect(); const nsStyleMargin* marginStyle = mContentFrame->GetStyleMargin(); nsMargin m(0,0,0,0); marginStyle->GetMargin(m); contentRect.Inflate(m); } } // use the computed width if the inner content does not fill it if (aReflowState.mComputedWidth != NS_INTRINSICSIZE && aReflowState.mComputedWidth > contentRect.width) { contentRect.width = aReflowState.mComputedWidth; } if (mLegendFrame) { // if the content rect is larger then the legend we can align the legend if (contentRect.width > mLegendRect.width) { PRInt32 align = ((nsLegendFrame*)mLegendFrame)->GetAlign(); switch(align) { case NS_STYLE_TEXT_ALIGN_RIGHT: mLegendRect.x = contentRect.width - mLegendRect.width + borderPadding.left; break; case NS_STYLE_TEXT_ALIGN_CENTER: float p2t; p2t = aPresContext->PixelsToTwips(); mLegendRect.x = NSIntPixelsToTwips((nscoord) NSToIntRound((float)(contentRect.width/2 - mLegendRect.width/2 + borderPadding.left) / p2t),p2t); break; } } else { //otherwise make place for the legend contentRect.width = mLegendRect.width; } // place the legend nsRect actualLegendRect(mLegendRect); actualLegendRect.Deflate(legendMargin); nsPoint curOrigin = mLegendFrame->GetPosition(); // only if the origin changed if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) { mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y)); nsContainerFrame::PositionFrameView(mLegendFrame); // We need to recursively process the legend frame's // children since we're moving the frame after Reflow. nsContainerFrame::PositionChildViews(mLegendFrame); } } // Return our size and our result if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) { aDesiredSize.height = mLegendSpace + borderPadding.top + contentRect.height + borderPadding.bottom; } else { nscoord min = borderPadding.top + borderPadding.bottom + mLegendRect.height; aDesiredSize.height = aReflowState.mComputedHeight + borderPadding.top + borderPadding.bottom; if (aDesiredSize.height < min) aDesiredSize.height = min; } aDesiredSize.width = contentRect.width + borderPadding.left + borderPadding.right; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; if (aDesiredSize.mComputeMEW) { // if the legend is wider use it if (aDesiredSize.mMaxElementWidth < mLegendRect.width + borderPadding.left + borderPadding.right) aDesiredSize.mMaxElementWidth = mLegendRect.width + borderPadding.left + borderPadding.right; } aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); // make the mMaximumWidth large enough if the legendframe determines the size if ((aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) && mLegendFrame) { aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, mLegendRect.width + borderPadding.left + borderPadding.right); } if (mLegendFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mLegendFrame); if (mContentFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mContentFrame); FinishAndStoreOverflow(&aDesiredSize); Invalidate(aDesiredSize.mOverflowArea); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }