Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_RenderingHelpers.h 102KB

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