Vertical metrics for FreeType.

https://codereview.appspot.com/6554064/


git-svn-id: http://skia.googlecode.com/svn/trunk@5677 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bungeman@google.com 2012-09-25 20:38:28 +00:00
parent e0e71afc66
commit 8ff8a1959f
4 changed files with 115 additions and 116 deletions

View File

@ -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<SkTypeface> 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);

View File

@ -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) {

View File

@ -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,

View File

@ -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)