SkCornerPathEffect.cpp revision 4a3b714d73e585a3985d614600c6b79d5c8b1f1e
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCornerPathEffect.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPoint.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBuffer.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCornerPathEffect::~SkCornerPathEffect()
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
233334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgstatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
243334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                        SkPoint* step) {
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkPoint::Distance(a, b);
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    step->set(b.fX - a.fX, b.fY - a.fY);
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dist <= radius * 2) {
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SK_ScalarHalf);
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
323334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    } else {
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SkScalarDiv(radius, dist));
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
383334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgbool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
393334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                    SkScalar* width) {
403334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    if (fRadius == 0) {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
423334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    }
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(src, false);
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        closed;
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint     moveTo, lastCorner;
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    firstStep, step;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        prevIsValid = true;
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to avoid warnings
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    moveTo.set(0, 0);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    firstStep.set(0, 0);
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    lastCorner.set(0, 0);
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (;;) {
594a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com        switch (verb = iter.next(pts, false)) {
603334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kMove_Verb:
613334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    // close out the previous (open) contour
623334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (SkPath::kLine_Verb == prevVerb) {
633334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->lineTo(lastCorner);
643334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
653334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                closed = iter.isClosedContour();
663334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (closed) {
673334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    moveTo = pts[0];
683334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = false;
693334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
703334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
713334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
723334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
733334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
743334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kLine_Verb: {
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // prev corner
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!prevIsValid) {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->moveTo(moveTo + step);
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    prevIsValid = true;
803334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
813334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
823334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                pts[0].fY + step.fY);
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (drawSegment) {
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastCorner = pts[1];
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
893334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
913334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kQuad_Verb:
923334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
933334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
943334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
953334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
963334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
973334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->quadTo(pts[1], pts[2]);
983334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[2];
993334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
1003334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1013334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kCubic_Verb:
1023334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
1033334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
1043334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
1053334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
1063334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
1073334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->cubicTo(pts[1], pts[2], pts[3]);
1083334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[3];
1093334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
1103334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1113334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kClose_Verb:
1123334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (firstStep.fX || firstStep.fY) {
1133334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(lastCorner.fX, lastCorner.fY,
1143334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fX + firstStep.fX,
1153334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fY + firstStep.fY);
1163334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    }
1173334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->close();
1183334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1193334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kDone_Verb:
1203334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                goto DONE;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1233334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        if (SkPath::kMove_Verb == prevVerb) {
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep = step;
1253334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        }
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prevVerb = verb;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comDONE:
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13254924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.comvoid SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
13354924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com    this->INHERITED::flatten(buffer);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fRadius);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1373334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgSkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRadius = buffer.readScalar();
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
141d26147adbbdca85f07dff432025afee0c8614387caryclark@google.comSK_DEFINE_FLATTENABLE_REGISTRAR(SkCornerPathEffect)
1426bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
143