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:
parent
b08c707847
commit
35fe7372b1
@ -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); )
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user