1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/Sk1DPathEffect.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,201 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "Sk1DPathEffect.h" 1.14 +#include "SkReadBuffer.h" 1.15 +#include "SkWriteBuffer.h" 1.16 +#include "SkPathMeasure.h" 1.17 + 1.18 +bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, 1.19 + SkStrokeRec*, const SkRect*) const { 1.20 + SkPathMeasure meas(src, false); 1.21 + do { 1.22 + SkScalar length = meas.getLength(); 1.23 + SkScalar distance = this->begin(length); 1.24 + while (distance < length) { 1.25 + SkScalar delta = this->next(dst, distance, meas); 1.26 + if (delta <= 0) { 1.27 + break; 1.28 + } 1.29 + distance += delta; 1.30 + } 1.31 + } while (meas.nextContour()); 1.32 + return true; 1.33 +} 1.34 + 1.35 +/////////////////////////////////////////////////////////////////////////////// 1.36 + 1.37 +SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance, 1.38 + SkScalar phase, Style style) : fPath(path) 1.39 +{ 1.40 + if (advance <= 0 || path.isEmpty()) { 1.41 + SkDEBUGF(("SkPath1DPathEffect can't use advance <= 0\n")); 1.42 + fAdvance = 0; // signals we can't draw anything 1.43 + fInitialOffset = 0; 1.44 + fStyle = kStyleCount; 1.45 + } else { 1.46 + // cleanup their phase parameter, inverting it so that it becomes an 1.47 + // offset along the path (to match the interpretation in PostScript) 1.48 + if (phase < 0) { 1.49 + phase = -phase; 1.50 + if (phase > advance) { 1.51 + phase = SkScalarMod(phase, advance); 1.52 + } 1.53 + } else { 1.54 + if (phase > advance) { 1.55 + phase = SkScalarMod(phase, advance); 1.56 + } 1.57 + phase = advance - phase; 1.58 + } 1.59 + // now catch the edge case where phase == advance (within epsilon) 1.60 + if (phase >= advance) { 1.61 + phase = 0; 1.62 + } 1.63 + SkASSERT(phase >= 0); 1.64 + 1.65 + fAdvance = advance; 1.66 + fInitialOffset = phase; 1.67 + 1.68 + if ((unsigned)style >= kStyleCount) { 1.69 + SkDEBUGF(("SkPath1DPathEffect style enum out of range %d\n", style)); 1.70 + } 1.71 + fStyle = style; 1.72 + } 1.73 +} 1.74 + 1.75 +bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, 1.76 + SkStrokeRec* rec, const SkRect* cullRect) const { 1.77 + if (fAdvance > 0) { 1.78 + rec->setFillStyle(); 1.79 + return this->INHERITED::filterPath(dst, src, rec, cullRect); 1.80 + } 1.81 + return false; 1.82 +} 1.83 + 1.84 +static bool morphpoints(SkPoint dst[], const SkPoint src[], int count, 1.85 + SkPathMeasure& meas, SkScalar dist) { 1.86 + for (int i = 0; i < count; i++) { 1.87 + SkPoint pos; 1.88 + SkVector tangent; 1.89 + 1.90 + SkScalar sx = src[i].fX; 1.91 + SkScalar sy = src[i].fY; 1.92 + 1.93 + if (!meas.getPosTan(dist + sx, &pos, &tangent)) { 1.94 + return false; 1.95 + } 1.96 + 1.97 + SkMatrix matrix; 1.98 + SkPoint pt; 1.99 + 1.100 + pt.set(sx, sy); 1.101 + matrix.setSinCos(tangent.fY, tangent.fX, 0, 0); 1.102 + matrix.preTranslate(-sx, 0); 1.103 + matrix.postTranslate(pos.fX, pos.fY); 1.104 + matrix.mapPoints(&dst[i], &pt, 1); 1.105 + } 1.106 + return true; 1.107 +} 1.108 + 1.109 +/* TODO 1.110 + 1.111 +Need differentially more subdivisions when the follow-path is curvy. Not sure how to 1.112 +determine that, but we need it. I guess a cheap answer is let the caller tell us, 1.113 +but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 1.114 +*/ 1.115 +static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 1.116 + SkScalar dist) { 1.117 + SkPath::Iter iter(src, false); 1.118 + SkPoint srcP[4], dstP[3]; 1.119 + SkPath::Verb verb; 1.120 + 1.121 + while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 1.122 + switch (verb) { 1.123 + case SkPath::kMove_Verb: 1.124 + if (morphpoints(dstP, srcP, 1, meas, dist)) { 1.125 + dst->moveTo(dstP[0]); 1.126 + } 1.127 + break; 1.128 + case SkPath::kLine_Verb: 1.129 + srcP[2] = srcP[1]; 1.130 + srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX), 1.131 + SkScalarAve(srcP[0].fY, srcP[2].fY)); 1.132 + // fall through to quad 1.133 + case SkPath::kQuad_Verb: 1.134 + if (morphpoints(dstP, &srcP[1], 2, meas, dist)) { 1.135 + dst->quadTo(dstP[0], dstP[1]); 1.136 + } 1.137 + break; 1.138 + case SkPath::kCubic_Verb: 1.139 + if (morphpoints(dstP, &srcP[1], 3, meas, dist)) { 1.140 + dst->cubicTo(dstP[0], dstP[1], dstP[2]); 1.141 + } 1.142 + break; 1.143 + case SkPath::kClose_Verb: 1.144 + dst->close(); 1.145 + break; 1.146 + default: 1.147 + SkDEBUGFAIL("unknown verb"); 1.148 + break; 1.149 + } 1.150 + } 1.151 +} 1.152 + 1.153 +SkPath1DPathEffect::SkPath1DPathEffect(SkReadBuffer& buffer) { 1.154 + fAdvance = buffer.readScalar(); 1.155 + if (fAdvance > 0) { 1.156 + buffer.readPath(&fPath); 1.157 + fInitialOffset = buffer.readScalar(); 1.158 + fStyle = (Style) buffer.readUInt(); 1.159 + } else { 1.160 + SkDEBUGF(("SkPath1DPathEffect can't use advance <= 0\n")); 1.161 + // Make Coverity happy. 1.162 + fInitialOffset = 0; 1.163 + fStyle = kStyleCount; 1.164 + } 1.165 +} 1.166 + 1.167 +SkScalar SkPath1DPathEffect::begin(SkScalar contourLength) const { 1.168 + return fInitialOffset; 1.169 +} 1.170 + 1.171 +void SkPath1DPathEffect::flatten(SkWriteBuffer& buffer) const { 1.172 + this->INHERITED::flatten(buffer); 1.173 + buffer.writeScalar(fAdvance); 1.174 + if (fAdvance > 0) { 1.175 + buffer.writePath(fPath); 1.176 + buffer.writeScalar(fInitialOffset); 1.177 + buffer.writeUInt(fStyle); 1.178 + } 1.179 +} 1.180 + 1.181 +SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance, 1.182 + SkPathMeasure& meas) const { 1.183 + switch (fStyle) { 1.184 + case kTranslate_Style: { 1.185 + SkPoint pos; 1.186 + if (meas.getPosTan(distance, &pos, NULL)) { 1.187 + dst->addPath(fPath, pos.fX, pos.fY); 1.188 + } 1.189 + } break; 1.190 + case kRotate_Style: { 1.191 + SkMatrix matrix; 1.192 + if (meas.getMatrix(distance, &matrix)) { 1.193 + dst->addPath(fPath, matrix); 1.194 + } 1.195 + } break; 1.196 + case kMorph_Style: 1.197 + morphpath(dst, fPath, meas, distance); 1.198 + break; 1.199 + default: 1.200 + SkDEBUGFAIL("unknown Style enum"); 1.201 + break; 1.202 + } 1.203 + return fAdvance; 1.204 +}