1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 10cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 11cb93a386Sopenharmony_ci#include "include/effects/SkCornerPathEffect.h" 12cb93a386Sopenharmony_ci#include "src/core/SkPathEffectBase.h" 13cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 14cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, 17cb93a386Sopenharmony_ci SkPoint* step) { 18cb93a386Sopenharmony_ci SkScalar dist = SkPoint::Distance(a, b); 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci *step = b - a; 21cb93a386Sopenharmony_ci if (dist <= radius * 2) { 22cb93a386Sopenharmony_ci *step *= SK_ScalarHalf; 23cb93a386Sopenharmony_ci return false; 24cb93a386Sopenharmony_ci } else { 25cb93a386Sopenharmony_ci *step *= radius / dist; 26cb93a386Sopenharmony_ci return true; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci} 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ciclass SkCornerPathEffectImpl : public SkPathEffectBase { 31cb93a386Sopenharmony_cipublic: 32cb93a386Sopenharmony_ci explicit SkCornerPathEffectImpl(SkScalar radius) : fRadius(radius) { 33cb93a386Sopenharmony_ci SkASSERT(radius > 0); 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*, 37cb93a386Sopenharmony_ci const SkMatrix&) const override { 38cb93a386Sopenharmony_ci if (fRadius <= 0) { 39cb93a386Sopenharmony_ci return false; 40cb93a386Sopenharmony_ci } 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci SkPath::Iter iter(src, false); 43cb93a386Sopenharmony_ci SkPath::Verb verb, prevVerb = SkPath::kDone_Verb; 44cb93a386Sopenharmony_ci SkPoint pts[4]; 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci bool closed; 47cb93a386Sopenharmony_ci SkPoint moveTo, lastCorner; 48cb93a386Sopenharmony_ci SkVector firstStep, step; 49cb93a386Sopenharmony_ci bool prevIsValid = true; 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci // to avoid warnings 52cb93a386Sopenharmony_ci step.set(0, 0); 53cb93a386Sopenharmony_ci moveTo.set(0, 0); 54cb93a386Sopenharmony_ci firstStep.set(0, 0); 55cb93a386Sopenharmony_ci lastCorner.set(0, 0); 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci for (;;) { 58cb93a386Sopenharmony_ci switch (verb = iter.next(pts)) { 59cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 60cb93a386Sopenharmony_ci // close out the previous (open) contour 61cb93a386Sopenharmony_ci if (SkPath::kLine_Verb == prevVerb) { 62cb93a386Sopenharmony_ci dst->lineTo(lastCorner); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci closed = iter.isClosedContour(); 65cb93a386Sopenharmony_ci if (closed) { 66cb93a386Sopenharmony_ci moveTo = pts[0]; 67cb93a386Sopenharmony_ci prevIsValid = false; 68cb93a386Sopenharmony_ci } else { 69cb93a386Sopenharmony_ci dst->moveTo(pts[0]); 70cb93a386Sopenharmony_ci prevIsValid = true; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci break; 73cb93a386Sopenharmony_ci case SkPath::kLine_Verb: { 74cb93a386Sopenharmony_ci bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step); 75cb93a386Sopenharmony_ci // prev corner 76cb93a386Sopenharmony_ci if (!prevIsValid) { 77cb93a386Sopenharmony_ci dst->moveTo(moveTo + step); 78cb93a386Sopenharmony_ci prevIsValid = true; 79cb93a386Sopenharmony_ci } else { 80cb93a386Sopenharmony_ci dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, 81cb93a386Sopenharmony_ci pts[0].fY + step.fY); 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci if (drawSegment) { 84cb93a386Sopenharmony_ci dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY); 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci lastCorner = pts[1]; 87cb93a386Sopenharmony_ci prevIsValid = true; 88cb93a386Sopenharmony_ci break; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 91cb93a386Sopenharmony_ci // TBD - just replicate the curve for now 92cb93a386Sopenharmony_ci if (!prevIsValid) { 93cb93a386Sopenharmony_ci dst->moveTo(pts[0]); 94cb93a386Sopenharmony_ci prevIsValid = true; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci dst->quadTo(pts[1], pts[2]); 97cb93a386Sopenharmony_ci lastCorner = pts[2]; 98cb93a386Sopenharmony_ci firstStep.set(0, 0); 99cb93a386Sopenharmony_ci break; 100cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 101cb93a386Sopenharmony_ci // TBD - just replicate the curve for now 102cb93a386Sopenharmony_ci if (!prevIsValid) { 103cb93a386Sopenharmony_ci dst->moveTo(pts[0]); 104cb93a386Sopenharmony_ci prevIsValid = true; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci dst->conicTo(pts[1], pts[2], iter.conicWeight()); 107cb93a386Sopenharmony_ci lastCorner = pts[2]; 108cb93a386Sopenharmony_ci firstStep.set(0, 0); 109cb93a386Sopenharmony_ci break; 110cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 111cb93a386Sopenharmony_ci if (!prevIsValid) { 112cb93a386Sopenharmony_ci dst->moveTo(pts[0]); 113cb93a386Sopenharmony_ci prevIsValid = true; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci // TBD - just replicate the curve for now 116cb93a386Sopenharmony_ci dst->cubicTo(pts[1], pts[2], pts[3]); 117cb93a386Sopenharmony_ci lastCorner = pts[3]; 118cb93a386Sopenharmony_ci firstStep.set(0, 0); 119cb93a386Sopenharmony_ci break; 120cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 121cb93a386Sopenharmony_ci if (firstStep.fX || firstStep.fY) { 122cb93a386Sopenharmony_ci dst->quadTo(lastCorner.fX, lastCorner.fY, 123cb93a386Sopenharmony_ci lastCorner.fX + firstStep.fX, 124cb93a386Sopenharmony_ci lastCorner.fY + firstStep.fY); 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci dst->close(); 127cb93a386Sopenharmony_ci prevIsValid = false; 128cb93a386Sopenharmony_ci break; 129cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 130cb93a386Sopenharmony_ci if (prevIsValid) { 131cb93a386Sopenharmony_ci dst->lineTo(lastCorner); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci return true; 134cb93a386Sopenharmony_ci default: 135cb93a386Sopenharmony_ci SkDEBUGFAIL("default should not be reached"); 136cb93a386Sopenharmony_ci return false; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (SkPath::kMove_Verb == prevVerb) { 140cb93a386Sopenharmony_ci firstStep = step; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci prevVerb = verb; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci return true; 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci bool computeFastBounds(SkRect*) const override { 148cb93a386Sopenharmony_ci // Rounding sharp corners within a path produces a new path that is still contained within 149cb93a386Sopenharmony_ci // the original's bounds, so leave 'bounds' unmodified. 150cb93a386Sopenharmony_ci return true; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) { 154cb93a386Sopenharmony_ci return SkCornerPathEffect::Make(buffer.readScalar()); 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci void flatten(SkWriteBuffer& buffer) const override { 158cb93a386Sopenharmony_ci buffer.writeScalar(fRadius); 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci Factory getFactory() const override { return CreateProc; } 162cb93a386Sopenharmony_ci const char* getTypeName() const override { return "SkCornerPathEffect"; } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ciprivate: 165cb93a386Sopenharmony_ci const SkScalar fRadius; 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci using INHERITED = SkPathEffectBase; 168cb93a386Sopenharmony_ci}; 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////// 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkCornerPathEffect::Make(SkScalar radius) { 173cb93a386Sopenharmony_ci return SkScalarIsFinite(radius) && (radius > 0) ? 174cb93a386Sopenharmony_ci sk_sp<SkPathEffect>(new SkCornerPathEffectImpl(radius)) : nullptr; 175cb93a386Sopenharmony_ci} 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_civoid SkCornerPathEffect::RegisterFlattenables() { 178cb93a386Sopenharmony_ci SkFlattenable::Register("SkCornerPathEffect", SkCornerPathEffectImpl::CreateProc); 179cb93a386Sopenharmony_ci} 180