SkCornerPathEffect.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* libs/graphics/effects/SkCornerPathEffect.cpp
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Copyright 2006, The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
58a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Licensed under the Apache License, Version 2.0 (the "License");
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** you may not use this file except in compliance with the License.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** You may obtain a copy of the License at
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**     http://www.apache.org/licenses/LICENSE-2.0
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com**
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** Unless required by applicable law or agreed to in writing, software
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** distributed under the License is distributed on an "AS IS" BASIS,
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** See the License for the specific language governing permissions and
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com** limitations under the License.
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCornerPathEffect.h"
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPoint.h"
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBuffer.h"
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCornerPathEffect::~SkCornerPathEffect()
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkPoint* step)
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar dist = SkPoint::Distance(a, b);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    step->set(b.fX - a.fX, b.fY - a.fY);
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dist <= radius * 2) {
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SK_ScalarHalf);
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    else {
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        step->scale(SkScalarDiv(radius, dist));
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fRadius == 0)
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(src, false);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        closed;
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint     moveTo, lastCorner;
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    firstStep, step;
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool        prevIsValid = true;
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to avoid warnings
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    moveTo.set(0, 0);
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    firstStep.set(0, 0);
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    lastCorner.set(0, 0);
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (;;) {
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (verb = iter.next(pts)) {
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kMove_Verb:
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            closed = iter.isClosedContour();
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (closed) {
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                moveTo = pts[0];
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = false;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else {
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst->moveTo(pts[0]);
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kLine_Verb:
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // prev corner
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!prevIsValid) {
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->moveTo(moveTo + step);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    prevIsValid = true;
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                else {
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (drawSegment) {
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastCorner = pts[1];
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kQuad_Verb:
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // TBD - just replicate the curve for now
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!prevIsValid)
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            {
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst->moveTo(pts[0]);
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst->quadTo(pts[1], pts[2]);
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastCorner = pts[2];
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep.set(0, 0);
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kCubic_Verb:
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!prevIsValid)
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            {
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst->moveTo(pts[0]);
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                prevIsValid = true;
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // TBD - just replicate the curve for now
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst->cubicTo(pts[1], pts[2], pts[3]);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastCorner = pts[3];
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep.set(0, 0);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kClose_Verb:
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (firstStep.fX || firstStep.fY)
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst->quadTo(lastCorner.fX, lastCorner.fY,
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            lastCorner.fX + firstStep.fX,
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            lastCorner.fY + firstStep.fY);
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst->close();
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkPath::kDone_Verb:
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto DONE;
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (SkPath::kMove_Verb == prevVerb)
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            firstStep = step;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prevVerb = verb;
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comDONE:
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkFlattenable::Factory SkCornerPathEffect::getFactory()
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return CreateProc;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fRadius);
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkNEW_ARGS(SkCornerPathEffect, (buffer));
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer)
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRadius = buffer.readScalar();
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158