Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Unified Diff: src/ports/SkFontHost_FreeType.cpp

Issue 2139703002: Rotate emoji with FreeType. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Modify subpixel condition. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/ports/SkFontHost_FreeType_common.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ports/SkFontHost_FreeType.cpp
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 2e0b8b6ee371abc703bd1c5db8bb336cceef9eda..856b7332fba96e9f82a2c090d39f283cbaf2b1f9 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -197,18 +197,23 @@ protected:
SkUnichar generateGlyphToChar(uint16_t glyph) override;
private:
- 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;
-
- // Need scalar versions for generateFontMetrics
- SkVector fScale;
- SkMatrix fMatrix22Scalar;
+ FT_Face fFace; // Shared face from gFaceRecHead.
+ FT_Size fFTSize; // The size on the fFace for this scaler.
+ FT_Int fStrikeIndex;
+
+ /** 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;
FT_Error setupSize();
void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox,
@@ -219,6 +224,7 @@ 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&);
};
///////////////////////////////////////////////////////////////////////////
@@ -747,47 +753,35 @@ 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;
}
- // determine target ppem
- FT_Pos targetPPEM = scaleY;
- // find a bitmap strike equal to or just larger than the requested size
+
+ FT_Pos requestedPPEM = scaleY; // FT_Bitmap_Size::y_ppem is in 26.6 format.
FT_Int chosenStrikeIndex = -1;
FT_Pos chosenPPEM = 0;
for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) {
- FT_Pos thisPPEM = face->available_sizes[strikeIndex].y_ppem;
- if (thisPPEM == targetPPEM) {
+ FT_Pos strikePPEM = face->available_sizes[strikeIndex].y_ppem;
+ if (strikePPEM == requestedPPEM) {
// exact match - our search stops here
- chosenPPEM = thisPPEM;
- chosenStrikeIndex = strikeIndex;
- break;
- } else if (chosenPPEM < targetPPEM) {
+ return strikeIndex;
+ } else if (chosenPPEM < requestedPPEM) {
// attempt to increase chosenPPEM
- if (thisPPEM > chosenPPEM) {
- chosenPPEM = thisPPEM;
+ if (chosenPPEM < strikePPEM) {
+ chosenPPEM = strikePPEM;
chosenStrikeIndex = strikeIndex;
}
} else {
- // attempt to decrease chosenPPEM, but not below targetPPEM
- if (thisPPEM < chosenPPEM && thisPPEM > targetPPEM) {
- chosenPPEM = thisPPEM;
+ // attempt to decrease chosenPPEM, but not below requestedPPEM
+ if (requestedPPEM < strikePPEM && strikePPEM < chosenPPEM) {
+ chosenPPEM = strikePPEM;
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;
}
@@ -814,14 +808,12 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
}
fRec.computeMatrices(SkScalerContextRec::kFull_PreMatrixScale, &fScale, &fMatrix22Scalar);
- fMatrix22Scalar.setSkewX(-fMatrix22Scalar.getSkewX());
- fMatrix22Scalar.setSkewY(-fMatrix22Scalar.getSkewY());
- fScaleX = SkScalarToFDot6(fScale.fX);
- fScaleY = SkScalarToFDot6(fScale.fY);
+ FT_F26Dot6 scaleX = SkScalarToFDot6(fScale.fX);
+ FT_F26Dot6 scaleY = 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);
@@ -900,7 +892,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 returned %x for face %s\n", err, ftFace->family_name));
+ SkDEBUGF(("FT_New_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
return nullptr;
}
return size;
@@ -912,39 +904,54 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
FT_Error err = FT_Activate_Size(ftSize.get());
if (err != 0) {
- SkDEBUGF(("FT_Activate_Size(%08x, 0x%x, 0x%x) returned 0x%x\n",
- ftFace.get(), fScaleX, fScaleY, err));
+ SkDEBUGF(("FT_Activate_Size(%s) returned 0x%x.\n", ftFace->family_name, err));
return;
}
if (FT_IS_SCALABLE(ftFace)) {
- err = FT_Set_Char_Size(ftFace.get(), fScaleX, fScaleY, 72, 72);
+ err = FT_Set_Char_Size(ftFace.get(), scaleX, scaleY, 72, 72);
if (err != 0) {
- SkDEBUGF(("FT_Set_CharSize(%08x, 0x%x, 0x%x) returned 0x%x\n",
- ftFace.get(), fScaleX, fScaleY, err));
+ SkDEBUGF(("FT_Set_CharSize(%s, %f, %f) returned 0x%x.\n",
+ ftFace->family_name, fScale.fX, fScale.fY, err));
return;
}
- FT_Set_Transform(ftFace.get(), &fMatrix22, nullptr);
} else if (FT_HAS_FIXED_SIZES(ftFace)) {
- fStrikeIndex = chooseBitmapStrike(ftFace.get(), fScaleY);
+ fStrikeIndex = chooseBitmapStrike(ftFace.get(), scaleY);
if (fStrikeIndex == -1) {
- 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;
+ SkDEBUGF(("No glyphs for font \"%s\" size %f.\n", ftFace->family_name, fScale.fY));
+ return;
}
+
+ 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, SkFDot6ToScalar(fScaleY)));
+ SkDEBUGF(("Unknown kind of font \"%s\" size %f.\n", fFace->family_name, fScale.fY));
+ return;
}
fFTSize = ftSize.release();
@@ -973,14 +980,8 @@ 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;
}
@@ -1037,7 +1038,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;
}
}
@@ -1111,15 +1112,13 @@ void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
}
}
-inline void scaleGlyphMetrics(SkGlyph& glyph, SkScalar scale) {
- glyph.fWidth *= scale;
- glyph.fHeight *= scale;
- glyph.fTop *= scale;
- glyph.fLeft *= scale;
-
- float floatScale = SkScalarToFloat(scale);
- glyph.fAdvanceX *= floatScale;
- glyph.fAdvanceY *= floatScale;
+bool SkScalerContext_FreeType::shouldSubpixelBitmap(const SkGlyph& glyph, const SkMatrix& matrix) {
+ // Do subpixel on bitmaps if glyph is bitmap and subpixel requested and
+ // (font has no outlines or already transforming bitmap).
mtklein 2016/07/15 21:08:48 might help to explain each of the subtle two heuri
bungeman-skia 2016/07/15 21:30:29 Done.
mtklein 2016/07/15 22:38:17 Thanks! This is awesome.
+ return fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
+ fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag &&
+ (glyph.getSubXFixed() || glyph.getSubYFixed()) &&
+ (!FT_IS_SCALABLE(fFace) || !matrix.isIdentity());
}
void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
@@ -1176,10 +1175,22 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
glyph->fMaskFormat = SkMask::kARGB32_Format;
}
- 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);
+ {
+ 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());
+ }
break;
default:
@@ -1191,7 +1202,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);
@@ -1201,7 +1212,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);
@@ -1213,15 +1224,7 @@ 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
}
@@ -1247,7 +1250,15 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
}
emboldenIfNeeded(fFace, fFace->glyph);
- generateGlyphImage(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);
}
@@ -1303,7 +1314,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)
« no previous file with comments | « no previous file | src/ports/SkFontHost_FreeType_common.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698