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.

398 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. // (This file gets included by juce_android_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext
  23. {
  24. public:
  25. AndroidLowLevelGraphicsContext (const GlobalRef& canvas_)
  26. : canvas (canvas_),
  27. currentState (new SavedState())
  28. {
  29. setFill (Colours::black);
  30. }
  31. ~AndroidLowLevelGraphicsContext()
  32. {
  33. }
  34. bool isVectorDevice() const { return false; }
  35. //==============================================================================
  36. void setOrigin (int x, int y)
  37. {
  38. canvas.callVoidMethod (android.translate, (float) x, (float) y);
  39. }
  40. void addTransform (const AffineTransform& transform)
  41. {
  42. canvas.callVoidMethod (android.concat, createMatrix (getEnv(), transform).get());
  43. }
  44. float getScaleFactor()
  45. {
  46. return 1.0f;
  47. }
  48. bool clipToRectangle (const Rectangle<int>& r)
  49. {
  50. return canvas.callBooleanMethod (android.clipRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom());
  51. }
  52. bool clipToRectangleList (const RectangleList& clipRegion)
  53. {
  54. return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get());
  55. }
  56. void excludeClipRectangle (const Rectangle<int>& r)
  57. {
  58. }
  59. void clipToPath (const Path& path, const AffineTransform& transform)
  60. {
  61. (void) canvas.callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get());
  62. }
  63. void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
  64. {
  65. }
  66. bool clipRegionIntersects (const Rectangle<int>& r)
  67. {
  68. return getClipBounds().intersects (r);
  69. }
  70. const Rectangle<int> getClipBounds() const
  71. {
  72. JNIEnv* env = getEnv();
  73. const LocalRef<jobject> rect (canvas.callObjectMethod (android.getClipBounds2));
  74. const int left = env->GetIntField (rect, android.rectLeft);
  75. const int top = env->GetIntField (rect, android.rectTop);
  76. const int right = env->GetIntField (rect, android.rectRight);
  77. const int bottom = env->GetIntField (rect, android.rectBottom);
  78. return Rectangle<int> (left, top, right - left, bottom - top);
  79. }
  80. bool isClipEmpty() const
  81. {
  82. LocalRef<jobject> tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0));
  83. return ! canvas.callBooleanMethod (android.getClipBounds, tempRect.get());
  84. }
  85. //==============================================================================
  86. void setFill (const FillType& fillType)
  87. {
  88. currentState->setFillType (fillType);
  89. }
  90. void setOpacity (float newOpacity)
  91. {
  92. }
  93. void setInterpolationQuality (Graphics::ResamplingQuality quality)
  94. {
  95. }
  96. //==============================================================================
  97. void fillRect (const Rectangle<int>& r, bool replaceExistingContents)
  98. {
  99. canvas.callVoidMethod (android.drawRect,
  100. (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(),
  101. getCurrentPaint());
  102. }
  103. void fillPath (const Path& path, const AffineTransform& transform)
  104. {
  105. canvas.callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(),
  106. getCurrentPaint());
  107. }
  108. void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles)
  109. {
  110. }
  111. void drawLine (const Line <float>& line)
  112. {
  113. canvas.callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(),
  114. line.getEndX(), line.getEndY(),
  115. getCurrentPaint());
  116. }
  117. void drawVerticalLine (int x, float top, float bottom)
  118. {
  119. canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint());
  120. }
  121. void drawHorizontalLine (int y, float left, float right)
  122. {
  123. canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint());
  124. }
  125. void setFont (const Font& newFont)
  126. {
  127. }
  128. const Font getFont()
  129. {
  130. return Font();
  131. }
  132. void drawGlyph (int glyphNumber, const AffineTransform& transform)
  133. {
  134. }
  135. //==============================================================================
  136. void saveState()
  137. {
  138. (void) canvas.callIntMethod (android.save);
  139. stateStack.add (new SavedState (*currentState));
  140. }
  141. void restoreState()
  142. {
  143. canvas.callVoidMethod (android.restore);
  144. SavedState* const top = stateStack.getLast();
  145. if (top != 0)
  146. {
  147. currentState = top;
  148. stateStack.removeLast (1, false);
  149. }
  150. else
  151. {
  152. jassertfalse; // trying to pop with an empty stack!
  153. }
  154. }
  155. void beginTransparencyLayer (float opacity)
  156. {
  157. }
  158. void endTransparencyLayer()
  159. {
  160. }
  161. class SavedState
  162. {
  163. public:
  164. SavedState()
  165. : font (1.0f), needsUpdate (true)
  166. {
  167. }
  168. SavedState (const SavedState& other)
  169. : fillType (other.fillType), font (other.font), needsUpdate (true)
  170. {
  171. }
  172. void setFillType (const FillType& newType)
  173. {
  174. needsUpdate = true;
  175. fillType = newType;
  176. }
  177. jobject getPaint()
  178. {
  179. if (needsUpdate)
  180. {
  181. JNIEnv* env = getEnv();
  182. if (paint.get() == 0)
  183. {
  184. paint = GlobalRef (env->NewObject (android.paintClass, android.paintClassConstructor));
  185. paint.callVoidMethod (android.setAntiAlias, true);
  186. }
  187. if (fillType.isColour())
  188. {
  189. paint.callObjectMethod (android.setShader, (jobject) 0);
  190. paint.callVoidMethod (android.setColor, colourToInt (fillType.colour));
  191. }
  192. else if (fillType.isGradient())
  193. {
  194. const ColourGradient& g = *fillType.gradient;
  195. const Point<float> p1 (g.point1);
  196. const Point<float> p2 (g.point2);
  197. const int numColours = g.getNumColours();
  198. jintArray coloursArray = env->NewIntArray (numColours);
  199. jfloatArray positionsArray = env->NewFloatArray (numColours);
  200. {
  201. HeapBlock<int> colours (numColours);
  202. HeapBlock<float> positions (numColours);
  203. for (int i = 0; i < numColours; ++i)
  204. {
  205. colours[i] = colourToInt (g.getColour (i));
  206. positions[i] = (float) g.getColourPosition(i);
  207. }
  208. env->SetIntArrayRegion (coloursArray, 0, numColours, colours.getData());
  209. env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData());
  210. }
  211. jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode);
  212. jobject shader;
  213. if (fillType.gradient->isRadial)
  214. {
  215. shader = env->NewObject (android.radialGradientClass,
  216. android.radialGradientConstructor,
  217. p1.getX(), p1.getY(),
  218. p1.getDistanceFrom (p2),
  219. coloursArray, positionsArray,
  220. tileMode);
  221. }
  222. else
  223. {
  224. shader = env->NewObject (android.linearGradientClass,
  225. android.linearGradientConstructor,
  226. p1.getX(), p1.getY(), p2.getX(), p2.getY(),
  227. coloursArray, positionsArray,
  228. tileMode);
  229. }
  230. env->DeleteLocalRef (coloursArray);
  231. env->DeleteLocalRef (positionsArray);
  232. env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (env, fillType.transform).get());
  233. paint.callObjectMethod (android.setShader, shader);
  234. env->DeleteLocalRef (shader);
  235. }
  236. else
  237. {
  238. }
  239. }
  240. return paint.get();
  241. }
  242. private:
  243. FillType fillType;
  244. Font font;
  245. GlobalRef paint;
  246. bool needsUpdate;
  247. };
  248. private:
  249. GlobalRef canvas;
  250. ScopedPointer <SavedState> currentState;
  251. OwnedArray <SavedState> stateStack;
  252. jobject getCurrentPaint() const
  253. {
  254. return currentState->getPaint();
  255. }
  256. static const LocalRef<jobject> createPath (JNIEnv* env, const Path& path)
  257. {
  258. jobject p = env->NewObject (android.pathClass, android.pathClassConstructor);
  259. Path::Iterator i (path);
  260. while (i.next())
  261. {
  262. switch (i.elementType)
  263. {
  264. case Path::Iterator::startNewSubPath: env->CallVoidMethod (p, android.moveTo, i.x1, i.y1); break;
  265. case Path::Iterator::lineTo: env->CallVoidMethod (p, android.lineTo, i.x1, i.y1); break;
  266. case Path::Iterator::quadraticTo: env->CallVoidMethod (p, android.quadTo, i.x1, i.y1, i.x2, i.y2); break;
  267. case Path::Iterator::cubicTo: env->CallVoidMethod (p, android.cubicTo, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break;
  268. case Path::Iterator::closePath: env->CallVoidMethod (p, android.closePath); break;
  269. default: jassertfalse; break;
  270. }
  271. }
  272. return LocalRef<jobject> (p);
  273. }
  274. static const LocalRef<jobject> createPath (JNIEnv* env, const Path& path, const AffineTransform& transform)
  275. {
  276. if (transform.isIdentity())
  277. return createPath (env, path);
  278. Path tempPath (path);
  279. tempPath.applyTransform (transform);
  280. return createPath (env, tempPath);
  281. }
  282. static const LocalRef<jobject> createMatrix (JNIEnv* env, const AffineTransform& t)
  283. {
  284. jobject m = env->NewObject (android.matrixClass, android.matrixClassConstructor);
  285. jfloat values[9] = { t.mat00, t.mat01, t.mat02,
  286. t.mat10, t.mat11, t.mat12,
  287. 0.0f, 0.0f, 1.0f };
  288. jfloatArray javaArray = env->NewFloatArray (9);
  289. env->SetFloatArrayRegion (javaArray, 0, 9, values);
  290. env->CallVoidMethod (m, android.setValues, javaArray);
  291. env->DeleteLocalRef (javaArray);
  292. return LocalRef<jobject> (m);
  293. }
  294. static const LocalRef<jobject> createRect (JNIEnv* env, const Rectangle<int>& r)
  295. {
  296. return LocalRef<jobject> (env->NewObject (android.rectClass, android.rectConstructor,
  297. r.getX(), r.getY(), r.getRight(), r.getBottom()));
  298. }
  299. static const LocalRef<jobject> createRegion (JNIEnv* env, const RectangleList& list)
  300. {
  301. jobject region = env->NewObject (android.regionClass, android.regionConstructor);
  302. const int numRects = list.getNumRectangles();
  303. for (int i = 0; i < numRects; ++i)
  304. env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get());
  305. return LocalRef<jobject> (region);
  306. }
  307. static int colourToInt (const Colour& col) throw()
  308. {
  309. return col.getARGB();
  310. }
  311. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidLowLevelGraphicsContext);
  312. };
  313. #endif