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"
138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16548a1f321011292359ef163f78c8a1d4871b3b7freed@google.comSkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
17548a1f321011292359ef163f78c8a1d4871b3b7freed@google.comSkCornerPathEffect::~SkCornerPathEffect() {}
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
193334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgstatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
203334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                        SkPoint* step) {
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkPoint::Distance(a, b);
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    step->set(b.fX - a.fX, b.fY - a.fY);
24fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dist <= radius * 2) {
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SK_ScalarHalf);
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
283334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    } else {
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SkScalarDiv(radius, dist));
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
343334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgbool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
354bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com                                    SkStrokeRec*, const SkRect*) const {
36548a1f321011292359ef163f78c8a1d4871b3b7freed@google.com    if (0 == fRadius) {
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
383334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org    }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(src, false);
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        closed;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint     moveTo, lastCorner;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    firstStep, step;
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        prevIsValid = true;
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to avoid warnings
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    moveTo.set(0, 0);
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    firstStep.set(0, 0);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    lastCorner.set(0, 0);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (;;) {
554a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com        switch (verb = iter.next(pts, false)) {
563334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kMove_Verb:
573334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    // close out the previous (open) contour
583334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (SkPath::kLine_Verb == prevVerb) {
593334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->lineTo(lastCorner);
603334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
613334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                closed = iter.isClosedContour();
623334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (closed) {
633334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    moveTo = pts[0];
643334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = false;
653334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
663334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
673334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
683334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
693334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
703334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kLine_Verb: {
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // prev corner
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!prevIsValid) {
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->moveTo(moveTo + step);
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    prevIsValid = true;
763334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                } else {
773334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
783334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                pts[0].fY + step.fY);
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (drawSegment) {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastCorner = pts[1];
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
853334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
873334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kQuad_Verb:
883334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
893334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
903334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
913334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
923334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
933334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->quadTo(pts[1], pts[2]);
943334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[2];
953334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
963334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
973334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kCubic_Verb:
983334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (!prevIsValid) {
993334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->moveTo(pts[0]);
1003334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    prevIsValid = true;
1013334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                }
1023334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                // TBD - just replicate the curve for now
1033334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->cubicTo(pts[1], pts[2], pts[3]);
1043334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                lastCorner = pts[3];
1053334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                firstStep.set(0, 0);
1063334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
1073334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kClose_Verb:
1083334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                if (firstStep.fX || firstStep.fY) {
1093334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    dst->quadTo(lastCorner.fX, lastCorner.fY,
1103334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fX + firstStep.fX,
1113334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                                lastCorner.fY + firstStep.fY);
1123334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                    }
1133334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                dst->close();
1143334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                break;
115277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com            case SkPath::kConic_Verb:
116277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com                SkASSERT(0);
117277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com                break;
1183334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org            case SkPath::kDone_Verb:
1193334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org                goto DONE;
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1223334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        if (SkPath::kMove_Verb == prevVerb) {
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep = step;
1243334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.org        }
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prevVerb = verb;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comDONE:
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1318b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
13254924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com    this->INHERITED::flatten(buffer);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fRadius);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1368b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) {
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRadius = buffer.readScalar();
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
139