diff --git a/modules/juce_core/native/java/JuceAppActivity.java b/modules/juce_core/native/java/JuceAppActivity.java index d1757db659..5c079df6c3 100644 --- a/modules/juce_core/native/java/JuceAppActivity.java +++ b/modules/juce_core/native/java/JuceAppActivity.java @@ -42,10 +42,8 @@ import android.opengl.*; import android.text.ClipboardManager; import android.text.InputType; import android.util.DisplayMetrics; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import android.util.Log; +import java.io.*; import java.net.URL; import java.net.HttpURLConnection; import javax.microedition.khronos.egl.EGLConfig; @@ -79,6 +77,8 @@ public class JuceAppActivity extends Activity { quitApp(); super.onDestroy(); + + clearDataCache(); } @Override @@ -816,4 +816,85 @@ public class JuceAppActivity extends Activity { new SingleMediaScanner (this, filename); } + + public final Typeface getTypeFaceFromAsset (String assetName) + { + try + { + return Typeface.createFromAsset (this.getResources().getAssets(), assetName); + } + catch (Throwable e) {} + + return null; + } + + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex (byte[] bytes) + { + char[] hexChars = new char[bytes.length * 2]; + + for (int j = 0; j < bytes.length; ++j) + { + int v = bytes[j] & 0xff; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0f]; + } + + return new String (hexChars); + } + + final private java.util.Map dataCache = new java.util.HashMap(); + + synchronized private final File getDataCacheFile (byte[] data) + { + try + { + java.security.MessageDigest digest = java.security.MessageDigest.getInstance ("MD5"); + digest.update (data); + + String key = bytesToHex (digest.digest()); + + if (dataCache.containsKey (key)) + return (File) dataCache.get (key); + + File f = new File (this.getCacheDir(), "bindata_" + key); + f.delete(); + FileOutputStream os = new FileOutputStream (f); + os.write (data, 0, data.length); + dataCache.put (key, f); + return f; + } + catch (Throwable e) {} + + return null; + } + + private final void clearDataCache() + { + java.util.Iterator it = dataCache.values().iterator(); + + while (it.hasNext()) + { + File f = (File) it.next(); + f.delete(); + } + } + + public final Typeface getTypeFaceFromByteArray (byte[] data) + { + try + { + File f = getDataCacheFile (data); + + if (f != null) + return Typeface.createFromFile (f); + } + catch (Exception e) + { + Log.e ("JUCE", e.toString()); + } + + return null; + } } diff --git a/modules/juce_core/native/juce_android_JNIHelpers.h b/modules/juce_core/native/juce_android_JNIHelpers.h index f2935d50bc..88869991bb 100644 --- a/modules/juce_core/native/juce_android_JNIHelpers.h +++ b/modules/juce_core/native/juce_android_JNIHelpers.h @@ -385,7 +385,9 @@ struct AndroidThreadScope METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \ - METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V") + METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V") \ + METHOD (getTypeFaceFromAsset, "getTypeFaceFromAsset", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ + METHOD (getTypeFaceFromByteArray,"getTypeFaceFromByteArray","([B)Landroid/graphics/Typeface;") DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH); #undef JNI_CLASS_MEMBERS diff --git a/modules/juce_graphics/native/juce_android_Fonts.cpp b/modules/juce_graphics/native/juce_android_Fonts.cpp index 29702a20b5..e08ef2a01a 100644 --- a/modules/juce_graphics/native/juce_android_Fonts.cpp +++ b/modules/juce_graphics/native/juce_android_Fonts.cpp @@ -138,22 +138,47 @@ public: { JNIEnv* const env = getEnv(); - const bool isBold = style.contains ("Bold"); - const bool isItalic = style.contains ("Italic"); + // First check whether there's an embedded asset with this font name: + typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromAsset, + javaString ("fonts/" + name).get())); - File fontFile (getFontFile (name, style)); + if (typeface.get() == nullptr) + { + const bool isBold = style.contains ("Bold"); + const bool isItalic = style.contains ("Italic"); - if (! fontFile.exists()) - fontFile = findFontFile (name, isBold, isItalic); + File fontFile (getFontFile (name, style)); - if (fontFile.exists()) - typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, - javaString (fontFile.getFullPathName()).get())); - else - typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, - javaString (getName()).get(), - (isBold ? 1 : 0) + (isItalic ? 2 : 0))); + if (! fontFile.exists()) + fontFile = findFontFile (name, isBold, isItalic); + if (fontFile.exists()) + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, + javaString (fontFile.getFullPathName()).get())); + else + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, + javaString (getName()).get(), + (isBold ? 1 : 0) + (isItalic ? 2 : 0))); + } + + initialise (env); + } + + AndroidTypeface (const void* data, size_t size) + : Typeface (String(), String()) + { + JNIEnv* const env = getEnv(); + + LocalRef bytes (env->NewByteArray (size)); + env->SetByteArrayRegion (bytes, 0, size, (const jbyte*) data); + + typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromByteArray, bytes.get())); + + initialise (env); + } + + void initialise (JNIEnv* const env) + { rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality)); @@ -315,10 +340,9 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) return new AndroidTypeface (font); } -Typeface::Ptr Typeface::createSystemTypefaceFor (const void*, size_t) +Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size) { - jassertfalse; // not yet implemented! - return nullptr; + return new AndroidTypeface (data, size); } void Typeface::scanFolderForFonts (const File&)