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.

738 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. const float oldOpacity = 1.0f;//xxx state->colour.getFloatAlpha();
  361. const float ramp = oldOpacity / bevelThickness;
  362. for (int i = bevelThickness; --i >= 0;)
  363. {
  364. const float op = useGradient ? ramp * (sharpEdgeOnOutside ? bevelThickness - i : i)
  365. : oldOpacity;
  366. context->setFill (topLeftColour.withMultipliedAlpha (op));
  367. context->fillRect (Rectangle<int> (x + i, y + i, width - i * 2, 1), false);
  368. context->setFill (topLeftColour.withMultipliedAlpha (op * 0.75f));
  369. context->fillRect (Rectangle<int> (x + i, y + i + 1, 1, height - i * 2 - 2), false);
  370. context->setFill (bottomRightColour.withMultipliedAlpha (op));
  371. context->fillRect (Rectangle<int> (x + i, y + height - i - 1, width - i * 2, 1), false);
  372. context->setFill (bottomRightColour.withMultipliedAlpha (op * 0.75f));
  373. context->fillRect (Rectangle<int> (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false);
  374. }
  375. context->restoreState();
  376. }
  377. }
  378. //==============================================================================
  379. void Graphics::fillEllipse (const float x, const float y, const float width, const float height) const
  380. {
  381. // passing in a silly number can cause maths problems in rendering!
  382. jassert (areCoordsSensibleNumbers (x, y, width, height));
  383. Path p;
  384. p.addEllipse (x, y, width, height);
  385. fillPath (p);
  386. }
  387. void Graphics::drawEllipse (const float x, const float y, const float width, const float height,
  388. const float lineThickness) const
  389. {
  390. // passing in a silly number can cause maths problems in rendering!
  391. jassert (areCoordsSensibleNumbers (x, y, width, height));
  392. Path p;
  393. p.addEllipse (x, y, width, height);
  394. strokePath (p, PathStrokeType (lineThickness));
  395. }
  396. void Graphics::fillRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize) const
  397. {
  398. // passing in a silly number can cause maths problems in rendering!
  399. jassert (areCoordsSensibleNumbers (x, y, width, height));
  400. Path p;
  401. p.addRoundedRectangle (x, y, width, height, cornerSize);
  402. fillPath (p);
  403. }
  404. void Graphics::fillRoundedRectangle (const Rectangle<float>& r, const float cornerSize) const
  405. {
  406. fillRoundedRectangle (r.getX(), r.getY(), r.getWidth(), r.getHeight(), cornerSize);
  407. }
  408. void Graphics::drawRoundedRectangle (const float x, const float y, const float width, const float height,
  409. const float cornerSize, const float lineThickness) const
  410. {
  411. // passing in a silly number can cause maths problems in rendering!
  412. jassert (areCoordsSensibleNumbers (x, y, width, height));
  413. Path p;
  414. p.addRoundedRectangle (x, y, width, height, cornerSize);
  415. strokePath (p, PathStrokeType (lineThickness));
  416. }
  417. void Graphics::drawRoundedRectangle (const Rectangle<float>& r, const float cornerSize, const float lineThickness) const
  418. {
  419. drawRoundedRectangle (r.getX(), r.getY(), r.getWidth(), r.getHeight(), cornerSize, lineThickness);
  420. }
  421. void Graphics::drawArrow (const Line<float>& line, const float lineThickness, const float arrowheadWidth, const float arrowheadLength) const
  422. {
  423. Path p;
  424. p.addArrow (line, lineThickness, arrowheadWidth, arrowheadLength);
  425. fillPath (p);
  426. }
  427. void Graphics::fillCheckerBoard (const Rectangle<int>& area,
  428. const int checkWidth, const int checkHeight,
  429. const Colour& colour1, const Colour& colour2) const
  430. {
  431. jassert (checkWidth > 0 && checkHeight > 0); // can't be zero or less!
  432. if (checkWidth > 0 && checkHeight > 0)
  433. {
  434. context->saveState();
  435. if (colour1 == colour2)
  436. {
  437. context->setFill (colour1);
  438. context->fillRect (area, false);
  439. }
  440. else
  441. {
  442. const Rectangle<int> clipped (context->getClipBounds().getIntersection (area));
  443. if (! clipped.isEmpty())
  444. {
  445. context->clipToRectangle (clipped);
  446. const int checkNumX = (clipped.getX() - area.getX()) / checkWidth;
  447. const int checkNumY = (clipped.getY() - area.getY()) / checkHeight;
  448. const int startX = area.getX() + checkNumX * checkWidth;
  449. const int startY = area.getY() + checkNumY * checkHeight;
  450. const int right = clipped.getRight();
  451. const int bottom = clipped.getBottom();
  452. for (int i = 0; i < 2; ++i)
  453. {
  454. context->setFill (i == ((checkNumX ^ checkNumY) & 1) ? colour1 : colour2);
  455. int cy = i;
  456. for (int y = startY; y < bottom; y += checkHeight)
  457. for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2)
  458. context->fillRect (Rectangle<int> (x, y, checkWidth, checkHeight), false);
  459. }
  460. }
  461. }
  462. context->restoreState();
  463. }
  464. }
  465. //==============================================================================
  466. void Graphics::drawVerticalLine (const int x, float top, float bottom) const
  467. {
  468. context->drawVerticalLine (x, top, bottom);
  469. }
  470. void Graphics::drawHorizontalLine (const int y, float left, float right) const
  471. {
  472. context->drawHorizontalLine (y, left, right);
  473. }
  474. void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2) const
  475. {
  476. context->drawLine (Line<float> (x1, y1, x2, y2));
  477. }
  478. void Graphics::drawLine (const Line<float>& line) const
  479. {
  480. context->drawLine (line);
  481. }
  482. void Graphics::drawLine (const float x1, const float y1, const float x2, const float y2, const float lineThickness) const
  483. {
  484. drawLine (Line<float> (x1, y1, x2, y2), lineThickness);
  485. }
  486. void Graphics::drawLine (const Line<float>& line, const float lineThickness) const
  487. {
  488. Path p;
  489. p.addLineSegment (line, lineThickness);
  490. fillPath (p);
  491. }
  492. void Graphics::drawDashedLine (const Line<float>& line, const float* const dashLengths,
  493. const int numDashLengths, const float lineThickness, int n) const
  494. {
  495. jassert (n >= 0 && n < numDashLengths); // your start index must be valid!
  496. const Point<double> delta ((line.getEnd() - line.getStart()).toDouble());
  497. const double totalLen = delta.getDistanceFromOrigin();
  498. if (totalLen >= 0.1)
  499. {
  500. const double onePixAlpha = 1.0 / totalLen;
  501. for (double alpha = 0.0; alpha < 1.0;)
  502. {
  503. jassert (dashLengths[n] > 0); // can't have zero-length dashes!
  504. const double lastAlpha = alpha;
  505. alpha = jmin (1.0, alpha + dashLengths [n] * onePixAlpha);
  506. n = (n + 1) % numDashLengths;
  507. if ((n & 1) != 0)
  508. {
  509. const Line<float> segment (line.getStart() + (delta * lastAlpha).toFloat(),
  510. line.getStart() + (delta * alpha).toFloat());
  511. if (lineThickness != 1.0f)
  512. drawLine (segment, lineThickness);
  513. else
  514. context->drawLine (segment);
  515. }
  516. }
  517. }
  518. }
  519. //==============================================================================
  520. void Graphics::setImageResamplingQuality (const Graphics::ResamplingQuality newQuality)
  521. {
  522. saveStateIfPending();
  523. context->setInterpolationQuality (newQuality);
  524. }
  525. //==============================================================================
  526. void Graphics::drawImageAt (const Image& imageToDraw,
  527. const int topLeftX, const int topLeftY,
  528. const bool fillAlphaChannelWithCurrentBrush) const
  529. {
  530. const int imageW = imageToDraw.getWidth();
  531. const int imageH = imageToDraw.getHeight();
  532. drawImage (imageToDraw,
  533. topLeftX, topLeftY, imageW, imageH,
  534. 0, 0, imageW, imageH,
  535. fillAlphaChannelWithCurrentBrush);
  536. }
  537. void Graphics::drawImageWithin (const Image& imageToDraw,
  538. const int destX, const int destY,
  539. const int destW, const int destH,
  540. const RectanglePlacement& placementWithinTarget,
  541. const bool fillAlphaChannelWithCurrentBrush) const
  542. {
  543. // passing in a silly number can cause maths problems in rendering!
  544. jassert (areCoordsSensibleNumbers (destX, destY, destW, destH));
  545. if (imageToDraw.isValid())
  546. {
  547. const int imageW = imageToDraw.getWidth();
  548. const int imageH = imageToDraw.getHeight();
  549. if (imageW > 0 && imageH > 0)
  550. {
  551. double newX = 0.0, newY = 0.0;
  552. double newW = imageW;
  553. double newH = imageH;
  554. placementWithinTarget.applyTo (newX, newY, newW, newH,
  555. destX, destY, destW, destH);
  556. if (newW > 0 && newH > 0)
  557. {
  558. drawImage (imageToDraw,
  559. roundToInt (newX), roundToInt (newY),
  560. roundToInt (newW), roundToInt (newH),
  561. 0, 0, imageW, imageH,
  562. fillAlphaChannelWithCurrentBrush);
  563. }
  564. }
  565. }
  566. }
  567. void Graphics::drawImage (const Image& imageToDraw,
  568. int dx, int dy, int dw, int dh,
  569. int sx, int sy, int sw, int sh,
  570. const bool fillAlphaChannelWithCurrentBrush) const
  571. {
  572. // passing in a silly number can cause maths problems in rendering!
  573. jassert (areCoordsSensibleNumbers (dx, dy, dw, dh));
  574. jassert (areCoordsSensibleNumbers (sx, sy, sw, sh));
  575. if (imageToDraw.isValid() && context->clipRegionIntersects (Rectangle<int> (dx, dy, dw, dh)))
  576. {
  577. drawImageTransformed (imageToDraw.getClippedImage (Rectangle<int> (sx, sy, sw, sh)),
  578. AffineTransform::scale (dw / (float) sw, dh / (float) sh)
  579. .translated ((float) dx, (float) dy),
  580. fillAlphaChannelWithCurrentBrush);
  581. }
  582. }
  583. void Graphics::drawImageTransformed (const Image& imageToDraw,
  584. const AffineTransform& transform,
  585. const bool fillAlphaChannelWithCurrentBrush) const
  586. {
  587. if (imageToDraw.isValid() && ! context->isClipEmpty())
  588. {
  589. if (fillAlphaChannelWithCurrentBrush)
  590. {
  591. context->saveState();
  592. context->clipToImageAlpha (imageToDraw, transform);
  593. fillAll();
  594. context->restoreState();
  595. }
  596. else
  597. {
  598. context->drawImage (imageToDraw, transform);
  599. }
  600. }
  601. }
  602. //==============================================================================
  603. Graphics::ScopedSaveState::ScopedSaveState (Graphics& g)
  604. : context (g)
  605. {
  606. context.saveState();
  607. }
  608. Graphics::ScopedSaveState::~ScopedSaveState()
  609. {
  610. context.restoreState();
  611. }
  612. END_JUCE_NAMESPACE