Bug 1099977. Part 2: Make gfxFont::Measure return an empty bounding-box when all glyphs are invisible. r=jfkthame

--HG--
extra : rebase_source : 41a9f586ef2992d96b789d6bd55daae18f15ed2f
This commit is contained in:
Robert O'Callahan 2014-11-18 23:23:45 +13:00
parent 198bbca1c1
commit 68c074dcb8
7 changed files with 109 additions and 45 deletions

View File

@ -2114,6 +2114,23 @@ NeedsGlyphExtents(gfxFont *aFont, gfxTextRun *aTextRun)
aFont->GetFontEntry()->IsUserFont(); aFont->GetFontEntry()->IsUserFont();
} }
bool
gfxFont::IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun)
{
if (!mFontEntry->mSpaceGlyphIsInvisibleInitialized &&
GetAdjustedSize() >= 1.0) {
gfxGlyphExtents *extents =
GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
gfxRect glyphExtents;
mFontEntry->mSpaceGlyphIsInvisible =
extents->GetTightGlyphExtentsAppUnits(this, eHorizontal,
aRefContext, GetSpaceGlyph(), &glyphExtents) &&
glyphExtents.IsEmpty();
mFontEntry->mSpaceGlyphIsInvisibleInitialized = true;
}
return mFontEntry->mSpaceGlyphIsInvisible;
}
gfxFont::RunMetrics gfxFont::RunMetrics
gfxFont::Measure(gfxTextRun *aTextRun, gfxFont::Measure(gfxTextRun *aTextRun,
uint32_t aStart, uint32_t aEnd, uint32_t aStart, uint32_t aEnd,
@ -2189,16 +2206,22 @@ gfxFont::Measure(gfxTextRun *aTextRun,
if (aSpacing) { if (aSpacing) {
x += direction*aSpacing[0].mBefore; x += direction*aSpacing[0].mBefore;
} }
uint32_t spaceGlyph = GetSpaceGlyph();
bool allGlyphsInvisible = true;
uint32_t i; uint32_t i;
for (i = aStart; i < aEnd; ++i) { for (i = aStart; i < aEnd; ++i) {
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i]; const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
if (glyphData->IsSimpleGlyph()) { if (glyphData->IsSimpleGlyph()) {
double advance = glyphData->GetSimpleAdvance(); double advance = glyphData->GetSimpleAdvance();
uint32_t glyphIndex = glyphData->GetSimpleGlyph();
if (glyphIndex != spaceGlyph ||
!IsSpaceGlyphInvisible(aRefContext, aTextRun)) {
allGlyphsInvisible = false;
}
// Only get the real glyph horizontal extent if we were asked // Only get the real glyph horizontal extent if we were asked
// for the tight bounding box or we're in quality mode // for the tight bounding box or we're in quality mode
if ((aBoundingBoxType != LOOSE_INK_EXTENTS || needsGlyphExtents) && if ((aBoundingBoxType != LOOSE_INK_EXTENTS || needsGlyphExtents) &&
extents) { extents){
uint32_t glyphIndex = glyphData->GetSimpleGlyph();
uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex); uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH && if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH &&
aBoundingBoxType == LOOSE_INK_EXTENTS) { aBoundingBoxType == LOOSE_INK_EXTENTS) {
@ -2221,6 +2244,7 @@ gfxFont::Measure(gfxTextRun *aTextRun,
} }
x += direction*advance; x += direction*advance;
} else { } else {
allGlyphsInvisible = false;
uint32_t glyphCount = glyphData->GetGlyphCount(); uint32_t glyphCount = glyphData->GetGlyphCount();
if (glyphCount > 0) { if (glyphCount > 0) {
const gfxTextRun::DetailedGlyph *details = const gfxTextRun::DetailedGlyph *details =
@ -2261,14 +2285,18 @@ gfxFont::Measure(gfxTextRun *aTextRun,
} }
} }
if (aBoundingBoxType == LOOSE_INK_EXTENTS) { if (allGlyphsInvisible) {
UnionRange(x, &advanceMin, &advanceMax); metrics.mBoundingBox.SetEmpty();
gfxRect fontBox(advanceMin, -metrics.mAscent, } else {
advanceMax - advanceMin, metrics.mAscent + metrics.mDescent); if (aBoundingBoxType == LOOSE_INK_EXTENTS) {
metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox); UnionRange(x, &advanceMin, &advanceMax);
} gfxRect fontBox(advanceMin, -metrics.mAscent,
if (isRTL) { advanceMax - advanceMin, metrics.mAscent + metrics.mDescent);
metrics.mBoundingBox -= gfxPoint(x, 0); metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox);
}
if (isRTL) {
metrics.mBoundingBox -= gfxPoint(x, 0);
}
} }
// If the font may be rendered with a fake-italic effect, we need to allow // If the font may be rendered with a fake-italic effect, we need to allow

View File

@ -1846,6 +1846,8 @@ protected:
return -1; return -1;
} }
bool IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun);
void AddGlyphChangeObserver(GlyphChangeObserver *aObserver); void AddGlyphChangeObserver(GlyphChangeObserver *aObserver);
void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver); void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver);

