diff options
author | george@mozilla.com <george@mozilla.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-23 00:39:08 +0000 |
---|---|---|
committer | george@mozilla.com <george@mozilla.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-23 00:39:08 +0000 |
commit | c59b5dac9081e3613ed80d8b6d498e093c03eb87 (patch) | |
tree | 8fdc4dc1a81494510be4aea136691b45e8bbbde6 /src/ports/SkFontHost_FreeType.cpp | |
parent | 55ed83db1b9d3d1187f59c9db9f225b0f1d56327 (diff) |
Split out SkFontHost_FreeType into common files
Review URL: https://codereview.appspot.com/6442092
git-svn-id: http://skia.googlecode.com/svn/trunk@5246 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/ports/SkFontHost_FreeType.cpp')
-rw-r--r-- | src/ports/SkFontHost_FreeType.cpp | 361 |
1 files changed, 14 insertions, 347 deletions
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 497a259a5b..550fae01b2 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -6,7 +6,6 @@ * found in the LICENSE file. */ - #include "SkBitmap.h" #include "SkCanvas.h" #include "SkColorPriv.h" @@ -14,6 +13,7 @@ #include "SkFDot6.h" #include "SkFloatingPoint.h" #include "SkFontHost.h" +#include "SkFontHost_FreeType_common.h" #include "SkGlyph.h" #include "SkMask.h" #include "SkMaskGamma.h" @@ -59,16 +59,6 @@ //#define SK_GAMMA_APPLY_TO_A8 -#ifdef SK_DEBUG - #define SkASSERT_CONTINUE(pred) \ - do { \ - if (!(pred)) \ - SkDebugf("file %s:%d: assert failed '" #pred "'\n", __FILE__, __LINE__); \ - } while (false) -#else - #define SkASSERT_CONTINUE(pred) -#endif - using namespace skia_advanced_typeface_metrics_utils; static bool isLCD(const SkScalerContext::Rec& rec) { @@ -95,15 +85,6 @@ static int gLCDExtra; // number of extra pixels for filtering. ///////////////////////////////////////////////////////////////////////// -// See http://freetype.sourceforge.net/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden -// This value was chosen by eyeballing the result in Firefox and trying to match it. -static const FT_Pos kBitmapEmboldenStrength = 1 << 6; - -// convert from Skia's fixed (16.16) to FreeType's fixed (26.6) representation -static inline int FixedToDot6(SkFixed x) { return x >> 10; } -// convert from FreeType's fixed (26.6) to Skia's fixed (16.16) representation -static inline SkFixed Dot6ToFixed(int x) { return x << 10; } - static bool InitFreetype() { FT_Error err = FT_Init_FreeType(&gFTLibrary); @@ -128,7 +109,7 @@ InitFreetype() { return true; } -class SkScalerContext_FreeType : public SkScalerContext { +class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { public: SkScalerContext_FreeType(const SkDescriptor* desc); virtual ~SkScalerContext_FreeType(); @@ -161,7 +142,6 @@ private: bool fLCDIsVert; FT_Error setupSize(); - void emboldenOutline(FT_Outline* outline); void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox, bool snapToPixelBoundary = false); void updateGlyphIfLCD(SkGlyph* glyph); @@ -684,7 +664,7 @@ uint32_t SkFontHost::GetUnitsPerEm(SkFontID fontID) { #endif SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) - : SkScalerContext(desc) { + : SkScalerContext_FreeType_Base(desc) { SkAutoMutexAcquire ac(gFTMutex); if (gFTCount == 0) { @@ -875,13 +855,6 @@ FT_Error SkScalerContext_FreeType::setupSize() { return err; } -void SkScalerContext_FreeType::emboldenOutline(FT_Outline* outline) { - FT_Pos strength; - strength = FT_MulFix(fFace->units_per_EM, fFace->size->metrics.y_scale) - / 24; - FT_Outline_Embolden(outline, strength); -} - unsigned SkScalerContext_FreeType::generateGlyphCount() { return fFace->num_glyphs; } @@ -905,16 +878,6 @@ SkUnichar SkScalerContext_FreeType::generateGlyphToChar(uint16_t glyph) { return 0; } -static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) { - switch (format) { - case SkMask::kBW_Format: - return FT_PIXEL_MODE_MONO; - case SkMask::kA8_Format: - default: - return FT_PIXEL_MODE_GRAY; - } -} - void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) { #ifdef FT_ADVANCES_H /* unhinted and light hinted text have linearly scaled advances @@ -955,8 +918,8 @@ void SkScalerContext_FreeType::getBBoxForCurrentGlyph(SkGlyph* glyph, FT_Outline_Get_CBox(&fFace->glyph->outline, bbox); if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { - int dx = FixedToDot6(glyph->getSubXFixed()); - int dy = FixedToDot6(glyph->getSubYFixed()); + int dx = SkFixedToFDot6(glyph->getSubXFixed()); + int dy = SkFixedToFDot6(glyph->getSubYFixed()); // negate dy since freetype-y-goes-up and skia-y-goes-down bbox->xMin += dx; bbox->yMin -= dy; @@ -1030,7 +993,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { } if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(&fFace->glyph->outline); + emboldenOutline(fFace, &fFace->glyph->outline); } getBBoxForCurrentGlyph(glyph, &bbox, true); @@ -1041,8 +1004,8 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { glyph->fLeft = SkToS16(bbox.xMin >> 6); if ((fRec.fFlags & SkScalerContext::kVertical_Flag)) { - vLeft = Dot6ToFixed(bbox.xMin); - vTop = Dot6ToFixed(bbox.yMax); + vLeft = SkFDot6ToFixed(bbox.xMin); + vTop = SkFDot6ToFixed(bbox.yMax); } updateGlyphIfLCD(glyph); @@ -1102,7 +1065,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { } if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(&fFace->glyph->outline); + emboldenOutline(fFace, &fFace->glyph->outline); } } @@ -1112,12 +1075,12 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { // compute the vertical gap above and below the glyph if the glyph were // centered within the linearVertAdvance - SkFixed vGap = (fFace->glyph->linearVertAdvance - Dot6ToFixed(bbox.yMax - bbox.yMin)) / 2; + SkFixed vGap = (fFace->glyph->linearVertAdvance - SkFDot6ToFixed(bbox.yMax - bbox.yMin)) / 2; // the origin point of the glyph when rendered vertically FT_Vector vOrigin; vOrigin.x = fFace->glyph->linearHoriAdvance / 2; - vOrigin.y = vGap + Dot6ToFixed(bbox.yMax); + vOrigin.y = vGap + SkFDot6ToFixed(bbox.yMax); // transform the vertical origin based on the matrix of the actual glyph FT_Vector_Transform(&vOrigin, &fMatrix22); @@ -1141,97 +1104,6 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { #endif } -/////////////////////////////////////////////////////////////////////////////// - -static uint16_t packTriple(unsigned r, unsigned g, unsigned b) { - return SkPackRGB16(r >> 3, g >> 2, b >> 3); -} - -static uint16_t grayToRGB16(U8CPU gray) { - SkASSERT(gray <= 255); - return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3); -} - -static int bittst(const uint8_t data[], int bitOffset) { - SkASSERT(bitOffset >= 0); - int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7); - return lowBit & 1; -} - -template<bool APPLY_PREBLEND> -static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap, - int lcdIsBGR, bool lcdIsVert, const uint8_t* tableR, - const uint8_t* tableG, const uint8_t* tableB) { - if (lcdIsVert) { - SkASSERT(3 * glyph.fHeight == bitmap.rows); - } else { - SkASSERT(glyph.fHeight == bitmap.rows); - } - - uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage); - const size_t dstRB = glyph.rowBytes(); - const int width = glyph.fWidth; - const uint8_t* src = bitmap.buffer; - - switch (bitmap.pixel_mode) { - case FT_PIXEL_MODE_MONO: { - for (int y = 0; y < glyph.fHeight; ++y) { - for (int x = 0; x < width; ++x) { - dst[x] = -bittst(src, x); - } - dst = (uint16_t*)((char*)dst + dstRB); - src += bitmap.pitch; - } - } break; - case FT_PIXEL_MODE_GRAY: { - for (int y = 0; y < glyph.fHeight; ++y) { - for (int x = 0; x < width; ++x) { - dst[x] = grayToRGB16(src[x]); - } - dst = (uint16_t*)((char*)dst + dstRB); - src += bitmap.pitch; - } - } break; - default: { - SkASSERT(lcdIsVert || (glyph.fWidth * 3 == bitmap.width)); - for (int y = 0; y < glyph.fHeight; y++) { - if (lcdIsVert) { // vertical stripes - const uint8_t* srcR = src; - const uint8_t* srcG = srcR + bitmap.pitch; - const uint8_t* srcB = srcG + bitmap.pitch; - if (lcdIsBGR) { - SkTSwap(srcR, srcB); - } - for (int x = 0; x < width; x++) { - dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(*srcR++, tableR), - sk_apply_lut_if<APPLY_PREBLEND>(*srcG++, tableG), - sk_apply_lut_if<APPLY_PREBLEND>(*srcB++, tableB)); - } - src += 3 * bitmap.pitch; - } else { // horizontal stripes - const uint8_t* triple = src; - if (lcdIsBGR) { - for (int x = 0; x < width; x++) { - dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableR), - sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG), - sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableB)); - triple += 3; - } - } else { - for (int x = 0; x < width; x++) { - dst[x] = packTriple(sk_apply_lut_if<APPLY_PREBLEND>(triple[0], tableR), - sk_apply_lut_if<APPLY_PREBLEND>(triple[1], tableG), - sk_apply_lut_if<APPLY_PREBLEND>(triple[2], tableB)); - triple += 3; - } - } - src += bitmap.pitch; - } - dst = (uint16_t*)((char*)dst + dstRB); - } - } break; - } -} void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) { SkAutoMutexAcquire ac(gFTMutex); @@ -1251,192 +1123,9 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, SkMaskGamma:: return; } - //Must be careful not to use these if maskPreBlend == NULL - const uint8_t* tableR = NULL; - const uint8_t* tableG = NULL; - const uint8_t* tableB = NULL; - if (maskPreBlend) { - tableR = maskPreBlend->fR; - tableG = maskPreBlend->fG; - tableB = maskPreBlend->fB; - } - - const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag); - const bool doVert = fLCDIsVert; - - switch ( fFace->glyph->format ) { - case FT_GLYPH_FORMAT_OUTLINE: { - FT_Outline* outline = &fFace->glyph->outline; - FT_BBox bbox; - FT_Bitmap target; - - if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(outline); - } - - int dx = 0, dy = 0; - if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { - dx = FixedToDot6(glyph.getSubXFixed()); - dy = FixedToDot6(glyph.getSubYFixed()); - // negate dy since freetype-y-goes-up and skia-y-goes-down - dy = -dy; - } - FT_Outline_Get_CBox(outline, &bbox); - /* - what we really want to do for subpixel is - offset(dx, dy) - compute_bounds - offset(bbox & !63) - but that is two calls to offset, so we do the following, which - achieves the same thing with only one offset call. - */ - FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63), - dy - ((bbox.yMin + dy) & ~63)); - - if (SkMask::kLCD16_Format == glyph.fMaskFormat) { - FT_Render_Glyph(fFace->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD); - if (maskPreBlend) { - copyFT2LCD16<true>(glyph, fFace->glyph->bitmap, doBGR, doVert, - tableR, tableG, tableB); - } else { - copyFT2LCD16<false>(glyph, fFace->glyph->bitmap, doBGR, doVert, - tableR, tableG, tableB); - } - } else { - target.width = glyph.fWidth; - target.rows = glyph.fHeight; - target.pitch = glyph.rowBytes(); - target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage); - target.pixel_mode = compute_pixel_mode( - (SkMask::Format)fRec.fMaskFormat); - target.num_grays = 256; - - memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); - FT_Outline_Get_Bitmap(gFTLibrary, outline, &target); - } - } break; - - case FT_GLYPH_FORMAT_BITMAP: { - if (fRec.fFlags & kEmbolden_Flag) { - FT_GlyphSlot_Own_Bitmap(fFace->glyph); - FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0); - } - SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width); - SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows); - SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top); - SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left); - - const uint8_t* src = (const uint8_t*)fFace->glyph->bitmap.buffer; - uint8_t* dst = (uint8_t*)glyph.fImage; - - if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY || - (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && - glyph.fMaskFormat == SkMask::kBW_Format)) { - unsigned srcRowBytes = fFace->glyph->bitmap.pitch; - unsigned dstRowBytes = glyph.rowBytes(); - unsigned minRowBytes = SkMin32(srcRowBytes, dstRowBytes); - unsigned extraRowBytes = dstRowBytes - minRowBytes; - - for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y) { - memcpy(dst, src, minRowBytes); - memset(dst + minRowBytes, 0, extraRowBytes); - src += srcRowBytes; - dst += dstRowBytes; - } - } else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && - glyph.fMaskFormat == SkMask::kA8_Format) { - for (int y = 0; y < fFace->glyph->bitmap.rows; ++y) { - uint8_t byte = 0; - int bits = 0; - const uint8_t* src_row = src; - uint8_t* dst_row = dst; - - for (int x = 0; x < fFace->glyph->bitmap.width; ++x) { - if (!bits) { - byte = *src_row++; - bits = 8; - } - - *dst_row++ = byte & 0x80 ? 0xff : 0; - bits--; - byte <<= 1; - } - - src += fFace->glyph->bitmap.pitch; - dst += glyph.rowBytes(); - } - } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { - if (maskPreBlend) { - copyFT2LCD16<true>(glyph, fFace->glyph->bitmap, doBGR, doVert, - tableR, tableG, tableB); - } else { - copyFT2LCD16<false>(glyph, fFace->glyph->bitmap, doBGR, doVert, - tableR, tableG, tableB); - } - } else { - SkDEBUGFAIL("unknown glyph bitmap transform needed"); - } - } break; - - default: - SkDEBUGFAIL("unknown glyph format"); - goto ERROR; - } - -// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum, -// it is optional -#if defined(SK_GAMMA_APPLY_TO_A8) - if (SkMask::kA8_Format == glyph.fMaskFormat && maskPreBlend) { - uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; - unsigned rowBytes = glyph.rowBytes(); - - for (int y = glyph.fHeight - 1; y >= 0; --y) { - for (int x = glyph.fWidth - 1; x >= 0; --x) { - dst[x] = tableG[dst[x]]; - } - dst += rowBytes; - } - } -#endif -} - -/////////////////////////////////////////////////////////////////////////////// - -#define ft2sk(x) SkFixedToScalar(Dot6ToFixed(x)) - -#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 2 - #define CONST_PARAM const -#else // older freetype doesn't use const here - #define CONST_PARAM -#endif - -static int move_proc(CONST_PARAM FT_Vector* pt, void* ctx) { - SkPath* path = (SkPath*)ctx; - path->close(); // to close the previous contour (if any) - path->moveTo(ft2sk(pt->x), -ft2sk(pt->y)); - return 0; -} - -static int line_proc(CONST_PARAM FT_Vector* pt, void* ctx) { - SkPath* path = (SkPath*)ctx; - path->lineTo(ft2sk(pt->x), -ft2sk(pt->y)); - return 0; -} - -static int quad_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, - void* ctx) { - SkPath* path = (SkPath*)ctx; - path->quadTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y)); - return 0; + generateGlyphImage(fFace, glyph, maskPreBlend); } -static int cubic_proc(CONST_PARAM FT_Vector* pt0, CONST_PARAM FT_Vector* pt1, - CONST_PARAM FT_Vector* pt2, void* ctx) { - SkPath* path = (SkPath*)ctx; - path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), - -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y)); - return 0; -} void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path) { @@ -1462,29 +1151,7 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, return; } - if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(&fFace->glyph->outline); - } - - FT_Outline_Funcs funcs; - - funcs.move_to = move_proc; - funcs.line_to = line_proc; - funcs.conic_to = quad_proc; - funcs.cubic_to = cubic_proc; - funcs.shift = 0; - funcs.delta = 0; - - err = FT_Outline_Decompose(&fFace->glyph->outline, &funcs, path); - - if (err != 0) { - SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n", - glyph.getGlyphID(fBaseGlyphCount), flags, err)); - path->reset(); - return; - } - - path->close(); + generateGlyphPath(fFace, glyph, path); } void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, @@ -1545,7 +1212,7 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, FT_BBox bbox; FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags); if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(&fFace->glyph->outline); + emboldenOutline(fFace, &fFace->glyph->outline); } FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); x_height = SkFixedToScalar(SkFDot6ToFixed(bbox.yMax)); |