565namespace EdgeTableFillers
568 template <
class PixelType,
bool replaceExisting = false>
572 : destData (image), sourceColour (colour)
574 if (
sizeof (PixelType) == 3 && (
size_t) destData.pixelStride == sizeof (PixelType))
575 areRGBComponentsEqual = sourceColour.getRed() == sourceColour.getGreen()
576 && sourceColour.getGreen() == sourceColour.getBlue();
578 areRGBComponentsEqual =
false;
583 linePixels = (PixelType*) destData.getLinePointer (y);
586 forcedinline void handleEdgeTablePixel (
int x,
int alphaLevel)
const noexcept
589 getPixel (x)->set (sourceColour);
591 getPixel (x)->blend (sourceColour, (
uint32) alphaLevel);
594 forcedinline void handleEdgeTablePixelFull (
int x)
const noexcept
597 getPixel (x)->set (sourceColour);
599 getPixel (x)->blend (sourceColour);
602 forcedinline void handleEdgeTableLine (
int x,
int width,
int alphaLevel)
const noexcept
604 auto p = sourceColour;
605 p.multiplyAlpha (alphaLevel);
607 auto* dest = getPixel (x);
609 if (replaceExisting || p.getAlpha() >= 0xff)
610 replaceLine (dest, p, width);
612 blendLine (dest, p, width);
615 forcedinline void handleEdgeTableLineFull (
int x,
int width)
const noexcept
617 auto* dest = getPixel (x);
619 if (replaceExisting || sourceColour.getAlpha() >= 0xff)
620 replaceLine (dest, sourceColour, width);
622 blendLine (dest, sourceColour, width);
625 void handleEdgeTableRectangle (
int x,
int y,
int width,
int height,
int alphaLevel)
noexcept
627 auto p = sourceColour;
628 p.multiplyAlpha (alphaLevel);
630 setEdgeTableYPos (y);
631 auto* dest = getPixel (x);
633 if (replaceExisting || p.getAlpha() >= 0xff)
635 while (--height >= 0)
637 replaceLine (dest, p, width);
643 while (--height >= 0)
645 blendLine (dest, p, width);
651 void handleEdgeTableRectangleFull (
int x,
int y,
int width,
int height)
noexcept
653 handleEdgeTableRectangle (x, y, width, height, 255);
658 PixelType* linePixels;
660 bool areRGBComponentsEqual;
667 inline void blendLine (PixelType* dest,
PixelARGB colour,
int width)
const noexcept
669 JUCE_PERFORM_PIXEL_OP_LOOP (blend (colour))
674 if ((
size_t) destData.
pixelStride == sizeof (*dest) && areRGBComponentsEqual)
675 memset ((
void*) dest, colour.getRed(), (
size_t) width * 3);
677 JUCE_PERFORM_PIXEL_OP_LOOP (set (colour));
682 if ((
size_t) destData.
pixelStride == sizeof (*dest))
683 memset ((
void*) dest, colour.getAlpha(), (
size_t) width);
685 JUCE_PERFORM_PIXEL_OP_LOOP (setAlpha (colour.getAlpha()))
690 JUCE_PERFORM_PIXEL_OP_LOOP (set (colour))
698 template <
class PixelType,
class GradientType>
702 const PixelARGB* colours,
int numColours)
703 :
GradientType (gradient, transform, colours, numColours - 1),
710 linePixels = (PixelType*) destData.getLinePointer (y);
711 GradientType::setY (y);
714 forcedinline void handleEdgeTablePixel (
int x,
int alphaLevel)
const noexcept
716 getPixel (x)->blend (GradientType::getPixel (x), (
uint32) alphaLevel);
719 forcedinline void handleEdgeTablePixelFull (
int x)
const noexcept
721 getPixel (x)->blend (GradientType::getPixel (x));
724 void handleEdgeTableLine (
int x,
int width,
int alphaLevel)
const noexcept
726 auto* dest = getPixel (x);
728 if (alphaLevel < 0xff)
729 JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++), (
uint32) alphaLevel))
731 JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++)))
734 void handleEdgeTableLineFull (
int x,
int width)
const noexcept
736 auto* dest = getPixel (x);
737 JUCE_PERFORM_PIXEL_OP_LOOP (blend (GradientType::getPixel (x++)))
740 void handleEdgeTableRectangle (
int x,
int y,
int width,
int height,
int alphaLevel)
noexcept
742 while (--height >= 0)
744 setEdgeTableYPos (y++);
745 handleEdgeTableLine (x, width, alphaLevel);
749 void handleEdgeTableRectangleFull (
int x,
int y,
int width,
int height)
noexcept
751 while (--height >= 0)
753 setEdgeTableYPos (y++);
754 handleEdgeTableLineFull (x, width);
760 PixelType* linePixels;
772 template <
class DestPixelType,
class SrcPixelType,
bool repeatPattern>
778 extraAlpha (alpha + 1),
786 linePixels = (DestPixelType*) destData.getLinePointer (y);
795 sourceLineStart = (SrcPixelType*) srcData.getLinePointer (y);
798 forcedinline void handleEdgeTablePixel (
int x,
int alphaLevel)
const noexcept
800 alphaLevel = (alphaLevel * extraAlpha) >> 8;
802 getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (
uint32) alphaLevel);
805 forcedinline void handleEdgeTablePixelFull (
int x)
const noexcept
807 getDestPixel (x)->blend (*getSrcPixel (repeatPattern ? ((x - xOffset) % srcData.width) : (x - xOffset)), (
uint32) extraAlpha);
810 void handleEdgeTableLine (
int x,
int width,
int alphaLevel)
const noexcept
812 auto* dest = getDestPixel (x);
813 alphaLevel = (alphaLevel * extraAlpha) >> 8;
818 if (alphaLevel < 0xfe)
819 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (
uint32) alphaLevel))
821 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width)))
825 jassert (x >= 0 && x + width <= srcData.width);
827 if (alphaLevel < 0xfe)
828 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (
uint32) alphaLevel))
830 copyRow (dest, getSrcPixel (x), width);
834 void handleEdgeTableLineFull (
int x,
int width)
const noexcept
836 auto* dest = getDestPixel (x);
841 if (extraAlpha < 0xfe)
842 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width), (
uint32) extraAlpha))
844 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++ % srcData.width)))
848 jassert (x >= 0 && x + width <= srcData.width);
850 if (extraAlpha < 0xfe)
851 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*getSrcPixel (x++), (
uint32) extraAlpha))
853 copyRow (dest, getSrcPixel (x), width);
857 void handleEdgeTableRectangle (
int x,
int y,
int width,
int height,
int alphaLevel)
noexcept
859 while (--height >= 0)
861 setEdgeTableYPos (y++);
862 handleEdgeTableLine (x, width, alphaLevel);
866 void handleEdgeTableRectangleFull (
int x,
int y,
int width,
int height)
noexcept
868 while (--height >= 0)
870 setEdgeTableYPos (y++);
871 handleEdgeTableLineFull (x, width);
875 void clipEdgeTableLine (
EdgeTable& et,
int x,
int y,
int width)
877 jassert (x - xOffset >= 0 && x + width - xOffset <= srcData.width);
878 auto* s = (SrcPixelType*) srcData.getLinePointer (y - yOffset);
879 auto* mask = (
uint8*) (s + x - xOffset);
881 if (
sizeof (SrcPixelType) ==
sizeof (
PixelARGB))
882 mask += PixelARGB::indexA;
884 et.clipLineToMask (x, y, mask,
sizeof (SrcPixelType), width);
890 const int extraAlpha, xOffset, yOffset;
891 DestPixelType* linePixels;
892 SrcPixelType* sourceLineStart;
894 forcedinline DestPixelType* getDestPixel (
int x)
const noexcept
899 forcedinline SrcPixelType
const* getSrcPixel (
int x)
const noexcept
904 forcedinline void copyRow (DestPixelType* dest, SrcPixelType
const* src,
int width)
const noexcept
909 if (destStride == srcStride
913 memcpy ((
void*) dest, src, (
size_t) (width * srcStride));
922 }
while (--width > 0);
931 template <
class DestPixelType,
class SrcPixelType,
bool repeatPattern>
932 struct TransformedImageFill
936 : interpolator (transform,
941 extraAlpha (alpha + 1),
943 maxX (src.width - 1),
944 maxY (src.height - 1)
946 scratchBuffer.malloc (scratchSize);
952 linePixels = (DestPixelType*) destData.getLinePointer (newY);
955 forcedinline void handleEdgeTablePixel (
int x,
int alphaLevel)
noexcept
960 getDestPixel (x)->blend (p, (
uint32) (alphaLevel * extraAlpha) >> 8);
963 forcedinline void handleEdgeTablePixelFull (
int x)
noexcept
968 getDestPixel (x)->blend (p, (
uint32) extraAlpha);
971 void handleEdgeTableLine (
int x,
int width,
int alphaLevel)
noexcept
973 if (width > (
int) scratchSize)
975 scratchSize = (
size_t) width;
976 scratchBuffer.malloc (scratchSize);
979 SrcPixelType* span = scratchBuffer;
980 generate (span, x, width);
982 auto* dest = getDestPixel (x);
983 alphaLevel *= extraAlpha;
986 if (alphaLevel < 0xfe)
987 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++, (
uint32) alphaLevel))
989 JUCE_PERFORM_PIXEL_OP_LOOP (blend (*span++))
992 forcedinline void handleEdgeTableLineFull (
int x,
int width)
noexcept
994 handleEdgeTableLine (x, width, 255);
997 void handleEdgeTableRectangle (
int x,
int y,
int width,
int height,
int alphaLevel)
noexcept
999 while (--height >= 0)
1001 setEdgeTableYPos (y++);
1002 handleEdgeTableLine (x, width, alphaLevel);
1006 void handleEdgeTableRectangleFull (
int x,
int y,
int width,
int height)
noexcept
1008 while (--height >= 0)
1010 setEdgeTableYPos (y++);
1011 handleEdgeTableLineFull (x, width);
1015 void clipEdgeTableLine (
EdgeTable& et,
int x,
int y,
int width)
1017 if (width > (
int) scratchSize)
1019 scratchSize = (
size_t) width;
1020 scratchBuffer.malloc (scratchSize);
1024 generate (scratchBuffer.get(), x, width);
1026 et.clipLineToMask (x, y,
1027 reinterpret_cast<uint8*
> (scratchBuffer.get()) + SrcPixelType::indexA,
1028 sizeof (SrcPixelType), width);
1032 forcedinline DestPixelType* getDestPixel (
int x)
const noexcept
1038 template <
class PixelType>
1039 void generate (PixelType* dest,
int x,
int numPixels)
noexcept
1041 this->interpolator.setStartOfLine ((
float) x, (
float) currentY, numPixels);
1046 this->interpolator.next (hiResX, hiResY);
1048 int loResX = hiResX >> 8;
1049 int loResY = hiResY >> 8;
1064 render4PixelAverage (dest, this->srcData.
getPixelPointer (loResX, loResY),
1065 hiResX & 255, hiResY & 255);
1070 if (! repeatPattern)
1074 render2PixelAverageX (dest, this->srcData.
getPixelPointer (loResX, 0), hiResX & 255);
1076 render2PixelAverageX (dest, this->srcData.
getPixelPointer (loResX, maxY), hiResX & 255);
1088 render2PixelAverageY (dest, this->srcData.
getPixelPointer (0, loResY), hiResY & 255);
1090 render2PixelAverageY (dest, this->srcData.
getPixelPointer (maxX, loResY), hiResY & 255);
1098 if (! repeatPattern)
1100 if (loResX < 0) loResX = 0;
1101 if (loResY < 0) loResY = 0;
1102 if (loResX > maxX) loResX = maxX;
1103 if (loResY > maxY) loResY = maxY;
1106 dest->set (*(
const PixelType*) this->srcData.getPixelPointer (loResX, loResY));
1109 }
while (--numPixels > 0);
1113 void render4PixelAverage (
PixelARGB* dest,
const uint8* src,
int subPixelX,
int subPixelY)
noexcept
1115 uint32 c[4] = { 256 * 128, 256 * 128, 256 * 128, 256 * 128 };
1117 auto weight = (
uint32) ((256 - subPixelX) * (256 - subPixelY));
1118 c[0] += weight * src[0];
1119 c[1] += weight * src[1];
1120 c[2] += weight * src[2];
1121 c[3] += weight * src[3];
1125 weight = (
uint32) (subPixelX * (256 - subPixelY));
1126 c[0] += weight * src[0];
1127 c[1] += weight * src[1];
1128 c[2] += weight * src[2];
1129 c[3] += weight * src[3];
1131 src += this->srcData.lineStride;
1133 weight = (
uint32) (subPixelX * subPixelY);
1134 c[0] += weight * src[0];
1135 c[1] += weight * src[1];
1136 c[2] += weight * src[2];
1137 c[3] += weight * src[3];
1139 src -= this->srcData.pixelStride;
1141 weight = (
uint32) ((256 - subPixelX) * subPixelY);
1142 c[0] += weight * src[0];
1143 c[1] += weight * src[1];
1144 c[2] += weight * src[2];
1145 c[3] += weight * src[3];
1147 dest->setARGB ((
uint8) (c[PixelARGB::indexA] >> 16),
1148 (
uint8) (c[PixelARGB::indexR] >> 16),
1149 (
uint8) (c[PixelARGB::indexG] >> 16),
1150 (
uint8) (c[PixelARGB::indexB] >> 16));
1155 uint32 c[4] = { 128, 128, 128, 128 };
1157 uint32 weight = 256 - subPixelX;
1158 c[0] += weight * src[0];
1159 c[1] += weight * src[1];
1160 c[2] += weight * src[2];
1161 c[3] += weight * src[3];
1166 c[0] += weight * src[0];
1167 c[1] += weight * src[1];
1168 c[2] += weight * src[2];
1169 c[3] += weight * src[3];
1171 dest->setARGB ((
uint8) (c[PixelARGB::indexA] >> 8),
1172 (
uint8) (c[PixelARGB::indexR] >> 8),
1173 (
uint8) (c[PixelARGB::indexG] >> 8),
1174 (
uint8) (c[PixelARGB::indexB] >> 8));
1179 uint32 c[4] = { 128, 128, 128, 128 };
1181 uint32 weight = 256 - subPixelY;
1182 c[0] += weight * src[0];
1183 c[1] += weight * src[1];
1184 c[2] += weight * src[2];
1185 c[3] += weight * src[3];
1190 c[0] += weight * src[0];
1191 c[1] += weight * src[1];
1192 c[2] += weight * src[2];
1193 c[3] += weight * src[3];
1195 dest->setARGB ((
uint8) (c[PixelARGB::indexA] >> 8),
1196 (
uint8) (c[PixelARGB::indexR] >> 8),
1197 (
uint8) (c[PixelARGB::indexG] >> 8),
1198 (
uint8) (c[PixelARGB::indexB] >> 8));
1204 uint32 c[3] = { 256 * 128, 256 * 128, 256 * 128 };
1206 uint32 weight = (256 - subPixelX) * (256 - subPixelY);
1207 c[0] += weight * src[0];
1208 c[1] += weight * src[1];
1209 c[2] += weight * src[2];
1213 weight = subPixelX * (256 - subPixelY);
1214 c[0] += weight * src[0];
1215 c[1] += weight * src[1];
1216 c[2] += weight * src[2];
1218 src += this->srcData.lineStride;
1220 weight = subPixelX * subPixelY;
1221 c[0] += weight * src[0];
1222 c[1] += weight * src[1];
1223 c[2] += weight * src[2];
1225 src -= this->srcData.pixelStride;
1227 weight = (256 - subPixelX) * subPixelY;
1228 c[0] += weight * src[0];
1229 c[1] += weight * src[1];
1230 c[2] += weight * src[2];
1232 dest->setARGB ((
uint8) 255,
1233 (
uint8) (c[PixelRGB::indexR] >> 16),
1234 (
uint8) (c[PixelRGB::indexG] >> 16),
1235 (
uint8) (c[PixelRGB::indexB] >> 16));
1240 uint32 c[3] = { 128, 128, 128 };
1242 const uint32 weight = 256 - subPixelX;
1243 c[0] += weight * src[0];
1244 c[1] += weight * src[1];
1245 c[2] += weight * src[2];
1249 c[0] += subPixelX * src[0];
1250 c[1] += subPixelX * src[1];
1251 c[2] += subPixelX * src[2];
1253 dest->setARGB ((
uint8) 255,
1254 (
uint8) (c[PixelRGB::indexR] >> 8),
1255 (
uint8) (c[PixelRGB::indexG] >> 8),
1256 (
uint8) (c[PixelRGB::indexB] >> 8));
1261 uint32 c[3] = { 128, 128, 128 };
1263 const uint32 weight = 256 - subPixelY;
1264 c[0] += weight * src[0];
1265 c[1] += weight * src[1];
1266 c[2] += weight * src[2];
1270 c[0] += subPixelY * src[0];
1271 c[1] += subPixelY * src[1];
1272 c[2] += subPixelY * src[2];
1274 dest->setARGB ((
uint8) 255,
1275 (
uint8) (c[PixelRGB::indexR] >> 8),
1276 (
uint8) (c[PixelRGB::indexG] >> 8),
1277 (
uint8) (c[PixelRGB::indexB] >> 8));
1284 c += src[0] * ((256 - subPixelX) * (256 - subPixelY));
1286 c += src[0] * (subPixelX * (256 - subPixelY));
1287 src += this->srcData.lineStride;
1288 c += src[0] * (subPixelX * subPixelY);
1289 src -= this->srcData.pixelStride;
1291 c += src[0] * ((256 - subPixelX) * subPixelY);
1299 c += src[0] * (256 - subPixelX);
1301 c += src[0] * subPixelX;
1308 c += src[0] * (256 - subPixelY);
1310 c += src[0] * subPixelY;
1315 struct TransformedImageSpanInterpolator
1317 TransformedImageSpanInterpolator (
const AffineTransform& transform,
float offsetFloat,
int offsetInt) noexcept
1318 : inverseTransform (transform.inverted()),
1319 pixelOffset (offsetFloat), pixelOffsetInt (offsetInt)
1322 void setStartOfLine (
float sx,
float sy,
int numPixels)
noexcept
1328 auto x1 = sx,
y1 = sy;
1329 sx += (
float) numPixels;
1330 inverseTransform.transformPoints (x1,
y1, sx, sy);
1332 xBresenham.set ((
int) (x1 * 256.0f), (
int) (sx * 256.0f), numPixels, pixelOffsetInt);
1333 yBresenham.set ((
int) (
y1 * 256.0f), (
int) (sy * 256.0f), numPixels, pixelOffsetInt);
1336 void next (
int& px,
int& py)
noexcept
1338 px = xBresenham.n; xBresenham.stepToNext();
1339 py = yBresenham.n; yBresenham.stepToNext();
1343 struct BresenhamInterpolator
1345 BresenhamInterpolator() =
default;
1347 void set (
int n1,
int n2,
int steps,
int offsetInt)
noexcept
1350 step = (n2 - n1) / numSteps;
1351 remainder = modulo = (n2 - n1) % numSteps;
1383 BresenhamInterpolator xBresenham, yBresenham;
1384 const float pixelOffset;
1385 const int pixelOffsetInt;
1391 TransformedImageSpanInterpolator interpolator;
1394 const int extraAlpha;
1396 const int maxX, maxY;
1398 DestPixelType* linePixels;
1400 size_t scratchSize = 2048;
1407 template <
class Iterator>
1417 if (tiledFill) { TransformedImageFill<PixelARGB, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1418 else { TransformedImageFill<PixelARGB, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1421 if (tiledFill) { TransformedImageFill<PixelARGB, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1422 else { TransformedImageFill<PixelARGB, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1425 case Image::UnknownFormat:
1427 if (tiledFill) { TransformedImageFill<PixelARGB, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1428 else { TransformedImageFill<PixelARGB, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1438 if (tiledFill) { TransformedImageFill<PixelRGB, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1439 else { TransformedImageFill<PixelRGB, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1442 if (tiledFill) { TransformedImageFill<PixelRGB, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1443 else { TransformedImageFill<PixelRGB, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1446 case Image::UnknownFormat:
1448 if (tiledFill) { TransformedImageFill<PixelRGB, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1449 else { TransformedImageFill<PixelRGB, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1456 case Image::UnknownFormat:
1461 if (tiledFill) { TransformedImageFill<PixelAlpha, PixelARGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1462 else { TransformedImageFill<PixelAlpha, PixelARGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1465 if (tiledFill) { TransformedImageFill<PixelAlpha, PixelRGB, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1466 else { TransformedImageFill<PixelAlpha, PixelRGB, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1469 case Image::UnknownFormat:
1471 if (tiledFill) { TransformedImageFill<PixelAlpha, PixelAlpha, true> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1472 else { TransformedImageFill<PixelAlpha, PixelAlpha, false> r (destData, srcData, transform, alpha, quality); iter.iterate (r); }
1479 template <
class Iterator>
1488 if (tiledFill) { ImageFill<PixelARGB, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1489 else { ImageFill<PixelARGB, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1492 if (tiledFill) { ImageFill<PixelARGB, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1493 else { ImageFill<PixelARGB, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1496 case Image::UnknownFormat:
1498 if (tiledFill) { ImageFill<PixelARGB, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1499 else { ImageFill<PixelARGB, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1508 if (tiledFill) { ImageFill<PixelRGB, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1509 else { ImageFill<PixelRGB, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1512 if (tiledFill) { ImageFill<PixelRGB, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1513 else { ImageFill<PixelRGB, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1516 case Image::UnknownFormat:
1518 if (tiledFill) { ImageFill<PixelRGB, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1519 else { ImageFill<PixelRGB, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1525 case Image::UnknownFormat:
1530 if (tiledFill) { ImageFill<PixelAlpha, PixelARGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1531 else { ImageFill<PixelAlpha, PixelARGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1534 if (tiledFill) { ImageFill<PixelAlpha, PixelRGB, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1535 else { ImageFill<PixelAlpha, PixelRGB, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1538 case Image::UnknownFormat:
1540 if (tiledFill) { ImageFill<PixelAlpha, PixelAlpha, true> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1541 else { ImageFill<PixelAlpha, PixelAlpha, false> r (destData, srcData, alpha, x, y); iter.iterate (r); }
1548 template <
class Iterator,
class DestPixelType>
1549 void renderSolidFill (Iterator& iter,
const Image::BitmapData& destData,
PixelARGB fillColour,
bool replaceContents, DestPixelType*)
1551 if (replaceContents)
1553 EdgeTableFillers::SolidColour<DestPixelType, true> r (destData, fillColour);
1558 EdgeTableFillers::SolidColour<DestPixelType, false> r (destData, fillColour);
1563 template <
class Iterator,
class DestPixelType>
1565 const PixelARGB* lookupTable,
int numLookupEntries,
bool isIdentity, DestPixelType*)
1571 EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::Radial> renderer (destData, g, transform, lookupTable, numLookupEntries);
1572 iter.iterate (renderer);
1576 EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::TransformedRadial> renderer (destData, g, transform, lookupTable, numLookupEntries);
1577 iter.iterate (renderer);
1582 EdgeTableFillers::Gradient<DestPixelType, GradientPixelIterators::Linear> renderer (destData, g, transform, lookupTable, numLookupEntries);
1583 iter.iterate (renderer);
2050 : clip (
new RectangleListRegionType (initialClip)),
2056 : clip (
new RectangleListRegionType (clipList)), transform (origin),
2062 : clip (other.clip), transform (other.transform), fillType (other.fillType),
2063 interpolationQuality (other.interpolationQuality),
2064 transparencyLayerAlpha (other.transparencyLayerAlpha)
2068 SavedStateType& getThis()
noexcept {
return *
static_cast<SavedStateType*
> (
this); }
2072 if (clip !=
nullptr)
2074 if (transform.isOnlyTranslated)
2076 cloneClipIfMultiplyReferenced();
2077 clip = clip->clipToRectangle (transform.translated (r));
2079 else if (! transform.isRotated)
2081 cloneClipIfMultiplyReferenced();
2082 clip = clip->clipToRectangle (transform.transformed (r));
2092 return clip !=
nullptr;
2097 if (clip !=
nullptr)
2099 if (transform.isOnlyTranslated)
2101 cloneClipIfMultiplyReferenced();
2103 if (transform.isIdentity())
2105 clip = clip->clipToRectangleList (r);
2110 offsetList.
offsetAll (transform.offset);
2111 clip = clip->clipToRectangleList (offsetList);
2114 else if (! transform.isRotated)
2116 cloneClipIfMultiplyReferenced();
2120 scaledList.
add (transform.transformed (i));
2122 clip = clip->clipToRectangleList (scaledList);
2126 clipToPath (r.
toPath(), {});
2130 return clip !=
nullptr;
2140 return { x1,
y1, x2 - x1, y2 -
y1 };
2145 if (clip !=
nullptr)
2147 cloneClipIfMultiplyReferenced();
2149 if (transform.isOnlyTranslated)
2151 clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.translated (r.
toFloat())));
2153 else if (! transform.isRotated)
2155 clip = clip->excludeClipRectangle (getLargestIntegerWithin (transform.transformed (r.
toFloat())));
2164 clip = clip->clipToPath (p, {});
2168 return clip !=
nullptr;
2173 if (clip !=
nullptr)
2175 cloneClipIfMultiplyReferenced();
2176 clip = clip->clipToPath (p, transform.getTransformWith (t));
2182 if (clip !=
nullptr)
2186 cloneClipIfMultiplyReferenced();
2187 clip = clip->clipToImageAlpha (sourceImage, transform.getTransformWith (t), interpolationQuality);
2200 if (clip !=
nullptr)
2202 if (transform.isOnlyTranslated)
2203 return clip->clipRegionIntersects (transform.translated (r));
2213 return clip !=
nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds())
2217 void setFillType (
const FillType& newFill)
2226 clip->fillRectWithColour (getThis(), r, fillType.
colour.
getPixelARGB(), replaceContents);
2230 auto clipped = clip->getClipBounds().getIntersection (r);
2232 if (! clipped.isEmpty())
2233 fillShape (*
new RectangleListRegionType (clipped),
false);
2245 auto clipped = clip->getClipBounds().toFloat().getIntersection (r);
2247 if (! clipped.isEmpty())
2248 fillShape (*
new EdgeTableRegionType (clipped),
false);
2252 template <
typename CoordType>
2262 if (clip !=
nullptr)
2264 if (transform.isOnlyTranslated)
2266 fillTargetRect (transform.translated (r), replaceContents);
2268 else if (! transform.isRotated)
2270 fillTargetRect (transform.transformed (r), replaceContents);
2282 if (clip !=
nullptr)
2284 if (transform.isOnlyTranslated)
2285 fillTargetRect (transform.translated (r));
2286 else if (! transform.isRotated)
2287 fillTargetRect (transform.transformed (r));
2295 if (clip !=
nullptr)
2297 if (list.getNumRectangles() == 1)
2298 return fillRect (*list.begin());
2300 if (transform.isIdentity())
2302 fillShape (*
new EdgeTableRegionType (list),
false);
2304 else if (! transform.isRotated)
2308 if (transform.isOnlyTranslated)
2313 fillShape (*
new EdgeTableRegionType (transformed),
false);
2317 fillPath (list.toPath(), {});
2324 if (clip !=
nullptr)
2326 auto trans = transform.getTransformWith (t);
2327 auto clipRect = clip->getClipBounds();
2330 fillShape (*
new EdgeTableRegionType (clipRect, path, trans),
false);
2334 void fillEdgeTable (
const EdgeTable& edgeTable,
float x,
int y)
2336 if (clip !=
nullptr)
2338 auto* edgeTableClip =
new EdgeTableRegionType (edgeTable);
2339 edgeTableClip->edgeTable.translate (x, y);
2345 if (brightness > 0.0f)
2346 edgeTableClip->edgeTable.multiplyLevels (1.0f + 1.6f * brightness);
2349 fillShape (*edgeTableClip,
false);
2363 renderImage (sourceImage, trans, {});
2366 static bool isOnlyTranslationAllowingError (
const AffineTransform& t,
float tolerance)
noexcept
2368 return std::abs (t.mat01) < tolerance
2369 && std::abs (t.mat10) < tolerance
2370 && std::abs (t.mat00 - 1.0f) < tolerance
2371 && std::abs (t.mat11 - 1.0f) < tolerance;
2374 void renderImage (
const Image& sourceImage,
const AffineTransform& trans,
const BaseRegionType* tiledFillClipRegion)
2376 auto t = transform.getTransformWith (trans);
2379 if (isOnlyTranslationAllowingError (t, 0.002f))
2387 tx = ((tx + 128) >> 8);
2388 ty = ((ty + 128) >> 8);
2390 if (tiledFillClipRegion !=
nullptr)
2392 tiledFillClipRegion->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty,
true);
2400 if (
auto c = clip->applyClipTo (*
new EdgeTableRegionType (area)))
2401 c->renderImageUntransformed (getThis(), sourceImage, alpha, tx, ty,
false);
2410 if (tiledFillClipRegion !=
nullptr)
2412 tiledFillClipRegion->renderImageTransformed (getThis(), sourceImage, alpha,
2413 t, interpolationQuality,
true);
2420 if (
auto c = clip->clone()->clipToPath (p, t))
2421 c->renderImageTransformed (getThis(), sourceImage, alpha,
2422 t, interpolationQuality,
false);
2427 void fillShape (
typename BaseRegionType::Ptr shapeToFill,
bool replaceContents)
2430 shapeToFill = clip->applyClipTo (shapeToFill);
2432 if (shapeToFill !=
nullptr)
2447 g2.point1.applyTransform (t);
2448 g2.point2.applyTransform (t);
2452 shapeToFill->fillAllWithGradient (getThis(), g2, t, isIdentity);
2456 renderImage (fillType.
image, fillType.
transform, shapeToFill.get());
2460 shapeToFill->fillAllWithColour (getThis(), fillType.
colour.
getPixelARGB(), replaceContents);
2465 void cloneClipIfMultiplyReferenced()
2467 if (clip->getReferenceCount() > 1)
2468 clip = clip->clone();
2471 typename BaseRegionType::Ptr clip;
2475 float transparencyLayerAlpha;