Revert of Rotate emoji with FreeType. (patchset #5 id:80001 of https://codereview.chromium.org/2139703002/ )

Reason for revert:
Causing roll to fail on telemetry_perf_unittests (bencharks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.load:search:taobao (and baidu)) and browser_tests (FindInPageControllerTest.FindInPageSpecialURLS).

This is due to triggering the assert in copyFTBitmap

SkASSERT(dstMask.fBounds.width() == static_cast<int>(srcFTBitmap.width));

when called from inside the block guarded by

if (bitmapTransform.isIdentity())

Original issue's description:
> Rotate bitmap strikes with FreeType.
>
> BUG=skia:3490
> GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2139703002
>
> Committed: https://skia.googlesource.com/skia/+/31e0c1379e6d0ce48196183e295b929af51fa74e

TBR=mtklein@google.com,reed@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:3490

Review-Url: https://codereview.chromium.org/2149253005
This commit is contained in:
bungeman 2016-07-15 18:49:42 -07:00 committed by Commit bot
parent 6fc8ff024b
commit 280d537e28
3 changed files with 106 additions and 131 deletions

View File

@ -197,23 +197,18 @@ protected:
SkUnichar generateGlyphToChar(uint16_t glyph) override;
private:
FT_Face fFace; // Shared face from gFaceRecHead.
FT_Size fFTSize; // The size on the fFace for this scaler.
FT_Int fStrikeIndex;
FT_Face fFace; // reference to shared face in gFaceRecHead
FT_Size fFTSize; // our own copy
FT_Int fStrikeIndex;
FT_F26Dot6 fScaleX, fScaleY;
FT_Matrix fMatrix22;
uint32_t fLoadGlyphFlags;
bool fDoLinearMetrics;
bool fLCDIsVert;
/** The rest of the matrix after FreeType handles the size.
* With outline font rasterization this is handled by FreeType with FT_Set_Transform.
* With bitmap only fonts this matrix must be applied to scale the bitmap.
*/
SkMatrix fMatrix22Scalar;
/** Same as fMatrix22Scalar, but in FreeType units and space. */
FT_Matrix fMatrix22;
/** The actual size requested. */
SkVector fScale;
uint32_t fLoadGlyphFlags;
bool fDoLinearMetrics;
bool fLCDIsVert;
// Need scalar versions for generateFontMetrics
SkVector fScale;
SkMatrix fMatrix22Scalar;
FT_Error setupSize();
void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox,
@ -224,7 +219,6 @@ private:
// Caller must lock gFTMutex before calling this function.
// update FreeType2 glyph slot with glyph emboldened
void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph);
bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&);
};
///////////////////////////////////////////////////////////////////////////
@ -753,35 +747,47 @@ bool SkTypeface_FreeType::onGetKerningPairAdjustments(const uint16_t glyphs[],
return true;
}
/** Returns the bitmap strike equal to or just larger than the requested size. */
static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY) {
// early out if face is bad
if (face == nullptr) {
SkDEBUGF(("chooseBitmapStrike aborted due to nullptr face.\n"));
SkDEBUGF(("chooseBitmapStrike aborted due to nullptr face\n"));
return -1;
}
FT_Pos requestedPPEM = scaleY; // FT_Bitmap_Size::y_ppem is in 26.6 format.
// determine target ppem
FT_Pos targetPPEM = scaleY;
// find a bitmap strike equal to or just larger than the requested size
FT_Int chosenStrikeIndex = -1;
FT_Pos chosenPPEM = 0;
for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) {
FT_Pos strikePPEM = face->available_sizes[strikeIndex].y_ppem;
if (strikePPEM == requestedPPEM) {
FT_Pos thisPPEM = face->available_sizes[strikeIndex].y_ppem;
if (thisPPEM == targetPPEM) {
// exact match - our search stops here
return strikeIndex;
} else if (chosenPPEM < requestedPPEM) {
chosenPPEM = thisPPEM;
chosenStrikeIndex = strikeIndex;
break;
} else if (chosenPPEM < targetPPEM) {
// attempt to increase chosenPPEM
if (chosenPPEM < strikePPEM) {
chosenPPEM = strikePPEM;
if (thisPPEM > chosenPPEM) {
chosenPPEM = thisPPEM;
chosenStrikeIndex = strikeIndex;
}
} else {
// attempt to decrease chosenPPEM, but not below requestedPPEM
if (requestedPPEM < strikePPEM && strikePPEM < chosenPPEM) {
chosenPPEM = strikePPEM;
// attempt to decrease chosenPPEM, but not below targetPPEM
if (thisPPEM < chosenPPEM && thisPPEM > targetPPEM) {
chosenPPEM = thisPPEM;
chosenStrikeIndex = strikeIndex;
}
}
}
if (chosenStrikeIndex != -1) {
// use the chosen strike
FT_Error err = FT_Select_Size(face, chosenStrikeIndex);
if (err != 0) {
SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x\n", face->family_name,
chosenStrikeIndex, err));
chosenStrikeIndex = -1;
}
}
return chosenStrikeIndex;
}
@ -808,12 +814,14 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
}
fRec.computeMatrices(SkScalerContextRec::kFull_PreMatrixScale, &fScale, &fMatrix22Scalar);
fMatrix22Scalar.setSkewX(-fMatrix22Scalar.getSkewX());
fMatrix22Scalar.setSkewY(-fMatrix22Scalar.getSkewY());
FT_F26Dot6 scaleX = SkScalarToFDot6(fScale.fX);
FT_F26Dot6 scaleY = SkScalarToFDot6(fScale.fY);
fScaleX = SkScalarToFDot6(fScale.fX);
fScaleY = SkScalarToFDot6(fScale.fY);
fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY());
fMatrix22.xy = SkScalarToFixed(fMatrix22Scalar.getSkewX());
fMatrix22.yx = SkScalarToFixed(fMatrix22Scalar.getSkewY());
fMatrix22.yy = SkScalarToFixed(fMatrix22Scalar.getScaleY());
fLCDIsVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
@ -892,7 +900,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
FT_Size size;
FT_Error err = FT_New_Size(ftFace.get(), &size);
if (err != 0) {
SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
SkDEBUGF(("FT_New_Size returned %x for face %s\n", err, ftFace->family_name));
return nullptr;
}
return size;
@ -904,54 +912,39 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
FT_Error err = FT_Activate_Size(ftSize.get());
if (err != 0) {
SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
SkDEBUGF(("FT_Activate_Size(%08x, 0x%x, 0x%x) returned 0x%x\n",
ftFace.get(), fScaleX, fScaleY, err));
return;
}
if (FT_IS_SCALABLE(ftFace)) {
err = FT_Set_Char_Size(ftFace.get(), scaleX, scaleY, 72, 72);
err = FT_Set_Char_Size(ftFace.get(), fScaleX, fScaleY, 72, 72);
if (err != 0) {
SkDEBUGF(("FT_Set_CharSize(%s, %f, %f) returned 0x%x.\n",
ftFace->family_name, fScale.fX, fScale.fY, err));
SkDEBUGF(("FT_Set_CharSize(%08x, 0x%x, 0x%x) returned 0x%x\n",
ftFace.get(), fScaleX, fScaleY, err));
return;
}
FT_Set_Transform(ftFace.get(), &fMatrix22, nullptr);
} else if (FT_HAS_FIXED_SIZES(ftFace)) {
fStrikeIndex = chooseBitmapStrike(ftFace.get(), scaleY);
fStrikeIndex = chooseBitmapStrike(ftFace.get(), fScaleY);
if (fStrikeIndex == -1) {
SkDEBUGF(("No glyphs for font \"%s\" size %f.\n", ftFace->family_name, fScale.fY));
return;
SkDEBUGF(("no glyphs for font \"%s\" size %f?\n",
ftFace->family_name, SkFDot6ToScalar(fScaleY)));
} else {
// FreeType does no provide linear metrics for bitmap fonts.
linearMetrics = false;
// FreeType documentation says:
// FT_LOAD_NO_BITMAP -- Ignore bitmap strikes when loading.
// Bitmap-only fonts ignore this flag.
//
// However, in FreeType 2.5.1 color bitmap only fonts do not ignore this flag.
// Force this flag off for bitmap only fonts.
fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
}
err = FT_Select_Size(ftFace.get(), fStrikeIndex);
if (err != 0) {
SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x.\n",
ftFace->family_name, fStrikeIndex, err));
fStrikeIndex = -1;
return;
}
// A non-ideal size was picked, so recompute the matrix.
// This adjusts for the difference between FT_Set_Char_Size and FT_Select_Size.
fMatrix22Scalar.preScale(fScale.x() / ftFace->size->metrics.x_ppem,
fScale.y() / ftFace->size->metrics.y_ppem);
fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY());
fMatrix22.yy = SkScalarToFixed(fMatrix22Scalar.getScaleY());
// FreeType does not provide linear metrics for bitmap fonts.
linearMetrics = false;
// FreeType documentation says:
// FT_LOAD_NO_BITMAP -- Ignore bitmap strikes when loading.
// Bitmap-only fonts ignore this flag.
//
// However, in FreeType 2.5.1 color bitmap only fonts do not ignore this flag.
// Force this flag off for bitmap only fonts.
fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
} else {
SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFace->family_name, fScale.fY));
return;
SkDEBUGF(("unknown kind of font \"%s\" size %f?\n",
fFace->family_name, SkFDot6ToScalar(fScaleY)));
}
fFTSize = ftSize.release();
@ -980,8 +973,14 @@ FT_Error SkScalerContext_FreeType::setupSize() {
gFTMutex.assertHeld();
FT_Error err = FT_Activate_Size(fFTSize);
if (err != 0) {
SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%s %s, 0x%x, 0x%x) returned 0x%x\n",
fFace->family_name, fFace->style_name, fScaleX, fScaleY, err));
fFTSize = nullptr;
return err;
}
// seems we need to reset this every time (not sure why, but without it
// I get random italics from some other fFTSize)
FT_Set_Transform(fFace, &fMatrix22, nullptr);
return 0;
}
@ -1038,7 +1037,7 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
glyph->fLsbDelta = 0;
const SkScalar advanceScalar = SkFT_FixedToScalar(advance);
glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getScaleX() * advanceScalar);
glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
glyph->fAdvanceY = -SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
return;
}
}
@ -1112,20 +1111,15 @@ void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
}
}
bool SkScalerContext_FreeType::shouldSubpixelBitmap(const SkGlyph& glyph, const SkMatrix& matrix) {
// If subpixel rendering of a bitmap *can* be done.
bool mechanism = fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag &&
(glyph.getSubXFixed() || glyph.getSubYFixed());
inline void scaleGlyphMetrics(SkGlyph& glyph, SkScalar scale) {
glyph.fWidth *= scale;
glyph.fHeight *= scale;
glyph.fTop *= scale;
glyph.fLeft *= scale;
// If subpixel rendering of a bitmap *should* be done.
// 1. If the face is not scalable then always allow subpixel rendering.
// Otherwise, if the font has an 8ppem strike 7 will subpixel render but 8 won't.
// 2. If the matrix is already not identity the bitmap will already be resampled,
// so resampling slightly differently shouldn't make much difference.
bool policy = !FT_IS_SCALABLE(fFace) || !matrix.isIdentity();
return mechanism && policy;
float floatScale = SkScalarToFloat(scale);
glyph.fAdvanceX *= floatScale;
glyph.fAdvanceY *= floatScale;
}
void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
@ -1182,22 +1176,10 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
glyph->fMaskFormat = SkMask::kARGB32_Format;
}
{
SkRect rect = SkRect::MakeXYWH(SkIntToScalar(fFace->glyph->bitmap_left),
-SkIntToScalar(fFace->glyph->bitmap_top),
SkIntToScalar(fFace->glyph->bitmap.width),
SkIntToScalar(fFace->glyph->bitmap.rows));
fMatrix22Scalar.mapRect(&rect);
if (this->shouldSubpixelBitmap(*glyph, fMatrix22Scalar)) {
rect.offset(SkFixedToScalar(glyph->getSubXFixed()),
SkFixedToScalar(glyph->getSubYFixed()));
}
SkIRect irect = rect.roundOut();
glyph->fWidth = SkToU16(irect.width());
glyph->fHeight = SkToU16(irect.height());
glyph->fTop = SkToS16(irect.top());
glyph->fLeft = SkToS16(irect.left());
}
glyph->fWidth = SkToU16(fFace->glyph->bitmap.width);
glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows);
glyph->fTop = -SkToS16(fFace->glyph->bitmap_top);
glyph->fLeft = SkToS16(fFace->glyph->bitmap_left);
break;
default:
@ -1209,7 +1191,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
if (fDoLinearMetrics) {
const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearVertAdvance);
glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getSkewX() * advanceScalar);
glyph->fAdvanceX = -SkScalarToFloat(fMatrix22Scalar.getSkewX() * advanceScalar);
glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getScaleY() * advanceScalar);
} else {
glyph->fAdvanceX = -SkFDot6ToFloat(fFace->glyph->advance.x);
@ -1219,7 +1201,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
if (fDoLinearMetrics) {
const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearHoriAdvance);
glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getScaleX() * advanceScalar);
glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
glyph->fAdvanceY = -SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar);
} else {
glyph->fAdvanceX = SkFDot6ToFloat(fFace->glyph->advance.x);
glyph->fAdvanceY = -SkFDot6ToFloat(fFace->glyph->advance.y);
@ -1231,7 +1213,15 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
}
}
// If the font isn't scalable, scale the metrics from the non-scalable strike.
// This means do not try to scale embedded bitmaps; only scale bitmaps in bitmap only fonts.
if (!FT_IS_SCALABLE(fFace) && !SkScalarNearlyZero(fScale.fY) && fFace->size->metrics.y_ppem) {
// NOTE: both dimensions are scaled by y_ppem. this is WAI.
scaleGlyphMetrics(*glyph, fScale.fY / fFace->size->metrics.y_ppem);
}
#ifdef ENABLE_GLYPH_SPEW
SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY));
SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(), fLoadGlyphFlags, glyph->fWidth));
#endif
}
@ -1257,15 +1247,7 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
}
emboldenIfNeeded(fFace, fFace->glyph);
SkMatrix* bitmapMatrix = &fMatrix22Scalar;
SkMatrix subpixelBitmapMatrix;
if (this->shouldSubpixelBitmap(glyph, *bitmapMatrix)) {
subpixelBitmapMatrix = fMatrix22Scalar;
subpixelBitmapMatrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
SkFixedToScalar(glyph.getSubYFixed()));
bitmapMatrix = &subpixelBitmapMatrix;
}
generateGlyphImage(fFace, glyph, *bitmapMatrix);
generateGlyphImage(fFace, glyph);
}
@ -1321,7 +1303,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* metrics
FT_Face face = fFace;
SkScalar scaleX = fScale.x();
SkScalar scaleY = fScale.y();
SkScalar mxy = -fMatrix22Scalar.getSkewX() * scaleY;
SkScalar mxy = fMatrix22Scalar.getSkewX() * scaleY;
SkScalar myy = fMatrix22Scalar.getScaleY() * scaleY;
// fetch units/EM from "head" table if needed (ie for bitmap fonts)

