aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2016-08-26 05:30:19 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-26 05:30:19 -0700
commitad2344693c70f13d5e4216df8458b4d907395bde (patch)
tree6e4ce1773716748290645e5e18eeb91b723bb5c3
parentcc319b95a58ae15e88c3c028b8726e7cab9121ff (diff)
Ignore fill when stroke & filling convex line-only paths
This seems to work well for miter and bevel joins with the resulting stroke and fill path remaining convex. There seems to be an issue with round joins where the outer generated shell is usually not convex. Without this CL the resulting stroke & filled paths are always concave. Perf-wise (on Windows): convex-lineonly-paths-stroke-and-fill bench (in ms) w/o w/CL %decrease 8888 2.88 2.01 30.2 gpu 4.4 1.38 68.6 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2275243003 Review-Url: https://codereview.chromium.org/2275243003
-rw-r--r--gm/convex_all_line_paths.cpp39
-rw-r--r--src/core/SkStroke.cpp40
2 files changed, 65 insertions, 14 deletions
diff --git a/gm/convex_all_line_paths.cpp b/gm/convex_all_line_paths.cpp
index eb4bdcfd05..a54c0e4a01 100644
--- a/gm/convex_all_line_paths.cpp
+++ b/gm/convex_all_line_paths.cpp
@@ -28,12 +28,17 @@ namespace skiagm {
// paths
class ConvexLineOnlyPathsGM : public GM {
public:
- ConvexLineOnlyPathsGM() {
+ ConvexLineOnlyPathsGM(bool doStrokeAndFill) : fDoStrokeAndFill(doStrokeAndFill) {
this->setBGColor(0xFFFFFFFF);
}
protected:
- SkString onShortName() override { return SkString("convex-lineonly-paths"); }
+ SkString onShortName() override {
+ if (fDoStrokeAndFill) {
+ return SkString("convex-lineonly-paths-stroke-and-fill");
+ }
+ return SkString("convex-lineonly-paths");
+ }
SkISize onISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
bool runAsBench() const override { return true; }
@@ -258,20 +263,35 @@ protected:
if (offset->fX+path.getBounds().width() > kGMWidth) {
offset->fX = 0;
offset->fY += kMaxPathHeight;
+ if (fDoStrokeAndFill) {
+ offset->fX += kStrokeWidth / 2.0f;
+ offset->fY += kStrokeWidth / 2.0f;
+ }
}
center = { offset->fX + SkScalarHalf(path.getBounds().width()), offset->fY};
offset->fX += path.getBounds().width();
+ if (fDoStrokeAndFill) {
+ offset->fX += kStrokeWidth;
+ }
}
const SkColor colors[2] = { SK_ColorBLACK, SK_ColorWHITE };
const SkPath::Direction dirs[2] = { SkPath::kCW_Direction, SkPath::kCCW_Direction };
const float scales[] = { 1.0f, 0.75f, 0.5f, 0.25f, 0.1f, 0.01f, 0.001f };
+ const SkPaint::Join joins[3] = { SkPaint::kRound_Join,
+ SkPaint::kBevel_Join,
+ SkPaint::kMiter_Join };
SkPaint paint;
paint.setAntiAlias(true);
for (size_t i = 0; i < SK_ARRAY_COUNT(scales); ++i) {
SkPath path = GetPath(index, (int) i, dirs[i%2]);
+ if (fDoStrokeAndFill) {
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setStrokeJoin(joins[i%3]);
+ paint.setStrokeWidth(SkIntToScalar(kStrokeWidth));
+ }
canvas->save();
canvas->translate(center.fX, center.fY);
@@ -285,6 +305,10 @@ protected:
void onDraw(SkCanvas* canvas) override {
// the right edge of the last drawn path
SkPoint offset = { 0, SkScalarHalf(kMaxPathHeight) };
+ if (fDoStrokeAndFill) {
+ offset.fX += kStrokeWidth / 2.0f;
+ offset.fY += kStrokeWidth / 2.0f;
+ }
for (int i = 0; i < kNumPaths; ++i) {
this->drawPath(canvas, i, &offset);
@@ -296,6 +320,11 @@ protected:
SkPaint p;
p.setAntiAlias(true);
+ if (fDoStrokeAndFill) {
+ p.setStyle(SkPaint::kStrokeAndFill_Style);
+ p.setStrokeJoin(SkPaint::kMiter_Join);
+ p.setStrokeWidth(SkIntToScalar(kStrokeWidth));
+ }
SkPath p1;
p1.moveTo(60.8522949f, 364.671021f);
@@ -307,15 +336,19 @@ protected:
}
private:
+ static const int kStrokeWidth = 10;
static const int kNumPaths = 20;
static const int kMaxPathHeight = 100;
static const int kGMWidth = 512;
static const int kGMHeight = 512;
+ bool fDoStrokeAndFill;
+
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
-DEF_GM(return new ConvexLineOnlyPathsGM;)
+DEF_GM(return new ConvexLineOnlyPathsGM(false);)
+DEF_GM(return new ConvexLineOnlyPathsGM(true);)
}
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index df3e0f98e1..8ff7910bdc 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -55,7 +55,7 @@ static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after, S
SkScalar radius,
SkVector* normal, SkVector* unitNormal) {
if (!unitNormal->setNormalize((after.fX - before.fX) * scale,
- (after.fY - before.fY) * scale)) {
+ (after.fY - before.fY) * scale)) {
return false;
}
unitNormal->rotateCCW();
@@ -121,7 +121,8 @@ class SkPathStroker {
public:
SkPathStroker(const SkPath& src,
SkScalar radius, SkScalar miterLimit, SkPaint::Cap,
- SkPaint::Join, SkScalar resScale);
+ SkPaint::Join, SkScalar resScale,
+ bool canIgnoreCenter);
bool hasOnlyMoveTo() const { return 0 == fSegmentCount; }
SkPoint moveToPt() const { return fFirstPt; }
@@ -157,6 +158,7 @@ private:
SkPoint fFirstOuterPt;
int fSegmentCount;
bool fPrevIsLine;
+ bool fCanIgnoreCenter;
SkStrokerPriv::CapProc fCapper;
SkStrokerPriv::JoinProc fJoiner;
@@ -294,11 +296,19 @@ void SkPathStroker::finishContour(bool close, bool currIsLine) {
fFirstUnitNormal, fRadius, fInvMiterLimit,
fPrevIsLine, currIsLine);
fOuter.close();
- // now add fInner as its own contour
- fInner.getLastPt(&pt);
- fOuter.moveTo(pt.fX, pt.fY);
- fOuter.reversePathTo(fInner);
- fOuter.close();
+
+ if (fCanIgnoreCenter) {
+ if (!fOuter.getBounds().contains(fInner.getBounds())) {
+ SkASSERT(fInner.getBounds().contains(fOuter.getBounds()));
+ fInner.swap(fOuter);
+ }
+ } else {
+ // now add fInner as its own contour
+ fInner.getLastPt(&pt);
+ fOuter.moveTo(pt.fX, pt.fY);
+ fOuter.reversePathTo(fInner);
+ fOuter.close();
+ }
} else { // add caps to start and end
// cap the end
fInner.getLastPt(&pt);
@@ -321,9 +331,11 @@ void SkPathStroker::finishContour(bool close, bool currIsLine) {
SkPathStroker::SkPathStroker(const SkPath& src,
SkScalar radius, SkScalar miterLimit,
- SkPaint::Cap cap, SkPaint::Join join, SkScalar resScale)
+ SkPaint::Cap cap, SkPaint::Join join, SkScalar resScale,
+ bool canIgnoreCenter)
: fRadius(radius)
- , fResScale(resScale) {
+ , fResScale(resScale)
+ , fCanIgnoreCenter(canIgnoreCenter) {
/* This is only used when join is miter_join, but we initialize it here
so that it is always defined, to fis valgrind warnings.
@@ -1366,7 +1378,13 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
}
}
- SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJoin(), fResScale);
+ // We can always ignore centers for stroke and fill convex line-only paths
+ // TODO: remove the line-only restriction
+ bool ignoreCenter = fDoFill && (src.getSegmentMasks() == SkPath::kLine_SegmentMask) &&
+ src.isLastContourClosed() && src.isConvex();
+
+ SkPathStroker stroker(src, radius, fMiterLimit, this->getCap(), this->getJoin(),
+ fResScale, ignoreCenter);
SkPath::Iter iter(src, false);
SkPath::Verb lastSegment = SkPath::kMove_Verb;
@@ -1420,7 +1438,7 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
DONE:
stroker.done(dst, lastSegment == SkPath::kLine_Verb);
- if (fDoFill) {
+ if (fDoFill && !ignoreCenter) {
if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirection)) {
dst->reverseAddPath(src);
} else {