nsDOMScrollAreaEvent::nsDOMScrollAreaEvent(nsPresContext *aPresContext, nsScrollAreaEvent *aEvent) : nsDOMUIEvent(aPresContext, aEvent) { mClientArea.SetLayoutRect(aEvent ? aEvent->mArea : nsRect()); }
/** * 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. */ PRBool nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState, PRBool aForceFit, nsLineBox* aLine, nsCollapsingMargin& aBottomMarginResult, nsRect& aInFlowBounds, nsRect& aCombinedRect, 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); PRBool 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 PR_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 PR_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); aCombinedRect = mMetrics.mOverflowArea + nsPoint(x, y); return PR_TRUE; }
static nsIFrame* GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs, nsIFrame* aRestrictToDescendants, nsTArray<nsIFrame*>& aCandidates, int32_t* aElementsInCluster) { 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; } (*aElementsInCluster)++; // 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; }
// Construct a rectangle, remove part of it, then check the remainder static bool TestNonRectangular() { nsRegion r(nsRect(0, 0, 30, 30)); const int nTests = 19; struct { nsRect rect; PRInt64 expectedArea; } tests[nTests] = { // Remove a 20x10 chunk from the square { nsRect(0, 0, 20, 10), 600 }, { nsRect(10, 0, 20, 10), 600 }, { nsRect(10, 20, 20, 10), 600 }, { nsRect(0, 20, 20, 10), 600 }, // Remove a 10x20 chunk from the square { nsRect(0, 0, 10, 20), 600 }, { nsRect(20, 0, 10, 20), 600 }, { nsRect(20, 10, 10, 20), 600 }, { nsRect(0, 10, 10, 20), 600 }, // Remove the center 10x10 { nsRect(10, 10, 10, 10), 300 }, // Remove the middle column { nsRect(10, 0, 10, 30), 300 }, // Remove the middle row { nsRect(0, 10, 30, 10), 300 }, // Remove the corners 10x10 { nsRect(0, 0, 10, 10), 600 }, { nsRect(20, 20, 10, 10), 600 }, { nsRect(20, 0, 10, 10), 600 }, { nsRect(0, 20, 10, 10), 600 }, // Remove the corners 20x20 { nsRect(0, 0, 20, 20), 300 }, { nsRect(10, 10, 20, 20), 300 }, { nsRect(10, 0, 20, 20), 300 }, { nsRect(0, 10, 20, 20), 300 } }; bool success = true; for (PRInt32 i = 0; i < nTests; i++) { nsRegion r2; r2.Sub(r, tests[i].rect); if (!r2.IsComplex()) fail("nsRegion code got unexpectedly smarter!"); nsRect largest = r2.GetLargestRectangle(); if (largest.width * largest.height != tests[i].expectedArea) { fail("Did not succesfully find largest rectangle in non-rectangular region on iteration %d", i); success = false; } } return success; }
// helper functions to perform the common task of formatting our chars /*static*/ nsresult nsMathMLmfencedFrame::ReflowChar(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsMathMLChar* aMathMLChar, nsOperatorFlags aForm, int32_t aScriptLevel, nscoord axisHeight, nscoord leading, nscoord em, nsBoundingMetrics& aContainerSize, nscoord& aAscent, nscoord& aDescent, bool aRTL) { if (aMathMLChar && 0 < aMathMLChar->Length()) { nscoord leftSpace; nscoord rightSpace; GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace); // stretch the char to the appropriate height if it is not big enough. nsBoundingMetrics charSize; nsresult res = aMathMLChar->Stretch(aPresContext, aRenderingContext, NS_STRETCH_DIRECTION_VERTICAL, aContainerSize, charSize, NS_STRETCH_NORMAL, aRTL); if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) { // has changed... so center the char around the axis nscoord height = charSize.ascent + charSize.descent; charSize.ascent = height/2 + axisHeight; charSize.descent = height - charSize.ascent; } else { // either it hasn't changed or stretching the char failed (i.e., // GetBoundingMetrics failed) leading = 0; if (NS_FAILED(res)) { nsAutoString data; aMathMLChar->GetData(data); nsBoundingMetrics metrics = aRenderingContext.GetBoundingMetrics(data.get(), data.Length()); charSize.ascent = metrics.ascent; charSize.descent = metrics.descent; charSize.width = metrics.width; // Set this as the bounding metrics of the MathMLChar to leave // the necessary room to paint the char. aMathMLChar->SetBoundingMetrics(charSize); } } if (aAscent < charSize.ascent + leading) aAscent = charSize.ascent + leading; if (aDescent < charSize.descent + leading) aDescent = charSize.descent + leading; // account the spacing charSize.width += leftSpace + rightSpace; // x-origin is used to store lspace ... // y-origin is used to stored the ascent ... aMathMLChar->SetRect(nsRect(leftSpace, charSize.ascent, charSize.width, charSize.ascent + charSize.descent)); } return NS_OK; }
NS_IMETHODIMP nsFieldSetFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame", aReflowState.reason); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // Initialize OUT parameter aStatus = NS_FRAME_COMPLETE; // Should we create a space manager? nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState)); // XXXldb If we start storing the space manager in the frame rather // than keeping it around only during reflow then we should create it // only when there are actually floats to manage. Otherwise things // like tables will gain significant bloat. if (NS_BLOCK_SPACE_MGR & mState) autoSpaceManager.CreateSpaceManagerFor(aPresContext, this); //------------ Handle Incremental Reflow ----------------- PRBool reflowContent = PR_TRUE; PRBool reflowLegend = PR_TRUE; nsReflowReason reason = aReflowState.reason; if (reason == eReflowReason_Incremental) { nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand; // See if it's targeted at us if (command) { nsReflowType reflowType; command->GetType(reflowType); switch (reflowType) { case eReflowType_StyleChanged: reason = eReflowReason_StyleChange; break; case eReflowType_ReflowDirty: reason = eReflowReason_Dirty; break; default: NS_ERROR("Unexpected Reflow Type"); } } else { reflowContent = PR_FALSE; reflowLegend = PR_FALSE; nsReflowPath::iterator iter = aReflowState.path->FirstChild(); nsReflowPath::iterator end = aReflowState.path->EndChildren(); for ( ; iter != end; ++iter) { if (*iter == mLegendFrame) reflowLegend = PR_TRUE; else if (*iter == mContentFrame) reflowContent = PR_TRUE; } } } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else if (reason == eReflowReason_Dirty) { // if dirty then check dirty flags if (GetStateBits() & NS_FRAME_IS_DIRTY) { reflowLegend = PR_TRUE; reflowContent = PR_TRUE; } else { if (reflowContent) { reflowContent = mContentFrame ? (mContentFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } if (reflowLegend) { reflowLegend = mLegendFrame ? (mLegendFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE; } } } // availSize could have unconstrained values, don't perform any addition on them nsSize availSize(aReflowState.mComputedWidth, aReflowState.availableHeight); // get our border and padding const nsMargin &borderPadding = aReflowState.mComputedBorderPadding; const nsMargin &padding = aReflowState.mComputedPadding; nsMargin border = borderPadding - padding; if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = borderPadding.left + borderPadding.right; } // Figure out how big the legend is if there is one. // get the legend's margin nsMargin legendMargin(0,0,0,0); // reflow the legend only if needed if (mLegendFrame) { const nsStyleMargin* marginStyle = mLegendFrame->GetStyleMargin(); marginStyle->GetMargin(legendMargin); if (reflowLegend) { nsHTMLReflowState legendReflowState(aPresContext, aReflowState, mLegendFrame, nsSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE), reason); // always give the legend as much size as it needs legendReflowState.mComputedWidth = NS_INTRINSICSIZE; legendReflowState.mComputedHeight = NS_INTRINSICSIZE; nsHTMLReflowMetrics legendDesiredSize(0,0); ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState, 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); #ifdef NOISY_REFLOW printf(" returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height); if (legendDesiredSize.mComputeMEW) printf(" and maxEW %d\n", legendDesiredSize.mMaxElementWidth); #endif // figure out the legend's rectangle mLegendRect.width = legendDesiredSize.width + legendMargin.left + legendMargin.right; mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom; mLegendRect.x = borderPadding.left; mLegendRect.y = 0; nscoord oldSpace = mLegendSpace; mLegendSpace = 0; if (mLegendRect.height > border.top) { // center the border on the legend mLegendSpace = mLegendRect.height - border.top; } else { mLegendRect.y = (border.top - mLegendRect.height)/2; } // if the legend space changes then we need to reflow the // content area as well. if (mLegendSpace != oldSpace) { if (reflowContent == PR_FALSE || reason == eReflowReason_Dirty) { reflowContent = PR_TRUE; reason = eReflowReason_Resize; } } // if we are contrained then remove the legend from our available height. if (NS_INTRINSICSIZE != availSize.height) { if (availSize.height >= mLegendSpace) availSize.height -= mLegendSpace; } // don't get any smaller than the legend if (NS_INTRINSICSIZE != availSize.width) { if (availSize.width < mLegendRect.width) availSize.width = mLegendRect.width; } FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState, legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME); } } else { mLegendRect.Empty(); mLegendSpace = 0; } nsRect contentRect; // reflow the content frame only if needed if (mContentFrame) { if (reflowContent) { availSize.width = aReflowState.mComputedWidth; nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame, availSize, reason); nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags); // Reflow the frame ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState, borderPadding.left + kidReflowState.mComputedMargin.left, borderPadding.top + mLegendSpace + kidReflowState.mComputedMargin.top, 0, aStatus); // set the rect. make sure we add the margin back in. contentRect.SetRect(borderPadding.left,borderPadding.top + mLegendSpace,kidDesiredSize.width ,kidDesiredSize.height); if (aReflowState.mComputedHeight != NS_INTRINSICSIZE && borderPadding.top + mLegendSpace+kidDesiredSize.height > aReflowState.mComputedHeight) { kidDesiredSize.height = aReflowState.mComputedHeight-(borderPadding.top + mLegendSpace); } FinishReflowChild(mContentFrame, aPresContext, &kidReflowState, kidDesiredSize, contentRect.x, contentRect.y, 0); if (aDesiredSize.mComputeMEW) { aDesiredSize.mMaxElementWidth = kidDesiredSize.mMaxElementWidth; if (eStyleUnit_Coord == aReflowState.mStylePosition->mWidth.GetUnit() && NS_INTRINSICSIZE != aReflowState.mComputedWidth) aDesiredSize.mMaxElementWidth = aReflowState.mComputedWidth; if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit()) aDesiredSize.mMaxElementWidth = 0; aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right; } if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { aDesiredSize.mMaximumWidth = kidDesiredSize.mMaximumWidth + borderPadding.left + borderPadding.right; } NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); } else { // if we don't need to reflow just get the old size contentRect = mContentFrame->GetRect(); const nsStyleMargin* marginStyle = mContentFrame->GetStyleMargin(); nsMargin m(0,0,0,0); marginStyle->GetMargin(m); contentRect.Inflate(m); } } // use the computed width if the inner content does not fill it if (aReflowState.mComputedWidth != NS_INTRINSICSIZE && aReflowState.mComputedWidth > contentRect.width) { contentRect.width = aReflowState.mComputedWidth; } if (mLegendFrame) { // if the content rect is larger then the legend we can align the legend if (contentRect.width > mLegendRect.width) { PRInt32 align = ((nsLegendFrame*)mLegendFrame)->GetAlign(); switch(align) { case NS_STYLE_TEXT_ALIGN_RIGHT: mLegendRect.x = contentRect.width - mLegendRect.width + borderPadding.left; break; case NS_STYLE_TEXT_ALIGN_CENTER: float p2t; p2t = aPresContext->PixelsToTwips(); mLegendRect.x = NSIntPixelsToTwips((nscoord) NSToIntRound((float)(contentRect.width/2 - mLegendRect.width/2 + borderPadding.left) / p2t),p2t); break; } } else { //otherwise make place for the legend contentRect.width = mLegendRect.width; } // place the legend nsRect actualLegendRect(mLegendRect); actualLegendRect.Deflate(legendMargin); nsPoint curOrigin = mLegendFrame->GetPosition(); // only if the origin changed if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) { mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y)); nsContainerFrame::PositionFrameView(mLegendFrame); // We need to recursively process the legend frame's // children since we're moving the frame after Reflow. nsContainerFrame::PositionChildViews(mLegendFrame); } } // Return our size and our result if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) { aDesiredSize.height = mLegendSpace + borderPadding.top + contentRect.height + borderPadding.bottom; } else { nscoord min = borderPadding.top + borderPadding.bottom + mLegendRect.height; aDesiredSize.height = aReflowState.mComputedHeight + borderPadding.top + borderPadding.bottom; if (aDesiredSize.height < min) aDesiredSize.height = min; } aDesiredSize.width = contentRect.width + borderPadding.left + borderPadding.right; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; if (aDesiredSize.mComputeMEW) { // if the legend is wider use it if (aDesiredSize.mMaxElementWidth < mLegendRect.width + borderPadding.left + borderPadding.right) aDesiredSize.mMaxElementWidth = mLegendRect.width + borderPadding.left + borderPadding.right; } aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); // make the mMaximumWidth large enough if the legendframe determines the size if ((aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) && mLegendFrame) { aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, mLegendRect.width + borderPadding.left + borderPadding.right); } if (mLegendFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mLegendFrame); if (mContentFrame) ConsiderChildOverflow(aDesiredSize.mOverflowArea, mContentFrame); FinishAndStoreOverflow(&aDesiredSize); Invalidate(aDesiredSize.mOverflowArea); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY, nscoord aAppUnitsPerPixel) const { /* When scaling a rect, walk forward through the rect list up until the y value is greater * than the current rect's YMost() value. * * For each rect found, check if the rects have a touching edge (in unscaled coordinates), * and if one edge is entirely contained within the other. * * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no * gap exists. * * Since this could be potentially expensive - O(n^2), we only attempt this algorithm * for the first rect. */ // make a copy of this region so that we can mutate it in place nsRegion region = *this; int n; pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n); nsIntRegion intRegion; if (n) { nsRect first = BoxToRect(boxes[0]); mozilla::gfx::IntRect firstDeviceRect = first.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel); for (int i=1; i<n; i++) { nsRect rect = nsRect(boxes[i].x1, boxes[i].y1, boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1); mozilla::gfx::IntRect deviceRect = rect.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel); if (rect.y <= first.YMost()) { if (rect.XMost() == first.x && rect.YMost() <= first.YMost()) { // rect is touching on the left edge of the first rect and contained within // the length of its left edge deviceRect.SetRightEdge(firstDeviceRect.x); } else if (rect.x == first.XMost() && rect.YMost() <= first.YMost()) { // rect is touching on the right edge of the first rect and contained within // the length of its right edge deviceRect.SetLeftEdge(firstDeviceRect.XMost()); } else if (rect.y == first.YMost()) { // The bottom of the first rect is on the same line as the top of rect, but // they aren't necessarily contained. if (rect.x <= first.x && rect.XMost() >= first.XMost()) { // The top of rect contains the bottom of the first rect firstDeviceRect.SetBottomEdge(deviceRect.y); } else if (rect.x >= first.x && rect.XMost() <= first.XMost()) { // The bottom of the first contains the top of rect deviceRect.SetTopEdge(firstDeviceRect.YMost()); } } } boxes[i] = RectToBox(deviceRect); } boxes[0] = RectToBox(firstDeviceRect); pixman_region32_fini(&intRegion.mImpl.mImpl); // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n); } return intRegion; }
void nsGroupBoxFrame::PaintBorderBackground(nsIRenderingContext& aRenderingContext, nsPoint aPt, const nsRect& aDirtyRect) { PRIntn skipSides = 0; const nsStyleBorder* borderStyleData = GetStyleBorder(); const nsMargin& border = borderStyleData->GetActualBorder(); nscoord yoff = 0; nsPresContext* presContext = PresContext(); nsRect groupRect; nsIBox* groupBox = GetCaptionBox(presContext, groupRect); if (groupBox) { // if the border is smaller than the legend. Move the border down // to be centered on the legend. nsMargin groupMargin; groupBox->GetStyleMargin()->GetMargin(groupMargin); groupRect.Inflate(groupMargin); if (border.top < groupRect.height) yoff = (groupRect.height - border.top)/2 + groupRect.y; } nsRect rect(aPt.x, aPt.y + yoff, mRect.width, mRect.height - yoff); groupRect += aPt; nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, aDirtyRect, rect, 0); if (groupBox) { // we should probably use PaintBorderEdges to do this but for now just use clipping // to achieve the same effect. // draw left side nsRect clipRect(rect); clipRect.width = groupRect.x - rect.x; clipRect.height = border.top; aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, aDirtyRect, rect, *borderStyleData, mStyleContext, skipSides); aRenderingContext.PopState(); // draw right side clipRect = rect; clipRect.x = groupRect.XMost(); clipRect.width = rect.XMost() - groupRect.XMost(); clipRect.height = border.top; aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, aDirtyRect, rect, *borderStyleData, mStyleContext, skipSides); aRenderingContext.PopState(); // draw bottom clipRect = rect; clipRect.y += border.top; clipRect.height = mRect.height - (yoff + border.top); aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, aDirtyRect, rect, *borderStyleData, mStyleContext, skipSides); aRenderingContext.PopState(); } else { nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, aDirtyRect, nsRect(aPt, GetSize()), *borderStyleData, mStyleContext, skipSides); } }
NS_IMETHODIMP nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { nsresult rv = NS_OK; nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); nsReflowStatus childStatus; aDesiredSize.width = aDesiredSize.height = 0; aDesiredSize.ascent = 0; nsBoundingMetrics bmSqr, bmBase, bmIndex; nsRenderingContext& renderingContext = *aReflowState.rendContext; ////////////////// // Reflow Children int32_t count = 0; nsIFrame* baseFrame = nullptr; nsIFrame* indexFrame = nullptr; nsHTMLReflowMetrics baseSize; nsHTMLReflowMetrics indexSize; nsIFrame* childFrame = mFrames.FirstChild(); 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, 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(mFrames.FirstChild(), childFrame); return rv; } if (0 == count) { // base baseFrame = childFrame; baseSize = childDesiredSize; bmBase = childDesiredSize.mBoundingMetrics; } else if (1 == count) { // index indexFrame = childFrame; indexSize = childDesiredSize; bmIndex = childDesiredSize.mBoundingMetrics; } count++; childFrame = childFrame->GetNextSibling(); } if (2 != count) { // report an error, encourage people to get their markups in order rv = ReflowError(renderingContext, aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); // Call DidReflow() for the child frames we successfully did reflow. DidReflowChildren(mFrames.FirstChild(), childFrame); return rv; } //////////// // Prepare the radical symbol and the overline bar nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); renderingContext.SetFont(fm); // For radical glyphs from TeX fonts and some of the radical glyphs from // Mathematica fonts, the thickness of the overline can be obtained from the // ascent of the glyph. Most fonts however have radical glyphs above the // baseline so no assumption can be made about the meaning of the ascent. nscoord ruleThickness, leading, em; GetRuleThickness(renderingContext, fm, ruleThickness); PRUnichar one = '1'; nsBoundingMetrics bmOne = renderingContext.GetBoundingMetrics(&one, 1); // 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)) phi = fm->XHeight(); 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; // make sure that the rule appears on on screen nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(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 // Stretch the radical symbol to the appropriate height if it is not big enough. nsBoundingMetrics contSize = bmBase; contSize.descent = bmBase.ascent + bmBase.descent + psi; contSize.ascent = ruleThickness; // height(radical) should be >= height(base) + psi + ruleThickness nsBoundingMetrics radicalSize; mSqrChar.Stretch(aPresContext, renderingContext, NS_STRETCH_DIRECTION_VERTICAL, contSize, radicalSize, NS_STRETCH_LARGER, NS_MATHML_IS_RTL(mPresentationData.flags)); // radicalSize have changed at this point, and should match with // the bounding metrics of the char mSqrChar.GetBoundingMetrics(bmSqr); // Update the desired size for the container (like msqrt, index is not yet included) // the baseline will be that of the base. mBoundingMetrics.ascent = bmBase.ascent + psi + ruleThickness; mBoundingMetrics.descent = NS_MAX(bmBase.descent, (bmSqr.ascent + bmSqr.descent - mBoundingMetrics.ascent)); mBoundingMetrics.width = bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = bmSqr.leftBearing; mBoundingMetrics.rightBearing = bmSqr.width + NS_MAX(bmBase.width, bmBase.rightBearing); // take also care of the rule aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.height = aDesiredSize.ascent + NS_MAX(baseSize.height - baseSize.ascent, mBoundingMetrics.descent + ruleThickness); aDesiredSize.width = mBoundingMetrics.width; ///////////// // Re-adjust the desired size to include the index. // the index is raised by some fraction of the height // of the radical, see \mroot macro in App. B, TexBook nscoord raiseIndexDelta = NSToCoordRound(0.6f * (bmSqr.ascent + bmSqr.descent)); nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical - (bmSqr.ascent + bmSqr.descent) // to bottom of radical + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index nscoord indexClearance = 0; if (mBoundingMetrics.ascent < indexRaisedAscent) { indexClearance = indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index mBoundingMetrics.ascent = indexRaisedAscent; nscoord descent = aDesiredSize.height - aDesiredSize.ascent; aDesiredSize.ascent = mBoundingMetrics.ascent + leading; aDesiredSize.height = aDesiredSize.ascent + descent; } nscoord dxIndex, dxSqr; GetRadicalXOffsets(bmIndex.width, bmSqr.width, fm, &dxIndex, &dxSqr); mBoundingMetrics.width = dxSqr + bmSqr.width + bmBase.width; mBoundingMetrics.leftBearing = NS_MIN(dxIndex + bmIndex.leftBearing, dxSqr + bmSqr.leftBearing); mBoundingMetrics.rightBearing = dxSqr + bmSqr.width + NS_MAX(bmBase.width, bmBase.rightBearing); aDesiredSize.width = mBoundingMetrics.width; aDesiredSize.mBoundingMetrics = mBoundingMetrics; GatherAndStoreOverflow(&aDesiredSize); // place the index nscoord dx = dxIndex; nscoord dy = aDesiredSize.ascent - (indexRaisedAscent + indexSize.ascent - bmIndex.ascent); FinishReflowChild(indexFrame, aPresContext, nullptr, indexSize, MirrorIfRTL(aDesiredSize.width, indexSize.width, dx), dy, 0); // place the radical symbol and the radical bar dx = dxSqr; dy = indexClearance + leading; // leave a leading at the top mSqrChar.SetRect(nsRect(MirrorIfRTL(aDesiredSize.width, bmSqr.width, dx), dy, bmSqr.width, bmSqr.ascent + bmSqr.descent)); dx += bmSqr.width; mBarRect.SetRect(MirrorIfRTL(aDesiredSize.width, bmBase.width, dx), dy, bmBase.width, ruleThickness); // place the base dy = aDesiredSize.ascent - baseSize.ascent; FinishReflowChild(baseFrame, aPresContext, nullptr, baseSize, MirrorIfRTL(aDesiredSize.width, baseSize.width, dx), dy, 0); mReference.x = 0; mReference.y = aDesiredSize.ascent; aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; }
NS_IMETHODIMP nsVideoFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsVideoFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsVideoFrame::Reflow: availSize=%d,%d", aReflowState.availableWidth, aReflowState.availableHeight)); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); aStatus = NS_FRAME_COMPLETE; aMetrics.width = aReflowState.ComputedWidth(); aMetrics.height = aReflowState.ComputedHeight(); // stash this away so we can compute our inner area later mBorderPadding = aReflowState.mComputedBorderPadding; aMetrics.width += mBorderPadding.left + mBorderPadding.right; aMetrics.height += mBorderPadding.top + mBorderPadding.bottom; // Reflow the child frames. We may have up to two, an image frame // which is the poster, and a box frame, which is the video controls. for (nsIFrame *child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { if (child->GetType() == nsGkAtoms::imageFrame) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child); nsHTMLReflowMetrics kidDesiredSize; nsSize availableSize = nsSize(aReflowState.availableWidth, aReflowState.availableHeight); nsHTMLReflowState kidReflowState(aPresContext, aReflowState, imageFrame, availableSize, aMetrics.width, aMetrics.height); if (ShouldDisplayPoster()) { kidReflowState.SetComputedWidth(aReflowState.ComputedWidth()); kidReflowState.SetComputedHeight(aReflowState.ComputedHeight()); } else { kidReflowState.SetComputedWidth(0); kidReflowState.SetComputedHeight(0); } ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState, mBorderPadding.left, mBorderPadding.top, 0, aStatus); FinishReflowChild(imageFrame, aPresContext, &kidReflowState, kidDesiredSize, mBorderPadding.left, mBorderPadding.top, 0); } else if (child->GetType() == nsGkAtoms::boxFrame) { // Reflow the video controls frame. nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext); nsBoxFrame::LayoutChildAt(boxState, child, nsRect(mBorderPadding.left, mBorderPadding.top, aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); } } aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height); FinishAndStoreOverflow(&aMetrics); if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { Invalidate(nsRect(0, 0, mRect.width, mRect.height)); } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsVideoFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height)); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); 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(aDesiredSize.GetWritingMode()); 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); char16_t 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 (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK) 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_UPDIAGONALARROW) || 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 = std::max(bmOne.ascent, bmBase.ascent); bmBase.descent = std::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; /////////////// // updiagonal arrow notation. We need enough space at the top right corner to // draw the arrow head. if (IsToDraw(NOTATION_UPDIAGONALARROW)) { // This is an estimate, see nsDisplayNotation::Paint for the exact head size nscoord arrowHeadSize = kArrowHeadSize * mRuleThickness; // We want that the arrow shaft strikes the menclose content and that the // arrow head does not overlap with that content. Hence we add some space // on the right. We don't add space on the top but only ensure that the // ascent is large enough. dx_right = std::max(dx_right, arrowHeadSize); mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, arrowHeadSize); } /////////////// // 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 = std::max(dx_left, padding2); dx_right = std::max(dx_right, padding2); // Update vertical parameters padding2 = ratio * (bmBase.ascent + bmBase.descent); mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, bmBase.ascent + padding2); mBoundingMetrics.descent = std::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 = std::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 = std::max(dx_left, bmLongdivChar.width); // Update vertical parameters longdivAscent = bmBase.ascent + psi + mRuleThickness; longdivDescent = std::max(bmBase.descent, (bmLongdivChar.ascent + bmLongdivChar.descent - longdivAscent)); mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, longdivAscent); mBoundingMetrics.descent = std::max(mBoundingMetrics.descent, longdivDescent); } } /////////////// // radical notation: if (IsToDraw(NOTATION_RADICAL)) { nscoord *dx_leading = StyleVisibility()->mDirection ? &dx_right : &dx_left; if (aWidthOnly) { nscoord radical_width = mMathMLChar[mRadicalCharIndex]. GetMaxWidth(PresContext(), aRenderingContext); // Update horizontal parameters *dx_leading = std::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, StyleVisibility()->mDirection); mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar); // Update horizontal parameters *dx_leading = std::max(*dx_leading, bmRadicalChar.width); // Update vertical parameters radicalAscent = bmBase.ascent + psi + mRuleThickness; radicalDescent = std::max(bmBase.descent, (bmRadicalChar.ascent + bmRadicalChar.descent - radicalAscent)); mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, radicalAscent); mBoundingMetrics.descent = std::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 = std::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 = std::min(0, dx_left + bmBase.leftBearing); mBoundingMetrics.rightBearing = std::max(mBoundingMetrics.width, dx_left + bmBase.rightBearing); aDesiredSize.Width() = mBoundingMetrics.width; aDesiredSize.SetTopAscent(std::max(mBoundingMetrics.ascent, baseSize.TopAscent())); aDesiredSize.Height() = aDesiredSize.TopAscent() + std::max(mBoundingMetrics.descent, baseSize.Height() - baseSize.TopAscent()); 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.TopAscent(); nscoord desiredSizeDescent = aDesiredSize.Height() - aDesiredSize.TopAscent(); if (IsToDraw(NOTATION_LONGDIV)) { desiredSizeAscent = std::max(desiredSizeAscent, longdivAscent + leading); desiredSizeDescent = std::max(desiredSizeDescent, longdivDescent + mRuleThickness); } if (IsToDraw(NOTATION_RADICAL)) { desiredSizeAscent = std::max(desiredSizeAscent, radicalAscent + leading); desiredSizeDescent = std::max(desiredSizeDescent, radicalDescent + mRuleThickness); } aDesiredSize.SetTopAscent(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 = std::max(aDesiredSize.TopAscent() - bmBase.ascent, aDesiredSize.Height() - aDesiredSize.TopAscent() - bmBase.descent); aDesiredSize.SetTopAscent(bmBase.ascent + dy); aDesiredSize.Height() = aDesiredSize.TopAscent() + bmBase.descent + dy; } // Update mBoundingMetrics ascent/descent if (IsToDraw(NOTATION_TOP) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_UPDIAGONALARROW) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.ascent = aDesiredSize.TopAscent(); if (IsToDraw(NOTATION_BOTTOM) || IsToDraw(NOTATION_RIGHT) || IsToDraw(NOTATION_LEFT) || IsToDraw(NOTATION_UPDIAGONALSTRIKE) || IsToDraw(NOTATION_UPDIAGONALARROW) || IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) || IsToDraw(NOTATION_VERTICALSTRIKE) || IsToDraw(NOTATION_CIRCLE) || IsToDraw(NOTATION_ROUNDEDBOX)) mBoundingMetrics.descent = aDesiredSize.Height() - aDesiredSize.TopAscent(); aDesiredSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredSize.TopAscent(); if (aPlaceOrigin) { ////////////////// // Set position and size of MathMLChars if (IsToDraw(NOTATION_LONGDIV)) mMathMLChar[mLongDivCharIndex].SetRect(nsRect(dx_left - bmLongdivChar.width, aDesiredSize.TopAscent() - longdivAscent, bmLongdivChar.width, bmLongdivChar.ascent + bmLongdivChar.descent)); if (IsToDraw(NOTATION_RADICAL)) { nscoord dx = (StyleVisibility()->mDirection ? dx_left + bmBase.width : dx_left - bmRadicalChar.width); mMathMLChar[mRadicalCharIndex].SetRect(nsRect(dx, aDesiredSize.TopAscent() - radicalAscent, bmRadicalChar.width, bmRadicalChar.ascent + bmRadicalChar.descent)); } mContentWidth = bmBase.width; ////////////////// // Finish reflowing child frames PositionRowChildFrames(dx_left, aDesiredSize.TopAscent()); } 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 false // aSkipPopupChecks ); 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; }
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)) { 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; }
void TransformReferenceBox::EnsureDimensionsAreCached() { if (mIsCached) { return; } MOZ_ASSERT(mFrame); mIsCached = true; if (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { if (!nsLayoutUtils::SVGTransformOriginEnabled()) { mX = -mFrame->GetPosition().x; mY = -mFrame->GetPosition().y; mWidth = 0; mHeight = 0; } else if (mFrame->StyleDisplay()->mTransformBox == NS_STYLE_TRANSFORM_BOX_FILL_BOX) { // Percentages in transforms resolve against the SVG bbox, and the // transform is relative to the top-left of the SVG bbox. gfxRect bbox = nsSVGUtils::GetBBox(const_cast<nsIFrame*>(mFrame)); nsRect bboxInAppUnits = nsLayoutUtils::RoundGfxRectToAppRect(bbox, mFrame->PresContext()->AppUnitsPerCSSPixel()); // The mRect of an SVG nsIFrame is its user space bounds *including* // stroke and markers, whereas bboxInAppUnits is its user space bounds // including fill only. We need to note the offset of the reference box // from the frame's mRect in mX/mY. mX = bboxInAppUnits.x - mFrame->GetPosition().x; mY = bboxInAppUnits.y - mFrame->GetPosition().y; mWidth = bboxInAppUnits.width; mHeight = bboxInAppUnits.height; } else { // The value 'border-box' is treated as 'view-box' for SVG content. MOZ_ASSERT(mFrame->StyleDisplay()->mTransformBox == NS_STYLE_TRANSFORM_BOX_VIEW_BOX || mFrame->StyleDisplay()->mTransformBox == NS_STYLE_TRANSFORM_BOX_BORDER_BOX, "Unexpected value for 'transform-box'"); // Percentages in transforms resolve against the width/height of the // nearest viewport (or it's viewBox if one is applied), and the // transform is relative to {0,0} in current user space. mX = -mFrame->GetPosition().x; mY = -mFrame->GetPosition().y; Size contextSize = nsSVGUtils::GetContextSize(mFrame); mWidth = nsPresContext::CSSPixelsToAppUnits(contextSize.width); mHeight = nsPresContext::CSSPixelsToAppUnits(contextSize.height); } return; } // If UNIFIED_CONTINUATIONS is not defined, this is simply the frame's // bounding rectangle, translated to the origin. Otherwise, it is the // smallest rectangle containing a frame and all of its continuations. For // example, if there is a <span> element with several continuations split // over several lines, this function will return the rectangle containing all // of those continuations. nsRect rect; #ifndef UNIFIED_CONTINUATIONS rect = mFrame->GetRect(); #else // Iterate the continuation list, unioning together the bounding rects: for (const nsIFrame *currFrame = mFrame->FirstContinuation(); currFrame != nullptr; currFrame = currFrame->GetNextContinuation()) { // Get the frame rect in local coordinates, then translate back to the // original coordinates: rect.UnionRect(result, nsRect(currFrame->GetOffsetTo(mFrame), currFrame->GetSize())); } #endif mX = 0; mY = 0; mWidth = rect.Width(); mHeight = rect.Height(); }
void nsRenderingContext::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { FillRect(nsRect(aX, aY, aWidth, aHeight)); }
// 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, StyleFont()); 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; } } // 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.TopAscent() - (mBoundingMetrics.ascent + leading); aDesiredStretchSize.SetTopAscent(mBoundingMetrics.ascent + leading); aDesiredStretchSize.Height() = aDesiredStretchSize.TopAscent() + mBoundingMetrics.descent; firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy)); } else if (useMathMLChar) { nscoord ascent = fm->MaxAscent(); nscoord descent = fm->MaxDescent(); aDesiredStretchSize.SetTopAscent(std::max(mBoundingMetrics.ascent + leading, ascent)); aDesiredStretchSize.Height() = aDesiredStretchSize.TopAscent() + std::max(mBoundingMetrics.descent + leading, descent); } aDesiredStretchSize.Width() = mBoundingMetrics.width; aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; mReference.x = 0; mReference.y = aDesiredStretchSize.TopAscent(); // Place our mMathMLChar, its origin is in our coordinate system if (useMathMLChar) { nscoord dy = aDesiredStretchSize.TopAscent() - 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; }
void nsRenderingContext::InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { InvertRect(nsRect(aX, aY, aWidth, aHeight)); }
// this is identical to nsHTMLContainerFrame::Paint except for the background and border. NS_IMETHODIMP nsFieldSetFrame::Paint(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, PRUint32 aFlags) { if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { // Paint our background and border PRBool isVisible; if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && isVisible && mRect.width && mRect.height) { PRIntn skipSides = GetSkipSides(); const nsStyleBorder* borderStyle = GetStyleBorder(); const nsStylePadding* paddingStyle = GetStylePadding(); nscoord topBorder = borderStyle->GetBorderWidth(NS_SIDE_TOP); nscoord yoff = 0; // if the border is smaller than the legend. Move the border down // to be centered on the legend. if (topBorder < mLegendRect.height) yoff = (mLegendRect.height - topBorder)/2; nsRect rect(0, yoff, mRect.width, mRect.height - yoff); nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *borderStyle, *paddingStyle, PR_TRUE); if (mLegendFrame) { // Use the rect of the legend frame, not mLegendRect, so we draw our // border under the legend's left and right margins. const nsRect & legendRect = mLegendFrame->GetRect(); // we should probably use PaintBorderEdges to do this but for now just use clipping // to achieve the same effect. // draw left side nsRect clipRect(rect); clipRect.width = legendRect.x - rect.x; clipRect.height = topBorder; aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *borderStyle, mStyleContext, skipSides); aRenderingContext.PopState(); // draw right side clipRect = rect; clipRect.x = legendRect.x + legendRect.width; clipRect.width -= (legendRect.x + legendRect.width); clipRect.height = topBorder; aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *borderStyle, mStyleContext, skipSides); aRenderingContext.PopState(); // draw bottom clipRect = rect; clipRect.y += topBorder; clipRect.height = mRect.height - (yoff + topBorder); aRenderingContext.PushState(); aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *borderStyle, mStyleContext, skipSides); aRenderingContext.PopState(); } else { nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, nsRect(0,0,mRect.width, mRect.height), *borderStyle, mStyleContext, skipSides); } } } PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); #ifdef DEBUG if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) { if (HasView()) { aRenderingContext.SetColor(NS_RGB(0,0,255)); } else { aRenderingContext.SetColor(NS_RGB(255,0,0)); } aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } #endif DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame", &aRenderingContext); return NS_OK; }