View File

@ -334,11 +334,7 @@ inline SkColorType SkColorType_for_SkMaskFormat(SkMask::Format format) {
}
}
void SkScalerContext_FreeType_Base::generateGlyphImage(
FT_Face face,
const SkGlyph& glyph,
const SkMatrix& bitmapTransform)
{
void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
@ -415,7 +411,11 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(
}
// If no scaling needed, directly copy glyph bitmap.
if (bitmapTransform.isIdentity()) {
if (glyph.fWidth == face->glyph->bitmap.width &&
glyph.fHeight == face->glyph->bitmap.rows &&
glyph.fTop == -face->glyph->bitmap_top &&
glyph.fLeft == face->glyph->bitmap_left)
{
SkMask dstMask;
glyph.toMask(&dstMask);
copyFTBitmap(face->glyph->bitmap, dstMask);
@ -426,7 +426,6 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(
// Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
SkBitmap unscaledBitmap;
// TODO: mark this as sRGB when the blits will be sRGB.
unscaledBitmap.allocPixels(SkImageInfo::Make(face->glyph->bitmap.width,
face->glyph->bitmap.rows,
SkColorType_for_FTPixelMode(pixel_mode),
@ -448,7 +447,6 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(
bitmapRowBytes = glyph.rowBytes();
}
SkBitmap dstBitmap;
// TODO: mark this as sRGB when the blits will be sRGB.
dstBitmap.setInfo(SkImageInfo::Make(glyph.fWidth, glyph.fHeight,
SkColorType_for_SkMaskFormat(maskFormat),
kPremul_SkAlphaType),
@ -461,15 +459,9 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(
// Scale unscaledBitmap into dstBitmap.
SkCanvas canvas(dstBitmap);
#ifdef SK_SHOW_TEXT_BLIT_COVERAGE
canvas.clear(0x33FF0000);
#else
canvas.clear(SK_ColorTRANSPARENT);
#endif
canvas.translate(-glyph.fLeft, -glyph.fTop);
canvas.concat(bitmapTransform);
canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
canvas.scale(SkIntToScalar(glyph.fWidth) / SkIntToScalar(face->glyph->bitmap.width),
SkIntToScalar(glyph.fHeight) / SkIntToScalar(face->glyph->bitmap.rows));
SkPaint paint;
paint.setFilterQuality(kMedium_SkFilterQuality);
canvas.drawBitmap(unscaledBitmap, 0, 0, &paint);

View File

@ -31,8 +31,9 @@ protected:
: INHERITED(typeface, effects, desc)
{}
void generateGlyphImage(FT_Face face, const SkGlyph& glyph, const SkMatrix& bitmapTransform);
void generateGlyphImage(FT_Face face, const SkGlyph& glyph);
void generateGlyphPath(FT_Face face, SkPath* path);
private:
typedef SkScalerContext INHERITED;
};