void nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { // initializations needed for empty markup like <mtag></mtag> aDesiredSize.Width() = aDesiredSize.Height() = 0; aDesiredSize.SetTopAscent(0); aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); nsIFrame* childFrame = GetFirstPrincipalChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); childFrame = childFrame->GetNextSibling(); } // place and size children FinalizeReflow(*aReflowState.rendContext, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
void nsMathMLTokenFrame::MarkTextFramesAsTokenMathML() { nsIFrame* child = nullptr; uint32_t childCount = 0; // Set flags on child text frames // - to force them to trim their leading and trailing whitespaces. // - Indicate which frames are suitable for mathvariant // - flag single character <mi> frames for special italic treatment for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame; childFrame = childFrame->GetNextSibling()) { for (nsIFrame* childFrame2 = childFrame->GetFirstPrincipalChild(); childFrame2; childFrame2 = childFrame2->GetNextSibling()) { if (childFrame2->GetType() == nsGkAtoms::textFrame) { childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML); child = childFrame2; childCount++; } } } if (mContent->Tag() == nsGkAtoms::mi_ && childCount == 1) { nsAutoString data; nsContentUtils::GetNodeTextContent(mContent, false, data); data.CompressWhitespace(); int32_t length = data.Length(); bool isSingleCharacter = length == 1 || (length == 2 && NS_IS_HIGH_SURROGATE(data[0])); if (isSingleCharacter) { child->AddStateBits(TEXT_IS_IN_SINGLE_CHAR_MI); } } }
void nsSVGForeignObjectFrame::MaybeReflowFromOuterSVGFrame() { // If IsDisabled() is true, then we know that our DoReflow() call will return // early, leaving us with a marked-dirty but not-reflowed kid. That'd be bad; // it'd mean that all future calls to this method would be doomed to take the // NS_FRAME_IS_DIRTY early-return below. To avoid that problem, we need to // bail out *before* we mark our kid as dirty. if (IsDisabled()) { return; } nsIFrame* kid = GetFirstPrincipalChild(); // If we're already scheduled to reflow (if we or our kid is dirty) we don't // want to reflow now or else our presShell will do extra work trying to // reflow us a second time. (It will also complain if it finds that a reflow // root scheduled for reflow isn't dirty). if (kid->GetStateBits() & NS_FRAME_IS_DIRTY) { return; } kid->AddStateBits(NS_FRAME_IS_DIRTY); // we must be fully marked dirty if (kid->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) { return; } // Make sure to not allow interrupts if we're not being reflown as a root nsPresContext::InterruptPreventer noInterrupts(PresContext()); DoReflow(); }
NS_IMETHODIMP nsTextControlFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) { nsresult rv = nsBoxFrame::SetInitialChildList(aListID, aChildList); nsIFrame* first = GetFirstPrincipalChild(); // Mark the scroll frame as being a reflow root. This will allow // incremental reflows to be initiated at the scroll frame, rather // than descending from the root frame of the frame hierarchy. if (first) { first->AddStateBits(NS_FRAME_REFLOW_ROOT); nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent()); NS_ASSERTION(txtCtrl, "Content not a text control element"); txtCtrl->InitializeKeyboardEventListeners(); nsPoint* contentScrollPos = static_cast<nsPoint*> (Properties().Get(ContentScrollPos())); if (contentScrollPos) { // If we have a scroll pos stored to be passed to our anonymous // div, do it here! nsIStatefulFrame* statefulFrame = do_QueryFrame(first); NS_ASSERTION(statefulFrame, "unexpected type of frame for the anonymous div"); nsPresState fakePresState; fakePresState.SetScrollState(*contentScrollPos); statefulFrame->RestoreState(&fakePresState); Properties().Remove(ContentScrollPos()); delete contentScrollPos; } } return rv; }
NS_IMETHODIMP nsProgressMeterFrame::AttributeChanged(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Scripts not blocked in nsProgressMeterFrame::AttributeChanged!"); nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); if (NS_OK != rv) { return rv; } // did the progress change? bool undetermined = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mode, nsGkAtoms::undetermined, eCaseMatters); if (nsGkAtoms::mode == aAttribute || (!undetermined && (nsGkAtoms::value == aAttribute || nsGkAtoms::max == aAttribute))) { nsIFrame* barChild = GetFirstPrincipalChild(); if (!barChild) return NS_OK; nsIFrame* remainderChild = barChild->GetNextSibling(); if (!remainderChild) return NS_OK; nsCOMPtr<nsIContent> remainderContent = remainderChild->GetContent(); if (!remainderContent) return NS_OK; PRInt32 flex = 1, maxFlex = 1; if (!undetermined) { nsAutoString value, maxValue; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value); mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxValue); nsresult error; flex = value.ToInteger(&error); maxFlex = maxValue.ToInteger(&error); if (NS_FAILED(error) || maxValue.IsEmpty()) { maxFlex = 100; } if (maxFlex < 1) { maxFlex = 1; } if (flex < 0) { flex = 0; } if (flex > maxFlex) { flex = maxFlex; } } nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( barChild->GetContent(), nsGkAtoms::flex, flex)); nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( remainderContent, nsGkAtoms::flex, maxFlex - flex)); nsContentUtils::AddScriptRunner(new nsReflowFrameRunnable( this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY)); } return NS_OK; }
// For token elements, mBoundingMetrics is computed at the ReflowToken // pass, it is not computed here because our children may be text frames // that do not implement the GetBoundingMetrics() interface. /* virtual */ nsresult nsMathMLTokenFrame::Place(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { mBoundingMetrics = nsBoundingMetrics(); for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame; childFrame = childFrame->GetNextSibling()) { nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode()); GetReflowAndBoundingMetricsFor(childFrame, childSize, childSize.mBoundingMetrics, nullptr); // compute and cache the bounding metrics mBoundingMetrics += childSize.mBoundingMetrics; } nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); nscoord ascent = fm->MaxAscent(); nscoord descent = fm->MaxDescent(); aDesiredSize.mBoundingMetrics = mBoundingMetrics; aDesiredSize.Width() = mBoundingMetrics.width; aDesiredSize.SetTopAscent(std::max(mBoundingMetrics.ascent, ascent)); aDesiredSize.Height() = aDesiredSize.TopAscent() + std::max(mBoundingMetrics.descent, descent); if (aPlaceOrigin) { nscoord dy, dx = 0; for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame; childFrame = childFrame->GetNextSibling()) { nsHTMLReflowMetrics childSize(aDesiredSize.GetWritingMode()); GetReflowAndBoundingMetricsFor(childFrame, childSize, childSize.mBoundingMetrics); // place and size the child; (dx,0) makes the caret happy - bug 188146 dy = childSize.Height() == 0 ? 0 : aDesiredSize.TopAscent() - childSize.TopAscent(); FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy, 0); dx += childSize.Width(); } } SetReference(nsPoint(0, aDesiredSize.TopAscent())); return NS_OK; }
void nsSVGForeignObjectFrame::UpdateBounds() { NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingUpdateBounds(this), "This call is probaby a wasteful mistake"); NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), "UpdateBounds mechanism not designed for this"); if (!nsSVGUtils::NeedsUpdatedBounds(this)) { return; } // We update mRect before the DoReflow call so that DoReflow uses the // correct dimensions: float x, y, w, h; static_cast<nsSVGForeignObjectElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &w, &h, nsnull); // If mRect's width or height are negative, reflow blows up! We must clamp! if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; // GetCanvasTM includes the x,y translation mRect = nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(0.0, 0.0, w, h), PresContext()->AppUnitsPerCSSPixel()); mCoveredRegion = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext()); // Since we'll invalidate our entire area at the end of this method, we // empty our cached dirty regions to prevent FlushDirtyRegion under DoReflow // from wasting time invalidating: mSameDocDirtyRegion.SetEmpty(); mSubDocDirtyRegion.SetEmpty(); // Fully mark our kid dirty so that it gets resized if necessary // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case): nsIFrame* kid = GetFirstPrincipalChild(); kid->AddStateBits(NS_FRAME_IS_DIRTY); // Make sure to not allow interrupts if we're not being reflown as a root: nsPresContext::InterruptPreventer noInterrupts(PresContext()); DoReflow(); // Now unset the various reflow bits: mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // We only invalidate if our outer-<svg> has already had its // initial reflow (since if it hasn't, its entire area will be // invalidated when it gets that initial reflow): nsSVGUtils::InvalidateBounds(this, true); } }
virtual nsIFrame* GetContentInsertionFrame() { nsIFrame* frame = GetFirstPrincipalChild(); // if no children return nsnull if (!frame) return nsnull; return frame->GetContentInsertionFrame(); }
nsresult nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; // initializations needed for empty markup like <mtag></mtag> aDesiredSize.width = aDesiredSize.height = 0; aDesiredSize.ascent = 0; aDesiredSize.mBoundingMetrics = nsBoundingMetrics(); nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); nsIFrame* childFrame = GetFirstPrincipalChild(); while (childFrame) { // ask our children to compute their bounding metrics nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags | NS_REFLOW_CALC_BOUNDING_METRICS); nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame, availSize); rv = ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState, aStatus); //NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); if (NS_FAILED(rv)) { // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(GetFirstPrincipalChild(), childFrame); return rv; } SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize, childDesiredSize.mBoundingMetrics); childFrame = childFrame->GetNextSibling(); } // place and size children FinalizeReflow(*aReflowState.rendContext, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType) { if (GetStateBits() & NS_FRAME_FIRST_REFLOW) // If we haven't had a UpdateBounds yet, nothing to do. return; nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return; PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY); }
void nsSVGForeignObjectFrame::DoReflow() { // Skip reflow if we're zero-sized, unless this is our first reflow. if (IsDisabled() && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) return; nsPresContext *presContext = PresContext(); nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return; // initiate a synchronous reflow here and now: nsIPresShell* presShell = presContext->PresShell(); NS_ASSERTION(presShell, "null presShell"); nsRefPtr<nsRenderingContext> renderingContext = presShell->GetReferenceRenderingContext(); if (!renderingContext) return; mInReflow = true; nsHTMLReflowState reflowState(presContext, kid, renderingContext, nsSize(mRect.width, NS_UNCONSTRAINEDSIZE)); nsHTMLReflowMetrics desiredSize; nsReflowStatus status; // We don't use mRect.height above because that tells the child to do // page/column breaking at that height. NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) && reflowState.mComputedMargin == nsMargin(0, 0, 0, 0), "style system should ensure that :-moz-svg-foreign-content " "does not get styled"); NS_ASSERTION(reflowState.ComputedWidth() == mRect.width, "reflow state made child wrong size"); reflowState.SetComputedHeight(mRect.height); ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, status); NS_ASSERTION(mRect.width == desiredSize.width && mRect.height == desiredSize.height, "unexpected size"); FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); mInReflow = false; if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { FlushDirtyRegion(0); } }
/* virtual */ void nsMathMLmfencedFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) { nscoord width = 0; nsPresContext* presContext = PresContext(); const nsStyleFont* font = StyleFont(); nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); nscoord em; GetEmHeight(fm, em); if (mOpenChar) { width += GetMaxCharWidth(presContext, aRenderingContext, mOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em); } int32_t i = 0; nsIFrame* childFrame = GetFirstPrincipalChild(); while (childFrame) { // XXX This includes margin while Reflow currently doesn't consider // margin, so we may end up with too much space, but, with stretchy // characters, this is an approximation anyway. width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame, nsLayoutUtils::PREF_WIDTH); if (i < mSeparatorsCount) { width += GetMaxCharWidth(presContext, aRenderingContext, &mSeparatorsChar[i], NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em); } i++; childFrame = childFrame->GetNextSibling(); } if (mCloseChar) { width += GetMaxCharWidth(presContext, aRenderingContext, mCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em); } aDesiredSize.Width() = width; aDesiredSize.mBoundingMetrics.width = width; aDesiredSize.mBoundingMetrics.leftBearing = 0; aDesiredSize.mBoundingMetrics.rightBearing = width; }
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; }
/* virtual */ nsresult nsMathMLmpaddedFrame::Place(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize) { nsresult rv = nsMathMLContainerFrame::Place(aRenderingContext, false, aDesiredSize); if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { DidReflowChildren(GetFirstPrincipalChild()); return rv; } nscoord height = mBoundingMetrics.ascent; nscoord depth = mBoundingMetrics.descent; // The REC says: // // "The lspace attribute ('leading' space) specifies the horizontal location // of the positioning point of the child content with respect to the // positioning point of the mpadded element. By default they coincide, and // therefore absolute values for lspace have the same effect as relative // values." // // "MathML renderers should ensure that, except for the effects of the // attributes, the relative spacing between the contents of the mpadded // element and surrounding MathML elements would not be modified by replacing // an mpadded element with an mrow element with the same content, even if // linebreaking occurs within the mpadded element." // // (http://www.w3.org/TR/MathML/chapter3.html#presm.mpadded) // // "In those discussions, the terms leading and trailing are used to specify // a side of an object when which side to use depends on the directionality; // ie. leading means left in LTR but right in RTL." // (http://www.w3.org/TR/MathML/chapter3.html#presm.bidi.math) nscoord lspace = 0; // In MathML3, "width" will be the bounding box width and "advancewidth" will // refer "to the horizontal distance between the positioning point of the // mpadded and the positioning point for the following content". MathML2 // doesn't make the distinction. nscoord width = mBoundingMetrics.width; nscoord voffset = 0; int32_t pseudoUnit; nscoord initialWidth = width; // update width pseudoUnit = (mWidthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_WIDTH : mWidthPseudoUnit; UpdateValue(mWidthSign, pseudoUnit, mWidth, mBoundingMetrics, width); width = NS_MAX(0, width); // update "height" (this is the ascent in the terminology of the REC) pseudoUnit = (mHeightPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_HEIGHT : mHeightPseudoUnit; UpdateValue(mHeightSign, pseudoUnit, mHeight, mBoundingMetrics, height); height = NS_MAX(0, height); // update "depth" (this is the descent in the terminology of the REC) pseudoUnit = (mDepthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF) ? NS_MATHML_PSEUDO_UNIT_DEPTH : mDepthPseudoUnit; UpdateValue(mDepthSign, pseudoUnit, mDepth, mBoundingMetrics, depth); depth = NS_MAX(0, depth); // update lspace if (mLeadingSpacePseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) { pseudoUnit = mLeadingSpacePseudoUnit; UpdateValue(mLeadingSpaceSign, pseudoUnit, mLeadingSpace, mBoundingMetrics, lspace); } // update voffset if (mVerticalOffsetPseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) { pseudoUnit = mVerticalOffsetPseudoUnit; UpdateValue(mVerticalOffsetSign, pseudoUnit, mVerticalOffset, mBoundingMetrics, voffset); } // do the padding now that we have everything // The idea here is to maintain the invariant that <mpadded>...</mpadded> (i.e., // with no attributes) looks the same as <mrow>...</mrow>. But when there are // attributes, tweak our metrics and move children to achieve the desired visual // effects. if ((NS_MATHML_IS_RTL(mPresentationData.flags) ? mWidthSign : mLeadingSpaceSign) != NS_MATHML_SIGN_INVALID) { // there was padding on the left. dismiss the left italic correction now // (so that our parent won't correct us) mBoundingMetrics.leftBearing = 0; } if ((NS_MATHML_IS_RTL(mPresentationData.flags) ? mLeadingSpaceSign : mWidthSign) != NS_MATHML_SIGN_INVALID) { // there was padding on the right. dismiss the right italic correction now // (so that our parent won't correct us) mBoundingMetrics.width = width; mBoundingMetrics.rightBearing = mBoundingMetrics.width; } nscoord dy = height - mBoundingMetrics.ascent; nscoord dx = NS_MATHML_IS_RTL(mPresentationData.flags) ? width - initialWidth - lspace : lspace; aDesiredSize.ascent += dy; aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.height += dy + depth - mBoundingMetrics.descent; mBoundingMetrics.ascent = height; mBoundingMetrics.descent = depth; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { // Finish reflowing child frames, positioning their origins. PositionRowChildFrames(dx, aDesiredSize.ascent - voffset); } return NS_OK; }
void nsSVGForeignObjectFrame::DoReflow() { NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)-> GetStateBits() & NS_FRAME_FIRST_REFLOW), "Calling InitialUpdate too early - must not call DoReflow!!!"); // Skip reflow if we're zero-sized, unless this is our first reflow. if (IsDisabled() && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) return; if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) return; nsPresContext *presContext = PresContext(); nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return; // initiate a synchronous reflow here and now: nsSize availableSpace(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); nsIPresShell* presShell = presContext->PresShell(); NS_ASSERTION(presShell, "null presShell"); nsRefPtr<nsRenderingContext> renderingContext = presShell->GetReferenceRenderingContext(); if (!renderingContext) return; nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*> (mContent); float width = fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO); float height = fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO); // Clamp height & width to be non-negative (to match UpdateCoveredRegion). width = NS_MAX(width, 0.0f); height = NS_MAX(height, 0.0f); nsSize size(nsPresContext::CSSPixelsToAppUnits(width), nsPresContext::CSSPixelsToAppUnits(height)); mInReflow = true; nsHTMLReflowState reflowState(presContext, kid, renderingContext, nsSize(size.width, NS_UNCONSTRAINEDSIZE)); nsHTMLReflowMetrics desiredSize; nsReflowStatus status; // We don't use size.height above because that tells the child to do // page/column breaking at that height. NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) && reflowState.mComputedMargin == nsMargin(0, 0, 0, 0), "style system should ensure that :-moz-svg-foreign content " "does not get styled"); NS_ASSERTION(reflowState.ComputedWidth() == size.width, "reflow state made child wrong size"); reflowState.SetComputedHeight(size.height); ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, status); NS_ASSERTION(size.width == desiredSize.width && size.height == desiredSize.height, "unexpected size"); FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); mInReflow = false; FlushDirtyRegion(0); }
NS_IMETHODIMP nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { nsresult rv; if (GetPrevInFlow()) { DisplayOverflowContainers(aBuilder, aDirtyRect, aLists); } // Force a background to be shown. We may have a background propagated to us, // in which case GetStyleBackground wouldn't have the right background // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us // a background. // We don't have any border or outline, and our background draws over // the overflow area, so just add nsDisplayCanvasBackground instead of // calling DisplayBorderBackgroundOutline. if (IsVisibleForPainting(aBuilder)) { nsStyleContext* bgSC; const nsStyleBackground* bg = nullptr; bool isThemed = IsThemed(); if (!isThemed && nsCSSRendering::FindBackground(PresContext(), this, &bgSC)) { bg = bgSC->GetStyleBackground(); } aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayCanvasBackgroundColor(aBuilder, this)); if (isThemed) { return aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, 0, isThemed, nullptr)); } if (!bg) { return NS_OK; } // Create separate items for each background layer. NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) { if (bg->mLayers[i].mImage.IsEmpty()) { continue; } rv = aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i, isThemed, bg)); NS_ENSURE_SUCCESS(rv, rv); } } nsIFrame* kid; for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { // Put our child into its own pseudo-stack. rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); NS_ENSURE_SUCCESS(rv, rv); } #ifdef DEBUG_CANVAS_FOCUS nsCOMPtr<nsIContent> focusContent; aPresContext->EventStateManager()-> GetFocusedContent(getter_AddRefs(focusContent)); bool hasFocus = false; nsCOMPtr<nsISupports> container; aPresContext->GetContainer(getter_AddRefs(container)); nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container)); if (docShell) { docShell->GetHasFocus(&hasFocus); printf("%p - nsCanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this, mRect.x, mRect.y, mRect.width, mRect.height, aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); } printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N", focusContent.get(), mDoPaintFocus?"Y":"N"); #endif if (!mDoPaintFocus) return NS_OK; // Only paint the focus if we're visible if (!GetStyleVisibility()->IsVisible()) return NS_OK; return aLists.Outlines()->AppendNewToTop(new (aBuilder) nsDisplayCanvasFocus(aBuilder, this)); }
NS_IMETHODIMP nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext, const nsIntRect *aDirtyRect) { if (IsDisabled()) return NS_OK; nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return NS_OK; gfxMatrix matrixForChildren = GetCanvasTMForChildren(); gfxMatrix matrix = GetCanvasTM(); if (matrixForChildren.IsSingular()) { NS_WARNING("Can't render foreignObject element!"); return NS_ERROR_FAILURE; } nsRect kidDirtyRect = kid->GetVisualOverflowRect(); /* Check if we need to draw anything. */ if (aDirtyRect) { // Transform the dirty rect into app units in our userspace. gfxMatrix invmatrix = matrix; invmatrix.Invert(); NS_ASSERTION(!invmatrix.IsSingular(), "inverse of non-singular matrix should be non-singular"); gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height); transDirtyRect = invmatrix.TransformBounds(transDirtyRect); kidDirtyRect.IntersectRect(kidDirtyRect, nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect, PresContext()->AppUnitsPerCSSPixel())); // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect, // not with kidDirtyRect. I.e. // PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect) if (kidDirtyRect.IsEmpty()) return NS_OK; } gfxContext *gfx = aContext->ThebesContext(); gfx->Save(); if (GetStyleDisplay()->IsScrollableOverflow()) { float x, y, width, height; static_cast<nsSVGElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height); nsSVGUtils::SetClipRect(gfx, matrix, clipRect); } gfx->Multiply(matrixForChildren); PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM; if (SVGAutoRenderState::IsPaintingToWindow(aContext)) { flags |= nsLayoutUtils::PAINT_TO_WINDOW; } nsresult rv = nsLayoutUtils::PaintFrame(aContext, kid, nsRegion(kidDirtyRect), NS_RGBA(0,0,0,0), flags); gfx->Restore(); return rv; }
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(); int32_t 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 = GetFirstPrincipalChild(); 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 = std::max(containerSize.ascent - axisHeight, containerSize.descent + axisHeight); containerSize.ascent = delta + axisHeight; containerSize.descent = delta - axisHeight; bool isRTL = NS_MATHML_IS_RTL(mPresentationData.flags); ///////////////// // opening fence ... ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar, NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent, isRTL); ///////////////// // 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, isRTL); } ///////////////// // closing fence ... ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar, NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, axisHeight, leading, em, containerSize, ascent, descent, isRTL); ////////////////// // Adjust the origins of each child. // and update our bounding metrics i = 0; nscoord dx = 0; nsBoundingMetrics bm; bool firstTime = true; nsMathMLChar *leftChar, *rightChar; if (isRTL) { leftChar = mCloseChar; rightChar = mOpenChar; } else { leftChar = mOpenChar; rightChar = mCloseChar; } if (leftChar) { PlaceChar(leftChar, ascent, bm, dx); aDesiredSize.mBoundingMetrics = bm; firstTime = false; } if (isRTL) { childFrame = this->GetLastChild(nsIFrame::kPrincipalList); } else { childFrame = firstChild; } while (childFrame) { nsHTMLReflowMetrics childSize; GetReflowAndBoundingMetricsFor(childFrame, childSize, bm); if (firstTime) { firstTime = false; aDesiredSize.mBoundingMetrics = bm; } else aDesiredSize.mBoundingMetrics += bm; FinishReflowChild(childFrame, aPresContext, nullptr, childSize, dx, ascent - childSize.ascent, 0); dx += childSize.width; if (i < mSeparatorsCount) { PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i], ascent, bm, dx); aDesiredSize.mBoundingMetrics += bm; } i++; if (isRTL) { childFrame = childFrame->GetPrevSibling(); } else { childFrame = childFrame->GetNextSibling(); } } if (rightChar) { PlaceChar(rightChar, 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; }
/* virtual */ nsresult nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext, bool aPlaceOrigin, nsHTMLReflowMetrics& aDesiredSize, bool aWidthOnly) { /////////////// // Measure the size of our content using the base class to format like an // inferred mrow. nsHTMLReflowMetrics baseSize; nsresult rv = nsMathMLContainerFrame::Place(aRenderingContext, false, baseSize); if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { DidReflowChildren(GetFirstPrincipalChild()); return rv; } nsBoundingMetrics bmBase = baseSize.mBoundingMetrics; nscoord dx_left = 0, dx_right = 0; nsBoundingMetrics bmLongdivChar, bmRadicalChar; nscoord radicalAscent = 0, radicalDescent = 0; nscoord longdivAscent = 0, longdivDescent = 0; nscoord psi = 0; /////////////// // Thickness of bars and font metrics nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); nscoord mEmHeight; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); aRenderingContext.SetFont(fm); GetRuleThickness(aRenderingContext, fm, mRuleThickness); GetEmHeight(fm, mEmHeight); PRUnichar one = '1'; nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1); /////////////// // General rules: the menclose element takes the size of the enclosed content. // We add a padding when needed. // determine padding & psi nscoord padding = 3 * mRuleThickness; nscoord delta = padding % onePixel; if (delta) padding += onePixel - delta; // round up if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) { nscoord phi; // Rule 11, App. G, TeXbook // psi = clearance between rule and content if (NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) phi = fm->XHeight(); else phi = mRuleThickness; psi = mRuleThickness + phi / 4; delta = psi % onePixel; if (delta) psi += onePixel - delta; // round up } if (mRuleThickness < onePixel) mRuleThickness = onePixel; // Set horizontal parameters if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) dx_left = padding; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) dx_right = padding; // Set vertical parameters if (IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_RADICAL) || IsToDraw(NOTATION_LONGDIV)) { // set a minimal value for the base height bmBase.ascent = NS_MAX(bmOne.ascent, bmBase.ascent); bmBase.descent = NS_MAX(0, bmBase.descent); } mBoundingMetrics.ascent = bmBase.ascent; mBoundingMetrics.descent = bmBase.descent; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_CIRCLE)) mBoundingMetrics.ascent += padding; if (IsToDraw(NOTATION_ROUNDEDBOX) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_CIRCLE)) mBoundingMetrics.descent += padding; /////////////// // circle notation: we don't want the ellipse to overlap the enclosed // content. Hence, we need to increase the size of the bounding box by a // factor of at least sqrt(2). if (IsToDraw(NOTATION_CIRCLE)) { double ratio = (sqrt(2.0) - 1.0) / 2.0; nscoord padding2; // Update horizontal parameters padding2 = ratio * bmBase.width; dx_left = NS_MAX(dx_left, padding2); dx_right = NS_MAX(dx_right, padding2); // Update vertical parameters padding2 = ratio * (bmBase.ascent + bmBase.descent); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, bmBase.ascent + padding2); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, bmBase.descent + padding2); } /////////////// // longdiv notation: if (IsToDraw(NOTATION_LONGDIV)) { if (aWidthOnly) { nscoord longdiv_width = mMathMLChar[mLongDivCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters dx_left = NS_MAX(dx_left, longdiv_width); } else { // Stretch the parenthesis to the appropriate height if it is not // big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = mRuleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(longdiv) should be >= height(base) + psi + mRuleThickness mMathMLChar[mLongDivCharIndex].Stretch(PresContext(), aRenderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, bmLongdivChar, NS_STRETCH_LARGER, false); mMathMLChar[mLongDivCharIndex].GetBoundingMetrics(bmLongdivChar); // Update horizontal parameters dx_left = NS_MAX(dx_left, bmLongdivChar.width); // Update vertical parameters longdivAscent = bmBase.ascent + psi + mRuleThickness; longdivDescent = NS_MAX(bmBase.descent, (bmLongdivChar.ascent + bmLongdivChar.descent - longdivAscent)); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, longdivAscent); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, longdivDescent); } } /////////////// // radical notation: if (IsToDraw(NOTATION_RADICAL)) { nscoord *dx_leading = NS_MATHML_IS_RTL(mPresentationData.flags) ? &dx_right : &dx_left; if (aWidthOnly) { nscoord radical_width = mMathMLChar[mRadicalCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters *dx_leading = NS_MAX(*dx_leading, radical_width); } else { // Stretch the radical symbol to the appropriate height if it is not // big enough. nsBoundingMetrics contSize = bmBase; contSize.ascent = mRuleThickness; contSize.descent = bmBase.ascent + bmBase.descent + psi; // height(radical) should be >= height(base) + psi + mRuleThickness mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, bmRadicalChar, NS_STRETCH_LARGER, NS_MATHML_IS_RTL(mPresentationData.flags)); mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar); // Update horizontal parameters *dx_leading = NS_MAX(*dx_leading, bmRadicalChar.width); // Update vertical parameters radicalAscent = bmBase.ascent + psi + mRuleThickness; radicalDescent = NS_MAX(bmBase.descent, (bmRadicalChar.ascent + bmRadicalChar.descent - radicalAscent)); mBoundingMetrics.ascent = NS_MAX(mBoundingMetrics.ascent, radicalAscent); mBoundingMetrics.descent = NS_MAX(mBoundingMetrics.descent, radicalDescent); } } /////////////// // if (IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || (IsToDraw(NOTATION_LEFT) && IsToDraw(NOTATION_RIGHT))) { // center the menclose around the content (horizontally) dx_left = dx_right = NS_MAX(dx_left, dx_right); } /////////////// // The maximum size is now computed: set the remaining parameters mBoundingMetrics.width = dx_left + bmBase.width + dx_right; mBoundingMetrics.leftBearing = NS_MIN(0, dx_left + bmBase.leftBearing); mBoundingMetrics.rightBearing = NS_MAX(mBoundingMetrics.width, dx_left + bmBase.rightBearing); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.ascent = NS_MAX(mBoundingMetrics.ascent, baseSize.ascent); aDesiredSize.height = aDesiredSize.ascent + NS_MAX(mBoundingMetrics.descent, baseSize.height - baseSize.ascent); if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) { // get the leading to be left at the top of the resulting frame // this seems more reliable than using fm->GetLeading() on suspicious // fonts nscoord leading = nscoord(0.2f * mEmHeight); nscoord desiredSizeAscent = aDesiredSize.ascent; nscoord desiredSizeDescent = aDesiredSize.height - aDesiredSize.ascent; if (IsToDraw(NOTATION_LONGDIV)) { desiredSizeAscent = NS_MAX(desiredSizeAscent, longdivAscent + leading); desiredSizeDescent = NS_MAX(desiredSizeDescent, longdivDescent + mRuleThickness); } if (IsToDraw(NOTATION_RADICAL)) { desiredSizeAscent = NS_MAX(desiredSizeAscent, radicalAscent + leading); desiredSizeDescent = NS_MAX(desiredSizeDescent, radicalDescent + mRuleThickness); } aDesiredSize.ascent = desiredSizeAscent; aDesiredSize.height = desiredSizeAscent + desiredSizeDescent; } if (IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX) || (IsToDraw(NOTATION_TOP) && IsToDraw(NOTATION_BOTTOM))) { // center the menclose around the content (vertically) nscoord dy = NS_MAX(aDesiredSize.ascent - bmBase.ascent, aDesiredSize.height - aDesiredSize.ascent - bmBase.descent); aDesiredSize.ascent = bmBase.ascent + dy; aDesiredSize.height = aDesiredSize.ascent + bmBase.descent + dy; } // Update mBoundingMetrics ascent/descent if (IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.ascent = aDesiredSize.ascent; if (IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.descent = aDesiredSize.height - aDesiredSize.ascent; aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.ascent; if (aPlaceOrigin) { ////////////////// // Set position and size of MathMLChars if (IsToDraw(NOTATION_LONGDIV)) mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left - bmLongdivChar.width, aDesiredSize.ascent - longdivAscent, bmLongdivChar.width, bmLongdivChar.ascent + bmLongdivChar.descent)); if (IsToDraw(NOTATION_RADICAL)) { nscoord dx = NS_MATHML_IS_RTL(mPresentationData.flags) ? dx_left + bmBase.width : dx_left - bmRadicalChar.width; mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx, aDesiredSize.ascent - radicalAscent, bmRadicalChar.width, bmRadicalChar.ascent + bmRadicalChar.descent)); } mContentWidth = bmBase.width; ////////////////// // Finish reflowing child frames PositionRowChildFrames(dx_left, aDesiredSize.ascent); } return NS_OK; }
nsresult nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext* aRenderingContext, nsSize& aIntrinsicSize, float aFontSizeInflation) { // Get leading and the Average/MaxAdvance char width nscoord lineHeight = 0; nscoord charWidth = 0; nscoord charMaxAdvance = 0; nsRefPtr<nsFontMetrics> fontMet; nsresult rv = nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet), aFontSizeInflation); NS_ENSURE_SUCCESS(rv, rv); aRenderingContext->SetFont(fontMet); lineHeight = nsHTMLReflowState::CalcLineHeight(GetStyleContext(), NS_AUTOHEIGHT, aFontSizeInflation); charWidth = fontMet->AveCharWidth(); charMaxAdvance = fontMet->MaxAdvance(); // Set the width equal to the width in characters PRInt32 cols = GetCols(); aIntrinsicSize.width = cols * charWidth; // To better match IE, take the maximum character width(in twips) and remove // 4 pixels add this on as additional padding(internalPadding). But only do // this if charMaxAdvance != charWidth; if they are equal, this is almost // certainly a fixed-width font. if (charWidth != charMaxAdvance) { nscoord internalPadding = NS_MAX(0, charMaxAdvance - nsPresContext::CSSPixelsToAppUnits(4)); nscoord t = nsPresContext::CSSPixelsToAppUnits(1); // Round to a multiple of t nscoord rest = internalPadding % t; if (rest < t - rest) { internalPadding -= rest; } else { internalPadding += t - rest; } // Now add the extra padding on (so that small input sizes work well) aIntrinsicSize.width += internalPadding; } else { // This is to account for the anonymous <br> having a 1 twip width // in Full Standards mode, see BRFrame::Reflow and bug 228752. if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards) { aIntrinsicSize.width += 1; } // Also add in the padding of our value div child. Note that it hasn't // been reflowed yet, so we can't get its used padding, but it shouldn't be // using percentage padding anyway. nsMargin childPadding; nsIFrame* firstChild = GetFirstPrincipalChild(); if (firstChild && firstChild->GetStylePadding()->GetPadding(childPadding)) { aIntrinsicSize.width += childPadding.LeftRight(); } else { NS_ERROR("Percentage padding on value div?"); } } // Increment width with cols * letter-spacing. { const nsStyleCoord& lsCoord = GetStyleText()->mLetterSpacing; if (eStyleUnit_Coord == lsCoord.GetUnit()) { nscoord letterSpacing = lsCoord.GetCoordValue(); if (letterSpacing != 0) { aIntrinsicSize.width += cols * letterSpacing; } } } // Set the height equal to total number of rows (times the height of each // line, of course) aIntrinsicSize.height = lineHeight * GetRows(); // Add in the size of the scrollbars for textarea if (IsTextArea()) { nsIFrame* first = GetFirstPrincipalChild(); nsIScrollableFrame *scrollableFrame = do_QueryFrame(first); NS_ASSERTION(scrollableFrame, "Child must be scrollable"); if (scrollableFrame) { nsMargin scrollbarSizes = scrollableFrame->GetDesiredScrollbarSizes(PresContext(), aRenderingContext); aIntrinsicSize.width += scrollbarSizes.LeftRight(); aIntrinsicSize.height += scrollbarSizes.TopBottom();; } } return NS_OK; }
NS_IMETHODIMP nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect) { NS_ABORT_IF_FALSE(aDirtyRect, "We expect aDirtyRect to be non-null"); if (IsDisabled()) return NS_OK; nsIFrame* kid = GetFirstPrincipalChild(); if (!kid) return NS_OK; gfxMatrix matrixForChildren = GetCanvasTMForChildren(); gfxMatrix matrix = GetCanvasTM(); nsRenderingContext *ctx = aContext->GetRenderingContext(this); if (!ctx || matrixForChildren.IsSingular()) { NS_WARNING("Can't render foreignObject element!"); return NS_ERROR_FAILURE; } /* Check if we need to draw anything. */ PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); if (!mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)) return NS_OK; gfxContext *gfx = aContext->GetGfxContext(); gfx->Save(); if (GetStyleDisplay()->IsScrollableOverflow()) { float x, y, width, height; static_cast<nsSVGElement*>(mContent)-> GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height); nsSVGUtils::SetClipRect(gfx, matrix, clipRect); } gfx->Multiply(matrixForChildren); // Transform the dirty rect into the rectangle containing the // transformed dirty rect. gfxMatrix invmatrix = matrix.Invert(); NS_ASSERTION(!invmatrix.IsSingular(), "inverse of non-singular matrix should be non-singular"); gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height); transDirtyRect = invmatrix.TransformBounds(transDirtyRect); transDirtyRect.Scale(nsPresContext::AppUnitsPerCSSPixel()); nsPoint tl(NSToCoordFloor(transDirtyRect.X()), NSToCoordFloor(transDirtyRect.Y())); nsPoint br(NSToCoordCeil(transDirtyRect.XMost()), NSToCoordCeil(transDirtyRect.YMost())); nsRect kidDirtyRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y); kidDirtyRect.IntersectRect(kidDirtyRect, kid->GetRect()); PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM; if (aContext->IsPaintingToWindow()) { flags |= nsLayoutUtils::PAINT_TO_WINDOW; } nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kidDirtyRect), NS_RGBA(0,0,0,0), flags); gfx->Restore(); return rv; }