prototype for kerning api

BUG=
R=bungeman@google.com

Review URL: https://codereview.chromium.org/29363009

git-svn-id: http://skia.googlecode.com/svn/trunk@12018 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2013-10-30 15:07:03 +00:00
parent b08c707847
commit 35fe7372b1
5 changed files with 146 additions and 6 deletions

View File

@ -74,6 +74,64 @@ private:
///////////////////////////////////////////////////////////////////////////////
static void getGlyphPositions(const SkPaint& paint, const uint16_t glyphs[],
int count, SkScalar x, SkScalar y, SkPoint pos[]) {
SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding());
SkAutoSTMalloc<128, SkScalar> widthStorage(count);
SkScalar* widths = widthStorage.get();
paint.getTextWidths(glyphs, count * sizeof(uint16_t), widths);
for (int i = 0; i < count; ++i) {
pos[i].set(x, y);
x += widths[i];
}
}
static void applyKerning(SkPoint pos[], const int32_t adjustments[], int count,
const SkPaint& paint) {
SkScalar scale = paint.getTextSize() / paint.getTypeface()->getUnitsPerEm();
SkScalar globalAdj = 0;
for (int i = 0; i < count - 1; ++i) {
globalAdj += adjustments[i] * scale;
pos[i + 1].fX += globalAdj;
}
}
static void drawKernText(SkCanvas* canvas, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
SkTypeface* face = paint.getTypeface();
if (!face) {
canvas->drawText(text, len, x, y, paint);
return;
}
SkAutoSTMalloc<128, uint16_t> glyphStorage(len);
uint16_t* glyphs = glyphStorage.get();
int glyphCount = paint.textToGlyphs(text, len, glyphs);
if (glyphCount < 1) {
return;
}
SkAutoSTMalloc<128, int32_t> adjustmentStorage(glyphCount - 1);
int32_t* adjustments = adjustmentStorage.get();
if (!face->getKerningPairAdjustments(glyphs, glyphCount, adjustments)) {
canvas->drawText(text, len, x, y, paint);
return;
}
SkPaint glyphPaint(paint);
glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
SkAutoSTMalloc<128, SkPoint> posStorage(glyphCount);
SkPoint* pos = posStorage.get();
getGlyphPositions(glyphPaint, glyphs, glyphCount, x, y, pos);
applyKerning(pos, adjustments, glyphCount, glyphPaint);
canvas->drawPosText(glyphs, glyphCount * sizeof(uint16_t), pos, glyphPaint);
}
static const struct {
const char* fName;
SkTypeface::Style fStyle;
@ -96,9 +154,10 @@ static const int gFaceStylesCount = SK_ARRAY_COUNT(gFaceStyles);
class TypefaceStylesGM : public skiagm::GM {
SkTypeface* fFaces[gFaceStylesCount];
bool fApplyKerning;
public:
TypefaceStylesGM() {
TypefaceStylesGM(bool applyKerning) : fApplyKerning(applyKerning) {
for (int i = 0; i < gFaceStylesCount; i++) {
fFaces[i] = SkTypeface::CreateFromName(gFaceStyles[i].fName,
gFaceStyles[i].fStyle);
@ -113,7 +172,11 @@ public:
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("typefacestyles");
SkString name("typefacestyles");
if (fApplyKerning) {
name.append("_kerning");
}
return name;
}
virtual SkISize onISize() SK_OVERRIDE {
@ -125,17 +188,24 @@ protected:
paint.setAntiAlias(true);
paint.setTextSize(SkIntToScalar(30));
const char* text = "Hamburgefons";
const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
const size_t textLen = strlen(text);
SkScalar x = SkIntToScalar(10);
SkScalar dy = paint.getFontMetrics(NULL);
SkScalar y = dy;
paint.setLinearText(true);
if (fApplyKerning) {
paint.setSubpixelText(true);
} else {
paint.setLinearText(true);
}
for (int i = 0; i < gFaceStylesCount; i++) {
paint.setTypeface(fFaces[i]);
canvas->drawText(text, textLen, x, y, paint);
if (fApplyKerning) {
drawKernText(canvas, text, textLen, x + 240, y, paint);
}
y += dy;
}
}
@ -147,4 +217,5 @@ private:
///////////////////////////////////////////////////////////////////////////////
DEF_GM( return new TypefaceGM; )
DEF_GM( return new TypefaceStylesGM; )
DEF_GM( return new TypefaceStylesGM(false); )
DEF_GM( return new TypefaceStylesGM(true); )

View File

@ -225,6 +225,29 @@ public:
*/
int getUnitsPerEm() const;
/**
* Given a run of glyphs, return the associated horizontal adjustments.
* Adjustments are in "design units", which are integers relative to the
* typeface's units per em (see getUnitsPerEm).
*
* Some typefaces are known to never support kerning. Calling this method
* with all zeros (e.g. getKerningPairAdustments(NULL, 0, NULL)) returns
* a boolean indicating if the typeface might support kerning. If it
* returns false, then it will always return false (no kerning) for all
* possible glyph runs. If it returns true, then it *may* return true for
* somne glyph runs.
*
* If count is non-zero, then the glyphs parameter must point to at least
* [count] valid glyph IDs, and the adjustments parameter must be
* sized to at least [count - 1] entries. If the method returns true, then
* [count-1] entries in the adjustments array will be set. If the method
* returns false, then no kerning should be applied, and the adjustments
* array will be in an undefined state (possibly some values may have been
* written, but none of them should be interpreted as valid values).
*/
bool getKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const;
struct LocalizedString {
SkString fString;
SkString fLanguage;
@ -303,6 +326,7 @@ protected:
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
const uint32_t* glyphIDs,
uint32_t glyphIDsCount) const = 0;
virtual SkStream* onOpenStream(int* ttcIndex) const = 0;
virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0;
@ -311,6 +335,8 @@ protected:
virtual int onCountGlyphs() const = 0;
virtual int onGetUPEM() const = 0;
virtual bool onGetKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const;
virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0;

View File

@ -233,6 +233,20 @@ int SkTypeface::getUnitsPerEm() const {
return this->onGetUPEM();
}
bool SkTypeface::getKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const {
SkASSERT(count >= 0);
// check for the only legal way to pass a NULL.. everything is 0
// in which case they just want to know if this face can possibly support
// kerning (true) or never (false).
if (NULL == glyphs || NULL == adjustments) {
SkASSERT(NULL == glyphs);
SkASSERT(0 == count);
SkASSERT(NULL == adjustments);
}
return this->onGetKerningPairAdjustments(glyphs, count, adjustments);
}
SkTypeface::LocalizedStrings* SkTypeface::createFamilyNameIterator() const {
return this->onCreateFamilyNameIterator();
}
@ -254,3 +268,11 @@ SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
SkTypeface* SkTypeface::refMatchingStyle(Style style) const {
return this->onRefMatchingStyle(style);
}
///////////////////////////////////////////////////////////////////////////////
bool SkTypeface::onGetKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const {
return false;
}

View File

@ -729,6 +729,26 @@ int SkTypeface_FreeType::onGetUPEM() const {
return face ? face->units_per_EM : 0;
}
bool SkTypeface_FreeType::onGetKerningPairAdjustments(const uint16_t glyphs[],
int count, int32_t adjustments[]) const {
AutoFTAccess fta(this);
FT_Face face = fta.face();
if (!face || !FT_HAS_KERNING(face)) {
return false;
}
for (int i = 0; i < count - 1; ++i) {
FT_Vector delta;
FT_Error err = FT_Get_Kerning(face, glyphs[i], glyphs[i+1],
FT_KERNING_UNSCALED, &delta);
if (err) {
return false;
}
adjustments[i] = delta.x;
}
return true;
}
SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface,
const SkDescriptor* desc)
: SkScalerContext_FreeType_Base(typeface, desc) {

View File

@ -59,7 +59,8 @@ protected:
SkAdvancedTypefaceMetrics::PerGlyphInfo,
const uint32_t*, uint32_t) const SK_OVERRIDE;
virtual int onGetUPEM() const SK_OVERRIDE;
virtual bool onGetKerningPairAdjustments(const uint16_t glyphs[], int count,
int32_t adjustments[]) const SK_OVERRIDE;
virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
int glyphCount) const SK_OVERRIDE;
virtual int onCountGlyphs() const SK_OVERRIDE;