// 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; }
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);
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);
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);
}
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);)
}
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();
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; }
SkPoint fFirstOuterPt;
int fSegmentCount;
bool fPrevIsLine;
+ bool fCanIgnoreCenter;
SkStrokerPriv::CapProc fCapper;
SkStrokerPriv::JoinProc fJoiner;
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);
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.
}
}
- 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;
DONE:
stroker.done(dst, lastSegment == SkPath::kLine_Verb);
- if (fDoFill) {
+ if (fDoFill && !ignoreCenter) {
if (SkPathPriv::CheapIsFirstDirection(src, SkPathPriv::kCCW_FirstDirection)) {
dst->reverseAddPath(src);
} else {