blob: e1acaf999770eddaaedfdc526146b72db28d822f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008
9#include "SkCornerPathEffect.h"
10#include "SkPath.h"
11#include "SkPoint.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
Mike Reed85fdbe22018-02-22 10:03:35 -050015SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) {
16 // check with ! to catch NaNs
17 if (!(radius > 0)) {
18 radius = 0;
19 }
20 fRadius = radius;
21}
reed@google.com548a1f32012-12-18 16:12:09 +000022SkCornerPathEffect::~SkCornerPathEffect() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000024static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
25 SkPoint* step) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 SkScalar dist = SkPoint::Distance(a, b);
27
reed80ea19c2015-05-12 10:37:34 -070028 *step = b - a;
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 if (dist <= radius * 2) {
reed80ea19c2015-05-12 10:37:34 -070030 *step *= SK_ScalarHalf;
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000032 } else {
reed80ea19c2015-05-12 10:37:34 -070033 *step *= radius / dist;
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 return true;
35 }
36}
37
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000038bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
reed@google.com4bbdeac2013-01-24 21:03:11 +000039 SkStrokeRec*, const SkRect*) const {
Mike Reed85fdbe22018-02-22 10:03:35 -050040 if (fRadius <= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000042 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
44 SkPath::Iter iter(src, false);
45 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
46 SkPoint pts[4];
47
48 bool closed;
49 SkPoint moveTo, lastCorner;
50 SkVector firstStep, step;
51 bool prevIsValid = true;
52
53 // to avoid warnings
reed80ea19c2015-05-12 10:37:34 -070054 step.set(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 moveTo.set(0, 0);
56 firstStep.set(0, 0);
57 lastCorner.set(0, 0);
58
59 for (;;) {
reed@google.com4a3b7142012-05-16 17:16:46 +000060 switch (verb = iter.next(pts, false)) {
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000061 case SkPath::kMove_Verb:
62 // close out the previous (open) contour
63 if (SkPath::kLine_Verb == prevVerb) {
64 dst->lineTo(lastCorner);
65 }
66 closed = iter.isClosedContour();
67 if (closed) {
68 moveTo = pts[0];
69 prevIsValid = false;
70 } else {
71 dst->moveTo(pts[0]);
72 prevIsValid = true;
73 }
74 break;
75 case SkPath::kLine_Verb: {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
77 // prev corner
78 if (!prevIsValid) {
79 dst->moveTo(moveTo + step);
80 prevIsValid = true;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000081 } else {
82 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
83 pts[0].fY + step.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 }
85 if (drawSegment) {
86 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
87 }
88 lastCorner = pts[1];
89 prevIsValid = true;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000090 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000092 case SkPath::kQuad_Verb:
93 // TBD - just replicate the curve for now
94 if (!prevIsValid) {
95 dst->moveTo(pts[0]);
96 prevIsValid = true;
97 }
98 dst->quadTo(pts[1], pts[2]);
99 lastCorner = pts[2];
100 firstStep.set(0, 0);
101 break;
reed2b9445b2014-12-17 05:50:55 -0800102 case SkPath::kConic_Verb:
103 // TBD - just replicate the curve for now
104 if (!prevIsValid) {
105 dst->moveTo(pts[0]);
106 prevIsValid = true;
107 }
108 dst->conicTo(pts[1], pts[2], iter.conicWeight());
109 lastCorner = pts[2];
110 firstStep.set(0, 0);
111 break;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000112 case SkPath::kCubic_Verb:
113 if (!prevIsValid) {
114 dst->moveTo(pts[0]);
115 prevIsValid = true;
116 }
117 // TBD - just replicate the curve for now
118 dst->cubicTo(pts[1], pts[2], pts[3]);
119 lastCorner = pts[3];
120 firstStep.set(0, 0);
121 break;
122 case SkPath::kClose_Verb:
123 if (firstStep.fX || firstStep.fY) {
124 dst->quadTo(lastCorner.fX, lastCorner.fY,
125 lastCorner.fX + firstStep.fX,
126 lastCorner.fY + firstStep.fY);
127 }
128 dst->close();
reed2b9445b2014-12-17 05:50:55 -0800129 prevIsValid = false;
reed@google.com277c3f82013-05-31 15:17:50 +0000130 break;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000131 case SkPath::kDone_Verb:
reed2b9445b2014-12-17 05:50:55 -0800132 if (prevIsValid) {
133 dst->lineTo(lastCorner);
134 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000135 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 }
137
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000138 if (SkPath::kMove_Verb == prevVerb) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 firstStep = step;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 prevVerb = verb;
142 }
143DONE:
144 return true;
145}
146
reed60c9b582016-04-03 09:11:13 -0700147sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
148 return SkCornerPathEffect::Make(buffer.readScalar());
reed9fa60da2014-08-21 07:59:51 -0700149}
150
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000151void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 buffer.writeScalar(fRadius);
153}
robertphillips42dbfa82015-01-26 06:08:52 -0800154
155#ifndef SK_IGNORE_TO_STRING
156void SkCornerPathEffect::toString(SkString* str) const {
157 str->appendf("SkCornerPathEffect: (");
158 str->appendf("radius: %.2f", fRadius);
159 str->appendf(")");
160}
161#endif