void TableBackgroundPainter::TranslateContext(nscoord aDX, nscoord aDY) { mRenderPt += nsPoint(aDX, aDY); if (mCols) { TableBackgroundData* lastColGroup = nsnull; for (PRUint32 i = 0; i < mNumCols; i++) { mCols[i].mCol.mRect.MoveBy(-aDX, -aDY); if (lastColGroup != mCols[i].mColGroup) { NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421"); // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix if (!mCols[i].mColGroup) return; mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY); lastColGroup = mCols[i].mColGroup; } } } }
NS_IMETHODIMP nsImageLoader::FrameChanged(imgIRequest *aRequest, imgIContainer *aContainer, const nsIntRect *aDirtyRect) { if (!mFrame) return NS_ERROR_FAILURE; if (!mRequest) { // We're in the middle of a paint anyway return NS_OK; } NS_ASSERTION(aRequest == mRequest, "This is a neat trick."); nsRect r = aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ? nsRect(nsPoint(0, 0), mFrame->GetSize()) : aDirtyRect->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel()); DoRedraw(&r); return NS_OK; }
void ImageDocument::ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage) { float ratio = GetRatio(); if (restoreImage) { RestoreImage(); FlushPendingNotifications(Flush_Layout); } nsCOMPtr<nsIPresShell> shell = GetShell(); if (!shell) return; nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable(); if (!sf) return; nsRect portRect = sf->GetScrollPortRect(); sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2, nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2), nsIScrollableFrame::INSTANT); }
nsPoint nsDOMUIEvent::GetClientPoint() { if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT && mEvent->eventStructType != NS_POPUP_EVENT && mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT && !NS_IS_DRAG_EVENT(mEvent)) || !mPresContext || !((nsGUIEvent*)mEvent)->widget) { return mClientPoint; } nsPoint pt(0, 0); nsIPresShell* shell = mPresContext->GetPresShell(); if (!shell) { return pt; } nsIFrame* rootFrame = shell->GetRootFrame(); if (rootFrame) pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, rootFrame); return nsPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), nsPresContext::AppUnitsToIntCSSPixels(pt.y)); }
NS_IMETHODIMP nsListBoxBodyFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState) { if (mScrolling) aBoxLayoutState.SetPaintingDisabled(true); nsresult rv = nsBoxFrame::DoLayout(aBoxLayoutState); // determine the real height for the scrollable area from the total number // of rows, since non-visible rows don't yet have frames nsRect rect(nsPoint(0, 0), GetSize()); nsOverflowAreas overflow(rect, rect); if (mLayoutManager) { nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { ConsiderChildOverflow(overflow, childFrame); childFrame = childFrame->GetNextSibling(); } nsSize prefSize = mLayoutManager->GetPrefSize(this, aBoxLayoutState); NS_FOR_FRAME_OVERFLOW_TYPES(otype) { nsRect& o = overflow.Overflow(otype); o.height = NS_MAX(o.height, prefSize.height); } } FinishAndStoreOverflow(overflow, GetSize()); if (mScrolling) aBoxLayoutState.SetPaintingDisabled(false); // if we are scrolled and the row height changed // make sure we are scrolled to a correct index. if (mAdjustScroll) PostReflowCallback(); return rv; }
/** * Restore information about floats into the float manager for an * incremental reflow, and simultaneously push the floats by * |aDeltaY|, which is the amount |aLine| was pushed relative to its * parent. The recovery of state is one of the things that makes * incremental reflow O(N^2) and this state should really be kept * around, attached to the frame tree. */ void nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine, nscoord aDeltaY) { if (aLine->HasFloats()) { // Place the floats into the space-manager again. Also slide // them, just like the regular frames on the line. nsFloatCache* fc = aLine->GetFirstFloat(); while (fc) { nsIFrame* floatFrame = fc->mFloat; if (aDeltaY != 0) { nsPoint p = floatFrame->GetPosition(); floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY)); nsContainerFrame::PositionFrameView(floatFrame); nsContainerFrame::PositionChildViews(floatFrame); } #ifdef DEBUG if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) { nscoord tx, ty; mFloatManager->GetTranslation(tx, ty); nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); printf("RecoverFloats: txy=%d,%d (%d,%d) ", tx, ty, mFloatManagerX, mFloatManagerY); nsFrame::ListTag(stdout, floatFrame); nsRect region = nsFloatManager::GetRegionFor(floatFrame); printf(" aDeltaY=%d region={%d,%d,%d,%d}\n", aDeltaY, region.x, region.y, region.width, region.height); } #endif mFloatManager->AddFloat(floatFrame, nsFloatManager::GetRegionFor(floatFrame)); fc = fc->Next(); } } else if (aLine->IsBlock()) { nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager); } }
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; }
static void AdjustChildWidgets(nsView *aView, nsPoint aWidgetToParentViewOrigin, float aScale, PRBool aInvalidate) { if (aView->HasWidget()) { nsIWidget* widget = aView->GetWidget(); nsWindowType type; widget->GetWindowType(type); if (type != eWindowType_popup) { nsRect bounds = aView->GetBounds(); nsPoint widgetOrigin = aWidgetToParentViewOrigin + nsPoint(bounds.x, bounds.y); widget->Move(NSTwipsToIntPixels(widgetOrigin.x, aScale), NSTwipsToIntPixels(widgetOrigin.y, aScale)); if (aInvalidate) { // Force the widget and everything in it to repaint. We can't // just use Invalidate because the widget might have child // widgets and they wouldn't get updated. We can't call // UpdateView(aView) because the area to be repainted might be // outside aView's clipped bounds. This isn't the greatest way // to achieve this, perhaps, but it works. widget->Show(PR_FALSE); widget->Show(PR_TRUE); } } } else { // Don't recurse if the view has a widget, because we adjusted the view's // widget position, and its child widgets are relative to its positon nsPoint widgetToViewOrigin = aWidgetToParentViewOrigin + aView->GetPosition(); for (nsView* kid = aView->GetFirstChild(); kid; kid = kid->GetNextSibling()) { AdjustChildWidgets(kid, widgetToViewOrigin, aScale, aInvalidate); } } }
// exported routine that both munderover and msubsup share. // munderover uses this when movablelimits is set. nsresult nsMathMLmsubsupFrame::PlaceSubSupScript(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, PRBool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, nsMathMLContainerFrame* aFrame, nscoord aUserSubScriptShift, nscoord aUserSupScriptShift, nscoord aScriptSpace) { // force the scriptSpace to be atleast 1 pixel nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); aScriptSpace = NS_MAX(onePixel, aScriptSpace); //////////////////////////////////// // Get the children's desired sizes nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics subScriptSize; nsHTMLReflowMetrics supScriptSize; nsBoundingMetrics bmBase, bmSubScript, bmSupScript; nsIFrame* subScriptFrame = nsnull; nsIFrame* supScriptFrame = nsnull; nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); if (baseFrame) subScriptFrame = baseFrame->GetNextSibling(); if (subScriptFrame) supScriptFrame = subScriptFrame->GetNextSibling(); if (!baseFrame || !subScriptFrame || !supScriptFrame || supScriptFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order return aFrame->ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); // get the subdrop from the subscript font nscoord subDrop; GetSubDropFromChild(subScriptFrame, subDrop); // parameter v, Rule 18a, App. G, TeXbook nscoord minSubScriptShift = bmBase.descent + subDrop; // get the supdrop from the supscript font nscoord supDrop; GetSupDropFromChild(supScriptFrame, supDrop); // parameter u, Rule 18a, App. G, TeXbook nscoord minSupScriptShift = bmBase.ascent - supDrop; ////////////////// // Place Children ////////////////// ////////////////////////////////////////////////// // Get subscript shift // slightly different from nsMathMLmsubFrame.cpp ////////////////////////////////////////////////// // subScriptShift{1,2} // = minimum amount to shift the subscript down // = sub{1,2} in TeXbook // subScriptShift1 = subscriptshift attribute * x-height nscoord subScriptShift1, subScriptShift2; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); // get x-height (an ex) nscoord xHeight = fm->XHeight(); nscoord ruleSize; GetRuleThickness (aRenderingContext, fm, ruleSize); // Get subScriptShift{1,2} default from font GetSubScriptShifts (fm, subScriptShift1, subScriptShift2); if (0 < aUserSubScriptShift) { // the user has set the subscriptshift attribute float scaler = ((float) subScriptShift2) / subScriptShift1; subScriptShift1 = NS_MAX(subScriptShift1, aUserSubScriptShift); subScriptShift2 = NSToCoordRound(scaler * subScriptShift1); } // get a tentative value for subscriptshift // Rule 18d, App. G, TeXbook nscoord subScriptShift = NS_MAX(minSubScriptShift,NS_MAX(subScriptShift1,subScriptShift2)); ////////////////////////////////////////////////// // Get supscript shift // same code from nsMathMLmsupFrame.cpp ////////////////////////////////////////////////// // get min supscript shift limit from x-height // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook nscoord minShiftFromXHeight = (nscoord) (bmSupScript.descent + (1.0f/4.0f) * xHeight); // supScriptShift{1,2,3} // = minimum amount to shift the supscript up // = sup{1,2,3} in TeX // supScriptShift1 = superscriptshift attribute * x-height // Note that there are THREE values for supscript shifts depending // on the current style nscoord supScriptShift1, supScriptShift2, supScriptShift3; // Set supScriptShift{1,2,3} default from font GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); if (0 < aUserSupScriptShift) { // the user has set the superscriptshift attribute float scaler2 = ((float) supScriptShift2) / supScriptShift1; float scaler3 = ((float) supScriptShift3) / supScriptShift1; supScriptShift1 = NS_MAX(supScriptShift1, aUserSupScriptShift); supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1); supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1); } // get sup script shift depending on current script level and display style // Rule 18c, App. G, TeXbook nscoord supScriptShift; nsPresentationData presentationData; aFrame->GetPresentationData(presentationData); if ( aFrame->GetStyleFont()->mScriptLevel == 0 && NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) && !NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style D in TeXbook supScriptShift = supScriptShift1; } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) { // Style C' in TeXbook = D',T',S',SS' supScriptShift = supScriptShift3; } else { // everything else = T,S,SS supScriptShift = supScriptShift2; } // get tentative value for superscriptshift // Rule 18c, App. G, TeXbook supScriptShift = NS_MAX(minSupScriptShift,NS_MAX(supScriptShift,minShiftFromXHeight)); ////////////////////////////////////////////////// // Negotiate between supScriptShift and subScriptShift // so that there will be enough gap between them // Rule 18e, App. G, TeXbook ////////////////////////////////////////////////// nscoord gap = (supScriptShift - bmSupScript.descent) - (bmSubScript.ascent - subScriptShift); if (gap < 4.0f * ruleSize) { // adjust subScriptShift to get a gap of (4.0 * ruleSize) subScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap); } // next we want to ensure that the bottom of the superscript // will be > (4/5) * x-height above baseline gap = NSToCoordRound ((4.0f/5.0f) * xHeight - (supScriptShift - bmSupScript.descent)); if (gap > 0) { supScriptShift += gap; subScriptShift -= gap; } ////////////////////////////////////////////////// // Do the Placing ////////////////////////////////////////////////// // get bounding box for base + subscript + superscript nsBoundingMetrics boundingMetrics; boundingMetrics.ascent = NS_MAX(bmBase.ascent, (bmSupScript.ascent + supScriptShift)); boundingMetrics.descent = NS_MAX(bmBase.descent, (bmSubScript.descent + subScriptShift)); // leave aScriptSpace after both super/subscript // add italicCorrection between base and superscript // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we // estimate the italic creation ourselves and it isn't the same as TeX nscoord italicCorrection; GetItalicCorrection(bmBase, italicCorrection); italicCorrection += onePixel; boundingMetrics.width = bmBase.width + aScriptSpace + NS_MAX((italicCorrection + bmSupScript.width), bmSubScript.width); boundingMetrics.leftBearing = bmBase.leftBearing; boundingMetrics.rightBearing = bmBase.width + NS_MAX((italicCorrection + bmSupScript.rightBearing), bmSubScript.rightBearing); aFrame->SetBoundingMetrics(boundingMetrics); // reflow metrics aDesiredSize.ascent = NS_MAX(baseSize.ascent, NS_MAX(subScriptSize.ascent - subScriptShift, supScriptSize.ascent + supScriptShift)); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(baseSize.height - baseSize.ascent, NS_MAX(subScriptSize.height - subScriptSize.ascent + subScriptShift, supScriptSize.height - subScriptSize.ascent - supScriptShift)); aDesiredSize.width = boundingMetrics.width; aDesiredSize.mBoundingMetrics = boundingMetrics; aFrame->SetReference(nsPoint(0, aDesiredSize.ascent)); if (aPlaceOrigin) { nscoord dx, dy; // now place the base ... dx = 0; dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild(baseFrame, aPresContext, nsnull, baseSize, dx, dy, 0); // ... and subscript dx = bmBase.width; dy = aDesiredSize.ascent - (subScriptSize.ascent - subScriptShift); FinishReflowChild(subScriptFrame, aPresContext, nsnull, subScriptSize, dx, dy, 0); // ... and the superscript dx = bmBase.width + italicCorrection; dy = aDesiredSize.ascent - (supScriptSize.ascent + supScriptShift); FinishReflowChild(supScriptFrame, aPresContext, nsnull, supScriptSize, dx, dy, 0); } return NS_OK; }
// exported routine that both munder and msub share. // munder uses this when movablelimits is set. nsresult nsMathMLmsubFrame::PlaceSubScript (nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, nsMathMLContainerFrame* aFrame, nscoord aUserSubScriptShift, nscoord aScriptSpace) { // force the scriptSpace to be atleast 1 pixel aScriptSpace = NS_MAX(nsPresContext::CSSPixelsToAppUnits(1), aScriptSpace); //////////////////////////////////// // Get the children's desired sizes nsBoundingMetrics bmBase, bmSubScript; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics subScriptSize; nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); nsIFrame* subScriptFrame = nullptr; if (baseFrame) subScriptFrame = baseFrame->GetNextSibling(); if (!baseFrame || !subScriptFrame || subScriptFrame->GetNextSibling()) { // report an error, encourage people to get their markups in order if (aPlaceOrigin) { aFrame->ReportChildCountError(); } return aFrame->ReflowError(aRenderingContext, aDesiredSize); } GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); // get the subdrop from the subscript font nscoord subDrop; GetSubDropFromChild(subScriptFrame, subDrop); // parameter v, Rule 18a, App. G, TeXbook nscoord minSubScriptShift = bmBase.descent + subDrop; ////////////////// // Place Children // get min subscript shift limit from x-height // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook nscoord xHeight = 0; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); xHeight = fm->XHeight(); nscoord minShiftFromXHeight = (nscoord) (bmSubScript.ascent - (4.0f/5.0f) * xHeight); // subScriptShift // = minimum amount to shift the subscript down set by user or from the font // = sub1 in TeX // = subscriptshift attribute * x-height nscoord subScriptShift, dummy; // get subScriptShift default from font GetSubScriptShifts (fm, subScriptShift, dummy); subScriptShift = NS_MAX(subScriptShift, aUserSubScriptShift); // get actual subscriptshift to be used // Rule 18b, App. G, TeXbook nscoord actualSubScriptShift = NS_MAX(minSubScriptShift,NS_MAX(subScriptShift,minShiftFromXHeight)); // get bounding box for base + subscript nsBoundingMetrics boundingMetrics; boundingMetrics.ascent = NS_MAX(bmBase.ascent, bmSubScript.ascent - actualSubScriptShift); boundingMetrics.descent = NS_MAX(bmBase.descent, bmSubScript.descent + actualSubScriptShift); // add aScriptSpace to the subscript's width boundingMetrics.width = bmBase.width + bmSubScript.width + aScriptSpace; boundingMetrics.leftBearing = bmBase.leftBearing; boundingMetrics.rightBearing = NS_MAX(bmBase.rightBearing, bmBase.width + NS_MAX(bmSubScript.width + aScriptSpace, bmSubScript.rightBearing)); aFrame->SetBoundingMetrics (boundingMetrics); // reflow metrics aDesiredSize.ascent = NS_MAX(baseSize.ascent, subScriptSize.ascent - actualSubScriptShift); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(baseSize.height - baseSize.ascent, subScriptSize.height - subScriptSize.ascent + actualSubScriptShift); aDesiredSize.width = boundingMetrics.width; aDesiredSize.mBoundingMetrics = boundingMetrics; aFrame->SetReference(nsPoint(0, aDesiredSize.ascent)); if (aPlaceOrigin) { nscoord dx, dy; // now place the base ... dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0); dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize, dx, dy, 0); // ... and subscript dx = aFrame->MirrorIfRTL(aDesiredSize.width, subScriptSize.width, bmBase.width); dy = aDesiredSize.ascent - (subScriptSize.ascent - actualSubScriptShift); FinishReflowChild (subScriptFrame, aPresContext, nullptr, subScriptSize, dx, dy, 0); } return NS_OK; }
NS_IMETHODIMP nsSimplePageSequenceFrame::PrintNextPage() { // Print each specified page // pageNum keeps track of the current page and what pages are printing // // printedPageNum keeps track of the current page number to be printed // Note: When print al the pages or a page range the printed page shows the // actual page number, when printing selection it prints the page number starting // with the first page of the selection. For example if the user has a // selection that starts on page 2 and ends on page 3, the page numbers when // print are 1 and then two (which is different than printing a page range, where // the page numbers would have been 2 and then 3) if (mCurrentPageFrame == nsnull) { return NS_ERROR_FAILURE; } PRBool printEvenPages, printOddPages; mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintEvenPages, &printEvenPages); mPageData->mPrintSettings->GetPrintOptions(nsIPrintSettings::kPrintOddPages, &printOddPages); // Begin printing of the document nsDeviceContext *dc = PresContext()->DeviceContext(); nsresult rv = NS_OK; // See whether we should print this page mPrintThisPage = PR_TRUE; // If printing a range of pages check whether the page number is in the // range of pages to print if (mDoingPageRange) { if (mPageNum < mFromPageNum) { mPrintThisPage = PR_FALSE; } else if (mPageNum > mToPageNum) { mPageNum++; mCurrentPageFrame = nsnull; return NS_OK; } } // Check for printing of odd and even pages if (mPageNum & 0x1) { if (!printOddPages) { mPrintThisPage = PR_FALSE; // don't print odd numbered page } } else { if (!printEvenPages) { mPrintThisPage = PR_FALSE; // don't print even numbered page } } if (nsIPrintSettings::kRangeSelection == mPrintRangeType) { mPrintThisPage = PR_TRUE; } if (mPrintThisPage) { // XXX This is temporary fix for printing more than one page of a selection // This does a poor man's "dump" pagination (see Bug 89353) // It has laid out as one long page and now we are just moving or view up/down // one page at a time and printing the contents of what is exposed by the rect. // currently this does not work for IFrames // I will soon improve this to work with IFrames PRBool continuePrinting = PR_TRUE; nscoord width, height; width = PresContext()->GetPageSize().width; height = PresContext()->GetPageSize().height; height -= mMargin.top + mMargin.bottom; width -= mMargin.left + mMargin.right; nscoord selectionY = height; nsIFrame* conFrame = mCurrentPageFrame->GetFirstChild(nsnull); if (mSelectionHeight >= 0) { conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -mYSelOffset)); nsContainerFrame::PositionChildViews(conFrame); } // cast the frame to be a page frame nsPageFrame * pf = static_cast<nsPageFrame*>(mCurrentPageFrame); pf->SetPageNumInfo(mPageNum, mTotalPages); pf->SetSharedPageData(mPageData); PRInt32 printedPageNum = 1; while (continuePrinting) { if (PresContext()->IsRootPaginatedDocument()) { PR_PL(("\n")); PR_PL(("***************** BeginPage *****************\n")); rv = dc->BeginPage(); NS_ENSURE_SUCCESS(rv, rv); } PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum)); nsRefPtr<nsRenderingContext> renderingContext; dc->CreateRenderingContext(*getter_AddRefs(renderingContext)); NS_ENSURE_TRUE(renderingContext, NS_ERROR_OUT_OF_MEMORY); #if defined(XP_UNIX) && !defined(XP_MACOSX) // On linux, need to rotate landscape-mode output on printed surfaces PRInt32 orientation; mPageData->mPrintSettings->GetOrientation(&orientation); if (nsIPrintSettings::kLandscapeOrientation == orientation) { // Shift up by one landscape-page-height (in points) before we rotate. float offset = POINTS_PER_INCH_FLOAT * (mCurrentPageFrame->GetSize().height / float(dc->AppUnitsPerCSSInch())); renderingContext->ThebesContext()->Translate(gfxPoint(offset, 0)); renderingContext->ThebesContext()->Rotate(M_PI/2); } #endif // XP_UNIX && !XP_MACOSX nsRect drawingRect(nsPoint(0, 0), mCurrentPageFrame->GetSize()); nsRegion drawingRegion(drawingRect); nsLayoutUtils::PaintFrame(renderingContext, mCurrentPageFrame, drawingRegion, NS_RGBA(0,0,0,0), nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES); if (mSelectionHeight >= 0 && selectionY < mSelectionHeight) { selectionY += height; printedPageNum++; pf->SetPageNumInfo(printedPageNum, mTotalPages); conFrame->SetPosition(conFrame->GetPosition() + nsPoint(0, -height)); nsContainerFrame::PositionChildViews(conFrame); PR_PL(("***************** End Page (PrintNextPage) *****************\n")); rv = dc->EndPage(); NS_ENSURE_SUCCESS(rv, rv); } else { continuePrinting = PR_FALSE; } } } return rv; }
void nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, const nsRect& aContainingBlock, bool aConstrainHeight, nsIFrame* aKidFrame, nsReflowStatus& aStatus, nsOverflowAreas* aOverflowAreas) { #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } char width[16]; char height[16]; PrettyUC(aReflowState.AvailableWidth(), width); PrettyUC(aReflowState.AvailableHeight(), height); printf(" a=%s,%s ", width, height); PrettyUC(aReflowState.ComputedWidth(), width); PrettyUC(aReflowState.ComputedHeight(), height); printf("c=%s,%s \n", width, height); } AutoNoisyIndenter indent(nsBlockFrame::gNoisy); #endif // DEBUG nscoord availWidth = aContainingBlock.width; if (availWidth == -1) { NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE, "Must have a useful width _somewhere_"); availWidth = aReflowState.ComputedWidth() + aReflowState.ComputedPhysicalPadding().LeftRight(); } nsHTMLReflowMetrics kidDesiredSize(aReflowState); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame, nsSize(availWidth, NS_UNCONSTRAINEDSIZE), aContainingBlock.width, aContainingBlock.height); // Send the WillReflow() notification and position the frame aKidFrame->WillReflow(aPresContext); // Get the border values const nsMargin& border = aReflowState.mStyleBorder->GetComputedBorder(); bool constrainHeight = (aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) && aConstrainHeight // Don't split if told not to (e.g. for fixed frames) && (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame) //XXX we don't handle splitting frames for inline absolute containing blocks yet && (aKidFrame->GetRect().y <= aReflowState.AvailableHeight()); // Don't split things below the fold. (Ideally we shouldn't *have* // anything totally below the fold, but we can't position frames // across next-in-flow breaks yet. if (constrainHeight) { kidReflowState.AvailableHeight() = aReflowState.AvailableHeight() - border.top - kidReflowState.ComputedPhysicalMargin().top; if (NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().top) kidReflowState.AvailableHeight() -= kidReflowState.ComputedPhysicalOffsets().top; } // Do the reflow 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.ComputedPhysicalOffsets().left) || (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top)) { nscoord aContainingBlockWidth = aContainingBlock.width; nscoord aContainingBlockHeight = aContainingBlock.height; if (-1 == aContainingBlockWidth) { // Get the containing block width/height kidReflowState.ComputeContainingBlockRectangle(aPresContext, &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().left) { NS_ASSERTION(NS_AUTOOFFSET != kidReflowState.ComputedPhysicalOffsets().right, "Can't solve for both left and right"); kidReflowState.ComputedPhysicalOffsets().left = aContainingBlockWidth - kidReflowState.ComputedPhysicalOffsets().right - kidReflowState.ComputedPhysicalMargin().right - kidDesiredSize.Width() - kidReflowState.ComputedPhysicalMargin().left; } if (NS_AUTOOFFSET == kidReflowState.ComputedPhysicalOffsets().top) { kidReflowState.ComputedPhysicalOffsets().top = aContainingBlockHeight - kidReflowState.ComputedPhysicalOffsets().bottom - kidReflowState.ComputedPhysicalMargin().bottom - kidDesiredSize.Height() - kidReflowState.ComputedPhysicalMargin().top; } } // Position the child relative to our padding edge nsRect rect(border.left + kidReflowState.ComputedPhysicalOffsets().left + kidReflowState.ComputedPhysicalMargin().left, border.top + kidReflowState.ComputedPhysicalOffsets().top + kidReflowState.ComputedPhysicalMargin().top, kidDesiredSize.Width(), kidDesiredSize.Height()); // Offset the frame rect by the given origin of the absolute containing block. // If the frame is auto-positioned on both sides of an axis, it will be // positioned based on its containing block and we don't need to offset. if (aContainingBlock.TopLeft() != nsPoint(0, 0)) { if (!(kidReflowState.mStylePosition->mOffset.GetLeftUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetRightUnit() == eStyleUnit_Auto)) { rect.x += aContainingBlock.x; } if (!(kidReflowState.mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Auto && kidReflowState.mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Auto)) { rect.y += aContainingBlock.y; } } aKidFrame->SetRect(rect); nsView* view = aKidFrame->GetView(); if (view) { // Size and position the view and set its opacity, visibility, content // transparency, and clip nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aKidFrame, view, kidDesiredSize.VisualOverflow()); } else { nsContainerFrame::PositionChildViews(aKidFrame); } aKidFrame->DidReflow(aPresContext, &kidReflowState, nsDidReflowStatus::FINISHED); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow) { nsFrame::IndentBy(stdout,nsBlockFrame::gNoiseIndent - 1); printf("abs pos "); if (aKidFrame) { nsAutoString name; aKidFrame->GetFrameName(name); printf("%s ", NS_LossyConvertUTF16toASCII(name).get()); } printf("%p rect=%d,%d,%d,%d\n", static_cast<void*>(aKidFrame), rect.x, rect.y, rect.width, rect.height); } #endif if (aOverflowAreas) { aOverflowAreas->UnionWith(kidDesiredSize.mOverflowAreas + rect.TopLeft()); } }
NS_IMETHODIMP nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { 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", aReflowState.availableWidth, aReflowState.availableHeight)); aStatus = NS_FRAME_COMPLETE; NS_ASSERTION(aPresContext->GetPresShell()->GetPrimaryFrameFor(mContent) == this, "Shouldn't happen"); // "offset" is the offset of our content area from our frame's // top-left corner. nsPoint offset(0, 0); if (IsInline()) { // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed> nsresult rv = nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState, aStatus); NS_ENSURE_SUCCESS(rv, rv); offset = nsPoint(aReflowState.mComputedBorderPadding.left, aReflowState.mComputedBorderPadding.top); } else { // HTML <frame> SizeToAvailSize(aReflowState, aDesiredSize); } nsSize innerSize(aDesiredSize.width, aDesiredSize.height); if (IsInline()) { innerSize.width -= aReflowState.mComputedBorderPadding.LeftRight(); innerSize.height -= aReflowState.mComputedBorderPadding.TopBottom(); } if (mInnerView) { nsIViewManager* vm = mInnerView->GetViewManager(); vm->MoveViewTo(mInnerView, offset.x, offset.y); vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE); } // Determine if we need to repaint our border, background or outline CheckInvalidateSizeChange(aDesiredSize); FinishAndStoreOverflow(&aDesiredSize); // Invalidate the frame contents // XXX is this really needed? nsRect rect(nsPoint(0, 0), GetSize()); Invalidate(rect); if (!aPresContext->IsPaginated() && !mPostedReflowCallback) { PresContext()->PresShell()->PostReflowCallback(this); mPostedReflowCallback = PR_TRUE; } // 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", aDesiredSize.width, aDesiredSize.height, aStatus)); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
void nsTableCellFrame::VerticallyAlignChild(const nsHTMLReflowState& aReflowState, nscoord aMaxAscent) { const nsStyleTextReset* textStyle = GetStyleTextReset(); /* XXX: remove tableFrame when border-collapse inherits */ nsPresContext* presContext = GetPresContext(); GET_PIXELS_TO_TWIPS(presContext, p2t); nsMargin borderPadding = nsTableFrame::GetBorderPadding(aReflowState, p2t, this); nscoord topInset = borderPadding.top; nscoord bottomInset = borderPadding.bottom; // As per bug 10207, we map 'sub', 'super', 'text-top', 'text-bottom', // length and percentage values to 'baseline' // XXX It seems that we don't get to see length and percentage values here // because the Style System has already fixed the error and mapped them // to whatever is inherited from the parent, i.e, 'middle' in most cases. PRUint8 verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_BASELINE; if (textStyle->mVerticalAlign.GetUnit() == eStyleUnit_Enumerated) { verticalAlignFlags = textStyle->mVerticalAlign.GetIntValue(); if (verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_TOP && verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_MIDDLE && verticalAlignFlags != NS_STYLE_VERTICAL_ALIGN_BOTTOM) { verticalAlignFlags = NS_STYLE_VERTICAL_ALIGN_BASELINE; } } nscoord height = mRect.height; nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); nsRect kidRect = firstKid->GetRect(); nscoord childHeight = kidRect.height; // Vertically align the child nscoord kidYTop = 0; switch (verticalAlignFlags) { case NS_STYLE_VERTICAL_ALIGN_BASELINE: // Align the baselines of the child frame with the baselines of // other children in the same row which have 'vertical-align: baseline' kidYTop = topInset + aMaxAscent - GetDesiredAscent(); break; case NS_STYLE_VERTICAL_ALIGN_TOP: // Align the top of the child frame with the top of the content area, kidYTop = topInset; break; case NS_STYLE_VERTICAL_ALIGN_BOTTOM: // Align the bottom of the child frame with the bottom of the content area, kidYTop = height - childHeight - bottomInset; break; default: case NS_STYLE_VERTICAL_ALIGN_MIDDLE: // Align the middle of the child frame with the middle of the content area, kidYTop = (height - childHeight - bottomInset + topInset) / 2; kidYTop = nsTableFrame::RoundToPixel(kidYTop, presContext->ScaledPixelsToTwips(), eAlwaysRoundDown); } // if the content is larger than the cell height align from top kidYTop = PR_MAX(0, kidYTop); firstKid->SetPosition(nsPoint(kidRect.x, kidYTop)); nsHTMLReflowMetrics desiredSize(PR_FALSE); desiredSize.width = mRect.width; desiredSize.height = mRect.height; GetSelfOverflow(desiredSize.mOverflowArea); ConsiderChildOverflow(desiredSize.mOverflowArea, firstKid); FinishAndStoreOverflow(&desiredSize); if (kidYTop != kidRect.y) { // Make sure any child views are correctly positioned. We know the inner table // cell won't have a view nsContainerFrame::PositionChildViews(firstKid); } if (HasView()) { nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, GetView(), &desiredSize.mOverflowArea, 0); } }
static nsIFrame* GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs, nsIFrame* aRestrictToDescendants, nsIContent* aClickableAncestor, nsTArray<nsIFrame*>& aCandidates, int32_t* aElementsInCluster) { std::vector<nsIContent*> mContentsInCluster; // List of content elements in the cluster without duplicate nsIFrame* bestTarget = nullptr; // Lower is better; distance is in appunits float bestDistance = 1e6f; nsRegion exposedRegion(aTargetRect); for (uint32_t i = 0; i < aCandidates.Length(); ++i) { nsIFrame* f = aCandidates[i]; PET_LOG("Checking candidate %p\n", f); bool preservesAxisAlignedRectangles = false; nsRect borderBox = nsLayoutUtils::TransformFrameRectToAncestor(f, nsRect(nsPoint(0, 0), f->GetSize()), aRoot, &preservesAxisAlignedRectangles); nsRegion region; region.And(exposedRegion, borderBox); if (region.IsEmpty()) { PET_LOG(" candidate %p had empty hit region\n", f); continue; } if (preservesAxisAlignedRectangles) { // Subtract from the exposed region if we have a transform that won't make // the bounds include a bunch of area that we don't actually cover. SubtractFromExposedRegion(&exposedRegion, region); } nsAutoString labelTargetId; if (aClickableAncestor && !IsDescendant(f, aClickableAncestor, &labelTargetId)) { PET_LOG(" candidate %p is not a descendant of required ancestor\n", f); continue; } nsIContent* clickableContent = GetClickableAncestor(f, nsGkAtoms::body, &labelTargetId); if (!aClickableAncestor && !clickableContent) { PET_LOG(" candidate %p was not clickable\n", f); continue; } // If our current closest frame is a descendant of 'f', skip 'f' (prefer // the nested frame). if (bestTarget && nsLayoutUtils::IsProperAncestorFrameCrossDoc(f, bestTarget, aRoot)) { PET_LOG(" candidate %p was ancestor for bestTarget %p\n", f, bestTarget); continue; } if (!aClickableAncestor && !nsLayoutUtils::IsAncestorFrameCrossDoc(aRestrictToDescendants, f, aRoot)) { PET_LOG(" candidate %p was not descendant of restrictroot %p\n", f, aRestrictToDescendants); continue; } // If the first clickable ancestor of f is a label element // and "for" attribute is present in label element, search the frame list for the "for" element // If this element is present in the current list, do not count the frame in // the cluster elements counter if ((labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) && !IsLargeElement(f, aPrefs)) { if (std::find(mContentsInCluster.begin(), mContentsInCluster.end(), clickableContent) == mContentsInCluster.end()) { mContentsInCluster.push_back(clickableContent); } } // distance is in appunits float distance = ComputeDistanceFromRegion(aPointRelativeToRootFrame, region); nsIContent* content = f->GetContent(); if (content && content->IsElement() && content->AsElement()->State().HasState( EventStates(NS_EVENT_STATE_VISITED))) { distance *= aPrefs->mVisitedWeight / 100.0f; } if (distance < bestDistance) { PET_LOG(" candidate %p is the new best\n", f); bestDistance = distance; bestTarget = f; } } *aElementsInCluster = mContentsInCluster.size(); return bestTarget; }
// Recursively create a new array of scrollables, preserving any scrollables // that are still in the layer tree. // // aXScale and aYScale are used to calculate any values that need to be in // chrome-document CSS pixels and aren't part of the rendering loop, such as // the initial scroll offset for a new view. static void BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews, nsFrameLoader* aFrameLoader, Layer* aLayer, float aXScale = 1, float aYScale = 1, float aAccConfigXScale = 1, float aAccConfigYScale = 1) { ContainerLayer* container = aLayer->AsContainerLayer(); if (!container) return; const FrameMetrics metrics = container->GetFrameMetrics(); const ViewID scrollId = metrics.mScrollId; const gfx3DMatrix transform = aLayer->GetTransform(); aXScale *= GetXScale(transform); aYScale *= GetYScale(transform); if (metrics.IsScrollable()) { nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent() ->PresContext()->AppUnitsPerDevPixel(); nsContentView* view = FindViewForId(oldContentViews, scrollId); if (view) { // View already exists. Be sure to propagate scales for any values // that need to be calculated something in chrome-doc CSS pixels. ViewConfig config = view->GetViewConfig(); aXScale *= config.mXScale; aYScale *= config.mYScale; view->mFrameLoader = aFrameLoader; // If scale has changed, then we should update // current scroll offset to new scaled value if (aAccConfigXScale != view->mParentScaleX || aAccConfigYScale != view->mParentScaleY) { float xscroll = 0, yscroll = 0; view->GetScrollX(&xscroll); view->GetScrollY(&yscroll); xscroll = xscroll * (aAccConfigXScale / view->mParentScaleX); yscroll = yscroll * (aAccConfigYScale / view->mParentScaleY); view->ScrollTo(xscroll, yscroll); view->mParentScaleX = aAccConfigXScale; view->mParentScaleY = aAccConfigYScale; } // Collect only config scale values for scroll compensation aAccConfigXScale *= config.mXScale; aAccConfigYScale *= config.mYScale; } else { // View doesn't exist, so generate one. We start the view scroll offset at // the same position as the framemetric's scroll offset from the layer. // The default scale is 1, so no need to propagate scale down. ViewConfig config; config.mScrollOffset = nsPoint( NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.x, auPerDevPixel) * aXScale, NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.y, auPerDevPixel) * aYScale); view = new nsContentView(aFrameLoader, scrollId, config); view->mParentScaleX = aAccConfigXScale; view->mParentScaleY = aAccConfigYScale; } view->mViewportSize = nsSize( NSIntPixelsToAppUnits(metrics.mViewport.width, auPerDevPixel) * aXScale, NSIntPixelsToAppUnits(metrics.mViewport.height, auPerDevPixel) * aYScale); view->mContentSize = nsSize( nsPresContext::CSSPixelsToAppUnits(metrics.mCSSContentSize.width) * aXScale, nsPresContext::CSSPixelsToAppUnits(metrics.mCSSContentSize.height) * aYScale); newContentViews[scrollId] = view; } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child, aXScale, aYScale, aAccConfigXScale, aAccConfigYScale); } }
NS_IMETHODIMP nsMathMLmfencedFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv; aDesiredSize.width = aDesiredSize.height = 0; aDesiredSize.ascent = 0; aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); PRInt32 i; const nsStyleFont* font = GetStyleFont(); nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aReflowState.rendContext->SetFont(fm); nscoord axisHeight, em; GetAxisHeight(*aReflowState.rendContext, fm, axisHeight); GetEmHeight(fm, em); // leading to be left at the top and the bottom of stretched chars nscoord leading = NSToCoordRound(0.2f * em); ///////////// // Reflow children // Asking each child to cache its bounding metrics // Note that we don't use the base method nsMathMLContainerFrame::Reflow() // because we want to stretch our fences, separators and stretchy frames using // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base // method here, our stretchy frames will be stretched and placed, and we may // end up stretching our fences/separators with a different aDesiredSize. // XXX The above decision was revisited in bug 121748 and this code can be // refactored to use nsMathMLContainerFrame::Reflow() at some stage. nsReflowStatus childStatus; nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); nsIFrame* firstChild = GetFirstChild(nsnull); nsIFrame* childFrame = firstChild; nscoord ascent = 0, descent = 0; if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) { // We use the ASCII metrics to get our minimum height. This way, // if we have borders or a background, they will fit better with // other elements on the line. ascent = fm->MaxAscent(); descent = fm->MaxDescent(); } while (childFrame) { nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, childStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status"); if (NS_FAILED(rv)) { // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(firstChild, childFrame); return rv; } SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent; if (descent < childDescent) descent = childDescent; if (ascent < childDesiredSize.ascent) ascent = childDesiredSize.ascent; childFrame = childFrame->GetNextSibling(); } ///////////// // Ask stretchy children to stretch themselves nsBoundingMetrics containerSize; nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL; GetPreferredStretchSize(*aReflowState.rendContext, 0, /* i.e., without embellishments */ stretchDir, containerSize); childFrame = firstChild; while (childFrame) { nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame); if (mathmlChild) { nsHTMLReflowMetrics childDesiredSize; // retrieve the metrics that was stored at the previous pass GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); mathmlChild->Stretch(*aReflowState.rendContext, stretchDir, containerSize, childDesiredSize); // store the updated metrics SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent; if (descent < childDescent) descent = childDescent; if (ascent < childDesiredSize.ascent) ascent = childDesiredSize.ascent; } childFrame = childFrame->GetNextSibling(); } // bug 121748: for surrounding fences & separators, use a size that covers everything GetPreferredStretchSize(*aReflowState.rendContext, STRETCH_CONSIDER_EMBELLISHMENTS, stretchDir, containerSize); ////////////////////////////////////////// // Prepare the opening fence, separators, and closing fence, and // adjust the origin of children. // we need to center around the axis nscoord delta = NS_MAX(containerSize.ascent - axisHeight, containerSize.descent + axisHeight); containerSize.ascent = delta + axisHeight; containerSize.descent = delta - axisHeight; ///////////////// // opening fence ... ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent); ///////////////// // separators ... for (i = 0; i < mSeparatorsCount; i++) { ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i], NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent); } ///////////////// // closing fence ... ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent); ////////////////// // Adjust the origins of each child. // and update our bounding metrics i = 0; nscoord dx = 0; nsBoundingMetrics bm; PRBool firstTime = PR_TRUE; if (mOpenChar) { PlaceChar(mOpenChar, ascent, bm, dx); aDesiredSize.mBoundingMetrics = bm; firstTime = PR_FALSE; } childFrame = firstChild; while (childFrame) { nsHTMLReflowMetrics childSize; GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); if (firstTime) { firstTime = PR_FALSE; aDesiredSize.mBoundingMetrics = bm; } else aDesiredSize.mBoundingMetrics += bm; FinishReflowChild(childFrame, aPresContext, nsnull, childSize, dx, ascent - childSize.ascent, 0); dx += childSize.width; if (i < mSeparatorsCount) { PlaceChar(&mSeparatorsChar[i], ascent, bm, dx); aDesiredSize.mBoundingMetrics += bm; } i++; childFrame = childFrame->GetNextSibling(); } if (mCloseChar) { PlaceChar(mCloseChar, ascent, bm, dx); if (firstTime) aDesiredSize.mBoundingMetrics = bm; else aDesiredSize.mBoundingMetrics += bm; } aDesiredSize.width = aDesiredSize.mBoundingMetrics.width; aDesiredSize.height = ascent + descent; aDesiredSize.ascent = ascent; SetBoundingMetrics(aDesiredSize.mBoundingMetrics); SetReference(nsPoint(0, aDesiredSize.ascent)); // see if we should fix the spacing FixInterFrameSpacing(aDesiredSize); // Finished with these: ClearSavedChildMetrics(); // Set our overflow area GatherAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
/* void scrollByIndex (long dindexes); */ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv) { nsIScrollableFrame* sf = GetScrollFrame(); if (!sf) { aRv.Throw(NS_ERROR_FAILURE); return; } nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) { aRv.Throw(NS_ERROR_FAILURE); return; } nsRect rect; // now get the scrolled boxes first child. nsIFrame* child = nsBox::GetChildBox(scrolledBox); bool horiz = scrolledBox->IsHorizontal(); nsPoint cp = sf->GetScrollPosition(); nscoord diff = 0; int32_t curIndex = 0; bool isLTR = scrolledBox->IsNormalDirection(); int32_t frameWidth = 0; if (!isLTR && horiz) { GetWidth(&frameWidth); nsCOMPtr<nsIPresShell> shell = GetPresShell(false); if (!shell) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth); } // first find out what index we are currently at while(child) { rect = child->GetRect(); if (horiz) { // In the left-to-right case we break from the loop when the center of // the current child rect is greater than the scrolled position of // the left edge of the scrollbox // In the right-to-left case we break when the center of the current // child rect is less than the scrolled position of the right edge of // the scrollbox. diff = rect.x + rect.width/2; // use the center, to avoid rounding errors if ((isLTR && diff > cp.x) || (!isLTR && diff < cp.x + frameWidth)) { break; } } else { diff = rect.y + rect.height/2;// use the center, to avoid rounding errors if (diff > cp.y) { break; } } child = nsBox::GetNextBox(child); curIndex++; } int32_t count = 0; if (dindexes == 0) return; if (dindexes > 0) { while(child) { child = nsBox::GetNextBox(child); if (child) { rect = child->GetRect(); } count++; if (count >= dindexes) { break; } } } else if (dindexes < 0) { child = nsBox::GetChildBox(scrolledBox); while(child) { rect = child->GetRect(); if (count >= curIndex + dindexes) { break; } count++; child = nsBox::GetNextBox(child); } } nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1); if (horiz) { // In the left-to-right case we scroll so that the left edge of the // selected child is scrolled to the left edge of the scrollbox. // In the right-to-left case we scroll so that the right edge of the // selected child is scrolled to the right edge of the scrollbox. nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth, cp.y); // Use a destination range that ensures the left edge (or right edge, // for RTL) will indeed be visible. Also ensure that the top edge // is visible. nsRect range(pt.x, pt.y, csspixel, 0); if (isLTR) { range.x -= csspixel; } sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); } else { // Use a destination range that ensures the top edge will be visible. nsRect range(cp.x, rect.y - csspixel, 0, csspixel); sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range); } }
static nsIFrame* GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs, nsIFrame* aRestrictToDescendants, nsTArray<nsIFrame*>& aCandidates) { nsIFrame* bestTarget = nullptr; // Lower is better; distance is in appunits float bestDistance = 1e6f; nsRegion exposedRegion(aTargetRect); for (uint32_t i = 0; i < aCandidates.Length(); ++i) { nsIFrame* f = aCandidates[i]; PET_LOG("Checking candidate %p\n", f); bool preservesAxisAlignedRectangles = false; nsRect borderBox = nsLayoutUtils::TransformFrameRectToAncestor(f, nsRect(nsPoint(0, 0), f->GetSize()), aRoot, &preservesAxisAlignedRectangles); nsRegion region; region.And(exposedRegion, borderBox); if (region.IsEmpty()) { PET_LOG(" candidate %p had empty hit region\n", f); continue; } if (preservesAxisAlignedRectangles) { // Subtract from the exposed region if we have a transform that won't make // the bounds include a bunch of area that we don't actually cover. SubtractFromExposedRegion(&exposedRegion, region); } if (!IsElementClickable(f, nsGkAtoms::body)) { PET_LOG(" candidate %p was not clickable\n", f); continue; } // If our current closest frame is a descendant of 'f', skip 'f' (prefer // the nested frame). if (bestTarget && nsLayoutUtils::IsProperAncestorFrameCrossDoc(f, bestTarget, aRoot)) { PET_LOG(" candidate %p was ancestor for bestTarget %p\n", f, bestTarget); continue; } if (!nsLayoutUtils::IsAncestorFrameCrossDoc(aRestrictToDescendants, f, aRoot)) { PET_LOG(" candidate %p was not descendant of restrictroot %p\n", f, aRestrictToDescendants); continue; } // distance is in appunits float distance = ComputeDistanceFromRegion(aPointRelativeToRootFrame, region); nsIContent* content = f->GetContent(); if (content && content->IsElement() && content->AsElement()->State().HasState( EventStates(NS_EVENT_STATE_VISITED))) { distance *= aPrefs->mVisitedWeight / 100.0f; } if (distance < bestDistance) { PET_LOG(" candidate %p is the new best\n", f); bestDistance = distance; bestTarget = f; } } return bestTarget; }
const nsPoint AsyncPanZoomController::GetVelocityVector() { return nsPoint( mX.GetVelocity(), mY.GetVelocity() ); }
NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame", aReflowState.reason); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState); #endif float p2t = aPresContext->ScaledPixelsToTwips(); // work around pixel rounding errors, round down to ensure we don't exceed the avail height in nscoord availHeight = aReflowState.availableHeight; if (NS_UNCONSTRAINEDSIZE != availHeight) { availHeight = nsTableFrame::RoundToPixel(availHeight, p2t, eAlwaysRoundDown); } nsresult rv = NS_OK; // see if a special height reflow needs to occur due to having a pct height if (!NeedSpecialReflow()) nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); // this should probably be cached somewhere nsCompatibility compatMode = aPresContext->CompatibilityMode(); // Initialize out parameter if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = 0; } aStatus = NS_FRAME_COMPLETE; nsSize availSize(aReflowState.availableWidth, availHeight); PRBool noBorderBeforeReflow = GetContentEmpty() && GetStyleTableBorder()->mEmptyCells != NS_STYLE_TABLE_EMPTY_CELLS_SHOW; /* XXX: remove tableFrame when border-collapse inherits */ nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER); nsMargin borderPadding = aReflowState.mComputedPadding; nsMargin border; GetBorderWidth(p2t, border); if ((NS_UNCONSTRAINEDSIZE == availSize.width) || !noBorderBeforeReflow) { borderPadding += border; } nscoord topInset = borderPadding.top; nscoord rightInset = borderPadding.right; nscoord bottomInset = borderPadding.bottom; nscoord leftInset = borderPadding.left; // reduce available space by insets, if we're in a constrained situation if (NS_UNCONSTRAINEDSIZE!=availSize.width) availSize.width -= leftInset+rightInset; if (NS_UNCONSTRAINEDSIZE!=availSize.height) availSize.height -= topInset+bottomInset; PRBool isStyleChanged = PR_FALSE; if (eReflowReason_Incremental == aReflowState.reason) { // if the path has a reflow command then the cell must be the target of a style change nsHTMLReflowCommand* command = aReflowState.path->mReflowCommand; if (command) { // if there are other reflow commands targeted at the cell's block, these will // be subsumed by the style change reflow nsReflowType type; command->GetType(type); if (eReflowType_StyleChanged == type) { isStyleChanged = PR_TRUE; } else NS_ASSERTION(PR_FALSE, "table cell target of illegal incremental reflow type"); } // else the reflow command will be passed down to the child } // Try to reflow the child into the available space. It might not // fit or might need continuing. if (availSize.height < 0) availSize.height = 1; nsHTMLReflowMetrics kidSize(NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth || aDesiredSize.mComputeMEW, aDesiredSize.mFlags); kidSize.width=kidSize.height=kidSize.ascent=kidSize.descent=0; SetPriorAvailWidth(aReflowState.availableWidth); nsIFrame* firstKid = mFrames.FirstChild(); NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); nscoord computedPaginatedHeight = 0; if (aReflowState.mFlags.mSpecialHeightReflow || (HadSpecialReflow() && (eReflowReason_Incremental == aReflowState.reason))) { ((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset; DISPLAY_REFLOW_CHANGE(); } else if (aPresContext->IsPaginated()) { computedPaginatedHeight = CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this, *tableFrame, topInset + bottomInset); if (computedPaginatedHeight > 0) { ((nsHTMLReflowState&)aReflowState).mComputedHeight = computedPaginatedHeight; DISPLAY_REFLOW_CHANGE(); } } else { SetHasPctOverHeight(PR_FALSE); } // If it was a style change targeted at us, then reflow the child with a style change reason nsReflowReason reason = aReflowState.reason; if (isStyleChanged) { reason = eReflowReason_StyleChange; // the following could be optimized with a fair amount of effort tableFrame->SetNeedStrategyInit(PR_TRUE); } nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid, availSize, reason); // mIPercentHeightObserver is for non table related frames inside cells in quirks mode kidReflowState.mPercentHeightObserver = (eCompatibility_NavQuirks == compatMode) ? (nsIPercentHeightObserver *)this : nsnull; // Assume the inner child will stay positioned exactly where it is. Later in // VerticallyAlignChild() we'll move it if it turns out to be wrong. This // avoids excessive movement and is more stable nsPoint kidOrigin; if (isStyleChanged || (eReflowReason_Initial == aReflowState.reason) || (eReflowReason_StyleChange == aReflowState.reason)) { kidOrigin.MoveTo(leftInset, topInset); } else { // handle percent padding-left which was 0 during initial reflow if (eStyleUnit_Percent == aReflowState.mStylePadding->mPadding.GetLeftUnit()) { nsRect kidRect = firstKid->GetRect(); // only move in the x direction for the same reason as above kidOrigin.MoveTo(leftInset, kidRect.y); firstKid->SetPosition(nsPoint(leftInset, kidRect.y)); } kidOrigin = firstKid->GetPosition(); } #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState); #endif nscoord priorBlockHeight = GetLastBlockHeight(); ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, kidOrigin.x, kidOrigin.y, 0, aStatus); SetLastBlockHeight(kidSize.height); if (isStyleChanged) { Invalidate(GetOverflowRect(), PR_FALSE); } #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(firstKid, (nsHTMLReflowState&)kidReflowState, &kidSize, aStatus); #endif #ifdef NS_DEBUG DebugCheckChildSize(firstKid, kidSize, availSize, (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)); #endif // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode // see testcase "emptyCells.html" if ((0 == kidSize.width) || (0 == kidSize.height)) { // XXX why was this && SetContentEmpty(PR_TRUE); if (NS_UNCONSTRAINEDSIZE == kidReflowState.availableWidth && GetStyleTableBorder()->mEmptyCells != NS_STYLE_TABLE_EMPTY_CELLS_SHOW) { // need to reduce the insets by border if the cell is empty leftInset -= border.left; rightInset -= border.right; topInset -= border.top; bottomInset -= border.bottom; } } else { SetContentEmpty(PR_FALSE); if ((eReflowReason_Incremental == aReflowState.reason) && noBorderBeforeReflow) { // need to consider borders, since they were factored out above leftInset += border.left; rightInset += border.right; topInset += border.top; bottomInset += border.bottom; kidOrigin.MoveTo(leftInset, topInset); } } const nsStylePosition* pos = GetStylePosition(); // calculate the min cell width nscoord onePixel = NSIntPixelsToTwips(1, p2t); nscoord smallestMinWidth = 0; if (eCompatibility_NavQuirks == compatMode) { if ((pos->mWidth.GetUnit() != eStyleUnit_Coord) && (pos->mWidth.GetUnit() != eStyleUnit_Percent)) { if (PR_TRUE == GetContentEmpty()) { if (border.left > 0) smallestMinWidth += onePixel; if (border.right > 0) smallestMinWidth += onePixel; } } } PRInt32 colspan = tableFrame->GetEffectiveColSpan(*this); if (colspan > 1) { smallestMinWidth = PR_MAX(smallestMinWidth, colspan * onePixel); nscoord spacingX = tableFrame->GetCellSpacingX(); nscoord spacingExtra = spacingX * (colspan - 1); smallestMinWidth += spacingExtra; if (aReflowState.mComputedPadding.left > 0) { smallestMinWidth -= onePixel; } } if ((0 == kidSize.width) && (NS_UNCONSTRAINEDSIZE != kidReflowState.availableWidth)) { // empty content has to be forced to the assigned width for resize or incremental reflow kidSize.width = kidReflowState.availableWidth; } if (0 == kidSize.height) { if ((pos->mHeight.GetUnit() != eStyleUnit_Coord) && (pos->mHeight.GetUnit() != eStyleUnit_Percent)) { PRInt32 pixHeight = (eCompatibility_NavQuirks == compatMode) ? 1 : 0; kidSize.height = NSIntPixelsToTwips(pixHeight, p2t); } } // end 0 dimensioned cells kidSize.width = PR_MAX(kidSize.width, smallestMinWidth); if (!tableFrame->IsAutoLayout()) { // a cell in a fixed layout table is constrained to the avail width // if we need to shorten the cell the previous non overflowing block // will get some overflow area if (kidSize.width > availSize.width) { kidSize.width = availSize.width; firstKid->FinishAndStoreOverflow(&kidSize); } } //if (eReflowReason_Resize == aReflowState.reason) { // NS_ASSERTION(kidSize.width <= availSize.width, "child needed more space during resize reflow"); //} // Place the child FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize, kidOrigin.x, kidOrigin.y, 0); // first, compute the height which can be set w/o being restricted by aMaxSize.height nscoord cellHeight = kidSize.height; if (NS_UNCONSTRAINEDSIZE != cellHeight) { cellHeight += topInset + bottomInset; // work around block rounding errors, round down to ensure we don't exceed the avail height in nsPixelRound roundMethod = (NS_UNCONSTRAINEDSIZE == availHeight) ? eAlwaysRoundUp : eAlwaysRoundDown; cellHeight = nsTableFrame::RoundToPixel(cellHeight, p2t, roundMethod); } // next determine the cell's width nscoord cellWidth = kidSize.width; // at this point, we've factored in the cell's style attributes // factor in border and padding if (NS_UNCONSTRAINEDSIZE != cellWidth) { cellWidth += leftInset + rightInset; } cellWidth = nsTableFrame::RoundToPixel(cellWidth, p2t); // work around block rounding errors // set the cell's desired size and max element size aDesiredSize.width = cellWidth; aDesiredSize.height = cellHeight; aDesiredSize.ascent = topInset; aDesiredSize.descent = bottomInset; aDesiredSize.ascent += kidSize.ascent; aDesiredSize.descent += kidSize.descent; // the overflow area will be computed when the child will be vertically aligned if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = PR_MAX(smallestMinWidth, kidSize.mMaxElementWidth); if (NS_UNCONSTRAINEDSIZE != aDesiredSize.mMaxElementWidth) { aDesiredSize.mMaxElementWidth = nsTableFrame::RoundToPixel( aDesiredSize.mMaxElementWidth + leftInset + rightInset, p2t); } } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aDesiredSize.mMaximumWidth = kidSize.mMaximumWidth; if (NS_UNCONSTRAINEDSIZE != aDesiredSize.mMaximumWidth) { aDesiredSize.mMaximumWidth += leftInset + rightInset; aDesiredSize.mMaximumWidth = nsTableFrame::RoundToPixel(aDesiredSize.mMaximumWidth, p2t); } // make sure the preferred width is at least as big as the max element width if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, aDesiredSize.mMaxElementWidth); } } if (aReflowState.mFlags.mSpecialHeightReflow) { if (aDesiredSize.height > mRect.height) { // set a bit indicating that the pct height contents exceeded // the height that they could honor in the pass 2 reflow SetHasPctOverHeight(PR_TRUE); } if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) { aDesiredSize.height = mRect.height; } SetNeedSpecialReflow(PR_FALSE); SetHadSpecialReflow(PR_TRUE); } else if (HadSpecialReflow()) { if (eReflowReason_Incremental == aReflowState.reason) { // with an unconstrained height, if the block height value hasn't changed, // use the last height of the cell. if ((NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) && (GetLastBlockHeight() == priorBlockHeight)) { aDesiredSize.height = mRect.height; } } // XXX should probably call SetHadSpecialReflow(PR_FALSE) when things change so that // nothing inside the cell has a percent height, but it is not easy determining this } // remember the desired size for this reflow SetDesiredSize(aDesiredSize); #if defined DEBUG_TABLE_REFLOW_TIMING nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus); #endif if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) { SetNeedPass2Reflow(PR_TRUE); } else if ((eReflowReason_Initial == aReflowState.reason) || (eReflowReason_Resize == aReflowState.reason)) { SetNeedPass2Reflow(PR_FALSE); } NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
NS_IMETHODIMP nsMathMLmsqrtFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { /////////////// // Let the base class format our content like an inferred mrow nsHTMLReflowMetrics baseSize(aDesiredSize); nsresult rv = nsMathMLContainerFrame::Reflow(aPresContext, baseSize, aReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); if (NS_FAILED(rv)) return rv; nsBoundingMetrics bmSqr, bmBase; bmBase = baseSize.mBoundingMetrics; //////////// // Prepare the radical symbol and the overline bar nsIRenderingContext& renderingContext = *aReflowState.rendContext; renderingContext.SetFont(GetStyleFont()->mFont, nsnull); nsCOMPtr<nsIFontMetrics> fm; renderingContext.GetFontMetrics(*getter_AddRefs(fm)); nscoord ruleThickness, leading, em; GetRuleThickness(renderingContext, fm, ruleThickness); nsBoundingMetrics bmOne; renderingContext.GetBoundingMetrics(NS_LITERAL_STRING("1").get(), 1, bmOne); // get the leading to be left at the top of the resulting frame // this seems more reliable than using fm->GetLeading() on suspicious fonts GetEmHeight(fm, em); leading = nscoord(0.2f * em); // Rule 11, App. G, TeXbook // psi = clearance between rule and content nscoord phi = 0, psi = 0; if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) fm->GetXHeight(phi); else phi = ruleThickness; psi = ruleThickness + phi/4; // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131) if (bmOne.ascent > bmBase.ascent) psi += bmOne.ascent - bmBase.ascent; // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = ruleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, renderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // According to TeX, the ascent of the returned radical should be // the thickness of the overline ruleThickness = bmSqr.ascent; // make sure that the rule appears on the screen nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1); if (ruleThickness < onePixel) { ruleThickness = onePixel; } // adjust clearance psi to get an exact number of pixels -- this // gives a nicer & uniform look on stacked radicals (bug 130282) nscoord delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up nscoord dx = 0, dy = 0; // place the radical symbol and the radical bar dy = leading; // leave a leading at the top mSqrChar.SetRect(nsRect(dx, dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx = bmSqr.width; mBarRect.SetRect(dx, dy, bmBase.width, ruleThickness); // Update the desired size for the container. // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = PR_MAX(bmBase.descent, (bmSqr.descent - (bmBase.ascent + psi))); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + PR_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.descent = PR_MAX(baseSize.descent, (mBoundingMetrics.descent + ruleThickness)); aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; ////////////////// // Adjust the origins to leave room for the sqrt char and the overline bar dx = radicalSize.width; dy = aDesiredSize.ascent - baseSize.ascent; nsIFrame* childFrame = mFrames.FirstChild(); while (childFrame) { childFrame->SetPosition(childFrame->GetPosition() + nsPoint(dx, dy)); childFrame = childFrame->GetNextSibling(); } if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = aDesiredSize.width; } aDesiredSize.mBoundingMetrics = mBoundingMetrics; aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
bool nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell, nsPresContext *aPresContext, nsIDOMRange *aRange, bool aMustBeInViewPort, bool aGetTopVisibleLeaf, nsIDOMRange **aFirstVisibleRange, bool *aUsesIndependentSelection) { NS_ASSERTION(aPresShell && aPresContext && aRange && aFirstVisibleRange, "params are invalid"); // We need to know if the range start is visible. // Otherwise, return the first visible range start // in aFirstVisibleRange aRange->CloneRange(aFirstVisibleRange); nsCOMPtr<nsIDOMNode> node; aRange->GetStartContainer(getter_AddRefs(node)); nsCOMPtr<nsIContent> content(do_QueryInterface(node)); if (!content) return false; nsIFrame *frame = content->GetPrimaryFrame(); if (!frame) return false; // No frame! Not visible then. if (!frame->StyleVisibility()->IsVisible()) return false; // Detect if we are _inside_ a text control, or something else with its own // selection controller. if (aUsesIndependentSelection) { *aUsesIndependentSelection = (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION); } // ---- We have a frame ---- if (!aMustBeInViewPort) return true; // Don't need it to be on screen, just in rendering tree // Get the next in flow frame that contains the range start int32_t startRangeOffset, startFrameOffset, endFrameOffset; aRange->GetStartOffset(&startRangeOffset); while (true) { frame->GetOffsets(startFrameOffset, endFrameOffset); if (startRangeOffset < endFrameOffset) break; nsIFrame *nextContinuationFrame = frame->GetNextContinuation(); if (nextContinuationFrame) frame = nextContinuationFrame; else break; } // Set up the variables we need, return true if we can't get at them all const uint16_t kMinPixels = 12; nscoord minDistance = nsPresContext::CSSPixelsToAppUnits(kMinPixels); // Get the bounds of the current frame, relative to the current view. // We don't use the more accurate AccGetBounds, because that is // more expensive and the STATE_OFFSCREEN flag that this is used // for only needs to be a rough indicator nsRectVisibility rectVisibility = nsRectVisibility_kAboveViewport; if (!aGetTopVisibleLeaf && !frame->GetRect().IsEmpty()) { rectVisibility = aPresShell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frame->GetSize()), minDistance); if (rectVisibility != nsRectVisibility_kAboveViewport) { return true; } } // We know that the target range isn't usable because it's not in the // view port. Move range forward to first visible point, // this speeds us up a lot in long documents nsCOMPtr<nsIFrameEnumerator> frameTraversal; nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID)); if (trav) trav->NewFrameTraversal(getter_AddRefs(frameTraversal), aPresContext, frame, eLeaf, false, // aVisual false, // aLockInScrollView false // aFollowOOFs ); if (!frameTraversal) return false; while (rectVisibility == nsRectVisibility_kAboveViewport) { frameTraversal->Next(); frame = frameTraversal->CurrentItem(); if (!frame) return false; if (!frame->GetRect().IsEmpty()) { rectVisibility = aPresShell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frame->GetSize()), minDistance); } } if (frame) { nsCOMPtr<nsIDOMNode> firstVisibleNode = do_QueryInterface(frame->GetContent()); if (firstVisibleNode) { frame->GetOffsets(startFrameOffset, endFrameOffset); (*aFirstVisibleRange)->SetStart(firstVisibleNode, startFrameOffset); (*aFirstVisibleRange)->SetEnd(firstVisibleNode, endFrameOffset); } } return false; }
/* virtual */ void nsTableCellFrame::GetSelfOverflow(nsRect& aOverflowArea) { aOverflowArea = nsRect(nsPoint(0,0), GetSize()); }
nsresult nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIRange> range = new nsRange(); if (!range) { return NS_ERROR_OUT_OF_MEMORY; } rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, aEvent->mInput.mLength, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); // used to iterate over all contents and their frames nsCOMPtr<nsIContentIterator> iter; rv = NS_NewContentIterator(getter_AddRefs(iter)); NS_ENSURE_SUCCESS(rv, rv); iter->Init(range); NS_ENSURE_SUCCESS(rv, rv); // get the starting frame PRInt32 offset = range->StartOffset(); nsINode* node = iter->GetCurrentNode(); if (!node) { node = AdjustTextRectNode(range->GetStartParent(), offset); } nsIFrame* firstFrame = nsnull; rv = GetFrameForTextRect(node, offset, PR_TRUE, &firstFrame); NS_ENSURE_SUCCESS(rv, rv); // get the starting frame rect nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size()); rv = ConvertToRootViewRelativeOffset(firstFrame, rect); NS_ENSURE_SUCCESS(rv, rv); nsRect frameRect = rect; nsPoint ptOffset; firstFrame->GetPointFromOffset(offset, &ptOffset); // minus 1 to avoid creating an empty rect rect.x += ptOffset.x - 1; rect.width -= ptOffset.x - 1; // get the ending frame offset = range->EndOffset(); node = AdjustTextRectNode(range->GetEndParent(), offset); nsIFrame* lastFrame = nsnull; rv = GetFrameForTextRect(node, offset, range->Collapsed(), &lastFrame); NS_ENSURE_SUCCESS(rv, rv); // iterate over all covered frames for (nsIFrame* frame = firstFrame; frame != lastFrame;) { frame = frame->GetNextContinuation(); if (!frame) { do { iter->Next(); node = iter->GetCurrentNode(); if (!node || !node->IsNodeOfType(nsINode::eCONTENT)) continue; frame = static_cast<nsIContent*>(node)->GetPrimaryFrame(); } while (!frame && !iter->IsDone()); if (!frame) { // this can happen when the end offset of the range is 0. frame = lastFrame; } } frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size()); rv = ConvertToRootViewRelativeOffset(frame, frameRect); NS_ENSURE_SUCCESS(rv, rv); if (frame != lastFrame) { // not last frame, so just add rect to previous result rect.UnionRect(rect, frameRect); } } // get the ending frame rect lastFrame->GetPointFromOffset(offset, &ptOffset); // minus 1 to avoid creating an empty rect frameRect.width -= lastFrame->GetRect().width - ptOffset.x - 1; if (firstFrame == lastFrame) { rect.IntersectRect(rect, frameRect); } else { rect.UnionRect(rect, frameRect); } aEvent->mReply.mRect = rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()); aEvent->mSucceeded = PR_TRUE; return NS_OK; }
// NOTE: aDesiredStretchSize is an IN/OUT parameter // On input - it contains our current size // On output - the same size or the new size that we want NS_IMETHODIMP nsMathMLmoFrame::Stretch(nsRenderingContext& aRenderingContext, nsStretchDirection aStretchDirection, nsBoundingMetrics& aContainerSize, nsHTMLReflowMetrics& aDesiredStretchSize) { if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) { NS_WARNING("it is wrong to fire stretch more than once on a frame"); return NS_OK; } mPresentationData.flags |= NS_MATHML_STRETCH_DONE; nsIFrame* firstChild = mFrames.FirstChild(); // get the axis height; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); nscoord axisHeight, height; GetAxisHeight(aRenderingContext, fm, axisHeight); // get the leading to be left at the top and the bottom of the stretched char // this seems more reliable than using fm->GetLeading() on suspicious fonts nscoord em; GetEmHeight(fm, em); nscoord leading = NSToCoordRound(0.2f * em); // Operators that are stretchy, or those that are to be centered // to cater for fonts that are not math-aware, are handled by the MathMLChar // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time) bool useMathMLChar = UseMathMLChar(); nsBoundingMetrics charSize; nsBoundingMetrics container = aDesiredStretchSize.mBoundingMetrics; bool isVertical = false; if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) || (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT)) && (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL)) { isVertical = true; } uint32_t stretchHint = GetStretchHint(mFlags, mPresentationData, isVertical); if (useMathMLChar) { nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics; if (stretchHint != NS_STRETCH_NONE) { container = aContainerSize; // some adjustments if the operator is symmetric and vertical if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { // we need to center about the axis nscoord delta = std::max(container.ascent - axisHeight, container.descent + axisHeight); container.ascent = delta + axisHeight; container.descent = delta - axisHeight; // get ready in case we encounter user-desired min-max size delta = std::max(initialSize.ascent - axisHeight, initialSize.descent + axisHeight); initialSize.ascent = delta + axisHeight; initialSize.descent = delta - axisHeight; } // check for user-desired min-max size if (mMaxSize != NS_MATHML_OPERATOR_SIZE_INFINITY && mMaxSize > 0.0f) { // if we are here, there is a user defined maxsize ... //XXX Set stretchHint = NS_STRETCH_NORMAL? to honor the maxsize as close as possible? if (NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)) { // there is an explicit value like maxsize="20pt" // try to maintain the aspect ratio of the char float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent); container.ascent = std::min(container.ascent, nscoord(initialSize.ascent * aspect)); container.descent = std::min(container.descent, nscoord(initialSize.descent * aspect)); // below we use a type cast instead of a conversion to avoid a VC++ bug // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP container.width = std::min(container.width, (nscoord)mMaxSize); } else { // multiplicative value container.ascent = std::min(container.ascent, nscoord(initialSize.ascent * mMaxSize)); container.descent = std::min(container.descent, nscoord(initialSize.descent * mMaxSize)); container.width = std::min(container.width, nscoord(initialSize.width * mMaxSize)); } if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { // re-adjust to align the char with the bottom of the initial container height = container.ascent + container.descent; container.descent = aContainerSize.descent; container.ascent = height - container.descent; } } if (mMinSize > 0.0f) { // if we are here, there is a user defined minsize ... // always allow the char to stretch in its natural direction, // even if it is different from the caller's direction if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && aStretchDirection != mEmbellishData.direction) { aStretchDirection = NS_STRETCH_DIRECTION_DEFAULT; // but when we are not honoring the requested direction // we should not use the caller's container size either container = initialSize; } if (NS_MATHML_OPERATOR_MINSIZE_IS_ABSOLUTE(mFlags)) { // there is an explicit value like minsize="20pt" // try to maintain the aspect ratio of the char float aspect = mMinSize / float(initialSize.ascent + initialSize.descent); container.ascent = std::max(container.ascent, nscoord(initialSize.ascent * aspect)); container.descent = std::max(container.descent, nscoord(initialSize.descent * aspect)); container.width = std::max(container.width, (nscoord)mMinSize); } else { // multiplicative value container.ascent = std::max(container.ascent, nscoord(initialSize.ascent * mMinSize)); container.descent = std::max(container.descent, nscoord(initialSize.descent * mMinSize)); container.width = std::max(container.width, nscoord(initialSize.width * mMinSize)); } if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { // re-adjust to align the char with the bottom of the initial container height = container.ascent + container.descent; container.descent = aContainerSize.descent; container.ascent = height - container.descent; } } } // let the MathMLChar stretch itself... nsresult res = mMathMLChar.Stretch(PresContext(), aRenderingContext, aStretchDirection, container, charSize, stretchHint, StyleVisibility()->mDirection); if (NS_FAILED(res)) { // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed) // clear our 'form' to behave as if the operator wasn't in the dictionary mFlags &= ~NS_MATHML_OPERATOR_FORM; useMathMLChar = false; } } // Child frames of invisble operators are not reflowed if (!NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags)) { // Place our children using the default method // This will allow our child text frame to get its DidReflow() nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize); if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { // Make sure the child frames get their DidReflow() calls. DidReflowChildren(mFrames.FirstChild()); } } if (useMathMLChar) { // update our bounding metrics... it becomes that of our MathML char mBoundingMetrics = charSize; // if the returned direction is 'unsupported', the char didn't actually change. // So we do the centering only if necessary if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { bool largeopOnly = (NS_STRETCH_LARGEOP & stretchHint) != 0 && (NS_STRETCH_VARIABLE_MASK & stretchHint) == 0; if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { // the desired size returned by mMathMLChar maybe different // from the size of the container. // the mMathMLChar.mRect.y calculation is subtle, watch out!!! height = mBoundingMetrics.ascent + mBoundingMetrics.descent; if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { // For symmetric and vertical operators, or for operators that are always // centered ('+', '*', etc) we want to center about the axis of the container mBoundingMetrics.descent = height/2 - axisHeight; } else if (!largeopOnly) { // Align the center of the char with the center of the container mBoundingMetrics.descent = height/2 + (container.ascent + container.descent)/2 - container.ascent; } // else align the baselines mBoundingMetrics.ascent = height - mBoundingMetrics.descent; } } } // Fixup for the final height. // On one hand, our stretchy height can sometimes be shorter than surrounding // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading| // that is smaller than the ASCII's ascent, hence when painting the background // later, it won't look uniform along the line. // On the other hand, sometimes we may leave too much gap when our glyph happens // to come from a font with tall glyphs. For example, since CMEX10 has very tall // glyphs, its natural font metrics are large, even if we pick a small glyph // whose size is comparable to the size of a normal ASCII glyph. // So to avoid uneven spacing in either of these two cases, we use the height // of the ASCII font as a reference and try to match it if possible. // special case for accents... keep them short to improve mouse operations... // an accent can only be the non-first child of <mover>, <munder>, <munderover> bool isAccent = NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags); if (isAccent) { nsEmbellishData parentData; GetEmbellishDataFrom(mParent, parentData); isAccent = (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) || NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) && parentData.coreFrame != this; } if (isAccent && firstChild) { // see bug 188467 for what is going on here nscoord dy = aDesiredStretchSize.ascent - (mBoundingMetrics.ascent + leading); aDesiredStretchSize.ascent = mBoundingMetrics.ascent + leading; aDesiredStretchSize.height = aDesiredStretchSize.ascent + mBoundingMetrics.descent; firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy)); } else if (useMathMLChar) { nscoord ascent = fm->MaxAscent(); nscoord descent = fm->MaxDescent(); aDesiredStretchSize.ascent = std::max(mBoundingMetrics.ascent + leading, ascent); aDesiredStretchSize.height = aDesiredStretchSize.ascent + std::max(mBoundingMetrics.descent + leading, descent); } aDesiredStretchSize.width = mBoundingMetrics.width; aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredStretchSize.ascent; // Place our mMathMLChar, its origin is in our coordinate system if (useMathMLChar) { nscoord dy = aDesiredStretchSize.ascent - mBoundingMetrics.ascent; mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent)); } // Before we leave... there is a last item in the check-list: // If our parent is not embellished, it means we are the outermost embellished // container and so we put the spacing, otherwise we don't include the spacing, // the outermost embellished container will take care of it. if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) { // Account the spacing if we are not an accent with explicit attributes nscoord leadingSpace = mEmbellishData.leadingSpace; if (isAccent && !NS_MATHML_OPERATOR_HAS_LSPACE_ATTR(mFlags)) { leadingSpace = 0; } nscoord trailingSpace = mEmbellishData.trailingSpace; if (isAccent && !NS_MATHML_OPERATOR_HAS_RSPACE_ATTR(mFlags)) { trailingSpace = 0; } mBoundingMetrics.width += leadingSpace + trailingSpace; aDesiredStretchSize.width = mBoundingMetrics.width; aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width; nscoord dx = (StyleVisibility()->mDirection ? trailingSpace : leadingSpace); if (dx) { // adjust the offsets mBoundingMetrics.leftBearing += dx; mBoundingMetrics.rightBearing += dx; aDesiredStretchSize.mBoundingMetrics.leftBearing += dx; aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; if (useMathMLChar) { nsRect rect; mMathMLChar.GetRect(rect); mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y, rect.width, rect.height)); } else { nsIFrame* childFrame = firstChild; while (childFrame) { childFrame->SetPosition(childFrame->GetPosition() + nsPoint(dx, 0)); childFrame = childFrame->GetNextSibling(); } } } } // Finished with these: ClearSavedChildMetrics(); // Set our overflow area GatherAndStoreOverflow(&aDesiredStretchSize); // There used to be code here to change the height of the child frame to // change the caret height, but the text frame that manages the caret is now // not a direct child but wrapped in a block frame. See also bug 412033. return NS_OK; }
/** * Attempt to place the block frame within the available space. If * it fits, apply horizontal positioning (CSS 10.3.3), collapse * margins (CSS2 8.3.1). Also apply relative positioning. */ bool nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState, bool aForceFit, nsLineBox* aLine, nsCollapsingMargin& aBottomMarginResult, nsRect& aInFlowBounds, nsOverflowAreas& aOverflowAreas, nsReflowStatus aReflowStatus) { // Compute collapsed bottom margin value. if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { aBottomMarginResult = mMetrics.mCarriedOutBottomMargin; aBottomMarginResult.Include(aReflowState.mComputedMargin.bottom); } else { // The used bottom-margin is set to zero above a break. aBottomMarginResult.Zero(); } nscoord x = mX; nscoord y = mY; nscoord backupContainingBlockAdvance = 0; // Check whether the block's bottom margin collapses with its top // margin. See CSS 2.1 section 8.3.1; those rules seem to match // nsBlockFrame::IsEmpty(). Any such block must have zero height so // check that first. Note that a block can have clearance and still // have adjoining top/bottom margins, because the clearance goes // above the top margin. // Mark the frame as non-dirty; it has been reflowed (or we wouldn't // be here), and we don't want to assert in CachedIsEmpty() mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY); bool empty = 0 == mMetrics.height && aLine->CachedIsEmpty(); if (empty) { // Collapse the bottom margin with the top margin that was already // applied. aBottomMarginResult.Include(mTopMargin); #ifdef NOISY_VERTICAL_MARGINS printf(" "); nsFrame::ListTag(stdout, mOuterReflowState.frame); printf(": "); nsFrame::ListTag(stdout, mFrame); printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n", y, mSpace.y); #endif // Section 8.3.1 of CSS 2.1 says that blocks with adjoining // top/bottom margins whose top margin collapses with their // parent's top margin should have their top border-edge at the // top border-edge of their parent. We actually don't have to do // anything special to make this happen. In that situation, // nsBlockFrame::ShouldApplyTopMargin will have returned false, // and mTopMargin and aClearance will have been zero in // ReflowBlock. // If we did apply our top margin, but now we're collapsing it // into the bottom margin, we need to back up the containing // block's y-advance by our top margin so that it doesn't get // counted twice. Note that here we're allowing the line's bounds // to become different from the block's position; we do this // because the containing block will place the next line at the // line's YMost, and it must place the next line at a different // point from where this empty block will be. backupContainingBlockAdvance = mTopMargin.get(); } // See if the frame fit. If it's the first frame or empty then it // always fits. If the height is unconstrained then it always fits, // even if there's some sort of integer overflow that makes y + // mMetrics.height appear to go beyond the available height. if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) { nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height; if (yMost > mSpace.YMost()) { // didn't fit, we must acquit. mFrame->DidReflow(mPresContext, &aReflowState, NS_FRAME_REFLOW_FINISHED); return false; } } aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance, mMetrics.width, mMetrics.height); // Apply CSS relative positioning const nsStyleDisplay* styleDisp = mFrame->GetStyleDisplay(); if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { x += aReflowState.mComputedOffsets.left; y += aReflowState.mComputedOffsets.top; } // Now place the frame and complete the reflow process nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0); aOverflowAreas = mMetrics.mOverflowAreas + nsPoint(x, y); return true; }
// Returns true if this function managed to successfully move a frame, and // false if it could not process the position change, and a reflow should // be performed instead. bool RecomputePosition(nsIFrame* aFrame) { // Don't process position changes on table frames, since we already handle // the dynamic position change on the table wrapper frame, and the // reflow-based fallback code path also ignores positions on inner table // frames. if (aFrame->GetType() == nsGkAtoms::tableFrame) { return true; } const nsStyleDisplay* display = aFrame->StyleDisplay(); // Changes to the offsets of a non-positioned element can safely be ignored. if (display->mPosition == NS_STYLE_POSITION_STATIC) { return true; } // Don't process position changes on frames which have views or the ones which // have a view somewhere in their descendants, because the corresponding view // needs to be repositioned properly as well. if (aFrame->HasView() || (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) { StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); return false; } aFrame->SchedulePaint(); // For relative positioning, we can simply update the frame rect if (display->IsRelativelyPositionedStyle()) { // Move the frame if (display->mPosition == NS_STYLE_POSITION_STICKY) { if (display->IsInnerTableStyle()) { // We don't currently support sticky positioning of inner table // elements (bug 975644). Bail. // // When this is fixed, remove the null-check for the computed // offsets in nsTableRowFrame::ReflowChildren. return true; } // Update sticky positioning for an entire element at once, starting with // the first continuation or ib-split sibling. // It's rare that the frame we already have isn't already the first // continuation or ib-split sibling, but it can happen when styles differ // across continuations such as ::first-line or ::first-letter, and in // those cases we will generally (but maybe not always) do the work twice. nsIFrame* firstContinuation = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame); StickyScrollContainer::ComputeStickyOffsets(firstContinuation); StickyScrollContainer* ssc = StickyScrollContainer::GetStickyScrollContainerForFrame( firstContinuation); if (ssc) { ssc->PositionContinuations(firstContinuation); } } else { MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition, "Unexpected type of positioning"); for (nsIFrame* cont = aFrame; cont; cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) { nsIFrame* cb = cont->GetContainingBlock(); nsMargin newOffsets; WritingMode wm = cb->GetWritingMode(); const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size()); ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets); NS_ASSERTION(newOffsets.left == -newOffsets.right && newOffsets.top == -newOffsets.bottom, "ComputeRelativeOffsets should return valid results"); // ReflowInput::ApplyRelativePositioning would work here, but // since we've already checked mPosition and aren't changing the frame's // normal position, go ahead and add the offsets directly. cont->SetPosition(cont->GetNormalPosition() + nsPoint(newOffsets.left, newOffsets.top)); } } return true; } // For the absolute positioning case, set up a fake HTML reflow state for // the frame, and then get the offsets and size from it. If the frame's size // doesn't need to change, we can simply update the frame position. Otherwise // we fall back to a reflow. nsRenderingContext rc( aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext()); // Construct a bogus parent reflow state so that there's a usable // containing block reflow state. nsIFrame* parentFrame = aFrame->GetParent(); WritingMode parentWM = parentFrame->GetWritingMode(); WritingMode frameWM = aFrame->GetWritingMode(); LogicalSize parentSize = parentFrame->GetLogicalSize(); nsFrameState savedState = parentFrame->GetStateBits(); ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame, &rc, parentSize); parentFrame->RemoveStateBits(~nsFrameState(0)); parentFrame->AddStateBits(savedState); // The bogus parent state here was created with no parent state of its own, // and therefore it won't have an mCBReflowInput set up. // But we may need one (for InitCBReflowInput in a child state), so let's // try to create one here for the cases where it will be needed. Maybe<ReflowInput> cbReflowInput; nsIFrame* cbFrame = parentFrame->GetContainingBlock(); if (cbFrame && (aFrame->GetContainingBlock() != parentFrame || parentFrame->GetType() == nsGkAtoms::tableFrame)) { LogicalSize cbSize = cbFrame->GetLogicalSize(); cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, &rc, cbSize); cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin(); cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding(); cbReflowInput->ComputedPhysicalBorderPadding() = cbFrame->GetUsedBorderAndPadding(); parentReflowInput.mCBReflowInput = cbReflowInput.ptr(); } NS_WARN_IF_FALSE(parentSize.ISize(parentWM) != NS_INTRINSICSIZE && parentSize.BSize(parentWM) != NS_INTRINSICSIZE, "parentSize should be valid"); parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0)); parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0)); parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0); parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding(); parentReflowInput.ComputedPhysicalBorderPadding() = parentFrame->GetUsedBorderAndPadding(); LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM); availSize.BSize(frameWM) = NS_INTRINSICSIZE; ViewportFrame* viewport = do_QueryFrame(parentFrame); nsSize cbSize = viewport ? viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size() : aFrame->GetContainingBlock()->GetSize(); const nsMargin& parentBorder = parentReflowInput.mStyleBorder->GetComputedBorder(); cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom()); LogicalSize lcbSize(frameWM, cbSize); ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput, aFrame, availSize, &lcbSize); nsSize computedSize(reflowInput.ComputedWidth(), reflowInput.ComputedHeight()); computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight(); if (computedSize.height != NS_INTRINSICSIZE) { computedSize.height += reflowInput.ComputedPhysicalBorderPadding().TopBottom(); } nsSize size = aFrame->GetSize(); // The RecomputePosition hint is not used if any offset changed between auto // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new // element height will be its intrinsic height, and since 'top' and 'bottom''s // auto-ness hasn't changed, the old height must also be its intrinsic // height, which we can assume hasn't changed (or reflow would have // been triggered). if (computedSize.width == size.width && (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) { // If we're solving for 'left' or 'top', then compute it here, in order to // match the reflow code path. if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) { reflowInput.ComputedPhysicalOffsets().left = cbSize.width - reflowInput.ComputedPhysicalOffsets().right - reflowInput.ComputedPhysicalMargin().right - size.width - reflowInput.ComputedPhysicalMargin().left; } if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) { reflowInput.ComputedPhysicalOffsets().top = cbSize.height - reflowInput.ComputedPhysicalOffsets().bottom - reflowInput.ComputedPhysicalMargin().bottom - size.height - reflowInput.ComputedPhysicalMargin().top; } // Move the frame nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left + reflowInput.ComputedPhysicalMargin().left, parentBorder.top + reflowInput.ComputedPhysicalOffsets().top + reflowInput.ComputedPhysicalMargin().top); aFrame->SetPosition(pos); return true; } // Fall back to a reflow StyleChangeReflow(aFrame, nsChangeHint_NeedReflow); return false; }
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 nsCanvasFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow"); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; nsCanvasFrame* prevCanvasFrame = static_cast<nsCanvasFrame*> (GetPrevInFlow()); if (prevCanvasFrame) { nsAutoPtr<nsFrameList> overflow(prevCanvasFrame->StealOverflowFrames()); if (overflow) { NS_ASSERTION(overflow->OnlyChild(), "must have doc root as canvas frame's only child"); nsContainerFrame::ReparentFrameViewList(aPresContext, *overflow, prevCanvasFrame, this); // Prepend overflow to the our child list. There may already be // children placeholders for fixed-pos elements, which don't get // reflowed but must not be lost until the canvas frame is destroyed. mFrames.InsertFrames(this, nullptr, *overflow); } } // 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.ComputedWidth(), aReflowState.ComputedHeight())); // Reflow our one and only normal child frame. It's either the root // element's frame or a placeholder for that frame, if the root element // is abs-pos or fixed-pos. We may have additional children which // are placeholders for continuations of fixed-pos content, but those // don't need to be reflowed. The normal child is always comes before // the fixed-pos placeholders, because we insert it at the start // of the child list, above. nsHTMLReflowMetrics kidDesiredSize; if (mFrames.IsEmpty()) { // We have no child frame, so return an empty size aDesiredSize.width = aDesiredSize.height = 0; } else { nsIFrame* kidFrame = mFrames.FirstChild(); bool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, nsSize(aReflowState.availableWidth, aReflowState.availableHeight)); if (aReflowState.mFlags.mVResize && (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) { // Tell our kid it's being vertically resized too. Bit of a // hack for framesets. kidReflowState.mFlags.mVResize = true; } nsPoint kidPt(kidReflowState.mComputedMargin.left, kidReflowState.mComputedMargin.top); // Apply CSS relative positioning const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay(); if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) { kidPt += nsPoint(kidReflowState.mComputedOffsets.left, kidReflowState.mComputedOffsets.top); } // Reflow the frame ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, kidPt.x, kidPt.y, 0, aStatus); // Complete the reflow and position and size the child frame FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize, kidPt.x, kidPt.y, 0); if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { nsIFrame* nextFrame = kidFrame->GetNextInFlow(); NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW, "If it's incomplete and has no nif yet, it must flag a nif reflow."); if (!nextFrame) { nsresult rv = aPresContext->PresShell()->FrameConstructor()-> CreateContinuingFrame(aPresContext, kidFrame, this, &nextFrame); NS_ENSURE_SUCCESS(rv, rv); SetOverflowFrames(aPresContext, nsFrameList(nextFrame, nextFrame)); // Root overflow containers will be normal children of // the canvas frame, but that's ok because there // aren't any other frames we need to isolate them from // during reflow. } if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); } } // If the child frame was just inserted, then we're responsible for making sure // it repaints 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 // scroll frame ensures that we are always the size of the viewport. // Also note: GetPosition() on a CanvasFrame is always going to return // (0, 0). We only want to invalidate GetRect() since Get*OverflowRect() // could also include overflow to our top and left (out of the viewport) // which doesn't need to be painted. nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); viewport->InvalidateFrame(); } // Return our desired size. Normally it's what we're told, but // sometimes we can be given an unconstrained height (when a window // is sizing-to-content), and we should compute our desired height. aDesiredSize.width = aReflowState.ComputedWidth(); if (aReflowState.ComputedHeight() == NS_UNCONSTRAINEDSIZE) { aDesiredSize.height = kidFrame->GetRect().height + kidReflowState.mComputedMargin.TopBottom(); } else { aDesiredSize.height = aReflowState.ComputedHeight(); } aDesiredSize.SetOverflowAreasToDesiredBounds(); aDesiredSize.mOverflowAreas.UnionWith( kidDesiredSize.mOverflowAreas + kidPt); } if (prevCanvasFrame) { ReflowOverflowContainerChildren(aPresContext, aReflowState, aDesiredSize.mOverflowAreas, 0, aStatus); } FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); NS_FRAME_TRACE_REFLOW_OUT("nsCanvasFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }