author | Jonathan Kew <jkew@mozilla.com> |
Thu, 13 Nov 2014 08:58:06 +0000 | |
changeset 215450 | 9e5ac3d61831ac98565256fadbb254f03269b3a5 |
parent 215449 | 72894fb00f2544fdc68948a3d58eb8dc4b7d39b0 |
child 215451 | acb19a80d5f7a2588d195041abe4e25bd9520aed |
push id | 51760 |
push user | jkew@mozilla.com |
push date | Thu, 13 Nov 2014 09:13:45 +0000 |
treeherder | mozilla-inbound@13167bb74be0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smontagu |
bugs | 1093553 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1897,32 +1897,38 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint bool sideways = false; gfxPoint origPt = *aPt; if (aRunParams.isVerticalRun && !fontParams.isVerticalFont) { sideways = true; aRunParams.context->Save(); gfxPoint p(aPt->x * aRunParams.devPerApp, aPt->y * aRunParams.devPerApp); const Metrics& metrics = GetMetrics(eHorizontal); - // Adjust the matrix to draw the (horizontally-shaped) textrun with - // 90-degree CW rotation, and adjust position so that the rotated - // horizontal text (which uses a standard alphabetic baseline) will + // Get a matrix we can use to draw the (horizontally-shaped) textrun + // with 90-degree CW rotation. + gfxMatrix mat = aRunParams.context->CurrentMatrix(). + Translate(p). // translate origin for rotation + Rotate(M_PI / 2.0). // turn 90deg clockwise + Translate(-p); // undo the translation + + // If we're drawing rotated horizontal text for an element styled + // text-orientation:mixed, the dominant baseline will be vertical- + // centered. So in this case, we need to adjust the position so that + // the rotated horizontal text (which uses an alphabetic baseline) will // look OK when juxtaposed with upright glyphs (rendered on a centered // vertical baseline). The adjustment here is somewhat ad hoc; we // should eventually look for baseline tables[1] in the fonts and use // those if available. - // [1] http://www.microsoft.com/typography/otspec/base.htm - aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix(). - Translate(p). // translate origin for rotation - Rotate(M_PI / 2.0). // turn 90deg clockwise - Translate(-p). // undo the translation - Translate(gfxPoint(0, (metrics.emAscent - metrics.emDescent) / 2))); - // and offset the (alphabetic) baseline of the - // horizontally-shaped text from the (centered) - // default baseline used for vertical + // [1] See http://www.microsoft.com/typography/otspec/base.htm + if (aTextRun->UseCenterBaseline()) { + gfxPoint baseAdj(0, (metrics.emAscent - metrics.emDescent) / 2); + mat.Translate(baseAdj); + } + + aRunParams.context->SetMatrix(mat); } nsAutoPtr<gfxTextContextPaint> contextPaint; if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) { // If no pattern is specified for fill, use the current pattern NS_ASSERTION((int(aRunParams.drawMode) & int(DrawMode::GLYPH_STROKE)) == 0, "no pattern supplied for stroking text"); nsRefPtr<gfxPattern> fillPattern = aRunParams.context->GetPattern(); @@ -2133,25 +2139,43 @@ gfxFont::Measure(gfxTextRun *aTextRun, aRefContext, aSpacing, aOrientation); } } const int32_t appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit(); // Current position in appunits gfxFont::Orientation orientation = aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT - ? gfxFont::eVertical : gfxFont::eHorizontal; + ? eVertical : eHorizontal; const gfxFont::Metrics& fontMetrics = GetMetrics(orientation); + gfxFloat baselineOffset = 0; + if (aTextRun->UseCenterBaseline() && orientation == eHorizontal) { + // For a horizontal font being used in vertical writing mode with + // text-orientation:mixed, the overall metrics we're accumulating + // will be aimed at a center baseline. But this font's metrics were + // based on the alphabetic baseline. So we compute a baseline offset + // that will be applied to ascent/descent values and glyph rects + // to effectively shift them relative to the baseline. + // XXX Eventually we should probably use the BASE table, if present. + // But it usually isn't, so we need an ad hoc adjustment for now. + baselineOffset = appUnitsPerDevUnit * + (fontMetrics.emAscent - fontMetrics.emDescent) / 2; + } + RunMetrics metrics; - metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit; - metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit; + metrics.mAscent = fontMetrics.maxAscent * appUnitsPerDevUnit; + metrics.mDescent = fontMetrics.maxDescent * appUnitsPerDevUnit; + if (aStart == aEnd) { // exit now before we look at aSpacing[0], which is undefined - metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent); + metrics.mAscent -= baselineOffset; + metrics.mDescent += baselineOffset; + metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, + 0, metrics.mAscent + metrics.mDescent); return metrics; } gfxFloat advanceMin = 0, advanceMax = 0; const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs(); bool isRTL = aTextRun->IsRightToLeft(); double direction = aTextRun->GetDirection(); bool needsGlyphExtents = NeedsGlyphExtents(this, aTextRun); @@ -2242,16 +2266,22 @@ gfxFont::Measure(gfxTextRun *aTextRun, gfxRect fontBox(advanceMin, -metrics.mAscent, advanceMax - advanceMin, metrics.mAscent + metrics.mDescent); metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox); } if (isRTL) { metrics.mBoundingBox -= gfxPoint(x, 0); } + if (baselineOffset != 0) { + metrics.mAscent -= baselineOffset; + metrics.mDescent += baselineOffset; + metrics.mBoundingBox.y += baselineOffset; + } + metrics.mAdvanceWidth = x*direction; return metrics; } static PLDHashOperator NotifyGlyphChangeObservers(nsPtrHashKey<gfxFont::GlyphChangeObserver>* aKey, void* aClosure) {
--- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -4157,18 +4157,22 @@ nsCSSRendering::PaintDecorationLine(nsIF drawOptions.mAntialiasMode = AntialiasMode::NONE; } break; default: NS_ERROR("Invalid style value!"); return; } - // The y position should be set to the middle of the line. - rect.y += lineThickness / 2; + // The block-direction position should be set to the middle of the line. + if (aVertical) { + rect.x -= lineThickness / 2; + } else { + rect.y += lineThickness / 2; + } switch (aStyle) { case NS_STYLE_TEXT_DECORATION_STYLE_SOLID: case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED: case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: { Point p1 = rect.TopLeft(); Point p2 = aVertical ? rect.BottomLeft() : rect.TopRight(); aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions); @@ -4355,22 +4359,28 @@ nsCSSRendering::DecorationLineToPath(nsI if (aStyle != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) { // For the moment, we support only solid text decorations. return; } gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0); - // The y position should be set to the middle of the line. - rect.y += lineThickness / 2; - - aGfxContext->Rectangle - (gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)), - gfxSize(rect.Width(), lineThickness))); + // The block-direction position should be set to the middle of the line. + if (aVertical) { + rect.x -= lineThickness / 2; + aGfxContext->Rectangle + (gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(lineThickness / 2, 0.0)), + gfxSize(lineThickness, rect.Height()))); + } else { + rect.y += lineThickness / 2; + aGfxContext->Rectangle + (gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)), + gfxSize(rect.Width(), lineThickness))); + } } nsRect nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext, const gfxSize& aLineSize, const gfxFloat aAscent, const gfxFloat aOffset, const uint8_t aDecoration,
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3491,17 +3491,18 @@ nsLayoutUtils::GetFontMetricsForStyleCon // doing so would be lossy. Fortunately, in such cases, aInflation is // guaranteed to be 1.0f. if (aInflation != 1.0f) { font.size = NSToCoordRound(font.size * aInflation); } WritingMode wm(aStyleContext); return pc->DeviceContext()->GetMetricsFor( font, aStyleContext->StyleFont()->mLanguage, - wm.IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal, + wm.IsVertical() && !wm.IsSideways() + ? gfxFont::eVertical : gfxFont::eHorizontal, fs, tp, *aFontMetrics); } nsIFrame* nsLayoutUtils::FindChildContainingDescendant(nsIFrame* aParent, nsIFrame* aDescendantFrame) { nsIFrame* result = aDescendantFrame; @@ -4888,19 +4889,21 @@ nsLayoutUtils::PaintTextShadow(const nsI contextBoxBlur.DoPaint(); aDestCtx->Restore(); } } /* static */ nscoord nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics, - nscoord aLineHeight) -{ - nscoord fontAscent = aFontMetrics->MaxAscent(); + nscoord aLineHeight, + bool aIsInverted) +{ + nscoord fontAscent = aIsInverted ? aFontMetrics->MaxDescent() + : aFontMetrics->MaxAscent(); nscoord fontHeight = aFontMetrics->MaxHeight(); nscoord leading = aLineHeight - fontHeight; return fontAscent + leading/2; } /* static */ bool @@ -7345,17 +7348,18 @@ nsLayoutUtils::SetBSizeFromFontMetrics(c // Do things the standard css2 way -- though it's hard to find it // in the css2 spec! It's actually found in the css1 spec section // 4.4 (you will have to read between the lines to really see // it). // // The height of our box is the sum of our font size plus the top // and bottom border and padding. The height of children do not // affect our height. - aMetrics.SetBlockStartAscent(fm->MaxAscent()); + aMetrics.SetBlockStartAscent(aLineWM.IsLineInverted() ? fm->MaxDescent() + : fm->MaxAscent()); aMetrics.BSize(aLineWM) = fm->MaxHeight(); } else { NS_WARNING("Cannot get font metrics - defaulting sizes to 0"); aMetrics.SetBlockStartAscent(aMetrics.BSize(aLineWM) = 0); } aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() + aFramePadding.BStart(aFrameWM)); aMetrics.BSize(aLineWM) +=
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1392,21 +1392,25 @@ public: const nsRect& aDirtyRect, const nscolor& aForegroundColor, TextShadowCallback aCallback, void* aCallbackData); /** * Gets the baseline to vertically center text from a font within a * line of specified height. + * aIsInverted: true if the text is inverted relative to the block + * direction, so that the block-dir "ascent" corresponds to font + * descent. (Applies to sideways text in vertical-lr mode.) * * Returns the baseline position relative to the top of the line. */ static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics, - nscoord aLineHeight); + nscoord aLineHeight, + bool aIsInverted); /** * Derive a baseline of |aFrame| (measured from its top border edge) * from its first in-flow line box (not descending into anything with * 'overflow' not 'visible', potentially including aFrame itself). * * Returns true if a baseline was found (and fills in aResult). * Otherwise returns false.
--- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -514,17 +514,18 @@ nsTextControlFrame::Reflow(nsPresContext lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(), NS_AUTOHEIGHT, inflation); } nsRefPtr<nsFontMetrics> fontMet; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet), inflation); // now adjust for our borders and padding aDesiredSize.SetBlockStartAscent( - nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight) + + 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);
--- a/layout/generic/WritingModes.h +++ b/layout/generic/WritingModes.h @@ -163,22 +163,27 @@ public: /** * Return the line-relative inline flow direction as a BidiDir */ BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); } /** * Return true if LTR. (Convenience method) */ - bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); } + bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); } /** * True if vertical-mode block direction is LR (convenience method). */ - bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); } + bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); } + + /** + * True if vertical-mode block direction is RL (convenience method). + */ + bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); } /** * True if vertical writing mode, i.e. when * writing-mode: vertical-lr | vertical-rl. */ #ifdef WRITING_MODE_VERTICAL_ENABLED bool IsVertical() const { return !!(mWritingMode & eOrientationMask); } #else
--- a/layout/generic/nsBRFrame.cpp +++ b/layout/generic/nsBRFrame.cpp @@ -117,17 +117,18 @@ BRFrame::Reflow(nsPresContext* aPresCont // normal inline frame. That line-height is used is important // here for cases where the line-height is less than 1. nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), nsLayoutUtils::FontSizeInflationFor(this)); if (fm) { nscoord logicalHeight = aReflowState.CalcLineHeight(); finalSize.BSize(wm) = logicalHeight; - aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, 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.
--- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -510,17 +510,19 @@ nsBlockFrame::GetCaretBaseline() const } } nsRefPtr<nsFontMetrics> fm; float inflation = nsLayoutUtils::FontSizeInflationFor(this); nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation); nscoord lineHeight = nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(), contentRect.height, inflation); - return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight) + bp.top; + const WritingMode wm = GetWritingMode(); + return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight, + wm.IsLineInverted()) + bp.top; } ///////////////////////////////////////////////////////////////////////////// // Child frame enumeration const nsFrameList& nsBlockFrame::GetChildList(ChildListID aListID) const { @@ -2547,17 +2549,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe } } nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), nsLayoutUtils::FontSizeInflationFor(this)); nscoord minAscent = - nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight); + nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight, + wm.IsLineInverted()); nscoord minDescent = aState.mMinLineHeight - minAscent; aState.mBCoord += std::max(minAscent, metrics.BlockStartAscent()) + std::max(minDescent, metrics.BSize(wm) - metrics.BlockStartAscent()); nscoord offset = minAscent - metrics.BlockStartAscent(); if (offset > 0) {
--- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1334,17 +1334,22 @@ nsFrame::SetAdditionalStyleContext(int32 NS_PRECONDITION(aIndex >= 0, "invalid index number"); } nscoord nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const { NS_ASSERTION(!NS_SUBTREE_DIRTY(this), "frame must not be dirty"); - // Default to the bottom margin edge, per CSS2.1's definition of the + // Baseline for inverted line content is the top (block-start) margin edge, + // as the frame is in effect "flipped" for alignment purposes. + if (aWritingMode.IsLineInverted()) { + return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode); + } + // Otherwise, the bottom margin edge, per CSS2.1's definition of the // 'baseline' value of 'vertical-align'. return BSize(aWritingMode) + GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode); } const nsFrameList& nsFrame::GetChildList(ChildListID aListID) const {
--- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -2093,17 +2093,18 @@ nsLineLayout::VerticalAlignFrames(PerSpa } if (applyMinLH) { if (psd->mHasNonemptyContent || preMode || mHasBullet) { #ifdef NOISY_BLOCKDIR_ALIGN printf(" [span]==> adjusting min/maxBCoord: currentValues: %d,%d", minBCoord, maxBCoord); #endif nscoord minimumLineBSize = mMinLineBSize; nscoord blockStart = - -nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize); + -nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize, + lineWM.IsLineInverted()); nscoord blockEnd = blockStart + minimumLineBSize; if (blockStart < minBCoord) minBCoord = blockStart; if (blockEnd > maxBCoord) maxBCoord = blockEnd; #ifdef NOISY_BLOCKDIR_ALIGN printf(" new values: %d,%d\n", minBCoord, maxBCoord); #endif
--- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -1785,23 +1785,23 @@ GetHyphenTextRun(gfxTextRun* aTextRun, g if (!ctx) return nullptr; return aTextRun->GetFontGroup()-> MakeHyphenTextRun(ctx, aTextRun->GetAppUnitsPerDevUnit()); } static gfxFont::Metrics -GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVertical) +GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVerticalMetrics) { if (!aFontGroup) return gfxFont::Metrics(); gfxFont* font = aFontGroup->GetFirstValidFont(); - return font->GetMetrics(aVertical ? gfxFont::eVertical : - gfxFont::eHorizontal); + return font->GetMetrics(aVerticalMetrics ? gfxFont::eVertical + : gfxFont::eHorizontal); } PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NORMAL == 0); PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE == 1); PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NOWRAP == 2); PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_WRAP == 3); PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_LINE == 4); PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_SPACE == 5); @@ -3156,17 +3156,17 @@ ComputeTabWidthAppUnits(nsIFrame* aFrame { // Get the number of spaces from CSS -moz-tab-size const nsStyleText* textStyle = aFrame->StyleText(); // Round the space width when converting to appunits the same way // textruns do gfxFloat spaceWidthAppUnits = NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(), - aTextRun->IsVertical()).spaceWidth * + aTextRun->UseCenterBaseline()).spaceWidth * aTextRun->GetAppUnitsPerDevUnit()); return textStyle->mTabSize * spaceWidthAppUnits; } // aX and the result are in whole appunits. static gfxFloat AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, gfxTextRun* aTextRun, gfxFloat* aCachedTabWidth) @@ -4913,51 +4913,55 @@ nsTextFrame::UnionAdditionalOverflow(nsP PropertyProvider& aProvider, nsRect* aVisualOverflowRect, bool aIncludeTextDecorations) { // Text-shadow overflows nsRect shadowRect = nsLayoutUtils::GetTextShadowRectsUnion(*aVisualOverflowRect, this); aVisualOverflowRect->UnionRect(*aVisualOverflowRect, shadowRect); - bool vertical = mTextRun->IsVertical(); + bool verticalRun = mTextRun->IsVertical(); + bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline(); + bool inverted = GetWritingMode().IsLineInverted(); if (IsFloatingFirstLetterChild()) { // The underline/overline drawable area must be contained in the overflow // rect when this is in floating first letter frame at *both* modes. // In this case, aBlock is the ::first-letter frame. uint8_t decorationStyle = aBlock->StyleContext()-> StyleTextReset()->GetDecorationStyle(); // If the style is none, let's include decoration line rect as solid style // since changing the style from none to solid/dotted/dashed doesn't cause // reflow. if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; } nsFontMetrics* fontMetrics = aProvider.GetFontMetrics(); nscoord underlineOffset, underlineSize; fontMetrics->GetUnderline(underlineOffset, underlineSize); - nscoord maxAscent = fontMetrics->MaxAscent(); + nscoord maxAscent = inverted ? fontMetrics->MaxDescent() + : fontMetrics->MaxAscent(); gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(); gfxFloat gfxWidth = - (vertical ? aVisualOverflowRect->height : aVisualOverflowRect->width) / + (verticalRun ? aVisualOverflowRect->height + : aVisualOverflowRect->width) / appUnitsPerDevUnit; gfxFloat gfxAscent = gfxFloat(mAscent) / appUnitsPerDevUnit; gfxFloat gfxMaxAscent = maxAscent / appUnitsPerDevUnit; gfxFloat gfxUnderlineSize = underlineSize / appUnitsPerDevUnit; gfxFloat gfxUnderlineOffset = underlineOffset / appUnitsPerDevUnit; nsRect underlineRect = nsCSSRendering::GetTextDecorationRect(aPresContext, gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxUnderlineOffset, - NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, vertical); + NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, verticalRun); nsRect overlineRect = nsCSSRendering::GetTextDecorationRect(aPresContext, gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxMaxAscent, - NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, vertical); + NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, verticalRun); aVisualOverflowRect->UnionRect(*aVisualOverflowRect, underlineRect); aVisualOverflowRect->UnionRect(*aVisualOverflowRect, overlineRect); // XXX If strikeoutSize is much thicker than the underlineSize, it may // cause overflowing from the overflow rect. However, such case // isn't realistic, we don't need to compute it now. } @@ -4967,108 +4971,129 @@ nsTextFrame::UnionAdditionalOverflow(nsP // maxima and minima are required to reliably generate the rectangle for // them TextDecorations textDecs; GetTextDecorations(aPresContext, eResolvedColors, textDecs); if (textDecs.HasDecorationLines()) { nscoord inflationMinFontSize = nsLayoutUtils::InflationMinFontSizeFor(aBlock); - const nscoord measure = vertical ? GetSize().height : GetSize().width; + const nscoord measure = verticalRun ? GetSize().height : GetSize().width; const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(), - gfxWidth = measure / appUnitsPerDevUnit, - ascent = gfxFloat(mAscent) / appUnitsPerDevUnit; - nscoord top(nscoord_MAX), bottom(nscoord_MIN); + gfxWidth = measure / appUnitsPerDevUnit; + gfxFloat ascent = gfxFloat(mAscent) / appUnitsPerDevUnit; + const WritingMode wm = GetWritingMode(); + if (wm.IsVerticalRL()) { + ascent = -ascent; + } + + nscoord topOrLeft(nscoord_MAX), bottomOrRight(nscoord_MIN); // Below we loop through all text decorations and compute the rectangle // containing all of them, in this frame's coordinate space for (uint32_t i = 0; i < textDecs.mUnderlines.Length(); ++i) { const LineDecoration& dec = textDecs.mUnderlines[i]; uint8_t decorationStyle = dec.mStyle; // If the style is solid, let's include decoration line rect of solid // style since changing the style from none to solid/dotted/dashed // doesn't cause reflow. if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); const nsRect decorationRect = nsCSSRendering::GetTextDecorationRect(aPresContext, gfxSize(gfxWidth, metrics.underlineSize), ascent, metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, - vertical) + + verticalRun) + nsPoint(0, -dec.mBaselineOffset); - top = std::min(decorationRect.y, top); - bottom = std::max(decorationRect.YMost(), bottom); + if (verticalRun) { + topOrLeft = std::min(decorationRect.x, topOrLeft); + bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight); + } else { + topOrLeft = std::min(decorationRect.y, topOrLeft); + bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight); + } } for (uint32_t i = 0; i < textDecs.mOverlines.Length(); ++i) { const LineDecoration& dec = textDecs.mOverlines[i]; uint8_t decorationStyle = dec.mStyle; // If the style is solid, let's include decoration line rect of solid // style since changing the style from none to solid/dotted/dashed // doesn't cause reflow. if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); const nsRect decorationRect = nsCSSRendering::GetTextDecorationRect(aPresContext, gfxSize(gfxWidth, metrics.underlineSize), ascent, metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, - vertical) + + verticalRun) + nsPoint(0, -dec.mBaselineOffset); - top = std::min(decorationRect.y, top); - bottom = std::max(decorationRect.YMost(), bottom); + if (verticalRun) { + topOrLeft = std::min(decorationRect.x, topOrLeft); + bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight); + } else { + topOrLeft = std::min(decorationRect.y, topOrLeft); + bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight); + } } for (uint32_t i = 0; i < textDecs.mStrikes.Length(); ++i) { const LineDecoration& dec = textDecs.mStrikes[i]; uint8_t decorationStyle = dec.mStyle; // If the style is solid, let's include decoration line rect of solid // style since changing the style from none to solid/dotted/dashed // doesn't cause reflow. if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); const nsRect decorationRect = nsCSSRendering::GetTextDecorationRect(aPresContext, gfxSize(gfxWidth, metrics.strikeoutSize), ascent, metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationStyle, - vertical) + + verticalRun) + nsPoint(0, -dec.mBaselineOffset); - top = std::min(decorationRect.y, top); - bottom = std::max(decorationRect.YMost(), bottom); + + if (verticalRun) { + topOrLeft = std::min(decorationRect.x, topOrLeft); + bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight); + } else { + topOrLeft = std::min(decorationRect.y, topOrLeft); + bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight); + } } - aVisualOverflowRect->UnionRect(*aVisualOverflowRect, - vertical ? - nsRect(top, 0, bottom - top, measure) : - nsRect(0, top, measure, bottom - top)); + aVisualOverflowRect->UnionRect( + *aVisualOverflowRect, + verticalRun ? nsRect(topOrLeft, 0, bottomOrRight - topOrLeft, measure) + : nsRect(0, topOrLeft, measure, bottomOrRight - topOrLeft)); } } // When this frame is not selected, the text-decoration area must be in // frame bounds. if (!IsSelected() || !CombineSelectionUnderlineRect(aPresContext, *aVisualOverflowRect)) return; AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED); @@ -5718,63 +5743,64 @@ nsTextFrame::PaintTextSelectionDecoratio for (int32_t i = start; i < end; ++i) { selectedChars[i] = sdptr; } } sdptr = sdptr->mNext; } gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont(); - bool vertical = mTextRun->IsVertical(); + bool verticalRun = mTextRun->IsVertical(); + bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline(); gfxFont::Metrics - decorationMetrics(firstFont->GetMetrics(vertical ? + decorationMetrics(firstFont->GetMetrics(useVerticalMetrics ? gfxFont::eVertical : gfxFont::eHorizontal)); - if (!vertical) { + if (!useVerticalMetrics) { // The potential adjustment from using gfxFontGroup::GetUnderlineOffset - // is only valid for horizontal text. + // is only valid for horizontal font metrics. decorationMetrics.underlineOffset = aProvider.GetFontGroup()->GetUnderlineOffset(); } gfxFloat startIOffset = - vertical ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x; + verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x; SelectionIterator iterator(selectedChars, aContentOffset, aContentLength, aProvider, mTextRun, startIOffset); gfxFloat iOffset, hyphenWidth; uint32_t offset, length; int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel(); // XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint? gfxPoint pt; - if (vertical) { + if (verticalRun) { pt.x = (aTextBaselinePt.x - mAscent) / app; } else { pt.y = (aTextBaselinePt.y - mAscent) / app; } gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app, aDirtyRect.width / app, aDirtyRect.height / app); SelectionType type; TextRangeStyle selectedStyle; while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth, &type, &selectedStyle)) { gfxFloat advance = hyphenWidth + mTextRun->GetAdvanceWidth(offset, length, &aProvider); if (type == aSelectionType) { - if (vertical) { + if (verticalRun) { pt.y = (aFramePt.y + iOffset - (mTextRun->IsRightToLeft() ? advance : 0)) / app; } else { pt.x = (aFramePt.x + iOffset - (mTextRun->IsRightToLeft() ? advance : 0)) / app; } gfxFloat width = Abs(advance) / app; gfxFloat xInFrame = pt.x - (aFramePt.x / app); DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this, aTextPaintStyle, selectedStyle, pt, xInFrame, width, mAscent / app, decorationMetrics, - aCallbacks, vertical); + aCallbacks, verticalRun); } iterator.UpdateWithAdvance(advance); } } bool nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, const gfxPoint& aFramePt, @@ -6008,38 +6034,37 @@ nsTextFrame::PaintText(nsRenderingContex return; PropertyProvider provider(this, iter, nsTextFrame::eInflated); // Trim trailing whitespace provider.InitializeForDisplay(true); gfxContext* ctx = aRenderingContext->ThebesContext(); const bool rtl = mTextRun->IsRightToLeft(); - const bool vertical = mTextRun->IsVertical(); + const bool verticalRun = mTextRun->IsVertical(); + WritingMode wm = GetWritingMode(); const nscoord frameWidth = GetSize().width; gfxPoint framePt(aPt.x, aPt.y); gfxPoint textBaselinePt; - if (vertical) { - WritingMode wm = GetWritingMode(); - textBaselinePt = - gfxPoint(wm.IsVerticalLR() ? aPt.x + mAscent - : aPt.x + frameWidth - mAscent, + if (verticalRun) { + textBaselinePt = // XXX sideways-left will need different handling here + gfxPoint(aPt.x + (wm.IsVerticalLR() ? mAscent : frameWidth - mAscent), rtl ? aPt.y + GetSize().height : aPt.y); } else { textBaselinePt = gfxPoint(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x, nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent)); } uint32_t startOffset = provider.GetStart().GetSkippedOffset(); uint32_t maxLength = ComputeTransformedLength(provider); nscoord snappedLeftEdge, snappedRightEdge; if (!MeasureCharClippedText(provider, aItem.mLeftEdge, aItem.mRightEdge, &startOffset, &maxLength, &snappedLeftEdge, &snappedRightEdge)) { return; } - if (vertical) { + if (verticalRun) { textBaselinePt.y += rtl ? -snappedRightEdge : snappedLeftEdge; } else { textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge; } nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge, snappedRightEdge); nsTextPaintStyle textPaintStyle(this); textPaintStyle.SetResolveColors(!aCallbacks); @@ -6154,42 +6179,53 @@ nsTextFrame::DrawTextRunAndDecorations( gfxFloat& aAdvanceWidth, bool aDrawSoftHyphen, const TextDecorations& aDecorations, const nscolor* const aDecorationOverrideColor, gfxTextContextPaint* aContextPaint, nsTextFrame::DrawPathCallbacks* aCallbacks) { const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel(); - bool vertical = mTextRun->IsVertical(); + bool verticalRun = mTextRun->IsVertical(); + bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline(); // XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint? nscoord x = NSToCoordRound(aFramePt.x); nscoord y = NSToCoordRound(aFramePt.y); - // 'width' here is textrun-relative, so for a vertical run it's - // really the height of the decoration - nscoord width = vertical ? GetRect().height : GetRect().width; + // 'measure' here is textrun-relative, so for a horizontal run it's the + // width, while for a vertical run it's the height of the decoration + const nsSize frameSize = GetSize(); + nscoord measure = verticalRun ? frameSize.height : frameSize.width; // XXX todo: probably should have a vertical version of this... - if (!vertical) { - aClipEdges.Intersect(&x, &width); + if (!verticalRun) { + aClipEdges.Intersect(&x, &measure); } // decPt is the physical point where the decoration is to be drawn, // relative to the frame; one of its coordinates will be updated below. gfxPoint decPt(x / app, y / app); - gfxFloat& bCoord = vertical ? decPt.x : decPt.y; - - // ...whereas decSize is a textrun-relative size - gfxSize decSize(width / app, 0); - const gfxFloat ascent = gfxFloat(mAscent) / app; + gfxFloat& bCoord = verticalRun ? decPt.x : decPt.y; + + // decSize is a textrun-relative size, so its 'width' field is actually + // the run-relative measure, and 'height' will be the line thickness + gfxSize decSize(measure / app, 0); + gfxFloat ascent = gfxFloat(mAscent) / app; // The starting edge of the frame in block direction - const gfxFloat frameBStart = vertical ? aFramePt.x : aFramePt.y; + gfxFloat frameBStart = verticalRun ? aFramePt.x : aFramePt.y; + + // In vertical-rl mode, block coordinates are measured from the right, + // so we need to adjust here. + const WritingMode wm = GetWritingMode(); + if (wm.IsVerticalRL()) { + frameBStart += frameSize.width; + ascent = -ascent; + } gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app, aDirtyRect.Width() / app, aDirtyRect.Height() / app); nscoord inflationMinFontSize = nsLayoutUtils::InflationMinFontSizeFor(this); // Underlines @@ -6198,46 +6234,46 @@ nsTextFrame::DrawTextRunAndDecorations( if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { continue; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, - dec.mStyle, eNormalDecoration, aCallbacks, vertical); + dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); } // Overlines for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) { const LineDecoration& dec = aDecorations.mOverlines[i]; if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { continue; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle, - eNormalDecoration, aCallbacks, vertical); + eNormalDecoration, aCallbacks, verticalRun); } // CSS 2.1 mandates that text be painted after over/underlines, and *then* // line-throughs DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor, aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks); // Line-throughs @@ -6246,25 +6282,25 @@ nsTextFrame::DrawTextRunAndDecorations( if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) { continue; } float inflation = GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize); const gfxFont::Metrics metrics = GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation), - vertical); + useVerticalMetrics); decSize.height = metrics.strikeoutSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor, aDecorationOverrideColor, decPt, 0.0, decSize, ascent, metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, - dec.mStyle, eNormalDecoration, aCallbacks, vertical); + dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); } } void nsTextFrame::DrawText( gfxContext* const aCtx, const gfxRect& aDirtyRect, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, uint32_t aOffset, uint32_t aLength, @@ -6453,19 +6489,22 @@ nsTextFrame::CombineSelectionUnderlineRe nsRect givenRect = aRect; nsRefPtr<nsFontMetrics> fm; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), GetFontSizeInflation()); gfxFontGroup* fontGroup = fm->GetThebesFontGroup(); gfxFont* firstFont = fontGroup->GetFirstValidFont(); - bool vertical = GetWritingMode().IsVertical(); + WritingMode wm = GetWritingMode(); + bool verticalRun = wm.IsVertical(); + bool useVerticalMetrics = verticalRun && !wm.IsSideways(); const gfxFont::Metrics& metrics = - firstFont->GetMetrics(vertical ? gfxFont::eVertical : gfxFont::eHorizontal); + firstFont->GetMetrics(useVerticalMetrics ? gfxFont::eVertical + : gfxFont::eHorizontal); gfxFloat underlineOffset = fontGroup->GetUnderlineOffset(); gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent); gfxFloat descentLimit = ComputeDescentLimitForSelectionUnderline(aPresContext, this, metrics); SelectionDetails *details = GetSelectionDetails(); for (SelectionDetails *sd = details; sd; sd = sd->mNext) { if (sd->mStart == sd->mEnd || !(sd->mType & SelectionTypesWithDecorations)) @@ -6500,17 +6539,17 @@ nsTextFrame::CombineSelectionUnderlineRe gfxSize size(aPresContext->AppUnitsToGfxUnits(aRect.width), ComputeSelectionUnderlineHeight(aPresContext, metrics, sd->mType)); relativeSize = std::max(relativeSize, 1.0f); size.height *= relativeSize; decorationArea = nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent, underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, - style, vertical, descentLimit); + style, verticalRun, descentLimit); aRect.UnionRect(aRect, decorationArea); } DestroySelectionDetails(details); return !aRect.IsEmpty() && !givenRect.Contains(aRect); } bool @@ -7612,17 +7651,21 @@ nsTextFrame::ComputeTightBounds(gfxConte gfxTextRun::Metrics metrics = mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(), ComputeTransformedLength(provider), gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aContext, &provider); // mAscent should be the same as metrics.mAscent, but it's what we use to // paint so that's the one we'll use. - nsRect boundingBox = RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent); + nsRect boundingBox = RoundOut(metrics.mBoundingBox); + if (GetWritingMode().IsLineInverted()) { + boundingBox.y = -boundingBox.YMost(); + } + boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. Swap(boundingBox.x, boundingBox.y); Swap(boundingBox.width, boundingBox.height); } return boundingBox; } @@ -8297,48 +8340,64 @@ nsTextFrame::ReflowText(nsLineLayout& aL finalSize.ISize(wm) = NSToCoordCeil(std::max(gfxFloat(0.0), textMetrics.mAdvanceWidth)); if (transformedCharsFit == 0 && !usedHyphenation) { aMetrics.SetBlockStartAscent(0); finalSize.BSize(wm) = 0; } else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) { // Use actual text metrics for floating first letter frame. - aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent)); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + - NSToCoordCeil(textMetrics.mDescent); + if (wm.IsLineInverted()) { + aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mDescent)); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + + NSToCoordCeil(textMetrics.mAscent); + } else { + aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent)); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + + NSToCoordCeil(textMetrics.mDescent); + } } else { // Otherwise, ascent should contain the overline drawable area. // And also descent should contain the underline drawable area. // nsFontMetrics::GetMaxAscent/GetMaxDescent contains them. nsFontMetrics* fm = provider.GetFontMetrics(); nscoord fontAscent = fm->MaxAscent(); nscoord fontDescent = fm->MaxDescent(); - aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent)); - nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent); - finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; + if (wm.IsLineInverted()) { + aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent)); + nscoord descent = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; + } else { + aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent)); + nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent); + finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; + } } aMetrics.SetSize(wm, finalSize); NS_ASSERTION(aMetrics.BlockStartAscent() >= 0, "Negative ascent???"); NS_ASSERTION(aMetrics.BSize(aMetrics.GetWritingMode()) - aMetrics.BlockStartAscent() >= 0, "Negative descent???"); mAscent = aMetrics.BlockStartAscent(); // Handle text that runs outside its normal bounds. - nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); - aMetrics.SetOverflowAreasToDesiredBounds(); + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); + if (wm.IsLineInverted()) { + boundingBox.y = -boundingBox.YMost(); + } + boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. Swap(boundingBox.x, boundingBox.y); Swap(boundingBox.width, boundingBox.height); } + aMetrics.SetOverflowAreasToDesiredBounds(); aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox); // When we have text decorations, we don't need to compute their overflow now // because we're guaranteed to do it later // (see nsLineLayout::RelativePositionFrames) UnionAdditionalOverflow(presContext, aLineLayout.LineContainerRS()->frame, provider, &aMetrics.VisualOverflow(), false); @@ -8544,28 +8603,33 @@ nsTextFrame::RecomputeOverflow(const nsH PropertyProvider provider(this, iter, nsTextFrame::eInflated); provider.InitializeForDisplay(true); gfxTextRun::Metrics textMetrics = mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(), ComputeTransformedLength(provider), gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); - nsRect &vis = result.VisualOverflow(); - nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent); + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); + if (GetWritingMode().IsLineInverted()) { + boundingBox.y = -boundingBox.YMost(); + } + boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. Swap(boundingBox.x, boundingBox.y); Swap(boundingBox.width, boundingBox.height); } + nsRect &vis = result.VisualOverflow(); vis.UnionRect(vis, boundingBox); UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider, &vis, true); return result; } + static char16_t TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun, uint32_t aSkippedOffset, char16_t aChar) { if (aChar == '\n') { return aStyle->NewlineIsSignificant() ? aChar : ' '; } if (aChar == '\t') { return aStyle->TabIsSignificant() ? aChar : ' ';