Simplify calculation of the path gap.
Simplify the gap calculation code. Mainly avoid passing the interval all over the place. Change code from handling both horizontal and vertical to just horizantal. Change-Id: Idb364da1e489e6a95d9b6d6dd97c4f6e85900c42 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/216691 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
3cd435eecf
commit
6a07591a55
@ -277,24 +277,6 @@ SkSpan<const SkGlyphPos> SkStrike::prepareForDrawing(const SkGlyphID glyphIDs[],
|
||||
#include "src/pathops/SkPathOpsCubic.h"
|
||||
#include "src/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 SkStrike::OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
|
||||
SkScalar xPos, SkScalar* array, int* count) {
|
||||
if (array) {
|
||||
@ -306,57 +288,6 @@ void SkStrike::OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale
|
||||
*count += 2;
|
||||
}
|
||||
|
||||
void SkStrike::AddInterval(SkScalar val, SkGlyph::Intercept* intercept) {
|
||||
intercept->fInterval[0] = SkTMin(intercept->fInterval[0], val);
|
||||
intercept->fInterval[1] = SkTMax(intercept->fInterval[1], val);
|
||||
}
|
||||
|
||||
void SkStrike::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 SkStrike::AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
|
||||
SkGlyph::Intercept* intercept) {
|
||||
SkScalar t = yAxis ? sk_ieee_float_divide(axis - pts[0].fX, pts[1].fX - pts[0].fX)
|
||||
: sk_ieee_float_divide(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 SkStrike::AddQuad(const SkPoint pts[3], 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 SkStrike::AddCubic(const SkPoint pts[4], 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* SkStrike::MatchBounds(const SkGlyph* glyph,
|
||||
const SkScalar bounds[2]) {
|
||||
if (!glyph->fPathData) {
|
||||
@ -372,8 +303,109 @@ const SkGlyph::Intercept* SkStrike::MatchBounds(const SkGlyph* glyph,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::tuple<SkScalar, SkScalar> calculate_path_gap(
|
||||
SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
|
||||
|
||||
// Left and Right of an ever expanding gap around the path.
|
||||
SkScalar left = SK_ScalarMax,
|
||||
right = SK_ScalarMin;
|
||||
auto expandGap = [&left, &right](SkScalar v) {
|
||||
left = SkTMin(left, v);
|
||||
right = SkTMax(right, v);
|
||||
};
|
||||
|
||||
// Handle all the different verbs for the path.
|
||||
SkPoint pts[4];
|
||||
auto addLine = [&expandGap, &pts](SkScalar offset) {
|
||||
SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
|
||||
if (0 <= t && t < 1) { // this handles divide by zero above
|
||||
expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
|
||||
}
|
||||
};
|
||||
|
||||
auto addQuad = [&expandGap, &pts](SkScalar offset) {
|
||||
SkDQuad quad;
|
||||
quad.set(pts);
|
||||
double roots[2];
|
||||
int count = quad.horizontalIntersect(offset, roots);
|
||||
while (--count >= 0) {
|
||||
expandGap(quad.ptAtT(roots[count]).asSkPoint().fX);
|
||||
}
|
||||
};
|
||||
|
||||
auto addCubic = [&expandGap, &pts](SkScalar offset) {
|
||||
SkDCubic cubic;
|
||||
cubic.set(pts);
|
||||
double roots[3];
|
||||
int count = cubic.horizontalIntersect(offset, roots);
|
||||
while (--count >= 0) {
|
||||
expandGap(cubic.ptAtT(roots[count]).asSkPoint().fX);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle when a verb's points are in the gap between top and bottom.
|
||||
auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
|
||||
for (int i = 0; i < ptCount; ++i) {
|
||||
if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
|
||||
expandGap(pts[i].fX);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SkPath::Iter iter(path, false);
|
||||
SkPath::Verb verb;
|
||||
while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb: {
|
||||
break;
|
||||
}
|
||||
case SkPath::kLine_Verb: {
|
||||
addLine(topOffset);
|
||||
addLine(bottomOffset);
|
||||
addPts(2);
|
||||
break;
|
||||
}
|
||||
case SkPath::kQuad_Verb: {
|
||||
SkScalar quadTop = SkTMin(SkTMin(pts[0].fY, pts[1].fY), pts[2].fY);
|
||||
if (bottomOffset < quadTop) { break; }
|
||||
SkScalar quadBottom = SkTMax(SkTMax(pts[0].fY, pts[1].fY), pts[2].fY);
|
||||
if (topOffset > quadBottom) { break; }
|
||||
addQuad(topOffset);
|
||||
addQuad(bottomOffset);
|
||||
addPts(3);
|
||||
break;
|
||||
}
|
||||
case SkPath::kConic_Verb: {
|
||||
SkASSERT(0); // no support for text composed of conics
|
||||
break;
|
||||
}
|
||||
case SkPath::kCubic_Verb: {
|
||||
SkScalar quadTop =
|
||||
SkTMin(SkTMin(SkTMin(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
|
||||
if (bottomOffset < quadTop) { break; }
|
||||
SkScalar quadBottom =
|
||||
SkTMax(SkTMax(SkTMax(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
|
||||
if (topOffset > quadBottom) { break; }
|
||||
addCubic(topOffset);
|
||||
addCubic(bottomOffset);
|
||||
addPts(4);
|
||||
break;
|
||||
}
|
||||
case SkPath::kClose_Verb: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SkASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::tie(left, right);
|
||||
}
|
||||
|
||||
void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
|
||||
bool yAxis, SkGlyph* glyph, SkScalar* array, int* count) {
|
||||
SkGlyph* glyph, SkScalar* array, int* count) {
|
||||
const SkGlyph::Intercept* match = MatchBounds(glyph, bounds);
|
||||
|
||||
if (match) {
|
||||
@ -392,47 +424,13 @@ void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar
|
||||
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)) {
|
||||
if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
std::tie(intercept->fInterval[0], intercept->fInterval[1])
|
||||
= calculate_path_gap(bounds[0], bounds[1], *path);
|
||||
|
||||
if (intercept->fInterval[0] >= intercept->fInterval[1]) {
|
||||
intercept->fInterval[0] = SK_ScalarMax;
|
||||
intercept->fInterval[1] = SK_ScalarMin;
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
to the array (if non-null), and set the count to the updated array length.
|
||||
*/
|
||||
void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
|
||||
bool yAxis, SkGlyph* , SkScalar* array, int* count);
|
||||
SkGlyph* , SkScalar* array, int* count);
|
||||
|
||||
/** Return the Path associated with the glyph. If it has not been generated this will trigger
|
||||
that.
|
||||
@ -188,15 +188,6 @@ private:
|
||||
|
||||
static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale,
|
||||
SkScalar xPos, SkScalar* array, int* count);
|
||||
static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept);
|
||||
static void AddPoints(const SkPoint* pts, int ptCount, const SkScalar bounds[2],
|
||||
bool yAxis, SkGlyph::Intercept* intercept);
|
||||
static void AddLine(const SkPoint pts[2], SkScalar axis, bool yAxis,
|
||||
SkGlyph::Intercept* intercept);
|
||||
static void AddQuad(const SkPoint pts[2], SkScalar axis, bool yAxis,
|
||||
SkGlyph::Intercept* intercept);
|
||||
static void AddCubic(const SkPoint pts[3], SkScalar axis, bool yAxis,
|
||||
SkGlyph::Intercept* intercept);
|
||||
static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
|
||||
const SkScalar bounds[2]);
|
||||
|
||||
|
@ -943,8 +943,7 @@ bool TextInterceptsIter::next(SkScalar* array, int* count) {
|
||||
fXPos += fPrevAdvance * fScale;
|
||||
fPrevAdvance = SkFloatToScalar(glyph.fAdvanceX);
|
||||
if (fCache->findPath(glyph)) {
|
||||
fCache->findIntercepts(fBounds, fScale, fXPos, false,
|
||||
const_cast<SkGlyph*>(&glyph), array, count);
|
||||
fCache->findIntercepts(fBounds, fScale, fXPos, const_cast<SkGlyph*>(&glyph), array, count);
|
||||
}
|
||||
return fGlyphs < fStop;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user