SkCornerPathEffect.cpp revision 4bbdeac58cc928dc66296bde3bd06e78070d96b7
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"
13c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com#include "SkFlattenableBuffers.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15548a1f321011292359ef163f78c8a1d4871b3b7freed@google.comSkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
16548a1f321011292359ef163f78c8a1d4871b3b7freed@google.comSkCornerPathEffect::~SkCornerPathEffect() {}
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
183334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgstatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
193334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                        SkPoint* step) {
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkPoint::Distance(a, b);
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    step->set(b.fX - a.fX, b.fY - a.fY);
23fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dist <= radius * 2) {
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SK_ScalarHalf);
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
273334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    } else {
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SkScalarDiv(radius, dist));
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
333334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgbool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
344bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com                                    SkStrokeRec*, const SkRect*) const {
35548a1f321011292359ef163f78c8a1d4871b3b7freed@google.com    if (0 == fRadius) {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
373334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    }
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(src, false);
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        closed;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint     moveTo, lastCorner;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    firstStep, step;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        prevIsValid = true;
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to avoid warnings
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    moveTo.set(0, 0);
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    firstStep.set(0, 0);
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    lastCorner.set(0, 0);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (;;) {
544a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com        switch (verb = iter.next(pts, false)) {
553334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kMove_Verb:
563334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    // close out the previous (open) contour
573334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (SkPath::kLine_Verb == prevVerb) {
583334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->lineTo(lastCorner);
593334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
603334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                closed = iter.isClosedContour();
613334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (closed) {
623334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    moveTo = pts[0];
633334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = false;
643334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
653334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
663334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
673334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
683334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
693334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kLine_Verb: {
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // prev corner
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!prevIsValid) {
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->moveTo(moveTo + step);
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    prevIsValid = true;
753334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
763334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
773334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                pts[0].fY + step.fY);
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (drawSegment) {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastCorner = pts[1];
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
843334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
863334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kQuad_Verb:
873334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
883334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
893334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
903334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
913334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
923334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->quadTo(pts[1], pts[2]);
933334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[2];
943334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
953334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
963334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kCubic_Verb:
973334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
983334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
993334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
1003334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
1013334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
1023334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->cubicTo(pts[1], pts[2], pts[3]);
1033334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[3];
1043334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
1053334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1063334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kClose_Verb:
1073334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (firstStep.fX || firstStep.fY) {
1083334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(lastCorner.fX, lastCorner.fY,
1093334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fX + firstStep.fX,
1103334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fY + firstStep.fY);
1113334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    }
1123334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->close();
1133334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1143334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kDone_Verb:
1153334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                goto DONE;
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1183334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        if (SkPath::kMove_Verb == prevVerb) {
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep = step;
1203334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        }
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prevVerb = verb;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comDONE:
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12754924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.comvoid SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
12854924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com    this->INHERITED::flatten(buffer);
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fRadius);
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1323334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgSkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRadius = buffer.readScalar();
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
135