Bug 1155261 - Fix computation of glyph extents and text-frame visual overflow for vertical text frames. r=smontagu

This commit is contained in:
Jonathan Kew 2015-04-27 09:45:55 +01:00
parent 4582eeaaf4
commit c050cf8885
6 changed files with 46 additions and 45 deletions

View File

@ -2124,8 +2124,8 @@ gfxFont::IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun)
GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit()); GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
gfxRect glyphExtents; gfxRect glyphExtents;
mFontEntry->mSpaceGlyphIsInvisible = mFontEntry->mSpaceGlyphIsInvisible =
extents->GetTightGlyphExtentsAppUnits(this, eHorizontal, extents->GetTightGlyphExtentsAppUnits(this, aRefContext,
aRefContext, GetSpaceGlyph(), &glyphExtents) && GetSpaceGlyph(), &glyphExtents) &&
glyphExtents.IsEmpty(); glyphExtents.IsEmpty();
mFontEntry->mSpaceGlyphIsInvisibleInitialized = true; mFontEntry->mSpaceGlyphIsInvisibleInitialized = true;
} }
@ -2232,11 +2232,14 @@ gfxFont::Measure(gfxTextRun *aTextRun,
} else { } else {
gfxRect glyphRect; gfxRect glyphRect;
if (!extents->GetTightGlyphExtentsAppUnits(this, if (!extents->GetTightGlyphExtentsAppUnits(this,
orientation,
aRefContext, glyphIndex, &glyphRect)) { aRefContext, glyphIndex, &glyphRect)) {
glyphRect = gfxRect(0, metrics.mBoundingBox.Y(), glyphRect = gfxRect(0, metrics.mBoundingBox.Y(),
advance, metrics.mBoundingBox.Height()); advance, metrics.mBoundingBox.Height());
} }
if (orientation == eVertical) {
Swap(glyphRect.x, glyphRect.y);
Swap(glyphRect.width, glyphRect.height);
}
if (isRTL) { if (isRTL) {
glyphRect -= gfxPoint(advance, 0); glyphRect -= gfxPoint(advance, 0);
} }
@ -2261,13 +2264,16 @@ gfxFont::Measure(gfxTextRun *aTextRun,
gfxRect glyphRect; gfxRect glyphRect;
if (glyphData->IsMissing() || !extents || if (glyphData->IsMissing() || !extents ||
!extents->GetTightGlyphExtentsAppUnits(this, !extents->GetTightGlyphExtentsAppUnits(this,
orientation,
aRefContext, glyphIndex, &glyphRect)) { aRefContext, glyphIndex, &glyphRect)) {
// We might have failed to get glyph extents due to // We might have failed to get glyph extents due to
// OOM or something // OOM or something
glyphRect = gfxRect(0, -metrics.mAscent, glyphRect = gfxRect(0, -metrics.mAscent,
advance, metrics.mAscent + metrics.mDescent); advance, metrics.mAscent + metrics.mDescent);
} }
if (orientation == eVertical) {
Swap(glyphRect.x, glyphRect.y);
Swap(glyphRect.width, glyphRect.height);
}
if (isRTL) { if (isRTL) {
glyphRect -= gfxPoint(advance, 0); glyphRect -= gfxPoint(advance, 0);
} }
@ -3128,7 +3134,7 @@ gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) {
} }
void void
gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation, gfxFont::SetupGlyphExtents(gfxContext *aContext,
uint32_t aGlyphID, bool aNeedTight, uint32_t aGlyphID, bool aNeedTight,
gfxGlyphExtents *aExtents) gfxGlyphExtents *aExtents)
{ {
@ -3154,7 +3160,7 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, Orientation aOrientation,
cairo_text_extents_t extents; cairo_text_extents_t extents;
cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents); cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents);
const Metrics& fontMetrics = GetMetrics(aOrientation); const Metrics& fontMetrics = GetMetrics(eHorizontal);
int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit(); int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
if (!aNeedTight && extents.x_bearing >= 0 && if (!aNeedTight && extents.x_bearing >= 0 &&
extents.y_bearing >= -fontMetrics.maxAscent && extents.y_bearing >= -fontMetrics.maxAscent &&

View File

@ -1619,8 +1619,7 @@ public:
gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit); gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
// You need to call SetupCairoFont on the aCR just before calling this // You need to call SetupCairoFont on the aCR just before calling this
virtual void SetupGlyphExtents(gfxContext *aContext, virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID,
Orientation aOrientation, uint32_t aGlyphID,
bool aNeedTight, gfxGlyphExtents *aExtents); bool aNeedTight, gfxGlyphExtents *aExtents);
// This is called by the default Draw() implementation above. // This is called by the default Draw() implementation above.

