commit c63cc708e0dd1076c9d9de8ac4138841ca6cae78 parent bcb5d139ef65192084cfb932688a875e47cd91e7 Author: Jonathan Kew <jkew@mozilla.com> Date: Mon, 3 Nov 2025 21:07:42 +0000 Bug 1996403 - Revert changesets 08b700ae5349, 9a06ba9c63f8, and 713d9f3a5771 (bug 1994197 patches 2-4) to restore previous text-measurement behavior and performance. r=firefox-svg-reviewers,longsonr Differential Revision: https://phabricator.services.mozilla.com/D270323 Diffstat:
20 files changed, 206 insertions(+), 208 deletions(-)
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4647,10 +4647,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final // asymmetry seems unfortunate. if (mProcessor.mTextRun->IsRightToLeft()) { aSpacing->mAfter = 0; - aSpacing->mBefore = mProcessor.mLetterSpacing; + aSpacing->mBefore = NSToCoordRound(mProcessor.mLetterSpacing); } else { aSpacing->mBefore = 0; - aSpacing->mAfter = mProcessor.mLetterSpacing; + aSpacing->mAfter = NSToCoordRound(mProcessor.mLetterSpacing); } } else { aSpacing->mBefore = 0; @@ -4658,14 +4658,14 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final } if (charGlyphs[i].CharIsSpace()) { if (mProcessor.mTextRun->IsRightToLeft()) { - aSpacing->mBefore += mProcessor.mWordSpacing; + aSpacing->mBefore += NSToCoordRound(mProcessor.mWordSpacing); } else { - aSpacing->mAfter += mProcessor.mWordSpacing; + aSpacing->mAfter += NSToCoordRound(mProcessor.mWordSpacing); } } aSpacing++; } - return mProcessor.mLetterSpacing != 0 || mProcessor.mWordSpacing != 0; + return mProcessor.mLetterSpacing != 0.0 || mProcessor.mWordSpacing != 0.0; } mozilla::StyleHyphens GetHyphensOption() const { @@ -4677,9 +4677,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 +4736,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 +4936,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 +5104,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 +5232,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 +5285,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; } @@ -312,7 +312,8 @@ nscoord nsFontMetrics::GetWidth(const char* aString, uint32_t aLength, StubPropertyProvider provider; AutoTextRun textRun(this, aDrawTarget, aString, aLength); if (textRun.get()) { - return textRun->GetAdvanceWidth(gfxTextRun::Range(0, aLength), &provider); + return NSToCoordRound( + textRun->GetAdvanceWidth(gfxTextRun::Range(0, aLength), &provider)); } return 0; } @@ -328,7 +329,8 @@ nscoord nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength, StubPropertyProvider provider; AutoTextRun textRun(this, aDrawTarget, aString, aLength); if (textRun.get()) { - return textRun->GetAdvanceWidth(gfxTextRun::Range(0, aLength), &provider); + return NSToCoordRound( + textRun->GetAdvanceWidth(gfxTextRun::Range(0, aLength), &provider)); } return 0; } @@ -399,11 +401,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 @@ -31,7 +31,6 @@ #include "gfxUserFontSet.h" #include "nsCRT.h" #include "nsContentUtils.h" -#include "nsLayoutUtils.h" #include "nsSpecialCasingData.h" #include "nsTextRunTransformations.h" #include "nsUGenCategory.h" @@ -962,13 +961,13 @@ 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 = NSCoordSaturatingAdd(mAdvanceWidth, aOther.mAdvanceWidth); + mAdvanceWidth += aOther.mAdvanceWidth; } gfxFont::gfxFont(const RefPtr<UnscaledFont>& aUnscaledFont, @@ -2874,7 +2873,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); } @@ -2895,7 +2894,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() @@ -2911,7 +2910,7 @@ 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(); uint32_t spaceGlyph = GetSpaceGlyph(); @@ -2935,7 +2934,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() @@ -2958,11 +2957,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 @@ -2985,15 +2984,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 @@ -3054,9 +3053,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. @@ -3124,7 +3123,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 @@ -3136,25 +3135,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 = @@ -3179,8 +3176,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); } @@ -3211,10 +3208,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) { @@ -4114,27 +4110,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; } @@ -4147,8 +4132,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; } } @@ -4158,6 +4145,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 = @@ -4174,8 +4162,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 @@ -1657,22 +1657,23 @@ class gfxFont { nscoord mBefore; nscoord 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 @@ -1680,7 +1681,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; }; /** @@ -1956,7 +1957,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 @@ -281,7 +281,7 @@ gfxTextRun::LigatureData gfxTextRun::ComputeLigatureData( } result.mRange.end = i; - nscoord ligatureWidth = GetAdvanceForGlyphs(result.mRange); + int32_t ligatureWidth = GetAdvanceForGlyphs(result.mRange); // Count the number of started clusters we have seen uint32_t totalClusterCount = 0; uint32_t partClusterIndex = 0; @@ -307,7 +307,7 @@ gfxTextRun::LigatureData gfxTextRun::ComputeLigatureData( // so that measuring all parts of a ligature and summing them is equal to // the ligature width. if (aPartRange.end == result.mRange.end) { - nscoord allParts = totalClusterCount * (ligatureWidth / totalClusterCount); + gfxFloat allParts = totalClusterCount * (ligatureWidth / totalClusterCount); result.mPartWidth += ligatureWidth - allParts; } @@ -331,15 +331,13 @@ gfxTextRun::LigatureData gfxTextRun::ComputeLigatureData( if (aPartRange.start == result.mRange.start) { if (aProvider->GetSpacing(Range(aPartRange.start, aPartRange.start + 1), &spacing)) { - result.mPartWidth = - NSCoordSaturatingAdd(result.mPartWidth, spacing.mBefore); + result.mPartWidth += spacing.mBefore; } } if (aPartRange.end == result.mRange.end) { if (aProvider->GetSpacing(Range(aPartRange.end - 1, aPartRange.end), &spacing)) { - result.mPartWidth = - NSCoordSaturatingAdd(result.mPartWidth, spacing.mAfter); + result.mPartWidth += spacing.mAfter; } } } @@ -347,19 +345,17 @@ gfxTextRun::LigatureData gfxTextRun::ComputeLigatureData( return result; } -nscoord gfxTextRun::ComputePartialLigatureWidth( +gfxFloat gfxTextRun::ComputePartialLigatureWidth( Range aPartRange, const PropertyProvider* aProvider) const { - if (aPartRange.start >= aPartRange.end) { - return 0; - } + if (aPartRange.start >= aPartRange.end) return 0; LigatureData data = ComputeLigatureData(aPartRange, aProvider); return data.mPartWidth; } -nscoord gfxTextRun::GetAdvanceForGlyphs(Range aRange) const { - nscoord advance = 0; +int32_t gfxTextRun::GetAdvanceForGlyphs(Range aRange) const { + int32_t advance = 0; for (auto i = aRange.start; i < aRange.end; ++i) { - advance = NSCoordSaturatingAdd(advance, GetAdvanceForGlyph(i)); + advance += GetAdvanceForGlyph(i); } return advance; } @@ -552,11 +548,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); @@ -675,9 +672,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; } @@ -978,19 +975,19 @@ uint32_t gfxTextRun::BreakAndMeasureText( } } - nscoord width = 0; - nscoord advance = 0; + gfxFloat width = 0; + gfxFloat advance = 0; // The number of space characters that can be trimmed or hang at a soft-wrap uint32_t trimmableChars = 0; // The amount of space removed by ignoring trimmableChars - nscoord trimmableAdvance = 0; + gfxFloat trimmableAdvance = 0; int32_t lastBreak = -1; int32_t lastBreakTrimmableChars = -1; - nscoord lastBreakTrimmableAdvance = -1; + gfxFloat lastBreakTrimmableAdvance = -1; // Cache the last candidate break int32_t lastCandidateBreak = -1; int32_t lastCandidateBreakTrimmableChars = -1; - nscoord lastCandidateBreakTrimmableAdvance = -1; + gfxFloat lastCandidateBreakTrimmableAdvance = -1; bool lastCandidateBreakUsedHyphenation = false; gfxBreakPriority lastCandidateBreakPriority = gfxBreakPriority::eNoBreak; bool aborted = false; @@ -1102,7 +1099,7 @@ uint32_t gfxTextRun::BreakAndMeasureText( : gfxBreakPriority::eWordWrapBreak; } - width = NSCoordSaturatingAdd(width, advance); + width += advance; advance = 0; if (width - trimmableAdvance > aWidth) { // No more text fits. Abort @@ -1138,24 +1135,23 @@ uint32_t gfxTextRun::BreakAndMeasureText( continue; } - nscoord charAdvance; + gfxFloat charAdvance; if (i >= ligatureRange.start && i < ligatureRange.end) { charAdvance = GetAdvanceForGlyphs(Range(i, i + 1)); if (haveSpacing) { PropertyProvider::Spacing* space = &spacingBuffer[i - bufferRange.start]; - charAdvance = - NSCoordSaturatingAdd(charAdvance, space->mBefore + space->mAfter); + charAdvance += space->mBefore + space->mAfter; } } else { charAdvance = ComputePartialLigatureWidth(Range(i, i + 1), &aProvider); } - advance = NSCoordSaturatingAdd(advance, charAdvance); + advance += charAdvance; if (aOutTrimmableWhitespace) { if (mCharacterGlyphs[i].CharIsSpace()) { ++trimmableChars; - trimmableAdvance = NSCoordSaturatingAdd(trimmableAdvance, charAdvance); + trimmableAdvance += charAdvance; } else { trimmableAdvance = 0; trimmableChars = 0; @@ -1164,7 +1160,7 @@ uint32_t gfxTextRun::BreakAndMeasureText( } if (!aborted) { - width = NSCoordSaturatingAdd(width, advance); + width += advance; } // There are three possibilities: @@ -1214,20 +1210,20 @@ uint32_t gfxTextRun::BreakAndMeasureText( return charsFit; } -nscoord gfxTextRun::GetAdvanceWidth(Range aRange, - const PropertyProvider* aProvider, - PropertyProvider::Spacing* aSpacing) const { +gfxFloat gfxTextRun::GetAdvanceWidth( + Range aRange, const PropertyProvider* aProvider, + PropertyProvider::Spacing* aSpacing) const { NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range"); Range ligatureRange = aRange; bool adjusted = ShrinkToLigatureBoundaries(&ligatureRange); - nscoord result = + gfxFloat result = adjusted ? ComputePartialLigatureWidth( Range(aRange.start, ligatureRange.start), aProvider) + ComputePartialLigatureWidth( Range(ligatureRange.end, aRange.end), aProvider) - : 0; + : 0.0; if (aSpacing) { aSpacing->mBefore = aSpacing->mAfter = 0; @@ -1243,7 +1239,7 @@ nscoord gfxTextRun::GetAdvanceWidth(Range aRange, spacingBuffer.Elements())) { for (i = 0; i < ligatureRange.Length(); ++i) { PropertyProvider::Spacing* space = &spacingBuffer[i]; - result = NSCoordSaturatingAdd(result, space->mBefore + space->mAfter); + result += space->mBefore + space->mAfter; } if (aSpacing) { aSpacing->mBefore = spacingBuffer[0].mBefore; @@ -1253,34 +1249,33 @@ nscoord gfxTextRun::GetAdvanceWidth(Range aRange, } } - return NSCoordSaturatingAdd(result, GetAdvanceForGlyphs(ligatureRange)); + return result + GetAdvanceForGlyphs(ligatureRange); } -nscoord gfxTextRun::GetMinAdvanceWidth(Range aRange) { +gfxFloat gfxTextRun::GetMinAdvanceWidth(Range aRange) { MOZ_ASSERT(aRange.end <= GetLength(), "Substring out of range"); Range ligatureRange = aRange; bool adjusted = ShrinkToLigatureBoundaries(&ligatureRange); - nscoord result = + gfxFloat result = adjusted ? std::max(ComputePartialLigatureWidth( Range(aRange.start, ligatureRange.start), nullptr), ComputePartialLigatureWidth( Range(ligatureRange.end, aRange.end), nullptr)) - : 0; + : 0.0; // Compute min advance width by assuming each grapheme cluster takes its own // line. - nscoord clusterAdvance = 0; + gfxFloat clusterAdvance = 0; for (uint32_t i = ligatureRange.start; i < ligatureRange.end; ++i) { if (mCharacterGlyphs[i].CharIsSpace()) { // Skip space char to prevent its advance width contributing to the // result. That is, don't consider a space can be in its own line. continue; } - clusterAdvance = - NSCoordSaturatingAdd(clusterAdvance, GetAdvanceForGlyph(i)); + clusterAdvance += GetAdvanceForGlyph(i); if (i + 1 == ligatureRange.end || IsClusterStart(i + 1)) { result = std::max(result, clusterAdvance); clusterAdvance = 0; 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; @@ -338,10 +338,10 @@ class gfxTextRun : public gfxShapedText { * the substring would be returned in it. NOTE: the spacing is * included in the advance width. */ - nscoord GetAdvanceWidth(Range aRange, const PropertyProvider* aProvider, - PropertyProvider::Spacing* aSpacing = nullptr) const; + gfxFloat GetAdvanceWidth(Range aRange, const PropertyProvider* aProvider, + PropertyProvider::Spacing* aSpacing = nullptr) const; - nscoord GetAdvanceWidth() const { + gfxFloat GetAdvanceWidth() const { return GetAdvanceWidth(Range(this), nullptr); } @@ -349,7 +349,7 @@ class gfxTextRun : public gfxShapedText { * Computes the minimum advance width for a substring assuming line * breaking is allowed everywhere. */ - nscoord GetMinAdvanceWidth(Range aRange); + gfxFloat GetMinAdvanceWidth(Range aRange); /** * Clear all stored line breaks for the given range (both before and after), @@ -724,11 +724,11 @@ class gfxTextRun : public gfxShapedText { Range mRange; // appunits advance to the start of the ligature part within the ligature; // never includes any spacing - nscoord mPartAdvance; + gfxFloat mPartAdvance; // appunits width of the ligature part; includes before-spacing // when the part is at the start of the ligature, and after-spacing // when the part is as the end of the ligature - nscoord mPartWidth; + gfxFloat mPartWidth; bool mClipBeforePart; bool mClipAfterPart; @@ -822,7 +822,7 @@ class gfxTextRun : public gfxShapedText { // **** general helpers **** // Get the total advance for a range of glyphs. - nscoord GetAdvanceForGlyphs(Range aRange) const; + int32_t GetAdvanceForGlyphs(Range aRange) const; // Spacing for characters outside the range aSpacingStart/aSpacingEnd // is assumed to be zero; such characters are not passed to aProvider. @@ -844,8 +844,8 @@ class gfxTextRun : public gfxShapedText { // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero LigatureData ComputeLigatureData(Range aPartRange, const PropertyProvider* aProvider) const; - nscoord ComputePartialLigatureWidth(Range aPartRange, - const PropertyProvider* aProvider) const; + gfxFloat ComputePartialLigatureWidth(Range aPartRange, + const PropertyProvider* aProvider) const; void DrawPartialLigature(gfxFont* aFont, Range aRange, mozilla::gfx::Point* aPt, const PropertyProvider* aProvider, @@ -856,6 +856,9 @@ class gfxTextRun : public gfxShapedText { // aRange->start == aRange->end. // Returns whether any adjustment was made. bool ShrinkToLigatureBoundaries(Range* aRange) const; + // result in appunits + gfxFloat GetPartialLigatureWidth(Range aRange, + const PropertyProvider* aProvider) const; void AccumulatePartialLigatureMetrics( gfxFont* aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, const PropertyProvider* aProvider, diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp @@ -271,11 +271,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 { @@ -3463,7 +3463,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), @@ -3493,7 +3493,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), @@ -3513,7 +3513,7 @@ already_AddRefed<DrawTarget> nsTextFrame::PropertyProvider::GetDrawTarget() } gfxFloat nsTextFrame::PropertyProvider::MinTabAdvance() const { - if (mMinTabAdvance < 0) { + if (mMinTabAdvance < 0.0) { mMinTabAdvance = GetMinTabAdvanceAppUnits(mTextRun); } return mMinTabAdvance; @@ -3862,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(); @@ -4265,13 +4265,12 @@ bool nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, } // 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, @@ -4332,10 +4331,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; } @@ -4355,7 +4355,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()) { @@ -6731,8 +6731,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(), @@ -7538,8 +7537,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); @@ -7563,12 +7562,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); } } @@ -9740,7 +9734,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(); } @@ -10067,6 +10061,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. @@ -10092,7 +10095,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. @@ -10117,8 +10120,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; } @@ -10871,15 +10874,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 @@ -10890,8 +10896,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); @@ -10905,9 +10911,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; @@ -11003,7 +11010,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); @@ -11261,7 +11268,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 @@ -161,7 +161,7 @@ class nsTextFrame : public nsIFrame { void InitializeForMeasure(); bool GetSpacing(Range aRange, Spacing* aSpacing) const final; - nscoord GetHyphenWidth() const final; + gfxFloat GetHyphenWidth() const final; void GetHyphenationBreaks(Range aRange, HyphenType* aBreakBefore) const final; mozilla::StyleHyphens GetHyphensOption() const final { @@ -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 @@ -884,11 +884,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/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list @@ -2121,7 +2121,7 @@ skip-if(Android) test-pref(ui.textScaleFactor,50) test-pref(browser.display.os-z pref(widget.disable-dark-scrollbar,false) == 1777135.html 1777135-ref.html test-pref(widget.non-native-theme.use-theme-accent,false) == 1778834.html 1778834-ref.html # do not adjust the fuzz without looking, this test was written as fuzzy on purpose (because that was the only way to make a test work) -fuzzy(16-47,26939-44425) == 1780191-1.svg 1780191-1-ref.svg +fuzzy(16-68,26939-44426) == 1780191-1.svg 1780191-1-ref.svg pref(layout.css.prefers-color-scheme.content-override,0) == 1787127.html 1787127-ref.html pref(layout.css.prefers-color-scheme.content-override,1) == 1787127.html 1787127-ref.html pref(layout.css.prefers-color-scheme.content-override,2) == 1787127.html 1787127-ref.html diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp @@ -838,18 +838,19 @@ SVGBBox TextRenderedRun::GetRunUserSpaceRect(uint32_t aFlags) const { 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; } @@ -857,7 +858,9 @@ SVGBBox TextRenderedRun::GetRunUserSpaceRect(uint32_t aFlags) const { 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-values/ch-unit-012.html.ini b/testing/web-platform/meta/css/css-values/ch-unit-012.html.ini @@ -0,0 +1,3 @@ +[ch-unit-012.html] + expected: + if (os == "android") and swgl: FAIL 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-72;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 diff --git a/testing/web-platform/tests/html/canvas/element/text/2d.text.drawing.style.letterSpacing.measure.html b/testing/web-platform/tests/html/canvas/element/text/2d.text.drawing.style.letterSpacing.measure.html @@ -44,7 +44,7 @@ _addTest(function(canvas, ctx) { ['-0.1em', -11, 0.1], ['1in', 1056, 0.1], ['-0.1cm', -41.65, 0.2], - ['-0.6mm', -24,95, 0.2]] + ['-0.6mm', -24.95, 0.2]] for (const test_case of test_cases) { test_letter_spacing(test_case[0], test_case[1], test_case[2]); diff --git a/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html b/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.html @@ -45,7 +45,7 @@ t.step(function() { ['-0.1em', -11, 0.1], ['1in', 1056, 0.1], ['-0.1cm', -41.65, 0.2], - ['-0.6mm', -24,95, 0.2]] + ['-0.6mm', -24.95, 0.2]] for (const test_case of test_cases) { test_letter_spacing(test_case[0], test_case[1], test_case[2]); diff --git a/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js b/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.js @@ -40,7 +40,7 @@ t.step(function() { ['-0.1em', -11, 0.1], ['1in', 1056, 0.1], ['-0.1cm', -41.65, 0.2], - ['-0.6mm', -24,95, 0.2]] + ['-0.6mm', -24.95, 0.2]] for (const test_case of test_cases) { test_letter_spacing(test_case[0], test_case[1], test_case[2]); diff --git a/testing/web-platform/tests/html/canvas/tools/yaml/text.yaml b/testing/web-platform/tests/html/canvas/tools/yaml/text.yaml @@ -2866,7 +2866,7 @@ ['-0.1em', -11, 0.1], ['1in', 1056, 0.1], ['-0.1cm', -41.65, 0.2], - ['-0.6mm', -24,95, 0.2]] + ['-0.6mm', -24.95, 0.2]] for (const test_case of test_cases) { test_letter_spacing(test_case[0], test_case[1], test_case[2]);