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();
}
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::Measure(gfxTextRun *aTextRun,
uint32_t aStart, uint32_t aEnd,
@ -2189,16 +2206,22 @@ gfxFont::Measure(gfxTextRun *aTextRun,
if (aSpacing) {
x += direction*aSpacing[0].mBefore;
}
uint32_t spaceGlyph = GetSpaceGlyph();
bool allGlyphsInvisible = true;
uint32_t i;
for (i = aStart; i < aEnd; ++i) {
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
if (glyphData->IsSimpleGlyph()) {
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
// for the tight bounding box or we're in quality mode
if ((aBoundingBoxType != LOOSE_INK_EXTENTS || needsGlyphExtents) &&
extents) {
uint32_t glyphIndex = glyphData->GetSimpleGlyph();
extents){
uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH &&
aBoundingBoxType == LOOSE_INK_EXTENTS) {
@ -2221,6 +2244,7 @@ gfxFont::Measure(gfxTextRun *aTextRun,
}
x += direction*advance;
} else {
allGlyphsInvisible = false;
uint32_t glyphCount = glyphData->GetGlyphCount();
if (glyphCount > 0) {
const gfxTextRun::DetailedGlyph *details =
@ -2261,14 +2285,18 @@ gfxFont::Measure(gfxTextRun *aTextRun,
}
}
if (aBoundingBoxType == LOOSE_INK_EXTENTS) {
UnionRange(x, &advanceMin, &advanceMax);
gfxRect fontBox(advanceMin, -metrics.mAscent,
advanceMax - advanceMin, metrics.mAscent + metrics.mDescent);
metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox);
}
if (isRTL) {
metrics.mBoundingBox -= gfxPoint(x, 0);
if (allGlyphsInvisible) {
metrics.mBoundingBox.SetEmpty();
} else {
if (aBoundingBoxType == LOOSE_INK_EXTENTS) {
UnionRange(x, &advanceMin, &advanceMax);
gfxRect fontBox(advanceMin, -metrics.mAscent,
advanceMax - advanceMin, metrics.mAscent + metrics.mDescent);
metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox);
}
if (isRTL) {
metrics.mBoundingBox -= gfxPoint(x, 0);
}
}
// If the font may be rendered with a fake-italic effect, we need to allow

View File

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

View File

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

View File

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

View File

@ -5695,36 +5695,22 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
// or from the ::-moz-selection pseudo-class if specified there
nsCSSShadowArray* shadow = textStyle->GetTextShadow();
GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
// Draw shadows, if any
if (shadow) {
gfxTextRun::Metrics shadowMetrics =
mTextRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
nullptr, &aProvider);
if (GetStateBits() & TEXT_HYPHEN_BREAK) {
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);
nscoord leftEdge = iOffset;
if (mTextRun->IsRightToLeft()) {
leftEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
hyphenWidth;
}
PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
leftEdge, aProvider, foreground, aClipEdges, aCtx);
}
// Draw text segment
gfxFloat advance;
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
if (hyphenWidth) {
advance += hyphenWidth;
}
advance += hyphenWidth;
iterator.UpdateWithAdvance(advance);
}
return true;
@ -6040,6 +6026,44 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider,
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
nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
const nsRect& aDirtyRect,
@ -6109,20 +6133,9 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
nscolor foregroundColor = textPaintStyle.GetTextColor();
if (!aCallbacks) {
const nsStyleText* textStyle = StyleText();
if (textStyle->HasTextShadow()) {
// Text shadow happens with the last value being painted at the back,
// ie. it is painted first.
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);
}
}
PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
aDirtyRect, framePt, textBaselinePt, snappedLeftEdge, provider,
foregroundColor, clipEdges, ctx);
}
gfxFloat advanceWidth;

View File

@ -584,6 +584,17 @@ protected:
nscoord aLeftSideOffset,
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 {
nsIFrame* mFrame;

View File

@ -908,6 +908,10 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
gfxTextRun::Metrics metrics =
textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
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,
// taking into account the measured vertical overflow due to