View File

@ -36,7 +36,6 @@ gfxGlyphExtents::~gfxGlyphExtents()
bool bool
gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
gfxFont::Orientation aOrientation,
gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents) gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents)
{ {
HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID); HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
@ -50,8 +49,7 @@ gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
++gGlyphExtentsSetupLazyTight; ++gGlyphExtentsSetupLazyTight;
#endif #endif
aFont->SetupGlyphExtents(aContext, aOrientation, aGlyphID, true, aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
this);
entry = mTightGlyphExtents.GetEntry(aGlyphID); entry = mTightGlyphExtents.GetEntry(aGlyphID);
} }
if (!entry) { if (!entry) {

View File

@ -63,7 +63,6 @@ public:
// Returns true on success. Can fail on OOM or when aContext is null // Returns true on success. Can fail on OOM or when aContext is null
// and extents were not (successfully) prefetched. // and extents were not (successfully) prefetched.
bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, bool GetTightGlyphExtentsAppUnits(gfxFont *aFont,
gfxFont::Orientation aOrientation,
gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents); gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents);
void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) { void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {

View File

@ -1373,8 +1373,6 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
for (j = start; j < end; ++j) { for (j = start; j < end; ++j) {
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j]; const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
gfxFont::Orientation orientation =
IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal;
if (glyphData->IsSimpleGlyph()) { if (glyphData->IsSimpleGlyph()) {
// If we're in speed mode, don't set up glyph extents here; we'll // If we're in speed mode, don't set up glyph extents here; we'll
// just return "optimistic" glyph bounds later // just return "optimistic" glyph bounds later
@ -1391,7 +1389,7 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
++gGlyphExtentsSetupEagerSimple; ++gGlyphExtentsSetupEagerSimple;
#endif #endif
font->SetupGlyphExtents(aRefContext, orientation, font->SetupGlyphExtents(aRefContext,
glyphIndex, false, extents); glyphIndex, false, extents);
} }
} }
@ -1417,7 +1415,7 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
++gGlyphExtentsSetupEagerTight; ++gGlyphExtentsSetupEagerTight;
#endif #endif
font->SetupGlyphExtents(aRefContext, orientation, font->SetupGlyphExtents(aRefContext,
glyphIndex, true, extents); glyphIndex, true, extents);
} }
} }

View File

