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:
parent
e0e71afc66
commit
8ff8a1959f
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user