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.

359 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. // First check whether there's an embedded asset with this font name:
  108. typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromAsset,
  109. javaString ("fonts/" + name).get()));
  110. if (typeface.get() == nullptr)
  111. {
  112. const bool isBold = style.contains ("Bold");
  113. const bool isItalic = style.contains ("Italic");
  114. File fontFile (getFontFile (name, style));
  115. if (! fontFile.exists())
  116. fontFile = findFontFile (name, isBold, isItalic);
  117. if (fontFile.exists())
  118. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
  119. javaString (fontFile.getFullPathName()).get()));
  120. else
  121. typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
  122. javaString (getName()).get(),
  123. (isBold ? 1 : 0) + (isItalic ? 2 : 0)));
  124. }
  125. initialise (env);
  126. }
  127. AndroidTypeface (const void* data, size_t size)
  128. : Typeface (String(), String())
  129. {
  130. JNIEnv* const env = getEnv();
  131. LocalRef<jbyteArray> bytes (env->NewByteArray (size));
  132. env->SetByteArrayRegion (bytes, 0, size, (const jbyte*) data);
  133. typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromByteArray, bytes.get()));
  134. initialise (env);
  135. }
  136. void initialise (JNIEnv* const env)
  137. {
  138. rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0));
  139. paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
  140. const LocalRef<jobject> ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get()));
  141. paint.callVoidMethod (Paint.setTextSize, referenceFontSize);
  142. const float fullAscent = std::abs (paint.callFloatMethod (Paint.ascent));
  143. const float fullDescent = paint.callFloatMethod (Paint.descent);
  144. const float totalHeight = fullAscent + fullDescent;
  145. ascent = fullAscent / totalHeight;
  146. descent = fullDescent / totalHeight;
  147. heightToPointsFactor = referenceFontSize / totalHeight;
  148. }
  149. float getAscent() const override { return ascent; }
  150. float getDescent() const override { return descent; }
  151. float getHeightToPointsFactor() const override { return heightToPointsFactor; }
  152. float getStringWidth (const String& text) override
  153. {
  154. JNIEnv* env = getEnv();
  155. const int numChars = text.length();
  156. jfloatArray widths = env->NewFloatArray (numChars);
  157. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  158. HeapBlock<jfloat> localWidths (numDone);
  159. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  160. env->DeleteLocalRef (widths);
  161. float x = 0;
  162. for (int i = 0; i < numDone; ++i)
  163. x += localWidths[i];
  164. return x * referenceFontToUnits;
  165. }
  166. void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) override
  167. {
  168. JNIEnv* env = getEnv();
  169. const int numChars = text.length();
  170. jfloatArray widths = env->NewFloatArray (numChars);
  171. const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths);
  172. HeapBlock<jfloat> localWidths (numDone);
  173. env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
  174. env->DeleteLocalRef (widths);
  175. String::CharPointerType s (text.getCharPointer());
  176. xOffsets.add (0);
  177. float x = 0;
  178. for (int i = 0; i < numDone; ++i)
  179. {
  180. glyphs.add ((int) s.getAndAdvance());
  181. x += localWidths[i];
  182. xOffsets.add (x * referenceFontToUnits);
  183. }
  184. }
  185. bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override
  186. {
  187. return false;
  188. }
  189. EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override
  190. {
  191. JNIEnv* env = getEnv();
  192. jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t));
  193. jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get());
  194. env->DeleteLocalRef (matrix);
  195. const int left = env->GetIntField (rect.get(), RectClass.left);
  196. const int top = env->GetIntField (rect.get(), RectClass.top);
  197. const int right = env->GetIntField (rect.get(), RectClass.right);
  198. const int bottom = env->GetIntField (rect.get(), RectClass.bottom);
  199. const Rectangle<int> bounds (left, top, right - left, bottom - top);
  200. EdgeTable* et = nullptr;
  201. if (! bounds.isEmpty())
  202. {
  203. et = new EdgeTable (bounds);
  204. jint* const maskDataElements = env->GetIntArrayElements (maskData, 0);
  205. const jint* mask = maskDataElements;
  206. for (int y = top; y < bottom; ++y)
  207. {
  208. #if JUCE_LITTLE_ENDIAN
  209. const uint8* const lineBytes = ((const uint8*) mask) + 3;
  210. #else
  211. const uint8* const lineBytes = (const uint8*) mask;
  212. #endif
  213. et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth());
  214. mask += bounds.getWidth();
  215. }
  216. env->ReleaseIntArrayElements (maskData, maskDataElements, 0);
  217. }
  218. env->DeleteLocalRef (maskData);
  219. return et;
  220. }
  221. GlobalRef typeface, paint, rect;
  222. float ascent, descent, heightToPointsFactor;
  223. private:
  224. static File findFontFile (const String& family,
  225. const bool bold, const bool italic)
  226. {
  227. File file;
  228. if (bold || italic)
  229. {
  230. String suffix;
  231. if (bold) suffix = "Bold";
  232. if (italic) suffix << "Italic";
  233. file = getFontFile (family, suffix);
  234. if (file.exists())
  235. return file;
  236. }
  237. file = getFontFile (family, "Regular");
  238. if (! file.exists())
  239. file = getFontFile (family, String());
  240. return file;
  241. }
  242. static File getFontFile (const String& family, const String& style)
  243. {
  244. String path ("/system/fonts/" + family);
  245. if (style.isNotEmpty())
  246. path << '-' << style;
  247. return File (path + ".ttf");
  248. }
  249. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface)
  250. };
  251. //==============================================================================
  252. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  253. {
  254. return new AndroidTypeface (font);
  255. }
  256. Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size)
  257. {
  258. return new AndroidTypeface (data, size);
  259. }
  260. void Typeface::scanFolderForFonts (const File&)
  261. {
  262. jassertfalse; // not available unless using FreeType
  263. }
  264. bool TextLayout::createNativeLayout (const AttributedString&)
  265. {
  266. return false;
  267. }
  268. #endif