1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/effects/SkDashPathEffect.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 12cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 13cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h" 14cb93a386Sopenharmony_ci#include "src/effects/SkDashImpl.h" 15cb93a386Sopenharmony_ci#include "src/utils/SkDashPathPriv.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include <utility> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ciSkDashImpl::SkDashImpl(const SkScalar intervals[], int count, SkScalar phase) 20cb93a386Sopenharmony_ci : fPhase(0) 21cb93a386Sopenharmony_ci , fInitialDashLength(-1) 22cb93a386Sopenharmony_ci , fInitialDashIndex(0) 23cb93a386Sopenharmony_ci , fIntervalLength(0) { 24cb93a386Sopenharmony_ci SkASSERT(intervals); 25cb93a386Sopenharmony_ci SkASSERT(count > 1 && SkIsAlign2(count)); 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count); 28cb93a386Sopenharmony_ci fCount = count; 29cb93a386Sopenharmony_ci for (int i = 0; i < count; i++) { 30cb93a386Sopenharmony_ci fIntervals[i] = intervals[i]; 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci // set the internal data members 34cb93a386Sopenharmony_ci SkDashPath::CalcDashParameters(phase, fIntervals, fCount, 35cb93a386Sopenharmony_ci &fInitialDashLength, &fInitialDashIndex, &fIntervalLength, &fPhase); 36cb93a386Sopenharmony_ci} 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ciSkDashImpl::~SkDashImpl() { 39cb93a386Sopenharmony_ci sk_free(fIntervals); 40cb93a386Sopenharmony_ci} 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_cibool SkDashImpl::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, 43cb93a386Sopenharmony_ci const SkRect* cullRect, const SkMatrix&) const { 44cb93a386Sopenharmony_ci return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals, fCount, 45cb93a386Sopenharmony_ci fInitialDashLength, fInitialDashIndex, fIntervalLength); 46cb93a386Sopenharmony_ci} 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_cistatic void outset_for_stroke(SkRect* rect, const SkStrokeRec& rec) { 49cb93a386Sopenharmony_ci SkScalar radius = SkScalarHalf(rec.getWidth()); 50cb93a386Sopenharmony_ci if (0 == radius) { 51cb93a386Sopenharmony_ci radius = SK_Scalar1; // hairlines 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci if (SkPaint::kMiter_Join == rec.getJoin()) { 54cb93a386Sopenharmony_ci radius *= rec.getMiter(); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci rect->outset(radius, radius); 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci// Attempt to trim the line to minimally cover the cull rect (currently 60cb93a386Sopenharmony_ci// only works for horizontal and vertical lines). 61cb93a386Sopenharmony_ci// Return true if processing should continue; false otherwise. 62cb93a386Sopenharmony_cistatic bool cull_line(SkPoint* pts, const SkStrokeRec& rec, 63cb93a386Sopenharmony_ci const SkMatrix& ctm, const SkRect* cullRect, 64cb93a386Sopenharmony_ci const SkScalar intervalLength) { 65cb93a386Sopenharmony_ci if (nullptr == cullRect) { 66cb93a386Sopenharmony_ci SkASSERT(false); // Shouldn't ever occur in practice 67cb93a386Sopenharmony_ci return false; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci SkScalar dx = pts[1].x() - pts[0].x(); 71cb93a386Sopenharmony_ci SkScalar dy = pts[1].y() - pts[0].y(); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci if ((dx && dy) || (!dx && !dy)) { 74cb93a386Sopenharmony_ci return false; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci SkRect bounds = *cullRect; 78cb93a386Sopenharmony_ci outset_for_stroke(&bounds, rec); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci // cullRect is in device space while pts are in the local coordinate system 81cb93a386Sopenharmony_ci // defined by the ctm. We want our answer in the local coordinate system. 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci SkASSERT(ctm.rectStaysRect()); 84cb93a386Sopenharmony_ci SkMatrix inv; 85cb93a386Sopenharmony_ci if (!ctm.invert(&inv)) { 86cb93a386Sopenharmony_ci return false; 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci inv.mapRect(&bounds); 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci if (dx) { 92cb93a386Sopenharmony_ci SkASSERT(dx && !dy); 93cb93a386Sopenharmony_ci SkScalar minX = pts[0].fX; 94cb93a386Sopenharmony_ci SkScalar maxX = pts[1].fX; 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci if (dx < 0) { 97cb93a386Sopenharmony_ci using std::swap; 98cb93a386Sopenharmony_ci swap(minX, maxX); 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci SkASSERT(minX < maxX); 102cb93a386Sopenharmony_ci if (maxX <= bounds.fLeft || minX >= bounds.fRight) { 103cb93a386Sopenharmony_ci return false; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci // Now we actually perform the chop, removing the excess to the left and 107cb93a386Sopenharmony_ci // right of the bounds (keeping our new line "in phase" with the dash, 108cb93a386Sopenharmony_ci // hence the (mod intervalLength). 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci if (minX < bounds.fLeft) { 111cb93a386Sopenharmony_ci minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci if (maxX > bounds.fRight) { 114cb93a386Sopenharmony_ci maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci SkASSERT(maxX > minX); 118cb93a386Sopenharmony_ci if (dx < 0) { 119cb93a386Sopenharmony_ci using std::swap; 120cb93a386Sopenharmony_ci swap(minX, maxX); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci pts[0].fX = minX; 123cb93a386Sopenharmony_ci pts[1].fX = maxX; 124cb93a386Sopenharmony_ci } else { 125cb93a386Sopenharmony_ci SkASSERT(dy && !dx); 126cb93a386Sopenharmony_ci SkScalar minY = pts[0].fY; 127cb93a386Sopenharmony_ci SkScalar maxY = pts[1].fY; 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci if (dy < 0) { 130cb93a386Sopenharmony_ci using std::swap; 131cb93a386Sopenharmony_ci swap(minY, maxY); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci SkASSERT(minY < maxY); 135cb93a386Sopenharmony_ci if (maxY <= bounds.fTop || minY >= bounds.fBottom) { 136cb93a386Sopenharmony_ci return false; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // Now we actually perform the chop, removing the excess to the top and 140cb93a386Sopenharmony_ci // bottom of the bounds (keeping our new line "in phase" with the dash, 141cb93a386Sopenharmony_ci // hence the (mod intervalLength). 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci if (minY < bounds.fTop) { 144cb93a386Sopenharmony_ci minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength); 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci if (maxY > bounds.fBottom) { 147cb93a386Sopenharmony_ci maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci SkASSERT(maxY > minY); 151cb93a386Sopenharmony_ci if (dy < 0) { 152cb93a386Sopenharmony_ci using std::swap; 153cb93a386Sopenharmony_ci swap(minY, maxY); 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci pts[0].fY = minY; 156cb93a386Sopenharmony_ci pts[1].fY = maxY; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci return true; 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci// Currently asPoints is more restrictive then it needs to be. In the future 163cb93a386Sopenharmony_ci// we need to: 164cb93a386Sopenharmony_ci// allow kRound_Cap capping (could allow rotations in the matrix with this) 165cb93a386Sopenharmony_ci// allow paths to be returned 166cb93a386Sopenharmony_cibool SkDashImpl::onAsPoints(PointData* results, const SkPath& src, const SkStrokeRec& rec, 167cb93a386Sopenharmony_ci const SkMatrix& matrix, const SkRect* cullRect) const { 168cb93a386Sopenharmony_ci // width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out 169cb93a386Sopenharmony_ci if (0 >= rec.getWidth()) { 170cb93a386Sopenharmony_ci return false; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // TODO: this next test could be eased up. We could allow any number of 174cb93a386Sopenharmony_ci // intervals as long as all the ons match and all the offs match. 175cb93a386Sopenharmony_ci // Additionally, they do not necessarily need to be integers. 176cb93a386Sopenharmony_ci // We cannot allow arbitrary intervals since we want the returned points 177cb93a386Sopenharmony_ci // to be uniformly sized. 178cb93a386Sopenharmony_ci if (fCount != 2 || 179cb93a386Sopenharmony_ci !SkScalarNearlyEqual(fIntervals[0], fIntervals[1]) || 180cb93a386Sopenharmony_ci !SkScalarIsInt(fIntervals[0]) || 181cb93a386Sopenharmony_ci !SkScalarIsInt(fIntervals[1])) { 182cb93a386Sopenharmony_ci return false; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci SkPoint pts[2]; 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci if (!src.isLine(pts)) { 188cb93a386Sopenharmony_ci return false; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci // TODO: this test could be eased up to allow circles 192cb93a386Sopenharmony_ci if (SkPaint::kButt_Cap != rec.getCap()) { 193cb93a386Sopenharmony_ci return false; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci // TODO: this test could be eased up for circles. Rotations could be allowed. 197cb93a386Sopenharmony_ci if (!matrix.rectStaysRect()) { 198cb93a386Sopenharmony_ci return false; 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci // See if the line can be limited to something plausible. 202cb93a386Sopenharmony_ci if (!cull_line(pts, rec, matrix, cullRect, fIntervalLength)) { 203cb93a386Sopenharmony_ci return false; 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci SkScalar length = SkPoint::Distance(pts[1], pts[0]); 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci SkVector tangent = pts[1] - pts[0]; 209cb93a386Sopenharmony_ci if (tangent.isZero()) { 210cb93a386Sopenharmony_ci return false; 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci tangent.scale(SkScalarInvert(length)); 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci // TODO: make this test for horizontal & vertical lines more robust 216cb93a386Sopenharmony_ci bool isXAxis = true; 217cb93a386Sopenharmony_ci if (SkScalarNearlyEqual(SK_Scalar1, tangent.fX) || 218cb93a386Sopenharmony_ci SkScalarNearlyEqual(-SK_Scalar1, tangent.fX)) { 219cb93a386Sopenharmony_ci results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth())); 220cb93a386Sopenharmony_ci } else if (SkScalarNearlyEqual(SK_Scalar1, tangent.fY) || 221cb93a386Sopenharmony_ci SkScalarNearlyEqual(-SK_Scalar1, tangent.fY)) { 222cb93a386Sopenharmony_ci results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0])); 223cb93a386Sopenharmony_ci isXAxis = false; 224cb93a386Sopenharmony_ci } else if (SkPaint::kRound_Cap != rec.getCap()) { 225cb93a386Sopenharmony_ci // Angled lines don't have axis-aligned boxes. 226cb93a386Sopenharmony_ci return false; 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci if (results) { 230cb93a386Sopenharmony_ci results->fFlags = 0; 231cb93a386Sopenharmony_ci SkScalar clampedInitialDashLength = std::min(length, fInitialDashLength); 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci if (SkPaint::kRound_Cap == rec.getCap()) { 234cb93a386Sopenharmony_ci results->fFlags |= PointData::kCircles_PointFlag; 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci results->fNumPoints = 0; 238cb93a386Sopenharmony_ci SkScalar len2 = length; 239cb93a386Sopenharmony_ci if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) { 240cb93a386Sopenharmony_ci SkASSERT(len2 >= clampedInitialDashLength); 241cb93a386Sopenharmony_ci if (0 == fInitialDashIndex) { 242cb93a386Sopenharmony_ci if (clampedInitialDashLength > 0) { 243cb93a386Sopenharmony_ci if (clampedInitialDashLength >= fIntervals[0]) { 244cb93a386Sopenharmony_ci ++results->fNumPoints; // partial first dash 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci len2 -= clampedInitialDashLength; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci len2 -= fIntervals[1]; // also skip first space 249cb93a386Sopenharmony_ci if (len2 < 0) { 250cb93a386Sopenharmony_ci len2 = 0; 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci } else { 253cb93a386Sopenharmony_ci len2 -= clampedInitialDashLength; // skip initial partial empty 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci // Too many midpoints can cause results->fNumPoints to overflow or 257cb93a386Sopenharmony_ci // otherwise cause the results->fPoints allocation below to OOM. 258cb93a386Sopenharmony_ci // Cap it to a sane value. 259cb93a386Sopenharmony_ci SkScalar numIntervals = len2 / fIntervalLength; 260cb93a386Sopenharmony_ci if (!SkScalarIsFinite(numIntervals) || numIntervals > SkDashPath::kMaxDashCount) { 261cb93a386Sopenharmony_ci return false; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci int numMidPoints = SkScalarFloorToInt(numIntervals); 264cb93a386Sopenharmony_ci results->fNumPoints += numMidPoints; 265cb93a386Sopenharmony_ci len2 -= numMidPoints * fIntervalLength; 266cb93a386Sopenharmony_ci bool partialLast = false; 267cb93a386Sopenharmony_ci if (len2 > 0) { 268cb93a386Sopenharmony_ci if (len2 < fIntervals[0]) { 269cb93a386Sopenharmony_ci partialLast = true; 270cb93a386Sopenharmony_ci } else { 271cb93a386Sopenharmony_ci ++numMidPoints; 272cb93a386Sopenharmony_ci ++results->fNumPoints; 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci results->fPoints = new SkPoint[results->fNumPoints]; 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci SkScalar distance = 0; 279cb93a386Sopenharmony_ci int curPt = 0; 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) { 282cb93a386Sopenharmony_ci SkASSERT(clampedInitialDashLength <= length); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci if (0 == fInitialDashIndex) { 285cb93a386Sopenharmony_ci if (clampedInitialDashLength > 0) { 286cb93a386Sopenharmony_ci // partial first block 287cb93a386Sopenharmony_ci SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles 288cb93a386Sopenharmony_ci SkScalar x = pts[0].fX + tangent.fX * SkScalarHalf(clampedInitialDashLength); 289cb93a386Sopenharmony_ci SkScalar y = pts[0].fY + tangent.fY * SkScalarHalf(clampedInitialDashLength); 290cb93a386Sopenharmony_ci SkScalar halfWidth, halfHeight; 291cb93a386Sopenharmony_ci if (isXAxis) { 292cb93a386Sopenharmony_ci halfWidth = SkScalarHalf(clampedInitialDashLength); 293cb93a386Sopenharmony_ci halfHeight = SkScalarHalf(rec.getWidth()); 294cb93a386Sopenharmony_ci } else { 295cb93a386Sopenharmony_ci halfWidth = SkScalarHalf(rec.getWidth()); 296cb93a386Sopenharmony_ci halfHeight = SkScalarHalf(clampedInitialDashLength); 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci if (clampedInitialDashLength < fIntervals[0]) { 299cb93a386Sopenharmony_ci // This one will not be like the others 300cb93a386Sopenharmony_ci results->fFirst.addRect(x - halfWidth, y - halfHeight, 301cb93a386Sopenharmony_ci x + halfWidth, y + halfHeight); 302cb93a386Sopenharmony_ci } else { 303cb93a386Sopenharmony_ci SkASSERT(curPt < results->fNumPoints); 304cb93a386Sopenharmony_ci results->fPoints[curPt].set(x, y); 305cb93a386Sopenharmony_ci ++curPt; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci distance += clampedInitialDashLength; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci distance += fIntervals[1]; // skip over the next blank block too 312cb93a386Sopenharmony_ci } else { 313cb93a386Sopenharmony_ci distance += clampedInitialDashLength; 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci if (0 != numMidPoints) { 318cb93a386Sopenharmony_ci distance += SkScalarHalf(fIntervals[0]); 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci for (int i = 0; i < numMidPoints; ++i) { 321cb93a386Sopenharmony_ci SkScalar x = pts[0].fX + tangent.fX * distance; 322cb93a386Sopenharmony_ci SkScalar y = pts[0].fY + tangent.fY * distance; 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci SkASSERT(curPt < results->fNumPoints); 325cb93a386Sopenharmony_ci results->fPoints[curPt].set(x, y); 326cb93a386Sopenharmony_ci ++curPt; 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci distance += fIntervalLength; 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci distance -= SkScalarHalf(fIntervals[0]); 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci if (partialLast) { 335cb93a386Sopenharmony_ci // partial final block 336cb93a386Sopenharmony_ci SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles 337cb93a386Sopenharmony_ci SkScalar temp = length - distance; 338cb93a386Sopenharmony_ci SkASSERT(temp < fIntervals[0]); 339cb93a386Sopenharmony_ci SkScalar x = pts[0].fX + tangent.fX * (distance + SkScalarHalf(temp)); 340cb93a386Sopenharmony_ci SkScalar y = pts[0].fY + tangent.fY * (distance + SkScalarHalf(temp)); 341cb93a386Sopenharmony_ci SkScalar halfWidth, halfHeight; 342cb93a386Sopenharmony_ci if (isXAxis) { 343cb93a386Sopenharmony_ci halfWidth = SkScalarHalf(temp); 344cb93a386Sopenharmony_ci halfHeight = SkScalarHalf(rec.getWidth()); 345cb93a386Sopenharmony_ci } else { 346cb93a386Sopenharmony_ci halfWidth = SkScalarHalf(rec.getWidth()); 347cb93a386Sopenharmony_ci halfHeight = SkScalarHalf(temp); 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci results->fLast.addRect(x - halfWidth, y - halfHeight, 350cb93a386Sopenharmony_ci x + halfWidth, y + halfHeight); 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci SkASSERT(curPt == results->fNumPoints); 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci return true; 357cb93a386Sopenharmony_ci} 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ciSkPathEffect::DashType SkDashImpl::onAsADash(DashInfo* info) const { 360cb93a386Sopenharmony_ci if (info) { 361cb93a386Sopenharmony_ci if (info->fCount >= fCount && info->fIntervals) { 362cb93a386Sopenharmony_ci memcpy(info->fIntervals, fIntervals, fCount * sizeof(SkScalar)); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci info->fCount = fCount; 365cb93a386Sopenharmony_ci info->fPhase = fPhase; 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci return kDash_DashType; 368cb93a386Sopenharmony_ci} 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_civoid SkDashImpl::flatten(SkWriteBuffer& buffer) const { 371cb93a386Sopenharmony_ci buffer.writeScalar(fPhase); 372cb93a386Sopenharmony_ci buffer.writeScalarArray(fIntervals, fCount); 373cb93a386Sopenharmony_ci} 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkDashImpl::CreateProc(SkReadBuffer& buffer) { 376cb93a386Sopenharmony_ci const SkScalar phase = buffer.readScalar(); 377cb93a386Sopenharmony_ci uint32_t count = buffer.getArrayCount(); 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci // Don't allocate gigantic buffers if there's not data for them. 380cb93a386Sopenharmony_ci if (!buffer.validateCanReadN<SkScalar>(count)) { 381cb93a386Sopenharmony_ci return nullptr; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_ci SkAutoSTArray<32, SkScalar> intervals(count); 385cb93a386Sopenharmony_ci if (buffer.readScalarArray(intervals.get(), count)) { 386cb93a386Sopenharmony_ci return SkDashPathEffect::Make(intervals.get(), SkToInt(count), phase); 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci return nullptr; 389cb93a386Sopenharmony_ci} 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////// 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkDashPathEffect::Make(const SkScalar intervals[], int count, SkScalar phase) { 394cb93a386Sopenharmony_ci if (!SkDashPath::ValidDashPath(phase, intervals, count)) { 395cb93a386Sopenharmony_ci return nullptr; 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci return sk_sp<SkPathEffect>(new SkDashImpl(intervals, count, phase)); 398cb93a386Sopenharmony_ci} 399