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

735 lines
25KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. namespace
  21. {
  22. template <typename Type>
  23. bool areCoordsSensibleNumbers (Type x, Type y, Type w, Type h)
  24. {
  25. const int maxVal = 0x3fffffff;
  26. return (int) x >= -maxVal && (int) x <= maxVal
  27. && (int) y >= -maxVal && (int) y <= maxVal
  28. && (int) w >= -maxVal && (int) w <= maxVal
  29. && (int) h >= -maxVal && (int) h <= maxVal;
  30. }
  31. }
  32. //==============================================================================
  33. LowLevelGraphicsContext::LowLevelGraphicsContext()
  34. {
  35. }
  36. LowLevelGraphicsContext::~LowLevelGraphicsContext()
  37. {
  38. }
  39. //==============================================================================
  40. Graphics::Graphics (const Image& imageToDrawOnto)
  41. : context (imageToDrawOnto.createLowLevelContext()),
  42. contextToDelete (context),
  43. saveStatePending (false)
  44. {
  45. }
  46. Graphics::Graphics (LowLevelGraphicsContext* const internalContext) noexcept
  47. : context (internalContext),
  48. saveStatePending (false)
  49. {
  50. }
  51. Graphics::~Graphics()
  52. {
  53. }
  54. //==============================================================================
  55. void Graphics::resetToDefaultState()
  56. {
  57. saveStateIfPending();
  58. context->setFill (FillType());
  59. context->setFont (Font());
  60. context->setInterpolationQuality (Graphics::mediumResamplingQuality);
  61. }
  62. bool Graphics::isVectorDevice() const
  63. {
  64. return context->isVectorDevice();
  65. }
  66. bool Graphics::reduceClipRegion (const Rectangle<int>& area)
  67. {
  68. saveStateIfPending();
  69. return context->clipToRectangle (area);
  70. }
  71. bool Graphics::reduceClipRegion (const int x, const int y, const int w, const int h)
  72. {
  73. return reduceClipRegion (Rectangle<int> (x, y, w, h));
  74. }
  75. bool Graphics::reduceClipRegion (const RectangleList& clipRegion)
  76. {
  77. saveStateIfPending();
  78. return context->clipToRectangleList (clipRegion);
  79. }
  80. bool Graphics::reduceClipRegion (const Path& path, const AffineTransform& transform)
  81. {
  82. saveStateIfPending();
  83. context->clipToPath (path, transform);
  84. return ! context->isClipEmpty();
  85. }
  86. bool Graphics::reduceClipRegion (const Image& image, const AffineTransform& transform)
  87. {
  88. saveStateIfPending();
  89. context->clipToImageAlpha (image, transform);
  90. return ! context->isClipEmpty();
  91. }
  92. void Graphics::excludeClipRegion (const Rectangle<int>& rectangleToExclude)
  93. {
  94. saveStateIfPending();
  95. context->excludeClipRectangle (rectangleToExclude);
  96. }
  97. bool Graphics::isClipEmpty() const
  98. {
  99. return context->isClipEmpty();
  100. }
  101. Rectangle<int> Graphics::getClipBounds() const
  102. {
  103. return context->getClipBounds();
  104. }
  105. void Graphics::saveState()
  106. {
  107. saveStateIfPending();
  108. saveStatePending = true;
  109. }
  110. void Graphics::restoreState()
  111. {
  112. if (saveStatePending)
  113. saveStatePending = false;
  114. else
  115. context->restoreState();
  116. }
  117. void Graphics::saveStateIfPending()
  118. {
  119. if (saveStatePending)
  120. {
  121. saveStatePending = false;
  122. context->saveState();
  123. }
  124. }
  125. void Graphics::setOrigin (const int newOriginX, const int newOriginY)
  126. {
  127. saveStateIfPending();
  128. context->setOrigin (newOriginX, newOriginY);
  129. }
  130. void Graphics::addTransform (const AffineTransform& transform)
  131. {
  132. saveStateIfPending();
  133. context->addTransform (transform);
  134. }
  135. bool Graphics::clipRegionIntersects (const Rectangle<int>& area) const
  136. {
  137. return context->clipRegionIntersects (area);
  138. }
  139. void Graphics::beginTransparencyLayer (float layerOpacity)
  140. {
  141. saveStateIfPending();
  142. context->beginTransparencyLayer (layerOpacity);
  143. }
  144. void Graphics::endTransparencyLayer()
  145. {
  146. context->endTransparencyLayer();
  147. }
  148. //==============================================================================
  149. void Graphics::setColour (const Colour& newColour)
  150. {
  151. saveStateIfPending();
  152. context->setFill (newColour);
  153. }
  154. void Graphics::setOpacity (const float newOpacity)
  155. {
  156. saveStateIfPending();
  157. context->setOpacity (newOpacity);
  158. }
  159. void Graphics::setGradientFill (const ColourGradient& gradient)
  160. {
  161. setFillType (gradient);
  162. }
  163. void Graphics::setTiledImageFill (const Image& imageToUse, const int anchorX, const int anchorY, const float opacity)
  164. {
  165. saveStateIfPending();
  166. context->setFill (FillType (imageToUse, AffineTransform::translation ((float) anchorX, (float) anchorY)));
  167. context->setOpacity (opacity);
  168. }
  169. void Graphics::setFillType (const FillType& newFill)
  170. {
  171. saveStateIfPending();
  172. context->setFill (newFill);
  173. }
  174. //==============================================================================
  175. void Graphics::setFont (const Font& newFont)
  176. {
  177. saveStateIfPending();
  178. context->setFont (newFont);
  179. }
  180. void Graphics::setFont (const float newFontHeight, const int newFontStyleFlags)
  181. {
  182. saveStateIfPending();
  183. Font f (context->getFont());
  184. f.setSizeAndStyle (newFontHeight, newFontStyleFlags, 1.0f, 0);
  185. context->setFont (f);
  186. }
  187. Font Graphics::getCurrentFont() const
  188. {
  189. return context->getFont();
  190. }
  191. //==============================================================================
  192. void Graphics::drawSingleLineText (const String& text, const int startX, const int baselineY,
  193. const Justification& justification) const
  194. {
  195. if (text.isNotEmpty()
  196. && startX < context->getClipBounds().getRight())
  197. {
  198. GlyphArrangement arr;
  199. arr.addLineOfText (context->getFont(), text, (float) startX, (float) baselineY);
  200. // Don't pass any vertical placement flags to this method - they'll be ignored.
  201. jassert (justification.getOnlyVerticalFlags() == 0);
  202. const int flags = justification.getOnlyHorizontalFlags();
  203. if (flags != Justification::left)
  204. {
  205. float w = arr.getBoundingBox (0, -1, true).getWidth();
  206. if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0)
  207. w /= 2.0f;
  208. arr.draw (*this, AffineTransform::translation (-w, 0));
  209. }
  210. else
  211. {
  212. arr.draw (*this);
  213. }
  214. }
  215. }
  216. void Graphics::drawTextAsPath (const String& text, const AffineTransform& transform) const
  217. {
  218. if (text.isNotEmpty())
  219. {
  220. GlyphArrangement arr;
  221. arr.addLineOfText (context->getFont(), text, 0.0f, 0.0f);
  222. arr.draw (*this, transform);
  223. }
  224. }
  225. void Graphics::drawMultiLineText (const String& text, const int startX, const int baselineY, const int maximumLineWidth) const
  226. {
  227. if (text.isNotEmpty()
  228. && startX < context->getClipBounds().getRight())
  229. {
  230. GlyphArrangement arr;
  231. arr.addJustifiedText (context->getFont(), text,
  232. (float) startX, (float) baselineY, (float) maximumLineWidth,
  233. Justification::left);
  234. arr.draw (*this);
  235. }
  236. }
  237. void Graphics::drawText (const String& text,
  238. const int x, const int y, const int width, const int height,
  239. const Justification& justificationType,
  240. const bool useEllipsesIfTooBig) const
  241. {
  242. if (text.isNotEmpty() && context->clipRegionIntersects (Rectangle<int> (x, y, width, height)))
  243. {
  244. GlyphArrangement arr;
  245. arr.addCurtailedLineOfText (context->getFont(), text,
  246. 0.0f, 0.0f, (float) width,
  247. useEllipsesIfTooBig);
  248. arr.justifyGlyphs (0, arr.getNumGlyphs(),
  249. (float) x, (float) y, (float) width, (float) height,
  250. justificationType);
  251. arr.draw (*this);
  252. }
  253. }
  254. void Graphics::drawFittedText (const String& text,
  255. const int x, const int y, const int width, const int height,
  256. const Justification& justification,
  257. const int maximumNumberOfLines,
  258. const float minimumHorizontalScale) const
  259. {
  260. if (text.isNotEmpty()
  261. && width > 0 && height > 0
  262. && context->clipRegionIntersects (Rectangle<int> (x, y, width, height)))
  263. {
  264. GlyphArrangement arr;
  265. arr.addFittedText (context->getFont(), text,
  266. (float) x, (float) y, (float) width, (float) height,
  267. justification,
  268. maximumNumberOfLines,
  269. minimumHorizontalScale);
  270. arr.draw (*this);
  271. }
  272. }
  273. //==============================================================================
  274. void Graphics::fillRect (int x, int y, int width, int height) const
  275. {
  276. // passing in a silly number can cause maths problems in rendering!
  277. jassert (areCoordsSensibleNumbers (x, y, width, height));
  278. context->fillRect (Rectangle<int> (x, y, width, height), false);
  279. }
  280. void Graphics::fillRect (const Rectangle<int>& r) const
  281. {
  282. context->fillRect (r, false);
  283. }
  284. void Graphics::fillRect (const float x, const float y, const float width, const float height) const
  285. {
  286. // passing in a silly number can cause maths problems in rendering!
  287. jassert (areCoordsSensibleNumbers (x, y, width, height));
  288. Path p;
  289. p.addRectangle (x, y, width, height);
  290. fillPath (p);
  291. }
  292. void Graphics::setPixel (int x, int y) const
  293. {
  294. context->fillRect (Rectangle<int> (x, y, 1, 1), false);
  295. }
  296. void Graphics::fillAll() const
  297. {
  298. fillRect (context->getClipBounds());
  299. }
  300. void Graphics::fillAll (const Colour& colourToUse) const
  301. {
  302. if (! colourToUse.isTransparent())
  303. {
  304. const Rectangle<int> clip (context->getClipBounds());
  305. context->saveState();
  306. context->setFill (colourToUse);
  307. context->fillRect (clip, false);
  308. context->restoreState();
  309. }
  310. }
  311. //==============================================================================
  312. void Graphics::fillPath (const Path& path, const AffineTransform& transform) const
  313. {
  314. if ((! context->isClipEmpty()) && ! path.isEmpty())
  315. context->fillPath (path, transform);
  316. }
  317. void Graphics::strokePath (const Path& path,
  318. const PathStrokeType& strokeType,
  319. const AffineTransform& transform) const
  320. {
  321. Path stroke;
  322. strokeType.createStrokedPath (stroke, path, transform, context->getScaleFactor());
  323. fillPath (stroke);
  324. }
  325. //==============================================================================
  326. void Graphics::drawRect (const int x, const int y, const int width, const int height,
  327. const int lineThickness) const
  328. {
  329. // passing in a silly number can cause maths problems in rendering!
  330. jassert (areCoordsSensibleNumbers (x, y, width, height));
  331. context->fillRect (Rectangle<int> (x, y, width, lineThickness), false);
  332. context->fillRect (Rectangle<int> (x, y + lineThickness, lineThickness, height - lineThickness * 2), false);
  333. context->fillRect (Rectangle<int> (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2), false);
  334. context->fillRect (Rectangle<int> (x, y + height - lineThickness, width, lineThickness), false);
  335. }
  336. void Graphics::drawRect (const float x, const float y, const float width, const float height, const float lineThickness) const
  337. {
  338. // passing in a silly number can cause maths problems in rendering!
  339. jassert (areCoordsSensibleNumbers (x, y, width, height));
  340. Path p;
  341. p.addRectangle (x, y, width, lineThickness);
  342. p.addRectangle (x, y + lineThickness, lineThickness, height - lineThickness * 2.0f);
  343. p.addRectangle (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2.0f);
  344. p.addRectangle (x, y + height - lineThickness, width, lineThickness);
  345. fillPath (p);
  346. }
  347. void Graphics::drawRect (const Rectangle<int>& r, const int lineThickness) const
  348. {
  349. drawRect (r.getX(), r.getY(), r.getWidth(), r.getHeight(), lineThickness);
  350. }
  351. void Graphics::drawBevel (const int x, const int y, const int width, const int height,
  352. const int bevelThickness, const Colour& topLeftColour, const Colour& bottomRightColour,
  353. const bool useGradient, const bool sharpEdgeOnOutside) const
  354. {
  355. // passing in a silly number can cause maths problems in rendering!
  356. jassert (areCoordsSensibleNumbers (x, y, width, height));
  357. if (clipRegionIntersects (Rectangle<int> (x, y, width, height)))
  358. {
  359. context->saveState();
  360. for (int i = bevelThickness; --i >= 0;)
  361. {
  362. const float op = useGradient ? (sharpEdgeOnOutside ? bevelThickness - i : i) / (float) bevelThickness
  363. : 1.0f;
  364. context->setFill (topLeftColour.withMultipliedAlpha (op));
  365. context->fillRect (Rectangle<int> (x + i, y + i, width - i * 2, 1), false);
  366. context->setFill (topLeftColour.withMultipliedAlpha (op * 0.75f));
  367. context->fillRect (Rectangle<int> (x + i, y + i + 1, 1, height - i * 2 - 2), false);
  368. context->setFill (bottomRightColour.withMultipliedAlpha (op));
  369. context->fillRect (Rectangle<int> (x + i, y + height - i - 1, width - i * 2, 1), false);
  370. context->setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f));
  371. context->fillRect (Rectangle<int> (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false);
  372. }
  373. context->restoreState();
  374. }
  375. }
  376. //==============================================================================
  377. void Graphics::fillEllipse (const float x, const float y, const float width, const float height) const
  378. {
  379. // passing in a silly number can cause maths problems in rendering!
  380. jassert (areCoordsSensibleNumbers (x, y, width, height));
  381. Path p;
  382. p.addEllipse (x, y, width, height);
  383. fillPath (p);
  384. }
  385. void Graphics::drawEllipse (const float x, const float y, const float width, const float height,
  386. const float lineThickness) const
  387. {
  388. // passing in a silly number can cause maths problems in rendering!
  389. jassert (areCoordsSensibleNumbers (x, y, width, height));
  390. Path p;
  391. p.addEllipse (x, y, width, height);
  392. strokePath (p, PathStrokeType (lineThickness));
  393. }
  394. void Graphics::fillRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize) const
  395. {
  396. // passing in a silly number can cause maths problems in rendering!
  397. jassert (areCoordsSensibleNumbers (x, y, width, height));
  398. Path p;
  399. p.addRoundedRectangle (x, y, width, height, cornerSize);
  400. fillPath (p);
  401. }
  402. void Graphics::fillRoundedRectangle (const Rectangle<float>& r, const float cornerSize) const
  403. {
  404. fillRoundedRectangle (r.getX(), r.getY(), r.getWidth(), r.getHeight(), cornerSize);
  405. }
  406. void Graphics::drawRoundedRectangle (const float x, const float y, const float width, const float height,
  407. const float cornerSize, const float lineThickness) const
  408. {
  409. // passing in a silly number can cause maths problems in rendering!
  410. jassert (areCoordsSensibleNumbers (x, y, width, height));
  411. Path p;
  412. p.addRoundedRectangle (x, y, width, height, cornerSize);
  413. strokePath (p, PathStrokeType (lineThickness));
  414. }
  415. void Graphics::drawRoundedRectangle (const Rectangle<float>& r, const float cornerSize, const float lineThickness) const
  416. {
  417. drawRoundedRectangle (r.getX(), r.getY(), r.getWidth(), r.getHeight(), cornerSize, lineThickness);
  418. }
  419. void Graphics::drawArrow (const Line<float>& line, const float lineThickness, const float arrowheadWidth, const float arrowheadLength) const
  420. {
  421. Path p;
  422. p.addArrow (line, lineThickness, arrowheadWidth, arrowheadLength);
  423. fillPath (p);
  424. }
  425. void Graphics::fillCheckerBoard (const Rectangle<int>& area,
  426. const int checkWidth, const int checkHeight,
  427. const Colour& colour1, const Colour& colour2) const
  428. {
  429. jassert (checkWidth > 0 && checkHeight > 0); // can't be zero or less!
  430. if (checkWidth > 0 && checkHeight > 0)
  431. {
  432. context->saveState();
  433. if (colour1 == colour2)
  434. {
  435. context->setFill (colour1);
  436. context->fillRect (area, false);
  437. }
  438. else
  439. {
  440. const Rectangle<int> clipped (context->getClipBounds().getIntersection (area));
  441. if (! clipped.isEmpty())
  442. {
  443. context->clipToRectangle (clipped);
  444. const int checkNumX = (clipped.getX() - area.getX()) / checkWidth;
  445. const int checkNumY = (clipped.getY() - area.getY()) / checkHeight;
  446. const int startX = area.getX() + checkNumX * checkWidth;
  447. const int startY = area.getY() + checkNumY * checkHeight;
  448. const int right = clipped.getRight();
  449. const int bottom = clipped.getBottom();
  450. for (int i = 0; i < 2; ++i)
  451. {
  452. context->setFill (i == ((checkNumX ^ checkNumY) & 1) ? colour1 : colour2);
  453. int cy = i;
  454. for (int y = startY; y < bottom; y += checkHeight)
  455. for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2)
  456. context->fillRect (Rectangle<int> (x, y, checkWidth, checkHeight), false);
  457. }
  458. }
  459. }
  460. context->restoreState();
  461. }
  462. }
  463. //==============================================================================
  464. void Graphics::drawVerticalLine (const int x, float top, float bottom) const
  465. {
  466. context->drawVerticalLine (x, top, bottom);
  467. }
  468. void Graphics::drawHorizontalLine (const int y, float left, float right) const
  469. {
  470. context->drawHorizontalLine (y, left, right);
  471. }
  472. void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2) const
  473. {
  474. context->drawLine (Line<float> (x1, y1, x2, y2));
  475. }
  476. void Graphics::drawLine (const Line<float>& line) const
  477. {
  478. context->drawLine (line);
  479. }
  480. void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2, const float lineThickness) const
  481. {
  482. drawLine (Line<float> (x1, y1, x2, y2), lineThickness);
  483. }
  484. void Graphics::drawLine (const Line<float>& line, const float lineThickness) const
  485. {
  486. Path p;
  487. p.addLineSegment (line, lineThickness);
  488. fillPath (p);
  489. }
  490. void Graphics::drawDashedLine (const Line<float>& line, const float* const dashLengths,
  491. const int numDashLengths, const float lineThickness, int n) const
  492. {
  493. jassert (n >= 0 && n < numDashLengths); // your start index must be valid!
  494. const Point<double> delta ((line.getEnd() - line.getStart()).toDouble());
  495. const double totalLen = delta.getDistanceFromOrigin();
  496. if (totalLen >= 0.1)
  497. {
  498. const double onePixAlpha = 1.0 / totalLen;
  499. for (double alpha = 0.0; alpha < 1.0;)
  500. {
  501. jassert (dashLengths[n] > 0); // can't have zero-length dashes!
  502. const double lastAlpha = alpha;
  503. alpha += dashLengths [n] * onePixAlpha;
  504. n = (n + 1) % numDashLengths;
  505. if ((n & 1) != 0)
  506. {
  507. const Line<float> segment (line.getStart() + (delta * lastAlpha).toFloat(),
  508. line.getStart() + (delta * jmin (1.0, alpha)).toFloat());
  509. if (lineThickness != 1.0f)
  510. drawLine (segment, lineThickness);
  511. else
  512. context->drawLine (segment);
  513. }
  514. }
  515. }
  516. }
  517. //==============================================================================
  518. void Graphics::setImageResamplingQuality (const Graphics::ResamplingQuality newQuality)
  519. {
  520. saveStateIfPending();
  521. context->setInterpolationQuality (newQuality);
  522. }
  523. //==============================================================================
  524. void Graphics::drawImageAt (const Image& imageToDraw,
  525. const int topLeftX, const int topLeftY,
  526. const bool fillAlphaChannelWithCurrentBrush) const
  527. {
  528. const int imageW = imageToDraw.getWidth();
  529. const int imageH = imageToDraw.getHeight();
  530. drawImage (imageToDraw,
  531. topLeftX, topLeftY, imageW, imageH,
  532. 0, 0, imageW, imageH,
  533. fillAlphaChannelWithCurrentBrush);
  534. }
  535. void Graphics::drawImageWithin (const Image& imageToDraw,
  536. const int destX, const int destY,
  537. const int destW, const int destH,
  538. const RectanglePlacement& placementWithinTarget,
  539. const bool fillAlphaChannelWithCurrentBrush) const
  540. {
  541. // passing in a silly number can cause maths problems in rendering!
  542. jassert (areCoordsSensibleNumbers (destX, destY, destW, destH));
  543. if (imageToDraw.isValid())
  544. {
  545. const int imageW = imageToDraw.getWidth();
  546. const int imageH = imageToDraw.getHeight();
  547. if (imageW > 0 && imageH > 0)
  548. {
  549. double newX = 0.0, newY = 0.0;
  550. double newW = imageW;
  551. double newH = imageH;
  552. placementWithinTarget.applyTo (newX, newY, newW, newH,
  553. destX, destY, destW, destH);
  554. if (newW > 0 && newH > 0)
  555. {
  556. drawImage (imageToDraw,
  557. roundToInt (newX), roundToInt (newY),
  558. roundToInt (newW), roundToInt (newH),
  559. 0, 0, imageW, imageH,
  560. fillAlphaChannelWithCurrentBrush);
  561. }
  562. }
  563. }
  564. }
  565. void Graphics::drawImage (const Image& imageToDraw,
  566. int dx, int dy, int dw, int dh,
  567. int sx, int sy, int sw, int sh,
  568. const bool fillAlphaChannelWithCurrentBrush) const
  569. {
  570. // passing in a silly number can cause maths problems in rendering!
  571. jassert (areCoordsSensibleNumbers (dx, dy, dw, dh));
  572. jassert (areCoordsSensibleNumbers (sx, sy, sw, sh));
  573. if (imageToDraw.isValid() && context->clipRegionIntersects (Rectangle<int> (dx, dy, dw, dh)))
  574. {
  575. drawImageTransformed (imageToDraw.getClippedImage (Rectangle<int> (sx, sy, sw, sh)),
  576. AffineTransform::scale (dw / (float) sw, dh / (float) sh)
  577. .translated ((float) dx, (float) dy),
  578. fillAlphaChannelWithCurrentBrush);
  579. }
  580. }
  581. void Graphics::drawImageTransformed (const Image& imageToDraw,
  582. const AffineTransform& transform,
  583. const bool fillAlphaChannelWithCurrentBrush) const
  584. {
  585. if (imageToDraw.isValid() && ! context->isClipEmpty())
  586. {
  587. if (fillAlphaChannelWithCurrentBrush)
  588. {
  589. context->saveState();
  590. context->clipToImageAlpha (imageToDraw, transform);
  591. fillAll();
  592. context->restoreState();
  593. }
  594. else
  595. {
  596. context->drawImage (imageToDraw, transform);
  597. }
  598. }
  599. }
  600. //==============================================================================
  601. Graphics::ScopedSaveState::ScopedSaveState (Graphics& g)
  602. : context (g)
  603. {
  604. context.saveState();
  605. }
  606. Graphics::ScopedSaveState::~ScopedSaveState()
  607. {
  608. context.restoreState();
  609. }
  610. END_JUCE_NAMESPACE