aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkAutoKern.h51
-rw-r--r--src/core/SkDraw.cpp1
-rw-r--r--src/core/SkFindAndPlaceGlyph.h38
-rw-r--r--src/core/SkGlyph.cpp2
-rw-r--r--src/core/SkGlyph.h4
-rw-r--r--src/core/SkPaint.cpp161
-rw-r--r--src/core/SkScalerContext.cpp15
-rw-r--r--src/core/SkScalerContext.h2
-rw-r--r--src/core/SkTextBlob.cpp1
-rw-r--r--src/core/SkTextToPathIter.h2
-rw-r--r--src/gpu/text/GrAtlasTextContext.cpp11
-rw-r--r--src/gpu/text/GrTextUtils.cpp2
-rw-r--r--src/ports/SkFontHost_FreeType.cpp10
-rw-r--r--src/ports/SkFontHost_mac.cpp3
-rw-r--r--src/ports/SkFontHost_win.cpp3
-rw-r--r--src/ports/SkScalerContext_win_dw.cpp6
-rw-r--r--src/ports/SkTypeface_win_dw.cpp1
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;