10910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* libs/graphics/effects/Sk1DPathEffect.cpp
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
30910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Copyright 2006, The Android Open Source Project
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
50910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
60910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** you may not use this file except in compliance with the License.
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** You may obtain a copy of the License at
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** See the License for the specific language governing permissions and
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** limitations under the License.
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "Sk1DPathEffect.h"
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPathMeasure.h"
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPathMeasure   meas(src, false);
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    length = meas.getLength();
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    distance = this->begin(length);
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        while (distance < length)
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar delta = this->next(dst, distance, meas);
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (delta <= 0)
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            distance += delta;
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (meas.nextContour());
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////////////////
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance,
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar phase, Style style) : fPath(path)
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (advance <= 0 || path.isEmpty())
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDEBUGF(("SkPath1DPathEffect can't use advance <= 0\n"));
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fAdvance = 0;   // signals we can't draw anything
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // cleanup their phase parameter, inverting it so that it becomes an
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // offset along the path (to match the interpretation in PostScript)
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (phase < 0)
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            phase = -phase;
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (phase > advance)
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                phase = SkScalarMod(phase, advance);
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        else
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (phase > advance)
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                phase = SkScalarMod(phase, advance);
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            phase = advance - phase;
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // now catch the edge case where phase == advance (within epsilon)
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (phase >= advance)
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            phase = 0;
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(phase >= 0);
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fAdvance = advance;
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fInitialOffset = phase;
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if ((unsigned)style >= kStyleCount) {
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkDEBUGF(("SkPath1DPathEffect style enum out of range %d\n", style));
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fStyle = style;
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fAdvance > 0)
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *width = -1;
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return this->INHERITED::filterPath(dst, src, width);
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void morphpoints(SkPoint dst[], const SkPoint src[], int count,
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        SkPathMeasure& meas, SkScalar dist)
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < count; i++)
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint pos;
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkVector tangent;
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar sx = src[i].fX;
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar sy = src[i].fY;
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        meas.getPosTan(dist + sx, &pos, &tangent);
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMatrix    matrix;
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint     pt;
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pt.set(sx, sy);
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.setSinCos(tangent.fY, tangent.fX, 0, 0);
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.preTranslate(-sx, 0);
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.postTranslate(pos.fX, pos.fY);
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix.mapPoints(&dst[i], &pt, 1);
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  TODO
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectNeed differentially more subdivisions when the follow-path is curvy. Not sure how to
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectdetermine that, but we need it. I guess a cheap answer is let the caller tell us,
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbut that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, SkScalar dist)
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Iter    iter(src, false);
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint         srcP[4], dstP[3];
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPath::Verb    verb;
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while ((verb = iter.next(srcP)) != SkPath::kDone_Verb)
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (verb) {
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kMove_Verb:
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                morphpoints(dstP, srcP, 1, meas, dist);
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->moveTo(dstP[0]);
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kLine_Verb:
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                srcP[2] = srcP[1];
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX),
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                            SkScalarAve(srcP[0].fY, srcP[2].fY));
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // fall through to quad
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kQuad_Verb:
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                morphpoints(dstP, &srcP[1], 2, meas, dist);
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->quadTo(dstP[0], dstP[1]);
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kCubic_Verb:
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                morphpoints(dstP, &srcP[1], 3, meas, dist);
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->cubicTo(dstP[0], dstP[1], dstP[2]);
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            case SkPath::kClose_Verb:
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dst->close();
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            default:
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(!"unknown verb");
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkPath1DPathEffect::SkPath1DPathEffect(SkFlattenableReadBuffer& buffer)
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fAdvance = buffer.readScalar();
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fAdvance > 0) {
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPath.unflatten(buffer);
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fInitialOffset = buffer.readScalar();
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fStyle = (Style) buffer.readU8();
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPath1DPathEffect::begin(SkScalar contourLength)
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fInitialOffset;
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkPath1DPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeScalar(fAdvance);
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fAdvance > 0) {
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPath.flatten(buffer);
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        buffer.writeScalar(fInitialOffset);
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        buffer.write8(fStyle);
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance, SkPathMeasure& meas)
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (fStyle) {
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kTranslate_Style:
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkPoint pos;
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            meas.getPosTan(distance, &pos, NULL);
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst->addPath(fPath, pos.fX, pos.fY);
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kRotate_Style:
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkMatrix matrix;
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            meas.getMatrix(distance, &matrix);
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst->addPath(fPath, matrix);
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case kMorph_Style:
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            morphpath(dst, fPath, meas, distance);
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(!"unknown Style enum");
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fAdvance;
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
207