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.

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