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.

727 lines
24KB

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