Audio plugin host https://kx.studio/carla
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.

juce_android_Fonts.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. struct DefaultFontNames
  18. {
  19. DefaultFontNames()
  20. : defaultSans ("sans"),
  21. defaultSerif ("serif"),
  22. defaultFixed ("monospace"),
  23. defaultFallback ("sans")
  24. {
  25. }
  26. String getRealFontName (const String& faceName) const
  27. {
  28. if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans;
  29. if (faceName == Font::getDefaultSerifFontName()) return defaultSerif;
  30. if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed;
  31. return faceName;
  32. }
  33. String defaultSans, defaultSerif, defaultFixed, defaultFallback;
  34. };
  35. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  36. {
  37. static DefaultFontNames defaultNames;
  38. Font f (font);
  39. f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName()));
  40. return Typeface::createSystemTypefaceFor (f);
  41. }
  42. //==============================================================================
  43. #if JUCE_USE_FREETYPE
  44. StringArray FTTypefaceList::getDefaultFontDirectories()
  45. {
  46. return StringArray ("/system/fonts");
  47. }
  48. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  49. {
  50. return new FreeTypeTypeface (font);
  51. }
  52. void Typeface::scanFolderForFonts (const File& folder)
  53. {
  54. FTTypefaceList::getInstance()->scanFontPaths (StringArray (folder.getFullPathName()));
  55. }
  56. StringArray Font::findAllTypefaceNames()
  57. {
  58. return FTTypefaceList::getInstance()->findAllFamilyNames();
  59. }
  60. StringArray Font::findAllTypefaceStyles (const String& family)
  61. {
  62. return FTTypefaceList::getInstance()->findAllTypefaceStyles (family);
  63. }
  64. bool TextLayout::createNativeLayout (const AttributedString&)
  65. {
  66. return false;
  67. }
  68. #else
  69. //==============================================================================
  70. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
  71. STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \
  72. STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
  73. DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface");
  74. #undef JNI_CLASS_MEMBERS
  75. //==============================================================================
  76. StringArray Font::findAllTypefaceNames()
  77. {
  78. StringArray results;
  79. Array<File> fonts;
  80. File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, "*.ttf");
  81. for (int i = 0; i < fonts.size(); ++i)
  82. results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension()
  83. .upToLastOccurrenceOf ("-", false, false));
  84. return results;
  85. }
  86. StringArray Font::findAllTypefaceStyles (const String& family)
  87. {
  88. StringArray results ("Regular");
  89. Array<File> fonts;
  90. File ("/system/fonts").findChildFiles (fonts, File::findFiles, false, family + "-*.ttf");
  91. for (int i = 0; i < fonts.size(); ++i)
  92. results.addIfNotAlreadyThere (fonts.getReference(i).getFileNameWithoutExtension()
  93. .fromLastOccurrenceOf ("-", false, false));
  94. return results;
  95. }
  96. const float referenceFontSize = 256.0f;
  97. const float referenceFontToUnits = 1.0f / referenceFontSize;
  98. //==============================================================================
  99. class AndroidTypeface : public Typeface
  100. {
  101. public:
  102. AndroidTypeface (const Font& font)
  103. : Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
  104. ascent (0), descent (0), heightToPointsFactor (1.0f)
  105. {
  106. JNIEnv* const env = getEnv();
  107. const bool isBold = style.contains ("Bold");
  108. const bool isItalic = style.contains ("Italic");
  109. File fontFile (getFontFile (name, style));
  110. if (! fontFile.exists())
  111. fontFile = findFontFile (name, isBold, isItalic);
  112. if (fontFile.exists())
  113. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
  114. javaString (fontFile.getFullPathName()).get()));
  115. else
  116. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
  117. javaString (getName()).get(),
  118. (isBold ? 1 : 0) + (isItalic ? 2 : 0)));
  119. rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0));
  120. paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
  121. const LocalRef<jobject> ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get()));
  122. paint.callVoidMethod (Paint.setTextSize, referenceFontSize);
  123. const float fullAscent = std::abs (paint.callFloatMethod (Paint.ascent));
  124. const float fullDescent = paint.callFloatMethod (Paint.descent);
  125. const float totalHeight = fullAscent + fullDescent;
  126. ascent = fullAscent / totalHeight;
  127. descent = fullDescent / totalHeight;
  128. heightToPointsFactor = referenceFontSize / totalHeight;
  129. }
  130. float getAscent() const override { return ascent; }
  131. float getDescent() const override { return descent; }
  132. float getHeightToPointsFactor() const override { return heightToPointsFactor; }
  133. float getStringWidth (const String& text) override
  134. {
  135. JNIEnv* env = getEnv();
  136. const int numChars = text.length();
  137. jfloatArray widths = env->NewFloatArray (numChars);
  138. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  139. HeapBlock<jfloat> localWidths (numDone);
  140. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  141. env->DeleteLocalRef (widths);
  142. float x = 0;
  143. for (int i = 0; i < numDone; ++i)
  144. x += localWidths[i];
  145. return x * referenceFontToUnits;
  146. }
  147. void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) override
  148. {
  149. JNIEnv* env = getEnv();
  150. const int numChars = text.length();
  151. jfloatArray widths = env->NewFloatArray (numChars);
  152. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  153. HeapBlock<jfloat> localWidths (numDone);
  154. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  155. env->DeleteLocalRef (widths);
  156. String::CharPointerType s (text.getCharPointer());
  157. xOffsets.add (0);
  158. float x = 0;
  159. for (int i = 0; i < numDone; ++i)
  160. {
  161. glyphs.add ((int) s.getAndAdvance());
  162. x += localWidths[i];
  163. xOffsets.add (x * referenceFontToUnits);
  164. }
  165. }
  166. bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override
  167. {
  168. return false;
  169. }
  170. EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override
  171. {
  172. JNIEnv* env = getEnv();
  173. jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t));
  174. jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get());
  175. env->DeleteLocalRef (matrix);
  176. const int left = env->GetIntField (rect.get(), RectClass.left);
  177. const int top = env->GetIntField (rect.get(), RectClass.top);
  178. const int right = env->GetIntField (rect.get(), RectClass.right);
  179. const int bottom = env->GetIntField (rect.get(), RectClass.bottom);
  180. const Rectangle<int> bounds (left, top, right - left, bottom - top);
  181. EdgeTable* et = nullptr;
  182. if (! bounds.isEmpty())
  183. {
  184. et = new EdgeTable (bounds);
  185. jint* const maskDataElements = env->GetIntArrayElements (maskData, 0);
  186. const jint* mask = maskDataElements;
  187. for (int y = top; y < bottom; ++y)
  188. {
  189. #if JUCE_LITTLE_ENDIAN
  190. const uint8* const lineBytes = ((const uint8*) mask) + 3;
  191. #else
  192. const uint8* const lineBytes = (const uint8*) mask;
  193. #endif
  194. et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth());
  195. mask += bounds.getWidth();
  196. }
  197. env->ReleaseIntArrayElements (maskData, maskDataElements, 0);
  198. }
  199. env->DeleteLocalRef (maskData);
  200. return et;
  201. }
  202. GlobalRef typeface, paint, rect;
  203. float ascent, descent, heightToPointsFactor;
  204. private:
  205. static File findFontFile (const String& family,
  206. const bool bold, const bool italic)
  207. {
  208. File file;
  209. if (bold || italic)
  210. {
  211. String suffix;
  212. if (bold) suffix = "Bold";
  213. if (italic) suffix << "Italic";
  214. file = getFontFile (family, suffix);
  215. if (file.exists())
  216. return file;
  217. }
  218. file = getFontFile (family, "Regular");
  219. if (! file.exists())
  220. file = getFontFile (family, String());
  221. return file;
  222. }
  223. static File getFontFile (const String& family, const String& style)
  224. {
  225. String path ("/system/fonts/" + family);
  226. if (style.isNotEmpty())
  227. path << '-' << style;
  228. return File (path + ".ttf");
  229. }
  230. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface)
  231. };
  232. //==============================================================================
  233. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  234. {
  235. return new AndroidTypeface (font);
  236. }
  237. Typeface::Ptr Typeface::createSystemTypefaceFor (const void*, size_t)
  238. {
  239. jassertfalse; // not yet implemented!
  240. return nullptr;
  241. }
  242. void Typeface::scanFolderForFonts (const File&)
  243. {
  244. jassertfalse; // not available unless using FreeType
  245. }
  246. bool TextLayout::createNativeLayout (const AttributedString&)
  247. {
  248. return false;
  249. }
  250. #endif