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