View File

@ -85,6 +85,8 @@ gfxFontEntry::gfxFontEntry() :
mHasSpaceFeaturesKerning(false), mHasSpaceFeaturesKerning(false),
mHasSpaceFeaturesNonKerning(false), mHasSpaceFeaturesNonKerning(false),
mSkipDefaultFeatureSpaceCheck(false), mSkipDefaultFeatureSpaceCheck(false),
mSpaceGlyphIsInvisible(false),
mSpaceGlyphIsInvisibleInitialized(false),
mCheckedForGraphiteTables(false), mCheckedForGraphiteTables(false),
mHasCmapTable(false), mHasCmapTable(false),
mGrFaceInitialized(false), mGrFaceInitialized(false),
@ -120,6 +122,8 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
mHasSpaceFeaturesKerning(false), mHasSpaceFeaturesKerning(false),
mHasSpaceFeaturesNonKerning(false), mHasSpaceFeaturesNonKerning(false),
mSkipDefaultFeatureSpaceCheck(false), mSkipDefaultFeatureSpaceCheck(false),
mSpaceGlyphIsInvisible(false),
mSpaceGlyphIsInvisibleInitialized(false),
mCheckedForGraphiteTables(false), mCheckedForGraphiteTables(false),
mHasCmapTable(false), mHasCmapTable(false),
mGrFaceInitialized(false), mGrFaceInitialized(false),

View File

@ -403,6 +403,8 @@ public:
bool mHasSpaceFeaturesKerning : 1; bool mHasSpaceFeaturesKerning : 1;
bool mHasSpaceFeaturesNonKerning : 1; bool mHasSpaceFeaturesNonKerning : 1;
bool mSkipDefaultFeatureSpaceCheck : 1; bool mSkipDefaultFeatureSpaceCheck : 1;
bool mSpaceGlyphIsInvisible : 1;
bool mSpaceGlyphIsInvisibleInitialized : 1;
bool mHasGraphiteTables : 1; bool mHasGraphiteTables : 1;
bool mCheckedForGraphiteTables : 1; bool mCheckedForGraphiteTables : 1;
bool mHasCmapTable : 1; bool mHasCmapTable : 1;

View File

