1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDashPathEffect.h" 9a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel 10a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel#include "SkDashPathPriv.h" 118b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 128b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 141c577cd3ee331944b9061ee0eec147b211ee563cmtkleinSkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase) 151c577cd3ee331944b9061ee0eec147b211ee563cmtklein : fPhase(0) 161c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fInitialDashLength(0) 171c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fInitialDashIndex(0) 181c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fIntervalLength(0) { 19aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org SkASSERT(intervals); 20aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org SkASSERT(count > 1 && SkAlign2(count) == count); 21aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org 22aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count); 23aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fCount = count; 24aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org for (int i = 0; i < count; i++) { 25aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org SkASSERT(intervals[i] >= 0); 26aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fIntervals[i] = intervals[i]; 27aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 28aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org 29a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel // set the internal data members 301c577cd3ee331944b9061ee0eec147b211ee563cmtklein SkDashPath::CalcDashParameters(phase, fIntervals, fCount, 311c577cd3ee331944b9061ee0eec147b211ee563cmtklein &fInitialDashLength, &fInitialDashIndex, &fIntervalLength, &fPhase); 32aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org} 33aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org 343334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgSkDashPathEffect::~SkDashPathEffect() { 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sk_free(fIntervals); 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 383334c3a1fa05b5ee0cab0f2f1ec7b19939737337mike@reedtribe.orgbool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, 394bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkStrokeRec* rec, const SkRect* cullRect) const { 40a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel return SkDashPath::FilterDashPath(dst, src, rec, cullRect, fIntervals, fCount, 41a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel fInitialDashLength, fInitialDashIndex, fIntervalLength); 42629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com} 43629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 44e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillipsstatic void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { 45e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar radius = SkScalarHalf(rec.getWidth()); 46e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (0 == radius) { 47e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips radius = SK_Scalar1; // hairlines 48e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 49e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (SkPaint::kMiter_Join == rec.getJoin()) { 50e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips radius = SkScalarMul(radius, rec.getMiter()); 51e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 52e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips rect->outset(radius, radius); 53e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips} 54e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 55e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips// Attempt to trim the line to minimally cover the cull rect (currently 56e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips// only works for horizontal and vertical lines). 57e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips// Return true if processing should continue; false otherwise. 58e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillipsstatic bool cull_line(SkPoint* pts, const SkStrokeRec& rec, 59e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips const SkMatrix& ctm, const SkRect* cullRect, 60e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips const SkScalar intervalLength) { 61e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (NULL == cullRect) { 62e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(false); // Shouldn't ever occur in practice 63e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 64e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 65e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 66e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar dx = pts[1].x() - pts[0].x(); 67e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar dy = pts[1].y() - pts[0].y(); 68e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 69e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if ((dx && dy) || (!dx && !dy)) { 70e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 71e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 72e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 73e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkRect bounds = *cullRect; 74e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips outset_for_stroke(&bounds, rec); 75e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 76e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // cullRect is in device space while pts are in the local coordinate system 77e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // defined by the ctm. We want our answer in the local coordinate system. 78e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 79e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(ctm.rectStaysRect()); 80e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkMatrix inv; 81e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (!ctm.invert(&inv)) { 82e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 83e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 84e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 85e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips inv.mapRect(&bounds); 86e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 87e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (dx) { 88e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(dx && !dy); 89e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar minX = pts[0].fX; 90e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar maxX = pts[1].fX; 91e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 92e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (dx < 0) { 93e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkTSwap(minX, maxX); 94e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 95e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 96e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(minX < maxX); 97e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (maxX < bounds.fLeft || minX > bounds.fRight) { 98e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 99e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 100e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 101e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // Now we actually perform the chop, removing the excess to the left and 102e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // right of the bounds (keeping our new line "in phase" with the dash, 103e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // hence the (mod intervalLength). 104e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 105e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (minX < bounds.fLeft) { 106e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength); 107e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 108e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (maxX > bounds.fRight) { 109e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength); 110e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 111e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 112e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(maxX > minX); 113e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (dx < 0) { 114e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkTSwap(minX, maxX); 115e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 116e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips pts[0].fX = minX; 117e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips pts[1].fX = maxX; 118e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } else { 119e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(dy && !dx); 120e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar minY = pts[0].fY; 121e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar maxY = pts[1].fY; 122e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 123e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (dy < 0) { 124e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkTSwap(minY, maxY); 125e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 126e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 127e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(minY < maxY); 128e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (maxY < bounds.fTop || minY > bounds.fBottom) { 129e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 130e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 131e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 132e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // Now we actually perform the chop, removing the excess to the top and 133e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // bottom of the bounds (keeping our new line "in phase" with the dash, 134e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // hence the (mod intervalLength). 135e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 136e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (minY < bounds.fTop) { 137e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength); 138e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 139e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (maxY > bounds.fBottom) { 140e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength); 141e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 142e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 143e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkASSERT(maxY > minY); 144e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (dy < 0) { 145e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkTSwap(minY, maxY); 146e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 147e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips pts[0].fY = minY; 148e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips pts[1].fY = maxY; 149e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 150e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 151e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return true; 152e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips} 153e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 154629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com// Currently asPoints is more restrictive then it needs to be. In the future 155629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com// we need to: 156629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com// allow kRound_Cap capping (could allow rotations in the matrix with this) 1576d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com// allow paths to be returned 158629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.combool SkDashPathEffect::asPoints(PointData* results, 159629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com const SkPath& src, 160629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com const SkStrokeRec& rec, 1614bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com const SkMatrix& matrix, 1624bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com const SkRect* cullRect) const { 1636d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out 1646d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (fInitialDashLength < 0 || 0 >= rec.getWidth()) { 165629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 166629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 167629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 1686d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // TODO: this next test could be eased up. We could allow any number of 1696d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // intervals as long as all the ons match and all the offs match. 1706d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // Additionally, they do not necessarily need to be integers. 1716d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // We cannot allow arbitrary intervals since we want the returned points 1726d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // to be uniformly sized. 1737a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com if (fCount != 2 || 1746d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com !SkScalarNearlyEqual(fIntervals[0], fIntervals[1]) || 1756d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com !SkScalarIsInt(fIntervals[0]) || 1766d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com !SkScalarIsInt(fIntervals[1])) { 177629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 178629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 179629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 180629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkPoint pts[2]; 181629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 1826d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (!src.isLine(pts)) { 183629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 184629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 185629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 1866d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // TODO: this test could be eased up to allow circles 187629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com if (SkPaint::kButt_Cap != rec.getCap()) { 188629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 189629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 190629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 1916d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // TODO: this test could be eased up for circles. Rotations could be allowed. 192629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com if (!matrix.rectStaysRect()) { 193629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 194629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 195629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 196e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips // See if the line can be limited to something plausible. 197e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) { 198e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips return false; 199e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } 200e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips 201e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalar length = SkPoint::Distance(pts[1], pts[0]); 2026d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 2036d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkVector tangent = pts[1] - pts[0]; 2046d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (tangent.isZero()) { 2056d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com return false; 2066d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 207629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 2086d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com tangent.scale(SkScalarInvert(length)); 2096d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 2106d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // TODO: make this test for horizontal & vertical lines more robust 2116d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com bool isXAxis = true; 212e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) || 213e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) { 2146d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth())); 215e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips } else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) || 216e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) { 2176d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0])); 2186d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com isXAxis = false; 2196d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else if (SkPaint::kRound_Cap != rec.getCap()) { 2206d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // Angled lines don't have axis-aligned boxes. 221629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return false; 222629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 223629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 22449f085dddff10473b6ebf832a974288300224e60bsalomon if (results) { 2257a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com results->fFlags = 0; 2265c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com SkScalar clampedInitialDashLength = SkMinScalar(length, fInitialDashLength); 227629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 2286d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (SkPaint::kRound_Cap == rec.getCap()) { 2296d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fFlags |= PointData::kCircles_PointFlag; 230629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 231629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 2326d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fNumPoints = 0; 2336d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar len2 = length; 2345c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) { 2355c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com SkASSERT(len2 >= clampedInitialDashLength); 2366d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (0 == fInitialDashIndex) { 2375c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength > 0) { 2385c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength >= fIntervals[0]) { 2396d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com ++results->fNumPoints; // partial first dash 2406d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2415c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com len2 -= clampedInitialDashLength; 2426d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2436d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com len2 -= fIntervals[1]; // also skip first space 2446d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (len2 < 0) { 2456d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com len2 = 0; 2466d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2476d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 2485c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com len2 -= clampedInitialDashLength; // skip initial partial empty 2496d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2506d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2516d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com int numMidPoints = SkScalarFloorToInt(SkScalarDiv(len2, fIntervalLength)); 2526d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fNumPoints += numMidPoints; 2536d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com len2 -= numMidPoints * fIntervalLength; 2546d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com bool partialLast = false; 2556d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (len2 > 0) { 2566d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (len2 < fIntervals[0]) { 2577a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com partialLast = true; 2586d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 2596d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com ++numMidPoints; 2606d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com ++results->fNumPoints; 2616d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2626d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 263629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 264935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com results->fPoints = new SkPoint[results->fNumPoints]; 265629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 2666d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar distance = 0; 2676d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com int curPt = 0; 2686d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 2695c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) { 2705c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com SkASSERT(clampedInitialDashLength <= length); 2716d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 2726d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (0 == fInitialDashIndex) { 2735c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength > 0) { 2746d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // partial first block 2756d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles 2765c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, SkScalarHalf(clampedInitialDashLength)); 2775c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, SkScalarHalf(clampedInitialDashLength)); 2786d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar halfWidth, halfHeight; 2796d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (isXAxis) { 2805c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com halfWidth = SkScalarHalf(clampedInitialDashLength); 2816d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfHeight = SkScalarHalf(rec.getWidth()); 2826d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 2836d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfWidth = SkScalarHalf(rec.getWidth()); 2845c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com halfHeight = SkScalarHalf(clampedInitialDashLength); 2856d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2865c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com if (clampedInitialDashLength < fIntervals[0]) { 2876d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // This one will not be like the others 2886d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fFirst.addRect(x - halfWidth, y - halfHeight, 2896d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com x + halfWidth, y + halfHeight); 2906d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 2916d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(curPt < results->fNumPoints); 2926d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fPoints[curPt].set(x, y); 2936d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com ++curPt; 2946d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 2956d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 2965c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com distance += clampedInitialDashLength; 2976d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 298629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 2996d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com distance += fIntervals[1]; // skip over the next blank block too 3006d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 3015c4d5582c9d47ea47c7699fe69b9f95d0117dbd5robertphillips@google.com distance += clampedInitialDashLength; 3026d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 3036d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 3046d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 3056d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (0 != numMidPoints) { 3066d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com distance += SkScalarHalf(fIntervals[0]); 307629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 3086d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com for (int i = 0; i < numMidPoints; ++i) { 3096d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance); 3106d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance); 3116d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 3126d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(curPt < results->fNumPoints); 3136d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fPoints[curPt].set(x, y); 3146d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com ++curPt; 3156d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 3166d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com distance += fIntervalLength; 317629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 318629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 3196d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com distance -= SkScalarHalf(fIntervals[0]); 3206d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 3216d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 3226d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (partialLast) { 3236d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // partial final block 3246d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles 3256d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar temp = length - distance; 3266d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(temp < fIntervals[0]); 3276d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance + SkScalarHalf(temp)); 3286d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance + SkScalarHalf(temp)); 3296d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkScalar halfWidth, halfHeight; 3306d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (isXAxis) { 3316d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfWidth = SkScalarHalf(temp); 3326d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfHeight = SkScalarHalf(rec.getWidth()); 3336d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 3346d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfWidth = SkScalarHalf(rec.getWidth()); 3356d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com halfHeight = SkScalarHalf(temp); 3366d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 3376d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com results->fLast.addRect(x - halfWidth, y - halfHeight, 3386d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com x + halfWidth, y + halfHeight); 339629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 340935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com 3416d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(curPt == results->fNumPoints); 342629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 343629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 344629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com return true; 3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 347aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.orgSkPathEffect::DashType SkDashPathEffect::asADash(DashInfo* info) const { 348aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org if (info) { 34949f085dddff10473b6ebf832a974288300224e60bsalomon if (info->fCount >= fCount && info->fIntervals) { 350aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org memcpy(info->fIntervals, fIntervals, fCount * sizeof(SkScalar)); 351aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 352aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org info->fCount = fCount; 353aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org info->fPhase = fPhase; 354aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 355aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org return kDash_DashType; 356aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org} 357aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org 3588b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkDashPathEffect::flatten(SkWriteBuffer& buffer) const { 359aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org buffer.writeScalar(fPhase); 360c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com buffer.writeScalarArray(fIntervals, fCount); 3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3638b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkFlattenable* SkDashPathEffect::CreateProc(SkReadBuffer& buffer) { 3649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkScalar phase = buffer.readScalar(); 3659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed uint32_t count = buffer.getArrayCount(); 3669fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkAutoSTArray<32, SkScalar> intervals(count); 3679fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (buffer.readScalarArray(intervals.get(), count)) { 3689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return Create(intervals.get(), SkToInt(count), phase); 3699fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; 3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3739fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 3741c577cd3ee331944b9061ee0eec147b211ee563cmtkleinSkDashPathEffect::SkDashPathEffect(SkReadBuffer& buffer) 3751c577cd3ee331944b9061ee0eec147b211ee563cmtklein : INHERITED(buffer) 3761c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fPhase(0) 3771c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fInitialDashLength(0) 3781c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fInitialDashIndex(0) 3791c577cd3ee331944b9061ee0eec147b211ee563cmtklein , fIntervalLength(0) { 3807ed173b1ebac84671fb0dc1b9bd323a5e6e63771commit-bot@chromium.org bool useOldPic = buffer.isVersionLT(SkReadBuffer::kDashWritesPhaseIntervals_Version); 381aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org if (useOldPic) { 382aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fInitialDashIndex = buffer.readInt(); 383aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fInitialDashLength = buffer.readScalar(); 384aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fIntervalLength = buffer.readScalar(); 385aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org buffer.readBool(); // Dummy for old ScalarToFit field 386aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } else { 387aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fPhase = buffer.readScalar(); 388aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 389fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 390c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com fCount = buffer.getArrayCount(); 391ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org size_t allocSize = sizeof(SkScalar) * fCount; 392ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org if (buffer.validateAvailable(allocSize)) { 393ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org fIntervals = (SkScalar*)sk_malloc_throw(allocSize); 394ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org buffer.readScalarArray(fIntervals, fCount); 395ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org } else { 396ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org fIntervals = NULL; 397ef74fa189b738e13295d6a96f86a6e10223505a8commit-bot@chromium.org } 398aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org 399aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org if (useOldPic) { 400aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org fPhase = 0; 4016b3eebce43dcd0e409ce953d2a2ea93df2b97733commit-bot@chromium.org if (fInitialDashLength != -1) { // Signal for bad dash interval 4026b3eebce43dcd0e409ce953d2a2ea93df2b97733commit-bot@chromium.org for (int i = 0; i < fInitialDashIndex; ++i) { 4036b3eebce43dcd0e409ce953d2a2ea93df2b97733commit-bot@chromium.org fPhase += fIntervals[i]; 4046b3eebce43dcd0e409ce953d2a2ea93df2b97733commit-bot@chromium.org } 4056b3eebce43dcd0e409ce953d2a2ea93df2b97733commit-bot@chromium.org fPhase += fIntervals[fInitialDashIndex] - fInitialDashLength; 406aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 407aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } else { 408a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel // set the internal data members, fPhase should have been between 0 and intervalLength 409a22ea1882391cc5c84136060636d5c952c1f34b3egdaniel // when written to buffer so no need to adjust it 4101c577cd3ee331944b9061ee0eec147b211ee563cmtklein SkDashPath::CalcDashParameters(fPhase, fIntervals, fCount, 4111c577cd3ee331944b9061ee0eec147b211ee563cmtklein &fInitialDashLength, &fInitialDashIndex, &fIntervalLength); 412aec143824c9be4e4af6e2cb7cce3d2d2268c0b15commit-bot@chromium.org } 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4149fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif 4159fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 416