blob: f4c31473018badb5164881756e46440d6bfb8415 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkCornerPathEffect.h"
11#include "SkPath.h"
12#include "SkPoint.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000013#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
reed@google.com548a1f32012-12-18 16:12:09 +000015SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
16SkCornerPathEffect::~SkCornerPathEffect() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000018static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
19 SkPoint* step) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 SkScalar dist = SkPoint::Distance(a, b);
21
22 step->set(b.fX - a.fX, b.fY - a.fY);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000023
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 if (dist <= radius * 2) {
25 step->scale(SK_ScalarHalf);
26 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000027 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 step->scale(SkScalarDiv(radius, dist));
29 return true;
30 }
31}
32
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000033bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
reed@google.com4bbdeac2013-01-24 21:03:11 +000034 SkStrokeRec*, const SkRect*) const {
reed@google.com548a1f32012-12-18 16:12:09 +000035 if (0 == fRadius) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 return false;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
39 SkPath::Iter iter(src, false);
40 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
41 SkPoint pts[4];
42
43 bool closed;
44 SkPoint moveTo, lastCorner;
45 SkVector firstStep, step;
46 bool prevIsValid = true;
47
48 // to avoid warnings
49 moveTo.set(0, 0);
50 firstStep.set(0, 0);
51 lastCorner.set(0, 0);
52
53 for (;;) {
reed@google.com4a3b7142012-05-16 17:16:46 +000054 switch (verb = iter.next(pts, false)) {
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000055 case SkPath::kMove_Verb:
56 // close out the previous (open) contour
57 if (SkPath::kLine_Verb == prevVerb) {
58 dst->lineTo(lastCorner);
59 }
60 closed = iter.isClosedContour();
61 if (closed) {
62 moveTo = pts[0];
63 prevIsValid = false;
64 } else {
65 dst->moveTo(pts[0]);
66 prevIsValid = true;
67 }
68 break;
69 case SkPath::kLine_Verb: {
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
71 // prev corner
72 if (!prevIsValid) {
73 dst->moveTo(moveTo + step);
74 prevIsValid = true;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000075 } else {
76 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
77 pts[0].fY + step.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 }
79 if (drawSegment) {
80 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
81 }
82 lastCorner = pts[1];
83 prevIsValid = true;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000084 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 }
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +000086 case SkPath::kQuad_Verb:
87 // TBD - just replicate the curve for now
88 if (!prevIsValid) {
89 dst->moveTo(pts[0]);
90 prevIsValid = true;
91 }
92 dst->quadTo(pts[1], pts[2]);
93 lastCorner = pts[2];
94 firstStep.set(0, 0);
95 break;
96 case SkPath::kCubic_Verb:
97 if (!prevIsValid) {
98 dst->moveTo(pts[0]);
99 prevIsValid = true;
100 }
101 // TBD - just replicate the curve for now
102 dst->cubicTo(pts[1], pts[2], pts[3]);
103 lastCorner = pts[3];
104 firstStep.set(0, 0);
105 break;
106 case SkPath::kClose_Verb:
107 if (firstStep.fX || firstStep.fY) {
108 dst->quadTo(lastCorner.fX, lastCorner.fY,
109 lastCorner.fX + firstStep.fX,
110 lastCorner.fY + firstStep.fY);
111 }
112 dst->close();
113 break;
reed@google.com277c3f82013-05-31 15:17:50 +0000114 case SkPath::kConic_Verb:
115 SkASSERT(0);
116 break;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000117 case SkPath::kDone_Verb:
118 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 }
120
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000121 if (SkPath::kMove_Verb == prevVerb) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 firstStep = step;
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000123 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 prevVerb = verb;
125 }
126DONE:
127 return true;
128}
129
djsollen@google.com54924242012-03-29 15:18:04 +0000130void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
131 this->INHERITED::flatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 buffer.writeScalar(fRadius);
133}
134
mike@reedtribe.org3334c3a2011-04-20 11:39:28 +0000135SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 fRadius = buffer.readScalar();
137}