fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
401
modules/juce_graphics/native/juce_android_Fonts.cpp
Normal file
401
modules/juce_graphics/native/juce_android_Fonts.cpp
Normal file
@ -0,0 +1,401 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct DefaultFontNames
|
||||
{
|
||||
DefaultFontNames()
|
||||
: defaultSans ("sans"),
|
||||
defaultSerif ("serif"),
|
||||
defaultFixed ("monospace"),
|
||||
defaultFallback ("sans")
|
||||
{
|
||||
}
|
||||
|
||||
String getRealFontName (const String& faceName) const
|
||||
{
|
||||
if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans;
|
||||
if (faceName == Font::getDefaultSerifFontName()) return defaultSerif;
|
||||
if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed;
|
||||
|
||||
return faceName;
|
||||
}
|
||||
|
||||
String defaultSans, defaultSerif, defaultFixed, defaultFallback;
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static DefaultFontNames defaultNames;
|
||||
|
||||
Font f (font);
|
||||
f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName()));
|
||||
return Typeface::createSystemTypefaceFor (f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_FREETYPE
|
||||
|
||||
StringArray FTTypefaceList::getDefaultFontDirectories()
|
||||
{
|
||||
return StringArray ("/system/fonts");
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new FreeTypeTypeface (font);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File& folder)
|
||||
{
|
||||
FTTypefaceList::getInstance()->scanFontPaths (StringArray (folder.getFullPathName()));
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
return FTTypefaceList::getInstance()->findAllFamilyNames();
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
return FTTypefaceList::getInstance()->findAllTypefaceStyles (family);
|
||||
}
|
||||
|
||||
bool TextLayout::createNativeLayout (const AttributedString&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \
|
||||
STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
|
||||
|
||||
DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
StringArray results;
|
||||
|
||||
for (auto& f : File ("/system/fonts").findChildFiles (File::findFiles, false, "*.ttf"))
|
||||
results.addIfNotAlreadyThere (f.getFileNameWithoutExtension().upToLastOccurrenceOf ("-", false, false));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
StringArray results ("Regular");
|
||||
|
||||
for (auto& f : File ("/system/fonts").findChildFiles (File::findFiles, false, family + "-*.ttf"))
|
||||
results.addIfNotAlreadyThere (f.getFileNameWithoutExtension().fromLastOccurrenceOf ("-", false, false));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
const float referenceFontSize = 256.0f;
|
||||
const float referenceFontToUnits = 1.0f / referenceFontSize;
|
||||
|
||||
//==============================================================================
|
||||
class AndroidTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
AndroidTypeface (const Font& font)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
|
||||
ascent (0), descent (0), heightToPointsFactor (1.0f)
|
||||
{
|
||||
JNIEnv* const env = getEnv();
|
||||
|
||||
// First check whether there's an embedded asset with this font name:
|
||||
typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromAsset,
|
||||
javaString ("fonts/" + name).get()));
|
||||
|
||||
if (typeface.get() == nullptr)
|
||||
{
|
||||
const bool isBold = style.contains ("Bold");
|
||||
const bool isItalic = style.contains ("Italic");
|
||||
|
||||
File fontFile (getFontFile (name, style));
|
||||
|
||||
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 (static_cast<uint64> (reinterpret_cast<uintptr_t> (data))), String())
|
||||
{
|
||||
JNIEnv* const env = getEnv();
|
||||
|
||||
LocalRef<jbyteArray> bytes (env->NewByteArray ((jsize) size));
|
||||
env->SetByteArrayRegion (bytes, 0, (jsize) size, (const jbyte*) data);
|
||||
|
||||
typeface = GlobalRef (android.activity.callObjectMethod (JuceAppActivity.getTypeFaceFromByteArray, bytes.get()));
|
||||
|
||||
initialise (env);
|
||||
}
|
||||
|
||||
void initialise (JNIEnv* const env)
|
||||
{
|
||||
rect = GlobalRef (env->NewObject (AndroidRect, AndroidRect.constructor, 0, 0, 0, 0));
|
||||
|
||||
paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
|
||||
const LocalRef<jobject> ignored (paint.callObjectMethod (AndroidPaint.setTypeface, typeface.get()));
|
||||
|
||||
paint.callVoidMethod (AndroidPaint.setTextSize, referenceFontSize);
|
||||
|
||||
const float fullAscent = std::abs (paint.callFloatMethod (AndroidPaint.ascent));
|
||||
const float fullDescent = paint.callFloatMethod (AndroidPaint.descent);
|
||||
const float totalHeight = fullAscent + fullDescent;
|
||||
|
||||
ascent = fullAscent / totalHeight;
|
||||
descent = fullDescent / totalHeight;
|
||||
heightToPointsFactor = referenceFontSize / totalHeight;
|
||||
}
|
||||
|
||||
float getAscent() const override { return ascent; }
|
||||
float getDescent() const override { return descent; }
|
||||
float getHeightToPointsFactor() const override { return heightToPointsFactor; }
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
const int numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
|
||||
jfloatArray widths = env->NewFloatArray (numChars);
|
||||
|
||||
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
|
||||
|
||||
HeapBlock<jfloat> localWidths (static_cast<size_t> (numDone));
|
||||
env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
|
||||
env->DeleteLocalRef (widths);
|
||||
|
||||
float x = 0;
|
||||
for (int i = 0; i < numDone; ++i)
|
||||
x += localWidths[i];
|
||||
|
||||
return x * referenceFontToUnits;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) override
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
const int numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
|
||||
jfloatArray widths = env->NewFloatArray (numChars);
|
||||
|
||||
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
|
||||
|
||||
HeapBlock<jfloat> localWidths (static_cast<size_t> (numDone));
|
||||
env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
|
||||
env->DeleteLocalRef (widths);
|
||||
|
||||
auto s = text.getCharPointer();
|
||||
|
||||
xOffsets.add (0);
|
||||
|
||||
float x = 0;
|
||||
for (int i = 0; i < numDone; ++i)
|
||||
{
|
||||
const float local = localWidths[i];
|
||||
|
||||
// Android uses jchar (UTF-16) characters
|
||||
jchar ch = (jchar) s.getAndAdvance();
|
||||
|
||||
// Android has no proper glyph support, so we have to do
|
||||
// a hacky workaround for ligature detection
|
||||
|
||||
#if JUCE_STRING_UTF_TYPE <= 16
|
||||
static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two java chars in one glyph");
|
||||
|
||||
// if the width of this glyph is zero inside the string but has
|
||||
// a width on it's own, then it's probably due to ligature
|
||||
if (local == 0.0f && glyphs.size() > 0 && getStringWidth (String (ch)) > 0.0f)
|
||||
{
|
||||
// modify the previous glyph
|
||||
int& glyphNumber = glyphs.getReference (glyphs.size() - 1);
|
||||
|
||||
// make sure this is not a three character ligature
|
||||
if (glyphNumber < std::numeric_limits<jchar>::max())
|
||||
{
|
||||
const unsigned int previousGlyph
|
||||
= static_cast<unsigned int> (glyphNumber) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
const unsigned int thisGlyph
|
||||
= static_cast<unsigned int> (ch) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
|
||||
glyphNumber = static_cast<int> ((thisGlyph << (sizeof (jchar) * 8U)) | previousGlyph);
|
||||
ch = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glyphs.add ((int) ch);
|
||||
x += local;
|
||||
xOffsets.add (x * referenceFontToUnits);
|
||||
}
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override
|
||||
{
|
||||
#if JUCE_STRING_UTF_TYPE <= 16
|
||||
static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two jni chars in one int");
|
||||
|
||||
// glyphNumber of zero is used to indicate that the last character was a ligature
|
||||
if (glyphNumber == 0) return nullptr;
|
||||
|
||||
jchar ch1 = (static_cast<unsigned int> (glyphNumber) >> 0) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
jchar ch2 = (static_cast<unsigned int> (glyphNumber) >> (sizeof (jchar) * 8U)) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
#else
|
||||
jchar ch1 = glyphNumber, ch2 = 0;
|
||||
#endif
|
||||
|
||||
JNIEnv* env = getEnv();
|
||||
|
||||
jobject matrix = GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits).followedBy (t));
|
||||
jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, ch1, ch2, paint.get(), matrix, rect.get());
|
||||
|
||||
env->DeleteLocalRef (matrix);
|
||||
|
||||
const int left = env->GetIntField (rect.get(), AndroidRect.left);
|
||||
const int top = env->GetIntField (rect.get(), AndroidRect.top);
|
||||
const int right = env->GetIntField (rect.get(), AndroidRect.right);
|
||||
const int bottom = env->GetIntField (rect.get(), AndroidRect.bottom);
|
||||
|
||||
const Rectangle<int> bounds (left, top, right - left, bottom - top);
|
||||
|
||||
EdgeTable* et = nullptr;
|
||||
|
||||
if (! bounds.isEmpty())
|
||||
{
|
||||
et = new EdgeTable (bounds);
|
||||
|
||||
jint* const maskDataElements = env->GetIntArrayElements (maskData, 0);
|
||||
const jint* mask = maskDataElements;
|
||||
|
||||
for (int y = top; y < bottom; ++y)
|
||||
{
|
||||
#if JUCE_LITTLE_ENDIAN
|
||||
const uint8* const lineBytes = ((const uint8*) mask) + 3;
|
||||
#else
|
||||
const uint8* const lineBytes = (const uint8*) mask;
|
||||
#endif
|
||||
|
||||
et->clipLineToMask (left, y, lineBytes, 4, bounds.getWidth());
|
||||
mask += bounds.getWidth();
|
||||
}
|
||||
|
||||
env->ReleaseIntArrayElements (maskData, maskDataElements, 0);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef (maskData);
|
||||
return et;
|
||||
}
|
||||
|
||||
GlobalRef typeface, paint, rect;
|
||||
float ascent, descent, heightToPointsFactor;
|
||||
|
||||
private:
|
||||
static File findFontFile (const String& family,
|
||||
const bool bold, const bool italic)
|
||||
{
|
||||
File file;
|
||||
|
||||
if (bold || italic)
|
||||
{
|
||||
String suffix;
|
||||
if (bold) suffix = "Bold";
|
||||
if (italic) suffix << "Italic";
|
||||
|
||||
file = getFontFile (family, suffix);
|
||||
|
||||
if (file.exists())
|
||||
return file;
|
||||
}
|
||||
|
||||
file = getFontFile (family, "Regular");
|
||||
|
||||
if (! file.exists())
|
||||
file = getFontFile (family, String());
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static File getFontFile (const String& family, const String& style)
|
||||
{
|
||||
String path ("/system/fonts/" + family);
|
||||
|
||||
if (style.isNotEmpty())
|
||||
path << '-' << style;
|
||||
|
||||
return File (path + ".ttf");
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new AndroidTypeface (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size)
|
||||
{
|
||||
return new AndroidTypeface (data, size);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File&)
|
||||
{
|
||||
jassertfalse; // not available unless using FreeType
|
||||
}
|
||||
|
||||
bool TextLayout::createNativeLayout (const AttributedString&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user