@ -5695,36 +5695,22 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
// or from the ::-moz-selection pseudo-class if specified there // or from the ::-moz-selection pseudo-class if specified there
nsCSSShadowArray* shadow = textStyle->GetTextShadow(); nsCSSShadowArray* shadow = textStyle->GetTextShadow();
GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow); GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
// Draw shadows, if any
if (shadow) { if (shadow) {
gfxTextRun::Metrics shadowMetrics = nscoord leftEdge = iOffset;
mTextRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, if (mTextRun->IsRightToLeft()) {
nullptr, &aProvider); leftEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
if (GetStateBits() & TEXT_HYPHEN_BREAK) { hyphenWidth;
AddHyphenToMetrics(this, mTextRun, &shadowMetrics,
gfxFont::LOOSE_INK_EXTENTS, aCtx);
}
for (uint32_t i = shadow->Length(); i > 0; --i) {
PaintOneShadow(offset, length,
shadow->ShadowAt(i - 1), &aProvider,
dirtyRect, aFramePt, textBaselinePt, aCtx,
foreground, aClipEdges,
iOffset - (mTextRun->IsRightToLeft() ?
shadowMetrics.mBoundingBox.width : 0),
shadowMetrics.mBoundingBox);
} }
PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
leftEdge, aProvider, foreground, aClipEdges, aCtx);
} }
// Draw text segment // Draw text segment
gfxFloat advance; gfxFloat advance;
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt, DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges, offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks); advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
if (hyphenWidth) { advance += hyphenWidth;
advance += hyphenWidth;
}
iterator.UpdateWithAdvance(advance); iterator.UpdateWithAdvance(advance);
} }
return true; return true;
@ -6040,6 +6026,44 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
return maxLength != 0; return maxLength != 0;
} }
void
nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
uint32_t aOffset, uint32_t aLength,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nscoord aLeftEdgeOffset,
PropertyProvider& aProvider,
nscolor aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxContext* aCtx)
{
if (!aShadow) {
return;
}
gfxTextRun::Metrics shadowMetrics =
mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS,
nullptr, &aProvider);
if (GetStateBits() & TEXT_HYPHEN_BREAK) {
AddHyphenToMetrics(this, mTextRun, &shadowMetrics,
gfxFont::LOOSE_INK_EXTENTS, aCtx);
}
// Add bounds of text decorations
gfxRect decorationRect(0, -shadowMetrics.mAscent,
shadowMetrics.mAdvanceWidth, shadowMetrics.mAscent + shadowMetrics.mDescent);
shadowMetrics.mBoundingBox.UnionRect(shadowMetrics.mBoundingBox,
decorationRect);
for (uint32_t i = aShadow->Length(); i > 0; --i) {
PaintOneShadow(aOffset, aLength,
aShadow->ShadowAt(i - 1), &aProvider,
aDirtyRect, aFramePt, aTextBaselinePt, aCtx,
aForegroundColor, aClipEdges,
aLeftEdgeOffset,
shadowMetrics.mBoundingBox);
}
}
void void
nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect, const nsRect& aDirtyRect,
@ -6109,20 +6133,9 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
nscolor foregroundColor = textPaintStyle.GetTextColor(); nscolor foregroundColor = textPaintStyle.GetTextColor();
if (!aCallbacks) { if (!aCallbacks) {
const nsStyleText* textStyle = StyleText(); const nsStyleText* textStyle = StyleText();
if (textStyle->HasTextShadow()) { PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
// Text shadow happens with the last value being painted at the back, aDirtyRect, framePt, textBaselinePt, snappedLeftEdge, provider,
// ie. it is painted first. foregroundColor, clipEdges, ctx);
gfxTextRun::Metrics shadowMetrics =
mTextRun->MeasureText(startOffset, maxLength, gfxFont::LOOSE_INK_EXTENTS,
nullptr, &provider);
for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
PaintOneShadow(startOffset, maxLength,
textStyle->mTextShadow->ShadowAt(i - 1), &provider,
aDirtyRect, framePt, textBaselinePt, ctx,
foregroundColor, clipEdges,
snappedLeftEdge, shadowMetrics.mBoundingBox);
}
}
} }
gfxFloat advanceWidth; gfxFloat advanceWidth;

View File

@ -584,6 +584,17 @@ protected:
nscoord aLeftSideOffset, nscoord aLeftSideOffset,
gfxRect& aBoundingBox); gfxRect& aBoundingBox);
void PaintShadows(nsCSSShadowArray* aShadow,
uint32_t aOffset, uint32_t aLength,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nscoord aLeftEdgeOffset,
PropertyProvider& aProvider,
nscolor aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxContext* aCtx);
struct LineDecoration { struct LineDecoration {
nsIFrame* mFrame; nsIFrame* mFrame;

View File

@ -908,6 +908,10 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
gfxTextRun::Metrics metrics = gfxTextRun::Metrics metrics =
textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
nullptr, nullptr); nullptr, nullptr);
// Make sure it includes the font-box.
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, // Determine the rectangle that covers the rendered run's fill,
// taking into account the measured vertical overflow due to // taking into account the measured vertical overflow due to