Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Unified Diff: src/core/SkGlyphCache.cpp

Issue 1654883003: add helper to create fancy underlines (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: correct comment to multiply by two Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkGlyphCache.h ('k') | src/core/SkPaint.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkGlyphCache.cpp
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index 1512dbf0e5dd0a627369e74d32ce804945dd6bfc..93d48a3d1511795fec61fe38ddc2f02e40ec92e5 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -53,7 +53,10 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca
}
SkGlyphCache::~SkGlyphCache() {
- fGlyphMap.foreach ([](SkGlyph* g) { delete g->fPath; });
+ fGlyphMap.foreach ([](SkGlyph* g) {
+ if (g->fPathData) {
+ delete g->fPathData->fPath;
+ } } );
SkDescriptor::Free(fDesc);
delete fScalerContext;
this->invokeAndRemoveAuxProcs();
@@ -214,14 +217,185 @@ const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
if (glyph.fWidth) {
- if (glyph.fPath == nullptr) {
- const_cast<SkGlyph&>(glyph).fPath = new SkPath;
- fScalerContext->getPath(glyph, glyph.fPath);
- fMemoryUsed += sizeof(SkPath) +
- glyph.fPath->countPoints() * sizeof(SkPoint);
+ if (glyph.fPathData == nullptr) {
+ SkGlyph::PathData* pathData =
+ (SkGlyph::PathData* ) fGlyphAlloc.allocThrow(sizeof(SkGlyph::PathData));
+ const_cast<SkGlyph&>(glyph).fPathData = pathData;
+ pathData->fIntercept = nullptr;
+ SkPath* path = pathData->fPath = new SkPath;
+ fScalerContext->getPath(glyph, path);
+ fMemoryUsed += sizeof(SkPath) + path->countPoints() * sizeof(SkPoint);
}
}
- return glyph.fPath;
+ return glyph.fPathData ? glyph.fPathData->fPath : nullptr;
+}
+
+#include "../pathops/SkPathOpsCubic.h"
+#include "../pathops/SkPathOpsQuad.h"
+
+static bool quad_in_bounds(const SkScalar* pts, const SkScalar bounds[2]) {
+ SkScalar min = SkTMin(SkTMin(pts[0], pts[2]), pts[4]);
+ if (bounds[1] < min) {
+ return false;
+ }
+ SkScalar max = SkTMax(SkTMax(pts[0], pts[2]), pts[4]);
+ return bounds[0] < max;
+}
+
+static bool cubic_in_bounds(const SkScalar* pts, const SkScalar bounds[2]) {
+ SkScalar min = SkTMin(SkTMin(SkTMin(pts[0], pts[2]), pts[4]), pts[6]);
+ if (bounds[1] < min) {
+ return false;
+ }
+ SkScalar max = SkTMax(SkTMax(SkTMax(pts[0], pts[2]), pts[4]), pts[6]);
+ return bounds[0] < max;
+}
+
+void SkGlyphCache::OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
+ SkScalar xPos, SkScalar* array, int* count) {
+ if (array) {
+ array += *count;
+ for (int index = 0; index < 2; index++) {
+ *array++ = intercept->fInterval[index] * scale + xPos;
+ }
+ }
+ *count += 2;
+}
+
+void SkGlyphCache::AddInterval(SkScalar val, SkGlyph::Intercept* intercept) {
+ intercept->fInterval[0] = SkTMin(intercept->fInterval[0], val);
+ intercept->fInterval[1] = SkTMax(intercept->fInterval[1], val);
+}
+
+void SkGlyphCache::AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
+ bool yAxis, SkGlyph::Intercept* intercept) {
+ for (int i = 0; i < ptCount; ++i) {
+ SkScalar val = *(&pts[i].fY - yAxis);
+ if (bounds[0] < val && val < bounds[1]) {
+ AddInterval(*(&pts[i].fX + yAxis), intercept);
+ }
+ }
+}
+
+void SkGlyphCache::AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
+ SkGlyph::Intercept* intercept) {
+ SkScalar t = yAxis ? (axis - pts[0].fX) / (pts[1].fX - pts[0].fX)
+ : (axis - pts[0].fY) / (pts[1].fY - pts[0].fY);
+ if (0 <= t && t < 1) { // this handles divide by zero above
+ AddInterval(yAxis ? pts[0].fY + t * (pts[1].fY - pts[0].fY)
+ : pts[0].fX + t * (pts[1].fX - pts[0].fX), intercept);
+ }
+}
+
+void SkGlyphCache::AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
+ SkGlyph::Intercept* intercept) {
+ SkDQuad quad;
+ quad.set(pts);
+ double roots[2];
+ int count = yAxis ? quad.verticalIntersect(axis, roots)
+ : quad.horizontalIntersect(axis, roots);
+ while (--count >= 0) {
+ SkPoint pt = quad.ptAtT(roots[count]).asSkPoint();
+ AddInterval(*(&pt.fX + yAxis), intercept);
+ }
+}
+
+void SkGlyphCache::AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
+ SkGlyph::Intercept* intercept) {
+ SkDCubic cubic;
+ cubic.set(pts);
+ double roots[3];
+ int count = yAxis ? cubic.verticalIntersect(axis, roots)
+ : cubic.horizontalIntersect(axis, roots);
+ while (--count >= 0) {
+ SkPoint pt = cubic.ptAtT(roots[count]).asSkPoint();
+ AddInterval(*(&pt.fX + yAxis), intercept);
+ }
+}
+
+const SkGlyph::Intercept* SkGlyphCache::MatchBounds(const SkGlyph* glyph,
+ const SkScalar bounds[2]) {
+ if (!glyph->fPathData) {
+ return nullptr;
+ }
+ const SkGlyph::Intercept* intercept = glyph->fPathData->fIntercept;
+ while (intercept) {
+ if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
+ return intercept;
+ }
+ intercept = intercept->fNext;
+ }
+ return nullptr;
+}
+
+void SkGlyphCache::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
+ bool yAxis, SkGlyph* glyph, SkScalar* array, int* count) {
+ const SkGlyph::Intercept* match = MatchBounds(glyph, bounds);
+
+ if (match) {
+ if (match->fInterval[0] < match->fInterval[1]) {
+ OffsetResults(match, scale, xPos, array, count);
+ }
+ return;
+ }
+
+ SkGlyph::Intercept* intercept =
+ (SkGlyph::Intercept* ) fGlyphAlloc.allocThrow(sizeof(SkGlyph::Intercept));
+ intercept->fNext = glyph->fPathData->fIntercept;
+ intercept->fBounds[0] = bounds[0];
+ intercept->fBounds[1] = bounds[1];
+ intercept->fInterval[0] = SK_ScalarMax;
+ intercept->fInterval[1] = SK_ScalarMin;
+ glyph->fPathData->fIntercept = intercept;
+ const SkPath* path = glyph->fPathData->fPath;
+ const SkRect& pathBounds = path->getBounds();
+ if (*(&pathBounds.fBottom - yAxis) < bounds[0] || bounds[1] < *(&pathBounds.fTop - yAxis)) {
+ return;
+ }
+ SkPath::Iter iter(*path, false);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+ while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ break;
+ case SkPath::kLine_Verb:
+ AddLine(pts, bounds[0], yAxis, intercept);
+ AddLine(pts, bounds[1], yAxis, intercept);
+ AddPoints(pts, 2, bounds, yAxis, intercept);
+ break;
+ case SkPath::kQuad_Verb:
+ if (!quad_in_bounds(&pts[0].fY - yAxis, bounds)) {
+ break;
+ }
+ AddQuad(pts, bounds[0], yAxis, intercept);
+ AddQuad(pts, bounds[1], yAxis, intercept);
+ AddPoints(pts, 3, bounds, yAxis, intercept);
+ break;
+ case SkPath::kConic_Verb:
+ SkASSERT(0); // no support for text composed of conics
+ break;
+ case SkPath::kCubic_Verb:
+ if (!cubic_in_bounds(&pts[0].fY - yAxis, bounds)) {
+ break;
+ }
+ AddCubic(pts, bounds[0], yAxis, intercept);
+ AddCubic(pts, bounds[1], yAxis, intercept);
+ AddPoints(pts, 4, bounds, yAxis, intercept);
+ break;
+ case SkPath::kClose_Verb:
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+ }
+ if (intercept->fInterval[0] >= intercept->fInterval[1]) {
+ intercept->fInterval[0] = SK_ScalarMax;
+ intercept->fInterval[1] = SK_ScalarMin;
+ return;
+ }
+ OffsetResults(intercept, scale, xPos, array, count);
}
void SkGlyphCache::dump() const {
« no previous file with comments | « src/core/SkGlyphCache.h ('k') | src/core/SkPaint.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698