Bug 1547063 - fix advance scaling for emoji. r=karlt

This fixes the regression in reftests/text/color-opacity-rtl-[12].html.

Differential Revision: https://phabricator.services.mozilla.com/D45956

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lee Salzman 2019-09-16 16:46:27 +00:00
Родитель 785b2c37e6
Коммит 18ac180309
2 изменённых файлов: 53 добавлений и 6 удалений

Просмотреть файл

@ -37,7 +37,8 @@ gfxFT2FontBase::gfxFT2FontBase(
mSpaceGlyph(0), mSpaceGlyph(0),
mFTLoadFlags(aLoadFlags | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | mFTLoadFlags(aLoadFlags | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH |
FT_LOAD_COLOR), FT_LOAD_COLOR),
mEmbolden(aEmbolden) { mEmbolden(aEmbolden),
mFTSize(1.0) {
cairo_scaled_font_reference(mScaledFont); cairo_scaled_font_reference(mScaledFont);
} }
@ -47,9 +48,8 @@ FT_Face gfxFT2FontBase::LockFTFace() {
if (!mFTFace->Lock(this)) { if (!mFTFace->Lock(this)) {
FT_Set_Transform(mFTFace->GetFace(), nullptr, nullptr); FT_Set_Transform(mFTFace->GetFace(), nullptr, nullptr);
gfxFloat size = std::max(GetAdjustedSize(), 1.0); FT_F26Dot6 charSize = NS_lround(mFTSize * 64.0);
FT_Set_Char_Size(mFTFace->GetFace(), FT_F26Dot6(size * 64.0 + 0.5), FT_Set_Char_Size(mFTFace->GetFace(), charSize, charSize, 0, 0);
FT_F26Dot6(size * 64.0 + 0.5), 0, 0);
} }
return mFTFace->GetFace(); return mFTFace->GetFace();
} }
@ -174,6 +174,38 @@ uint32_t gfxFT2FontBase::GetCharWidth(char aChar, gfxFloat* aWidth) {
} }
} }
/**
* Find the closest available fixed strike size, if applicable, to the
* desired font size.
*/
static double FindClosestSize(FT_Face aFace, double aSize) {
// FT size selection does not actually support sizes smaller than 1 and will
// clamp this internally, regardless of what is requested. Do the clamp here
// instead so that glyph extents/font matrix scaling will compensate it, as
// Cairo normally would.
if (aSize < 1.0) {
aSize = 1.0;
}
if (FT_IS_SCALABLE(aFace)) {
return aSize;
}
double bestDist = DBL_MAX;
FT_Int bestSize = -1;
for (FT_Int i = 0; i < aFace->num_fixed_sizes; i++) {
double dist = aFace->available_sizes[i].y_ppem / 64.0 - aSize;
// If the previous best is smaller than the desired size, prefer
// a bigger size. Otherwise, just choose whatever size is closest.
if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
bestDist = dist;
bestSize = i;
}
}
if (bestSize < 0) {
return aSize;
}
return aFace->available_sizes[bestSize].y_ppem / 64.0;
}
void gfxFT2FontBase::InitMetrics() { void gfxFT2FontBase::InitMetrics() {
mFUnitsConvFactor = 0.0; mFUnitsConvFactor = 0.0;
@ -184,6 +216,12 @@ void gfxFT2FontBase::InitMetrics() {
return; return;
} }
// Cairo metrics are normalized to em-space, so that whatever fixed size
// might actually be chosen is factored out. They are then later scaled by
// the font matrix to the target adjusted size. Stash the chosen closest
// size here for later scaling of the metrics.
mFTSize = FindClosestSize(mFTFace->GetFace(), GetAdjustedSize());
// Explicitly lock the face so we can release it early before calling // Explicitly lock the face so we can release it early before calling
// back into Cairo below. // back into Cairo below.
FT_Face face = LockFTFace(); FT_Face face = LockFTFace();
@ -505,6 +543,10 @@ bool gfxFT2FontBase::GetFTGlyphExtents(uint16_t aGID, int32_t* aAdvance,
bool hintMetrics = ShouldHintMetrics(); bool hintMetrics = ShouldHintMetrics();
// Normalize out the loaded FT glyph size and then scale to the actually
// desired size, in case these two sizes differ.
gfxFloat extentsScale = GetAdjustedSize() / mFTSize;
// Due to freetype bug 52683 we MUST use the linearHoriAdvance field when // Due to freetype bug 52683 we MUST use the linearHoriAdvance field when
// dealing with a variation font; also use it for scalable fonts when not // dealing with a variation font; also use it for scalable fonts when not
// applying hinting. Otherwise, prefer hinted width from glyph->advance.x. // applying hinting. Otherwise, prefer hinted width from glyph->advance.x.
@ -516,17 +558,21 @@ bool gfxFT2FontBase::GetFTGlyphExtents(uint16_t aGID, int32_t* aAdvance,
advance = face.get()->glyph->advance.x << 10; // convert 26.6 to 16.16 advance = face.get()->glyph->advance.x << 10; // convert 26.6 to 16.16
} }
advance += GetEmboldenAdvance(face.get(), advance); advance += GetEmboldenAdvance(face.get(), advance);
// Hinting was requested, but FT did not apply any hinting to the metrics.
// Round the advance here to approximate hinting as Cairo does. This must
// happen BEFORE we apply the glyph extents scale, just like FT hinting
// would.
if (hintMetrics && (mFTLoadFlags & FT_LOAD_NO_HINTING)) { if (hintMetrics && (mFTLoadFlags & FT_LOAD_NO_HINTING)) {
advance = (advance + 0x8000) & 0xffff0000u; advance = (advance + 0x8000) & 0xffff0000u;
} }
*aAdvance = advance; *aAdvance = NS_lround(advance * extentsScale);
if (aHeight) { if (aHeight) {
FT_F26Dot6 height = -face.get()->glyph->metrics.horiBearingY; FT_F26Dot6 height = -face.get()->glyph->metrics.horiBearingY;
if (hintMetrics && (mFTLoadFlags & FT_LOAD_NO_HINTING)) { if (hintMetrics && (mFTLoadFlags & FT_LOAD_NO_HINTING)) {
height &= -64; height &= -64;
} }
*aHeight = height; *aHeight = NS_lround(height * extentsScale);
} }
return true; return true;
} }

Просмотреть файл

@ -60,6 +60,7 @@ class gfxFT2FontBase : public gfxFont {
Metrics mMetrics; Metrics mMetrics;
int mFTLoadFlags; int mFTLoadFlags;
bool mEmbolden; bool mEmbolden;
gfxFloat mFTSize;
// For variation/multiple-master fonts, this will be an array of the values // For variation/multiple-master fonts, this will be an array of the values
// for each axis, as specified by mStyle.variationSettings (or the font's // for each axis, as specified by mStyle.variationSettings (or the font's