SkShadowTessellator.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. /*
  2. * Copyright 2017 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkPath.h"
  8. #include "include/core/SkPoint3.h"
  9. #include "include/core/SkVertices.h"
  10. #include "include/private/SkColorData.h"
  11. #include "src/core/SkDrawShadowInfo.h"
  12. #include "src/core/SkGeometry.h"
  13. #include "src/core/SkPointPriv.h"
  14. #include "src/utils/SkPolyUtils.h"
  15. #include "src/utils/SkShadowTessellator.h"
  16. #if SK_SUPPORT_GPU
  17. #include "src/gpu/geometry/GrPathUtils.h"
  18. #endif
  19. /**
  20. * Base class
  21. */
  22. class SkBaseShadowTessellator {
  23. public:
  24. SkBaseShadowTessellator(const SkPoint3& zPlaneParams, const SkRect& bounds, bool transparent);
  25. virtual ~SkBaseShadowTessellator() {}
  26. sk_sp<SkVertices> releaseVertices() {
  27. if (!fSucceeded) {
  28. return nullptr;
  29. }
  30. return SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, this->vertexCount(),
  31. fPositions.begin(), nullptr, fColors.begin(),
  32. this->indexCount(), fIndices.begin());
  33. }
  34. protected:
  35. static constexpr auto kMinHeight = 0.1f;
  36. static constexpr auto kPenumbraColor = SK_ColorTRANSPARENT;
  37. static constexpr auto kUmbraColor = SK_ColorBLACK;
  38. int vertexCount() const { return fPositions.count(); }
  39. int indexCount() const { return fIndices.count(); }
  40. // initialization methods
  41. bool accumulateCentroid(const SkPoint& c, const SkPoint& n);
  42. bool checkConvexity(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2);
  43. void finishPathPolygon();
  44. // convex shadow methods
  45. bool computeConvexShadow(SkScalar inset, SkScalar outset, bool doClip);
  46. void computeClipVectorsAndTestCentroid();
  47. bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
  48. void addEdge(const SkVector& nextPoint, const SkVector& nextNormal, SkColor umbraColor,
  49. const SkTDArray<SkPoint>& umbraPolygon, bool lastEdge, bool doClip);
  50. bool addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
  51. const SkTDArray<SkPoint>& umbraPolygon, int* currUmbraIndex);
  52. int getClosestUmbraIndex(const SkPoint& point, const SkTDArray<SkPoint>& umbraPolygon);
  53. // concave shadow methods
  54. bool computeConcaveShadow(SkScalar inset, SkScalar outset);
  55. void stitchConcaveRings(const SkTDArray<SkPoint>& umbraPolygon,
  56. SkTDArray<int>* umbraIndices,
  57. const SkTDArray<SkPoint>& penumbraPolygon,
  58. SkTDArray<int>* penumbraIndices);
  59. void handleLine(const SkPoint& p);
  60. void handleLine(const SkMatrix& m, SkPoint* p);
  61. void handleQuad(const SkPoint pts[3]);
  62. void handleQuad(const SkMatrix& m, SkPoint pts[3]);
  63. void handleCubic(const SkMatrix& m, SkPoint pts[4]);
  64. void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
  65. bool addArc(const SkVector& nextNormal, SkScalar offset, bool finishArc);
  66. void appendTriangle(uint16_t index0, uint16_t index1, uint16_t index2);
  67. void appendQuad(uint16_t index0, uint16_t index1, uint16_t index2, uint16_t index3);
  68. SkScalar heightFunc(SkScalar x, SkScalar y) {
  69. return fZPlaneParams.fX*x + fZPlaneParams.fY*y + fZPlaneParams.fZ;
  70. }
  71. SkPoint3 fZPlaneParams;
  72. // temporary buffer
  73. SkTDArray<SkPoint> fPointBuffer;
  74. SkTDArray<SkPoint> fPositions;
  75. SkTDArray<SkColor> fColors;
  76. SkTDArray<uint16_t> fIndices;
  77. SkTDArray<SkPoint> fPathPolygon;
  78. SkTDArray<SkPoint> fClipPolygon;
  79. SkTDArray<SkVector> fClipVectors;
  80. SkRect fPathBounds;
  81. SkPoint fCentroid;
  82. SkScalar fArea;
  83. SkScalar fLastArea;
  84. SkScalar fLastCross;
  85. int fFirstVertexIndex;
  86. SkVector fFirstOutset;
  87. SkPoint fFirstPoint;
  88. bool fSucceeded;
  89. bool fTransparent;
  90. bool fIsConvex;
  91. bool fValidUmbra;
  92. SkScalar fDirection;
  93. int fPrevUmbraIndex;
  94. int fCurrUmbraIndex;
  95. int fCurrClipIndex;
  96. bool fPrevUmbraOutside;
  97. bool fFirstUmbraOutside;
  98. SkVector fPrevOutset;
  99. SkPoint fPrevPoint;
  100. };
  101. // make external linkage happy
  102. constexpr SkColor SkBaseShadowTessellator::kUmbraColor;
  103. constexpr SkColor SkBaseShadowTessellator::kPenumbraColor;
  104. static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
  105. SkVector* newNormal) {
  106. SkVector normal;
  107. // compute perpendicular
  108. normal.fX = p0.fY - p1.fY;
  109. normal.fY = p1.fX - p0.fX;
  110. normal *= dir;
  111. if (!normal.normalize()) {
  112. return false;
  113. }
  114. *newNormal = normal;
  115. return true;
  116. }
  117. static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) {
  118. static constexpr SkScalar kClose = (SK_Scalar1 / 16);
  119. static constexpr SkScalar kCloseSqd = kClose * kClose;
  120. SkScalar distSq = SkPointPriv::DistanceToSqd(p0, p1);
  121. return distSq < kCloseSqd;
  122. }
  123. static SkScalar perp_dot(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
  124. SkVector v0 = p1 - p0;
  125. SkVector v1 = p2 - p1;
  126. return v0.cross(v1);
  127. }
  128. SkBaseShadowTessellator::SkBaseShadowTessellator(const SkPoint3& zPlaneParams, const SkRect& bounds,
  129. bool transparent)
  130. : fZPlaneParams(zPlaneParams)
  131. , fPathBounds(bounds)
  132. , fCentroid({0, 0})
  133. , fArea(0)
  134. , fLastArea(0)
  135. , fLastCross(0)
  136. , fFirstVertexIndex(-1)
  137. , fSucceeded(false)
  138. , fTransparent(transparent)
  139. , fIsConvex(true)
  140. , fValidUmbra(true)
  141. , fDirection(1)
  142. , fPrevUmbraIndex(-1)
  143. , fCurrUmbraIndex(0)
  144. , fCurrClipIndex(0)
  145. , fPrevUmbraOutside(false)
  146. , fFirstUmbraOutside(false) {
  147. // child classes will set reserve for positions, colors and indices
  148. }
  149. bool SkBaseShadowTessellator::accumulateCentroid(const SkPoint& curr, const SkPoint& next) {
  150. if (duplicate_pt(curr, next)) {
  151. return false;
  152. }
  153. SkASSERT(fPathPolygon.count() > 0);
  154. SkVector v0 = curr - fPathPolygon[0];
  155. SkVector v1 = next - fPathPolygon[0];
  156. SkScalar quadArea = v0.cross(v1);
  157. fCentroid.fX += (v0.fX + v1.fX) * quadArea;
  158. fCentroid.fY += (v0.fY + v1.fY) * quadArea;
  159. fArea += quadArea;
  160. // convexity check
  161. if (quadArea*fLastArea < 0) {
  162. fIsConvex = false;
  163. }
  164. if (0 != quadArea) {
  165. fLastArea = quadArea;
  166. }
  167. return true;
  168. }
  169. bool SkBaseShadowTessellator::checkConvexity(const SkPoint& p0,
  170. const SkPoint& p1,
  171. const SkPoint& p2) {
  172. SkScalar cross = perp_dot(p0, p1, p2);
  173. // skip collinear point
  174. if (SkScalarNearlyZero(cross)) {
  175. return false;
  176. }
  177. // check for convexity
  178. if (fLastCross*cross < 0) {
  179. fIsConvex = false;
  180. }
  181. if (0 != cross) {
  182. fLastCross = cross;
  183. }
  184. return true;
  185. }
  186. void SkBaseShadowTessellator::finishPathPolygon() {
  187. if (fPathPolygon.count() > 1) {
  188. if (!this->accumulateCentroid(fPathPolygon[fPathPolygon.count() - 1], fPathPolygon[0])) {
  189. // remove coincident point
  190. fPathPolygon.pop();
  191. }
  192. }
  193. if (fPathPolygon.count() > 2) {
  194. // do this before the final convexity check, so we use the correct fPathPolygon[0]
  195. fCentroid *= sk_ieee_float_divide(1, 3 * fArea);
  196. fCentroid += fPathPolygon[0];
  197. if (!checkConvexity(fPathPolygon[fPathPolygon.count() - 2],
  198. fPathPolygon[fPathPolygon.count() - 1],
  199. fPathPolygon[0])) {
  200. // remove collinear point
  201. fPathPolygon[0] = fPathPolygon[fPathPolygon.count() - 1];
  202. fPathPolygon.pop();
  203. }
  204. }
  205. // if area is positive, winding is ccw
  206. fDirection = fArea > 0 ? -1 : 1;
  207. }
  208. bool SkBaseShadowTessellator::computeConvexShadow(SkScalar inset, SkScalar outset, bool doClip) {
  209. if (doClip) {
  210. this->computeClipVectorsAndTestCentroid();
  211. }
  212. // adjust inset distance and umbra color if necessary
  213. auto umbraColor = kUmbraColor;
  214. SkScalar minDistSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid,
  215. fPathPolygon[0],
  216. fPathPolygon[1]);
  217. SkRect bounds;
  218. bounds.setBounds(&fPathPolygon[0], fPathPolygon.count());
  219. for (int i = 1; i < fPathPolygon.count(); ++i) {
  220. int j = i + 1;
  221. if (i == fPathPolygon.count() - 1) {
  222. j = 0;
  223. }
  224. SkPoint currPoint = fPathPolygon[i];
  225. SkPoint nextPoint = fPathPolygon[j];
  226. SkScalar distSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid, currPoint,
  227. nextPoint);
  228. if (distSq < minDistSq) {
  229. minDistSq = distSq;
  230. }
  231. }
  232. SkTDArray<SkPoint> insetPolygon;
  233. if (inset > SK_ScalarNearlyZero) {
  234. static constexpr auto kTolerance = 1.0e-2f;
  235. if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
  236. // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
  237. auto newInset = SkScalarSqrt(minDistSq) - kTolerance;
  238. auto ratio = 128 * (newInset / inset + 1);
  239. SkASSERT(SkScalarIsFinite(ratio));
  240. // they aren't PMColors, but the interpolation algorithm is the same
  241. umbraColor = SkPMLerp(kUmbraColor, kPenumbraColor, (unsigned)ratio);
  242. inset = newInset;
  243. }
  244. // generate inner ring
  245. if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
  246. &insetPolygon)) {
  247. // not ideal, but in this case we'll inset using the centroid
  248. fValidUmbra = false;
  249. }
  250. }
  251. const SkTDArray<SkPoint>& umbraPolygon = (inset > SK_ScalarNearlyZero) ? insetPolygon
  252. : fPathPolygon;
  253. // walk around the path polygon, generate outer ring and connect to inner ring
  254. if (fTransparent) {
  255. fPositions.push_back(fCentroid);
  256. fColors.push_back(umbraColor);
  257. }
  258. fCurrUmbraIndex = 0;
  259. // initial setup
  260. // add first quad
  261. int polyCount = fPathPolygon.count();
  262. if (!compute_normal(fPathPolygon[polyCount - 1], fPathPolygon[0], fDirection, &fFirstOutset)) {
  263. // polygon should be sanitized by this point, so this is unrecoverable
  264. return false;
  265. }
  266. fFirstOutset *= outset;
  267. fFirstPoint = fPathPolygon[polyCount - 1];
  268. fFirstVertexIndex = fPositions.count();
  269. fPrevOutset = fFirstOutset;
  270. fPrevPoint = fFirstPoint;
  271. fPrevUmbraIndex = -1;
  272. this->addInnerPoint(fFirstPoint, umbraColor, umbraPolygon, &fPrevUmbraIndex);
  273. if (!fTransparent && doClip) {
  274. SkPoint clipPoint;
  275. bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertexIndex],
  276. fCentroid, &clipPoint);
  277. if (isOutside) {
  278. fPositions.push_back(clipPoint);
  279. fColors.push_back(umbraColor);
  280. }
  281. fPrevUmbraOutside = isOutside;
  282. fFirstUmbraOutside = isOutside;
  283. }
  284. SkPoint newPoint = fFirstPoint + fFirstOutset;
  285. fPositions.push_back(newPoint);
  286. fColors.push_back(kPenumbraColor);
  287. this->addEdge(fPathPolygon[0], fFirstOutset, umbraColor, umbraPolygon, false, doClip);
  288. for (int i = 1; i < polyCount; ++i) {
  289. SkVector normal;
  290. if (!compute_normal(fPrevPoint, fPathPolygon[i], fDirection, &normal)) {
  291. return false;
  292. }
  293. normal *= outset;
  294. this->addArc(normal, outset, true);
  295. this->addEdge(fPathPolygon[i], normal, umbraColor, umbraPolygon,
  296. i == polyCount - 1, doClip);
  297. }
  298. SkASSERT(this->indexCount());
  299. // final fan
  300. SkASSERT(fPositions.count() >= 3);
  301. if (this->addArc(fFirstOutset, outset, false)) {
  302. if (fFirstUmbraOutside) {
  303. this->appendTriangle(fFirstVertexIndex, fPositions.count() - 1,
  304. fFirstVertexIndex + 2);
  305. } else {
  306. this->appendTriangle(fFirstVertexIndex, fPositions.count() - 1,
  307. fFirstVertexIndex + 1);
  308. }
  309. } else {
  310. // no arc added, fix up by setting first penumbra point position to last one
  311. if (fFirstUmbraOutside) {
  312. fPositions[fFirstVertexIndex + 2] = fPositions[fPositions.count() - 1];
  313. } else {
  314. fPositions[fFirstVertexIndex + 1] = fPositions[fPositions.count() - 1];
  315. }
  316. }
  317. return true;
  318. }
  319. void SkBaseShadowTessellator::computeClipVectorsAndTestCentroid() {
  320. SkASSERT(fClipPolygon.count() >= 3);
  321. fCurrClipIndex = fClipPolygon.count() - 1;
  322. // init clip vectors
  323. SkVector v0 = fClipPolygon[1] - fClipPolygon[0];
  324. SkVector v1 = fClipPolygon[2] - fClipPolygon[0];
  325. fClipVectors.push_back(v0);
  326. // init centroid check
  327. bool hiddenCentroid = true;
  328. v1 = fCentroid - fClipPolygon[0];
  329. SkScalar initCross = v0.cross(v1);
  330. for (int p = 1; p < fClipPolygon.count(); ++p) {
  331. // add to clip vectors
  332. v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p];
  333. fClipVectors.push_back(v0);
  334. // Determine if transformed centroid is inside clipPolygon.
  335. v1 = fCentroid - fClipPolygon[p];
  336. if (initCross*v0.cross(v1) <= 0) {
  337. hiddenCentroid = false;
  338. }
  339. }
  340. SkASSERT(fClipVectors.count() == fClipPolygon.count());
  341. fTransparent = fTransparent || !hiddenCentroid;
  342. }
  343. void SkBaseShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal,
  344. SkColor umbraColor, const SkTDArray<SkPoint>& umbraPolygon,
  345. bool lastEdge, bool doClip) {
  346. // add next umbra point
  347. int currUmbraIndex;
  348. bool duplicate;
  349. if (lastEdge) {
  350. duplicate = false;
  351. currUmbraIndex = fFirstVertexIndex;
  352. fPrevPoint = nextPoint;
  353. } else {
  354. duplicate = this->addInnerPoint(nextPoint, umbraColor, umbraPolygon, &currUmbraIndex);
  355. }
  356. int prevPenumbraIndex = duplicate || (currUmbraIndex == fFirstVertexIndex)
  357. ? fPositions.count() - 1
  358. : fPositions.count() - 2;
  359. if (!duplicate) {
  360. // add to center fan if transparent or centroid showing
  361. if (fTransparent) {
  362. this->appendTriangle(0, fPrevUmbraIndex, currUmbraIndex);
  363. // otherwise add to clip ring
  364. } else if (doClip) {
  365. SkPoint clipPoint;
  366. bool isOutside = lastEdge ? fFirstUmbraOutside
  367. : this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid,
  368. &clipPoint);
  369. if (isOutside) {
  370. if (!lastEdge) {
  371. fPositions.push_back(clipPoint);
  372. fColors.push_back(umbraColor);
  373. }
  374. this->appendTriangle(fPrevUmbraIndex, currUmbraIndex, currUmbraIndex + 1);
  375. if (fPrevUmbraOutside) {
  376. // fill out quad
  377. this->appendTriangle(fPrevUmbraIndex, currUmbraIndex + 1,
  378. fPrevUmbraIndex + 1);
  379. }
  380. } else if (fPrevUmbraOutside) {
  381. // add tri
  382. this->appendTriangle(fPrevUmbraIndex, currUmbraIndex, fPrevUmbraIndex + 1);
  383. }
  384. fPrevUmbraOutside = isOutside;
  385. }
  386. }
  387. // add next penumbra point and quad
  388. SkPoint newPoint = nextPoint + nextNormal;
  389. fPositions.push_back(newPoint);
  390. fColors.push_back(kPenumbraColor);
  391. if (!duplicate) {
  392. this->appendTriangle(fPrevUmbraIndex, prevPenumbraIndex, currUmbraIndex);
  393. }
  394. this->appendTriangle(prevPenumbraIndex, fPositions.count() - 1, currUmbraIndex);
  395. fPrevUmbraIndex = currUmbraIndex;
  396. fPrevOutset = nextNormal;
  397. }
  398. bool SkBaseShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid,
  399. SkPoint* clipPoint) {
  400. SkVector segmentVector = centroid - umbraPoint;
  401. int startClipPoint = fCurrClipIndex;
  402. do {
  403. SkVector dp = umbraPoint - fClipPolygon[fCurrClipIndex];
  404. SkScalar denom = fClipVectors[fCurrClipIndex].cross(segmentVector);
  405. SkScalar t_num = dp.cross(segmentVector);
  406. // if line segments are nearly parallel
  407. if (SkScalarNearlyZero(denom)) {
  408. // and collinear
  409. if (SkScalarNearlyZero(t_num)) {
  410. return false;
  411. }
  412. // otherwise are separate, will try the next poly segment
  413. // else if crossing lies within poly segment
  414. } else if (t_num >= 0 && t_num <= denom) {
  415. SkScalar s_num = dp.cross(fClipVectors[fCurrClipIndex]);
  416. // if umbra point is inside the clip polygon
  417. if (s_num >= 0 && s_num <= denom) {
  418. segmentVector *= s_num / denom;
  419. *clipPoint = umbraPoint + segmentVector;
  420. return true;
  421. }
  422. }
  423. fCurrClipIndex = (fCurrClipIndex + 1) % fClipPolygon.count();
  424. } while (fCurrClipIndex != startClipPoint);
  425. return false;
  426. }
  427. bool SkBaseShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
  428. const SkTDArray<SkPoint>& umbraPolygon,
  429. int* currUmbraIndex) {
  430. SkPoint umbraPoint;
  431. if (!fValidUmbra) {
  432. SkVector v = fCentroid - pathPoint;
  433. v *= 0.95f;
  434. umbraPoint = pathPoint + v;
  435. } else {
  436. umbraPoint = umbraPolygon[this->getClosestUmbraIndex(pathPoint, umbraPolygon)];
  437. }
  438. fPrevPoint = pathPoint;
  439. // merge "close" points
  440. if (fPrevUmbraIndex == -1 ||
  441. !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) {
  442. // if we've wrapped around, don't add a new point
  443. if (fPrevUmbraIndex >= 0 && duplicate_pt(umbraPoint, fPositions[fFirstVertexIndex])) {
  444. *currUmbraIndex = fFirstVertexIndex;
  445. } else {
  446. *currUmbraIndex = fPositions.count();
  447. fPositions.push_back(umbraPoint);
  448. fColors.push_back(umbraColor);
  449. }
  450. return false;
  451. } else {
  452. *currUmbraIndex = fPrevUmbraIndex;
  453. return true;
  454. }
  455. }
  456. int SkBaseShadowTessellator::getClosestUmbraIndex(const SkPoint& p,
  457. const SkTDArray<SkPoint>& umbraPolygon) {
  458. SkScalar minDistance = SkPointPriv::DistanceToSqd(p, umbraPolygon[fCurrUmbraIndex]);
  459. int index = fCurrUmbraIndex;
  460. int dir = 1;
  461. int next = (index + dir) % umbraPolygon.count();
  462. // init travel direction
  463. SkScalar distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
  464. if (distance < minDistance) {
  465. index = next;
  466. minDistance = distance;
  467. } else {
  468. dir = umbraPolygon.count() - 1;
  469. }
  470. // iterate until we find a point that increases the distance
  471. next = (index + dir) % umbraPolygon.count();
  472. distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
  473. while (distance < minDistance) {
  474. index = next;
  475. minDistance = distance;
  476. next = (index + dir) % umbraPolygon.count();
  477. distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
  478. }
  479. fCurrUmbraIndex = index;
  480. return index;
  481. }
  482. bool SkBaseShadowTessellator::computeConcaveShadow(SkScalar inset, SkScalar outset) {
  483. if (!SkIsSimplePolygon(&fPathPolygon[0], fPathPolygon.count())) {
  484. return false;
  485. }
  486. // generate inner ring
  487. SkTDArray<SkPoint> umbraPolygon;
  488. SkTDArray<int> umbraIndices;
  489. umbraIndices.setReserve(fPathPolygon.count());
  490. if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), fPathBounds, inset,
  491. &umbraPolygon, &umbraIndices)) {
  492. // TODO: figure out how to handle this case
  493. return false;
  494. }
  495. // generate outer ring
  496. SkTDArray<SkPoint> penumbraPolygon;
  497. SkTDArray<int> penumbraIndices;
  498. penumbraPolygon.setReserve(umbraPolygon.count());
  499. penumbraIndices.setReserve(umbraPolygon.count());
  500. if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), fPathBounds, -outset,
  501. &penumbraPolygon, &penumbraIndices)) {
  502. // TODO: figure out how to handle this case
  503. return false;
  504. }
  505. if (!umbraPolygon.count() || !penumbraPolygon.count()) {
  506. return false;
  507. }
  508. // attach the rings together
  509. this->stitchConcaveRings(umbraPolygon, &umbraIndices, penumbraPolygon, &penumbraIndices);
  510. return true;
  511. }
  512. void SkBaseShadowTessellator::stitchConcaveRings(const SkTDArray<SkPoint>& umbraPolygon,
  513. SkTDArray<int>* umbraIndices,
  514. const SkTDArray<SkPoint>& penumbraPolygon,
  515. SkTDArray<int>* penumbraIndices) {
  516. // TODO: only create and fill indexMap when fTransparent is true?
  517. SkAutoSTMalloc<64, uint16_t> indexMap(umbraPolygon.count());
  518. // find minimum indices
  519. int minIndex = 0;
  520. int min = (*penumbraIndices)[0];
  521. for (int i = 1; i < (*penumbraIndices).count(); ++i) {
  522. if ((*penumbraIndices)[i] < min) {
  523. min = (*penumbraIndices)[i];
  524. minIndex = i;
  525. }
  526. }
  527. int currPenumbra = minIndex;
  528. minIndex = 0;
  529. min = (*umbraIndices)[0];
  530. for (int i = 1; i < (*umbraIndices).count(); ++i) {
  531. if ((*umbraIndices)[i] < min) {
  532. min = (*umbraIndices)[i];
  533. minIndex = i;
  534. }
  535. }
  536. int currUmbra = minIndex;
  537. // now find a case where the indices are equal (there should be at least one)
  538. int maxPenumbraIndex = fPathPolygon.count() - 1;
  539. int maxUmbraIndex = fPathPolygon.count() - 1;
  540. while ((*penumbraIndices)[currPenumbra] != (*umbraIndices)[currUmbra]) {
  541. if ((*penumbraIndices)[currPenumbra] < (*umbraIndices)[currUmbra]) {
  542. (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
  543. maxPenumbraIndex = (*penumbraIndices)[currPenumbra];
  544. currPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
  545. } else {
  546. (*umbraIndices)[currUmbra] += fPathPolygon.count();
  547. maxUmbraIndex = (*umbraIndices)[currUmbra];
  548. currUmbra = (currUmbra + 1) % umbraPolygon.count();
  549. }
  550. }
  551. fPositions.push_back(penumbraPolygon[currPenumbra]);
  552. fColors.push_back(kPenumbraColor);
  553. int prevPenumbraIndex = 0;
  554. fPositions.push_back(umbraPolygon[currUmbra]);
  555. fColors.push_back(kUmbraColor);
  556. fPrevUmbraIndex = 1;
  557. indexMap[currUmbra] = 1;
  558. int nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
  559. int nextUmbra = (currUmbra + 1) % umbraPolygon.count();
  560. while ((*penumbraIndices)[nextPenumbra] <= maxPenumbraIndex ||
  561. (*umbraIndices)[nextUmbra] <= maxUmbraIndex) {
  562. if ((*umbraIndices)[nextUmbra] == (*penumbraIndices)[nextPenumbra]) {
  563. // advance both one step
  564. fPositions.push_back(penumbraPolygon[nextPenumbra]);
  565. fColors.push_back(kPenumbraColor);
  566. int currPenumbraIndex = fPositions.count() - 1;
  567. fPositions.push_back(umbraPolygon[nextUmbra]);
  568. fColors.push_back(kUmbraColor);
  569. int currUmbraIndex = fPositions.count() - 1;
  570. indexMap[nextUmbra] = currUmbraIndex;
  571. this->appendQuad(prevPenumbraIndex, currPenumbraIndex,
  572. fPrevUmbraIndex, currUmbraIndex);
  573. prevPenumbraIndex = currPenumbraIndex;
  574. (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
  575. currPenumbra = nextPenumbra;
  576. nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
  577. fPrevUmbraIndex = currUmbraIndex;
  578. (*umbraIndices)[currUmbra] += fPathPolygon.count();
  579. currUmbra = nextUmbra;
  580. nextUmbra = (currUmbra + 1) % umbraPolygon.count();
  581. }
  582. while ((*penumbraIndices)[nextPenumbra] < (*umbraIndices)[nextUmbra] &&
  583. (*penumbraIndices)[nextPenumbra] <= maxPenumbraIndex) {
  584. // fill out penumbra arc
  585. fPositions.push_back(penumbraPolygon[nextPenumbra]);
  586. fColors.push_back(kPenumbraColor);
  587. int currPenumbraIndex = fPositions.count() - 1;
  588. this->appendTriangle(prevPenumbraIndex, currPenumbraIndex, fPrevUmbraIndex);
  589. prevPenumbraIndex = currPenumbraIndex;
  590. // this ensures the ordering when we wrap around
  591. (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
  592. currPenumbra = nextPenumbra;
  593. nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
  594. }
  595. while ((*umbraIndices)[nextUmbra] < (*penumbraIndices)[nextPenumbra] &&
  596. (*umbraIndices)[nextUmbra] <= maxUmbraIndex) {
  597. // fill out umbra arc
  598. fPositions.push_back(umbraPolygon[nextUmbra]);
  599. fColors.push_back(kUmbraColor);
  600. int currUmbraIndex = fPositions.count() - 1;
  601. indexMap[nextUmbra] = currUmbraIndex;
  602. this->appendTriangle(fPrevUmbraIndex, prevPenumbraIndex, currUmbraIndex);
  603. fPrevUmbraIndex = currUmbraIndex;
  604. // this ensures the ordering when we wrap around
  605. (*umbraIndices)[currUmbra] += fPathPolygon.count();
  606. currUmbra = nextUmbra;
  607. nextUmbra = (currUmbra + 1) % umbraPolygon.count();
  608. }
  609. }
  610. // finish up by advancing both one step
  611. fPositions.push_back(penumbraPolygon[nextPenumbra]);
  612. fColors.push_back(kPenumbraColor);
  613. int currPenumbraIndex = fPositions.count() - 1;
  614. fPositions.push_back(umbraPolygon[nextUmbra]);
  615. fColors.push_back(kUmbraColor);
  616. int currUmbraIndex = fPositions.count() - 1;
  617. indexMap[nextUmbra] = currUmbraIndex;
  618. this->appendQuad(prevPenumbraIndex, currPenumbraIndex,
  619. fPrevUmbraIndex, currUmbraIndex);
  620. if (fTransparent) {
  621. SkTriangulateSimplePolygon(umbraPolygon.begin(), indexMap, umbraPolygon.count(),
  622. &fIndices);
  623. }
  624. }
  625. // tesselation tolerance values, in device space pixels
  626. #if SK_SUPPORT_GPU
  627. static const SkScalar kQuadTolerance = 0.2f;
  628. static const SkScalar kCubicTolerance = 0.2f;
  629. #endif
  630. static const SkScalar kConicTolerance = 0.25f;
  631. // clamps the point to the nearest 16th of a pixel
  632. static void sanitize_point(const SkPoint& in, SkPoint* out) {
  633. out->fX = SkScalarRoundToScalar(16.f*in.fX)*0.0625f;
  634. out->fY = SkScalarRoundToScalar(16.f*in.fY)*0.0625f;
  635. }
  636. void SkBaseShadowTessellator::handleLine(const SkPoint& p) {
  637. SkPoint pSanitized;
  638. sanitize_point(p, &pSanitized);
  639. if (fPathPolygon.count() > 0) {
  640. if (!this->accumulateCentroid(fPathPolygon[fPathPolygon.count() - 1], pSanitized)) {
  641. // skip coincident point
  642. return;
  643. }
  644. }
  645. if (fPathPolygon.count() > 1) {
  646. if (!checkConvexity(fPathPolygon[fPathPolygon.count() - 2],
  647. fPathPolygon[fPathPolygon.count() - 1],
  648. pSanitized)) {
  649. // remove collinear point
  650. fPathPolygon.pop();
  651. // it's possible that the previous point is coincident with the new one now
  652. if (duplicate_pt(fPathPolygon[fPathPolygon.count() - 1], pSanitized)) {
  653. fPathPolygon.pop();
  654. }
  655. }
  656. }
  657. fPathPolygon.push_back(pSanitized);
  658. }
  659. void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
  660. m.mapPoints(p, 1);
  661. this->handleLine(*p);
  662. }
  663. void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
  664. #if SK_SUPPORT_GPU
  665. // check for degeneracy
  666. SkVector v0 = pts[1] - pts[0];
  667. SkVector v1 = pts[2] - pts[0];
  668. if (SkScalarNearlyZero(v0.cross(v1))) {
  669. return;
  670. }
  671. // TODO: Pull PathUtils out of Ganesh?
  672. int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
  673. fPointBuffer.setCount(maxCount);
  674. SkPoint* target = fPointBuffer.begin();
  675. int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
  676. kQuadTolerance, &target, maxCount);
  677. fPointBuffer.setCount(count);
  678. for (int i = 0; i < count; i++) {
  679. this->handleLine(fPointBuffer[i]);
  680. }
  681. #else
  682. // for now, just to draw something
  683. this->handleLine(pts[1]);
  684. this->handleLine(pts[2]);
  685. #endif
  686. }
  687. void SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
  688. m.mapPoints(pts, 3);
  689. this->handleQuad(pts);
  690. }
  691. void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
  692. m.mapPoints(pts, 4);
  693. #if SK_SUPPORT_GPU
  694. // TODO: Pull PathUtils out of Ganesh?
  695. int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
  696. fPointBuffer.setCount(maxCount);
  697. SkPoint* target = fPointBuffer.begin();
  698. int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
  699. kCubicTolerance, &target, maxCount);
  700. fPointBuffer.setCount(count);
  701. for (int i = 0; i < count; i++) {
  702. this->handleLine(fPointBuffer[i]);
  703. }
  704. #else
  705. // for now, just to draw something
  706. this->handleLine(pts[1]);
  707. this->handleLine(pts[2]);
  708. this->handleLine(pts[3]);
  709. #endif
  710. }
  711. void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
  712. if (m.hasPerspective()) {
  713. w = SkConic::TransformW(pts, w, m);
  714. }
  715. m.mapPoints(pts, 3);
  716. SkAutoConicToQuads quadder;
  717. const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
  718. SkPoint lastPoint = *(quads++);
  719. int count = quadder.countQuads();
  720. for (int i = 0; i < count; ++i) {
  721. SkPoint quadPts[3];
  722. quadPts[0] = lastPoint;
  723. quadPts[1] = quads[0];
  724. quadPts[2] = i == count - 1 ? pts[2] : quads[1];
  725. this->handleQuad(quadPts);
  726. lastPoint = quadPts[2];
  727. quads += 2;
  728. }
  729. }
  730. bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, SkScalar offset, bool finishArc) {
  731. // fill in fan from previous quad
  732. SkScalar rotSin, rotCos;
  733. int numSteps;
  734. if (!SkComputeRadialSteps(fPrevOutset, nextNormal, offset, &rotSin, &rotCos, &numSteps)) {
  735. // recover as best we can
  736. numSteps = 0;
  737. }
  738. SkVector prevNormal = fPrevOutset;
  739. for (int i = 0; i < numSteps-1; ++i) {
  740. SkVector currNormal;
  741. currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
  742. currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
  743. fPositions.push_back(fPrevPoint + currNormal);
  744. fColors.push_back(kPenumbraColor);
  745. this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
  746. prevNormal = currNormal;
  747. }
  748. if (finishArc && numSteps) {
  749. fPositions.push_back(fPrevPoint + nextNormal);
  750. fColors.push_back(kPenumbraColor);
  751. this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
  752. }
  753. fPrevOutset = nextNormal;
  754. return (numSteps > 0);
  755. }
  756. void SkBaseShadowTessellator::appendTriangle(uint16_t index0, uint16_t index1, uint16_t index2) {
  757. auto indices = fIndices.append(3);
  758. indices[0] = index0;
  759. indices[1] = index1;
  760. indices[2] = index2;
  761. }
  762. void SkBaseShadowTessellator::appendQuad(uint16_t index0, uint16_t index1,
  763. uint16_t index2, uint16_t index3) {
  764. auto indices = fIndices.append(6);
  765. indices[0] = index0;
  766. indices[1] = index1;
  767. indices[2] = index2;
  768. indices[3] = index2;
  769. indices[4] = index1;
  770. indices[5] = index3;
  771. }
  772. //////////////////////////////////////////////////////////////////////////////////////////////////
  773. class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
  774. public:
  775. SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
  776. const SkPoint3& zPlaneParams, bool transparent);
  777. private:
  778. bool computePathPolygon(const SkPath& path, const SkMatrix& ctm);
  779. typedef SkBaseShadowTessellator INHERITED;
  780. };
  781. SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
  782. const SkMatrix& ctm,
  783. const SkPoint3& zPlaneParams,
  784. bool transparent)
  785. : INHERITED(zPlaneParams, path.getBounds(), transparent) {
  786. // Set base colors
  787. auto baseZ = heightFunc(fPathBounds.centerX(), fPathBounds.centerY());
  788. // umbraColor is the interior value, penumbraColor the exterior value.
  789. auto outset = SkDrawShadowMetrics::AmbientBlurRadius(baseZ);
  790. auto inset = outset * SkDrawShadowMetrics::AmbientRecipAlpha(baseZ) - outset;
  791. inset = SkScalarPin(inset, 0, SkTMin(path.getBounds().width(),
  792. path.getBounds().height()));
  793. if (!this->computePathPolygon(path, ctm)) {
  794. return;
  795. }
  796. if (fPathPolygon.count() < 3 || !SkScalarIsFinite(fArea)) {
  797. fSucceeded = true; // We don't want to try to blur these cases, so we will
  798. // return an empty SkVertices instead.
  799. return;
  800. }
  801. // Outer ring: 3*numPts
  802. // Middle ring: numPts
  803. fPositions.setReserve(4 * path.countPoints());
  804. fColors.setReserve(4 * path.countPoints());
  805. // Outer ring: 12*numPts
  806. // Middle ring: 0
  807. fIndices.setReserve(12 * path.countPoints());
  808. if (fIsConvex) {
  809. fSucceeded = this->computeConvexShadow(inset, outset, false);
  810. } else {
  811. fSucceeded = this->computeConcaveShadow(inset, outset);
  812. }
  813. }
  814. bool SkAmbientShadowTessellator::computePathPolygon(const SkPath& path, const SkMatrix& ctm) {
  815. fPathPolygon.setReserve(path.countPoints());
  816. // walk around the path, tessellate and generate outer ring
  817. // if original path is transparent, will accumulate sum of points for centroid
  818. SkPath::Iter iter(path, true);
  819. SkPoint pts[4];
  820. SkPath::Verb verb;
  821. bool verbSeen = false;
  822. bool closeSeen = false;
  823. while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
  824. if (closeSeen) {
  825. return false;
  826. }
  827. switch (verb) {
  828. case SkPath::kLine_Verb:
  829. this->handleLine(ctm, &pts[1]);
  830. break;
  831. case SkPath::kQuad_Verb:
  832. this->handleQuad(ctm, pts);
  833. break;
  834. case SkPath::kCubic_Verb:
  835. this->handleCubic(ctm, pts);
  836. break;
  837. case SkPath::kConic_Verb:
  838. this->handleConic(ctm, pts, iter.conicWeight());
  839. break;
  840. case SkPath::kMove_Verb:
  841. if (verbSeen) {
  842. return false;
  843. }
  844. break;
  845. case SkPath::kClose_Verb:
  846. case SkPath::kDone_Verb:
  847. closeSeen = true;
  848. break;
  849. }
  850. verbSeen = true;
  851. }
  852. this->finishPathPolygon();
  853. return true;
  854. }
  855. ///////////////////////////////////////////////////////////////////////////////////////////////////
  856. class SkSpotShadowTessellator : public SkBaseShadowTessellator {
  857. public:
  858. SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
  859. const SkPoint3& zPlaneParams, const SkPoint3& lightPos,
  860. SkScalar lightRadius, bool transparent);
  861. private:
  862. bool computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
  863. const SkMatrix& shadowTransform);
  864. void addToClip(const SkVector& nextPoint);
  865. typedef SkBaseShadowTessellator INHERITED;
  866. };
  867. SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
  868. const SkPoint3& zPlaneParams,
  869. const SkPoint3& lightPos, SkScalar lightRadius,
  870. bool transparent)
  871. : INHERITED(zPlaneParams, path.getBounds(), transparent) {
  872. // Compute the blur radius, scale and translation for the spot shadow.
  873. SkMatrix shadowTransform;
  874. SkScalar outset;
  875. if (!SkDrawShadowMetrics::GetSpotShadowTransform(lightPos, lightRadius,
  876. ctm, zPlaneParams, path.getBounds(),
  877. &shadowTransform, &outset)) {
  878. return;
  879. }
  880. SkScalar inset = outset;
  881. // compute rough clip bounds for umbra, plus offset polygon, plus centroid
  882. if (!this->computeClipAndPathPolygons(path, ctm, shadowTransform)) {
  883. return;
  884. }
  885. if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3 || !SkScalarIsFinite(fArea)) {
  886. fSucceeded = true; // We don't want to try to blur these cases, so we will
  887. // return an empty SkVertices instead.
  888. return;
  889. }
  890. // TODO: calculate these reserves better
  891. // Penumbra ring: 3*numPts
  892. // Umbra ring: numPts
  893. // Inner ring: numPts
  894. fPositions.setReserve(5 * path.countPoints());
  895. fColors.setReserve(5 * path.countPoints());
  896. // Penumbra ring: 12*numPts
  897. // Umbra ring: 3*numPts
  898. fIndices.setReserve(15 * path.countPoints());
  899. if (fIsConvex) {
  900. fSucceeded = this->computeConvexShadow(inset, outset, true);
  901. } else {
  902. fSucceeded = this->computeConcaveShadow(inset, outset);
  903. }
  904. if (!fSucceeded) {
  905. return;
  906. }
  907. fSucceeded = true;
  908. }
  909. bool SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
  910. const SkMatrix& shadowTransform) {
  911. fPathPolygon.setReserve(path.countPoints());
  912. fClipPolygon.setReserve(path.countPoints());
  913. // Walk around the path and compute clip polygon and path polygon.
  914. // Will also accumulate sum of areas for centroid.
  915. // For Bezier curves, we compute additional interior points on curve.
  916. SkPath::Iter iter(path, true);
  917. SkPoint pts[4];
  918. SkPoint clipPts[4];
  919. SkPath::Verb verb;
  920. // coefficients to compute cubic Bezier at t = 5/16
  921. static constexpr SkScalar kA = 0.32495117187f;
  922. static constexpr SkScalar kB = 0.44311523437f;
  923. static constexpr SkScalar kC = 0.20141601562f;
  924. static constexpr SkScalar kD = 0.03051757812f;
  925. SkPoint curvePoint;
  926. SkScalar w;
  927. bool closeSeen = false;
  928. bool verbSeen = false;
  929. while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
  930. if (closeSeen) {
  931. return false;
  932. }
  933. switch (verb) {
  934. case SkPath::kLine_Verb:
  935. ctm.mapPoints(clipPts, &pts[1], 1);
  936. this->addToClip(clipPts[0]);
  937. this->handleLine(shadowTransform, &pts[1]);
  938. break;
  939. case SkPath::kQuad_Verb:
  940. ctm.mapPoints(clipPts, pts, 3);
  941. // point at t = 1/2
  942. curvePoint.fX = 0.25f*clipPts[0].fX + 0.5f*clipPts[1].fX + 0.25f*clipPts[2].fX;
  943. curvePoint.fY = 0.25f*clipPts[0].fY + 0.5f*clipPts[1].fY + 0.25f*clipPts[2].fY;
  944. this->addToClip(curvePoint);
  945. this->addToClip(clipPts[2]);
  946. this->handleQuad(shadowTransform, pts);
  947. break;
  948. case SkPath::kConic_Verb:
  949. ctm.mapPoints(clipPts, pts, 3);
  950. w = iter.conicWeight();
  951. // point at t = 1/2
  952. curvePoint.fX = 0.25f*clipPts[0].fX + w*0.5f*clipPts[1].fX + 0.25f*clipPts[2].fX;
  953. curvePoint.fY = 0.25f*clipPts[0].fY + w*0.5f*clipPts[1].fY + 0.25f*clipPts[2].fY;
  954. curvePoint *= SkScalarInvert(0.5f + 0.5f*w);
  955. this->addToClip(curvePoint);
  956. this->addToClip(clipPts[2]);
  957. this->handleConic(shadowTransform, pts, w);
  958. break;
  959. case SkPath::kCubic_Verb:
  960. ctm.mapPoints(clipPts, pts, 4);
  961. // point at t = 5/16
  962. curvePoint.fX = kA*clipPts[0].fX + kB*clipPts[1].fX
  963. + kC*clipPts[2].fX + kD*clipPts[3].fX;
  964. curvePoint.fY = kA*clipPts[0].fY + kB*clipPts[1].fY
  965. + kC*clipPts[2].fY + kD*clipPts[3].fY;
  966. this->addToClip(curvePoint);
  967. // point at t = 11/16
  968. curvePoint.fX = kD*clipPts[0].fX + kC*clipPts[1].fX
  969. + kB*clipPts[2].fX + kA*clipPts[3].fX;
  970. curvePoint.fY = kD*clipPts[0].fY + kC*clipPts[1].fY
  971. + kB*clipPts[2].fY + kA*clipPts[3].fY;
  972. this->addToClip(curvePoint);
  973. this->addToClip(clipPts[3]);
  974. this->handleCubic(shadowTransform, pts);
  975. break;
  976. case SkPath::kMove_Verb:
  977. if (verbSeen) {
  978. return false;
  979. }
  980. break;
  981. case SkPath::kClose_Verb:
  982. case SkPath::kDone_Verb:
  983. closeSeen = true;
  984. break;
  985. default:
  986. SkDEBUGFAIL("unknown verb");
  987. }
  988. verbSeen = true;
  989. }
  990. this->finishPathPolygon();
  991. return true;
  992. }
  993. void SkSpotShadowTessellator::addToClip(const SkPoint& point) {
  994. if (fClipPolygon.isEmpty() || !duplicate_pt(point, fClipPolygon[fClipPolygon.count() - 1])) {
  995. fClipPolygon.push_back(point);
  996. }
  997. }
  998. ///////////////////////////////////////////////////////////////////////////////////////////////////
  999. sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
  1000. const SkPoint3& zPlane, bool transparent) {
  1001. if (!ctm.mapRect(path.getBounds()).isFinite() || !zPlane.isFinite()) {
  1002. return nullptr;
  1003. }
  1004. SkAmbientShadowTessellator ambientTess(path, ctm, zPlane, transparent);
  1005. return ambientTess.releaseVertices();
  1006. }
  1007. sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
  1008. const SkPoint3& zPlane, const SkPoint3& lightPos,
  1009. SkScalar lightRadius, bool transparent) {
  1010. if (!ctm.mapRect(path.getBounds()).isFinite() || !zPlane.isFinite() ||
  1011. !lightPos.isFinite() || !(lightPos.fZ >= SK_ScalarNearlyZero) ||
  1012. !SkScalarIsFinite(lightRadius) || !(lightRadius >= SK_ScalarNearlyZero)) {
  1013. return nullptr;
  1014. }
  1015. SkSpotShadowTessellator spotTess(path, ctm, zPlane, lightPos, lightRadius, transparent);
  1016. return spotTess.releaseVertices();
  1017. }