tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit afa632d8ef0c12f07ee3b36574e53f505ce256fe
parent f66df20fb0b399ca2b4b5e194f2cc62cdba4b9b6
Author: Serban Stanca <sstanca@mozilla.com>
Date:   Thu, 16 Oct 2025 05:46:12 +0300

Revert "Bug 1994197, Bug 1994193 - patch 3 - Also use integer nscoords for textrun ascent/descent metrics and bounding box. r=firefox-svg-reviewers,longsonr" for causing assertion failures in nsTextFrame.cpp.

This reverts commit eb7cdb05c4bcd0835692824bbf9741f6857e668d.

This reverts commit d1e97328cdef956eb5ef2cbd74754655d51acfee.

This reverts commit f0290e617fba4d07670494febc4db4349196e5b5.

This reverts commit f4ed96250592feb6e435f09305a3f067c6442d61.

Diffstat:
Mdom/canvas/CanvasRenderingContext2D.cpp | 29++++++++++++-----------------
Mgfx/src/nsFontMetrics.cpp | 15+++++++--------
Mgfx/thebes/gfxFont.cpp | 105+++++++++++++++++++++++++++++++++++++------------------------------------------
Mgfx/thebes/gfxFont.h | 23+++++++++++++----------
Mgfx/thebes/gfxGlyphExtents.cpp | 6+++---
Mgfx/thebes/gfxGlyphExtents.h | 10+++++-----
Mgfx/thebes/gfxTextRun.cpp | 61++++++++++++++++++++++++++-----------------------------------
Mgfx/thebes/gfxTextRun.h | 6++----
Mlayout/generic/nsTextFrame.cpp | 123++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mlayout/generic/nsTextFrame.h | 16++++++++--------
Mlayout/mathml/nsMathMLChar.cpp | 10+++++-----
Mlayout/svg/SVGTextFrame.cpp | 17++++++++++-------
Mtesting/web-platform/meta/css/css-writing-modes/text-combine-upright-gen-con-001.html.ini | 1-
Mtesting/web-platform/mozilla/meta/mathml/tables/dir-6a.html.ini | 1-
14 files changed, 199 insertions(+), 224 deletions(-)

diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4635,7 +4635,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final explicit PropertyProvider(const CanvasBidiProcessor& aProcessor) : mProcessor(aProcessor) {} - bool GetSpacing(gfxTextRun::Range aRange, + void GetSpacing(gfxTextRun::Range aRange, gfxFont::Spacing* aSpacing) const { for (auto i = aRange.start; i < aRange.end; ++i) { auto* charGlyphs = mProcessor.mTextRun->GetCharacterGlyphs(); @@ -4665,7 +4665,6 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final } aSpacing++; } - return mProcessor.mLetterSpacing != 0 || mProcessor.mWordSpacing != 0; } mozilla::StyleHyphens GetHyphensOption() const { @@ -4677,9 +4676,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final gfxTextRun::HyphenType* aBreakBefore) const { MOZ_ASSERT_UNREACHABLE("no hyphenation in canvas2d text!"); } - nscoord GetHyphenWidth() const { + gfxFloat GetHyphenWidth() const { MOZ_ASSERT_UNREACHABLE("no hyphenation in canvas2d text!"); - return 0; + return 0.0; } already_AddRefed<DrawTarget> GetDrawTarget() const { MOZ_ASSERT_UNREACHABLE("no hyphenation in canvas2d text!"); @@ -4736,13 +4735,11 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final // this only measures the height; the total width is gotten from the // the return value of ProcessText. if (mDoMeasureBoundingBox) { - // The bounding box is tracked in device pixels. - gfxRect bbox = nsLayoutUtils::RectToGfxRect(textRunMetrics.mBoundingBox, - mAppUnitsPerDevPixel); - mBoundingBox = mBoundingBox.Union(bbox); + textRunMetrics.mBoundingBox.Scale(1.0 / mAppUnitsPerDevPixel); + mBoundingBox = mBoundingBox.Union(textRunMetrics.mBoundingBox); } - return textRunMetrics.mAdvanceWidth; + return NSToCoordRound(textRunMetrics.mAdvanceWidth); } already_AddRefed<gfxPattern> GetGradientFor(Style aStyle) { @@ -4938,8 +4935,8 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final mozilla::gfx::PaletteCache& mPaletteCache; // spacing adjustments to be applied - nscoord mLetterSpacing = 0; - nscoord mWordSpacing = 0; + gfx::Float mLetterSpacing = 0.0f; + gfx::Float mWordSpacing = 0.0f; // to record any unsupported characters found in the text, // and notify front-end if it is interested @@ -5106,9 +5103,8 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText( if (state.letterSpacing != 0.0 || state.wordSpacing != 0.0) { processor.mLetterSpacing = - NSToCoordRound(state.letterSpacing * processor.mAppUnitsPerDevPixel); - processor.mWordSpacing = - NSToCoordRound(state.wordSpacing * processor.mAppUnitsPerDevPixel); + state.letterSpacing * processor.mAppUnitsPerDevPixel; + processor.mWordSpacing = state.wordSpacing * processor.mAppUnitsPerDevPixel; processor.mTextRunFlags |= gfx::ShapedTextFlags::TEXT_ENABLE_SPACING; if (state.letterSpacing != 0.0) { processor.mTextRunFlags |= @@ -5235,7 +5231,7 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText( // based on the text position and advance. if (!doCalculateBounds) { processor.mBoundingBox.width = totalWidth; - processor.mBoundingBox.MoveBy(processor.mPt.x, processor.mPt.y); + processor.mBoundingBox.MoveBy(gfxPoint(processor.mPt.x, processor.mPt.y)); } processor.mPt.x *= processor.mAppUnitsPerDevPixel; @@ -5288,8 +5284,7 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText( if (aOp == CanvasRenderingContext2D::TextDrawOperation::FILL && !doCalculateBounds) { - RedrawUser(gfxRect(boundingBox.x, boundingBox.y, boundingBox.width, - boundingBox.height)); + RedrawUser(boundingBox); } else { Redraw(); } diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp @@ -89,7 +89,7 @@ class StubPropertyProvider final : public gfxTextRun::PropertyProvider { "This shouldn't be called because we never call BreakAndMeasureText"); return mozilla::StyleHyphens::None; } - nscoord GetHyphenWidth() const override { + gfxFloat GetHyphenWidth() const override { NS_ERROR("This shouldn't be called because we never enable hyphens"); return 0; } @@ -101,9 +101,8 @@ class StubPropertyProvider final : public gfxTextRun::PropertyProvider { NS_ERROR("This shouldn't be called because we never enable hyphens"); return 60; } - bool GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) const override { + void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) const override { NS_ERROR("This shouldn't be called because we never enable spacing"); - return false; } gfx::ShapedTextFlags GetShapedTextFlags() const override { NS_ERROR("This shouldn't be called because we never enable hyphens"); @@ -401,11 +400,11 @@ static nsBoundingMetrics GetTextBoundingMetrics( gfxTextRun::Metrics theMetrics = textRun->MeasureText( gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider); - m.leftBearing = theMetrics.mBoundingBox.X(); - m.rightBearing = theMetrics.mBoundingBox.XMost(); - m.ascent = -theMetrics.mBoundingBox.Y(); - m.descent = theMetrics.mBoundingBox.YMost(); - m.width = theMetrics.mAdvanceWidth; + m.leftBearing = NSToCoordFloor(theMetrics.mBoundingBox.X()); + m.rightBearing = NSToCoordCeil(theMetrics.mBoundingBox.XMost()); + m.ascent = NSToCoordCeil(-theMetrics.mBoundingBox.Y()); + m.descent = NSToCoordCeil(theMetrics.mBoundingBox.YMost()); + m.width = NSToCoordRound(theMetrics.mAdvanceWidth); } return m; } diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp @@ -32,7 +32,6 @@ #include "gfxUserFontSet.h" #include "nsCRT.h" #include "nsContentUtils.h" -#include "nsLayoutUtils.h" #include "nsSpecialCasingData.h" #include "nsTextRunTransformations.h" #include "nsUGenCategory.h" @@ -963,11 +962,11 @@ void gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, mAscent = std::max(mAscent, aOther.mAscent); mDescent = std::max(mDescent, aOther.mDescent); if (aOtherIsOnLeft) { - mBoundingBox = (mBoundingBox + nsPoint(aOther.mAdvanceWidth, 0)) + mBoundingBox = (mBoundingBox + gfxPoint(aOther.mAdvanceWidth, 0)) .Union(aOther.mBoundingBox); } else { mBoundingBox = - mBoundingBox.Union(aOther.mBoundingBox + nsPoint(mAdvanceWidth, 0)); + mBoundingBox.Union(aOther.mBoundingBox + gfxPoint(mAdvanceWidth, 0)); } mAdvanceWidth += aOther.mAdvanceWidth; } @@ -2875,7 +2874,7 @@ bool gfxFont::HasColorGlyphFor(uint32_t aCh, uint32_t aNextCh) { return false; } -static void UnionRange(nscoord aX, nscoord* aDestMin, nscoord* aDestMax) { +static void UnionRange(gfxFloat aX, gfxFloat* aDestMin, gfxFloat* aDestMax) { *aDestMin = std::min(*aDestMin, aX); *aDestMax = std::max(*aDestMax, aX); } @@ -2896,7 +2895,7 @@ bool gfxFont::IsSpaceGlyphInvisible(DrawTarget* aRefDrawTarget, GetAdjustedSize() >= 1.0) { gfxGlyphExtents* extents = GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit()); - nsRect glyphExtents; + gfxRect glyphExtents; flag = extents->GetTightGlyphExtentsAppUnits( this, aRefDrawTarget, GetSpaceGlyph(), &glyphExtents) && glyphExtents.IsEmpty() @@ -2912,19 +2911,19 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, DrawTarget* aRefDrawTarget, Spacing* aSpacing, gfxGlyphExtents* aExtents, bool aIsRTL, bool aNeedsGlyphExtents, RunMetrics& aMetrics, - nscoord* aAdvanceMin, nscoord* aAdvanceMax) { + gfxFloat* aAdvanceMin, gfxFloat* aAdvanceMax) { const gfxTextRun::CompressedGlyph* charGlyphs = aTextRun->GetCharacterGlyphs(); + double x = 0; + if (aSpacing) { + x += aSpacing[0].mBefore; + } uint32_t spaceGlyph = GetSpaceGlyph(); bool allGlyphsInvisible = true; AutoReadLock lock(aExtents->mLock); - double x = 0; for (uint32_t i = aStart; i < aEnd; ++i) { - if (aSpacing) { - x += aSpacing->mBefore; - } const gfxTextRun::CompressedGlyph* glyphData = &charGlyphs[i]; if (glyphData->IsSimpleGlyph()) { double advance = glyphData->GetSimpleAdvance(); @@ -2936,7 +2935,7 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, gfxFontEntry::LazyFlag flag = mFontEntry->mSpaceGlyphIsInvisible; if (flag == gfxFontEntry::LazyFlag::Uninitialized && GetAdjustedSize() >= 1.0) { - nsRect glyphExtents; + gfxRect glyphExtents; flag = aExtents->GetTightGlyphExtentsAppUnitsLocked( this, aRefDrawTarget, spaceGlyph, &glyphExtents) && glyphExtents.IsEmpty() @@ -2959,11 +2958,11 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, UnionRange(x, aAdvanceMin, aAdvanceMax); UnionRange(x + extentsWidth, aAdvanceMin, aAdvanceMax); } else { - nsRect glyphRect; + gfxRect glyphRect; if (!aExtents->GetTightGlyphExtentsAppUnitsLocked( this, aRefDrawTarget, glyphIndex, &glyphRect)) { - glyphRect = nsRect(0, aMetrics.mBoundingBox.Y(), advance, - aMetrics.mBoundingBox.Height()); + glyphRect = gfxRect(0, aMetrics.mBoundingBox.Y(), advance, + aMetrics.mBoundingBox.Height()); } if (aIsRTL) { // In effect, swap left and right sidebearings of the glyph, for @@ -2986,15 +2985,15 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t j; for (j = 0; j < glyphCount; ++j, ++details) { uint32_t glyphIndex = details->mGlyphID; - nscoord advance = details->mAdvance; - nsRect glyphRect; + double advance = details->mAdvance; + gfxRect glyphRect; if (glyphData->IsMissing() || !aExtents->GetTightGlyphExtentsAppUnitsLocked( this, aRefDrawTarget, glyphIndex, &glyphRect)) { // We might have failed to get glyph extents due to // OOM or something - glyphRect = nsRect(0, -aMetrics.mAscent, advance, - aMetrics.mAscent + aMetrics.mDescent); + glyphRect = gfxRect(0, -aMetrics.mAscent, advance, + aMetrics.mAscent + aMetrics.mDescent); } if (aIsRTL) { // Swap left/right sidebearings of the glyph, because we're doing @@ -3012,8 +3011,11 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, } } if (aSpacing) { - x += aSpacing->mAfter; - ++aSpacing; + double space = aSpacing[i - aStart].mAfter; + if (i + 1 < aEnd) { + space += aSpacing[i + 1 - aStart].mBefore; + } + x += space; } } @@ -3055,9 +3057,9 @@ bool gfxFont::MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, "detailedGlyph record should not be missing!"); uint32_t j; for (j = 0; j < glyphCount; ++j, ++details) { - nscoord advance = details->mAdvance; - nsRect glyphRect(0, -aMetrics.mAscent, advance, - aMetrics.mAscent + aMetrics.mDescent); + double advance = details->mAdvance; + gfxRect glyphRect(0, -aMetrics.mAscent, advance, + aMetrics.mAscent + aMetrics.mDescent); if (aIsRTL) { // Swap left/right sidebearings of the glyph, because we're doing // mirrored measurement. @@ -3125,7 +3127,7 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun, : nsFontMetrics::eHorizontal; const gfxFont::Metrics& fontMetrics = GetMetrics(orientation); - nscoord baselineOffset = 0; + gfxFloat baselineOffset = 0; if (aTextRun->UseCenterBaseline() && orientation == nsFontMetrics::eHorizontal) { // For a horizontal font being used in vertical writing mode with @@ -3137,25 +3139,23 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun, // 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 = - NSToCoordRound(appUnitsPerDevUnit * - (fontMetrics.emAscent - fontMetrics.emDescent) / 2.0); + appUnitsPerDevUnit * (fontMetrics.emAscent - fontMetrics.emDescent) / 2; } RunMetrics metrics; - metrics.mAscent = NSToCoordRound(fontMetrics.maxAscent * appUnitsPerDevUnit); - metrics.mDescent = - NSToCoordRound(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.mAscent -= baselineOffset; metrics.mDescent += baselineOffset; metrics.mBoundingBox = - nsRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent); + gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent); return metrics; } - nscoord advanceMin = 0, advanceMax = 0; + gfxFloat advanceMin = 0, advanceMax = 0; bool isRTL = aTextRun->IsRightToLeft(); bool needsGlyphExtents = NeedsGlyphExtents(this, aTextRun); gfxGlyphExtents* extents = @@ -3180,8 +3180,8 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun, metrics.mBoundingBox.SetEmpty(); } else if (aBoundingBoxType == LOOSE_INK_EXTENTS) { UnionRange(metrics.mAdvanceWidth, &advanceMin, &advanceMax); - nsRect fontBox(advanceMin, -metrics.mAscent, advanceMax - advanceMin, - metrics.mAscent + metrics.mDescent); + gfxRect fontBox(advanceMin, -metrics.mAscent, advanceMax - advanceMin, + metrics.mAscent + metrics.mDescent); metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox); } @@ -3212,10 +3212,9 @@ gfxFont::RunMetrics gfxFont::Measure(const gfxTextRun* aTextRun, extendRightEdge = skew < 0.0 ? ceil(-skew * metrics.mBoundingBox.YMost()) : ceil(skew * -metrics.mBoundingBox.Y()); } - metrics.mBoundingBox.SetWidth( - metrics.mBoundingBox.Width() + - NSToCoordRound(extendLeftEdge + extendRightEdge)); - metrics.mBoundingBox.MoveByX(NSToCoordRound(-extendLeftEdge)); + metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() + + extendLeftEdge + extendRightEdge); + metrics.mBoundingBox.MoveByX(-extendLeftEdge); } if (baselineOffset != 0) { @@ -4115,27 +4114,16 @@ gfxGlyphExtents* gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) { return glyphExtents; } -// Helper to convert device-pixel bounds to nsRect using aAppPerDev factor. -// Note: not using nsLayoutUtils::RoundGfxRectToAppRect here because it -// has different rounding behavior (using Rect::ScaleRoundOut rather than -// rounding the individual fields), which affects MathML glyph placement. -template <class T> -static inline nsRect ToAppRect(const T& aBounds, int32_t aAppPerDev) { - return nsRect(NSToCoordRound(aBounds.X() * aAppPerDev), - NSToCoordRound(aBounds.Y() * aAppPerDev), - NSToCoordRound(aBounds.Width() * aAppPerDev), - NSToCoordRound(aBounds.Height() * aAppPerDev)); -} - void gfxFont::SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID, bool aNeedTight, gfxGlyphExtents* aExtents) { - int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit(); gfxRect svgBounds; if (mFontEntry->TryGetSVGData(this) && mFontEntry->HasSVGGlyph(aGlyphID) && mFontEntry->GetSVGGlyphExtents(aDrawTarget, aGlyphID, GetAdjustedSize(), &svgBounds)) { - aExtents->SetTightGlyphExtents(aGlyphID, - ToAppRect(svgBounds, appUnitsPerDevUnit)); + gfxFloat d2a = aExtents->GetAppUnitsPerDevUnit(); + aExtents->SetTightGlyphExtents( + aGlyphID, gfxRect(svgBounds.X() * d2a, svgBounds.Y() * d2a, + svgBounds.Width() * d2a, svgBounds.Height() * d2a)); return; } @@ -4148,8 +4136,10 @@ void gfxFont::SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID, mFontEntry->mCOLR, shaper->GetHBFont(), aGlyphID, aDrawTarget, scaledFont, mFUnitsConvFactor); if (!r.IsEmpty()) { - aExtents->SetTightGlyphExtents(aGlyphID, - ToAppRect(r, appUnitsPerDevUnit)); + gfxFloat d2a = aExtents->GetAppUnitsPerDevUnit(); + aExtents->SetTightGlyphExtents( + aGlyphID, gfxRect(r.X() * d2a, r.Y() * d2a, r.Width() * d2a, + r.Height() * d2a)); return; } } @@ -4159,6 +4149,7 @@ void gfxFont::SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID, GetGlyphBounds(aGlyphID, &bounds, mAntialiasOption == kAntialiasNone); const Metrics& fontMetrics = GetMetrics(nsFontMetrics::eHorizontal); + int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit(); if (!aNeedTight && bounds.x >= 0.0 && bounds.y >= -fontMetrics.maxAscent && bounds.height + bounds.y <= fontMetrics.maxDescent) { uint32_t appUnitsWidth = @@ -4175,8 +4166,10 @@ void gfxFont::SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID, } #endif - aExtents->SetTightGlyphExtents(aGlyphID, - ToAppRect(bounds, appUnitsPerDevUnit)); + gfxFloat d2a = appUnitsPerDevUnit; + aExtents->SetTightGlyphExtents( + aGlyphID, gfxRect(bounds.x * d2a, bounds.y * d2a, bounds.width * d2a, + bounds.height * d2a)); } // Try to initialize font metrics by reading sfnt tables directly; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h @@ -1652,28 +1652,31 @@ class gfxFont { * We let layout specify spacing on either side of any * character. We need to specify both before and after * spacing so that substring measurement can do the right things. - * These values are in appunits. + * These values are in appunits. They're always an integral number of + * appunits, but we specify them in floats in case very large spacing + * values are required. */ struct Spacing { - nscoord mBefore; - nscoord mAfter; + gfxFloat mBefore; + gfxFloat mAfter; }; - /** - * Metrics for a particular string. These are in appUnits. + * Metrics for a particular string */ struct RunMetrics { + RunMetrics() { mAdvanceWidth = mAscent = mDescent = 0.0; } + void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft); // can be negative (partly due to negative spacing). // Advance widths should be additive: the advance width of the // (offset1, length1) plus the advance width of (offset1 + length1, // length2) should be the advance width of (offset1, length1 + length2) - nscoord mAdvanceWidth = 0; + gfxFloat mAdvanceWidth; // For zero-width substrings, these must be zero! - nscoord mAscent = 0; // always non-negative - nscoord mDescent = 0; // always non-negative + gfxFloat mAscent; // always non-negative + gfxFloat mDescent; // always non-negative // Bounding box that is guaranteed to include everything drawn. // If a tight boundingBox was requested when these metrics were @@ -1681,7 +1684,7 @@ class gfxFont { // "loose" and may be larger than the true bounding box. // Coordinates are relative to the baseline left origin, so typically // mBoundingBox.y == -mAscent - nsRect mBoundingBox; + gfxRect mBoundingBox; }; /** @@ -1957,7 +1960,7 @@ class gfxFont { DrawTarget* aRefDrawTarget, Spacing* aSpacing, gfxGlyphExtents* aExtents, bool aIsRTL, bool aNeedsGlyphExtents, RunMetrics& aMetrics, - nscoord* aAdvanceMin, nscoord* aAdvanceMax); + gfxFloat* aAdvanceMin, gfxFloat* aAdvanceMax); bool MeasureGlyphs(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd, BoundingBoxType aBoundingBoxType, diff --git a/gfx/thebes/gfxGlyphExtents.cpp b/gfx/thebes/gfxGlyphExtents.cpp @@ -35,7 +35,7 @@ gfxGlyphExtents::~gfxGlyphExtents() { bool gfxGlyphExtents::GetTightGlyphExtentsAppUnitsLocked( gfxFont* aFont, DrawTarget* aDrawTarget, uint32_t aGlyphID, - nsRect* aExtents) { + gfxRect* aExtents) { HashEntry* entry = mTightGlyphExtents.GetEntry(aGlyphID); if (!entry) { // Some functions higher up in the call chain deliberately pass in a @@ -64,7 +64,7 @@ bool gfxGlyphExtents::GetTightGlyphExtentsAppUnitsLocked( } } - *aExtents = nsRect(entry->x, entry->y, entry->width, entry->height); + *aExtents = gfxRect(entry->x, entry->y, entry->width, entry->height); return true; } @@ -127,7 +127,7 @@ void gfxGlyphExtents::GlyphWidths::Set(uint32_t aGlyphID, uint16_t aWidth) { } void gfxGlyphExtents::SetTightGlyphExtents(uint32_t aGlyphID, - const nsRect& aExtentsAppUnits) { + const gfxRect& aExtentsAppUnits) { AutoWriteLock lock(mLock); HashEntry* entry = mTightGlyphExtents.PutEntry(aGlyphID); if (!entry) { diff --git a/gfx/thebes/gfxGlyphExtents.h b/gfx/thebes/gfxGlyphExtents.h @@ -77,10 +77,10 @@ class gfxGlyphExtents { // and extents were not (successfully) prefetched. bool GetTightGlyphExtentsAppUnitsLocked(gfxFont* aFont, DrawTarget* aDrawTarget, - uint32_t aGlyphID, nsRect* aExtents) + uint32_t aGlyphID, gfxRect* aExtents) MOZ_REQUIRES_SHARED(mLock); bool GetTightGlyphExtentsAppUnits(gfxFont* aFont, DrawTarget* aDrawTarget, - uint32_t aGlyphID, nsRect* aExtents) { + uint32_t aGlyphID, gfxRect* aExtents) { mozilla::AutoReadLock lock(mLock); return GetTightGlyphExtentsAppUnitsLocked(aFont, aDrawTarget, aGlyphID, aExtents); @@ -90,7 +90,7 @@ class gfxGlyphExtents { mozilla::AutoWriteLock lock(mLock); mContainedGlyphWidths.Set(aGlyphID, aWidth); } - void SetTightGlyphExtents(uint32_t aGlyphID, const nsRect& aExtentsAppUnits); + void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits); int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; } @@ -103,7 +103,7 @@ class gfxGlyphExtents { // When constructing a new entry in the hashtable, we'll leave this // blank. The caller of Put() will fill this in. explicit HashEntry(KeyTypePointer aPtr) - : nsUint32HashKey(aPtr), x(0), y(0), width(0), height(0) {} + : nsUint32HashKey(aPtr), x(0.0), y(0.0), width(0.0), height(0.0) {} HashEntry(HashEntry&& aOther) : nsUint32HashKey(std::move(aOther)), x(aOther.x), @@ -111,7 +111,7 @@ class gfxGlyphExtents { width(aOther.width), height(aOther.height) {} - nscoord x, y, width, height; + float x, y, width, height; }; enum { diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp @@ -29,7 +29,6 @@ #include "mozilla/StaticPresData.h" #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" -#include "nsLayoutUtils.h" #include "nsStyleConsts.h" #include "nsStyleUtil.h" #include "nsUnicodeProperties.h" @@ -330,16 +329,14 @@ gfxTextRun::LigatureData gfxTextRun::ComputeLigatureData( if (aProvider && (mFlags & gfx::ShapedTextFlags::TEXT_ENABLE_SPACING)) { gfxFont::Spacing spacing; if (aPartRange.start == result.mRange.start) { - if (aProvider->GetSpacing(Range(aPartRange.start, aPartRange.start + 1), - &spacing)) { - result.mPartWidth += spacing.mBefore; - } + aProvider->GetSpacing(Range(aPartRange.start, aPartRange.start + 1), + &spacing); + result.mPartWidth += spacing.mBefore; } if (aPartRange.end == result.mRange.end) { - if (aProvider->GetSpacing(Range(aPartRange.end - 1, aPartRange.end), - &spacing)) { - result.mPartWidth += spacing.mAfter; - } + aProvider->GetSpacing(Range(aPartRange.end - 1, aPartRange.end), + &spacing); + result.mPartWidth += spacing.mAfter; } } @@ -361,16 +358,15 @@ int32_t gfxTextRun::GetAdvanceForGlyphs(Range aRange) const { return advance; } -// Returns false if there is definitely no spacing to apply. -static bool GetAdjustedSpacing( +static void GetAdjustedSpacing( const gfxTextRun* aTextRun, gfxTextRun::Range aRange, const gfxTextRun::PropertyProvider& aProvider, gfxTextRun::PropertyProvider::Spacing* aSpacing) { if (aRange.start >= aRange.end) { - return false; + return; } - bool result = aProvider.GetSpacing(aRange, aSpacing); + aProvider.GetSpacing(aRange, aSpacing); #ifdef DEBUG // Check to see if we have spacing inside ligatures @@ -389,8 +385,6 @@ static bool GetAdjustedSpacing( } } #endif - - return result; } bool gfxTextRun::GetAdjustedSpacingArray( @@ -404,11 +398,8 @@ bool gfxTextRun::GetAdjustedSpacingArray( } auto spacingOffset = aSpacingRange.start - aRange.start; memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing) * spacingOffset); - if (!GetAdjustedSpacing(this, aSpacingRange, *aProvider, - aSpacing->Elements() + spacingOffset)) { - aSpacing->Clear(); - return false; - } + GetAdjustedSpacing(this, aSpacingRange, *aProvider, + aSpacing->Elements() + spacingOffset); memset(aSpacing->Elements() + spacingOffset + aSpacingRange.Length(), 0, sizeof(gfxFont::Spacing) * (aRange.end - aSpacingRange.end)); return true; @@ -549,11 +540,12 @@ struct MOZ_STACK_CLASS BufferAlphaColor { ~BufferAlphaColor() = default; - void PushSolidColor(const nsRect& aBounds, const DeviceColor& aAlphaColor, + void PushSolidColor(const gfxRect& aBounds, const DeviceColor& aAlphaColor, uint32_t appsPerDevUnit) { mContext->Save(); - mContext->SnappedClip( - nsLayoutUtils::RectToGfxRect(aBounds, appsPerDevUnit)); + mContext->SnappedClip(gfxRect( + aBounds.X() / appsPerDevUnit, aBounds.Y() / appsPerDevUnit, + aBounds.Width() / appsPerDevUnit, aBounds.Height() / appsPerDevUnit)); mContext->SetDeviceColor( DeviceColor(aAlphaColor.r, aAlphaColor.g, aAlphaColor.b)); mContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, aAlphaColor.a); @@ -672,9 +664,9 @@ void gfxTextRun::Draw(const Range aRange, const gfx::Point aPt, aParams.provider); if (IsRightToLeft()) { metrics.mBoundingBox.MoveBy( - nsPoint(aPt.x - metrics.mAdvanceWidth, aPt.y)); + gfxPoint(aPt.x - metrics.mAdvanceWidth, aPt.y)); } else { - metrics.mBoundingBox.MoveBy(nsPoint(aPt.x, aPt.y)); + metrics.mBoundingBox.MoveBy(gfxPoint(aPt.x, aPt.y)); } gotMetrics = true; } @@ -1235,16 +1227,15 @@ gfxFloat gfxTextRun::GetAdvanceWidth( uint32_t i; AutoTArray<PropertyProvider::Spacing, 200> spacingBuffer; if (spacingBuffer.AppendElements(aRange.Length(), fallible)) { - if (GetAdjustedSpacing(this, ligatureRange, *aProvider, - spacingBuffer.Elements())) { - for (i = 0; i < ligatureRange.Length(); ++i) { - PropertyProvider::Spacing* space = &spacingBuffer[i]; - result += space->mBefore + space->mAfter; - } - if (aSpacing) { - aSpacing->mBefore = spacingBuffer[0].mBefore; - aSpacing->mAfter = spacingBuffer.LastElement().mAfter; - } + GetAdjustedSpacing(this, ligatureRange, *aProvider, + spacingBuffer.Elements()); + for (i = 0; i < ligatureRange.Length(); ++i) { + PropertyProvider::Spacing* space = &spacingBuffer[i]; + result += space->mBefore + space->mAfter; + } + if (aSpacing) { + aSpacing->mBefore = spacingBuffer[0].mBefore; + aSpacing->mAfter = spacingBuffer.LastElement().mAfter; } } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h @@ -230,7 +230,7 @@ class gfxTextRun : public gfxShapedText { // Returns the extra width that will be consumed by a hyphen. This should // be constant for a given textrun. - virtual nscoord GetHyphenWidth() const = 0; + virtual gfxFloat GetHyphenWidth() const = 0; // Return orientation flags to be used when creating a hyphen textrun. virtual mozilla::gfx::ShapedTextFlags GetShapedTextFlags() const = 0; @@ -242,10 +242,8 @@ class gfxTextRun : public gfxShapedText { * inside clusters. In other words, if character i is not * CLUSTER_START, then character i-1 must have zero after-spacing and * character i must have zero before-spacing. - * Returns true if there is (or may be) any custom spacing; false if we - * are sure that aSpacing contains only zero values. */ - virtual bool GetSpacing(Range aRange, Spacing* aSpacing) const = 0; + virtual void GetSpacing(Range aRange, Spacing* aSpacing) const = 0; // Returns a gfxContext that can be used to measure the hyphen glyph. // Only called if the hyphen width is requested. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp @@ -272,11 +272,11 @@ TextAutospace::BoundarySet TextAutospace::InitBoundarySet( } // namespace mozilla struct TabWidth { - TabWidth(uint32_t aOffset, nscoord aWidth) - : mOffset(aOffset), mWidth(aWidth) {} + TabWidth(uint32_t aOffset, uint32_t aWidth) + : mOffset(aOffset), mWidth(float(aWidth)) {} uint32_t mOffset; // DOM offset relative to the current frame's offset. - nscoord mWidth; // extra space to be added at this position (in app units) + float mWidth; // extra space to be added at this position (in app units) }; struct nsTextFrame::TabWidthStore { @@ -3464,7 +3464,7 @@ nsTextFrame::PropertyProvider::PropertyProvider( mLength(aLength), mWordSpacing(WordSpacing(aFrame, *aTextStyle)), mLetterSpacing(LetterSpacing(aFrame, *aTextStyle)), - mMinTabAdvance(-1), + mMinTabAdvance(-1.0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs), mJustificationArrayStart(0), @@ -3494,7 +3494,7 @@ nsTextFrame::PropertyProvider::PropertyProvider( mLength(aFrame->GetContentLength()), mWordSpacing(WordSpacing(aFrame, *mTextStyle)), mLetterSpacing(LetterSpacing(aFrame, *mTextStyle)), - mMinTabAdvance(-1), + mMinTabAdvance(-1.0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(0), mJustificationArrayStart(0), @@ -3514,7 +3514,7 @@ already_AddRefed<DrawTarget> nsTextFrame::PropertyProvider::GetDrawTarget() } gfxFloat nsTextFrame::PropertyProvider::MinTabAdvance() const { - if (mMinTabAdvance < 0) { + if (mMinTabAdvance < 0.0) { mMinTabAdvance = GetMinTabAdvanceAppUnits(mTextRun); } return mMinTabAdvance; @@ -3815,11 +3815,10 @@ JustificationInfo nsTextFrame::PropertyProvider::ComputeJustification( return info; } -// aStart, aLength in transformed string offsets. -// Returns false if no non-standard spacing was required. -bool nsTextFrame::PropertyProvider::GetSpacing(Range aRange, +// aStart, aLength in transformed string offsets +void nsTextFrame::PropertyProvider::GetSpacing(Range aRange, Spacing* aSpacing) const { - return GetSpacingInternal( + GetSpacingInternal( aRange, aSpacing, !(mTextRun->GetFlags2() & nsTextFrameUtils::Flags::HasTab)); } @@ -3863,7 +3862,7 @@ static gfxFloat ComputeTabWidthAppUnits(const nsIFrame* aFrame) { MOZ_ASSERT(tabSize.IsNumber()); gfxFloat spaces = tabSize.number._0; - MOZ_ASSERT(spaces >= 0.0); + MOZ_ASSERT(spaces >= 0); const nsIFrame* cb = aFrame->GetContainingBlock(0, aFrame->StyleDisplay()); const auto* styleText = cb->StyleText(); @@ -3879,8 +3878,8 @@ static gfxFloat ComputeTabWidthAppUnits(const nsIFrame* aFrame) { RefPtr font = fm->GetThebesFontGroup()->GetFirstValidFont(' '); auto metrics = font->GetMetrics(vertical ? nsFontMetrics::eVertical : nsFontMetrics::eHorizontal); - nscoord spaceWidth = NSToCoordRound(metrics.spaceWidth * - cb->PresContext()->AppUnitsPerDevPixel()); + nscoord spaceWidth = nscoord( + NS_round(metrics.spaceWidth * cb->PresContext()->AppUnitsPerDevPixel())); return spaces * (spaceWidth + styleText->mLetterSpacing.Resolve(fm->EmHeight()) + styleText->mWordSpacing.Resolve(spaceWidth)); @@ -4067,7 +4066,7 @@ static bool HasCJKGlyphRun(const gfxTextRun* aTextRun) { return false; } -bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, +void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs) const { MOZ_ASSERT(IsInBounds(mStart, mLength, aRange), "Range out of bounds"); @@ -4075,14 +4074,9 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, std::memset(aSpacing, 0, aRange.Length() * sizeof(*aSpacing)); if (mFrame->Style()->IsTextCombined()) { - return false; + return; } - // Track whether any non-standard spacing is actually present in this range. - // If letter-spacing is non-zero this will always be true, but for the - /// word-spacing and text-autospace cases it will depend on the actual text. - bool spacingPresent = mLetterSpacing; - // First, compute the word spacing, letter spacing, and text-autospace // spacing. if (mWordSpacing || mLetterSpacing || mTextAutospace) { @@ -4091,24 +4085,24 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, // 0 - Gecko legacy model, spacing added to trailing side of letter // 1 - WebKit/Blink-compatible, spacing added to right-hand side // 2 - Symmetrical spacing, half added to each side - nscoord before, after; + gfxFloat before, after; switch (StaticPrefs::layout_css_letter_spacing_model()) { default: // use Gecko legacy behavior if pref value is unknown case 0: - before = 0; + before = 0.0; after = mLetterSpacing; break; case 1: if (mTextRun->IsRightToLeft()) { before = mLetterSpacing; - after = 0; + after = 0.0; } else { - before = 0; + before = 0.0; after = mLetterSpacing; } break; case 2: - before = NSToCoordRound(mLetterSpacing * 0.5); + before = mLetterSpacing / 2.0; after = mLetterSpacing - before; break; } @@ -4170,12 +4164,12 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start; gfxSkipCharsIterator iter = run.GetPos(); for (int32_t i = 0; i < run.GetRunLength(); ++i) { - if (!atStart && before != 0 && + if (!atStart && before != 0.0 && CanAddSpacingBefore(mTextRun, run.GetSkippedOffset() + i, newlineIsSignificant)) { aSpacing[runOffsetInSubstring + i].mBefore += before; } - if (after != 0 && + if (after != 0.0 && CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i, newlineIsSignificant)) { // End of a cluster, not in a ligature: put letter-spacing after it @@ -4191,7 +4185,6 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, &iter); uint32_t runOffset = iter.GetSkippedOffset() - aRange.start; aSpacing[runOffset].mAfter += mWordSpacing; - spacingPresent = true; } // Add text-autospace spacing only at cluster starts. Always check the // character classes if the textrun includes CJK; otherwise, check only @@ -4216,7 +4209,6 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, prevClass.valueOrFrom(findPrecedingClass), currClass)) { aSpacing[runOffsetInSubstring + i].mBefore += mTextAutospace->InterScriptSpacing(); - spacingPresent = true; } // Even if we didn't actually need to check spacing rules here, we // record the new prevClass. (Incidentally, this ensure that we'll @@ -4238,7 +4230,6 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, mTabWidths->ApplySpacing(aSpacing, aRange.start - mStart.GetSkippedOffset(), aRange.Length()); - spacingPresent = true; } } } @@ -4259,20 +4250,16 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, aSpacing[offset].mBefore += spacing.mBefore; aSpacing[offset].mAfter += spacing.mAfter; } - spacingPresent = true; } - - return spacingPresent; } // aX and the result are in whole appunits. -static nscoord AdvanceToNextTab(nscoord aX, gfxFloat aTabWidth, - gfxFloat aMinAdvance) { +static gfxFloat AdvanceToNextTab(gfxFloat aX, gfxFloat aTabWidth, + gfxFloat aMinAdvance) { // Advance aX to the next multiple of aTabWidth. We must advance // by at least aMinAdvance. gfxFloat nextPos = aX + aMinAdvance; - return NSToCoordRound(aTabWidth > 0 ? ceil(nextPos / aTabWidth) * aTabWidth - : nextPos); + return aTabWidth > 0.0 ? ceil(nextPos / aTabWidth) * aTabWidth : nextPos; } void nsTextFrame::PropertyProvider::CalcTabWidths(Range aRange, @@ -4333,10 +4320,11 @@ void nsTextFrame::PropertyProvider::CalcTabWidths(Range aRange, mTabWidths = new TabWidthStore(mFrame->GetContentOffset()); mFrame->SetProperty(TabWidthProperty(), mTabWidths); } - nscoord nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs, - aTabWidth, MinTabAdvance()); + double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs, + aTabWidth, MinTabAdvance()); mTabWidths->mWidths.AppendElement( - TabWidth(i - startOffset, nextTab - mOffsetFromBlockOriginForTabs)); + TabWidth(i - startOffset, + NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs))); mOffsetFromBlockOriginForTabs = nextTab; } @@ -4356,7 +4344,7 @@ void nsTextFrame::PropertyProvider::CalcTabWidths(Range aRange, } } -nscoord nsTextFrame::PropertyProvider::GetHyphenWidth() const { +gfxFloat nsTextFrame::PropertyProvider::GetHyphenWidth() const { if (mHyphenWidth < 0) { const auto& hyphenateChar = mTextStyle->mHyphenateCharacter; if (hyphenateChar.IsAuto()) { @@ -6567,8 +6555,7 @@ static void AddHyphenToMetrics(nsTextFrame* aTextFrame, bool aIsRightToLeft, void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams, const StyleSimpleShadow& aShadowDetails, - const gfxRect& aBoundingBox, - uint32_t aBlurFlags) { + gfxRect& aBoundingBox, uint32_t aBlurFlags) { AUTO_PROFILER_LABEL("nsTextFrame::PaintOneShadow", GRAPHICS); nsPoint shadowOffset(aShadowDetails.horizontal.ToAppUnits(), @@ -7372,8 +7359,8 @@ void nsTextFrame::PaintShadows(Span<const StyleSimpleShadow> aShadows, aParams.context->GetDrawTarget()); } // Add bounds of text decorations - nsRect decorationRect(0, -shadowMetrics.mAscent, shadowMetrics.mAdvanceWidth, - shadowMetrics.mAscent + shadowMetrics.mDescent); + gfxRect decorationRect(0, -shadowMetrics.mAscent, shadowMetrics.mAdvanceWidth, + shadowMetrics.mAscent + shadowMetrics.mDescent); shadowMetrics.mBoundingBox.UnionRect(shadowMetrics.mBoundingBox, decorationRect); @@ -7397,12 +7384,7 @@ void nsTextFrame::PaintShadows(Span<const StyleSimpleShadow> aShadows, } for (const auto& shadow : Reversed(aShadows)) { - PaintOneShadow( - aParams, shadow, - gfxRect(shadowMetrics.mBoundingBox.x, shadowMetrics.mBoundingBox.y, - shadowMetrics.mBoundingBox.width, - shadowMetrics.mBoundingBox.height), - blurFlags); + PaintOneShadow(aParams, shadow, shadowMetrics.mBoundingBox, blurFlags); } } @@ -9550,7 +9532,7 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext, aData->ForceBreak(); } else if (i < flowEndInTextRun && hyphenating && gfxTextRun::IsOptionalHyphenBreak(hyphBuffer[i - start])) { - aData->OptionallyBreak(provider.GetHyphenWidth()); + aData->OptionallyBreak(NSToCoordRound(provider.GetHyphenWidth())); } else { aData->OptionallyBreak(); } @@ -9877,6 +9859,15 @@ nsIFrame::SizeComputationResult nsTextFrame::ComputeSize( AspectRatioUsage::None}; } +static nsRect RoundOut(const gfxRect& aRect) { + nsRect r; + r.x = NSToCoordFloor(aRect.X()); + r.y = NSToCoordFloor(aRect.Y()); + r.width = NSToCoordCeil(aRect.XMost()) - r.x; + r.height = NSToCoordCeil(aRect.YMost()) - r.y; + return r; +} + nsRect nsTextFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const { if (Style()->HasTextDecorationLines() || HasAnyStateBits(TEXT_HYPHEN_BREAK)) { // This is conservative, but OK. @@ -9902,7 +9893,7 @@ nsRect nsTextFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const { } // 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 = metrics.mBoundingBox; + nsRect boundingBox = RoundOut(metrics.mBoundingBox); boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. @@ -9927,8 +9918,8 @@ nsresult nsTextFrame::GetPrefWidthTightBounds(gfxContext* aContext, nscoord* aX, ComputeTransformedRange(provider), gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aContext->GetDrawTarget(), &provider); // Round it like nsTextFrame::ComputeTightBounds() to ensure consistency. - *aX = metrics.mBoundingBox.x; - *aXMost = metrics.mBoundingBox.XMost(); + *aX = NSToCoordFloor(metrics.mBoundingBox.x); + *aXMost = NSToCoordCeil(metrics.mBoundingBox.XMost()); return NS_OK; } @@ -10681,15 +10672,18 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, // first-letter frames should use the tight bounding box metrics for // ascent/descent for good drop-cap effects if (HasAnyStateBits(TEXT_FIRST_LETTER)) { - textMetrics.mAscent = std::max(0, -textMetrics.mBoundingBox.Y()); - textMetrics.mDescent = std::max(0, textMetrics.mBoundingBox.YMost()); + textMetrics.mAscent = + std::max(gfxFloat(0.0), -textMetrics.mBoundingBox.Y()); + textMetrics.mDescent = + std::max(gfxFloat(0.0), textMetrics.mBoundingBox.YMost()); } // Setup metrics for caller // Disallow negative widths WritingMode wm = GetWritingMode(); LogicalSize finalSize(wm); - finalSize.ISize(wm) = std::max(0, textMetrics.mAdvanceWidth); + finalSize.ISize(wm) = + NSToCoordCeilClamped(std::max(gfxFloat(0.0), textMetrics.mAdvanceWidth)); nscoord fontBaseline; // Note(dshin): Baseline should tecnhically be halfway through the em box for @@ -10700,8 +10694,8 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, finalSize.BSize(wm) = 0; fontBaseline = 0; } else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) { - fontBaseline = textMetrics.mAscent; - const auto size = fontBaseline + textMetrics.mDescent; + fontBaseline = NSToCoordCeil(textMetrics.mAscent); + const auto size = fontBaseline + NSToCoordCeil(textMetrics.mDescent); // Use actual text metrics for floating first letter frame. aMetrics.SetBlockStartAscent(wm.IsAlphabeticalBaseline() ? fontBaseline : size / 2); @@ -10715,9 +10709,10 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, wm.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent(); nscoord fontDescent = wm.IsLineInverted() ? fm->MaxAscent() : fm->MaxDescent(); - fontBaseline = std::max(textMetrics.mAscent, fontAscent); + fontBaseline = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent); const auto size = - fontBaseline + std::max(textMetrics.mDescent, fontDescent); + fontBaseline + + std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent); aMetrics.SetBlockStartAscent(wm.IsAlphabeticalBaseline() ? fontBaseline : size / 2); finalSize.BSize(wm) = size; @@ -10813,7 +10808,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, mAscent = fontBaseline; // Handle text that runs outside its normal bounds. - nsRect boundingBox = textMetrics.mBoundingBox; + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. std::swap(boundingBox.x, boundingBox.y); @@ -11071,7 +11066,7 @@ OverflowAreas nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame, if (GetWritingMode().IsLineInverted()) { textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost(); } - nsRect boundingBox = textMetrics.mBoundingBox; + nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); boundingBox += nsPoint(0, mAscent); if (mTextRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h @@ -160,8 +160,8 @@ class nsTextFrame : public nsIFrame { void InitializeForMeasure(); - bool GetSpacing(Range aRange, Spacing* aSpacing) const final; - nscoord GetHyphenWidth() const final; + void GetSpacing(Range aRange, Spacing* aSpacing) const final; + gfxFloat GetHyphenWidth() const final; void GetHyphenationBreaks(Range aRange, HyphenType* aBreakBefore) const final; mozilla::StyleHyphens GetHyphensOption() const final { @@ -175,7 +175,7 @@ class nsTextFrame : public nsIFrame { return mTextRun->GetAppUnitsPerDevUnit(); } - bool GetSpacingInternal(Range aRange, Spacing* aSpacing, + void GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs) const; /** @@ -259,10 +259,10 @@ class nsTextFrame : public nsIFrame { int32_t mLength; // space for each whitespace char - const nscoord mWordSpacing; + const gfxFloat mWordSpacing; // space for each letter - const nscoord mLetterSpacing; + const gfxFloat mLetterSpacing; // If TextAutospace exists, inter-script spacing applies. Maybe<mozilla::TextAutospace> mTextAutospace; @@ -270,8 +270,8 @@ class nsTextFrame : public nsIFrame { // min advance for <tab> char mutable gfxFloat mMinTabAdvance; - mutable nscoord mHyphenWidth; - mutable nscoord mOffsetFromBlockOriginForTabs; + mutable gfxFloat mHyphenWidth; + mutable gfxFloat mOffsetFromBlockOriginForTabs; // The values in mJustificationSpacings corresponds to unskipped // characters start from mJustificationArrayStart. @@ -937,7 +937,7 @@ class nsTextFrame : public nsIFrame { void PaintOneShadow(const PaintShadowParams& aParams, const mozilla::StyleSimpleShadow& aShadowDetails, - const gfxRect& aBoundingBox, uint32_t aBlurFlags); + gfxRect& aBoundingBox, uint32_t aBlurFlags); void PaintShadows(mozilla::Span<const mozilla::StyleSimpleShadow>, const PaintShadowParams& aParams); diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp @@ -885,11 +885,11 @@ static nsBoundingMetrics MeasureTextRun(DrawTarget* aDrawTarget, aTextRun->MeasureText(gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aDrawTarget); nsBoundingMetrics bm; - bm.leftBearing = metrics.mBoundingBox.X(); - bm.rightBearing = metrics.mBoundingBox.XMost(); - bm.ascent = -metrics.mBoundingBox.Y(); - bm.descent = metrics.mBoundingBox.YMost(); - bm.width = metrics.mAdvanceWidth; + bm.leftBearing = NSToCoordFloor(metrics.mBoundingBox.X()); + bm.rightBearing = NSToCoordCeil(metrics.mBoundingBox.XMost()); + bm.ascent = NSToCoordCeil(-metrics.mBoundingBox.Y()); + bm.descent = NSToCoordCeil(metrics.mBoundingBox.YMost()); + bm.width = NSToCoordRound(metrics.mAdvanceWidth); return bm; } diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp @@ -850,18 +850,19 @@ SVGBBox TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, gfxTextRun::Metrics metrics = textRun->MeasureText( range, gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); // Make sure it includes the font-box. - nsRect fontBox(0, -metrics.mAscent, metrics.mAdvanceWidth, - metrics.mAscent + metrics.mDescent); + gfxRect fontBox(0, -metrics.mAscent, metrics.mAdvanceWidth, + metrics.mAscent + metrics.mDescent); metrics.mBoundingBox.UnionRect(metrics.mBoundingBox, fontBox); // Determine the rectangle that covers the rendered run's fill, // taking into account the measured overflow due to decorations. - nscoord baseline = metrics.mBoundingBox.y + metrics.mAscent; - nscoord x, width; + nscoord baseline = + NSToCoordRoundWithClamp(metrics.mBoundingBox.y + metrics.mAscent); + gfxFloat x, width; if (aFlags & eNoHorizontalOverflow) { - x = 0; + x = 0.0; width = textRun->GetAdvanceWidth(range, &provider); - if (width < 0) { + if (width < 0.0) { x = width; width = -width; } @@ -869,7 +870,9 @@ SVGBBox TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, x = metrics.mBoundingBox.x; width = metrics.mBoundingBox.width; } - nsRect fillInAppUnits(x, baseline, width, metrics.mBoundingBox.height); + nsRect fillInAppUnits(NSToCoordRoundWithClamp(x), baseline, + NSToCoordRoundWithClamp(width), + NSToCoordRoundWithClamp(metrics.mBoundingBox.height)); fillInAppUnits.Inflate(inkOverflow); if (textRun->IsVertical()) { // Swap line-relative textMetrics dimensions to physical coordinates. diff --git a/testing/web-platform/meta/css/css-writing-modes/text-combine-upright-gen-con-001.html.ini b/testing/web-platform/meta/css/css-writing-modes/text-combine-upright-gen-con-001.html.ini @@ -2,6 +2,5 @@ fuzzy: if os == "linux": maxDifference=0-255;totalPixels=0-60 if os == "android": maxDifference=0-92;totalPixels=0-93 - if os == "win": maxDifference=0-70;totalPixels=0-67 expected: PASS diff --git a/testing/web-platform/mozilla/meta/mathml/tables/dir-6a.html.ini b/testing/web-platform/mozilla/meta/mathml/tables/dir-6a.html.ini @@ -1,4 +1,3 @@ [dir-6a.html] fuzzy: if (os == "mac"): maxDifference=0-135;totalPixels=0-56 - if (os == "win"): maxDifference=0-92;totalPixels=0-41