diff --git a/gm/verttext.cpp b/gm/verttext.cpp index 67a2da59c6..1471cbce9c 100644 --- a/gm/verttext.cpp +++ b/gm/verttext.cpp @@ -8,16 +8,32 @@ #include "gm.h" #include "SkCanvas.h" +#include "SkTypeface.h" namespace skiagm { #define TEXT_SIZE 48 static const char gText[] = "Hello"; + +//Before shaping +//static const char gText[] = "「テスト。」"; +//static const char gText[] = {0xE3,0x80,0x8C, 0xE3,0x83,0x86, 0xE3,0x82,0xB9, 0xE3,0x83,0x88, 0xE3,0x80,0x82, 0xE3,0x80,0x8D, 0x0}; + +//After shaping +//static const char gText[] = "﹁テスト︒﹂"; +//static const char gText[] = {0xEF,0xB9,0x81, 0xE3,0x83,0x86, 0xE3,0x82,0xB9, 0xE3,0x83,0x88, 0xEF,0xB8,0x92, 0xEF,0xB9,0x82, 0x0}; + static const size_t gLen = sizeof(gText) - 1; class VertTextGM : public GM { public: - VertTextGM() {} + VertTextGM() + // : fFace(SkTypeface::CreateFromName("unifont", SkTypeface::kNormal)) + // : fFace(SkTypeface::CreateFromFile("MotoyaL04Mincho_3.ttf")) + { + } + + //SkAutoTUnref fFace; protected: @@ -58,10 +74,11 @@ protected: SkScalar y = SkIntToScalar(50); for (int i = 0; i < 4; ++i) { - SkPaint paint; + SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(SkIntToScalar(TEXT_SIZE)); - + //paint.setTypeface(fFace); + //paint.setFakeBoldText(true); paint.setVerticalText(false); drawBaseline(canvas, paint, x, y); diff --git a/src/core/SkFDot6.h b/src/core/SkFDot6.h index aa588572f8..9b8e4d05ad 100644 --- a/src/core/SkFDot6.h +++ b/src/core/SkFDot6.h @@ -10,6 +10,7 @@ #ifndef SkFDot6_DEFINED #define SkFDot6_DEFINED +#include "SkScalar.h" #include "SkMath.h" typedef int32_t SkFDot6; @@ -40,8 +41,10 @@ inline SkFixed SkFDot6ToFixed(SkFDot6 x) { #ifdef SK_SCALAR_IS_FLOAT #define SkScalarToFDot6(x) (SkFDot6)((x) * 64) + #define SkFDot6ToScalar(x) ((SkScalar)(x) * SkFloatToScalar(0.015625f)) #else #define SkScalarToFDot6(x) ((x) >> 10) + #define SkFDot6ToScalar(x) ((x) << 10) #endif inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) { diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 0f3dded50c..4f036a81e8 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -830,6 +830,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) // See http://code.google.com/p/skia/issues/detail?id=222. loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + // Use vertical layout if requested. + if (fRec.fFlags & SkScalerContext::kVertical_Flag) { + loadFlags |= FT_LOAD_VERTICAL_LAYOUT; + } + fLoadGlyphFlags = loadFlags; fDoLinearMetrics = linearMetrics; } @@ -982,6 +987,20 @@ void SkScalerContext_FreeType::getBBoxForCurrentGlyph(SkGlyph* glyph, bbox->xMax = (bbox->xMax + 63) & ~63; bbox->yMax = (bbox->yMax + 63) & ~63; } + + // Must come after snapToPixelBoundary so that the width and height are + // consistent. Otherwise asserts will fire later on when generating the + // glyph image. + if (fRec.fFlags & SkScalerContext::kVertical_Flag) { + FT_Vector vector; + vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX; + vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY; + FT_Vector_Transform(&vector, &fMatrix22); + bbox->xMin += vector.x; + bbox->xMax += vector.x; + bbox->yMin += vector.y; + bbox->yMax += vector.y; + } } void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) { @@ -1026,8 +1045,6 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { return; } - SkFixed vLeft = 0, vTop = 0; - switch ( fFace->glyph->format ) { case FT_GLYPH_FORMAT_OUTLINE: { FT_BBox bbox; @@ -1046,15 +1063,10 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { getBBoxForCurrentGlyph(glyph, &bbox, true); - glyph->fWidth = SkToU16((bbox.xMax - bbox.xMin) >> 6); - glyph->fHeight = SkToU16((bbox.yMax - bbox.yMin) >> 6); - glyph->fTop = -SkToS16(bbox.yMax >> 6); - glyph->fLeft = SkToS16(bbox.xMin >> 6); - - if ((fRec.fFlags & SkScalerContext::kVertical_Flag)) { - vLeft = SkFDot6ToFixed(bbox.xMin); - vTop = SkFDot6ToFixed(bbox.yMax); - } + glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin)); + glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin)); + glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax)); + glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin)); updateGlyphIfLCD(glyph); @@ -1066,6 +1078,16 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { FT_GlyphSlot_Own_Bitmap(fFace->glyph); FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0); } + + if (fRec.fFlags & SkScalerContext::kVertical_Flag) { + FT_Vector vector; + vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX; + vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY; + FT_Vector_Transform(&vector, &fMatrix22); + fFace->glyph->bitmap_left += SkFDot6Floor(vector.x); + fFace->glyph->bitmap_top += SkFDot6Floor(vector.y); + } + glyph->fWidth = SkToU16(fFace->glyph->bitmap.width); glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows); glyph->fTop = -SkToS16(fFace->glyph->bitmap_top); @@ -1077,72 +1099,27 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { goto ERROR; } - if (fDoLinearMetrics) { - glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdvance); - glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance); + if (fRec.fFlags & SkScalerContext::kVertical_Flag) { + if (fDoLinearMetrics) { + glyph->fAdvanceX = -SkFixedMul(fMatrix22.xy, fFace->glyph->linearVertAdvance); + glyph->fAdvanceY = SkFixedMul(fMatrix22.yy, fFace->glyph->linearVertAdvance); + } else { + glyph->fAdvanceX = -SkFDot6ToFixed(fFace->glyph->advance.x); + glyph->fAdvanceY = SkFDot6ToFixed(fFace->glyph->advance.y); + } } else { - glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x); - glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y); + if (fDoLinearMetrics) { + glyph->fAdvanceX = SkFixedMul(fMatrix22.xx, fFace->glyph->linearHoriAdvance); + glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance); + } else { + glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x); + glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y); - if (fRec.fFlags & kDevKernText_Flag) { - glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta); - glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta); - } - } - - if ((fRec.fFlags & SkScalerContext::kVertical_Flag) - && fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { - - //TODO: do we need to specially handle SubpixelPositioning and Kerning? - - FT_Matrix identityMatrix; - identityMatrix.xx = identityMatrix.yy = SK_Fixed1; - identityMatrix.xy = identityMatrix.yx = 0; - - // if the matrix is not the identity matrix then we need to re-load the - // glyph with the identity matrix to get the necessary bounding box - if (memcmp(&fMatrix22, &identityMatrix, sizeof(FT_Matrix)) != 0) { - - FT_Set_Transform(fFace, &identityMatrix, NULL); - - err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags ); - if (err != 0) { - SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n", - fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err)); - goto ERROR; - } - - if (fRec.fFlags & kEmbolden_Flag) { - emboldenOutline(fFace, &fFace->glyph->outline); + if (fRec.fFlags & kDevKernText_Flag) { + glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta); + glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta); } } - - // bounding box of the unskewed and unscaled glyph - FT_BBox bbox = {0, 0, 0, 0}; // Suppress Coverity warning. - getBBoxForCurrentGlyph(glyph, &bbox); - - // compute the vertical gap above and below the glyph if the glyph were - // centered within the linearVertAdvance - 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 + SkFDot6ToFixed(bbox.yMax); - - // transform the vertical origin based on the matrix of the actual glyph - FT_Vector_Transform(&vOrigin, &fMatrix22); - - // compute a new offset vector for the glyph by subtracting the vertical - // origin from the original horizontal offset vector - glyph->fLeft = SkFixedRoundToInt(vLeft - vOrigin.x); - glyph->fTop = -SkFixedRoundToInt(vTop - vOrigin.y); - - updateGlyphPosIfLCD(glyph); - - // use the vertical advance values computed by freetype - glyph->fAdvanceX = -SkFixedMul(fMatrix22.xy, fFace->glyph->linearVertAdvance); - glyph->fAdvanceY = SkFixedMul(fMatrix22.yy, fFace->glyph->linearVertAdvance); } @@ -1200,6 +1177,16 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, } generateGlyphPath(fFace, glyph, path); + + // The path's origin from FreeType is always the horizontal layout origin. + // Offset the path so that it is relative to the vertical origin if needed. + if (fRec.fFlags & SkScalerContext::kVertical_Flag) { + FT_Vector vector; + vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX; + vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY; + FT_Vector_Transform(&vector, &fMatrix22); + path->offset(SkFDot6ToScalar(vector.x), -SkFDot6ToScalar(vector.y)); + } } void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, diff --git a/src/ports/SkFontHost_FreeType_common.cpp b/src/ports/SkFontHost_FreeType_common.cpp index 332b8c47b8..3a827d70bc 100644 --- a/src/ports/SkFontHost_FreeType_common.cpp +++ b/src/ports/SkFontHost_FreeType_common.cpp @@ -119,46 +119,6 @@ static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap, } } -/////////////////////////////////////////////////////////////////////////////// - -#define ft2sk(x) SkFixedToScalar(SkFDot6ToFixed(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; -} - -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_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) @@ -313,6 +273,38 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, #endif } +/////////////////////////////////////////////////////////////////////////////// + +static int move_proc(const FT_Vector* pt, void* ctx) { + SkPath* path = (SkPath*)ctx; + path->close(); // to close the previous contour (if any) + path->moveTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); + return 0; +} + +static int line_proc(const FT_Vector* pt, void* ctx) { + SkPath* path = (SkPath*)ctx; + path->lineTo(SkFDot6ToScalar(pt->x), -SkFDot6ToScalar(pt->y)); + return 0; +} + +static int quad_proc(const FT_Vector* pt0, const FT_Vector* pt1, + void* ctx) { + SkPath* path = (SkPath*)ctx; + path->quadTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), + SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y)); + return 0; +} + +static int cubic_proc(const FT_Vector* pt0, const FT_Vector* pt1, + const FT_Vector* pt2, void* ctx) { + SkPath* path = (SkPath*)ctx; + path->cubicTo(SkFDot6ToScalar(pt0->x), -SkFDot6ToScalar(pt0->y), + SkFDot6ToScalar(pt1->x), -SkFDot6ToScalar(pt1->y), + SkFDot6ToScalar(pt2->x), -SkFDot6ToScalar(pt2->y)); + return 0; +} + void SkScalerContext_FreeType_Base::generateGlyphPath(FT_Face face, const SkGlyph& glyph, SkPath* path)