nscoord nsFloatManager::FloatInfo::LineRight(WritingMode aWM, ShapeType aShapeType, const nscoord aBStart, const nscoord aBEnd) const { if (aShapeType == ShapeType::Margin) { return LineRight(); } MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside); const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside; if (shapeOutside.GetType() == StyleShapeSourceType::None) { return LineRight(); } if (shapeOutside.GetType() == StyleShapeSourceType::Box) { nscoord radii[8]; bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii); if (!hasRadii) { return ShapeBoxRect().XMost(); } // Get the physical side for line-right since border-radii are in // the physical axis. mozilla::Side lineRightSide = aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight)); nscoord blockStartCornerRadiusL = radii[SideToHalfCorner(lineRightSide, false, false)]; nscoord blockStartCornerRadiusB = radii[SideToHalfCorner(lineRightSide, false, true)]; nscoord blockEndCornerRadiusL = radii[SideToHalfCorner(lineRightSide, true, false)]; nscoord blockEndCornerRadiusB = radii[SideToHalfCorner(lineRightSide, true, true)]; if (aWM.IsLineInverted()) { // This happens only when aWM is vertical-lr. Need to swap blockStart // and blockEnd corners. std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL); std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB); } nscoord lineRightDiff = ComputeEllipseLineInterceptDiff( ShapeBoxRect().y, ShapeBoxRect().YMost(), blockStartCornerRadiusL, blockStartCornerRadiusB, blockEndCornerRadiusL, blockEndCornerRadiusB, aBStart, aBEnd); return ShapeBoxRect().XMost() - lineRightDiff; } // XXX: Other shape source types are not implemented yet. return LineRight(); }
void nsTextControlFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // make sure that the form registers itself on the initial/first reflow if (mState & NS_FRAME_FIRST_REFLOW) { nsFormControlFrame::RegUnRegAccessKey(this, true); } // set values of reflow's out parameters WritingMode wm = aReflowState.GetWritingMode(); LogicalSize finalSize(wm, aReflowState.ComputedISize() + aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm), aReflowState.ComputedBSize() + aReflowState.ComputedLogicalBorderPadding().BStartEnd(wm)); aDesiredSize.SetSize(wm, finalSize); // computation of the ascent wrt the input height nscoord lineHeight = aReflowState.ComputedBSize(); float inflation = nsLayoutUtils::FontSizeInflationFor(this); if (!IsSingleLineTextControl()) { lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(), NS_AUTOHEIGHT, inflation); } RefPtr<nsFontMetrics> fontMet; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet), inflation); // now adjust for our borders and padding aDesiredSize.SetBlockStartAscent( nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight, wm.IsLineInverted()) + aReflowState.ComputedLogicalBorderPadding().BStart(wm)); // overflow handling aDesiredSize.SetOverflowAreasToDesiredBounds(); // perform reflow on all kids nsIFrame* kid = mFrames.FirstChild(); while (kid) { ReflowTextControlChild(kid, aPresContext, aReflowState, aStatus, aDesiredSize); kid = kid->GetNextSibling(); } // take into account css properties that affect overflow handling FinishAndStoreOverflow(&aDesiredSize); aStatus = NS_FRAME_COMPLETE; NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); }
nscoord nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const { NS_ASSERTION(!NS_SUBTREE_DIRTY(this), "frame must not be dirty"); // Treat radio buttons and checkboxes as having an intrinsic baseline // at the block-end of the control (use the block-end content edge rather // than the margin edge). // For "inverted" lines (typically in writing-mode:vertical-lr), use the // block-start end instead. return aWritingMode.IsLineInverted() ? GetLogicalUsedBorderAndPadding(aWritingMode).BStart(aWritingMode) : BSize(aWritingMode) - GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode); }
void nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset, nsRect* aCaretRect, nsRect* aHookRect) { NS_ASSERTION(aFrame, "Should have a frame here"); WritingMode wm = aFrame->GetWritingMode(); bool isVertical = wm.IsVertical(); nscoord bidiIndicatorSize; *aCaretRect = GetGeometryForFrame(aFrame, aFrameOffset, &bidiIndicatorSize); // on RTL frames the right edge of mCaretRect must be equal to framePos const nsStyleVisibility* vis = aFrame->StyleVisibility(); if (NS_STYLE_DIRECTION_RTL == vis->mDirection) { if (isVertical) { aCaretRect->y -= aCaretRect->height; } else { aCaretRect->x -= aCaretRect->width; } } // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction aHookRect->SetEmpty(); if (!IsBidiUI()) { return; } bool isCaretRTL; nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard(); // if bidiKeyboard->IsLangRTL() fails, there is no way to tell the // keyboard direction, or the user has no right-to-left keyboard // installed, so we never draw the hook. if (bidiKeyboard && NS_SUCCEEDED(bidiKeyboard->IsLangRTL(&isCaretRTL))) { // If keyboard language is RTL, draw the hook on the left; if LTR, to the right // The height of the hook rectangle is the same as the width of the caret // rectangle. if (isVertical) { bool isSidewaysLR = wm.IsVerticalLR() && !wm.IsLineInverted(); if (isSidewaysLR) { aHookRect->SetRect(aCaretRect->x + bidiIndicatorSize, aCaretRect->y + (!isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->height), aCaretRect->height, bidiIndicatorSize); } else { aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize, aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->height), aCaretRect->height, bidiIndicatorSize); } } else { aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->width), aCaretRect->y + bidiIndicatorSize, bidiIndicatorSize, aCaretRect->width); } } }
/* static */ nsRect nsCaret::GetGeometryForFrame(nsIFrame* aFrame, int32_t aFrameOffset, nscoord* aBidiIndicatorSize) { nsPoint framePos(0, 0); nsRect rect; nsresult rv = aFrame->GetPointFromOffset(aFrameOffset, &framePos); if (NS_FAILED(rv)) { if (aBidiIndicatorSize) { *aBidiIndicatorSize = 0; } return rect; } nsIFrame* frame = aFrame->GetContentInsertionFrame(); if (!frame) { frame = aFrame; } NS_ASSERTION(!(frame->GetStateBits() & NS_FRAME_IN_REFLOW), "We should not be in the middle of reflow"); nscoord baseline = frame->GetCaretBaseline(); nscoord ascent = 0, descent = 0; RefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm), nsLayoutUtils::FontSizeInflationFor(aFrame)); NS_ASSERTION(fm, "We should be able to get the font metrics"); if (fm) { ascent = fm->MaxAscent(); descent = fm->MaxDescent(); } nscoord height = ascent + descent; WritingMode wm = aFrame->GetWritingMode(); bool vertical = wm.IsVertical(); if (vertical) { if (wm.IsLineInverted()) { framePos.x = baseline - descent; } else { framePos.x = baseline - ascent; } } else { framePos.y = baseline - ascent; } Metrics caretMetrics = ComputeMetrics(aFrame, aFrameOffset, height); rect = nsRect(framePos, vertical ? nsSize(height, caretMetrics.mCaretWidth) : nsSize(caretMetrics.mCaretWidth, height)); // Clamp the inline-position to be within our scroll frame. If we don't, then // it clips us, and we don't appear at all. See bug 335560. nsIFrame *scrollFrame = nsLayoutUtils::GetClosestFrameOfType(aFrame, nsGkAtoms::scrollFrame); if (scrollFrame) { // First, use the scrollFrame to get at the scrollable view that we're in. nsIScrollableFrame *sf = do_QueryFrame(scrollFrame); nsIFrame *scrolled = sf->GetScrolledFrame(); nsRect caretInScroll = rect + aFrame->GetOffsetTo(scrolled); // Now see if the caret extends beyond the view's bounds. If it does, // then snap it back, put it as close to the edge as it can. if (vertical) { nscoord overflow = caretInScroll.YMost() - scrolled->GetVisualOverflowRectRelativeToSelf().height; if (overflow > 0) { rect.y -= overflow; } } else { nscoord overflow = caretInScroll.XMost() - scrolled->GetVisualOverflowRectRelativeToSelf().width; if (overflow > 0) { rect.x -= overflow; } } } if (aBidiIndicatorSize) { *aBidiIndicatorSize = caretMetrics.mBidiIndicatorSize; } return rect; }
void BRFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const ReflowInput& aReflowInput, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("BRFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus); WritingMode wm = aReflowInput.GetWritingMode(); LogicalSize finalSize(wm); finalSize.BSize(wm) = 0; // BR frames with block size 0 are ignored in quirks // mode by nsLineLayout::VerticalAlignFrames . // However, it's not always 0. See below. finalSize.ISize(wm) = 0; aMetrics.SetBlockStartAscent(0); // Only when the BR is operating in a line-layout situation will it // behave like a BR. Additionally, we suppress breaks from BR inside // of ruby frames. To determine if we're inside ruby, we have to rely // on the *parent's* ShouldSuppressLineBreak() method, instead of our // own, because we may have custom "display" value that makes our // ShouldSuppressLineBreak() return false. nsLineLayout* ll = aReflowInput.mLineLayout; if (ll && !GetParent()->StyleContext()->ShouldSuppressLineBreak()) { // Note that the compatibility mode check excludes AlmostStandards // mode, since this is the inline box model. See bug 161691. if ( ll->LineIsEmpty() || aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) { // The line is logically empty; any whitespace is trimmed away. // // If this frame is going to terminate the line we know // that nothing else will go on the line. Therefore, in this // case, we provide some height for the BR frame so that it // creates some vertical whitespace. It's necessary to use the // line-height rather than the font size because the // quirks-mode fix that doesn't apply the block's min // line-height makes this necessary to make BR cause a line // of the full line-height // We also do this in strict mode because BR should act like a // normal inline frame. That line-height is used is important // here for cases where the line-height is less than 1. RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetInflatedFontMetricsForFrame(this); if (fm) { nscoord logicalHeight = aReflowInput.CalcLineHeight(); finalSize.BSize(wm) = logicalHeight; aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline( fm, logicalHeight, wm.IsLineInverted())); } else { aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0); } // XXX temporary until I figure out a better solution; see the // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY // if the width is zero. // XXX This also fixes bug 10036! // Warning: nsTextControlFrame::CalculateSizeStandard depends on // the following line, see bug 228752. // The code below in AddInlinePrefISize also adds 1 appunit to width finalSize.ISize(wm) = 1; } // Return our reflow status uint32_t breakType = aReflowInput.mStyleDisplay->PhysicalBreakType(wm); if (NS_STYLE_CLEAR_NONE == breakType) { breakType = NS_STYLE_CLEAR_LINE; } aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | NS_INLINE_MAKE_BREAK_TYPE(breakType); ll->SetLineEndsInBR(true); } else { aStatus = NS_FRAME_COMPLETE; } aMetrics.SetSize(wm, finalSize); aMetrics.SetOverflowAreasToDesiredBounds(); mAscent = aMetrics.BlockStartAscent(); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics); }