The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

846 lines
22KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255 6263 6386)
  21. const int juce_edgeTableDefaultEdgesPerLine = 32;
  22. //==============================================================================
  23. EdgeTable::EdgeTable (Rectangle<int> area, const Path& path, const AffineTransform& transform)
  24. : bounds (area),
  25. // this is a very vague heuristic to make a rough guess at a good table size
  26. // for a given path, such that it's big enough to mostly avoid remapping, but also
  27. // not so big that it's wasteful for simple paths.
  28. maxEdgesPerLine (jmax (juce_edgeTableDefaultEdgesPerLine / 2,
  29. 4 * (int) std::sqrt (path.data.size()))),
  30. lineStrideElements (maxEdgesPerLine * 2 + 1)
  31. {
  32. allocate();
  33. int* t = table;
  34. for (int i = bounds.getHeight(); --i >= 0;)
  35. {
  36. *t = 0;
  37. t += lineStrideElements;
  38. }
  39. auto leftLimit = bounds.getX() * 256;
  40. auto topLimit = bounds.getY() * 256;
  41. auto rightLimit = bounds.getRight() * 256;
  42. auto heightLimit = bounds.getHeight() * 256;
  43. PathFlatteningIterator iter (path, transform);
  44. while (iter.next())
  45. {
  46. auto y1 = roundToInt (iter.y1 * 256.0f);
  47. auto y2 = roundToInt (iter.y2 * 256.0f);
  48. if (y1 != y2)
  49. {
  50. y1 -= topLimit;
  51. y2 -= topLimit;
  52. auto startY = y1;
  53. int direction = -1;
  54. if (y1 > y2)
  55. {
  56. std::swap (y1, y2);
  57. direction = 1;
  58. }
  59. if (y1 < 0)
  60. y1 = 0;
  61. if (y2 > heightLimit)
  62. y2 = heightLimit;
  63. if (y1 < y2)
  64. {
  65. const double startX = 256.0f * iter.x1;
  66. const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
  67. auto stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier)));
  68. do
  69. {
  70. auto step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
  71. auto x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY));
  72. if (x < leftLimit)
  73. x = leftLimit;
  74. else if (x >= rightLimit)
  75. x = rightLimit - 1;
  76. addEdgePoint (x, y1 >> 8, direction * step);
  77. y1 += step;
  78. }
  79. while (y1 < y2);
  80. }
  81. }
  82. }
  83. sanitiseLevels (path.isUsingNonZeroWinding());
  84. }
  85. EdgeTable::EdgeTable (Rectangle<int> rectangleToAdd)
  86. : bounds (rectangleToAdd),
  87. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  88. lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1)
  89. {
  90. allocate();
  91. table[0] = 0;
  92. auto x1 = rectangleToAdd.getX() << 8;
  93. auto x2 = rectangleToAdd.getRight() << 8;
  94. int* t = table;
  95. for (int i = rectangleToAdd.getHeight(); --i >= 0;)
  96. {
  97. t[0] = 2;
  98. t[1] = x1;
  99. t[2] = 255;
  100. t[3] = x2;
  101. t[4] = 0;
  102. t += lineStrideElements;
  103. }
  104. }
  105. EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
  106. : bounds (rectanglesToAdd.getBounds()),
  107. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  108. lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
  109. needToCheckEmptiness (true)
  110. {
  111. allocate();
  112. clearLineSizes();
  113. for (auto& r : rectanglesToAdd)
  114. {
  115. auto x1 = r.getX() << 8;
  116. auto x2 = r.getRight() << 8;
  117. auto y = r.getY() - bounds.getY();
  118. for (int j = r.getHeight(); --j >= 0;)
  119. addEdgePointPair (x1, x2, y++, 255);
  120. }
  121. sanitiseLevels (true);
  122. }
  123. EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
  124. : bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()),
  125. maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2),
  126. lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1)
  127. {
  128. bounds.setHeight (bounds.getHeight() + 1);
  129. allocate();
  130. clearLineSizes();
  131. for (auto& r : rectanglesToAdd)
  132. {
  133. auto x1 = roundToInt (r.getX() * 256.0f);
  134. auto x2 = roundToInt (r.getRight() * 256.0f);
  135. auto y1 = roundToInt (r.getY() * 256.0f) - (bounds.getY() << 8);
  136. auto y2 = roundToInt (r.getBottom() * 256.0f) - (bounds.getY() << 8);
  137. if (x2 <= x1 || y2 <= y1)
  138. continue;
  139. auto y = y1 >> 8;
  140. auto lastLine = y2 >> 8;
  141. if (y == lastLine)
  142. {
  143. addEdgePointPair (x1, x2, y, y2 - y1);
  144. }
  145. else
  146. {
  147. addEdgePointPair (x1, x2, y++, 255 - (y1 & 255));
  148. while (y < lastLine)
  149. addEdgePointPair (x1, x2, y++, 255);
  150. jassert (y < bounds.getHeight());
  151. addEdgePointPair (x1, x2, y, y2 & 255);
  152. }
  153. }
  154. sanitiseLevels (true);
  155. }
  156. EdgeTable::EdgeTable (Rectangle<float> rectangleToAdd)
  157. : bounds ((int) std::floor (rectangleToAdd.getX()),
  158. roundToInt (rectangleToAdd.getY() * 256.0f) >> 8,
  159. 2 + (int) rectangleToAdd.getWidth(),
  160. 2 + (int) rectangleToAdd.getHeight()),
  161. maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
  162. lineStrideElements ((juce_edgeTableDefaultEdgesPerLine * 2) + 1)
  163. {
  164. jassert (! rectangleToAdd.isEmpty());
  165. allocate();
  166. table[0] = 0;
  167. auto x1 = roundToInt (rectangleToAdd.getX() * 256.0f);
  168. auto x2 = roundToInt (rectangleToAdd.getRight() * 256.0f);
  169. auto y1 = roundToInt (rectangleToAdd.getY() * 256.0f) - (bounds.getY() << 8);
  170. auto y2 = roundToInt (rectangleToAdd.getBottom() * 256.0f) - (bounds.getY() << 8);
  171. jassert (y1 < 256);
  172. if (x2 <= x1 || y2 <= y1)
  173. {
  174. bounds.setHeight (0);
  175. return;
  176. }
  177. int lineY = 0;
  178. int* t = table;
  179. if ((y1 >> 8) == (y2 >> 8))
  180. {
  181. t[0] = 2;
  182. t[1] = x1;
  183. t[2] = y2 - y1;
  184. t[3] = x2;
  185. t[4] = 0;
  186. ++lineY;
  187. t += lineStrideElements;
  188. }
  189. else
  190. {
  191. t[0] = 2;
  192. t[1] = x1;
  193. t[2] = 255 - (y1 & 255);
  194. t[3] = x2;
  195. t[4] = 0;
  196. ++lineY;
  197. t += lineStrideElements;
  198. while (lineY < (y2 >> 8))
  199. {
  200. t[0] = 2;
  201. t[1] = x1;
  202. t[2] = 255;
  203. t[3] = x2;
  204. t[4] = 0;
  205. ++lineY;
  206. t += lineStrideElements;
  207. }
  208. jassert (lineY < bounds.getHeight());
  209. t[0] = 2;
  210. t[1] = x1;
  211. t[2] = y2 & 255;
  212. t[3] = x2;
  213. t[4] = 0;
  214. ++lineY;
  215. t += lineStrideElements;
  216. }
  217. while (lineY < bounds.getHeight())
  218. {
  219. t[0] = 0;
  220. t += lineStrideElements;
  221. ++lineY;
  222. }
  223. }
  224. EdgeTable::EdgeTable (const EdgeTable& other)
  225. {
  226. operator= (other);
  227. }
  228. EdgeTable& EdgeTable::operator= (const EdgeTable& other)
  229. {
  230. bounds = other.bounds;
  231. maxEdgesPerLine = other.maxEdgesPerLine;
  232. lineStrideElements = other.lineStrideElements;
  233. needToCheckEmptiness = other.needToCheckEmptiness;
  234. allocate();
  235. copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight());
  236. return *this;
  237. }
  238. EdgeTable::~EdgeTable()
  239. {
  240. }
  241. //==============================================================================
  242. static size_t getEdgeTableAllocationSize (int lineStride, int height) noexcept
  243. {
  244. // (leave an extra line at the end for use as scratch space)
  245. return (size_t) (lineStride * (2 + jmax (0, height)));
  246. }
  247. void EdgeTable::allocate()
  248. {
  249. table.malloc (getEdgeTableAllocationSize (lineStrideElements, bounds.getHeight()));
  250. }
  251. void EdgeTable::clearLineSizes() noexcept
  252. {
  253. int* t = table;
  254. for (int i = bounds.getHeight(); --i >= 0;)
  255. {
  256. *t = 0;
  257. t += lineStrideElements;
  258. }
  259. }
  260. void EdgeTable::copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept
  261. {
  262. while (--numLines >= 0)
  263. {
  264. memcpy (dest, src, (size_t) (src[0] * 2 + 1) * sizeof (int));
  265. src += srcLineStride;
  266. dest += destLineStride;
  267. }
  268. }
  269. void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
  270. {
  271. // Convert the table from relative windings to absolute levels..
  272. int* lineStart = table;
  273. for (int y = bounds.getHeight(); --y >= 0;)
  274. {
  275. auto num = lineStart[0];
  276. if (num > 0)
  277. {
  278. auto* items = reinterpret_cast<LineItem*> (lineStart + 1);
  279. auto* itemsEnd = items + num;
  280. // sort the X coords
  281. std::sort (items, itemsEnd);
  282. auto* src = items;
  283. auto correctedNum = num;
  284. int level = 0;
  285. while (src < itemsEnd)
  286. {
  287. level += src->level;
  288. auto x = src->x;
  289. ++src;
  290. while (src < itemsEnd && src->x == x)
  291. {
  292. level += src->level;
  293. ++src;
  294. --correctedNum;
  295. }
  296. auto corrected = std::abs (level);
  297. if (corrected >> 8)
  298. {
  299. if (useNonZeroWinding)
  300. {
  301. corrected = 255;
  302. }
  303. else
  304. {
  305. corrected &= 511;
  306. if (corrected >> 8)
  307. corrected = 511 - corrected;
  308. }
  309. }
  310. items->x = x;
  311. items->level = corrected;
  312. ++items;
  313. }
  314. lineStart[0] = correctedNum;
  315. (items - 1)->level = 0; // force the last level to 0, just in case something went wrong in creating the table
  316. }
  317. lineStart += lineStrideElements;
  318. }
  319. }
  320. void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
  321. {
  322. if (newNumEdgesPerLine != maxEdgesPerLine)
  323. {
  324. maxEdgesPerLine = newNumEdgesPerLine;
  325. jassert (bounds.getHeight() > 0);
  326. auto newLineStrideElements = maxEdgesPerLine * 2 + 1;
  327. HeapBlock<int> newTable (getEdgeTableAllocationSize (newLineStrideElements, bounds.getHeight()));
  328. copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight());
  329. table.swapWith (newTable);
  330. lineStrideElements = newLineStrideElements;
  331. }
  332. }
  333. inline void EdgeTable::remapWithExtraSpace (int numPoints)
  334. {
  335. remapTableForNumEdges (numPoints * 2);
  336. jassert (numPoints < maxEdgesPerLine);
  337. }
  338. void EdgeTable::optimiseTable()
  339. {
  340. int maxLineElements = 0;
  341. for (int i = bounds.getHeight(); --i >= 0;)
  342. maxLineElements = jmax (maxLineElements, table[i * lineStrideElements]);
  343. remapTableForNumEdges (maxLineElements);
  344. }
  345. void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
  346. {
  347. jassert (y >= 0 && y < bounds.getHeight());
  348. auto* line = table + lineStrideElements * y;
  349. auto numPoints = line[0];
  350. if (numPoints >= maxEdgesPerLine)
  351. {
  352. remapWithExtraSpace (numPoints);
  353. line = table + lineStrideElements * y;
  354. }
  355. line[0] = numPoints + 1;
  356. line += numPoints * 2;
  357. line[1] = x;
  358. line[2] = winding;
  359. }
  360. void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding)
  361. {
  362. jassert (y >= 0 && y < bounds.getHeight());
  363. auto* line = table + lineStrideElements * y;
  364. auto numPoints = line[0];
  365. if (numPoints + 1 >= maxEdgesPerLine)
  366. {
  367. remapWithExtraSpace (numPoints + 1);
  368. line = table + lineStrideElements * y;
  369. }
  370. line[0] = numPoints + 2;
  371. line += numPoints * 2;
  372. line[1] = x1;
  373. line[2] = winding;
  374. line[3] = x2;
  375. line[4] = -winding;
  376. }
  377. void EdgeTable::translate (float dx, int dy) noexcept
  378. {
  379. bounds.translate ((int) std::floor (dx), dy);
  380. int* lineStart = table;
  381. auto intDx = (int) (dx * 256.0f);
  382. for (int i = bounds.getHeight(); --i >= 0;)
  383. {
  384. auto* line = lineStart;
  385. lineStart += lineStrideElements;
  386. auto num = *line++;
  387. while (--num >= 0)
  388. {
  389. *line += intDx;
  390. line += 2;
  391. }
  392. }
  393. }
  394. void EdgeTable::multiplyLevels (float amount)
  395. {
  396. int* lineStart = table;
  397. auto multiplier = (int) (amount * 256.0f);
  398. for (int y = 0; y < bounds.getHeight(); ++y)
  399. {
  400. auto numPoints = lineStart[0];
  401. auto* item = reinterpret_cast<LineItem*> (lineStart + 1);
  402. lineStart += lineStrideElements;
  403. while (--numPoints > 0)
  404. {
  405. item->level = jmin (255, (item->level * multiplier) >> 8);
  406. ++item;
  407. }
  408. }
  409. }
  410. void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherLine)
  411. {
  412. jassert (y >= 0 && y < bounds.getHeight());
  413. auto* srcLine = table + lineStrideElements * y;
  414. auto srcNum1 = *srcLine;
  415. if (srcNum1 == 0)
  416. return;
  417. auto srcNum2 = *otherLine;
  418. if (srcNum2 == 0)
  419. {
  420. *srcLine = 0;
  421. return;
  422. }
  423. auto right = bounds.getRight() << 8;
  424. // optimise for the common case where our line lies entirely within a
  425. // single pair of points, as happens when clipping to a simple rect.
  426. if (srcNum2 == 2 && otherLine[2] >= 255)
  427. {
  428. clipEdgeTableLineToRange (srcLine, otherLine[1], jmin (right, otherLine[3]));
  429. return;
  430. }
  431. bool isUsingTempSpace = false;
  432. const int* src1 = srcLine + 1;
  433. auto x1 = *src1++;
  434. const int* src2 = otherLine + 1;
  435. auto x2 = *src2++;
  436. int destIndex = 0, destTotal = 0;
  437. int level1 = 0, level2 = 0;
  438. int lastX = std::numeric_limits<int>::min(), lastLevel = 0;
  439. while (srcNum1 > 0 && srcNum2 > 0)
  440. {
  441. int nextX;
  442. if (x1 <= x2)
  443. {
  444. if (x1 == x2)
  445. {
  446. level2 = *src2++;
  447. x2 = *src2++;
  448. --srcNum2;
  449. }
  450. nextX = x1;
  451. level1 = *src1++;
  452. x1 = *src1++;
  453. --srcNum1;
  454. }
  455. else
  456. {
  457. nextX = x2;
  458. level2 = *src2++;
  459. x2 = *src2++;
  460. --srcNum2;
  461. }
  462. if (nextX > lastX)
  463. {
  464. if (nextX >= right)
  465. break;
  466. lastX = nextX;
  467. auto nextLevel = (level1 * (level2 + 1)) >> 8;
  468. jassert (isPositiveAndBelow (nextLevel, 256));
  469. if (nextLevel != lastLevel)
  470. {
  471. if (destTotal >= maxEdgesPerLine)
  472. {
  473. srcLine[0] = destTotal;
  474. if (isUsingTempSpace)
  475. {
  476. auto tempSize = (size_t) srcNum1 * 2 * sizeof (int);
  477. auto oldTemp = static_cast<int*> (alloca (tempSize));
  478. memcpy (oldTemp, src1, tempSize);
  479. remapTableForNumEdges (jmax (256, destTotal * 2));
  480. srcLine = table + lineStrideElements * y;
  481. auto* newTemp = table + lineStrideElements * bounds.getHeight();
  482. memcpy (newTemp, oldTemp, tempSize);
  483. src1 = newTemp;
  484. }
  485. else
  486. {
  487. remapTableForNumEdges (jmax (256, destTotal * 2));
  488. srcLine = table + lineStrideElements * y;
  489. }
  490. }
  491. ++destTotal;
  492. lastLevel = nextLevel;
  493. if (! isUsingTempSpace)
  494. {
  495. isUsingTempSpace = true;
  496. auto* temp = table + lineStrideElements * bounds.getHeight();
  497. memcpy (temp, src1, (size_t) srcNum1 * 2 * sizeof (int));
  498. src1 = temp;
  499. }
  500. srcLine[++destIndex] = nextX;
  501. srcLine[++destIndex] = nextLevel;
  502. }
  503. }
  504. }
  505. if (lastLevel > 0)
  506. {
  507. if (destTotal >= maxEdgesPerLine)
  508. {
  509. srcLine[0] = destTotal;
  510. remapTableForNumEdges (jmax (256, destTotal * 2));
  511. srcLine = table + lineStrideElements * y;
  512. }
  513. ++destTotal;
  514. srcLine[++destIndex] = right;
  515. srcLine[++destIndex] = 0;
  516. }
  517. srcLine[0] = destTotal;
  518. }
  519. void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2) noexcept
  520. {
  521. int* lastItem = dest + (dest[0] * 2 - 1);
  522. if (x2 < lastItem[0])
  523. {
  524. if (x2 <= dest[1])
  525. {
  526. dest[0] = 0;
  527. return;
  528. }
  529. while (x2 < lastItem[-2])
  530. {
  531. --(dest[0]);
  532. lastItem -= 2;
  533. }
  534. lastItem[0] = x2;
  535. lastItem[1] = 0;
  536. }
  537. if (x1 > dest[1])
  538. {
  539. while (lastItem[0] > x1)
  540. lastItem -= 2;
  541. auto itemsRemoved = (int) (lastItem - (dest + 1)) / 2;
  542. if (itemsRemoved > 0)
  543. {
  544. dest[0] -= itemsRemoved;
  545. memmove (dest + 1, lastItem, (size_t) dest[0] * (sizeof (int) * 2));
  546. }
  547. dest[1] = x1;
  548. }
  549. }
  550. //==============================================================================
  551. void EdgeTable::clipToRectangle (Rectangle<int> r)
  552. {
  553. auto clipped = r.getIntersection (bounds);
  554. if (clipped.isEmpty())
  555. {
  556. needToCheckEmptiness = false;
  557. bounds.setHeight (0);
  558. }
  559. else
  560. {
  561. auto top = clipped.getY() - bounds.getY();
  562. auto bottom = clipped.getBottom() - bounds.getY();
  563. if (bottom < bounds.getHeight())
  564. bounds.setHeight (bottom);
  565. for (int i = 0; i < top; ++i)
  566. table[lineStrideElements * i] = 0;
  567. if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight())
  568. {
  569. auto x1 = clipped.getX() << 8;
  570. auto x2 = jmin (bounds.getRight(), clipped.getRight()) << 8;
  571. int* line = table + lineStrideElements * top;
  572. for (int i = bottom - top; --i >= 0;)
  573. {
  574. if (line[0] != 0)
  575. clipEdgeTableLineToRange (line, x1, x2);
  576. line += lineStrideElements;
  577. }
  578. }
  579. needToCheckEmptiness = true;
  580. }
  581. }
  582. void EdgeTable::excludeRectangle (Rectangle<int> r)
  583. {
  584. auto clipped = r.getIntersection (bounds);
  585. if (! clipped.isEmpty())
  586. {
  587. auto top = clipped.getY() - bounds.getY();
  588. auto bottom = clipped.getBottom() - bounds.getY();
  589. const int rectLine[] = { 4, std::numeric_limits<int>::min(), 255,
  590. clipped.getX() << 8, 0,
  591. clipped.getRight() << 8, 255,
  592. std::numeric_limits<int>::max(), 0 };
  593. for (int i = top; i < bottom; ++i)
  594. intersectWithEdgeTableLine (i, rectLine);
  595. needToCheckEmptiness = true;
  596. }
  597. }
  598. void EdgeTable::clipToEdgeTable (const EdgeTable& other)
  599. {
  600. auto clipped = other.bounds.getIntersection (bounds);
  601. if (clipped.isEmpty())
  602. {
  603. needToCheckEmptiness = false;
  604. bounds.setHeight (0);
  605. }
  606. else
  607. {
  608. auto top = clipped.getY() - bounds.getY();
  609. auto bottom = clipped.getBottom() - bounds.getY();
  610. if (bottom < bounds.getHeight())
  611. bounds.setHeight (bottom);
  612. if (clipped.getRight() < bounds.getRight())
  613. bounds.setRight (clipped.getRight());
  614. for (int i = 0; i < top; ++i)
  615. table[lineStrideElements * i] = 0;
  616. auto* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY());
  617. for (int i = top; i < bottom; ++i)
  618. {
  619. intersectWithEdgeTableLine (i, otherLine);
  620. otherLine += other.lineStrideElements;
  621. }
  622. needToCheckEmptiness = true;
  623. }
  624. }
  625. void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels)
  626. {
  627. y -= bounds.getY();
  628. if (y < 0 || y >= bounds.getHeight())
  629. return;
  630. needToCheckEmptiness = true;
  631. if (numPixels <= 0)
  632. {
  633. table[lineStrideElements * y] = 0;
  634. return;
  635. }
  636. auto* tempLine = static_cast<int*> (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int)));
  637. int destIndex = 0, lastLevel = 0;
  638. while (--numPixels >= 0)
  639. {
  640. auto alpha = *mask;
  641. mask += maskStride;
  642. if (alpha != lastLevel)
  643. {
  644. tempLine[++destIndex] = (x << 8);
  645. tempLine[++destIndex] = alpha;
  646. lastLevel = alpha;
  647. }
  648. ++x;
  649. }
  650. if (lastLevel > 0)
  651. {
  652. tempLine[++destIndex] = (x << 8);
  653. tempLine[++destIndex] = 0;
  654. }
  655. tempLine[0] = destIndex >> 1;
  656. intersectWithEdgeTableLine (y, tempLine);
  657. }
  658. bool EdgeTable::isEmpty() noexcept
  659. {
  660. if (needToCheckEmptiness)
  661. {
  662. needToCheckEmptiness = false;
  663. int* t = table;
  664. for (int i = bounds.getHeight(); --i >= 0;)
  665. {
  666. if (t[0] > 1)
  667. return false;
  668. t += lineStrideElements;
  669. }
  670. bounds.setHeight (0);
  671. }
  672. return bounds.getHeight() == 0;
  673. }
  674. JUCE_END_IGNORE_WARNINGS_MSVC
  675. } // namespace juce