diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkAutoKern.h | 51 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 1 | ||||
-rw-r--r-- | src/core/SkFindAndPlaceGlyph.h | 38 | ||||
-rw-r--r-- | src/core/SkGlyph.cpp | 2 | ||||
-rw-r--r-- | src/core/SkGlyph.h | 4 | ||||
-rw-r--r-- | src/core/SkPaint.cpp | 161 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 15 | ||||
-rw-r--r-- | src/core/SkScalerContext.h | 2 | ||||
-rw-r--r-- | src/core/SkTextBlob.cpp | 1 | ||||
-rw-r--r-- | src/core/SkTextToPathIter.h | 2 | ||||
-rw-r--r-- | src/gpu/text/GrAtlasTextContext.cpp | 11 | ||||
-rw-r--r-- | src/gpu/text/GrTextUtils.cpp | 2 | ||||
-rw-r--r-- | src/ports/SkFontHost_FreeType.cpp | 10 | ||||
-rw-r--r-- | src/ports/SkFontHost_mac.cpp | 3 | ||||
-rw-r--r-- | src/ports/SkFontHost_win.cpp | 3 | ||||
-rw-r--r-- | src/ports/SkScalerContext_win_dw.cpp | 6 | ||||
-rw-r--r-- | src/ports/SkTypeface_win_dw.cpp | 1 |
17 files changed, 259 insertions, 54 deletions
diff --git a/src/core/SkAutoKern.h b/src/core/SkAutoKern.h new file mode 100644 index 0000000000..8b032519b3 --- /dev/null +++ b/src/core/SkAutoKern.h @@ -0,0 +1,51 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkAutoKern_DEFINED +#define SkAutoKern_DEFINED + +#include "SkGlyph.h" + +#define SkAutoKern_Adjust(prev, next) SkIntToScalar(((next) - (prev) + 32) >> 6) + +/* this is a helper class to perform auto-kerning + * the adjust() method returns a SkScalar corresponding + * to a +1/0/-1 pixel adjustment + */ + +class SkAutoKern { +public: + SkAutoKern() : fPrevRsbDelta(0) {} + + SkScalar adjust(const SkGlyph& glyph) + { +// if (SkAbs32(glyph.fLsbDelta) > 47 || SkAbs32(glyph.fRsbDelta) > 47) +// printf("------- %d> L %d R %d\n", glyph.f_GlyphID, glyph.fLsbDelta, glyph.fRsbDelta); + +#if 0 + int distort = fPrevRsbDelta - glyph.fLsbDelta; + + fPrevRsbDelta = glyph.fRsbDelta; + + if (distort >= 32) + return -SK_Scalar1; + else if (distort < -32) + return +SK_Scalar1; + else + return 0; +#else + SkScalar adjust = SkAutoKern_Adjust(fPrevRsbDelta, glyph.fLsbDelta); + fPrevRsbDelta = glyph.fRsbDelta; + return adjust; +#endif + } +private: + int fPrevRsbDelta; +}; + +#endif diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 0526f76f8e..e3c81ba258 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1571,6 +1571,7 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkS paint.setPathEffect(nullptr); SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), true); auto cache = SkStrikeCache::FindOrCreateStrikeExclusive( paint, props, this->scalerContextFlags(), nullptr); diff --git a/src/core/SkFindAndPlaceGlyph.h b/src/core/SkFindAndPlaceGlyph.h index 00417152ab..d92edb6b17 100644 --- a/src/core/SkFindAndPlaceGlyph.h +++ b/src/core/SkFindAndPlaceGlyph.h @@ -9,6 +9,7 @@ #define SkFindAndPositionGlyph_DEFINED #include "SkArenaAlloc.h" +#include "SkAutoKern.h" #include "SkGlyph.h" #include "SkGlyphCache.h" #include "SkMatrixPriv.h" @@ -319,8 +320,8 @@ private: virtual ~GlyphFindAndPlaceInterface() { } // findAndPositionGlyph calculates the position of the glyph, finds the glyph, and - // returns the position of where the next glyph will be using the glyph's advance. The - // returned position is used by drawText, but ignored by drawPosText. + // returns the position of where the next glyph will be using the glyph's advance and + // possibly kerning. The returned position is used by drawText, but ignored by drawPosText. // The compiler should prune all this calculation if the return value is not used. // // This should be a pure virtual, but some versions of GCC <= 4.8 have a bug that causes a @@ -382,20 +383,31 @@ private: GlyphFinderInterface* fGlyphFinder; }; + enum SelectKerning { + kNoKerning = false, + kUseKerning = true + }; + // GlyphFindAndPlaceFullPixel handles finding and placing glyphs when no sub-pixel - // positioning is requested. - template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment> + // positioning is requested. The kUseKerning argument should be true for drawText, and false + // for drawPosText. + template<typename ProcessOneGlyph, SkPaint::Align kTextAlignment, SelectKerning kUseKerning> class GlyphFindAndPlaceFullPixel final : public GlyphFindAndPlaceInterface<ProcessOneGlyph> { public: explicit GlyphFindAndPlaceFullPixel(GlyphFinderInterface* glyphFinder) : fGlyphFinder(glyphFinder) { + // Kerning can only be used with SkPaint::kLeft_Align + static_assert(!kUseKerning || SkPaint::kLeft_Align == kTextAlignment, + "Kerning can only be used with left aligned text."); } SkPoint findAndPositionGlyph( const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) override { SkPoint finalPosition = position; const SkGlyph& glyph = fGlyphFinder->lookupGlyph(text); - + if (kUseKerning) { + finalPosition += {fAutoKern.adjust(glyph), 0.0f}; + } if (glyph.fWidth > 0) { finalPosition -= TextAlignmentAdjustment(kTextAlignment, glyph); processOneGlyph(glyph, finalPosition, {SK_ScalarHalf, SK_ScalarHalf}); @@ -406,6 +418,8 @@ private: private: GlyphFinderInterface* fGlyphFinder; + + SkAutoKern fAutoKern; }; template <typename ProcessOneGlyph, SkPaint::Align kTextAlignment> @@ -432,12 +446,14 @@ private: SkScalar x = 0, y = 0; const char* stop = text + byteLength; + SkAutoKern autokern; + while (text < stop) { // don't need x, y here, since all subpixel variants will have the // same advance const SkGlyph& glyph = glyphFinder->lookupGlyph(&text); - x += SkFloatToScalar(glyph.fAdvanceX); + x += autokern.adjust(glyph) + SkFloatToScalar(glyph.fAdvanceX); y += SkFloatToScalar(glyph.fAdvanceY); } SkASSERT(text == stop); @@ -527,17 +543,18 @@ inline void SkFindAndPlaceGlyph::ProcessPosText( switch (textAlignment) { case SkPaint::kLeft_Align: findAndPosition = arena.make< - GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align>>(glyphFinder); + GlyphFindAndPlaceFullPixel<ProcessOneGlyph, + SkPaint::kLeft_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kCenter_Align: findAndPosition = arena.make< GlyphFindAndPlaceFullPixel<ProcessOneGlyph, - SkPaint::kCenter_Align>>(glyphFinder); + SkPaint::kCenter_Align, kNoKerning>>(glyphFinder); break; case SkPaint::kRight_Align: findAndPosition = arena.make< GlyphFindAndPlaceFullPixel<ProcessOneGlyph, - SkPaint::kRight_Align>>(glyphFinder); + SkPaint::kRight_Align, kNoKerning>>(glyphFinder); break; } } @@ -578,7 +595,8 @@ inline void SkFindAndPlaceGlyph::ProcessText( findAndPosition = getSubpixel<ProcessOneGlyph, SkPaint::kLeft_Align>( &arena, axisAlignment, glyphFinder); } else { - using FullPixel = GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align>; + using FullPixel = + GlyphFindAndPlaceFullPixel<ProcessOneGlyph, SkPaint::kLeft_Align, kUseKerning>; findAndPosition = arena.make<FullPixel>(glyphFinder); } diff --git a/src/core/SkGlyph.cpp b/src/core/SkGlyph.cpp index 33246cc2dc..2abe98aa1e 100644 --- a/src/core/SkGlyph.cpp +++ b/src/core/SkGlyph.cpp @@ -31,6 +31,8 @@ void SkGlyph::zeroMetrics() { fHeight = 0; fTop = 0; fLeft = 0; + fRsbDelta = 0; + fLsbDelta = 0; } static size_t bits_to_bytes(size_t bits) { diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h index 87cd852bd8..211039e520 100644 --- a/src/core/SkGlyph.h +++ b/src/core/SkGlyph.h @@ -131,6 +131,7 @@ struct SkPackedUnicharID : public SkPackedID { } }; +SK_BEGIN_REQUIRE_DENSE class SkGlyph { // Support horizontal and vertical skipping strike-through / underlines. // The caller walks the linked list looking for a match. For a horizontal underline, @@ -158,9 +159,7 @@ public: int16_t fTop, fLeft; uint8_t fMaskFormat; -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK int8_t fRsbDelta, fLsbDelta; // used by auto-kerning -#endif int8_t fForceBW; void initWithGlyphID(SkPackedGlyphID glyph_id); @@ -225,5 +224,6 @@ public: #endif SkPackedGlyphID fID; }; +SK_END_REQUIRE_DENSE #endif diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index ab3e2da9b5..141b60b252 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -7,6 +7,7 @@ #include "SkPaint.h" #include "SkPaintPriv.h" +#include "SkAutoKern.h" #include "SkColorFilter.h" #include "SkData.h" #include "SkDraw.h" @@ -244,6 +245,10 @@ void SkPaint::setFakeBoldText(bool doFakeBold) { this->setFlags(set_clear_mask(fBitfields.fFlags, doFakeBold, kFakeBoldText_Flag)); } +void SkPaint::setDevKernText(bool doDevKern) { + this->setFlags(set_clear_mask(fBitfields.fFlags, doDevKern, kDevKernText_Flag)); +} + void SkPaint::setStyle(Style style) { if ((unsigned)style < kStyleCount) { fBitfields.fStyle = style; @@ -620,7 +625,8 @@ static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache, } SkPaint::GlyphCacheProc SkPaint::GetGlyphCacheProc(TextEncoding encoding, - bool needFullMetrics) { + bool isDevKern, + bool needFullMetrics) { static const GlyphCacheProc gGlyphCacheProcs[] = { sk_getMetrics_utf8_next, sk_getMetrics_utf16_next, @@ -635,7 +641,7 @@ SkPaint::GlyphCacheProc SkPaint::GetGlyphCacheProc(TextEncoding encoding, unsigned index = encoding; - if (!needFullMetrics) { + if (!needFullMetrics && !isDevKern) { index += 4; } @@ -646,6 +652,7 @@ SkPaint::GlyphCacheProc SkPaint::GetGlyphCacheProc(TextEncoding encoding, /////////////////////////////////////////////////////////////////////////////// #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \ +SkPaint::kDevKernText_Flag | \ SkPaint::kLinearText_Flag | \ SkPaint::kLCDRenderText_Flag | \ SkPaint::kEmbeddedBitmapText_Flag | \ @@ -732,6 +739,7 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache, } GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(this->getTextEncoding(), + this->isDevKernText(), nullptr != bounds); int xyIndex; @@ -750,16 +758,33 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache, SkScalar x = advance(*g, xyIndex); if (nullptr == bounds) { - for (; text < stop; n++) { - x += advance(glyphCacheProc(cache, &text), xyIndex); + if (this->isDevKernText()) { + for (; text < stop; n++) { + const int rsb = g->fRsbDelta; + g = &glyphCacheProc(cache, &text); + x += SkAutoKern_Adjust(rsb, g->fLsbDelta) + advance(*g, xyIndex); + } + } else { + for (; text < stop; n++) { + x += advance(glyphCacheProc(cache, &text), xyIndex); + } } } else { set_bounds(*g, bounds); - - for (; text < stop; n++) { - g = &glyphCacheProc(cache, &text); - joinBoundsProc(*g, bounds, x); - x += advance(*g, xyIndex); + if (this->isDevKernText()) { + for (; text < stop; n++) { + const int rsb = g->fRsbDelta; + g = &glyphCacheProc(cache, &text); + x += SkAutoKern_Adjust(rsb, g->fLsbDelta); + joinBoundsProc(*g, bounds, x); + x += advance(*g, xyIndex); + } + } else { + for (; text < stop; n++) { + g = &glyphCacheProc(cache, &text); + joinBoundsProc(*g, bounds, x); + x += advance(*g, xyIndex); + } } } SkASSERT(text == stop); @@ -832,17 +857,33 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint); GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), false); const int xyIndex = paint.isVerticalText() ? 1 : 0; SkScalar width = 0; - while (text < stop) { - const char* curr = text; - SkScalar x = advance(glyphCacheProc(cache.get(), &text), xyIndex); - if ((width += x) > maxWidth) { - width -= x; - text = curr; - break; + if (this->isDevKernText()) { + int rsb = 0; + while (text < stop) { + const char* curr = text; + const SkGlyph& g = glyphCacheProc(cache.get(), &text); + SkScalar x = SkAutoKern_Adjust(rsb, g.fLsbDelta) + advance(g, xyIndex); + if ((width += x) > maxWidth) { + width -= x; + text = curr; + break; + } + rsb = g.fRsbDelta; + } + } else { + while (text < stop) { + const char* curr = text; + SkScalar x = advance(glyphCacheProc(cache.get(), &text), xyIndex); + if ((width += x) > maxWidth) { + width -= x; + text = curr; + break; + } } } @@ -920,6 +961,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint); GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), nullptr != bounds); const char* text = (const char*)textData; @@ -927,27 +969,73 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, int count = 0; const int xyIndex = paint.isVerticalText() ? 1 : 0; - if (scale) { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache.get(), &text); - if (widths) { - *widths++ = advance(g, xyIndex) * scale; + if (this->isDevKernText()) { + // we adjust the widths returned here through auto-kerning + SkAutoKern autokern; + SkScalar prevWidth = 0; + + if (scale) { + while (text < stop) { + const SkGlyph& g = glyphCacheProc(cache.get(), &text); + if (widths) { + SkScalar adjust = autokern.adjust(g); + + if (count > 0) { + *widths++ = (prevWidth + adjust) * scale; + } + prevWidth = advance(g, xyIndex); + } + if (bounds) { + set_bounds(g, bounds++, scale); + } + ++count; } - if (bounds) { - set_bounds(g, bounds++, scale); + if (count > 0 && widths) { + *widths = prevWidth * scale; + } + } else { + while (text < stop) { + const SkGlyph& g = glyphCacheProc(cache.get(), &text); + if (widths) { + SkScalar adjust = autokern.adjust(g); + + if (count > 0) { + *widths++ = prevWidth + adjust; + } + prevWidth = advance(g, xyIndex); + } + if (bounds) { + set_bounds(g, bounds++); + } + ++count; + } + if (count > 0 && widths) { + *widths = prevWidth; } - ++count; } - } else { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache.get(), &text); - if (widths) { - *widths++ = advance(g, xyIndex); + } else { // no devkern + if (scale) { + while (text < stop) { + const SkGlyph& g = glyphCacheProc(cache.get(), &text); + if (widths) { + *widths++ = advance(g, xyIndex) * scale; + } + if (bounds) { + set_bounds(g, bounds++, scale); + } + ++count; } - if (bounds) { - set_bounds(g, bounds++); + } else { + while (text < stop) { + const SkGlyph& g = glyphCacheProc(cache.get(), &text); + if (widths) { + *widths++ = advance(g, xyIndex); + } + if (bounds) { + set_bounds(g, bounds++); + } + ++count; } - ++count; } } @@ -1561,6 +1649,7 @@ void SkPaint::toString(SkString* str) const { SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator); SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator); SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator); + SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator); SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator); SkAddFlagToString(str, this->isEmbeddedBitmapText(), "EmbeddedBitmapText", &needSeparator); @@ -1620,7 +1709,9 @@ SkTextBaseIter::SkTextBaseIter(const char text[], size_t length, const SkPaint& paint, bool applyStrokeAndPathEffects) : fPaint(paint) { - fGlyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), true); + fGlyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), + true); fPaint.setLinearText(true); fPaint.setMaskFilter(nullptr); // don't want this affecting our path-cache lookup @@ -1689,7 +1780,7 @@ bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { if (fText < fStop) { const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText); - fXPos += fPrevAdvance * fScale; + fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale; fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); if (glyph.fWidth) { @@ -1711,7 +1802,7 @@ bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { bool SkTextInterceptsIter::next(SkScalar* array, int* count) { const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText); - fXPos += fPrevAdvance * fScale; + fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale; fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); if (fCache->findPath(glyph)) { fCache->findIntercepts(fBounds, fScale, fXPos, SkToBool(fXYIndex), diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index 57d8bc1ddf..b8cd107bd3 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -106,6 +106,15 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) { } } + // for now we have separate cache entries for devkerning on and off + // in the future we might share caches, but make our measure/draw + // code make the distinction. Thus we zap the values if the caller + // has not asked for them. + if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) { + // no devkern, so zap the fields + glyph->fLsbDelta = glyph->fRsbDelta = 0; + } + // if either dimension is empty, zap the image bounds of the glyph if (0 == glyph->fWidth || 0 == glyph->fHeight) { glyph->fWidth = 0; @@ -153,6 +162,8 @@ SK_ERROR: glyph->fTop = 0; glyph->fWidth = 0; glyph->fHeight = 0; + glyph->fLsbDelta = 0; + glyph->fRsbDelta = 0; // put a valid value here, in case it was earlier set to // MASK_FORMAT_JUST_ADVANCE glyph->fMaskFormat = fRec.fMaskFormat; @@ -874,6 +885,10 @@ void SkScalerContext::MakeRecAndEffects(const SkPaint& paint, #endif } + if (paint.isDevKernText()) { + flags |= SkScalerContext::kDevKernText_Flag; + } + if (style != SkPaint::kFill_Style && strokeWidth > 0) { rec->fFrameWidth = strokeWidth; rec->fMiterLimit = paint.getStrokeMiter(); diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 9995fd9292..675e9a0524 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -224,7 +224,7 @@ class SkScalerContext { public: enum Flags { kFrameAndFill_Flag = 0x0001, - kUnused = 0x0002, + kDevKernText_Flag = 0x0002, kEmbeddedBitmapText_Flag = 0x0004, kEmbolden_Flag = 0x0008, kSubpixelPositioning_Flag = 0x0010, diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp index e2d3be4518..2c29d9d613 100644 --- a/src/core/SkTextBlob.cpp +++ b/src/core/SkTextBlob.cpp @@ -67,6 +67,7 @@ private: SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | SkPaint::kSubpixelText_Flag | + SkPaint::kDevKernText_Flag | SkPaint::kLCDRenderText_Flag | SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag | diff --git a/src/core/SkTextToPathIter.h b/src/core/SkTextToPathIter.h index c135de620b..49564d96af 100644 --- a/src/core/SkTextToPathIter.h +++ b/src/core/SkTextToPathIter.h @@ -8,6 +8,7 @@ #ifndef SkTextToPathIter_DEFINED #define SkTextToPathIter_DEFINED +#include "SkAutoKern.h" #include "SkPaint.h" #include "SkStrikeCache.h" @@ -26,6 +27,7 @@ protected: SkPaint::GlyphCacheProc fGlyphCacheProc; SkScalar fXPos; // accumulated xpos, returned in next + SkAutoKern fAutoKern; int fXYIndex; // cache for horizontal -vs- vertical text }; diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index e99d9df044..27c8dea670 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -498,6 +498,7 @@ void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runInd pathPaint.setPathEffect(nullptr); SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(pathPaint.getTextEncoding(), + pathPaint.isDevKernText(), true); auto cache = SkStrikeCache::FindOrCreateStrikeExclusive( pathPaint, &props, SkScalerContextFlags::kFakeGammaAndBoostContrast, nullptr); @@ -678,7 +679,7 @@ void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, const SkPaint& skPaint = paint.skPaint(); SkPaint::GlyphCacheProc glyphCacheProc = - SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), true); + SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), skPaint.isDevKernText(), true); SkTArray<SkScalar> positions; @@ -704,13 +705,14 @@ void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex, auto origPaintCache = SkStrikeCache::FindOrCreateStrikeExclusive(*desc.getDesc(), effects, *typeface); + SkAutoKern autokern; const char* stop = text + byteLength; while (textPtr < stop) { // don't need x, y here, since all subpixel variants will have the // same advance const SkGlyph& glyph = glyphCacheProc(origPaintCache.get(), &textPtr); - SkScalar width = SkFloatToScalar(glyph.fAdvanceX); + SkScalar width = SkFloatToScalar(glyph.fAdvanceX) + autokern.adjust(glyph); positions.push_back(stopX + origin * width); SkScalar height = SkFloatToScalar(glyph.fAdvanceY); @@ -775,7 +777,7 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex, auto cache = blob->setupCache(runIndex, props, SkScalerContextFlags::kNone, dfPaint, nullptr); SkPaint::GlyphCacheProc glyphCacheProc = - SkPaint::GetGlyphCacheProc(dfPaint.getTextEncoding(), true); + SkPaint::GetGlyphCacheProc(dfPaint.getTextEncoding(), dfPaint.isDevKernText(), true); const char* stop = text + byteLength; @@ -882,7 +884,8 @@ void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int SkExclusiveStrikePtr cache; const SkPaint& skPaint = paint.skPaint(); SkPaint::GlyphCacheProc glyphCacheProc = - SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), true); + SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), + skPaint.isDevKernText(), true); SkColor textColor = paint.filteredPremulColor(); SkScalar textRatio = SK_Scalar1; if (fUseScaledFallback) { diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp index ab332e0417..738cfb68be 100644 --- a/src/gpu/text/GrTextUtils.cpp +++ b/src/gpu/text/GrTextUtils.cpp @@ -62,7 +62,7 @@ bool GrTextUtils::PathTextIter::next(const SkGlyph** skGlyph, const SkPath** pat if (fText < fStop) { const SkGlyph& glyph = fGlyphCacheProc(fCache.get(), &fText); - fXPos += fPrevAdvance * fScale; + fXPos += (fPrevAdvance + fAutoKern.adjust(glyph)) * fScale; SkASSERT(0 == fXYIndex || 1 == fXYIndex); fPrevAdvance = SkFloatToScalar((&glyph.fAdvanceX)[fXYIndex]); diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index c5e8a65733..4c4c6d4f65 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -994,6 +994,8 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) { fLoadGlyphFlags | FT_ADVANCE_FLAG_FAST_ONLY, &advance ); if (0 == error) { + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; const SkScalar advanceScalar = SkFT_FixedToScalar(advance); glyph->fAdvanceX = SkScalarToFloat(fMatrix22Scalar.getScaleX() * advanceScalar); glyph->fAdvanceY = SkScalarToFloat(fMatrix22Scalar.getSkewY() * advanceScalar); @@ -1089,6 +1091,9 @@ bool SkScalerContext_FreeType::shouldSubpixelBitmap(const SkGlyph& glyph, const void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { SkAutoMutexAcquire ac(gFTMutex); + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; + FT_Error err; if (this->setupSize()) { @@ -1179,6 +1184,11 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { } else { glyph->fAdvanceX = SkFDot6ToFloat(fFace->glyph->advance.x); glyph->fAdvanceY = -SkFDot6ToFloat(fFace->glyph->advance.y); + + if (fRec.fFlags & kDevKernText_Flag) { + glyph->fRsbDelta = SkToS8(fFace->glyph->rsb_delta); + glyph->fLsbDelta = SkToS8(fFace->glyph->lsb_delta); + } } } diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 8047c4352f..efd74f6f8e 100644 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -2249,7 +2249,8 @@ void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { rec->setHinting(SkPaint::kNormal_Hinting); } - unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag | + unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | + SkScalerContext::kForceAutohinting_Flag | SkScalerContext::kLCD_BGROrder_Flag | SkScalerContext::kLCD_Vertical_Flag; diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 35a0a74b22..7bc1e298aa 100644 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -943,6 +943,8 @@ void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) { // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]? glyph->fAdvanceX = (float)((int)gm.gmCellIncX); glyph->fAdvanceY = (float)((int)gm.gmCellIncY); + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; if (this->isSubpixel()) { sk_bzero(&gm, sizeof(gm)); @@ -2263,6 +2265,7 @@ void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const { } unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag | + SkScalerContext::kDevKernText_Flag | SkScalerContext::kForceAutohinting_Flag | SkScalerContext::kEmbeddedBitmapText_Flag | SkScalerContext::kEmbolden_Flag | diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp index 98d8ca812e..8e73b16047 100644 --- a/src/ports/SkScalerContext_win_dw.cpp +++ b/src/ports/SkScalerContext_win_dw.cpp @@ -377,6 +377,12 @@ uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { } void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { + //Delta is the difference between the right/left side bearing metric + //and where the right/left side bearing ends up after hinting. + //DirectWrite does not provide this information. + glyph->fRsbDelta = 0; + glyph->fLsbDelta = 0; + glyph->fAdvanceX = 0; glyph->fAdvanceY = 0; diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp index 69bf7ff034..69be774612 100644 --- a/src/ports/SkTypeface_win_dw.cpp +++ b/src/ports/SkTypeface_win_dw.cpp @@ -258,6 +258,7 @@ void DWriteFontTypeface::onFilterRec(SkScalerContextRec* rec) const { } unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag | + SkScalerContext::kDevKernText_Flag | SkScalerContext::kForceAutohinting_Flag | SkScalerContext::kEmbolden_Flag | SkScalerContext::kLCD_Vertical_Flag; |