@ -5537,6 +5537,9 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun,
gfxTextRun::Metrics hyphenMetrics = gfxTextRun::Metrics hyphenMetrics =
hyphenTextRun->MeasureText(0, hyphenTextRun->GetLength(), hyphenTextRun->MeasureText(0, hyphenTextRun->GetLength(),
aBoundingBoxType, aContext, nullptr); aBoundingBoxType, aContext, nullptr);
if (aTextFrame->GetWritingMode().IsLineInverted()) {
hyphenMetrics.mBoundingBox.y = -hyphenMetrics.mBoundingBox.YMost();
}
aMetrics->CombineWith(hyphenMetrics, aBaseTextRun->IsRightToLeft()); aMetrics->CombineWith(hyphenMetrics, aBaseTextRun->IsRightToLeft());
} }
@ -7765,12 +7768,12 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const
ComputeTransformedLength(provider), ComputeTransformedLength(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aContext, &provider); aContext, &provider);
if (GetWritingMode().IsLineInverted()) {
metrics.mBoundingBox.y = -metrics.mBoundingBox.YMost();
}
// mAscent should be the same as metrics.mAscent, but it's what we use to // mAscent should be the same as metrics.mAscent, but it's what we use to
// paint so that's the one we'll use. // paint so that's the one we'll use.
nsRect boundingBox = RoundOut(metrics.mBoundingBox); nsRect boundingBox = RoundOut(metrics.mBoundingBox);
if (GetWritingMode().IsLineInverted()) {
boundingBox.y = -boundingBox.YMost();
}
boundingBox += nsPoint(0, mAscent); boundingBox += nsPoint(0, mAscent);
if (mTextRun->IsVertical()) { if (mTextRun->IsVertical()) {
// Swap line-relative textMetrics dimensions to physical coordinates. // Swap line-relative textMetrics dimensions to physical coordinates.
@ -8360,6 +8363,10 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
textMetrics.mDescent = gfxFloat(fm->MaxDescent()); textMetrics.mDescent = gfxFloat(fm->MaxDescent());
} }
} }
if (GetWritingMode().IsLineInverted()) {
Swap(textMetrics.mAscent, textMetrics.mDescent);
textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost();
}
// The "end" iterator points to the first character after the string mapped // The "end" iterator points to the first character after the string mapped
// by this frame. Basically, its original-string offset is offset+charsFit // by this frame. Basically, its original-string offset is offset+charsFit
// after we've computed charsFit. // after we've computed charsFit.
@ -8465,31 +8472,21 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
finalSize.BSize(wm) = 0; finalSize.BSize(wm) = 0;
} else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) { } else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) {
// Use actual text metrics for floating first letter frame. // Use actual text metrics for floating first letter frame.
if (wm.IsLineInverted()) { aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mDescent)); finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + NSToCoordCeil(textMetrics.mDescent);
NSToCoordCeil(textMetrics.mAscent);
} else {
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
NSToCoordCeil(textMetrics.mDescent);
}
} else { } else {
// Otherwise, ascent should contain the overline drawable area. // Otherwise, ascent should contain the overline drawable area.
// And also descent should contain the underline drawable area. // And also descent should contain the underline drawable area.
// nsFontMetrics::GetMaxAscent/GetMaxDescent contains them. // nsFontMetrics::GetMaxAscent/GetMaxDescent contains them.
nsFontMetrics* fm = provider.GetFontMetrics(); nsFontMetrics* fm = provider.GetFontMetrics();
nscoord fontAscent = fm->MaxAscent(); nscoord fontAscent =
nscoord fontDescent = fm->MaxDescent(); wm.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent();
if (wm.IsLineInverted()) { nscoord fontDescent =
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent)); wm.IsLineInverted() ? fm->MaxAscent() : fm->MaxDescent();
nscoord descent = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent); aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent; nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
} else { finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
}
} }
aMetrics.SetSize(wm, finalSize); aMetrics.SetSize(wm, finalSize);
@ -8503,14 +8500,18 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
// Handle text that runs outside its normal bounds. // Handle text that runs outside its normal bounds.
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox); nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
if (wm.IsLineInverted()) {
boundingBox.y = -boundingBox.YMost();
}
boundingBox += nsPoint(0, mAscent);
if (mTextRun->IsVertical()) { if (mTextRun->IsVertical()) {
// Swap line-relative textMetrics dimensions to physical coordinates. // Swap line-relative textMetrics dimensions to physical coordinates.
Swap(boundingBox.x, boundingBox.y); Swap(boundingBox.x, boundingBox.y);
Swap(boundingBox.width, boundingBox.height); Swap(boundingBox.width, boundingBox.height);
if (GetWritingMode().IsVerticalRL()) {
boundingBox.x = -boundingBox.XMost();
boundingBox.x += aMetrics.Width() - mAscent;
} else {
boundingBox.x += mAscent;
}
} else {
boundingBox.y += mAscent;
} }
aMetrics.SetOverflowAreasToDesiredBounds(); aMetrics.SetOverflowAreasToDesiredBounds();
aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox); aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox);
@ -8732,10 +8733,10 @@ nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame)
ComputeTransformedLength(provider), ComputeTransformedLength(provider),
gfxFont::LOOSE_INK_EXTENTS, nullptr, gfxFont::LOOSE_INK_EXTENTS, nullptr,
&provider); &provider);
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
if (GetWritingMode().IsLineInverted()) { if (GetWritingMode().IsLineInverted()) {
boundingBox.y = -boundingBox.YMost(); textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost();
} }
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
boundingBox += nsPoint(0, mAscent); boundingBox += nsPoint(0, mAscent);
if (mTextRun->IsVertical()) { if (mTextRun->IsVertical()) {
// Swap line-relative textMetrics dimensions to physical coordinates. // Swap line-relative textMetrics dimensions to physical coordinates.