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.

281 lines
9.8KB

  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. //==============================================================================
  19. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
  20. STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \
  21. STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
  22. DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface");
  23. #undef JNI_CLASS_MEMBERS
  24. //==============================================================================
  25. StringArray Font::findAllTypefaceNames()
  26. {
  27. StringArray results;
  28. Array<File> fonts;
  29. File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, "*.ttf");
  30. for (int i = 0; i < fonts.size(); ++i)
  31. results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension()
  32. .upToLastOccurrenceOf ("-", false, false));
  33. return results;
  34. }
  35. StringArray Font::findAllTypefaceStyles (const String& family)
  36. {
  37. StringArray results ("Regular");
  38. Array<File> fonts;
  39. File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, family + "-*.ttf");
  40. for (int i = 0; i < fonts.size(); ++i)
  41. results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension()
  42. .fromLastOccurrenceOf ("-", false, false));
  43. return results;
  44. }
  45. struct DefaultFontNames
  46. {
  47. DefaultFontNames()
  48. : defaultSans ("sans"),
  49. defaultSerif ("serif"),
  50. defaultFixed ("monospace"),
  51. defaultFallback ("sans")
  52. {
  53. }
  54. String defaultSans, defaultSerif, defaultFixed, defaultFallback;
  55. };
  56. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  57. {
  58. static DefaultFontNames defaultNames;
  59. String faceName (font.getTypefaceName());
  60. if (faceName == Font::getDefaultSansSerifFontName()) faceName = defaultNames.defaultSans;
  61. else if (faceName == Font::getDefaultSerifFontName()) faceName = defaultNames.defaultSerif;
  62. else if (faceName == Font::getDefaultMonospacedFontName()) faceName = defaultNames.defaultFixed;
  63. Font f (font);
  64. f.setTypefaceName (faceName);
  65. return Typeface::createSystemTypefaceFor (f);
  66. }
  67. //==============================================================================
  68. class AndroidTypeface : public Typeface
  69. {
  70. public:
  71. AndroidTypeface (const Font& font)
  72. : Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
  73. ascent (0),
  74. descent (0)
  75. {
  76. JNIEnv* const env = getEnv();
  77. const bool isBold = style.contains ("Bold");
  78. const bool isItalic = style.contains ("Italic");
  79. File fontFile (getFontFile (name, style));
  80. if (! fontFile.exists())
  81. fontFile = findFontFile (name, isBold, isItalic);
  82. if (fontFile.exists())
  83. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
  84. javaString (fontFile.getFullPathName()).get()));
  85. else
  86. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
  87. javaString (getName()).get(),
  88. (isBold ? 1 : 0) + (isItalic ? 2 : 0)));
  89. rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0));
  90. paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
  91. const LocalRef<jobject> ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get()));
  92. const float standardSize = 256.0f;
  93. paint.callVoidMethod (Paint.setTextSize, standardSize);
  94. ascent = std::abs (paint.callFloatMethod (Paint.ascent)) / standardSize;
  95. descent = paint.callFloatMethod (Paint.descent) / standardSize;
  96. const float height = ascent + descent;
  97. unitsToHeightScaleFactor = 1.0f / 256.0f;
  98. }
  99. float getAscent() const { return ascent; }
  100. float getDescent() const { return descent; }
  101. float getStringWidth (const String& text)
  102. {
  103. JNIEnv* env = getEnv();
  104. const int numChars = text.length();
  105. jfloatArray widths = env->NewFloatArray (numChars);
  106. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  107. HeapBlock<jfloat> localWidths (numDone);
  108. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  109. env->DeleteLocalRef (widths);
  110. float x = 0;
  111. for (int i = 0; i < numDone; ++i)
  112. x += localWidths[i];
  113. return x * unitsToHeightScaleFactor;
  114. }
  115. void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets)
  116. {
  117. JNIEnv* env = getEnv();
  118. const int numChars = text.length();
  119. jfloatArray widths = env->NewFloatArray (numChars);
  120. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  121. HeapBlock<jfloat> localWidths (numDone);
  122. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  123. env->DeleteLocalRef (widths);
  124. String::CharPointerType s (text.getCharPointer());
  125. xOffsets.add (0);
  126. float x = 0;
  127. for (int i = 0; i < numDone; ++i)
  128. {
  129. glyphs.add ((int) s.getAndAdvance());
  130. x += localWidths[i];
  131. xOffsets.add (x * unitsToHeightScaleFactor);
  132. }
  133. }
  134. bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/)
  135. {
  136. return false;
  137. }
  138. EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t)
  139. {
  140. JNIEnv* env = getEnv();
  141. jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (unitsToHeightScaleFactor, unitsToHeightScaleFactor).followedBy (t));
  142. jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get());
  143. env->DeleteLocalRef (matrix);
  144. const int left = env->GetIntField (rect.get(), RectClass.left);
  145. const int top = env->GetIntField (rect.get(), RectClass.top);
  146. const int right = env->GetIntField (rect.get(), RectClass.right);
  147. const int bottom = env->GetIntField (rect.get(), RectClass.bottom);
  148. const Rectangle<int> bounds (left, top, right - left, bottom - top);
  149. EdgeTable* et = nullptr;
  150. if (! bounds.isEmpty())
  151. {
  152. et = new EdgeTable (bounds);
  153. jint* const maskDataElements = env->GetIntArrayElements (maskData, 0);
  154. const jint* mask = maskDataElements;
  155. for (int y = top; y < bottom; ++y)
  156. {
  157. #if JUCE_LITTLE_ENDIAN
  158. const uint8* const lineBytes = ((const uint8*) mask) + 3;
  159. #else
  160. const uint8* const lineBytes = (const uint8*) mask;
  161. #endif
  162. et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth());
  163. mask += bounds.getWidth();
  164. }
  165. env->ReleaseIntArrayElements (maskData, maskDataElements, 0);
  166. }
  167. env->DeleteLocalRef (maskData);
  168. return et;
  169. }
  170. GlobalRef typeface, paint, rect;
  171. float ascent, descent, unitsToHeightScaleFactor;
  172. private:
  173. static File findFontFile (const String& family,
  174. const bool bold, const bool italic)
  175. {
  176. File file;
  177. if (bold || italic)
  178. {
  179. String suffix;
  180. if (bold) suffix = "Bold";
  181. if (italic) suffix << "Italic";
  182. file = getFontFile (family, suffix);
  183. if (file.exists())
  184. return file;
  185. }
  186. file = getFontFile (family, "Regular");
  187. if (! file.exists())
  188. file = getFontFile (family, String::empty);
  189. return file;
  190. }
  191. static File getFontFile (const String& family, const String& style)
  192. {
  193. String path ("/system/fonts/" + family);
  194. if (style.isNotEmpty())
  195. path << '-' << style;
  196. return File (path + ".ttf");
  197. }
  198. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface);
  199. };
  200. //==============================================================================
  201. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  202. {
  203. return new AndroidTypeface (font);
  204. }
  205. bool TextLayout::createNativeLayout (const AttributedString&)
  206. {
  207. return false;
  208. }