| 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 {
|
|
|