openshot-audio  0.1.6
juce_RenderingHelpers.h
Go to the documentation of this file.
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2015 - ROLI Ltd.
6 
7  Permission is granted to use this software under the terms of either:
8  a) the GPL v2 (or any later version)
9  b) the Affero GPL v3
10 
11  Details of these licenses can be found at: www.gnu.org/licenses
12 
13  JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15  A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 
17  ------------------------------------------------------------------------------
18 
19  To release a closed-source product which uses JUCE, commercial licenses are
20  available: visit www.juce.com for more information.
21 
22  ==============================================================================
23 */
24 
25 #ifndef JUCE_RENDERINGHELPERS_H_INCLUDED
26 #define JUCE_RENDERINGHELPERS_H_INCLUDED
27 
28 #if JUCE_MSVC
29  #pragma warning (push)
30  #pragma warning (disable: 4127) // "expression is constant" warning
31 #endif
32 
34 {
35 
36 //==============================================================================
40 {
41 public:
43  : offset (origin), isOnlyTranslated (true), isRotated (false)
44  {
45  }
46 
48  : complexTransform (other.complexTransform), offset (other.offset),
49  isOnlyTranslated (other.isOnlyTranslated), isRotated (other.isRotated)
50  {
51  }
52 
54  {
57  }
58 
60  {
61  return isOnlyTranslated ? userTransform.translated (offset)
62  : userTransform.followedBy (complexTransform);
63  }
64 
66  {
67  if (isOnlyTranslated)
68  offset += delta;
69  else
72  }
73 
75  {
76  if (isOnlyTranslated && t.isOnlyTranslation())
77  {
78  const int tx = (int) (t.getTranslationX() * 256.0f);
79  const int ty = (int) (t.getTranslationY() * 256.0f);
80 
81  if (((tx | ty) & 0xf8) == 0)
82  {
83  offset += Point<int> (tx >> 8, ty >> 8);
84  return;
85  }
86  }
87 
89  isOnlyTranslated = false;
92  }
93 
95  {
96  return isOnlyTranslated ? 1.0f : std::abs (complexTransform.getScaleFactor());
97  }
98 
100  {
101  if (isOnlyTranslated)
102  offset += delta;
103  else
105  }
106 
108  {
110  return r + offset;
111  }
112 
114  {
116  return r + offset.toFloat();
117  }
118 
119  template <typename RectangleOrPoint>
120  RectangleOrPoint transformed (const RectangleOrPoint& r) const noexcept
121  {
123  return r.transformedBy (complexTransform);
124  }
125 
126  template <typename Type>
128  {
129  return isOnlyTranslated ? r - offset
131  }
132 
136 };
137 
138 //==============================================================================
140 template <class CachedGlyphType, class RenderTargetType>
142 {
143 public:
145  {
146  reset();
147  }
148 
150  {
151  getSingletonPointer() = nullptr;
152  }
153 
155  {
156  GlyphCache*& g = getSingletonPointer();
157 
158  if (g == nullptr)
159  g = new GlyphCache();
160 
161  return *g;
162  }
163 
164  //==============================================================================
165  void reset()
166  {
167  const ScopedLock sl (lock);
168  glyphs.clear();
169  addNewGlyphSlots (120);
170  hits.set (0);
171  misses.set (0);
172  }
173 
174  void drawGlyph (RenderTargetType& target, const Font& font, const int glyphNumber, Point<float> pos)
175  {
176  if (ReferenceCountedObjectPtr<CachedGlyphType> glyph = findOrCreateGlyph (font, glyphNumber))
177  {
178  glyph->lastAccessCount = ++accessCounter;
179  glyph->draw (target, pos);
180  }
181  }
182 
184  {
185  const ScopedLock sl (lock);
186 
187  if (CachedGlyphType* g = findExistingGlyph (font, glyphNumber))
188  {
189  ++hits;
190  return g;
191  }
192 
193  ++misses;
194  CachedGlyphType* g = getGlyphForReuse();
195  jassert (g != nullptr);
196  g->generate (font, glyphNumber);
197  return g;
198  }
199 
200 private:
201  friend struct ContainerDeletePolicy<CachedGlyphType>;
203  Atomic<int> accessCounter, hits, misses;
204  CriticalSection lock;
205 
206  CachedGlyphType* findExistingGlyph (const Font& font, int glyphNumber) const
207  {
208  for (int i = 0; i < glyphs.size(); ++i)
209  {
210  CachedGlyphType* const g = glyphs.getUnchecked (i);
211 
212  if (g->glyph == glyphNumber && g->font == font)
213  return g;
214  }
215 
216  return nullptr;
217  }
218 
219  CachedGlyphType* getGlyphForReuse()
220  {
221  if (hits.value + misses.value > glyphs.size() * 16)
222  {
223  if (misses.value * 2 > hits.value)
224  addNewGlyphSlots (32);
225 
226  hits.set (0);
227  misses.set (0);
228  }
229 
230  if (CachedGlyphType* g = findLeastRecentlyUsedGlyph())
231  return g;
232 
233  addNewGlyphSlots (32);
234  return glyphs.getLast();
235  }
236 
237  void addNewGlyphSlots (int num)
238  {
239  glyphs.ensureStorageAllocated (glyphs.size() + num);
240 
241  while (--num >= 0)
242  glyphs.add (new CachedGlyphType());
243  }
244 
245  CachedGlyphType* findLeastRecentlyUsedGlyph() const noexcept
246  {
247  CachedGlyphType* oldest = nullptr;
248  int oldestCounter = std::numeric_limits<int>::max();
249 
250  for (int i = glyphs.size() - 1; --i >= 0;)
251  {
252  CachedGlyphType* const glyph = glyphs.getUnchecked(i);
253 
254  if (glyph->lastAccessCount <= oldestCounter
255  && glyph->getReferenceCount() == 1)
256  {
257  oldestCounter = glyph->lastAccessCount;
258  oldest = glyph;
259  }
260  }
261 
262  return oldest;
263  }
264 
265  static GlyphCache*& getSingletonPointer() noexcept
266  {
267  static GlyphCache* g = nullptr;
268  return g;
269  }
270 
272 };
273 
274 //==============================================================================
276 template <class RendererType>
278 {
279 public:
280  CachedGlyphEdgeTable() : glyph (0), lastAccessCount (0) {}
281 
282  void draw (RendererType& state, Point<float> pos) const
283  {
284  if (snapToIntegerCoordinate)
285  pos.x = std::floor (pos.x + 0.5f);
286 
287  if (edgeTable != nullptr)
288  state.fillEdgeTable (*edgeTable, pos.x, roundToInt (pos.y));
289  }
290 
291  void generate (const Font& newFont, const int glyphNumber)
292  {
293  font = newFont;
294  Typeface* const typeface = newFont.getTypeface();
295  snapToIntegerCoordinate = typeface->isHinted();
296  glyph = glyphNumber;
297 
298  const float fontHeight = font.getHeight();
299  edgeTable = typeface->getEdgeTableForGlyph (glyphNumber,
300  AffineTransform::scale (fontHeight * font.getHorizontalScale(),
301  fontHeight), fontHeight);
302  }
303 
306  int glyph, lastAccessCount;
308 
310 };
311 
312 //==============================================================================
317 {
319  : left (roundToInt (256.0f * area.getX())),
320  top (roundToInt (256.0f * area.getY())),
321  right (roundToInt (256.0f * area.getRight())),
322  bottom (roundToInt (256.0f * area.getBottom()))
323  {
324  if ((top >> 8) == (bottom >> 8))
325  {
326  topAlpha = bottom - top;
327  bottomAlpha = 0;
328  totalTop = top >> 8;
329  totalBottom = bottom = top = totalTop + 1;
330  }
331  else
332  {
333  if ((top & 255) == 0)
334  {
335  topAlpha = 0;
336  top = totalTop = (top >> 8);
337  }
338  else
339  {
340  topAlpha = 255 - (top & 255);
341  totalTop = (top >> 8);
342  top = totalTop + 1;
343  }
344 
345  bottomAlpha = bottom & 255;
346  bottom >>= 8;
347  totalBottom = bottom + (bottomAlpha != 0 ? 1 : 0);
348  }
349 
350  if ((left >> 8) == (right >> 8))
351  {
352  leftAlpha = right - left;
353  rightAlpha = 0;
354  totalLeft = (left >> 8);
355  totalRight = right = left = totalLeft + 1;
356  }
357  else
358  {
359  if ((left & 255) == 0)
360  {
361  leftAlpha = 0;
362  left = totalLeft = (left >> 8);
363  }
364  else
365  {
366  leftAlpha = 255 - (left & 255);
367  totalLeft = (left >> 8);
368  left = totalLeft + 1;
369  }
370 
371  rightAlpha = right & 255;
372  right >>= 8;
373  totalRight = right + (rightAlpha != 0 ? 1 : 0);
374  }
375  }
376 
377  template <class Callback>
378  void iterate (Callback& callback) const
379  {
380  if (topAlpha != 0) callback (totalLeft, totalTop, totalRight - totalLeft, 1, topAlpha);
381  if (bottomAlpha != 0) callback (totalLeft, bottom, totalRight - totalLeft, 1, bottomAlpha);
382  if (leftAlpha != 0) callback (totalLeft, totalTop, 1, totalBottom - totalTop, leftAlpha);
383  if (rightAlpha != 0) callback (right, totalTop, 1, totalBottom - totalTop, rightAlpha);
384 
385  callback (left, top, right - left, bottom - top, 255);
386  }
387 
388  inline bool isOnePixelWide() const noexcept { return right - left == 1 && leftAlpha + rightAlpha == 0; }
389 
390  inline int getTopLeftCornerAlpha() const noexcept { return (topAlpha * leftAlpha) >> 8; }
391  inline int getTopRightCornerAlpha() const noexcept { return (topAlpha * rightAlpha) >> 8; }
392  inline int getBottomLeftCornerAlpha() const noexcept { return (bottomAlpha * leftAlpha) >> 8; }
393  inline int getBottomRightCornerAlpha() const noexcept { return (bottomAlpha * rightAlpha) >> 8; }
394 
395  //==============================================================================
396  int left, top, right, bottom; // bounds of the solid central area, excluding anti-aliased edges
397  int totalTop, totalLeft, totalBottom, totalRight; // bounds of the total area, including edges
398  int topAlpha, leftAlpha, bottomAlpha, rightAlpha; // alpha of each anti-aliased edge
399 };
400 
401 //==============================================================================
403 namespace GradientPixelIterators
404 {
406  class Linear
407  {
408  public:
409  Linear (const ColourGradient& gradient, const AffineTransform& transform,
410  const PixelARGB* const colours, const int numColours)
411  : lookupTable (colours),
412  numEntries (numColours)
413  {
414  jassert (numColours >= 0);
415  Point<float> p1 (gradient.point1);
416  Point<float> p2 (gradient.point2);
417 
418  if (! transform.isIdentity())
419  {
420  const Line<float> l (p2, p1);
421  Point<float> p3 = l.getPointAlongLine (0.0f, 100.0f);
422 
423  p1.applyTransform (transform);
424  p2.applyTransform (transform);
425  p3.applyTransform (transform);
426 
427  p2 = Line<float> (p2, p3).findNearestPointTo (p1);
428  }
429 
430  vertical = std::abs (p1.x - p2.x) < 0.001f;
431  horizontal = std::abs (p1.y - p2.y) < 0.001f;
432 
433  if (vertical)
434  {
435  scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.y - p1.y));
436  start = roundToInt (p1.y * (float) scale);
437  }
438  else if (horizontal)
439  {
440  scale = roundToInt ((numEntries << (int) numScaleBits) / (double) (p2.x - p1.x));
441  start = roundToInt (p1.x * (float) scale);
442  }
443  else
444  {
445  grad = (p2.getY() - p1.y) / (double) (p1.x - p2.x);
446  yTerm = p1.getY() - p1.x / grad;
447  scale = roundToInt ((numEntries << (int) numScaleBits) / (yTerm * grad - (p2.y * grad - p2.x)));
448  grad *= scale;
449  }
450  }
451 
452  forcedinline void setY (const int y) noexcept
453  {
454  if (vertical)
455  linePix = lookupTable [jlimit (0, numEntries, (y * scale - start) >> (int) numScaleBits)];
456  else if (! horizontal)
457  start = roundToInt ((y - yTerm) * grad);
458  }
459 
460  inline PixelARGB getPixel (const int x) const noexcept
461  {
462  return vertical ? linePix
463  : lookupTable [jlimit (0, numEntries, (x * scale - start) >> (int) numScaleBits)];
464  }
465 
466  private:
467  const PixelARGB* const lookupTable;
468  const int numEntries;
469  PixelARGB linePix;
470  int start, scale;
471  double grad, yTerm;
472  bool vertical, horizontal;
473  enum { numScaleBits = 12 };
474 
476  };
477 
478  //==============================================================================
480  class Radial
481  {
482  public:
483  Radial (const ColourGradient& gradient, const AffineTransform&,
484  const PixelARGB* const colours, const int numColours)
485  : lookupTable (colours),
486  numEntries (numColours),
487  gx1 (gradient.point1.x),
488  gy1 (gradient.point1.y)
489  {
490  jassert (numColours >= 0);
491  const Point<float> diff (gradient.point1 - gradient.point2);
492  maxDist = diff.x * diff.x + diff.y * diff.y;
493  invScale = numEntries / std::sqrt (maxDist);
494  jassert (roundToInt (std::sqrt (maxDist) * invScale) <= numEntries);
495  }
496 
497  forcedinline void setY (const int y) noexcept
498  {
499  dy = y - gy1;
500  dy *= dy;
501  }
502 
503  inline PixelARGB getPixel (const int px) const noexcept
504  {
505  double x = px - gx1;
506  x *= x;
507  x += dy;
508 
509  return lookupTable [x >= maxDist ? numEntries : roundToInt (std::sqrt (x) * invScale)];
510  }
511 
512  protected:
513  const PixelARGB* const lookupTable;
514  const int numEntries;
515  const double gx1, gy1;
516  double maxDist, invScale, dy;
517 
519  };
520 
521  //==============================================================================
523  class TransformedRadial : public Radial
524  {
525  public:
526  TransformedRadial (const ColourGradient& gradient, const AffineTransform& transform,
527  const PixelARGB* const colours, const int numColours)
528  : Radial (gradient, transform, colours, numColours),
529  inverseTransform (transform.inverted())
530  {
531  tM10 = inverseTransform.mat10;
532  tM00 = inverseTransform.mat00;
533  }
534 
535  forcedinline void setY (const int y) noexcept
536  {
537  const float floatY = (float) y;
538  lineYM01 = inverseTransform.mat01 * floatY + inverseTransform.mat02 - gx1;
539  lineYM11 = inverseTransform.mat11 * floatY + inverseTransform.mat12 - gy1;
540  }
541 
542  inline PixelARGB getPixel (const int px) const noexcept
543  {
544  double x = px;
545  const double y = tM10 * x + lineYM11;
546  x = tM00 * x + lineYM01;
547  x *= x;
548  x += y * y;
549 
550  if (x >= maxDist)
551  return lookupTable [numEntries];
552 
553  return lookupTable [jmin (numEntries, roundToInt (std::sqrt (x) * invScale))];
554  }
555 
556  private:
557  double tM10, tM00, lineYM01, lineYM11;
558  const AffineTransform inverseTransform;
559 
561  };
562 }
563 
564 #define JUCE_PERFORM_PIXEL_OP_LOOP(op) \
565 { \
566  const int destStride = destData.pixelStride; \
567  do { dest->op; dest = addBytesToPointer (dest, destStride); } while (--width > 0); \
568 }
569 
570 //==============================================================================
572 namespace EdgeTableFillers
573 {
575  template <class PixelType, bool replaceExisting = false>
577  {
578  public:
579  SolidColour (const Image::BitmapData& image, const PixelARGB colour)
580  : destData (image), sourceColour (colour)
581  {
582  if (sizeof (PixelType) == 3 && destData.pixelStride == sizeof (PixelType))
583  {
584  areRGBComponentsEqual = sourceColour.getRed() == sourceColour.getGreen()
585  && sourceColour.getGreen() == sourceColour.getBlue();
586  filler[0].set (sourceColour);
587  filler[1].set (sourceColour);
588  filler[2].set (sourceColour);
589  filler[3].set (sourceColour);
590  }
591  else
592  {
593  areRGBComponentsEqual = false;
594  }
595  }
596 
598  {
599  linePixels = (PixelType*) destData.getLinePointer (y);
600  }
601 
602  forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
603  {
604  if (replaceExisting)
605  getPixel (x)->set (sourceColour);
606  else
607  getPixel (x)->blend (sourceColour, (uint32) alphaLevel);
608  }
609 
611  {
612  if (replaceExisting)
613  getPixel (x)->set (sourceColour);
614  else
615  getPixel (x)->blend (sourceColour);
616  }
617 
618  forcedinline void handleEdgeTableLine (const int x, const int width, const int alphaLevel) const noexcept
619  {
620  PixelARGB p (sourceColour);
621  p.multiplyAlpha (alphaLevel);
622 
623  PixelType* dest = getPixel (x);
624 
625  if (replaceExisting || p.getAlpha() >= 0xff)
626  replaceLine (dest, p, width);
627  else
628  blendLine (dest, p, width);
629  }
630 
631  forcedinline void handleEdgeTableLineFull (const int x, const int width) const noexcept
632  {
633  PixelType* dest = getPixel (x);
634 
635  if (replaceExisting || sourceColour.getAlpha() >= 0xff)
636  replaceLine (dest, sourceColour, width);
637  else
638  blendLine (dest, sourceColour, width);
639  }
640 
641  private:
642  const Image::BitmapData& destData;
643  PixelType* linePixels;
644  PixelARGB sourceColour;
645  PixelRGB filler [4];
646  bool areRGBComponentsEqual;
647 
648  forcedinline PixelType* getPixel (const int x) const noexcept
649  {
650  return addBytesToPointer (linePixels, x * destData.pixelStride);
651  }
652 
653  inline void blendLine (PixelType* dest, const PixelARGB colour, int width) const noexcept
654  {
655  JUCE_PERFORM_PIXEL_OP_LOOP (blend (colour))
656  }
657 
658  forcedinline void replaceLine (PixelRGB* dest, const PixelARGB colour, int width) const noexcept
659  {
660  if (destData.pixelStride == sizeof (*dest))
661  {
662  if (areRGBComponentsEqual) // if all the component values are the same, we can cheat..
663  {
664  memset (dest, colour.getRed(), (size_t) width * 3);
665  }
666  else
667  {
668  if (width >> 5)
669  {
670  const int* const intFiller = reinterpret_cast<const int*> (filler);
671 
672  while (width > 8 && (((pointer_sized_int) dest) & 7) != 0)
673  {
674  dest->set (colour);
675  ++dest;
676  --width;
677  }
678 
679  while (width > 4)
680  {
681  int* d = reinterpret_cast<int*> (dest);
682  *d++ = intFiller[0];
683  *d++ = intFiller[1];
684  *d++ = intFiller[2];
685  dest = reinterpret_cast<PixelRGB*> (d);
686  width -= 4;
687  }
688  }
689 
690  while (--width >= 0)
691  {
692  dest->set (colour);
693  ++dest;
694  }
695  }
696  }
697  else
698  {
699  JUCE_PERFORM_PIXEL_OP_LOOP (set (colour))
700  }
701  }
702 
703  forcedinline void replaceLine (PixelAlpha* dest, const PixelARGB colour, int width) const noexcept
704  {
705  if (destData.pixelStride == sizeof (*dest))
706  memset (dest, colour.getAlpha(), (size_t) width);
707  else
708  JUCE_PERFORM_PIXEL_OP_LOOP (setAlpha (colour.getAlpha()))
709  }
710 
711  forcedinline void replaceLine (PixelARGB* dest, const PixelARGB colour, int width) const noexcept
712  {
713  JUCE_PERFORM_PIXEL_OP_LOOP (set (colour))
714  }
715 
717  };
718 
719  //==============================================================================
721  template <class PixelType, class GradientType>
722  class Gradient : public GradientType
723  {
724  public:
725  Gradient (const Image::BitmapData& dest, const ColourGradient& gradient, const AffineTransform& transform,
726  const PixelARGB* const colours, const int numColours)
727  : GradientType (gradient, transform, colours, numColours - 1),
728  destData (dest)
729  {
730  }
731 
733  {
734  linePixels = (PixelType*) destData.getLinePointer (y);
735  GradientType::setY (y);
736  }
737 
738  forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const noexcept
739  {
740  getPixel (x)->blend (GradientType::getPixel (x), (uint32) alphaLevel);
741  }
742 
744  {
745  getPixel (x)->blend (GradientType::getPixel (x));
746  }
747 
748  void handleEdgeTableLine (int x, int width, const int alphaLevel) const noexcept
749  {
750  PixelType* dest = getPixel (x);
751 
752  if (alphaLevel < 0xff)
753  JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++), (uint32) alphaLevel))
754  else
755  JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++)))
756  }
757 
758  void handleEdgeTableLineFull (int x, int width) const noexcept
759  {
760  PixelType* dest = getPixel (x);
761  JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++)))
762  }
763 
764  private:
765  const Image::BitmapData& destData;
766  PixelType* linePixels;
767 
768  forcedinline PixelType* getPixel (const int x) const noexcept
769  {
770  return addBytesToPointer (linePixels, x * destData.pixelStride);
771  }
772 
774  };
775 
776  //==============================================================================
778  template <class DestPixelType, class SrcPixelType, bool repeatPattern>
779  class ImageFill
780  {
781  public:
783  const int alpha, const int x, const int y)
784  : destData (dest),
785  srcData (src),
786  extraAlpha (alpha + 1),
787  xOffset (repeatPattern ? negativeAwareModulo (x, src.width) - src.width : x),
788  yOffset (repeatPattern ? negativeAwareModulo (y, src.height) - src.height : y)
789  {
790  }
791 
793  {
794  linePixels = (DestPixelType*) destData.getLinePointer (y);
795 
796  y -= yOffset;
797  if (repeatPattern)
798  {
799  jassert (y >= 0);
800  y %= srcData.height;
801  }
802 
803  sourceLineStart = (SrcPixelType*) srcData.getLinePointer (y);
804  }
805 
806  forcedinline void handleEdgeTablePixel (const int x, int alphaLevel) const noexcept
807  {
808  alphaLevel = (alphaLevel * extraAlpha) >> 8;
809 
810  getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (uint32) alphaLevel);
811  }
812 
814  {
815  getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (uint32) extraAlpha);
816  }
817 
818  void handleEdgeTableLine (int x, int width, int alphaLevel) const noexcept
819  {
820  DestPixelType* dest = getDestPixel (x);
821  alphaLevel = (alphaLevel * extraAlpha) >> 8;
822  x -= xOffset;
823 
824  if (repeatPattern)
825  {
826  if (alphaLevel < 0xfe)
827  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) alphaLevel))
828  else
829  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width)))
830  }
831  else
832  {
833  jassert (x >= 0 && x + width <= srcData.width);
834 
835  if (alphaLevel < 0xfe)
836  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) alphaLevel))
837  else
838  copyRow (dest, getSrcPixel (x), width);
839  }
840  }
841 
842  void handleEdgeTableLineFull (int x, int width) const noexcept
843  {
844  DestPixelType* dest = getDestPixel (x);
845  x -= xOffset;
846 
847  if (repeatPattern)
848  {
849  if (extraAlpha < 0xfe)
850  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (uint32) extraAlpha))
851  else
852  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width)))
853  }
854  else
855  {
856  jassert (x >= 0 && x + width <= srcData.width);
857 
858  if (extraAlpha < 0xfe)
859  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (uint32) extraAlpha))
860  else
861  copyRow (dest, getSrcPixel (x), width);
862  }
863  }
864 
865  void clipEdgeTableLine (EdgeTable& et, int x, int y, int width)
866  {
867  jassert (x - xOffset >= 0 && x + width - xOffset <= srcData.width);
868  SrcPixelType* s = (SrcPixelType*) srcData.getLinePointer (y - yOffset);
869  uint8* mask = (uint8*) (s + x - xOffset);
870 
871  if (sizeof (SrcPixelType) == sizeof (PixelARGB))
872  mask += PixelARGB::indexA;
873 
874  et.clipLineToMask (x, y, mask, sizeof (SrcPixelType), width);
875  }
876 
877  private:
878  const Image::BitmapData& destData;
879  const Image::BitmapData& srcData;
880  const int extraAlpha, xOffset, yOffset;
881  DestPixelType* linePixels;
882  SrcPixelType* sourceLineStart;
883 
884  forcedinline DestPixelType* getDestPixel (int const x) const noexcept
885  {
886  return addBytesToPointer (linePixels, x * destData.pixelStride);
887  }
888 
889  forcedinline SrcPixelType const* getSrcPixel (int const x) const noexcept
890  {
891  return addBytesToPointer (sourceLineStart, x * srcData.pixelStride);
892  }
893 
894  forcedinline void copyRow (DestPixelType* dest, SrcPixelType const* src, int width) const noexcept
895  {
896  const int destStride = destData.pixelStride;
897  const int srcStride = srcData.pixelStride;
898 
899  if (destStride == srcStride
900  && srcData.pixelFormat == Image::RGB
901  && destData.pixelFormat == Image::RGB)
902  {
903  memcpy (dest, src, (size_t) (width * srcStride));
904  }
905  else
906  {
907  do
908  {
909  dest->blend (*src);
910  dest = addBytesToPointer (dest, destStride);
911  src = addBytesToPointer (src, srcStride);
912  } while (--width > 0);
913  }
914  }
915 
917  };
918 
919  //==============================================================================
921  template <class DestPixelType, class SrcPixelType, bool repeatPattern>
923  {
924  public:
926  const AffineTransform& transform, const int alpha, const Graphics::ResamplingQuality q)
927  : interpolator (transform,
928  q != Graphics::lowResamplingQuality ? 0.5f : 0.0f,
929  q != Graphics::lowResamplingQuality ? -128 : 0),
930  destData (dest),
931  srcData (src),
932  extraAlpha (alpha + 1),
933  quality (q),
934  maxX (src.width - 1),
935  maxY (src.height - 1),
936  scratchSize (2048)
937  {
938  scratchBuffer.malloc (scratchSize);
939  }
940 
941  forcedinline void setEdgeTableYPos (const int newY) noexcept
942  {
943  y = newY;
944  linePixels = (DestPixelType*) destData.getLinePointer (newY);
945  }
946 
947  forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept
948  {
949  SrcPixelType p;
950  generate (&p, x, 1);
951 
952  getDestPixel (x)->blend (p, (uint32) (alphaLevel * extraAlpha) >> 8);
953  }
954 
956  {
957  SrcPixelType p;
958  generate (&p, x, 1);
959 
960  getDestPixel (x)->blend (p, (uint32) extraAlpha);
961  }
962 
963  void handleEdgeTableLine (const int x, int width, int alphaLevel) noexcept
964  {
965  if (width > (int) scratchSize)
966  {
967  scratchSize = (size_t) width;
968  scratchBuffer.malloc (scratchSize);
969  }
970 
971  SrcPixelType* span = scratchBuffer;
972  generate (span, x, width);
973 
974  DestPixelType* dest = getDestPixel (x);
975  alphaLevel *= extraAlpha;
976  alphaLevel >>= 8;
977 
978  if (alphaLevel < 0xfe)
979  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++, (uint32) alphaLevel))
980  else
981  JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++))
982  }
983 
985  {
986  handleEdgeTableLine (x, width, 255);
987  }
988 
989  void clipEdgeTableLine (EdgeTable& et, int x, int y_, int width)
990  {
991  if (width > (int) scratchSize)
992  {
993  scratchSize = (size_t) width;
994  scratchBuffer.malloc (scratchSize);
995  }
996 
997  y = y_;
998  generate (scratchBuffer.getData(), x, width);
999 
1000  et.clipLineToMask (x, y_,
1001  reinterpret_cast<uint8*> (scratchBuffer.getData()) + SrcPixelType::indexA,
1002  sizeof (SrcPixelType), width);
1003  }
1004 
1005  private:
1006  forcedinline DestPixelType* getDestPixel (const int x) const noexcept
1007  {
1008  return addBytesToPointer (linePixels, x * destData.pixelStride);
1009  }
1010 
1011  //==============================================================================
1012  template <class PixelType>
1013  void generate (PixelType* dest, const int x, int numPixels) noexcept
1014  {
1015  this->interpolator.setStartOfLine ((float) x, (float) y, numPixels);
1016 
1017  do
1018  {
1019  int hiResX, hiResY;
1020  this->interpolator.next (hiResX, hiResY);
1021 
1022  int loResX = hiResX >> 8;
1023  int loResY = hiResY >> 8;
1024 
1025  if (repeatPattern)
1026  {
1027  loResX = negativeAwareModulo (loResX, srcData.width);
1028  loResY = negativeAwareModulo (loResY, srcData.height);
1029  }
1030 
1032  {
1033  if (isPositiveAndBelow (loResX, maxX))
1034  {
1035  if (isPositiveAndBelow (loResY, maxY))
1036  {
1037  // In the centre of the image..
1038  render4PixelAverage (dest, this->srcData.getPixelPointer (loResX, loResY),
1039  hiResX & 255, hiResY & 255);
1040  ++dest;
1041  continue;
1042  }
1043 
1044  if (! repeatPattern)
1045  {
1046  // At a top or bottom edge..
1047  if (loResY < 0)
1048  render2PixelAverageX (dest, this->srcData.getPixelPointer (loResX, 0), hiResX & 255);
1049  else
1050  render2PixelAverageX (dest, this->srcData.getPixelPointer (loResX, maxY), hiResX & 255);
1051 
1052  ++dest;
1053  continue;
1054  }
1055  }
1056  else
1057  {
1058  if (isPositiveAndBelow (loResY, maxY) && ! repeatPattern)
1059  {
1060  // At a left or right hand edge..
1061  if (loResX < 0)
1062  render2PixelAverageY (dest, this->srcData.getPixelPointer (0, loResY), hiResY & 255);
1063  else
1064  render2PixelAverageY (dest, this->srcData.getPixelPointer (maxX, loResY), hiResY & 255);
1065 
1066  ++dest;
1067  continue;
1068  }
1069  }
1070  }
1071 
1072  if (! repeatPattern)
1073  {
1074  if (loResX < 0) loResX = 0;
1075  if (loResY < 0) loResY = 0;
1076  if (loResX > maxX) loResX = maxX;
1077  if (loResY > maxY) loResY = maxY;
1078  }
1079 
1080  dest->set (*(const PixelType*) this->srcData.getPixelPointer (loResX, loResY));
1081  ++dest;
1082 
1083  } while (--numPixels > 0);
1084  }
1085 
1086  //==============================================================================
1087  void render4PixelAverage (PixelARGB* const dest, const uint8* src, const int subPixelX, const int subPixelY) noexcept
1088  {
1089  uint32 c[4] = { 256 * 128, 256 * 128, 256 * 128, 256 * 128 };
1090 
1091  uint32 weight = (uint32) ((256 - subPixelX) * (256 - subPixelY));
1092  c[0] += weight * src[0];
1093  c[1] += weight * src[1];
1094  c[2] += weight * src[2];
1095  c[3] += weight * src[3];
1096 
1097  src += this->srcData.pixelStride;
1098 
1099  weight = (uint32) (subPixelX * (256 - subPixelY));
1100  c[0] += weight * src[0];
1101  c[1] += weight * src[1];
1102  c[2] += weight * src[2];
1103  c[3] += weight * src[3];
1104 
1105  src += this->srcData.lineStride;
1106 
1107  weight = (uint32) (subPixelX * subPixelY);
1108  c[0] += weight * src[0];
1109  c[1] += weight * src[1];
1110  c[2] += weight * src[2];
1111  c[3] += weight * src[3];
1112 
1113  src -= this->srcData.pixelStride;
1114 
1115  weight = (uint32) ((256 - subPixelX) * subPixelY);
1116  c[0] += weight * src[0];
1117  c[1] += weight * src[1];
1118  c[2] += weight * src[2];
1119  c[3] += weight * src[3];
1120 
1121  dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 16),
1122  (uint8) (c[PixelARGB::indexR] >> 16),
1123  (uint8) (c[PixelARGB::indexG] >> 16),
1124  (uint8) (c[PixelARGB::indexB] >> 16));
1125  }
1126 
1127  void render2PixelAverageX (PixelARGB* const dest, const uint8* src, const uint32 subPixelX) noexcept
1128  {
1129  uint32 c[4] = { 128, 128, 128, 128 };
1130 
1131  uint32 weight = 256 - subPixelX;
1132  c[0] += weight * src[0];
1133  c[1] += weight * src[1];
1134  c[2] += weight * src[2];
1135  c[3] += weight * src[3];
1136 
1137  src += this->srcData.pixelStride;
1138 
1139  weight = subPixelX;
1140  c[0] += weight * src[0];
1141  c[1] += weight * src[1];
1142  c[2] += weight * src[2];
1143  c[3] += weight * src[3];
1144 
1145  dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 8),
1146  (uint8) (c[PixelARGB::indexR] >> 8),
1147  (uint8) (c[PixelARGB::indexG] >> 8),
1148  (uint8) (c[PixelARGB::indexB] >> 8));
1149  }
1150 
1151  void render2PixelAverageY (PixelARGB* const dest, const uint8* src, const uint32 subPixelY) noexcept
1152  {
1153  uint32 c[4] = { 128, 128, 128, 128 };
1154 
1155  uint32 weight = 256 - subPixelY;
1156  c[0] += weight * src[0];
1157  c[1] += weight * src[1];
1158  c[2] += weight * src[2];
1159  c[3] += weight * src[3];
1160 
1161  src += this->srcData.lineStride;
1162 
1163  weight = subPixelY;
1164  c[0] += weight * src[0];
1165  c[1] += weight * src[1];
1166  c[2] += weight * src[2];
1167  c[3] += weight * src[3];
1168 
1169  dest->setARGB ((uint8) (c[PixelARGB::indexA] >> 8),
1170  (uint8) (c[PixelARGB::indexR] >> 8),
1171  (uint8) (c[PixelARGB::indexG] >> 8),
1172  (uint8) (c[PixelARGB::indexB] >> 8));
1173  }
1174 
1175  //==============================================================================
1176  void render4PixelAverage (PixelRGB* const dest, const uint8* src, const uint32 subPixelX, const uint32 subPixelY) noexcept
1177  {
1178  uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 };
1179 
1180  uint32 weight = (256 - subPixelX) * (256 - subPixelY);
1181  c[0] += weight * src[0];
1182  c[1] += weight * src[1];
1183  c[2] += weight * src[2];
1184 
1185  src += this->srcData.pixelStride;
1186 
1187  weight = subPixelX * (256 - subPixelY);
1188  c[0] += weight * src[0];
1189  c[1] += weight * src[1];
1190  c[2] += weight * src[2];
1191 
1192  src += this->srcData.lineStride;
1193 
1194  weight = subPixelX * subPixelY;
1195  c[0] += weight * src[0];
1196  c[1] += weight * src[1];
1197  c[2] += weight * src[2];
1198 
1199  src -= this->srcData.pixelStride;
1200 
1201  weight = (256 - subPixelX) * subPixelY;
1202  c[0] += weight * src[0];
1203  c[1] += weight * src[1];
1204  c[2] += weight * src[2];
1205 
1206  dest->setARGB ((uint8) 255,
1207  (uint8) (c[PixelRGB::indexR] >> 16),
1208  (uint8) (c[PixelRGB::indexG] >> 16),
1209  (uint8) (c[PixelRGB::indexB] >> 16));
1210  }
1211 
1212  void render2PixelAverageX (PixelRGB* const dest, const uint8* src, const uint32 subPixelX) noexcept
1213  {
1214  uint32 c[3] = { 128, 128, 128 };
1215 
1216  const uint32 weight = 256 - subPixelX;
1217  c[0] += weight * src[0];
1218  c[1] += weight * src[1];
1219  c[2] += weight * src[2];
1220 
1221  src += this->srcData.pixelStride;
1222 
1223  c[0] += subPixelX * src[0];
1224  c[1] += subPixelX * src[1];
1225  c[2] += subPixelX * src[2];
1226 
1227  dest->setARGB ((uint8) 255,
1228  (uint8) (c[PixelRGB::indexR] >> 8),
1229  (uint8) (c[PixelRGB::indexG] >> 8),
1230  (uint8) (c[PixelRGB::indexB] >> 8));
1231  }
1232 
1233  void render2PixelAverageY (PixelRGB* const dest, const uint8* src, const uint32 subPixelY) noexcept
1234  {
1235  uint32 c[3] = { 128, 128, 128 };
1236 
1237  const uint32 weight = 256 - subPixelY;
1238  c[0] += weight * src[0];
1239  c[1] += weight * src[1];
1240  c[2] += weight * src[2];
1241 
1242  src += this->srcData.lineStride;
1243 
1244  c[0] += subPixelY * src[0];
1245  c[1] += subPixelY * src[1];
1246  c[2] += subPixelY * src[2];
1247 
1248  dest->setARGB ((uint8) 255,
1249  (uint8) (c[PixelRGB::indexR] >> 8),
1250  (uint8) (c[PixelRGB::indexG] >> 8),
1251  (uint8) (c[PixelRGB::indexB] >> 8));
1252  }
1253 
1254  //==============================================================================
1255  void render4PixelAverage (PixelAlpha* const dest, const uint8* src, const uint32 subPixelX, const uint32 subPixelY) noexcept
1256  {
1257  uint32 c = 256 * 128;
1258  c += src[0] * ((256 - subPixelX) * (256 - subPixelY));
1259  src += this->srcData.pixelStride;
1260  c += src[1] * (subPixelX * (256 - subPixelY));
1261  src += this->srcData.lineStride;
1262  c += src[1] * (subPixelX * subPixelY);
1263  src -= this->srcData.pixelStride;
1264 
1265  c += src[0] * ((256 - subPixelX) * subPixelY);
1266 
1267  *((uint8*) dest) = (uint8) (c >> 16);
1268  }
1269 
1270  void render2PixelAverageX (PixelAlpha* const dest, const uint8* src, const uint32 subPixelX) noexcept
1271  {
1272  uint32 c = 128;
1273  c += src[0] * (256 - subPixelX);
1274  src += this->srcData.pixelStride;
1275  c += src[0] * subPixelX;
1276  *((uint8*) dest) = (uint8) (c >> 8);
1277  }
1278 
1279  void render2PixelAverageY (PixelAlpha* const dest, const uint8* src, const uint32 subPixelY) noexcept
1280  {
1281  uint32 c = 128;
1282  c += src[0] * (256 - subPixelY);
1283  src += this->srcData.lineStride;
1284  c += src[0] * subPixelY;
1285  *((uint8*) dest) = (uint8) (c >> 8);
1286  }
1287 
1288  //==============================================================================
1289  class TransformedImageSpanInterpolator
1290  {
1291  public:
1292  TransformedImageSpanInterpolator (const AffineTransform& transform,
1293  const float offsetFloat, const int offsetInt) noexcept
1294  : inverseTransform (transform.inverted()),
1295  pixelOffset (offsetFloat), pixelOffsetInt (offsetInt)
1296  {}
1297 
1298  void setStartOfLine (float sx, float sy, const int numPixels) noexcept
1299  {
1300  jassert (numPixels > 0);
1301 
1302  sx += pixelOffset;
1303  sy += pixelOffset;
1304  float x1 = sx, y1 = sy;
1305  sx += (float) numPixels;
1306  inverseTransform.transformPoints (x1, y1, sx, sy);
1307 
1308  xBresenham.set ((int) (x1 * 256.0f), (int) (sx * 256.0f), numPixels, pixelOffsetInt);
1309  yBresenham.set ((int) (y1 * 256.0f), (int) (sy * 256.0f), numPixels, pixelOffsetInt);
1310  }
1311 
1312  void next (int& px, int& py) noexcept
1313  {
1314  px = xBresenham.n; xBresenham.stepToNext();
1315  py = yBresenham.n; yBresenham.stepToNext();
1316  }
1317 
1318  private:
1319  class BresenhamInterpolator
1320  {
1321  public:
1322  BresenhamInterpolator() noexcept {}
1323 
1324  void set (const int n1, const int n2, const int steps, const int offsetInt) noexcept
1325  {
1326  numSteps = steps;
1327  step = (n2 - n1) / numSteps;
1328  remainder = modulo = (n2 - n1) % numSteps;
1329  n = n1 + offsetInt;
1330 
1331  if (modulo <= 0)
1332  {
1333  modulo += numSteps;
1334  remainder += numSteps;
1335  --step;
1336  }
1337 
1338  modulo -= numSteps;
1339  }
1340 
1341  forcedinline void stepToNext() noexcept
1342  {
1343  modulo += remainder;
1344  n += step;
1345 
1346  if (modulo > 0)
1347  {
1348  modulo -= numSteps;
1349  ++n;
1350  }
1351  }
1352 
1353  int n;
1354 
1355  private:
1356  int numSteps, step, modulo, remainder;
1357  };
1358 
1359  const AffineTransform inverseTransform;
1360  BresenhamInterpolator xBresenham, yBresenham;
1361  const float pixelOffset;
1362  const int pixelOffsetInt;
1363 
1364  JUCE_DECLARE_NON_COPYABLE (TransformedImageSpanInterpolator)
1365  };
1366 
1367  //==============================================================================
1368  TransformedImageSpanInterpolator interpolator;
1369  const Image::BitmapData& destData;
1370  const Image::BitmapData& srcData;
1371  const int extraAlpha;
1373  const int maxX, maxY;
1374  int y;
1375  DestPixelType* linePixels;
1376  HeapBlock<SrcPixelType> scratchBuffer;
1377  size_t scratchSize;
1378 
1380  };
1381 
1382 
1383  //==============================================================================
1384  template <class Iterator>
1385  void renderImageTransformed (Iterator& iter, const Image::BitmapData& destData, const Image::BitmapData& srcData,
1386  const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill)
1387  {
1388  switch (destData.pixelFormat)
1389  {
1390  case Image::ARGB:
1391  switch (srcData.pixelFormat)
1392  {
1393  case Image::ARGB:
1394  if (tiledFill) { TransformedImageFill<PixelARGB, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1395  else { TransformedImageFill<PixelARGB, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1396  break;
1397  case Image::RGB:
1398  if (tiledFill) { TransformedImageFill<PixelARGB, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1399  else { TransformedImageFill<PixelARGB, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1400  break;
1401  default:
1402  if (tiledFill) { TransformedImageFill<PixelARGB, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1403  else { TransformedImageFill<PixelARGB, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1404  break;
1405  }
1406  break;
1407 
1408  case Image::RGB:
1409  switch (srcData.pixelFormat)
1410  {
1411  case Image::ARGB:
1412  if (tiledFill) { TransformedImageFill<PixelRGB, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1413  else { TransformedImageFill<PixelRGB, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1414  break;
1415  case Image::RGB:
1416  if (tiledFill) { TransformedImageFill<PixelRGB, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1417  else { TransformedImageFill<PixelRGB, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1418  break;
1419  default:
1420  if (tiledFill) { TransformedImageFill<PixelRGB, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1421  else { TransformedImageFill<PixelRGB, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1422  break;
1423  }
1424  break;
1425 
1426  default:
1427  switch (srcData.pixelFormat)
1428  {
1429  case Image::ARGB:
1430  if (tiledFill) { TransformedImageFill<PixelAlpha, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1431  else { TransformedImageFill<PixelAlpha, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1432  break;
1433  case Image::RGB:
1434  if (tiledFill) { TransformedImageFill<PixelAlpha, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1435  else { TransformedImageFill<PixelAlpha, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1436  break;
1437  default:
1438  if (tiledFill) { TransformedImageFill<PixelAlpha, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1439  else { TransformedImageFill<PixelAlpha, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1440  break;
1441  }
1442  break;
1443  }
1444  }
1445 
1446  template <class Iterator>
1447  void renderImageUntransformed (Iterator& iter, const Image::BitmapData& destData, const Image::BitmapData& srcData, const int alpha, int x, int y, bool tiledFill)
1448  {
1449  switch (destData.pixelFormat)
1450  {
1451  case Image::ARGB:
1452  switch (srcData.pixelFormat)
1453  {
1454  case Image::ARGB:
1455  if (tiledFill) { ImageFill<PixelARGB, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1456  else { ImageFill<PixelARGB, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1457  break;
1458  case Image::RGB:
1459  if (tiledFill) { ImageFill<PixelARGB, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1460  else { ImageFill<PixelARGB, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1461  break;
1462  default:
1463  if (tiledFill) { ImageFill<PixelARGB, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1464  else { ImageFill<PixelARGB, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1465  break;
1466  }
1467  break;
1468 
1469  case Image::RGB:
1470  switch (srcData.pixelFormat)
1471  {
1472  case Image::ARGB:
1473  if (tiledFill) { ImageFill<PixelRGB, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1474  else { ImageFill<PixelRGB, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1475  break;
1476  case Image::RGB:
1477  if (tiledFill) { ImageFill<PixelRGB, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1478  else { ImageFill<PixelRGB, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1479  break;
1480  default:
1481  if (tiledFill) { ImageFill<PixelRGB, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1482  else { ImageFill<PixelRGB, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1483  break;
1484  }
1485  break;
1486 
1487  default:
1488  switch (srcData.pixelFormat)
1489  {
1490  case Image::ARGB:
1491  if (tiledFill) { ImageFill<PixelAlpha, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1492  else { ImageFill<PixelAlpha, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1493  break;
1494  case Image::RGB:
1495  if (tiledFill) { ImageFill<PixelAlpha, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1496  else { ImageFill<PixelAlpha, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1497  break;
1498  default:
1499  if (tiledFill) { ImageFill<PixelAlpha, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1500  else { ImageFill<PixelAlpha, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1501  break;
1502  }
1503  break;
1504  }
1505  }
1506 
1507  template <class Iterator, class DestPixelType>
1508  void renderSolidFill (Iterator& iter, const Image::BitmapData& destData, const PixelARGB fillColour, const bool replaceContents, DestPixelType*)
1509  {
1510  if (replaceContents)
1511  {
1512  EdgeTableFillers::SolidColour<DestPixelType, true> r (destData, fillColour);
1513  iter.iterate (r);
1514  }
1515  else
1516  {
1517  EdgeTableFillers::SolidColour<DestPixelType, false> r (destData, fillColour);
1518  iter.iterate (r);
1519  }
1520  }
1521 
1522  template <class Iterator, class DestPixelType>
1523  void renderGradient (Iterator& iter, const Image::BitmapData& destData, const ColourGradient& g, const AffineTransform& transform,
1524  const PixelARGB* const lookupTable, const int numLookupEntries, const bool isIdentity, DestPixelType*)
1525  {
1526  if (g.isRadial)
1527  {
1528  if (isIdentity)
1529  {
1530  EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::Radial> renderer (destData, g, transform, lookupTable, numLookupEntries);
1531  iter.iterate (renderer);
1532  }
1533  else
1534  {
1535  EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::TransformedRadial> renderer (destData, g, transform, lookupTable, numLookupEntries);
1536  iter.iterate (renderer);
1537  }
1538  }
1539  else
1540  {
1541  EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::Linear> renderer (destData, g, transform, lookupTable, numLookupEntries);
1542  iter.iterate (renderer);
1543  }
1544  }
1545 }
1546 
1547 //==============================================================================
1548 template <class SavedStateType>
1550 {
1552  {
1553  public:
1554  Base() {}
1555  virtual ~Base() {}
1556 
1558 
1559  virtual Ptr clone() const = 0;
1560  virtual Ptr applyClipTo (const Ptr& target) const = 0;
1561 
1562  virtual Ptr clipToRectangle (const Rectangle<int>&) = 0;
1563  virtual Ptr clipToRectangleList (const RectangleList<int>&) = 0;
1564  virtual Ptr excludeClipRectangle (const Rectangle<int>&) = 0;
1565  virtual Ptr clipToPath (const Path&, const AffineTransform&) = 0;
1566  virtual Ptr clipToEdgeTable (const EdgeTable& et) = 0;
1567  virtual Ptr clipToImageAlpha (const Image&, const AffineTransform&, const Graphics::ResamplingQuality) = 0;
1568  virtual void translate (Point<int> delta) = 0;
1569 
1570  virtual bool clipRegionIntersects (const Rectangle<int>&) const = 0;
1571  virtual Rectangle<int> getClipBounds() const = 0;
1572 
1573  virtual void fillRectWithColour (SavedStateType&, const Rectangle<int>&, const PixelARGB colour, bool replaceContents) const = 0;
1574  virtual void fillRectWithColour (SavedStateType&, const Rectangle<float>&, const PixelARGB colour) const = 0;
1575  virtual void fillAllWithColour (SavedStateType&, const PixelARGB colour, bool replaceContents) const = 0;
1576  virtual void fillAllWithGradient (SavedStateType&, ColourGradient&, const AffineTransform&, bool isIdentity) const = 0;
1577  virtual void renderImageTransformed (SavedStateType&, const Image&, const int alpha, const AffineTransform&, Graphics::ResamplingQuality, bool tiledFill) const = 0;
1578  virtual void renderImageUntransformed (SavedStateType&, const Image&, const int alpha, int x, int y, bool tiledFill) const = 0;
1579  };
1580 
1581  //==============================================================================
1582  class EdgeTableRegion : public Base
1583  {
1584  public:
1585  EdgeTableRegion (const EdgeTable& e) : edgeTable (e) {}
1586  EdgeTableRegion (const Rectangle<int>& r) : edgeTable (r) {}
1587  EdgeTableRegion (const Rectangle<float>& r) : edgeTable (r) {}
1588  EdgeTableRegion (const RectangleList<int>& r) : edgeTable (r) {}
1589  EdgeTableRegion (const RectangleList<float>& r) : edgeTable (r) {}
1590  EdgeTableRegion (const Rectangle<int>& bounds, const Path& p, const AffineTransform& t) : edgeTable (bounds, p, t) {}
1591  EdgeTableRegion (const EdgeTableRegion& other) : Base(), edgeTable (other.edgeTable) {}
1592 
1593  typedef typename Base::Ptr Ptr;
1594 
1595  Ptr clone() const { return new EdgeTableRegion (*this); }
1596  Ptr applyClipTo (const Ptr& target) const { return target->clipToEdgeTable (edgeTable); }
1597 
1599  {
1600  edgeTable.clipToRectangle (r);
1601  return edgeTable.isEmpty() ? nullptr : this;
1602  }
1603 
1605  {
1606  RectangleList<int> inverse (edgeTable.getMaximumBounds());
1607 
1608  if (inverse.subtract (r))
1609  for (const Rectangle<int>* i = inverse.begin(), * const e = inverse.end(); i != e; ++i)
1610  edgeTable.excludeRectangle (*i);
1611 
1612  return edgeTable.isEmpty() ? nullptr : this;
1613  }
1614 
1616  {
1617  edgeTable.excludeRectangle (r);
1618  return edgeTable.isEmpty() ? nullptr : this;
1619  }
1620 
1621  Ptr clipToPath (const Path& p, const AffineTransform& transform)
1622  {
1623  EdgeTable et (edgeTable.getMaximumBounds(), p, transform);
1624  edgeTable.clipToEdgeTable (et);
1625  return edgeTable.isEmpty() ? nullptr : this;
1626  }
1627 
1628  Ptr clipToEdgeTable (const EdgeTable& et)
1629  {
1630  edgeTable.clipToEdgeTable (et);
1631  return edgeTable.isEmpty() ? nullptr : this;
1632  }
1633 
1634  Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const Graphics::ResamplingQuality quality)
1635  {
1636  const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
1637 
1638  if (transform.isOnlyTranslation())
1639  {
1640  // If our translation doesn't involve any distortion, just use a simple blit..
1641  const int tx = (int) (transform.getTranslationX() * 256.0f);
1642  const int ty = (int) (transform.getTranslationY() * 256.0f);
1643 
1644  if (quality == Graphics::lowResamplingQuality || ((tx | ty) & 224) == 0)
1645  {
1646  const int imageX = ((tx + 128) >> 8);
1647  const int imageY = ((ty + 128) >> 8);
1648 
1649  if (image.getFormat() == Image::ARGB)
1650  straightClipImage (srcData, imageX, imageY, (PixelARGB*) 0);
1651  else
1652  straightClipImage (srcData, imageX, imageY, (PixelAlpha*) 0);
1653 
1654  return edgeTable.isEmpty() ? nullptr : this;
1655  }
1656  }
1657 
1658  if (transform.isSingularity())
1659  return Ptr();
1660 
1661  {
1662  Path p;
1663  p.addRectangle (0, 0, (float) srcData.width, (float) srcData.height);
1664  EdgeTable et2 (edgeTable.getMaximumBounds(), p, transform);
1665  edgeTable.clipToEdgeTable (et2);
1666  }
1667 
1668  if (! edgeTable.isEmpty())
1669  {
1670  if (image.getFormat() == Image::ARGB)
1671  transformedClipImage (srcData, transform, quality, (PixelARGB*) 0);
1672  else
1673  transformedClipImage (srcData, transform, quality, (PixelAlpha*) 0);
1674  }
1675 
1676  return edgeTable.isEmpty() ? nullptr : this;
1677  }
1678 
1679  void translate (Point<int> delta)
1680  {
1681  edgeTable.translate ((float) delta.x, delta.y);
1682  }
1683 
1684  bool clipRegionIntersects (const Rectangle<int>& r) const
1685  {
1686  return edgeTable.getMaximumBounds().intersects (r);
1687  }
1688 
1690  {
1691  return edgeTable.getMaximumBounds();
1692  }
1693 
1694  void fillRectWithColour (SavedStateType& state, const Rectangle<int>& area, const PixelARGB colour, bool replaceContents) const
1695  {
1696  const Rectangle<int> totalClip (edgeTable.getMaximumBounds());
1697  const Rectangle<int> clipped (totalClip.getIntersection (area));
1698 
1699  if (! clipped.isEmpty())
1700  {
1701  EdgeTableRegion et (clipped);
1702  et.edgeTable.clipToEdgeTable (edgeTable);
1703  state.fillWithSolidColour (et.edgeTable, colour, replaceContents);
1704  }
1705  }
1706 
1707  void fillRectWithColour (SavedStateType& state, const Rectangle<float>& area, const PixelARGB colour) const
1708  {
1709  const Rectangle<float> totalClip (edgeTable.getMaximumBounds().toFloat());
1710  const Rectangle<float> clipped (totalClip.getIntersection (area));
1711 
1712  if (! clipped.isEmpty())
1713  {
1714  EdgeTableRegion et (clipped);
1715  et.edgeTable.clipToEdgeTable (edgeTable);
1716  state.fillWithSolidColour (et.edgeTable, colour, false);
1717  }
1718  }
1719 
1720  void fillAllWithColour (SavedStateType& state, const PixelARGB colour, bool replaceContents) const
1721  {
1722  state.fillWithSolidColour (edgeTable, colour, replaceContents);
1723  }
1724 
1725  void fillAllWithGradient (SavedStateType& state, ColourGradient& gradient, const AffineTransform& transform, bool isIdentity) const
1726  {
1727  state.fillWithGradient (edgeTable, gradient, transform, isIdentity);
1728  }
1729 
1730  void renderImageTransformed (SavedStateType& state, const Image& src, const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill) const
1731  {
1732  state.renderImageTransformed (edgeTable, src, alpha, transform, quality, tiledFill);
1733  }
1734 
1735  void renderImageUntransformed (SavedStateType& state, const Image& src, const int alpha, int x, int y, bool tiledFill) const
1736  {
1737  state.renderImageUntransformed (edgeTable, src, alpha, x, y, tiledFill);
1738  }
1739 
1741 
1742  private:
1743  template <class SrcPixelType>
1744  void transformedClipImage (const Image::BitmapData& srcData, const AffineTransform& transform, const Graphics::ResamplingQuality quality, const SrcPixelType*)
1745  {
1746  EdgeTableFillers::TransformedImageFill<SrcPixelType, SrcPixelType, false> renderer (srcData, srcData, transform, 255, quality);
1747 
1748  for (int y = 0; y < edgeTable.getMaximumBounds().getHeight(); ++y)
1749  renderer.clipEdgeTableLine (edgeTable, edgeTable.getMaximumBounds().getX(), y + edgeTable.getMaximumBounds().getY(),
1750  edgeTable.getMaximumBounds().getWidth());
1751  }
1752 
1753  template <class SrcPixelType>
1754  void straightClipImage (const Image::BitmapData& srcData, int imageX, int imageY, const SrcPixelType*)
1755  {
1756  Rectangle<int> r (imageX, imageY, srcData.width, srcData.height);
1757  edgeTable.clipToRectangle (r);
1758 
1759  EdgeTableFillers::ImageFill<SrcPixelType, SrcPixelType, false> renderer (srcData, srcData, 255, imageX, imageY);
1760 
1761  for (int y = 0; y < r.getHeight(); ++y)
1762  renderer.clipEdgeTableLine (edgeTable, r.getX(), y + r.getY(), r.getWidth());
1763  }
1764 
1765  EdgeTableRegion& operator= (const EdgeTableRegion&);
1766  };
1767 
1768  //==============================================================================
1769  class RectangleListRegion : public Base
1770  {
1771  public:
1772  RectangleListRegion (const Rectangle<int>& r) : clip (r) {}
1773  RectangleListRegion (const RectangleList<int>& r) : clip (r) {}
1774  RectangleListRegion (const RectangleListRegion& other) : Base(), clip (other.clip) {}
1775 
1776  typedef typename Base::Ptr Ptr;
1777 
1778  Ptr clone() const { return new RectangleListRegion (*this); }
1779  Ptr applyClipTo (const Ptr& target) const { return target->clipToRectangleList (clip); }
1780 
1782  {
1783  clip.clipTo (r);
1784  return clip.isEmpty() ? nullptr : this;
1785  }
1786 
1788  {
1789  clip.clipTo (r);
1790  return clip.isEmpty() ? nullptr : this;
1791  }
1792 
1794  {
1795  clip.subtract (r);
1796  return clip.isEmpty() ? nullptr : this;
1797  }
1798 
1799  Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toEdgeTable()->clipToPath (p, transform); }
1800  Ptr clipToEdgeTable (const EdgeTable& et) { return toEdgeTable()->clipToEdgeTable (et); }
1801 
1802  Ptr clipToImageAlpha (const Image& image, const AffineTransform& transform, const Graphics::ResamplingQuality quality)
1803  {
1804  return toEdgeTable()->clipToImageAlpha (image, transform, quality);
1805  }
1806 
1807  void translate (Point<int> delta) { clip.offsetAll (delta); }
1808  bool clipRegionIntersects (const Rectangle<int>& r) const { return clip.intersects (r); }
1809  Rectangle<int> getClipBounds() const { return clip.getBounds(); }
1810 
1811  void fillRectWithColour (SavedStateType& state, const Rectangle<int>& area, const PixelARGB colour, bool replaceContents) const
1812  {
1813  SubRectangleIterator iter (clip, area);
1814  state.fillWithSolidColour (iter, colour, replaceContents);
1815  }
1816 
1817  void fillRectWithColour (SavedStateType& state, const Rectangle<float>& area, const PixelARGB colour) const
1818  {
1819  SubRectangleIteratorFloat iter (clip, area);
1820  state.fillWithSolidColour (iter, colour, false);
1821  }
1822 
1823  void fillAllWithColour (SavedStateType& state, const PixelARGB colour, bool replaceContents) const
1824  {
1825  state.fillWithSolidColour (*this, colour, replaceContents);
1826  }
1827 
1828  void fillAllWithGradient (SavedStateType& state, ColourGradient& gradient, const AffineTransform& transform, bool isIdentity) const
1829  {
1830  state.fillWithGradient (*this, gradient, transform, isIdentity);
1831  }
1832 
1833  void renderImageTransformed (SavedStateType& state, const Image& src, const int alpha, const AffineTransform& transform, Graphics::ResamplingQuality quality, bool tiledFill) const
1834  {
1835  state.renderImageTransformed (*this, src, alpha, transform, quality, tiledFill);
1836  }
1837 
1838  void renderImageUntransformed (SavedStateType& state, const Image& src, const int alpha, int x, int y, bool tiledFill) const
1839  {
1840  state.renderImageUntransformed (*this, src, alpha, x, y, tiledFill);
1841  }
1842 
1844 
1845  //==============================================================================
1846  template <class Renderer>
1847  void iterate (Renderer& r) const noexcept
1848  {
1849  for (const Rectangle<int>* i = clip.begin(), * const e = clip.end(); i != e; ++i)
1850  {
1851  const int x = i->getX();
1852  const int w = i->getWidth();
1853  jassert (w > 0);
1854  const int bottom = i->getBottom();
1855 
1856  for (int y = i->getY(); y < bottom; ++y)
1857  {
1858  r.setEdgeTableYPos (y);
1859  r.handleEdgeTableLineFull (x, w);
1860  }
1861  }
1862  }
1863 
1864  private:
1865  //==============================================================================
1866  class SubRectangleIterator
1867  {
1868  public:
1869  SubRectangleIterator (const RectangleList<int>& clipList, const Rectangle<int>& clipBounds)
1870  : clip (clipList), area (clipBounds)
1871  {}
1872 
1873  template <class Renderer>
1874  void iterate (Renderer& r) const noexcept
1875  {
1876  for (const Rectangle<int>* i = clip.begin(), * const e = clip.end(); i != e; ++i)
1877  {
1878  const Rectangle<int> rect (i->getIntersection (area));
1879 
1880  if (! rect.isEmpty())
1881  {
1882  const int x = rect.getX();
1883  const int w = rect.getWidth();
1884  const int bottom = rect.getBottom();
1885 
1886  for (int y = rect.getY(); y < bottom; ++y)
1887  {
1888  r.setEdgeTableYPos (y);
1889  r.handleEdgeTableLineFull (x, w);
1890  }
1891  }
1892  }
1893  }
1894 
1895  private:
1896  const RectangleList<int>& clip;
1897  const Rectangle<int> area;
1898 
1899  JUCE_DECLARE_NON_COPYABLE (SubRectangleIterator)
1900  };
1901 
1902  //==============================================================================
1903  class SubRectangleIteratorFloat
1904  {
1905  public:
1906  SubRectangleIteratorFloat (const RectangleList<int>& clipList, const Rectangle<float>& clipBounds) noexcept
1907  : clip (clipList), area (clipBounds)
1908  {
1909  }
1910 
1911  template <class Renderer>
1912  void iterate (Renderer& r) const noexcept
1913  {
1915 
1916  for (const Rectangle<int>* i = clip.begin(), * const e = clip.end(); i != e; ++i)
1917  {
1918  const int clipLeft = i->getX();
1919  const int clipRight = i->getRight();
1920  const int clipTop = i->getY();
1921  const int clipBottom = i->getBottom();
1922 
1923  if (f.totalBottom > clipTop && f.totalTop < clipBottom
1924  && f.totalRight > clipLeft && f.totalLeft < clipRight)
1925  {
1926  if (f.isOnePixelWide())
1927  {
1928  if (f.topAlpha != 0 && f.totalTop >= clipTop)
1929  {
1930  r.setEdgeTableYPos (f.totalTop);
1931  r.handleEdgeTablePixel (f.left, f.topAlpha);
1932  }
1933 
1934  const int endY = jmin (f.bottom, clipBottom);
1935  for (int y = jmax (clipTop, f.top); y < endY; ++y)
1936  {
1937  r.setEdgeTableYPos (y);
1938  r.handleEdgeTablePixelFull (f.left);
1939  }
1940 
1941  if (f.bottomAlpha != 0 && f.bottom < clipBottom)
1942  {
1943  r.setEdgeTableYPos (f.bottom);
1944  r.handleEdgeTablePixel (f.left, f.bottomAlpha);
1945  }
1946  }
1947  else
1948  {
1949  const int clippedLeft = jmax (f.left, clipLeft);
1950  const int clippedWidth = jmin (f.right, clipRight) - clippedLeft;
1951  const bool doLeftAlpha = f.leftAlpha != 0 && f.totalLeft >= clipLeft;
1952  const bool doRightAlpha = f.rightAlpha != 0 && f.right < clipRight;
1953 
1954  if (f.topAlpha != 0 && f.totalTop >= clipTop)
1955  {
1956  r.setEdgeTableYPos (f.totalTop);
1957 
1958  if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getTopLeftCornerAlpha());
1959  if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.topAlpha);
1960  if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getTopRightCornerAlpha());
1961  }
1962 
1963  const int endY = jmin (f.bottom, clipBottom);
1964  for (int y = jmax (clipTop, f.top); y < endY; ++y)
1965  {
1966  r.setEdgeTableYPos (y);
1967 
1968  if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.leftAlpha);
1969  if (clippedWidth > 0) r.handleEdgeTableLineFull (clippedLeft, clippedWidth);
1970  if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.rightAlpha);
1971  }
1972 
1973  if (f.bottomAlpha != 0 && f.bottom < clipBottom)
1974  {
1975  r.setEdgeTableYPos (f.bottom);
1976 
1977  if (doLeftAlpha) r.handleEdgeTablePixel (f.totalLeft, f.getBottomLeftCornerAlpha());
1978  if (clippedWidth > 0) r.handleEdgeTableLine (clippedLeft, clippedWidth, f.bottomAlpha);
1979  if (doRightAlpha) r.handleEdgeTablePixel (f.right, f.getBottomRightCornerAlpha());
1980  }
1981  }
1982  }
1983  }
1984  }
1985 
1986  private:
1987  const RectangleList<int>& clip;
1988  const Rectangle<float>& area;
1989 
1990  JUCE_DECLARE_NON_COPYABLE (SubRectangleIteratorFloat)
1991  };
1992 
1993  Ptr toEdgeTable() const { return new EdgeTableRegion (clip); }
1994 
1995  RectangleListRegion& operator= (const RectangleListRegion&);
1996  };
1997 };
1998 
1999 //==============================================================================
2000 template <class SavedStateType>
2002 {
2003 public:
2007 
2008  SavedStateBase (const Rectangle<int>& initialClip)
2009  : clip (new RectangleListRegionType (initialClip)), transform (Point<int>()),
2010  interpolationQuality (Graphics::mediumResamplingQuality), transparencyLayerAlpha (1.0f)
2011  {
2012  }
2013 
2015  : clip (new RectangleListRegionType (clipList)), transform (origin),
2016  interpolationQuality (Graphics::mediumResamplingQuality), transparencyLayerAlpha (1.0f)
2017  {
2018  }
2019 
2021  : clip (other.clip), transform (other.transform), fillType (other.fillType),
2022  interpolationQuality (other.interpolationQuality),
2023  transparencyLayerAlpha (other.transparencyLayerAlpha)
2024  {
2025  }
2026 
2027  SavedStateType& getThis() noexcept { return *static_cast<SavedStateType*> (this); }
2028 
2030  {
2031  if (clip != nullptr)
2032  {
2033  if (transform.isOnlyTranslated)
2034  {
2035  cloneClipIfMultiplyReferenced();
2036  clip = clip->clipToRectangle (transform.translated (r));
2037  }
2038  else if (! transform.isRotated)
2039  {
2040  cloneClipIfMultiplyReferenced();
2041  clip = clip->clipToRectangle (transform.transformed (r));
2042  }
2043  else
2044  {
2045  Path p;
2046  p.addRectangle (r);
2047  clipToPath (p, AffineTransform::identity);
2048  }
2049  }
2050 
2051  return clip != nullptr;
2052  }
2053 
2055  {
2056  if (clip != nullptr)
2057  {
2058  if (transform.isOnlyTranslated)
2059  {
2060  cloneClipIfMultiplyReferenced();
2061  RectangleList<int> offsetList (r);
2062  offsetList.offsetAll (transform.offset.x, transform.offset.y);
2063  clip = clip->clipToRectangleList (offsetList);
2064  }
2065  else if (! transform.isRotated)
2066  {
2067  cloneClipIfMultiplyReferenced();
2068  RectangleList<int> scaledList;
2069 
2070  for (const Rectangle<int>* i = r.begin(), * const e = r.end(); i != e; ++i)
2071  scaledList.add (transform.transformed (*i));
2072 
2073  clip = clip->clipToRectangleList (scaledList);
2074  }
2075  else
2076  {
2077  clipToPath (r.toPath(), AffineTransform::identity);
2078  }
2079  }
2080 
2081  return clip != nullptr;
2082  }
2083 
2085  {
2086  const int x1 = (int) std::ceil (r.getX());
2087  const int y1 = (int) std::ceil (r.getY());
2088  const int x2 = (int) std::floor (r.getRight());
2089  const int y2 = (int) std::floor (r.getBottom());
2090 
2091  return Rectangle<int> (x1, y1, x2 - x1, y2 - y1);
2092  }
2093 
2095  {
2096  if (clip != nullptr)
2097  {
2098  cloneClipIfMultiplyReferenced();
2099 
2100  if (transform.isOnlyTranslated)
2101  {
2102  clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.translated (r.toFloat())));
2103  }
2104  else if (! transform.isRotated)
2105  {
2106  clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.transformed (r.toFloat())));
2107  }
2108  else
2109  {
2110  Path p;
2111  p.addRectangle (r.toFloat());
2112  p.applyTransform (transform.complexTransform);
2113  p.addRectangle (clip->getClipBounds().toFloat());
2114  p.setUsingNonZeroWinding (false);
2115  clip = clip->clipToPath (p, AffineTransform::identity);
2116  }
2117  }
2118 
2119  return clip != nullptr;
2120  }
2121 
2122  void clipToPath (const Path& p, const AffineTransform& t)
2123  {
2124  if (clip != nullptr)
2125  {
2126  cloneClipIfMultiplyReferenced();
2127  clip = clip->clipToPath (p, transform.getTransformWith (t));
2128  }
2129  }
2130 
2131  void clipToImageAlpha (const Image& sourceImage, const AffineTransform& t)
2132  {
2133  if (clip != nullptr)
2134  {
2135  if (sourceImage.hasAlphaChannel())
2136  {
2137  cloneClipIfMultiplyReferenced();
2138  clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t), interpolationQuality);
2139  }
2140  else
2141  {
2142  Path p;
2143  p.addRectangle (sourceImage.getBounds());
2144  clipToPath (p, t);
2145  }
2146  }
2147  }
2148 
2149  bool clipRegionIntersects (const Rectangle<int>& r) const
2150  {
2151  if (clip != nullptr)
2152  {
2153  if (transform.isOnlyTranslated)
2154  return clip->clipRegionIntersects (transform.translated (r));
2155 
2156  return getClipBounds().intersects (r);
2157  }
2158 
2159  return false;
2160  }
2161 
2163  {
2164  return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
2165  : Rectangle<int>();
2166  }
2167 
2168  void setFillType (const FillType& newFill)
2169  {
2170  fillType = newFill;
2171  }
2172 
2173  void fillTargetRect (const Rectangle<int>& r, const bool replaceContents)
2174  {
2175  if (fillType.isColour())
2176  {
2177  clip->fillRectWithColour (getThis(), r, fillType.colour.getPixelARGB(), replaceContents);
2178  }
2179  else
2180  {
2181  const Rectangle<int> clipped (clip->getClipBounds().getIntersection (r));
2182 
2183  if (! clipped.isEmpty())
2184  fillShape (new RectangleListRegionType (clipped), false);
2185  }
2186  }
2187 
2189  {
2190  if (fillType.isColour())
2191  {
2192  clip->fillRectWithColour (getThis(), r, fillType.colour.getPixelARGB());
2193  }
2194  else
2195  {
2196  const Rectangle<float> clipped (clip->getClipBounds().toFloat().getIntersection (r));
2197 
2198  if (! clipped.isEmpty())
2199  fillShape (new EdgeTableRegionType (clipped), false);
2200  }
2201  }
2202 
2203  template <typename CoordType>
2205  {
2206  Path p;
2207  p.addRectangle (r);
2208  fillPath (p, AffineTransform::identity);
2209  }
2210 
2211  void fillRect (const Rectangle<int>& r, const bool replaceContents)
2212  {
2213  if (clip != nullptr)
2214  {
2215  if (transform.isOnlyTranslated)
2216  {
2217  fillTargetRect (transform.translated (r), replaceContents);
2218  }
2219  else if (! transform.isRotated)
2220  {
2221  fillTargetRect (transform.transformed (r), replaceContents);
2222  }
2223  else
2224  {
2225  jassert (! replaceContents); // not implemented..
2226  fillRectAsPath (r);
2227  }
2228  }
2229  }
2230 
2231  void fillRect (const Rectangle<float>& r)
2232  {
2233  if (clip != nullptr)
2234  {
2235  if (transform.isOnlyTranslated)
2236  fillTargetRect (transform.translated (r));
2237  else if (! transform.isRotated)
2238  fillTargetRect (transform.transformed (r));
2239  else
2240  fillRectAsPath (r);
2241  }
2242  }
2243 
2245  {
2246  if (clip != nullptr)
2247  {
2248  if (! transform.isRotated)
2249  {
2251 
2252  if (transform.isOnlyTranslated)
2253  transformed.offsetAll (transform.offset.toFloat());
2254  else
2255  transformed.transformAll (transform.getTransform());
2256 
2257  fillShape (new EdgeTableRegionType (transformed), false);
2258  }
2259  else
2260  {
2261  fillPath (list.toPath(), AffineTransform::identity);
2262  }
2263  }
2264  }
2265 
2266  void fillPath (const Path& path, const AffineTransform& t)
2267  {
2268  if (clip != nullptr)
2269  fillShape (new EdgeTableRegionType (clip->getClipBounds(), path, transform.getTransformWith (t)), false);
2270  }
2271 
2272  void fillEdgeTable (const EdgeTable& edgeTable, const float x, const int y)
2273  {
2274  if (clip != nullptr)
2275  {
2276  EdgeTableRegionType* edgeTableClip = new EdgeTableRegionType (edgeTable);
2277  edgeTableClip->edgeTable.translate (x, y);
2278 
2279  if (fillType.isColour())
2280  {
2281  float brightness = fillType.colour.getBrightness() - 0.5f;
2282 
2283  if (brightness > 0.0f)
2284  edgeTableClip->edgeTable.multiplyLevels (1.0f + 1.6f * brightness);
2285  }
2286 
2287  fillShape (edgeTableClip, false);
2288  }
2289  }
2290 
2291  void drawLine (const Line<float>& line)
2292  {
2293  Path p;
2294  p.addLineSegment (line, 1.0f);
2295  fillPath (p, AffineTransform::identity);
2296  }
2297 
2298  void drawImage (const Image& sourceImage, const AffineTransform& trans)
2299  {
2300  if (clip != nullptr && ! fillType.colour.isTransparent())
2301  renderImage (sourceImage, trans, nullptr);
2302  }
2303 
2305  {
2306  return (std::abs (t.mat01) < 0.002)
2307  && (std::abs (t.mat10) < 0.002)
2308  && (std::abs (t.mat00 - 1.0f) < 0.002)
2309  && (std::abs (t.mat11 - 1.0f) < 0.002);
2310  }
2311 
2312  void renderImage (const Image& sourceImage, const AffineTransform& trans,
2313  const BaseRegionType* const tiledFillClipRegion)
2314  {
2315  const AffineTransform t (transform.getTransformWith (trans));
2316 
2317  const int alpha = fillType.colour.getAlpha();
2318 
2319  if (isOnlyTranslationAllowingError (t))
2320  {
2321  // If our translation doesn't involve any distortion, just use a simple blit..
2322  int tx = (int) (t.getTranslationX() * 256.0f);
2323  int ty = (int) (t.getTranslationY() * 256.0f);
2324 
2325  if (interpolationQuality == Graphics::lowResamplingQuality || ((tx | ty) & 224) == 0)
2326  {
2327  tx = ((tx + 128) >> 8);
2328  ty = ((ty + 128) >> 8);
2329 
2330  if (tiledFillClipRegion != nullptr)
2331  {
2332  tiledFillClipRegion->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty, true);
2333  }
2334  else
2335  {
2336  Rectangle<int> area (tx, ty, sourceImage.getWidth(), sourceImage.getHeight());
2337  area = area.getIntersection (getThis().getMaximumBounds());
2338 
2339  if (! area.isEmpty())
2340  if (typename BaseRegionType::Ptr c = clip->applyClipTo (new EdgeTableRegionType (area)))
2341  c->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty, false);
2342  }
2343 
2344  return;
2345  }
2346  }
2347 
2348  if (! t.isSingularity())
2349  {
2350  if (tiledFillClipRegion != nullptr)
2351  {
2352  tiledFillClipRegion->renderImageTransformed (getThis(), sourceImage, alpha, t, interpolationQuality, true);
2353  }
2354  else
2355  {
2356  Path p;
2357  p.addRectangle (sourceImage.getBounds());
2358 
2359  typename BaseRegionType::Ptr c (clip->clone());
2360  c = c->clipToPath (p, t);
2361 
2362  if (c != nullptr)
2363  c->renderImageTransformed (getThis(), sourceImage, alpha, t, interpolationQuality, false);
2364  }
2365  }
2366  }
2367 
2368  void fillShape (typename BaseRegionType::Ptr shapeToFill, const bool replaceContents)
2369  {
2370  jassert (clip != nullptr);
2371 
2372  shapeToFill = clip->applyClipTo (shapeToFill);
2373 
2374  if (shapeToFill != nullptr)
2375  {
2376  if (fillType.isGradient())
2377  {
2378  jassert (! replaceContents); // that option is just for solid colours
2379 
2380  ColourGradient g2 (*(fillType.gradient));
2381  g2.multiplyOpacity (fillType.getOpacity());
2382  AffineTransform t (transform.getTransformWith (fillType.transform).translated (-0.5f, -0.5f));
2383 
2384  const bool isIdentity = t.isOnlyTranslation();
2385 
2386  if (isIdentity)
2387  {
2388  // If our translation doesn't involve any distortion, we can speed it up..
2389  g2.point1.applyTransform (t);
2390  g2.point2.applyTransform (t);
2392  }
2393 
2394  shapeToFill->fillAllWithGradient (getThis(), g2, t, isIdentity);
2395  }
2396  else if (fillType.isTiledImage())
2397  {
2398  renderImage (fillType.image, fillType.transform, shapeToFill);
2399  }
2400  else
2401  {
2402  shapeToFill->fillAllWithColour (getThis(), fillType.colour.getPixelARGB(), replaceContents);
2403  }
2404  }
2405  }
2406 
2408  {
2409  if (clip->getReferenceCount() > 1)
2410  clip = clip->clone();
2411  }
2412 
2418 };
2419 
2420 //==============================================================================
2421 class SoftwareRendererSavedState : public SavedStateBase<SoftwareRendererSavedState>
2422 {
2424 
2425 public:
2426  SoftwareRendererSavedState (const Image& im, const Rectangle<int>& clipBounds)
2427  : BaseClass (clipBounds), image (im)
2428  {
2429  }
2430 
2431  SoftwareRendererSavedState (const Image& im, const RectangleList<int>& clipList, Point<int> origin)
2432  : BaseClass (clipList, origin), image (im)
2433  {
2434  }
2435 
2437  : BaseClass (other), image (other.image), font (other.font)
2438  {
2439  }
2440 
2442  {
2444 
2445  if (clip != nullptr)
2446  {
2447  const Rectangle<int> layerBounds (clip->getClipBounds());
2448 
2449  s->image = Image (Image::ARGB, layerBounds.getWidth(), layerBounds.getHeight(), true);
2450  s->transparencyLayerAlpha = opacity;
2451  s->transform.moveOriginInDeviceSpace (-layerBounds.getPosition());
2453  s->clip->translate (-layerBounds.getPosition());
2454  }
2455 
2456  return s;
2457  }
2458 
2460  {
2461  if (clip != nullptr)
2462  {
2463  const Rectangle<int> layerBounds (clip->getClipBounds());
2464 
2465  const ScopedPointer<LowLevelGraphicsContext> g (image.createLowLevelContext());
2466  g->setOpacity (finishedLayerState.transparencyLayerAlpha);
2467  g->drawImage (finishedLayerState.image, AffineTransform::translation (layerBounds.getPosition()));
2468  }
2469  }
2470 
2472 
2473  static void clearGlyphCache()
2474  {
2475  GlyphCacheType::getInstance().reset();
2476  }
2477 
2478  //==============================================================================
2479  void drawGlyph (int glyphNumber, const AffineTransform& trans)
2480  {
2481  if (clip != nullptr)
2482  {
2483  if (trans.isOnlyTranslation() && ! transform.isRotated)
2484  {
2485  GlyphCacheType& cache = GlyphCacheType::getInstance();
2486 
2487  Point<float> pos (trans.getTranslationX(), trans.getTranslationY());
2488 
2489  if (transform.isOnlyTranslated)
2490  {
2491  cache.drawGlyph (*this, font, glyphNumber, pos + transform.offset.toFloat());
2492  }
2493  else
2494  {
2495  pos = transform.transformed (pos);
2496 
2497  Font f (font);
2498  f.setHeight (font.getHeight() * transform.complexTransform.mat11);
2499 
2500  const float xScale = transform.complexTransform.mat00 / transform.complexTransform.mat11;
2501  if (std::abs (xScale - 1.0f) > 0.01f)
2502  f.setHorizontalScale (xScale);
2503 
2504  cache.drawGlyph (*this, f, glyphNumber, pos);
2505  }
2506  }
2507  else
2508  {
2509  const float fontHeight = font.getHeight();
2510 
2511  AffineTransform t (transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
2512  .followedBy (trans)));
2513 
2514  const ScopedPointer<EdgeTable> et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight));
2515 
2516  if (et != nullptr)
2517  fillShape (new EdgeTableRegionType (*et), false);
2518  }
2519  }
2520  }
2521 
2522  Rectangle<int> getMaximumBounds() const { return image.getBounds(); }
2523 
2524  //==============================================================================
2525  template <typename IteratorType>
2526  void renderImageTransformed (IteratorType& iter, const Image& src, const int alpha, const AffineTransform& trans, Graphics::ResamplingQuality quality, bool tiledFill) const
2527  {
2529  const Image::BitmapData srcData (src, Image::BitmapData::readOnly);
2530  EdgeTableFillers::renderImageTransformed (iter, destData, srcData, alpha, trans, quality, tiledFill);
2531  }
2532 
2533  template <typename IteratorType>
2534  void renderImageUntransformed (IteratorType& iter, const Image& src, const int alpha, int x, int y, bool tiledFill) const
2535  {
2537  const Image::BitmapData srcData (src, Image::BitmapData::readOnly);
2538  EdgeTableFillers::renderImageUntransformed (iter, destData, srcData, alpha, x, y, tiledFill);
2539  }
2540 
2541  template <typename IteratorType>
2542  void fillWithSolidColour (IteratorType& iter, const PixelARGB colour, bool replaceContents) const
2543  {
2545 
2546  switch (destData.pixelFormat)
2547  {
2548  case Image::ARGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelARGB*) 0); break;
2549  case Image::RGB: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelRGB*) 0); break;
2550  default: EdgeTableFillers::renderSolidFill (iter, destData, colour, replaceContents, (PixelAlpha*) 0); break;
2551  }
2552  }
2553 
2554  template <typename IteratorType>
2555  void fillWithGradient (IteratorType& iter, ColourGradient& gradient, const AffineTransform& trans, bool isIdentity) const
2556  {
2557  HeapBlock<PixelARGB> lookupTable;
2558  const int numLookupEntries = gradient.createLookupTable (trans, lookupTable);
2559  jassert (numLookupEntries > 0);
2560 
2562 
2563  switch (destData.pixelFormat)
2564  {
2565  case Image::ARGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelARGB*) 0); break;
2566  case Image::RGB: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) 0); break;
2567  default: EdgeTableFillers::renderGradient (iter, destData, gradient, trans, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) 0); break;
2568  }
2569  }
2570 
2571  //==============================================================================
2574 
2575 private:
2577 };
2578 
2579 //==============================================================================
2580 template <class StateObjectType>
2582 {
2583 public:
2584  SavedStateStack (StateObjectType* const initialState) noexcept
2585  : currentState (initialState)
2586  {}
2587 
2589 
2590  void initialise (StateObjectType* state)
2591  {
2592  currentState = state;
2593  }
2594 
2595  inline StateObjectType* operator->() const noexcept { return currentState; }
2596  inline StateObjectType& operator*() const noexcept { return *currentState; }
2597 
2598  void save()
2599  {
2600  stack.add (new StateObjectType (*currentState));
2601  }
2602 
2603  void restore()
2604  {
2605  if (StateObjectType* const top = stack.getLast())
2606  {
2607  currentState = top;
2608  stack.removeLast (1, false);
2609  }
2610  else
2611  {
2612  jassertfalse; // trying to pop with an empty stack!
2613  }
2614  }
2615 
2616  void beginTransparencyLayer (float opacity)
2617  {
2618  save();
2619  currentState = currentState->beginTransparencyLayer (opacity);
2620  }
2621 
2623  {
2624  const ScopedPointer<StateObjectType> finishedTransparencyLayer (currentState);
2625  restore();
2626  currentState->endTransparencyLayer (*finishedTransparencyLayer);
2627  }
2628 
2629 private:
2630  ScopedPointer<StateObjectType> currentState;
2632 
2634 };
2635 
2636 //==============================================================================
2637 template <class SavedStateType>
2639 {
2640 public:
2641  bool isVectorDevice() const override { return false; }
2642  void setOrigin (Point<int> o) override { stack->transform.setOrigin (o); }
2643  void addTransform (const AffineTransform& t) override { stack->transform.addTransform (t); }
2644  float getPhysicalPixelScaleFactor() override { return stack->transform.getPhysicalPixelScaleFactor(); }
2645  Rectangle<int> getClipBounds() const override { return stack->getClipBounds(); }
2646  bool isClipEmpty() const override { return stack->clip == nullptr; }
2647  bool clipRegionIntersects (const Rectangle<int>& r) override { return stack->clipRegionIntersects (r); }
2648  bool clipToRectangle (const Rectangle<int>& r) override { return stack->clipToRectangle (r); }
2649  bool clipToRectangleList (const RectangleList<int>& r) override { return stack->clipToRectangleList (r); }
2650  void excludeClipRectangle (const Rectangle<int>& r) override { stack->excludeClipRectangle (r); }
2651  void clipToPath (const Path& path, const AffineTransform& t) override { stack->clipToPath (path, t); }
2652  void clipToImageAlpha (const Image& im, const AffineTransform& t) override { stack->clipToImageAlpha (im, t); }
2653  void saveState() override { stack.save(); }
2654  void restoreState() override { stack.restore(); }
2655  void beginTransparencyLayer (float opacity) override { stack.beginTransparencyLayer (opacity); }
2656  void endTransparencyLayer() override { stack.endTransparencyLayer(); }
2657  void setFill (const FillType& fillType) override { stack->setFillType (fillType); }
2658  void setOpacity (float newOpacity) override { stack->fillType.setOpacity (newOpacity); }
2659  void setInterpolationQuality (Graphics::ResamplingQuality quality) override { stack->interpolationQuality = quality; }
2660  void fillRect (const Rectangle<int>& r, bool replace) override { stack->fillRect (r, replace); }
2661  void fillRect (const Rectangle<float>& r) override { stack->fillRect (r); }
2662  void fillRectList (const RectangleList<float>& list) override { stack->fillRectList (list); }
2663  void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); }
2664  void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); }
2665  void drawGlyph (int glyphNumber, const AffineTransform& t) override { stack->drawGlyph (glyphNumber, t); }
2666  void drawLine (const Line<float>& line) override { stack->drawLine (line); }
2667  void setFont (const Font& newFont) override { stack->font = newFont; }
2668  const Font& getFont() override { return stack->font; }
2669 
2670 protected:
2671  StackBasedLowLevelGraphicsContext (SavedStateType* initialState) : stack (initialState) {}
2673 
2675 };
2676 
2677 }
2678 
2679 #if JUCE_MSVC
2680  #pragma warning (pop)
2681 #endif
2682 
2683 #endif // JUCE_RENDERINGHELPERS_H_INCLUDED
void translate(float dx, int dy) noexcept
Definition: juce_EdgeTable.cpp:456
void fillRectWithColour(SavedStateType &state, const Rectangle< int > &area, const PixelARGB colour, bool replaceContents) const
Definition: juce_RenderingHelpers.h:1811
const double gy1
Definition: juce_RenderingHelpers.h:515
Graphics::ResamplingQuality interpolationQuality
Definition: juce_RenderingHelpers.h:2416
SoftwareRendererSavedState(const Image &im, const Rectangle< int > &clipBounds)
Definition: juce_RenderingHelpers.h:2426
int getBottomRightCornerAlpha() const noexcept
Definition: juce_RenderingHelpers.h:393
Ptr clone() const
Definition: juce_RenderingHelpers.h:1778
bool clipRegionIntersects(const Rectangle< int > &r) const
Definition: juce_RenderingHelpers.h:1684
SoftwareRendererSavedState(const Image &im, const RectangleList< int > &clipList, Point< int > origin)
Definition: juce_RenderingHelpers.h:2431
Base()
Definition: juce_RenderingHelpers.h:1554
static bool isOnlyTranslationAllowingError(const AffineTransform &t)
Definition: juce_RenderingHelpers.h:2304
static GlyphCache & getInstance()
Definition: juce_RenderingHelpers.h:154
ValueType getWidth() const noexcept
Definition: juce_Rectangle.h:113
GlyphCache< CachedGlyphEdgeTable< SoftwareRendererSavedState >, SoftwareRendererSavedState > GlyphCacheType
Definition: juce_RenderingHelpers.h:2471
forcedinline void handleEdgeTablePixel(const int x, const int alphaLevel) noexcept
Definition: juce_RenderingHelpers.h:947
void reset()
Definition: juce_RenderingHelpers.h:165
void setHeight(float newHeight)
Definition: juce_Font.cpp:455
Rectangle< int > translated(const Rectangle< int > &r) const noexcept
Definition: juce_RenderingHelpers.h:107
Definition: juce_Image.h:311
void save()
Definition: juce_RenderingHelpers.h:2598
void drawGlyph(RenderTargetType &target, const Font &font, const int glyphNumber, Point< float > pos)
Definition: juce_RenderingHelpers.h:174
void drawImage(const Image &sourceImage, const AffineTransform &trans)
Definition: juce_RenderingHelpers.h:2298
Definition: juce_graphics.h:45
void drawLine(const Line< float > &line)
Definition: juce_RenderingHelpers.h:2291
Definition: juce_EdgeTable.h:35
TransformedRadial(const ColourGradient &gradient, const AffineTransform &transform, const PixelARGB *const colours, const int numColours)
Definition: juce_RenderingHelpers.h:526
Ptr clipToImageAlpha(const Image &image, const AffineTransform &transform, const Graphics::ResamplingQuality quality)
Definition: juce_RenderingHelpers.h:1802
ValueType getY() const noexcept
Definition: juce_Point.h:68
bool hasAlphaChannel() const noexcept
Definition: juce_Image.cpp:266
GlyphCache()
Definition: juce_RenderingHelpers.h:144
int pointer_sized_int
Definition: juce_MathsFunctions.h:86
int getTopRightCornerAlpha() const noexcept
Definition: juce_RenderingHelpers.h:391
ValueType getRight() const noexcept
Definition: juce_Rectangle.h:119
forcedinline void handleEdgeTablePixel(const int x, const int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:602
bool clipRegionIntersects(const Rectangle< int > &r) override
Definition: juce_RenderingHelpers.h:2647
ResamplingQuality
Definition: juce_GraphicsContext.h:465
void beginTransparencyLayer(float opacity) override
Definition: juce_RenderingHelpers.h:2655
Definition: juce_Font.h:39
RenderingHelpers::TranslationOrTransform transform
Definition: juce_RenderingHelpers.h:2414
void fillAllWithColour(SavedStateType &state, const PixelARGB colour, bool replaceContents) const
Definition: juce_RenderingHelpers.h:1720
void offsetAll(Point< ValueType > offset) noexcept
Definition: juce_RectangleList.h:597
Ptr clipToRectangleList(const RectangleList< int > &r)
Definition: juce_RenderingHelpers.h:1604
forcedinline void setEdgeTableYPos(int y) noexcept
Definition: juce_RenderingHelpers.h:792
void setUsingNonZeroWinding(bool isNonZeroWinding) noexcept
Definition: juce_Path.cpp:211
bool excludeClipRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:2094
void fillShape(typename BaseRegionType::Ptr shapeToFill, const bool replaceContents)
Definition: juce_RenderingHelpers.h:2368
double maxDist
Definition: juce_RenderingHelpers.h:516
void beginTransparencyLayer(float opacity)
Definition: juce_RenderingHelpers.h:2616
void multiplyLevels(float factor)
Definition: juce_EdgeTable.cpp:477
ReferenceCountedObjectPtr< Base > Ptr
Definition: juce_RenderingHelpers.h:1557
Definition: juce_RenderingHelpers.h:2581
bool clipToRectangle(const Rectangle< int > &r) override
Definition: juce_RenderingHelpers.h:2648
Definition: juce_Line.h:44
AffineTransform inverted() const noexcept
Definition: juce_AffineTransform.cpp:206
int totalLeft
Definition: juce_RenderingHelpers.h:397
PixelARGB getPixel(const int x) const noexcept
Definition: juce_RenderingHelpers.h:460
#define noexcept
Definition: juce_CompilerSupport.h:141
ValueType getX() const noexcept
Definition: juce_graphics.h:108
int getWidth() const noexcept
Definition: juce_Image.cpp:259
void endTransparencyLayer() override
Definition: juce_RenderingHelpers.h:2656
void handleEdgeTableLine(int x, int width, const int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:748
Gradient(const Image::BitmapData &dest, const ColourGradient &gradient, const AffineTransform &transform, const PixelARGB *const colours, const int numColours)
Definition: juce_RenderingHelpers.h:725
virtual bool isHinted() const
Definition: juce_Typeface.h:123
void setFill(const FillType &fillType) override
Definition: juce_RenderingHelpers.h:2657
virtual void renderImageTransformed(SavedStateType &, const Image &, const int alpha, const AffineTransform &, Graphics::ResamplingQuality, bool tiledFill) const =0
AffineTransform getTransformWith(const AffineTransform &userTransform) const noexcept
Definition: juce_RenderingHelpers.h:59
void restoreState() override
Definition: juce_RenderingHelpers.h:2654
static Rectangle< int > getLargestIntegerWithin(Rectangle< float > r)
Definition: juce_RenderingHelpers.h:2084
SavedStateBase(const RectangleList< int > &clipList, Point< int > origin)
Definition: juce_RenderingHelpers.h:2014
EdgeTableRegion(const RectangleList< float > &r)
Definition: juce_RenderingHelpers.h:1589
ValueType getX() const noexcept
Definition: juce_Rectangle.h:107
Definition: juce_RenderingHelpers.h:316
#define JUCE_PERFORM_PIXEL_OP_LOOP(op)
Definition: juce_RenderingHelpers.h:564
Typeface * getTypeface() const
Definition: juce_Font.cpp:395
void multiplyOpacity(float multiplier) noexcept
Definition: juce_ColourGradient.cpp:90
ValueType getWidth() const noexcept
Definition: juce_graphics.h:114
ValueType getHeight() const noexcept
Definition: juce_Rectangle.h:116
int getTopLeftCornerAlpha() const noexcept
Definition: juce_RenderingHelpers.h:390
Type jmin(const Type a, const Type b)
Definition: juce_core.h:113
Definition: juce_ScopedLock.h:59
ClipRegions< SavedStateType >::RectangleListRegion RectangleListRegionType
Definition: juce_RenderingHelpers.h:2006
void fillTargetRect(const Rectangle< float > &r)
Definition: juce_RenderingHelpers.h:2188
forcedinline void multiplyAlpha(int multiplier) noexcept
Definition: juce_PixelFormats.h:219
Definition: juce_GraphicsContext.h:467
void set(Type newValue) noexcept
Definition: juce_Atomic.h:79
forcedinline void setY(const int y) noexcept
Definition: juce_RenderingHelpers.h:452
bool isPositiveAndBelow(Type valueToTest, Type upperLimit) noexcept
Definition: juce_core.h:238
PixelFormat pixelFormat
Definition: juce_Image.h:349
Definition: juce_RenderingHelpers.h:406
void renderImage(const Image &sourceImage, const AffineTransform &trans, const BaseRegionType *const tiledFillClipRegion)
Definition: juce_RenderingHelpers.h:2312
Ptr clone() const
Definition: juce_RenderingHelpers.h:1595
ClipRegions< SavedStateType >::EdgeTableRegion EdgeTableRegionType
Definition: juce_RenderingHelpers.h:2005
forcedinline void setEdgeTableYPos(const int y) noexcept
Definition: juce_RenderingHelpers.h:597
StackBasedLowLevelGraphicsContext()
Definition: juce_RenderingHelpers.h:2672
void initialise(StateObjectType *state)
Definition: juce_RenderingHelpers.h:2590
Definition: juce_DeletedAtShutdown.h:40
AffineTransform complexTransform
Definition: juce_RenderingHelpers.h:133
forcedinline void handleEdgeTablePixelFull(const int x) const noexcept
Definition: juce_RenderingHelpers.h:813
void clipEdgeTableLine(EdgeTable &et, int x, int y, int width)
Definition: juce_RenderingHelpers.h:865
int roundToInt(const FloatType value) noexcept
Definition: juce_core.h:418
void drawLine(const Line< float > &line) override
Definition: juce_RenderingHelpers.h:2666
forcedinline void handleEdgeTableLineFull(const int x, const int width) const noexcept
Definition: juce_RenderingHelpers.h:631
EdgeTableRegion(const EdgeTable &e)
Definition: juce_RenderingHelpers.h:1585
Type * addBytesToPointer(Type *basePointer, IntegerType bytes) noexcept
Definition: juce_Memory.h:53
int rightAlpha
Definition: juce_RenderingHelpers.h:398
int totalRight
Definition: juce_RenderingHelpers.h:397
Definition: juce_RenderingHelpers.h:39
Definition: juce_graphics.h:41
int getBottomLeftCornerAlpha() const noexcept
Definition: juce_RenderingHelpers.h:392
Definition: juce_Image.h:63
void clipToImageAlpha(const Image &sourceImage, const AffineTransform &t)
Definition: juce_RenderingHelpers.h:2131
Rectangle< float > toFloat() const noexcept
Definition: juce_Rectangle.h:792
void iterate(Renderer &r) const noexcept
Definition: juce_RenderingHelpers.h:1847
virtual void setOpacity(float)=0
Ptr excludeClipRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1615
SavedStateBase(const Rectangle< int > &initialClip)
Definition: juce_RenderingHelpers.h:2008
#define jassertfalse
Definition: juce_PlatformDefs.h:141
forcedinline void setEdgeTableYPos(const int newY) noexcept
Definition: juce_RenderingHelpers.h:941
Definition: juce_PixelFormats.h:309
Definition: juce_ColourGradient.h:35
void setFont(const Font &newFont) override
Definition: juce_RenderingHelpers.h:2667
Definition: juce_RenderingHelpers.h:722
void fillWithGradient(IteratorType &iter, ColourGradient &gradient, const AffineTransform &trans, bool isIdentity) const
Definition: juce_RenderingHelpers.h:2555
void drawGlyph(int glyphNumber, const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2665
Definition: juce_RenderingHelpers.h:2001
float getPhysicalPixelScaleFactor() const noexcept
Definition: juce_RenderingHelpers.h:94
Point< float > point2
Definition: juce_ColourGradient.h:145
void setInterpolationQuality(Graphics::ResamplingQuality quality) override
Definition: juce_RenderingHelpers.h:2659
Definition: juce_PixelFormats.h:309
RectangleListRegion(const RectangleList< int > &r)
Definition: juce_RenderingHelpers.h:1773
RectangleList< int > clip
Definition: juce_RenderingHelpers.h:1843
EdgeTableRegion(const Rectangle< int > &bounds, const Path &p, const AffineTransform &t)
Definition: juce_RenderingHelpers.h:1590
void fillRect(const Rectangle< int > &r, bool replace) override
Definition: juce_RenderingHelpers.h:2660
float getScaleFactor() const noexcept
Definition: juce_AffineTransform.cpp:259
void renderGradient(Iterator &iter, const Image::BitmapData &destData, const ColourGradient &g, const AffineTransform &transform, const PixelARGB *const lookupTable, const int numLookupEntries, const bool isIdentity, DestPixelType *)
Definition: juce_RenderingHelpers.h:1523
forcedinline void handleEdgeTablePixel(const int x, int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:806
FloatRectangleRasterisingInfo(const Rectangle< float > &area)
Definition: juce_RenderingHelpers.h:318
StateObjectType & operator*() const noexcept
Definition: juce_RenderingHelpers.h:2596
Rectangle< float > translated(const Rectangle< float > &r) const noexcept
Definition: juce_RenderingHelpers.h:113
static const AffineTransform identity
Definition: juce_AffineTransform.h:78
TransformedImageFill(const Image::BitmapData &dest, const Image::BitmapData &src, const AffineTransform &transform, const int alpha, const Graphics::ResamplingQuality q)
Definition: juce_RenderingHelpers.h:925
Definition: juce_graphics.h:63
Rectangle< int > getMaximumBounds() const
Definition: juce_RenderingHelpers.h:2522
int left
Definition: juce_RenderingHelpers.h:396
#define const
ReferenceCountedObjectPtr< CachedGlyphType > findOrCreateGlyph(const Font &font, int glyphNumber)
Definition: juce_RenderingHelpers.h:183
Definition: juce_RenderingHelpers.h:1549
bool isIdentity() const noexcept
Definition: juce_AffineTransform.cpp:72
void transformAll(const AffineTransform &transform) noexcept
Definition: juce_RectangleList.h:621
Ptr clipToRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1781
forcedinline void handleEdgeTablePixelFull(const int x) const noexcept
Definition: juce_RenderingHelpers.h:743
ValueType getBottom() const noexcept
Definition: juce_Rectangle.h:122
Ptr clipToEdgeTable(const EdgeTable &et)
Definition: juce_RenderingHelpers.h:1628
forcedinline void set(const Pixel &src) noexcept
Definition: juce_PixelFormats.h:443
float getTranslationY() const noexcept
Definition: juce_AffineTransform.h:261
static AffineTransform translation(float deltaX, float deltaY) noexcept
Definition: juce_AffineTransform.cpp:101
CachedGlyphEdgeTable()
Definition: juce_RenderingHelpers.h:280
Definition: juce_RenderingHelpers.h:480
Definition: juce_ReferenceCountedObject.h:65
void fillRectAsPath(const Rectangle< CoordType > &r)
Definition: juce_RenderingHelpers.h:2204
const int numEntries
Definition: juce_RenderingHelpers.h:514
Definition: juce_CriticalSection.h:47
void clipToPath(const Path &p, const AffineTransform &t)
Definition: juce_RenderingHelpers.h:2122
Definition: juce_Image.h:313
Definition: juce_PixelFormats.h:566
Definition: juce_Typeface.h:44
void clipToPath(const Path &path, const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2651
SolidColour(const Image::BitmapData &image, const PixelARGB colour)
Definition: juce_RenderingHelpers.h:579
Definition: juce_Rectangle.h:36
Rectangle< int > getClipBounds() const
Definition: juce_RenderingHelpers.h:2162
void setARGB(const uint8 a, const uint8 r, const uint8 g, const uint8 b) noexcept
Definition: juce_PixelFormats.h:137
RectangleListRegion(const RectangleListRegion &other)
Definition: juce_RenderingHelpers.h:1774
void iterate(Callback &callback) const
Definition: juce_RenderingHelpers.h:378
float mat11
Definition: juce_AffineTransform.h:277
float mat10
Definition: juce_AffineTransform.h:277
bool isOnePixelWide() const noexcept
Definition: juce_RenderingHelpers.h:388
int leftAlpha
Definition: juce_RenderingHelpers.h:398
Point transformedBy(const AffineTransform &transform) const noexcept
Definition: juce_Point.h:203
void fillRect(const Rectangle< float > &r) override
Definition: juce_RenderingHelpers.h:2661
SoftwareRendererSavedState(const SoftwareRendererSavedState &other)
Definition: juce_RenderingHelpers.h:2436
void renderImageTransformed(SavedStateType &state, const Image &src, const int alpha, const AffineTransform &transform, Graphics::ResamplingQuality quality, bool tiledFill) const
Definition: juce_RenderingHelpers.h:1730
AffineTransform getTransform() const noexcept
Definition: juce_RenderingHelpers.h:53
void drawImage(const Image &im, const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2664
int width
Definition: juce_Image.h:352
Definition: juce_PixelFormats.h:309
void saveState() override
Definition: juce_RenderingHelpers.h:2653
void addRectangle(float x, float y, float width, float height)
Definition: juce_Path.cpp:399
Definition: juce_Path.h:62
Point< float > toFloat() const noexcept
Definition: juce_Point.h:214
void fillPath(const Path &path, const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2663
const RectangleType * begin() const noexcept
Definition: juce_RectangleList.h:641
int top
Definition: juce_RenderingHelpers.h:396
FillType fillType
Definition: juce_RenderingHelpers.h:2415
Linear(const ColourGradient &gradient, const AffineTransform &transform, const PixelARGB *const colours, const int numColours)
Definition: juce_RenderingHelpers.h:409
void clipEdgeTableLine(EdgeTable &et, int x, int y_, int width)
Definition: juce_RenderingHelpers.h:989
Definition: juce_graphics.h:55
Rectangle< int > getBounds() const noexcept
Definition: juce_Image.cpp:261
unsigned int uint32
Definition: juce_MathsFunctions.h:51
Ptr clipToRectangleList(const RectangleList< int > &r)
Definition: juce_RenderingHelpers.h:1787
void cloneClipIfMultiplyReferenced()
Definition: juce_RenderingHelpers.h:2407
void fillAllWithColour(SavedStateType &state, const PixelARGB colour, bool replaceContents) const
Definition: juce_RenderingHelpers.h:1823
AffineTransform followedBy(const AffineTransform &other) const noexcept
Definition: juce_AffineTransform.cpp:85
Ptr excludeClipRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1793
Ptr clipToRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1598
void renderImageUntransformed(SavedStateType &state, const Image &src, const int alpha, int x, int y, bool tiledFill) const
Definition: juce_RenderingHelpers.h:1838
SavedStateStack() noexcept
Definition: juce_RenderingHelpers.h:2588
void fillRect(const Rectangle< float > &r)
Definition: juce_RenderingHelpers.h:2231
Definition: juce_PixelFormats.h:610
virtual EdgeTable * getEdgeTableForGlyph(int glyphNumber, const AffineTransform &transform, float fontHeight)
Definition: juce_Typeface.cpp:119
PixelFormat getFormat() const noexcept
Definition: juce_Image.cpp:262
void fillAllWithGradient(SavedStateType &state, ColourGradient &gradient, const AffineTransform &transform, bool isIdentity) const
Definition: juce_RenderingHelpers.h:1828
Definition: juce_Image.h:64
void drawGlyph(int glyphNumber, const AffineTransform &trans)
Definition: juce_RenderingHelpers.h:2479
EdgeTableRegion(const Rectangle< float > &r)
Definition: juce_RenderingHelpers.h:1587
void renderImageUntransformed(SavedStateType &state, const Image &src, const int alpha, int x, int y, bool tiledFill) const
Definition: juce_RenderingHelpers.h:1735
RectangleOrPoint transformed(const RectangleOrPoint &r) const noexcept
Definition: juce_RenderingHelpers.h:120
void restore()
Definition: juce_RenderingHelpers.h:2603
forcedinline void setEdgeTableYPos(const int y) noexcept
Definition: juce_RenderingHelpers.h:732
void clipToImageAlpha(const Image &im, const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2652
void endTransparencyLayer()
Definition: juce_RenderingHelpers.h:2622
void handleEdgeTableLine(int x, int width, int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:818
float getTranslationX() const noexcept
Definition: juce_AffineTransform.h:256
Definition: juce_ReferenceCountedObject.h:227
bool isEmpty() const noexcept
Definition: juce_RectangleList.h:82
IntegerType negativeAwareModulo(IntegerType dividend, const IntegerType divisor) noexcept
Definition: juce_MathsFunctions.h:531
ScopedPointer< EdgeTable > edgeTable
Definition: juce_RenderingHelpers.h:305
int quality
Definition: jpeglib.h:919
bool clipToRectangleList(const RectangleList< int > &r)
Definition: juce_RenderingHelpers.h:2054
void generate(const Font &newFont, const int glyphNumber)
Definition: juce_RenderingHelpers.h:291
Definition: juce_RenderingHelpers.h:576
void draw(RendererType &state, Point< float > pos) const
Definition: juce_RenderingHelpers.h:282
void addTransform(const AffineTransform &t) noexcept
Definition: juce_RenderingHelpers.h:74
Type jmax(const Type a, const Type b)
Definition: juce_core.h:101
forcedinline uint8 getRed() const noexcept
Definition: juce_PixelFormats.h:107
const RectangleType * end() const noexcept
Definition: juce_RectangleList.h:643
volatile Type value
Definition: juce_Atomic.h:153
StateObjectType * operator->() const noexcept
Definition: juce_RenderingHelpers.h:2595
ResamplingQuality
Definition: juce_graphics.h:466
void fillRectWithColour(SavedStateType &state, const Rectangle< int > &area, const PixelARGB colour, bool replaceContents) const
Definition: juce_RenderingHelpers.h:1694
Image image
Definition: juce_RenderingHelpers.h:2572
Rectangle< int > getClipBounds() const override
Definition: juce_RenderingHelpers.h:2645
const PixelARGB *const lookupTable
Definition: juce_RenderingHelpers.h:513
void add(const RectangleType &rect)
Definition: juce_RectangleList.h:108
int bottomAlpha
Definition: juce_RenderingHelpers.h:398
forcedinline void handleEdgeTableLineFull(const int x, int width) noexcept
Definition: juce_RenderingHelpers.h:984
int topAlpha
Definition: juce_RenderingHelpers.h:398
void setOrigin(Point< int > delta) noexcept
Definition: juce_RenderingHelpers.h:65
int totalBottom
Definition: juce_RenderingHelpers.h:397
Rectangle< int > getClipBounds() const
Definition: juce_RenderingHelpers.h:1809
Definition: juce_graphics.h:40
Font font
Definition: juce_RenderingHelpers.h:2573
ValueType getHeight() const noexcept
Definition: juce_graphics.h:117
png_const_structrp png_const_inforp int png_fixed_point * width
Definition: juce_PNGLoader.cpp:2339
ImageFill(const Image::BitmapData &dest, const Image::BitmapData &src, const int alpha, const int x, const int y)
Definition: juce_RenderingHelpers.h:782
void renderImageUntransformed(Iterator &iter, const Image::BitmapData &destData, const Image::BitmapData &srcData, const int alpha, int x, int y, bool tiledFill)
Definition: juce_RenderingHelpers.h:1447
AffineTransform translated(float deltaX, float deltaY) const noexcept
Definition: juce_AffineTransform.cpp:95
void handleEdgeTableLine(const int x, int width, int alphaLevel) noexcept
Definition: juce_RenderingHelpers.h:963
Rectangle< int > getClipBounds() const
Definition: juce_RenderingHelpers.h:1689
Radial(const ColourGradient &gradient, const AffineTransform &, const PixelARGB *const colours, const int numColours)
Definition: juce_RenderingHelpers.h:483
void fillPath(const Path &path, const AffineTransform &t)
Definition: juce_RenderingHelpers.h:2266
SavedStateStack(StateObjectType *const initialState) noexcept
Definition: juce_RenderingHelpers.h:2584
int height
Definition: juce_Image.h:352
void handleEdgeTableLineFull(int x, int width) const noexcept
Definition: juce_RenderingHelpers.h:842
Path toPath() const
Definition: juce_RectangleList.h:629
void renderImageTransformed(IteratorType &iter, const Image &src, const int alpha, const AffineTransform &trans, Graphics::ResamplingQuality quality, bool tiledFill) const
Definition: juce_RenderingHelpers.h:2526
Definition: juce_FillType.h:38
void applyTransform(const AffineTransform &transform) noexcept
Definition: juce_graphics.h:201
Definition: juce_ContainerDeletePolicy.h:44
void fillEdgeTable(const EdgeTable &edgeTable, const float x, const int y)
Definition: juce_RenderingHelpers.h:2272
Point< ValueType > getPointAlongLine(ValueType distanceFromStart) const noexcept
Definition: juce_Line.h:200
Base::Ptr Ptr
Definition: juce_RenderingHelpers.h:1593
Type jlimit(const Type lowerLimit, const Type upperLimit, const Type valueToConstrain) noexcept
Definition: juce_MathsFunctions.h:220
void renderImageUntransformed(IteratorType &iter, const Image &src, const int alpha, int x, int y, bool tiledFill) const
Definition: juce_RenderingHelpers.h:2534
void applyTransform(const AffineTransform &transform) noexcept
Definition: juce_Point.h:200
Ptr clipToImageAlpha(const Image &image, const AffineTransform &transform, const Graphics::ResamplingQuality quality)
Definition: juce_RenderingHelpers.h:1634
int getHeight() const noexcept
Definition: juce_Image.cpp:260
Definition: juce_PixelFormats.h:56
void renderSolidFill(Iterator &iter, const Image::BitmapData &destData, const PixelARGB fillColour, const bool replaceContents, DestPixelType *)
Definition: juce_RenderingHelpers.h:1508
EdgeTableRegion(const EdgeTableRegion &other)
Definition: juce_RenderingHelpers.h:1591
PixelARGB getPixel(const int px) const noexcept
Definition: juce_RenderingHelpers.h:542
Definition: juce_RenderingHelpers.h:922
SavedStateType & getThis() noexcept
Definition: juce_RenderingHelpers.h:2027
StackBasedLowLevelGraphicsContext(SavedStateType *initialState)
Definition: juce_RenderingHelpers.h:2671
Point< int > offset
Definition: juce_RenderingHelpers.h:134
EdgeTable edgeTable
Definition: juce_RenderingHelpers.h:1740
void translate(Point< int > delta)
Definition: juce_RenderingHelpers.h:1807
#define jassert(a)
Definition: juce_PlatformDefs.h:146
Definition: juce_Image.h:306
int totalTop
Definition: juce_RenderingHelpers.h:397
static void clearGlyphCache()
Definition: juce_RenderingHelpers.h:2473
void fillRect(const Rectangle< int > &r, const bool replaceContents)
Definition: juce_RenderingHelpers.h:2211
void clipToRectangle(const Rectangle< int > &r)
Definition: juce_EdgeTable.cpp:673
TranslationOrTransform(const TranslationOrTransform &other) noexcept
Definition: juce_RenderingHelpers.h:47
#define JUCE_DECLARE_NON_COPYABLE(className)
Definition: juce_PlatformDefs.h:191
void addTransform(const AffineTransform &t) override
Definition: juce_RenderingHelpers.h:2643
bool isRotated
Definition: juce_RenderingHelpers.h:135
ValueType getY() const noexcept
Definition: juce_Rectangle.h:110
~GlyphCache()
Definition: juce_RenderingHelpers.h:149
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
Definition: juce_PlatformDefs.h:198
forcedinline void handleEdgeTablePixel(const int x, const int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:738
void fillWithSolidColour(IteratorType &iter, const PixelARGB colour, bool replaceContents) const
Definition: juce_RenderingHelpers.h:2542
Definition: juce_GraphicsContext.h:42
bool isOnlyTranslation() const noexcept
Definition: juce_AffineTransform.cpp:251
void setFillType(const FillType &newFill)
Definition: juce_RenderingHelpers.h:2168
void translate(Point< int > delta)
Definition: juce_RenderingHelpers.h:1679
Definition: juce_Image.h:54
static AffineTransform scale(float factorX, float factorY) noexcept
Definition: juce_AffineTransform.cpp:161
RenderingHelpers::SavedStateStack< SavedStateType > stack
Definition: juce_RenderingHelpers.h:2674
EdgeTableRegion(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1586
Base::Ptr Ptr
Definition: juce_RenderingHelpers.h:1776
int pixelStride
Definition: juce_Image.h:351
bool isClipEmpty() const override
Definition: juce_RenderingHelpers.h:2646
Definition: juce_LowLevelGraphicsContext.h:43
Definition: juce_RenderingHelpers.h:1551
void fillTargetRect(const Rectangle< int > &r, const bool replaceContents)
Definition: juce_RenderingHelpers.h:2173
void endTransparencyLayer(SoftwareRendererSavedState &finishedLayerState)
Definition: juce_RenderingHelpers.h:2459
void setARGB(const uint8, const uint8 red, const uint8 green, const uint8 blue) noexcept
Definition: juce_PixelFormats.h:451
Ptr applyClipTo(const Ptr &target) const
Definition: juce_RenderingHelpers.h:1779
BaseRegionType::Ptr clip
Definition: juce_RenderingHelpers.h:2413
void fillRectList(const RectangleList< float > &list) override
Definition: juce_RenderingHelpers.h:2662
void setHorizontalScale(float scaleFactor)
Definition: juce_Font.cpp:558
void setOrigin(Point< int > o) override
Definition: juce_RenderingHelpers.h:2642
void applyTransform(const AffineTransform &transform) noexcept
Definition: juce_Path.cpp:916
Definition: juce_AffineTransform.h:40
#define nullptr
Definition: juce_CompilerSupport.h:151
Definition: juce_RenderingHelpers.h:779
virtual ~Base()
Definition: juce_RenderingHelpers.h:1555
int lastAccessCount
Definition: juce_RenderingHelpers.h:306
Rectangle getIntersection(const Rectangle &other) const noexcept
Definition: juce_Rectangle.h:609
void addLineSegment(const Line< float > &line, float lineThickness)
Definition: juce_Path.cpp:674
Definition: juce_PixelFormats.h:566
void renderImageTransformed(Iterator &iter, const Image::BitmapData &destData, const Image::BitmapData &srcData, const int alpha, const AffineTransform &transform, Graphics::ResamplingQuality quality, bool tiledFill)
Definition: juce_RenderingHelpers.h:1385
Rectangle< Type > deviceSpaceToUserSpace(const Rectangle< Type > &r) const noexcept
Definition: juce_RenderingHelpers.h:127
bool clipToRectangleList(const RectangleList< int > &r) override
Definition: juce_RenderingHelpers.h:2649
JUCE_API String translate(const String &text)
Definition: juce_core.cpp:198
Definition: juce_RenderingHelpers.h:33
Definition: juce_RenderingHelpers.h:1769
forcedinline void setY(const int y) noexcept
Definition: juce_RenderingHelpers.h:535
void handleEdgeTableLineFull(int x, int width) const noexcept
Definition: juce_RenderingHelpers.h:758
void excludeClipRectangle(const Rectangle< int > &r) override
Definition: juce_RenderingHelpers.h:2650
Definition: juce_RenderingHelpers.h:141
int createLookupTable(const AffineTransform &transform, HeapBlock< PixelARGB > &resultLookupTable) const
Definition: juce_ColourGradient.cpp:181
TranslationOrTransform(Point< int > origin) noexcept
Definition: juce_RenderingHelpers.h:42
forcedinline void handleEdgeTablePixelFull(const int x) noexcept
Definition: juce_RenderingHelpers.h:955
bool isOnlyTranslated
Definition: juce_RenderingHelpers.h:135
Definition: juce_PixelFormats.h:309
const Font & getFont() override
Definition: juce_RenderingHelpers.h:2668
bool isVectorDevice() const override
Definition: juce_RenderingHelpers.h:2641
void fillRectList(const RectangleList< float > &list)
Definition: juce_RenderingHelpers.h:2244
bool snapToIntegerCoordinate
Definition: juce_RenderingHelpers.h:307
Definition: juce_RenderingHelpers.h:2638
Ptr clipToPath(const Path &p, const AffineTransform &transform)
Definition: juce_RenderingHelpers.h:1621
void fillRectWithColour(SavedStateType &state, const Rectangle< float > &area, const PixelARGB colour) const
Definition: juce_RenderingHelpers.h:1817
float getPhysicalPixelScaleFactor() override
Definition: juce_RenderingHelpers.h:2644
void setOpacity(float newOpacity) override
Definition: juce_RenderingHelpers.h:2658
void renderImageTransformed(SavedStateType &state, const Image &src, const int alpha, const AffineTransform &transform, Graphics::ResamplingQuality quality, bool tiledFill) const
Definition: juce_RenderingHelpers.h:1833
SavedStateBase(const SavedStateBase &other)
Definition: juce_RenderingHelpers.h:2020
virtual void renderImageUntransformed(SavedStateType &, const Image &, const int alpha, int x, int y, bool tiledFill) const =0
ValueType getY() const noexcept
Definition: juce_graphics.h:111
forcedinline void setY(const int y) noexcept
Definition: juce_RenderingHelpers.h:497
Definition: juce_PixelFormats.h:566
Definition: juce_RenderingHelpers.h:2421
Definition: juce_graphics.h:39
#define max(x, y)
Definition: os.h:79
Definition: juce_ReferenceCountedObject.h:144
unsigned char uint8
Definition: juce_MathsFunctions.h:43
float mat00
Definition: juce_AffineTransform.h:276
PixelARGB getPixel(const int px) const noexcept
Definition: juce_RenderingHelpers.h:503
void clipToEdgeTable(const EdgeTable &)
Definition: juce_EdgeTable.cpp:733
ClipRegions< SavedStateType >::Base BaseRegionType
Definition: juce_RenderingHelpers.h:2004
bool clipRegionIntersects(const Rectangle< int > &r) const
Definition: juce_RenderingHelpers.h:1808
#define forcedinline
Definition: juce_PlatformDefs.h:294
forcedinline void handleEdgeTablePixelFull(const int x) const noexcept
Definition: juce_RenderingHelpers.h:610
bool clipRegionIntersects(const Rectangle< int > &r) const
Definition: juce_RenderingHelpers.h:2149
forcedinline void handleEdgeTableLine(const int x, const int width, const int alphaLevel) const noexcept
Definition: juce_RenderingHelpers.h:618
float getHeight() const noexcept
Definition: juce_Font.cpp:625
Ptr clipToEdgeTable(const EdgeTable &et)
Definition: juce_RenderingHelpers.h:1800
void fillRectWithColour(SavedStateType &state, const Rectangle< float > &area, const PixelARGB colour) const
Definition: juce_RenderingHelpers.h:1707
bool isRadial
Definition: juce_ColourGradient.h:152
float getHorizontalScale() const noexcept
Definition: juce_Font.cpp:565
float mat01
Definition: juce_AffineTransform.h:276
void moveOriginInDeviceSpace(Point< int > delta) noexcept
Definition: juce_RenderingHelpers.h:99
const Rectangle< int > & getMaximumBounds() const noexcept
Definition: juce_EdgeTable.h:79
Point< float > point1
Definition: juce_ColourGradient.h:145
bool clipToRectangle(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:2029
forcedinline uint8 getAlpha() const noexcept
Definition: juce_PixelFormats.h:106
Ptr applyClipTo(const Ptr &target) const
Definition: juce_RenderingHelpers.h:1596
EdgeTableRegion(const RectangleList< int > &r)
Definition: juce_RenderingHelpers.h:1588
float transparencyLayerAlpha
Definition: juce_RenderingHelpers.h:2417
void fillAllWithGradient(SavedStateType &state, ColourGradient &gradient, const AffineTransform &transform, bool isIdentity) const
Definition: juce_RenderingHelpers.h:1725
RectangleListRegion(const Rectangle< int > &r)
Definition: juce_RenderingHelpers.h:1772
bool isSingularity() const noexcept
Definition: juce_AffineTransform.cpp:229
ValueType x
Definition: juce_Point.h:226
Definition: juce_RenderingHelpers.h:277
Definition: juce_PixelFormats.h:361
int right
Definition: juce_RenderingHelpers.h:396
int bottom
Definition: juce_RenderingHelpers.h:396
ValueType y
Definition: juce_Point.h:227
Font font
Definition: juce_RenderingHelpers.h:304
Definition: juce_RenderingHelpers.h:1582
SoftwareRendererSavedState * beginTransparencyLayer(float opacity)
Definition: juce_RenderingHelpers.h:2441
void clipLineToMask(int x, int y, const uint8 *mask, int maskStride, int numPixels)
Definition: juce_EdgeTable.cpp:768
Ptr clipToPath(const Path &p, const AffineTransform &transform)
Definition: juce_RenderingHelpers.h:1799
bool isEmpty() const noexcept
Definition: juce_Rectangle.h:101