migrating to the latest JUCE version
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,66 +1,66 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
namespace GraphicsHelpers
|
||||
{
|
||||
LocalRef<jobject> createPaint (Graphics::ResamplingQuality quality)
|
||||
{
|
||||
jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/
|
||||
| 4 /*DITHER_FLAG*/
|
||||
| 128 /*SUBPIXEL_TEXT_FLAG*/;
|
||||
|
||||
if (quality > Graphics::lowResamplingQuality)
|
||||
constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/
|
||||
|
||||
return LocalRef<jobject>(getEnv()->NewObject (AndroidPaint, AndroidPaint.constructor, constructorFlags));
|
||||
}
|
||||
|
||||
const LocalRef<jobject> createMatrix (JNIEnv* env, const AffineTransform& t)
|
||||
{
|
||||
auto m = LocalRef<jobject>(env->NewObject (AndroidMatrix, AndroidMatrix.constructor));
|
||||
|
||||
jfloat values[9] = { t.mat00, t.mat01, t.mat02,
|
||||
t.mat10, t.mat11, t.mat12,
|
||||
0.0f, 0.0f, 1.0f };
|
||||
|
||||
jfloatArray javaArray = env->NewFloatArray (9);
|
||||
env->SetFloatArrayRegion (javaArray, 0, 9, values);
|
||||
|
||||
env->CallVoidMethod (m, AndroidMatrix.setValues, javaArray);
|
||||
env->DeleteLocalRef (javaArray);
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return SoftwareImageType().create (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
namespace GraphicsHelpers
|
||||
{
|
||||
static LocalRef<jobject> createPaint (Graphics::ResamplingQuality quality)
|
||||
{
|
||||
jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/
|
||||
| 4 /*DITHER_FLAG*/
|
||||
| 128 /*SUBPIXEL_TEXT_FLAG*/;
|
||||
|
||||
if (quality > Graphics::lowResamplingQuality)
|
||||
constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/
|
||||
|
||||
return LocalRef<jobject>(getEnv()->NewObject (AndroidPaint, AndroidPaint.constructor, constructorFlags));
|
||||
}
|
||||
|
||||
static LocalRef<jobject> createMatrix (JNIEnv* env, const AffineTransform& t)
|
||||
{
|
||||
auto m = LocalRef<jobject>(env->NewObject (AndroidMatrix, AndroidMatrix.constructor));
|
||||
|
||||
jfloat values[9] = { t.mat00, t.mat01, t.mat02,
|
||||
t.mat10, t.mat11, t.mat12,
|
||||
0.0f, 0.0f, 1.0f };
|
||||
|
||||
jfloatArray javaArray = env->NewFloatArray (9);
|
||||
env->SetFloatArrayRegion (javaArray, 0, 9, values);
|
||||
|
||||
env->CallVoidMethod (m, AndroidMatrix.setValues, javaArray);
|
||||
env->DeleteLocalRef (javaArray);
|
||||
|
||||
return m;
|
||||
}
|
||||
} // namespace GraphicsHelpers
|
||||
|
||||
ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return SoftwareImageType().create (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,29 +1,30 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int);
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
|
@ -1,453 +1,453 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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 FTLibWrapper : public ReferenceCountedObject
|
||||
{
|
||||
FTLibWrapper()
|
||||
{
|
||||
if (FT_Init_FreeType (&library) != 0)
|
||||
{
|
||||
library = {};
|
||||
DBG ("Failed to initialize FreeType");
|
||||
}
|
||||
}
|
||||
|
||||
~FTLibWrapper()
|
||||
{
|
||||
if (library != nullptr)
|
||||
FT_Done_FreeType (library);
|
||||
}
|
||||
|
||||
FT_Library library = {};
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<FTLibWrapper>;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTLibWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct FTFaceWrapper : public ReferenceCountedObject
|
||||
{
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
|
||||
: library (ftLib)
|
||||
{
|
||||
if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0)
|
||||
face = {};
|
||||
}
|
||||
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex)
|
||||
: library (ftLib), savedFaceData (data, dataSize)
|
||||
{
|
||||
if (FT_New_Memory_Face (ftLib->library, (const FT_Byte*) savedFaceData.getData(),
|
||||
(FT_Long) savedFaceData.getSize(), faceIndex, &face) != 0)
|
||||
face = {};
|
||||
}
|
||||
|
||||
~FTFaceWrapper()
|
||||
{
|
||||
if (face != nullptr)
|
||||
FT_Done_Face (face);
|
||||
}
|
||||
|
||||
FT_Face face = {};
|
||||
FTLibWrapper::Ptr library;
|
||||
MemoryBlock savedFaceData;
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<FTFaceWrapper>;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTFaceWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FTTypefaceList : private DeletedAtShutdown
|
||||
{
|
||||
public:
|
||||
FTTypefaceList() : library (new FTLibWrapper())
|
||||
{
|
||||
scanFontPaths (getDefaultFontDirectories());
|
||||
}
|
||||
|
||||
~FTTypefaceList()
|
||||
{
|
||||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct KnownTypeface
|
||||
{
|
||||
KnownTypeface (const File& f, int index, const FTFaceWrapper& face)
|
||||
: file (f),
|
||||
family (face.face->family_name),
|
||||
style (face.face->style_name),
|
||||
faceIndex (index),
|
||||
isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0),
|
||||
isSansSerif (isFaceSansSerif (family))
|
||||
{
|
||||
}
|
||||
|
||||
const File file;
|
||||
const String family, style;
|
||||
const int faceIndex;
|
||||
const bool isMonospaced, isSansSerif;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownTypeface)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static FTFaceWrapper::Ptr selectUnicodeCharmap (FTFaceWrapper* face)
|
||||
{
|
||||
if (face != nullptr)
|
||||
if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
|
||||
FT_Set_Charmap (face->face, face->face->charmaps[0]);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const void* data, size_t dataSize, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, data, dataSize, index));
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const File& file, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, file, index));
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle)
|
||||
{
|
||||
auto ftFace = matchTypeface (fontName, fontStyle);
|
||||
|
||||
if (ftFace == nullptr) ftFace = matchTypeface (fontName, "Regular");
|
||||
if (ftFace == nullptr) ftFace = matchTypeface (fontName, {});
|
||||
|
||||
if (ftFace != nullptr)
|
||||
return createFace (ftFace->file, ftFace->faceIndex);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
StringArray findAllFamilyNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* face : faces)
|
||||
s.addIfNotAlreadyThere (face->family);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int indexOfRegularStyle (const StringArray& styles)
|
||||
{
|
||||
int i = styles.indexOf ("Regular", true);
|
||||
|
||||
if (i >= 0)
|
||||
return i;
|
||||
|
||||
for (i = 0; i < styles.size(); ++i)
|
||||
if (! (styles[i].containsIgnoreCase ("Bold") || styles[i].containsIgnoreCase ("Italic")))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
StringArray findAllTypefaceStyles (const String& family) const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* face : faces)
|
||||
if (face->family == family)
|
||||
s.addIfNotAlreadyThere (face->style);
|
||||
|
||||
// try to get a regular style to be first in the list
|
||||
auto regular = indexOfRegularStyle (s);
|
||||
|
||||
if (regular > 0)
|
||||
s.strings.swap (0, regular);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void scanFontPaths (const StringArray& paths)
|
||||
{
|
||||
for (auto& path : paths)
|
||||
{
|
||||
for (const auto& iter : RangedDirectoryIterator (File::getCurrentWorkingDirectory().getChildFile (path), true))
|
||||
if (iter.getFile().hasFileExtension ("ttf;pfb;pcf;otf"))
|
||||
scanFont (iter.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
void getMonospacedNames (StringArray& monoSpaced) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isMonospaced)
|
||||
monoSpaced.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSerifNames (StringArray& serif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (! (face->isSansSerif || face->isMonospaced))
|
||||
serif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSansSerifNames (StringArray& sansSerif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isSansSerif)
|
||||
sansSerif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FTTypefaceList)
|
||||
|
||||
private:
|
||||
FTLibWrapper::Ptr library;
|
||||
OwnedArray<KnownTypeface> faces;
|
||||
|
||||
static StringArray getDefaultFontDirectories();
|
||||
|
||||
void scanFont (const File& file)
|
||||
{
|
||||
int faceIndex = 0;
|
||||
int numFaces = 0;
|
||||
|
||||
do
|
||||
{
|
||||
FTFaceWrapper face (library, file, faceIndex);
|
||||
|
||||
if (face.face != nullptr)
|
||||
{
|
||||
if (faceIndex == 0)
|
||||
numFaces = (int) face.face->num_faces;
|
||||
|
||||
if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
|
||||
faces.add (new KnownTypeface (file, faceIndex, face));
|
||||
}
|
||||
|
||||
++faceIndex;
|
||||
}
|
||||
while (faceIndex < numFaces);
|
||||
}
|
||||
|
||||
const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->family == familyName
|
||||
&& (face->style.equalsIgnoreCase (style) || style.isEmpty()))
|
||||
return face;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool isFaceSansSerif (const String& family)
|
||||
{
|
||||
static const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" };
|
||||
|
||||
for (auto* name : sansNames)
|
||||
if (family.containsIgnoreCase (name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTTypefaceList)
|
||||
};
|
||||
|
||||
JUCE_IMPLEMENT_SINGLETON (FTTypefaceList)
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FreeTypeTypeface : public CustomTypeface
|
||||
{
|
||||
public:
|
||||
FreeTypeTypeface (const Font& font)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (font.getTypefaceName(),
|
||||
font.getTypefaceStyle()))
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (font.getTypefaceName(),
|
||||
font.getTypefaceStyle());
|
||||
}
|
||||
|
||||
FreeTypeTypeface (const void* data, size_t dataSize)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (data, dataSize, 0))
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (faceWrapper->face->family_name,
|
||||
faceWrapper->face->style_name);
|
||||
}
|
||||
|
||||
void initialiseCharacteristics (const String& fontName, const String& fontStyle)
|
||||
{
|
||||
setCharacteristics (fontName, fontStyle,
|
||||
faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender),
|
||||
L' ');
|
||||
}
|
||||
|
||||
bool loadGlyphIfPossible (const juce_wchar character)
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
{
|
||||
auto face = faceWrapper->face;
|
||||
auto glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
|
||||
|
||||
if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING) == 0
|
||||
&& face->glyph->format == ft_glyph_format_outline)
|
||||
{
|
||||
auto scale = 1.0f / (float) (face->ascender - face->descender);
|
||||
Path destShape;
|
||||
|
||||
if (getGlyphShape (destShape, face->glyph->outline, scale))
|
||||
{
|
||||
addGlyph (character, destShape, (float) face->glyph->metrics.horiAdvance * scale);
|
||||
|
||||
if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
|
||||
addKerning (face, (uint32) character, glyphIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
FTFaceWrapper::Ptr faceWrapper;
|
||||
|
||||
bool getGlyphShape (Path& destShape, const FT_Outline& outline, float scaleX)
|
||||
{
|
||||
auto scaleY = -scaleX;
|
||||
auto* contours = outline.contours;
|
||||
auto* tags = outline.tags;
|
||||
auto* points = outline.points;
|
||||
|
||||
for (int c = 0; c < outline.n_contours; ++c)
|
||||
{
|
||||
const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
|
||||
const int endPoint = contours[c];
|
||||
|
||||
for (int p = startPoint; p <= endPoint; ++p)
|
||||
{
|
||||
auto x = scaleX * (float) points[p].x;
|
||||
auto y = scaleY * (float) points[p].y;
|
||||
|
||||
if (p == startPoint)
|
||||
{
|
||||
if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
auto x2 = scaleX * (float) points[endPoint].x;
|
||||
auto y2 = scaleY * (float) points[endPoint].y;
|
||||
|
||||
if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
|
||||
{
|
||||
x2 = (x + x2) * 0.5f;
|
||||
y2 = (y + y2) * 0.5f;
|
||||
}
|
||||
|
||||
destShape.startNewSubPath (x2, y2);
|
||||
}
|
||||
else
|
||||
{
|
||||
destShape.startNewSubPath (x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
|
||||
{
|
||||
if (p != startPoint)
|
||||
destShape.lineTo (x, y);
|
||||
}
|
||||
else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
const int nextIndex = (p == endPoint) ? startPoint : p + 1;
|
||||
auto x2 = scaleX * (float) points[nextIndex].x;
|
||||
auto y2 = scaleY * (float) points[nextIndex].y;
|
||||
|
||||
if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
x2 = (x + x2) * 0.5f;
|
||||
y2 = (y + y2) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
destShape.quadraticTo (x, y, x2, y2);
|
||||
}
|
||||
else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
|
||||
{
|
||||
const int next1 = p + 1;
|
||||
const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2);
|
||||
|
||||
if (p >= endPoint
|
||||
|| FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
|
||||
|| FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
|
||||
return false;
|
||||
|
||||
auto x2 = scaleX * (float) points[next1].x;
|
||||
auto y2 = scaleY * (float) points[next1].y;
|
||||
auto x3 = scaleX * (float) points[next2].x;
|
||||
auto y3 = scaleY * (float) points[next2].y;
|
||||
|
||||
destShape.cubicTo (x, y, x2, y2, x3, y3);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
destShape.closeSubPath();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
|
||||
{
|
||||
auto height = (float) (face->ascender - face->descender);
|
||||
|
||||
uint32 rightGlyphIndex;
|
||||
auto rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
|
||||
|
||||
while (rightGlyphIndex != 0)
|
||||
{
|
||||
FT_Vector kerning;
|
||||
|
||||
if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0
|
||||
&& kerning.x != 0)
|
||||
addKerningPair ((juce_wchar) character, (juce_wchar) rightCharCode, (float) kerning.x / height);
|
||||
|
||||
rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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 FTLibWrapper : public ReferenceCountedObject
|
||||
{
|
||||
FTLibWrapper()
|
||||
{
|
||||
if (FT_Init_FreeType (&library) != 0)
|
||||
{
|
||||
library = {};
|
||||
DBG ("Failed to initialize FreeType");
|
||||
}
|
||||
}
|
||||
|
||||
~FTLibWrapper()
|
||||
{
|
||||
if (library != nullptr)
|
||||
FT_Done_FreeType (library);
|
||||
}
|
||||
|
||||
FT_Library library = {};
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<FTLibWrapper>;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTLibWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct FTFaceWrapper : public ReferenceCountedObject
|
||||
{
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
|
||||
: library (ftLib)
|
||||
{
|
||||
if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0)
|
||||
face = {};
|
||||
}
|
||||
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex)
|
||||
: library (ftLib), savedFaceData (data, dataSize)
|
||||
{
|
||||
if (FT_New_Memory_Face (ftLib->library, (const FT_Byte*) savedFaceData.getData(),
|
||||
(FT_Long) savedFaceData.getSize(), faceIndex, &face) != 0)
|
||||
face = {};
|
||||
}
|
||||
|
||||
~FTFaceWrapper()
|
||||
{
|
||||
if (face != nullptr)
|
||||
FT_Done_Face (face);
|
||||
}
|
||||
|
||||
FT_Face face = {};
|
||||
FTLibWrapper::Ptr library;
|
||||
MemoryBlock savedFaceData;
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<FTFaceWrapper>;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTFaceWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FTTypefaceList : private DeletedAtShutdown
|
||||
{
|
||||
public:
|
||||
FTTypefaceList() : library (new FTLibWrapper())
|
||||
{
|
||||
scanFontPaths (getDefaultFontDirectories());
|
||||
}
|
||||
|
||||
~FTTypefaceList()
|
||||
{
|
||||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct KnownTypeface
|
||||
{
|
||||
KnownTypeface (const File& f, int index, const FTFaceWrapper& face)
|
||||
: file (f),
|
||||
family (face.face->family_name),
|
||||
style (face.face->style_name),
|
||||
faceIndex (index),
|
||||
isMonospaced ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0),
|
||||
isSansSerif (isFaceSansSerif (family))
|
||||
{
|
||||
}
|
||||
|
||||
const File file;
|
||||
const String family, style;
|
||||
const int faceIndex;
|
||||
const bool isMonospaced, isSansSerif;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownTypeface)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static FTFaceWrapper::Ptr selectUnicodeCharmap (FTFaceWrapper* face)
|
||||
{
|
||||
if (face != nullptr)
|
||||
if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
|
||||
FT_Set_Charmap (face->face, face->face->charmaps[0]);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const void* data, size_t dataSize, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, data, dataSize, index));
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const File& file, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, file, index));
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle)
|
||||
{
|
||||
auto ftFace = matchTypeface (fontName, fontStyle);
|
||||
|
||||
if (ftFace == nullptr) ftFace = matchTypeface (fontName, "Regular");
|
||||
if (ftFace == nullptr) ftFace = matchTypeface (fontName, {});
|
||||
|
||||
if (ftFace != nullptr)
|
||||
return createFace (ftFace->file, ftFace->faceIndex);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
StringArray findAllFamilyNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* face : faces)
|
||||
s.addIfNotAlreadyThere (face->family);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int indexOfRegularStyle (const StringArray& styles)
|
||||
{
|
||||
int i = styles.indexOf ("Regular", true);
|
||||
|
||||
if (i >= 0)
|
||||
return i;
|
||||
|
||||
for (i = 0; i < styles.size(); ++i)
|
||||
if (! (styles[i].containsIgnoreCase ("Bold") || styles[i].containsIgnoreCase ("Italic")))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
StringArray findAllTypefaceStyles (const String& family) const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* face : faces)
|
||||
if (face->family == family)
|
||||
s.addIfNotAlreadyThere (face->style);
|
||||
|
||||
// try to get a regular style to be first in the list
|
||||
auto regular = indexOfRegularStyle (s);
|
||||
|
||||
if (regular > 0)
|
||||
s.strings.swap (0, regular);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void scanFontPaths (const StringArray& paths)
|
||||
{
|
||||
for (auto& path : paths)
|
||||
{
|
||||
for (const auto& iter : RangedDirectoryIterator (File::getCurrentWorkingDirectory().getChildFile (path), true))
|
||||
if (iter.getFile().hasFileExtension ("ttf;pfb;pcf;otf"))
|
||||
scanFont (iter.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
void getMonospacedNames (StringArray& monoSpaced) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isMonospaced)
|
||||
monoSpaced.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSerifNames (StringArray& serif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (! (face->isSansSerif || face->isMonospaced))
|
||||
serif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSansSerifNames (StringArray& sansSerif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isSansSerif)
|
||||
sansSerif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FTTypefaceList)
|
||||
|
||||
private:
|
||||
FTLibWrapper::Ptr library;
|
||||
OwnedArray<KnownTypeface> faces;
|
||||
|
||||
static StringArray getDefaultFontDirectories();
|
||||
|
||||
void scanFont (const File& file)
|
||||
{
|
||||
int faceIndex = 0;
|
||||
int numFaces = 0;
|
||||
|
||||
do
|
||||
{
|
||||
FTFaceWrapper face (library, file, faceIndex);
|
||||
|
||||
if (face.face != nullptr)
|
||||
{
|
||||
if (faceIndex == 0)
|
||||
numFaces = (int) face.face->num_faces;
|
||||
|
||||
if ((face.face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
|
||||
faces.add (new KnownTypeface (file, faceIndex, face));
|
||||
}
|
||||
|
||||
++faceIndex;
|
||||
}
|
||||
while (faceIndex < numFaces);
|
||||
}
|
||||
|
||||
const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->family == familyName
|
||||
&& (face->style.equalsIgnoreCase (style) || style.isEmpty()))
|
||||
return face;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool isFaceSansSerif (const String& family)
|
||||
{
|
||||
static const char* sansNames[] = { "Sans", "Verdana", "Arial", "Ubuntu" };
|
||||
|
||||
for (auto* name : sansNames)
|
||||
if (family.containsIgnoreCase (name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTTypefaceList)
|
||||
};
|
||||
|
||||
JUCE_IMPLEMENT_SINGLETON (FTTypefaceList)
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FreeTypeTypeface : public CustomTypeface
|
||||
{
|
||||
public:
|
||||
FreeTypeTypeface (const Font& font)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (font.getTypefaceName(),
|
||||
font.getTypefaceStyle()))
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (font.getTypefaceName(),
|
||||
font.getTypefaceStyle());
|
||||
}
|
||||
|
||||
FreeTypeTypeface (const void* data, size_t dataSize)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (data, dataSize, 0))
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (faceWrapper->face->family_name,
|
||||
faceWrapper->face->style_name);
|
||||
}
|
||||
|
||||
void initialiseCharacteristics (const String& fontName, const String& fontStyle)
|
||||
{
|
||||
setCharacteristics (fontName, fontStyle,
|
||||
faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender),
|
||||
L' ');
|
||||
}
|
||||
|
||||
bool loadGlyphIfPossible (const juce_wchar character)
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
{
|
||||
auto face = faceWrapper->face;
|
||||
auto glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
|
||||
|
||||
if (FT_Load_Glyph (face, glyphIndex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING) == 0
|
||||
&& face->glyph->format == ft_glyph_format_outline)
|
||||
{
|
||||
auto scale = 1.0f / (float) (face->ascender - face->descender);
|
||||
Path destShape;
|
||||
|
||||
if (getGlyphShape (destShape, face->glyph->outline, scale))
|
||||
{
|
||||
addGlyph (character, destShape, (float) face->glyph->metrics.horiAdvance * scale);
|
||||
|
||||
if ((face->face_flags & FT_FACE_FLAG_KERNING) != 0)
|
||||
addKerning (face, (uint32) character, glyphIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
FTFaceWrapper::Ptr faceWrapper;
|
||||
|
||||
bool getGlyphShape (Path& destShape, const FT_Outline& outline, float scaleX)
|
||||
{
|
||||
auto scaleY = -scaleX;
|
||||
auto* contours = outline.contours;
|
||||
auto* tags = outline.tags;
|
||||
auto* points = outline.points;
|
||||
|
||||
for (int c = 0; c < outline.n_contours; ++c)
|
||||
{
|
||||
const int startPoint = (c == 0) ? 0 : contours [c - 1] + 1;
|
||||
const int endPoint = contours[c];
|
||||
|
||||
for (int p = startPoint; p <= endPoint; ++p)
|
||||
{
|
||||
auto x = scaleX * (float) points[p].x;
|
||||
auto y = scaleY * (float) points[p].y;
|
||||
|
||||
if (p == startPoint)
|
||||
{
|
||||
if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
auto x2 = scaleX * (float) points[endPoint].x;
|
||||
auto y2 = scaleY * (float) points[endPoint].y;
|
||||
|
||||
if (FT_CURVE_TAG (tags[endPoint]) != FT_Curve_Tag_On)
|
||||
{
|
||||
x2 = (x + x2) * 0.5f;
|
||||
y2 = (y + y2) * 0.5f;
|
||||
}
|
||||
|
||||
destShape.startNewSubPath (x2, y2);
|
||||
}
|
||||
else
|
||||
{
|
||||
destShape.startNewSubPath (x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_On)
|
||||
{
|
||||
if (p != startPoint)
|
||||
destShape.lineTo (x, y);
|
||||
}
|
||||
else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
const int nextIndex = (p == endPoint) ? startPoint : p + 1;
|
||||
auto x2 = scaleX * (float) points[nextIndex].x;
|
||||
auto y2 = scaleY * (float) points[nextIndex].y;
|
||||
|
||||
if (FT_CURVE_TAG (tags [nextIndex]) == FT_Curve_Tag_Conic)
|
||||
{
|
||||
x2 = (x + x2) * 0.5f;
|
||||
y2 = (y + y2) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
destShape.quadraticTo (x, y, x2, y2);
|
||||
}
|
||||
else if (FT_CURVE_TAG (tags[p]) == FT_Curve_Tag_Cubic)
|
||||
{
|
||||
const int next1 = p + 1;
|
||||
const int next2 = (p == (endPoint - 1)) ? startPoint : (p + 2);
|
||||
|
||||
if (p >= endPoint
|
||||
|| FT_CURVE_TAG (tags[next1]) != FT_Curve_Tag_Cubic
|
||||
|| FT_CURVE_TAG (tags[next2]) != FT_Curve_Tag_On)
|
||||
return false;
|
||||
|
||||
auto x2 = scaleX * (float) points[next1].x;
|
||||
auto y2 = scaleY * (float) points[next1].y;
|
||||
auto x3 = scaleX * (float) points[next2].x;
|
||||
auto y3 = scaleY * (float) points[next2].y;
|
||||
|
||||
destShape.cubicTo (x, y, x2, y2, x3, y3);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
destShape.closeSubPath();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
|
||||
{
|
||||
auto height = (float) (face->ascender - face->descender);
|
||||
|
||||
uint32 rightGlyphIndex;
|
||||
auto rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
|
||||
|
||||
while (rightGlyphIndex != 0)
|
||||
{
|
||||
FT_Vector kerning;
|
||||
|
||||
if (FT_Get_Kerning (face, glyphIndex, rightGlyphIndex, ft_kerning_unscaled, &kerning) == 0
|
||||
&& kerning.x != 0)
|
||||
addKerningPair ((juce_wchar) character, (juce_wchar) rightCharCode, (float) kerning.x / height);
|
||||
|
||||
rightCharCode = FT_Get_Next_Char (face, rightCharCode, &rightGlyphIndex);
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,197 +1,233 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
static std::unique_ptr<XmlElement> findFontsConfFile()
|
||||
{
|
||||
static const char* pathsToSearch[] = { "/etc/fonts/fonts.conf",
|
||||
"/usr/share/fonts/fonts.conf",
|
||||
"/usr/local/etc/fonts/fonts.conf" };
|
||||
|
||||
for (auto* path : pathsToSearch)
|
||||
if (auto xml = parseXML (File (path)))
|
||||
return xml;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray FTTypefaceList::getDefaultFontDirectories()
|
||||
{
|
||||
StringArray fontDirs;
|
||||
|
||||
fontDirs.addTokens (String (CharPointer_UTF8 (getenv ("JUCE_FONT_PATH"))), ";,", "");
|
||||
fontDirs.removeEmptyStrings (true);
|
||||
|
||||
if (fontDirs.isEmpty())
|
||||
{
|
||||
if (auto fontsInfo = findFontsConfFile())
|
||||
{
|
||||
for (auto* e : fontsInfo->getChildWithTagNameIterator ("dir"))
|
||||
{
|
||||
auto fontPath = e->getAllSubText().trim();
|
||||
|
||||
if (fontPath.isNotEmpty())
|
||||
{
|
||||
if (e->getStringAttribute ("prefix") == "xdg")
|
||||
{
|
||||
auto xdgDataHome = SystemStats::getEnvironmentVariable ("XDG_DATA_HOME", {});
|
||||
|
||||
if (xdgDataHome.trimStart().isEmpty())
|
||||
xdgDataHome = "~/.local/share";
|
||||
|
||||
fontPath = File (xdgDataHome).getChildFile (fontPath).getFullPathName();
|
||||
}
|
||||
|
||||
fontDirs.add (fontPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fontDirs.isEmpty())
|
||||
fontDirs.add ("/usr/X11R6/lib/X11/fonts");
|
||||
|
||||
fontDirs.removeDuplicates (false);
|
||||
return fontDirs;
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new FreeTypeTypeface (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize)
|
||||
{
|
||||
return new FreeTypeTypeface (data, dataSize);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct DefaultFontNames
|
||||
{
|
||||
DefaultFontNames()
|
||||
: defaultSans (getDefaultSansSerifFontName()),
|
||||
defaultSerif (getDefaultSerifFontName()),
|
||||
defaultFixed (getDefaultMonospacedFontName())
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
static String pickBestFont (const StringArray& names, const char* const* choicesArray)
|
||||
{
|
||||
const StringArray choices (choicesArray);
|
||||
|
||||
for (auto& choice : choices)
|
||||
if (names.contains (choice, true))
|
||||
return choice;
|
||||
|
||||
for (auto& choice : choices)
|
||||
for (auto& name : names)
|
||||
if (name.startsWithIgnoreCase (choice))
|
||||
return name;
|
||||
|
||||
for (auto& choice : choices)
|
||||
for (auto& name : names)
|
||||
if (name.containsIgnoreCase (choice))
|
||||
return name;
|
||||
|
||||
return names[0];
|
||||
}
|
||||
|
||||
static String getDefaultSansSerifFontName()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getSansSerifNames (allFonts);
|
||||
|
||||
static const char* targets[] = { "Verdana", "Bitstream Vera Sans", "Luxi Sans",
|
||||
"Liberation Sans", "DejaVu Sans", "Sans", nullptr };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
static String getDefaultSerifFontName()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getSerifNames (allFonts);
|
||||
|
||||
static const char* targets[] = { "Bitstream Vera Serif", "Times", "Nimbus Roman",
|
||||
"Liberation Serif", "DejaVu Serif", "Serif", nullptr };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
static String getDefaultMonospacedFontName()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getMonospacedNames (allFonts);
|
||||
|
||||
static const char* targets[] = { "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Sans Mono",
|
||||
"Liberation Mono", "Courier", "DejaVu Mono", "Mono", nullptr };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (DefaultFontNames)
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static DefaultFontNames defaultNames;
|
||||
|
||||
Font f (font);
|
||||
f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName()));
|
||||
return Typeface::createSystemTypefaceFor (f);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
static std::unique_ptr<XmlElement> findFontsConfFile()
|
||||
{
|
||||
static const char* pathsToSearch[] = { "/etc/fonts/fonts.conf",
|
||||
"/usr/share/fonts/fonts.conf",
|
||||
"/usr/local/etc/fonts/fonts.conf",
|
||||
"/usr/share/defaults/fonts/fonts.conf" };
|
||||
|
||||
for (auto* path : pathsToSearch)
|
||||
if (auto xml = parseXML (File (path)))
|
||||
return xml;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringArray FTTypefaceList::getDefaultFontDirectories()
|
||||
{
|
||||
StringArray fontDirs;
|
||||
|
||||
fontDirs.addTokens (String (CharPointer_UTF8 (getenv ("JUCE_FONT_PATH"))), ";,", "");
|
||||
fontDirs.removeEmptyStrings (true);
|
||||
|
||||
if (fontDirs.isEmpty())
|
||||
{
|
||||
if (auto fontsInfo = findFontsConfFile())
|
||||
{
|
||||
for (auto* e : fontsInfo->getChildWithTagNameIterator ("dir"))
|
||||
{
|
||||
auto fontPath = e->getAllSubText().trim();
|
||||
|
||||
if (fontPath.isNotEmpty())
|
||||
{
|
||||
if (e->getStringAttribute ("prefix") == "xdg")
|
||||
{
|
||||
auto xdgDataHome = SystemStats::getEnvironmentVariable ("XDG_DATA_HOME", {});
|
||||
|
||||
if (xdgDataHome.trimStart().isEmpty())
|
||||
xdgDataHome = "~/.local/share";
|
||||
|
||||
fontPath = File (xdgDataHome).getChildFile (fontPath).getFullPathName();
|
||||
}
|
||||
|
||||
fontDirs.add (fontPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fontDirs.isEmpty())
|
||||
fontDirs.add ("/usr/X11R6/lib/X11/fonts");
|
||||
|
||||
fontDirs.removeDuplicates (false);
|
||||
return fontDirs;
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new FreeTypeTypeface (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize)
|
||||
{
|
||||
return new FreeTypeTypeface (data, dataSize);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct DefaultFontInfo
|
||||
{
|
||||
struct Characteristics
|
||||
{
|
||||
explicit Characteristics (String nameIn) : name (nameIn) {}
|
||||
|
||||
Characteristics withStyle (String styleIn) const
|
||||
{
|
||||
auto copy = *this;
|
||||
copy.style = std::move (styleIn);
|
||||
return copy;
|
||||
}
|
||||
|
||||
String name, style;
|
||||
};
|
||||
|
||||
DefaultFontInfo()
|
||||
: defaultSans (getDefaultSansSerifFontCharacteristics()),
|
||||
defaultSerif (getDefaultSerifFontCharacteristics()),
|
||||
defaultFixed (getDefaultMonospacedFontCharacteristics())
|
||||
{
|
||||
}
|
||||
|
||||
Characteristics getRealFontCharacteristics (const String& faceName) const
|
||||
{
|
||||
if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans;
|
||||
if (faceName == Font::getDefaultSerifFontName()) return defaultSerif;
|
||||
if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed;
|
||||
|
||||
return Characteristics { faceName };
|
||||
}
|
||||
|
||||
Characteristics defaultSans, defaultSerif, defaultFixed;
|
||||
|
||||
private:
|
||||
template <typename Range>
|
||||
static Characteristics pickBestFont (const StringArray& names, Range&& choicesArray)
|
||||
{
|
||||
for (auto& choice : choicesArray)
|
||||
if (names.contains (choice.name, true))
|
||||
return choice;
|
||||
|
||||
for (auto& choice : choicesArray)
|
||||
for (auto& name : names)
|
||||
if (name.startsWithIgnoreCase (choice.name))
|
||||
return Characteristics { name }.withStyle (choice.style);
|
||||
|
||||
for (auto& choice : choicesArray)
|
||||
for (auto& name : names)
|
||||
if (name.containsIgnoreCase (choice.name))
|
||||
return Characteristics { name }.withStyle (choice.style);
|
||||
|
||||
return Characteristics { names[0] };
|
||||
}
|
||||
|
||||
static Characteristics getDefaultSansSerifFontCharacteristics()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getSansSerifNames (allFonts);
|
||||
|
||||
static const Characteristics targets[] { Characteristics { "Verdana" },
|
||||
Characteristics { "Bitstream Vera Sans" }.withStyle ("Roman"),
|
||||
Characteristics { "Luxi Sans" },
|
||||
Characteristics { "Liberation Sans" },
|
||||
Characteristics { "DejaVu Sans" },
|
||||
Characteristics { "Sans" } };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
static Characteristics getDefaultSerifFontCharacteristics()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getSerifNames (allFonts);
|
||||
|
||||
static const Characteristics targets[] { Characteristics { "Bitstream Vera Serif" }.withStyle ("Roman"),
|
||||
Characteristics { "Times" },
|
||||
Characteristics { "Nimbus Roman" },
|
||||
Characteristics { "Liberation Serif" },
|
||||
Characteristics { "DejaVu Serif" },
|
||||
Characteristics { "Serif" } };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
static Characteristics getDefaultMonospacedFontCharacteristics()
|
||||
{
|
||||
StringArray allFonts;
|
||||
FTTypefaceList::getInstance()->getMonospacedNames (allFonts);
|
||||
|
||||
static const Characteristics targets[] { Characteristics { "DejaVu Sans Mono" },
|
||||
Characteristics { "Bitstream Vera Sans Mono" }.withStyle ("Roman"),
|
||||
Characteristics { "Sans Mono" },
|
||||
Characteristics { "Liberation Mono" },
|
||||
Characteristics { "Courier" },
|
||||
Characteristics { "DejaVu Mono" },
|
||||
Characteristics { "Mono" } };
|
||||
return pickBestFont (allFonts, targets);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (DefaultFontInfo)
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static const DefaultFontInfo defaultInfo;
|
||||
|
||||
Font f (font);
|
||||
|
||||
const auto name = font.getTypefaceName();
|
||||
const auto characteristics = defaultInfo.getRealFontCharacteristics (name);
|
||||
f.setTypefaceName (characteristics.name);
|
||||
|
||||
const auto styles = findAllTypefaceStyles (name);
|
||||
|
||||
if (! styles.contains (font.getTypefaceStyle()))
|
||||
f.setTypefaceStyle (characteristics.style);
|
||||
|
||||
return Typeface::createSystemTypefaceFor (f);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,29 +1,30 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int);
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
|
@ -1,150 +1,150 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct ColorSpaceDelete
|
||||
{
|
||||
void operator() (CGColorSpaceRef ptr) const noexcept { CGColorSpaceRelease (ptr); }
|
||||
};
|
||||
|
||||
struct ContextDelete
|
||||
{
|
||||
void operator() (CGContextRef ptr) const noexcept { CGContextRelease (ptr); }
|
||||
};
|
||||
|
||||
struct DataProviderDelete
|
||||
{
|
||||
void operator() (CGDataProviderRef ptr) const noexcept { CGDataProviderRelease (ptr); }
|
||||
};
|
||||
|
||||
struct ImageDelete
|
||||
{
|
||||
void operator() (CGImageRef ptr) const noexcept { CGImageRelease (ptr); }
|
||||
};
|
||||
|
||||
struct GradientDelete
|
||||
{
|
||||
void operator() (CGGradientRef ptr) const noexcept { CGGradientRelease (ptr); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
using ColorSpacePtr = std::unique_ptr<CGColorSpace, ColorSpaceDelete>;
|
||||
using ContextPtr = std::unique_ptr<CGContext, ContextDelete>;
|
||||
using DataProviderPtr = std::unique_ptr<CGDataProvider, DataProviderDelete>;
|
||||
using ImagePtr = std::unique_ptr<CGImage, ImageDelete>;
|
||||
using GradientPtr = std::unique_ptr<CGGradient, GradientDelete>;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class CoreGraphicsContext : public LowLevelGraphicsContext
|
||||
{
|
||||
public:
|
||||
CoreGraphicsContext (CGContextRef context, float flipHeight);
|
||||
~CoreGraphicsContext() override;
|
||||
|
||||
//==============================================================================
|
||||
bool isVectorDevice() const override { return false; }
|
||||
|
||||
void setOrigin (Point<int>) override;
|
||||
void addTransform (const AffineTransform&) override;
|
||||
float getPhysicalPixelScaleFactor() override;
|
||||
bool clipToRectangle (const Rectangle<int>&) override;
|
||||
bool clipToRectangleList (const RectangleList<int>&) override;
|
||||
void excludeClipRectangle (const Rectangle<int>&) override;
|
||||
void clipToPath (const Path&, const AffineTransform&) override;
|
||||
void clipToImageAlpha (const Image&, const AffineTransform&) override;
|
||||
bool clipRegionIntersects (const Rectangle<int>&) override;
|
||||
Rectangle<int> getClipBounds() const override;
|
||||
bool isClipEmpty() const override;
|
||||
|
||||
//==============================================================================
|
||||
void saveState() override;
|
||||
void restoreState() override;
|
||||
void beginTransparencyLayer (float opacity) override;
|
||||
void endTransparencyLayer() override;
|
||||
|
||||
//==============================================================================
|
||||
void setFill (const FillType&) override;
|
||||
void setOpacity (float) override;
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality) override;
|
||||
|
||||
//==============================================================================
|
||||
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
|
||||
void fillRect (const Rectangle<float>&) override;
|
||||
void fillRectList (const RectangleList<float>&) override;
|
||||
void fillPath (const Path&, const AffineTransform&) override;
|
||||
void drawImage (const Image& sourceImage, const AffineTransform&) override;
|
||||
|
||||
//==============================================================================
|
||||
void drawLine (const Line<float>&) override;
|
||||
void setFont (const Font&) override;
|
||||
const Font& getFont() override;
|
||||
void drawGlyph (int glyphNumber, const AffineTransform&) override;
|
||||
bool drawTextLayout (const AttributedString&, const Rectangle<float>&) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
detail::ContextPtr context;
|
||||
const CGFloat flipHeight;
|
||||
detail::ColorSpacePtr rgbColourSpace, greyColourSpace;
|
||||
mutable Rectangle<int> lastClipRect;
|
||||
mutable bool lastClipRectIsValid = false;
|
||||
|
||||
struct SavedState
|
||||
{
|
||||
SavedState();
|
||||
SavedState (const SavedState&);
|
||||
~SavedState();
|
||||
|
||||
void setFill (const FillType&);
|
||||
|
||||
FillType fillType;
|
||||
Font font;
|
||||
CGFontRef fontRef = {};
|
||||
CGAffineTransform textMatrix = CGAffineTransformIdentity,
|
||||
inverseTextMatrix = CGAffineTransformIdentity;
|
||||
detail::GradientPtr gradient = {};
|
||||
};
|
||||
|
||||
std::unique_ptr<SavedState> state;
|
||||
OwnedArray<SavedState> stateStack;
|
||||
|
||||
void drawGradient();
|
||||
void createPath (const Path&) const;
|
||||
void createPath (const Path&, const AffineTransform&) const;
|
||||
void flip() const;
|
||||
void applyTransform (const AffineTransform&) const;
|
||||
void drawImage (const Image&, const AffineTransform&, bool fillEntireClipAsTiles);
|
||||
bool clipToRectangleListWithoutTest (const RectangleList<int>&);
|
||||
void fillCGRect (const CGRect&, bool replaceExistingContents);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsContext)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct ColorSpaceDelete
|
||||
{
|
||||
void operator() (CGColorSpaceRef ptr) const noexcept { CGColorSpaceRelease (ptr); }
|
||||
};
|
||||
|
||||
struct ContextDelete
|
||||
{
|
||||
void operator() (CGContextRef ptr) const noexcept { CGContextRelease (ptr); }
|
||||
};
|
||||
|
||||
struct DataProviderDelete
|
||||
{
|
||||
void operator() (CGDataProviderRef ptr) const noexcept { CGDataProviderRelease (ptr); }
|
||||
};
|
||||
|
||||
struct ImageDelete
|
||||
{
|
||||
void operator() (CGImageRef ptr) const noexcept { CGImageRelease (ptr); }
|
||||
};
|
||||
|
||||
struct GradientDelete
|
||||
{
|
||||
void operator() (CGGradientRef ptr) const noexcept { CGGradientRelease (ptr); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
using ColorSpacePtr = std::unique_ptr<CGColorSpace, ColorSpaceDelete>;
|
||||
using ContextPtr = std::unique_ptr<CGContext, ContextDelete>;
|
||||
using DataProviderPtr = std::unique_ptr<CGDataProvider, DataProviderDelete>;
|
||||
using ImagePtr = std::unique_ptr<CGImage, ImageDelete>;
|
||||
using GradientPtr = std::unique_ptr<CGGradient, GradientDelete>;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class CoreGraphicsContext : public LowLevelGraphicsContext
|
||||
{
|
||||
public:
|
||||
CoreGraphicsContext (CGContextRef context, float flipHeight);
|
||||
~CoreGraphicsContext() override;
|
||||
|
||||
//==============================================================================
|
||||
bool isVectorDevice() const override { return false; }
|
||||
|
||||
void setOrigin (Point<int>) override;
|
||||
void addTransform (const AffineTransform&) override;
|
||||
float getPhysicalPixelScaleFactor() override;
|
||||
bool clipToRectangle (const Rectangle<int>&) override;
|
||||
bool clipToRectangleList (const RectangleList<int>&) override;
|
||||
void excludeClipRectangle (const Rectangle<int>&) override;
|
||||
void clipToPath (const Path&, const AffineTransform&) override;
|
||||
void clipToImageAlpha (const Image&, const AffineTransform&) override;
|
||||
bool clipRegionIntersects (const Rectangle<int>&) override;
|
||||
Rectangle<int> getClipBounds() const override;
|
||||
bool isClipEmpty() const override;
|
||||
|
||||
//==============================================================================
|
||||
void saveState() override;
|
||||
void restoreState() override;
|
||||
void beginTransparencyLayer (float opacity) override;
|
||||
void endTransparencyLayer() override;
|
||||
|
||||
//==============================================================================
|
||||
void setFill (const FillType&) override;
|
||||
void setOpacity (float) override;
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality) override;
|
||||
|
||||
//==============================================================================
|
||||
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
|
||||
void fillRect (const Rectangle<float>&) override;
|
||||
void fillRectList (const RectangleList<float>&) override;
|
||||
void fillPath (const Path&, const AffineTransform&) override;
|
||||
void drawImage (const Image& sourceImage, const AffineTransform&) override;
|
||||
|
||||
//==============================================================================
|
||||
void drawLine (const Line<float>&) override;
|
||||
void setFont (const Font&) override;
|
||||
const Font& getFont() override;
|
||||
void drawGlyph (int glyphNumber, const AffineTransform&) override;
|
||||
bool drawTextLayout (const AttributedString&, const Rectangle<float>&) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
detail::ContextPtr context;
|
||||
const CGFloat flipHeight;
|
||||
detail::ColorSpacePtr rgbColourSpace, greyColourSpace;
|
||||
mutable Rectangle<int> lastClipRect;
|
||||
mutable bool lastClipRectIsValid = false;
|
||||
|
||||
struct SavedState
|
||||
{
|
||||
SavedState();
|
||||
SavedState (const SavedState&);
|
||||
~SavedState();
|
||||
|
||||
void setFill (const FillType&);
|
||||
|
||||
FillType fillType;
|
||||
Font font;
|
||||
CGFontRef fontRef = {};
|
||||
CGAffineTransform textMatrix = CGAffineTransformIdentity,
|
||||
inverseTextMatrix = CGAffineTransformIdentity;
|
||||
detail::GradientPtr gradient = {};
|
||||
};
|
||||
|
||||
std::unique_ptr<SavedState> state;
|
||||
OwnedArray<SavedState> stateStack;
|
||||
|
||||
void drawGradient();
|
||||
void createPath (const Path&) const;
|
||||
void createPath (const Path&, const AffineTransform&) const;
|
||||
void flip() const;
|
||||
void applyTransform (const AffineTransform&) const;
|
||||
void drawImage (const Image&, const AffineTransform&, bool fillEntireClipAsTiles);
|
||||
bool clipToRectangleListWithoutTest (const RectangleList<int>&);
|
||||
void fillCGRect (const CGRect&, bool replaceExistingContents);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsContext)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -2,15 +2,15 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
@ -41,19 +41,17 @@ public:
|
||||
|
||||
auto numComponents = (size_t) lineStride * (size_t) jmax (1, height);
|
||||
|
||||
# if JUCE_MAC && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
// This version of the SDK intermittently requires a bit of extra space
|
||||
// SDK version 10.14+ intermittently requires a bit of extra space
|
||||
// at the end of the image data. This feels like something has gone
|
||||
// wrong in Apple's code.
|
||||
numComponents += (size_t) lineStride;
|
||||
#endif
|
||||
|
||||
imageDataHolder->data.allocate (numComponents, clearImage);
|
||||
imageData->data.allocate (numComponents, clearImage);
|
||||
|
||||
auto colourSpace = detail::ColorSpacePtr { CGColorSpaceCreateWithName ((format == Image::SingleChannel) ? kCGColorSpaceGenericGrayGamma2_2
|
||||
: kCGColorSpaceSRGB) };
|
||||
|
||||
context = detail::ContextPtr { CGBitmapContextCreate (imageDataHolder->data, (size_t) width, (size_t) height, 8, (size_t) lineStride,
|
||||
context = detail::ContextPtr { CGBitmapContextCreate (imageData->data, (size_t) width, (size_t) height, 8, (size_t) lineStride,
|
||||
colourSpace.get(), getCGImageFlags (format)) };
|
||||
}
|
||||
|
||||
@ -71,7 +69,9 @@ public:
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
|
||||
{
|
||||
bitmap.data = imageDataHolder->data + x * pixelStride + y * lineStride;
|
||||
const auto offset = (size_t) (x * pixelStride + y * lineStride);
|
||||
bitmap.data = imageData->data + offset;
|
||||
bitmap.size = (size_t) (lineStride * height) - offset;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
@ -86,7 +86,7 @@ public:
|
||||
ImagePixelData::Ptr clone() override
|
||||
{
|
||||
auto im = new CoreGraphicsPixelData (pixelFormat, width, height, false);
|
||||
memcpy (im->imageDataHolder->data, imageDataHolder->data, (size_t) (lineStride * height));
|
||||
memcpy (im->imageData->data, imageData->data, (size_t) (lineStride * height));
|
||||
return *im;
|
||||
}
|
||||
|
||||
@ -98,12 +98,9 @@ public:
|
||||
auto cgim = dynamic_cast<CoreGraphicsPixelData*> (juceImage.getPixelData());
|
||||
|
||||
if (cgim != nullptr && cgim->cachedImageRef != nullptr)
|
||||
{
|
||||
CGImageRetain (cgim->cachedImageRef.get());
|
||||
return cgim->cachedImageRef.get();
|
||||
}
|
||||
return CGImageRetain (cgim->cachedImageRef.get());
|
||||
|
||||
CGImageRef ref = createImage (juceImage, colourSpace, false);
|
||||
CGImageRef ref = createImage (juceImage, colourSpace);
|
||||
|
||||
if (cgim != nullptr)
|
||||
cgim->cachedImageRef.reset (CGImageRetain (ref));
|
||||
@ -111,56 +108,47 @@ public:
|
||||
return ref;
|
||||
}
|
||||
|
||||
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace, bool mustOutliveSource)
|
||||
static CGImageRef createImage (const Image& juceImage, CGColorSpaceRef colourSpace)
|
||||
{
|
||||
const Image::BitmapData srcData (juceImage, Image::BitmapData::readOnly);
|
||||
detail::DataProviderPtr provider;
|
||||
|
||||
if (mustOutliveSource)
|
||||
const auto provider = [&]
|
||||
{
|
||||
CFUniquePtr<CFDataRef> data (CFDataCreate (nullptr,
|
||||
(const UInt8*) srcData.data,
|
||||
(CFIndex) ((size_t) srcData.lineStride * (size_t) srcData.height)));
|
||||
provider = detail::DataProviderPtr { CGDataProviderCreateWithCFData (data.get()) };
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* imageDataContainer = [] (const Image& img) -> HeapBlockContainer::Ptr*
|
||||
if (auto* cgim = dynamic_cast<CoreGraphicsPixelData*> (juceImage.getPixelData()))
|
||||
{
|
||||
if (auto* cgim = dynamic_cast<CoreGraphicsPixelData*> (img.getPixelData()))
|
||||
return new HeapBlockContainer::Ptr (cgim->imageDataHolder);
|
||||
|
||||
return nullptr;
|
||||
} (juceImage);
|
||||
|
||||
provider = detail::DataProviderPtr { CGDataProviderCreateWithData (imageDataContainer,
|
||||
return detail::DataProviderPtr { CGDataProviderCreateWithData (new ImageDataContainer::Ptr (cgim->imageData),
|
||||
srcData.data,
|
||||
(size_t) srcData.lineStride * (size_t) srcData.height,
|
||||
[] (void * __nullable info, const void*, size_t) { delete (HeapBlockContainer::Ptr*) info; }) };
|
||||
}
|
||||
srcData.size,
|
||||
[] (void * __nullable info, const void*, size_t) { delete (ImageDataContainer::Ptr*) info; }) };
|
||||
}
|
||||
|
||||
CGImageRef imageRef = CGImageCreate ((size_t) srcData.width,
|
||||
(size_t) srcData.height,
|
||||
8,
|
||||
(size_t) srcData.pixelStride * 8,
|
||||
(size_t) srcData.lineStride,
|
||||
colourSpace, getCGImageFlags (juceImage.getFormat()), provider.get(),
|
||||
nullptr, true, kCGRenderingIntentDefault);
|
||||
const auto usableSize = jmin ((size_t) srcData.lineStride * (size_t) srcData.height, srcData.size);
|
||||
CFUniquePtr<CFDataRef> data (CFDataCreate (nullptr, (const UInt8*) srcData.data, (CFIndex) usableSize));
|
||||
return detail::DataProviderPtr { CGDataProviderCreateWithCFData (data.get()) };
|
||||
}();
|
||||
|
||||
return imageRef;
|
||||
return CGImageCreate ((size_t) srcData.width,
|
||||
(size_t) srcData.height,
|
||||
8,
|
||||
(size_t) srcData.pixelStride * 8,
|
||||
(size_t) srcData.lineStride,
|
||||
colourSpace, getCGImageFlags (juceImage.getFormat()), provider.get(),
|
||||
nullptr, true, kCGRenderingIntentDefault);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
detail::ContextPtr context;
|
||||
detail::ImagePtr cachedImageRef;
|
||||
|
||||
struct HeapBlockContainer : public ReferenceCountedObject
|
||||
struct ImageDataContainer : public ReferenceCountedObject
|
||||
{
|
||||
using Ptr = ReferenceCountedObjectPtr<HeapBlockContainer>;
|
||||
ImageDataContainer() = default;
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<ImageDataContainer>;
|
||||
HeapBlock<uint8> data;
|
||||
};
|
||||
|
||||
HeapBlockContainer::Ptr imageDataHolder = new HeapBlockContainer();
|
||||
ImageDataContainer::Ptr imageData = new ImageDataContainer();
|
||||
int pixelStride, lineStride;
|
||||
|
||||
private:
|
||||
@ -329,7 +317,7 @@ void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const Affi
|
||||
if (sourceImage.getFormat() != Image::SingleChannel)
|
||||
singleChannelImage = sourceImage.convertedToFormat (Image::SingleChannel);
|
||||
|
||||
auto image = detail::ImagePtr { CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace.get(), true) };
|
||||
auto image = detail::ImagePtr { CoreGraphicsPixelData::createImage (singleChannelImage, greyColourSpace.get()) };
|
||||
|
||||
flip();
|
||||
auto t = AffineTransform::verticalFlip (sourceImage.getHeight()).followedBy (transform);
|
||||
@ -521,7 +509,7 @@ void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTrans
|
||||
|
||||
auto colourSpace = sourceImage.getFormat() == Image::PixelFormat::SingleChannel ? greyColourSpace.get()
|
||||
: rgbColourSpace.get();
|
||||
auto image = detail::ImagePtr { CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace) };
|
||||
detail::ImagePtr image { CoreGraphicsPixelData::getCachedImageRef (sourceImage, colourSpace) };
|
||||
|
||||
ScopedCGContextState scopedState (context.get());
|
||||
CGContextSetAlpha (context.get(), state->fillType.getOpacity());
|
||||
@ -899,10 +887,9 @@ Image juce_createImageFromCIImage (CIImage* im, int w, int h)
|
||||
return Image (*cgImage);
|
||||
}
|
||||
|
||||
CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace,
|
||||
const bool mustOutliveSource)
|
||||
CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, CGColorSpaceRef colourSpace)
|
||||
{
|
||||
return CoreGraphicsPixelData::createImage (juceImage, colourSpace, mustOutliveSource);
|
||||
return CoreGraphicsPixelData::createImage (juceImage, colourSpace);
|
||||
}
|
||||
|
||||
CGContextRef juce_getImageContext (const Image& image)
|
||||
@ -929,8 +916,11 @@ CGContextRef juce_getImageContext (const Image& image)
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC
|
||||
NSImage* imageToNSImage (const Image& image, float scaleFactor)
|
||||
NSImage* imageToNSImage (const ScaledImage& scaled)
|
||||
{
|
||||
const auto image = scaled.getImage();
|
||||
const auto scaleFactor = scaled.getScale();
|
||||
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
NSImage* im = [[NSImage alloc] init];
|
||||
@ -938,7 +928,7 @@ CGContextRef juce_getImageContext (const Image& image)
|
||||
|
||||
[im setSize: requiredSize];
|
||||
detail::ColorSpacePtr colourSpace { CGColorSpaceCreateWithName (kCGColorSpaceSRGB) };
|
||||
detail::ImagePtr imageRef { juce_createCoreGraphicsImage (image, colourSpace.get(), true) };
|
||||
detail::ImagePtr imageRef { juce_createCoreGraphicsImage (image, colourSpace.get()) };
|
||||
|
||||
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: imageRef.get()];
|
||||
[imageRep setSize: requiredSize];
|
||||
|
@ -1,108 +1,108 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
template <class RectType>
|
||||
Rectangle<int> convertToRectInt (RectType r) noexcept
|
||||
{
|
||||
return { (int) r.origin.x,
|
||||
(int) r.origin.y,
|
||||
(int) r.size.width,
|
||||
(int) r.size.height };
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
Rectangle<float> convertToRectFloat (RectType r) noexcept
|
||||
{
|
||||
return { (float) r.origin.x,
|
||||
(float) r.origin.y,
|
||||
(float) r.size.width,
|
||||
(float) r.size.height };
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
CGRect convertToCGRect (RectType r) noexcept
|
||||
{
|
||||
return CGRectMake ((CGFloat) r.getX(), (CGFloat) r.getY(), (CGFloat) r.getWidth(), (CGFloat) r.getHeight());
|
||||
}
|
||||
|
||||
template <class PointType>
|
||||
Point<float> convertToPointFloat (PointType p) noexcept
|
||||
{
|
||||
return { (float) p.x, (float) p.y };
|
||||
}
|
||||
|
||||
template <typename PointType>
|
||||
CGPoint convertToCGPoint (PointType p) noexcept
|
||||
{
|
||||
return CGPointMake ((CGFloat) p.x, (CGFloat) p.y);
|
||||
}
|
||||
|
||||
template <class PointType>
|
||||
Point<int> roundToIntPoint (PointType p) noexcept
|
||||
{
|
||||
return { roundToInt (p.x), roundToInt (p.y) };
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
inline CGFloat getMainScreenHeight() noexcept
|
||||
{
|
||||
if ([[NSScreen screens] count] == 0)
|
||||
return 0.0f;
|
||||
|
||||
return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
|
||||
}
|
||||
|
||||
inline NSRect flippedScreenRect (NSRect r) noexcept
|
||||
{
|
||||
r.origin.y = getMainScreenHeight() - (r.origin.y + r.size.height);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline NSPoint flippedScreenPoint (NSPoint p) noexcept
|
||||
{
|
||||
p.y = getMainScreenHeight() - p.y;
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource);
|
||||
CGContextRef juce_getImageContext (const Image&);
|
||||
|
||||
#if JUCE_IOS
|
||||
Image juce_createImageFromUIImage (UIImage*);
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC
|
||||
NSImage* imageToNSImage (const Image& image, float scaleFactor = 1.0f);
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
template <class RectType>
|
||||
Rectangle<int> convertToRectInt (RectType r) noexcept
|
||||
{
|
||||
return { (int) r.origin.x,
|
||||
(int) r.origin.y,
|
||||
(int) r.size.width,
|
||||
(int) r.size.height };
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
Rectangle<float> convertToRectFloat (RectType r) noexcept
|
||||
{
|
||||
return { (float) r.origin.x,
|
||||
(float) r.origin.y,
|
||||
(float) r.size.width,
|
||||
(float) r.size.height };
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
CGRect convertToCGRect (RectType r) noexcept
|
||||
{
|
||||
return CGRectMake ((CGFloat) r.getX(), (CGFloat) r.getY(), (CGFloat) r.getWidth(), (CGFloat) r.getHeight());
|
||||
}
|
||||
|
||||
template <class PointType>
|
||||
Point<float> convertToPointFloat (PointType p) noexcept
|
||||
{
|
||||
return { (float) p.x, (float) p.y };
|
||||
}
|
||||
|
||||
template <typename PointType>
|
||||
CGPoint convertToCGPoint (PointType p) noexcept
|
||||
{
|
||||
return CGPointMake ((CGFloat) p.x, (CGFloat) p.y);
|
||||
}
|
||||
|
||||
template <class PointType>
|
||||
Point<int> roundToIntPoint (PointType p) noexcept
|
||||
{
|
||||
return { roundToInt (p.x), roundToInt (p.y) };
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
inline CGFloat getMainScreenHeight() noexcept
|
||||
{
|
||||
if ([[NSScreen screens] count] == 0)
|
||||
return 0.0f;
|
||||
|
||||
return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
|
||||
}
|
||||
|
||||
inline NSRect flippedScreenRect (NSRect r) noexcept
|
||||
{
|
||||
r.origin.y = getMainScreenHeight() - (r.origin.y + r.size.height);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline NSPoint flippedScreenPoint (NSPoint p) noexcept
|
||||
{
|
||||
p.y = getMainScreenHeight() - p.y;
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef);
|
||||
CGContextRef juce_getImageContext (const Image&);
|
||||
|
||||
#if JUCE_IOS
|
||||
Image juce_createImageFromUIImage (UIImage*);
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC
|
||||
NSImage* imageToNSImage (const ScaledImage& image);
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
@ -2,15 +2,15 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
@ -208,34 +208,75 @@ namespace CoreTextTypeLayout
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// A flatmap that properly retains/releases font refs
|
||||
class FontMap
|
||||
{
|
||||
public:
|
||||
void emplace (CTFontRef ctFontRef, Font value)
|
||||
{
|
||||
pairs.emplace (std::lower_bound (pairs.begin(), pairs.end(), ctFontRef), ctFontRef, std::move (value));
|
||||
}
|
||||
|
||||
const Font* find (CTFontRef ctFontRef) const
|
||||
{
|
||||
const auto iter = std::lower_bound (pairs.begin(), pairs.end(), ctFontRef);
|
||||
|
||||
if (iter == pairs.end())
|
||||
return nullptr;
|
||||
|
||||
if (iter->key.get() != ctFontRef)
|
||||
return nullptr;
|
||||
|
||||
return &iter->value;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Pair
|
||||
{
|
||||
Pair (CTFontRef ref, Font font) : key (ref), value (std::move (font)) { CFRetain (ref); }
|
||||
|
||||
bool operator< (CTFontRef other) const { return key.get() < other; }
|
||||
|
||||
CFUniquePtr<CTFontRef> key;
|
||||
Font value;
|
||||
};
|
||||
|
||||
std::vector<Pair> pairs;
|
||||
};
|
||||
|
||||
struct AttributedStringAndFontMap
|
||||
{
|
||||
CFUniquePtr<CFAttributedStringRef> string;
|
||||
std::map<CTFontRef, Font> fontMap;
|
||||
FontMap fontMap;
|
||||
};
|
||||
|
||||
static AttributedStringAndFontMap createCFAttributedString (const AttributedString& text)
|
||||
{
|
||||
std::map<CTFontRef, Font> fontMap;
|
||||
FontMap fontMap;
|
||||
|
||||
const detail::ColorSpacePtr rgbColourSpace { CGColorSpaceCreateWithName (kCGColorSpaceSRGB) };
|
||||
|
||||
auto attribString = CFAttributedStringCreateMutable (kCFAllocatorDefault, 0);
|
||||
CFUniquePtr<CFStringRef> cfText (text.getText().toCFString());
|
||||
|
||||
CFAttributedStringReplaceString (attribString, CFRangeMake (0, 0), cfText.get());
|
||||
|
||||
auto numCharacterAttributes = text.getNumAttributes();
|
||||
auto attribStringLen = CFAttributedStringGetLength (attribString);
|
||||
const auto numCharacterAttributes = text.getNumAttributes();
|
||||
const auto attribStringLen = CFAttributedStringGetLength (attribString);
|
||||
const auto beginPtr = text.getText().toUTF16();
|
||||
auto currentPosition = beginPtr;
|
||||
|
||||
for (int i = 0; i < numCharacterAttributes; ++i)
|
||||
for (int i = 0; i < numCharacterAttributes; currentPosition += text.getAttribute (i).range.getLength(), ++i)
|
||||
{
|
||||
auto& attr = text.getAttribute (i);
|
||||
auto rangeStart = attr.range.getStart();
|
||||
const auto& attr = text.getAttribute (i);
|
||||
const auto wordBegin = currentPosition.getAddress() - beginPtr.getAddress();
|
||||
|
||||
if (rangeStart >= attribStringLen)
|
||||
if (attribStringLen <= wordBegin)
|
||||
continue;
|
||||
|
||||
auto range = CFRangeMake (rangeStart, jmin (attr.range.getEnd(), (int) attribStringLen) - rangeStart);
|
||||
const auto wordEndAddress = (currentPosition + attr.range.getLength()).getAddress();
|
||||
const auto wordEnd = jmin (attribStringLen, (CFIndex) (wordEndAddress - beginPtr.getAddress()));
|
||||
const auto range = CFRangeMake (wordBegin, wordEnd - wordBegin);
|
||||
|
||||
if (auto ctFontRef = getOrCreateFont (attr.font))
|
||||
{
|
||||
@ -300,7 +341,7 @@ namespace CoreTextTypeLayout
|
||||
struct FramesetterAndFontMap
|
||||
{
|
||||
CFUniquePtr<CTFramesetterRef> framesetter;
|
||||
std::map<CTFontRef, Font> fontMap;
|
||||
FontMap fontMap;
|
||||
};
|
||||
|
||||
static FramesetterAndFontMap createCTFramesetter (const AttributedString& text)
|
||||
@ -324,7 +365,7 @@ namespace CoreTextTypeLayout
|
||||
struct FrameAndFontMap
|
||||
{
|
||||
CFUniquePtr<CTFrameRef> frame;
|
||||
std::map<CTFontRef, Font> fontMap;
|
||||
FontMap fontMap;
|
||||
};
|
||||
|
||||
static FrameAndFontMap createCTFrame (const AttributedString& text, CGRect bounds)
|
||||
@ -476,10 +517,8 @@ namespace CoreTextTypeLayout
|
||||
{
|
||||
glyphRun->font = [&]
|
||||
{
|
||||
auto it = frameAndMap.fontMap.find (ctRunFont);
|
||||
|
||||
if (it != frameAndMap.fontMap.end())
|
||||
return it->second;
|
||||
if (auto* it = frameAndMap.fontMap.find (ctRunFont))
|
||||
return *it;
|
||||
|
||||
CFUniquePtr<CFStringRef> cfsFontName (CTFontCopyPostScriptName (ctRunFont));
|
||||
CFUniquePtr<CTFontRef> ctFontRef (CTFontCreateWithName (cfsFontName.get(), referenceFontSize, nullptr));
|
||||
|
@ -1,141 +1,141 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
extern Image JUCE_API getIconFromApplication (const String&, int);
|
||||
|
||||
static Image getIconFromIcnsFile (const File& icnsFile, const int size)
|
||||
{
|
||||
FileInputStream stream (icnsFile);
|
||||
|
||||
if (! stream.openedOk())
|
||||
return {};
|
||||
|
||||
const int numHeaderSectionBytes = 4;
|
||||
char headerSection [numHeaderSectionBytes];
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes
|
||||
|| headerSection[0] != 'i'
|
||||
|| headerSection[1] != 'c'
|
||||
|| headerSection[2] != 'n'
|
||||
|| headerSection[3] != 's')
|
||||
return {};
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
|
||||
return {};
|
||||
|
||||
const auto dataSize = juce::ByteOrder::bigEndianInt (headerSection);
|
||||
|
||||
if (dataSize <= 0)
|
||||
return {};
|
||||
|
||||
OwnedArray<juce::ImageFileFormat> internalFormats;
|
||||
internalFormats.add (new PNGImageFormat());
|
||||
internalFormats.add (new JPEGImageFormat());
|
||||
|
||||
Array<Image> images;
|
||||
auto maxWidth = 0;
|
||||
auto maxWidthIndex = -1;
|
||||
|
||||
while (stream.getPosition() < dataSize)
|
||||
{
|
||||
const auto sectionStart = stream.getPosition();
|
||||
|
||||
if (! stream.setPosition (sectionStart + 4))
|
||||
break;
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
|
||||
break;
|
||||
|
||||
const auto sectionSize = ByteOrder::bigEndianInt (headerSection);
|
||||
|
||||
if (sectionSize <= 0)
|
||||
break;
|
||||
|
||||
const auto sectionDataStart = stream.getPosition();
|
||||
|
||||
for (auto* fmt : internalFormats)
|
||||
{
|
||||
if (fmt->canUnderstand (stream))
|
||||
{
|
||||
stream.setPosition (sectionDataStart);
|
||||
|
||||
images.add (fmt->decodeImage (stream));
|
||||
|
||||
const auto lastImageIndex = images.size() - 1;
|
||||
const auto lastWidth = images.getReference (lastImageIndex).getWidth();
|
||||
|
||||
if (lastWidth > maxWidth)
|
||||
{
|
||||
maxWidthIndex = lastImageIndex;
|
||||
maxWidth = lastWidth;
|
||||
}
|
||||
}
|
||||
|
||||
stream.setPosition (sectionDataStart);
|
||||
}
|
||||
|
||||
stream.setPosition (sectionStart + sectionSize);
|
||||
}
|
||||
|
||||
return maxWidthIndex == -1 ? juce::Image()
|
||||
: images.getReference (maxWidthIndex).rescaled (size, size, Graphics::ResamplingQuality::highResamplingQuality);
|
||||
}
|
||||
|
||||
Image JUCE_API getIconFromApplication (const String& applicationPath, const int size)
|
||||
{
|
||||
if (auto pathCFString = CFUniquePtr<CFStringRef> (CFStringCreateWithCString (kCFAllocatorDefault, applicationPath.toRawUTF8(), kCFStringEncodingUTF8)))
|
||||
{
|
||||
if (auto url = CFUniquePtr<CFURLRef> (CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pathCFString.get(), kCFURLPOSIXPathStyle, 1)))
|
||||
{
|
||||
if (auto appBundle = CFUniquePtr<CFBundleRef> (CFBundleCreate (kCFAllocatorDefault, url.get())))
|
||||
{
|
||||
if (CFTypeRef infoValue = CFBundleGetValueForInfoDictionaryKey (appBundle.get(), CFSTR("CFBundleIconFile")))
|
||||
{
|
||||
if (CFGetTypeID (infoValue) == CFStringGetTypeID())
|
||||
{
|
||||
CFStringRef iconFilename = reinterpret_cast<CFStringRef> (infoValue);
|
||||
CFStringRef resourceURLSuffix = CFStringHasSuffix (iconFilename, CFSTR(".icns")) ? nullptr : CFSTR("icns");
|
||||
|
||||
if (auto iconURL = CFUniquePtr<CFURLRef> (CFBundleCopyResourceURL (appBundle.get(), iconFilename, resourceURLSuffix, nullptr)))
|
||||
{
|
||||
if (auto iconPath = CFUniquePtr<CFStringRef> (CFURLCopyFileSystemPath (iconURL.get(), kCFURLPOSIXPathStyle)))
|
||||
{
|
||||
File icnsFile (CFStringGetCStringPtr (iconPath.get(), CFStringGetSystemEncoding()));
|
||||
return getIconFromIcnsFile (icnsFile, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
extern Image JUCE_API getIconFromApplication (const String&, int);
|
||||
|
||||
static Image getIconFromIcnsFile (const File& icnsFile, const int size)
|
||||
{
|
||||
FileInputStream stream (icnsFile);
|
||||
|
||||
if (! stream.openedOk())
|
||||
return {};
|
||||
|
||||
const int numHeaderSectionBytes = 4;
|
||||
char headerSection [numHeaderSectionBytes];
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes
|
||||
|| headerSection[0] != 'i'
|
||||
|| headerSection[1] != 'c'
|
||||
|| headerSection[2] != 'n'
|
||||
|| headerSection[3] != 's')
|
||||
return {};
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
|
||||
return {};
|
||||
|
||||
const auto dataSize = juce::ByteOrder::bigEndianInt (headerSection);
|
||||
|
||||
if (dataSize <= 0)
|
||||
return {};
|
||||
|
||||
OwnedArray<juce::ImageFileFormat> internalFormats;
|
||||
internalFormats.add (new PNGImageFormat());
|
||||
internalFormats.add (new JPEGImageFormat());
|
||||
|
||||
Array<Image> images;
|
||||
auto maxWidth = 0;
|
||||
auto maxWidthIndex = -1;
|
||||
|
||||
while (stream.getPosition() < dataSize)
|
||||
{
|
||||
const auto sectionStart = stream.getPosition();
|
||||
|
||||
if (! stream.setPosition (sectionStart + 4))
|
||||
break;
|
||||
|
||||
if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
|
||||
break;
|
||||
|
||||
const auto sectionSize = ByteOrder::bigEndianInt (headerSection);
|
||||
|
||||
if (sectionSize <= 0)
|
||||
break;
|
||||
|
||||
const auto sectionDataStart = stream.getPosition();
|
||||
|
||||
for (auto* fmt : internalFormats)
|
||||
{
|
||||
if (fmt->canUnderstand (stream))
|
||||
{
|
||||
stream.setPosition (sectionDataStart);
|
||||
|
||||
images.add (fmt->decodeImage (stream));
|
||||
|
||||
const auto lastImageIndex = images.size() - 1;
|
||||
const auto lastWidth = images.getReference (lastImageIndex).getWidth();
|
||||
|
||||
if (lastWidth > maxWidth)
|
||||
{
|
||||
maxWidthIndex = lastImageIndex;
|
||||
maxWidth = lastWidth;
|
||||
}
|
||||
}
|
||||
|
||||
stream.setPosition (sectionDataStart);
|
||||
}
|
||||
|
||||
stream.setPosition (sectionStart + sectionSize);
|
||||
}
|
||||
|
||||
return maxWidthIndex == -1 ? juce::Image()
|
||||
: images.getReference (maxWidthIndex).rescaled (size, size, Graphics::ResamplingQuality::highResamplingQuality);
|
||||
}
|
||||
|
||||
Image JUCE_API getIconFromApplication (const String& applicationPath, const int size)
|
||||
{
|
||||
if (auto pathCFString = CFUniquePtr<CFStringRef> (CFStringCreateWithCString (kCFAllocatorDefault, applicationPath.toRawUTF8(), kCFStringEncodingUTF8)))
|
||||
{
|
||||
if (auto url = CFUniquePtr<CFURLRef> (CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pathCFString.get(), kCFURLPOSIXPathStyle, 1)))
|
||||
{
|
||||
if (auto appBundle = CFUniquePtr<CFBundleRef> (CFBundleCreate (kCFAllocatorDefault, url.get())))
|
||||
{
|
||||
if (CFTypeRef infoValue = CFBundleGetValueForInfoDictionaryKey (appBundle.get(), CFSTR("CFBundleIconFile")))
|
||||
{
|
||||
if (CFGetTypeID (infoValue) == CFStringGetTypeID())
|
||||
{
|
||||
CFStringRef iconFilename = reinterpret_cast<CFStringRef> (infoValue);
|
||||
CFStringRef resourceURLSuffix = CFStringHasSuffix (iconFilename, CFSTR(".icns")) ? nullptr : CFSTR("icns");
|
||||
|
||||
if (auto iconURL = CFUniquePtr<CFURLRef> (CFBundleCopyResourceURL (appBundle.get(), iconFilename, resourceURLSuffix, nullptr)))
|
||||
{
|
||||
if (auto iconPath = CFUniquePtr<CFStringRef> (CFURLCopyFileSystemPath (iconURL.get(), kCFURLPOSIXPathStyle)))
|
||||
{
|
||||
File icnsFile (CFStringGetCStringPtr (iconPath.get(), CFStringGetSystemEncoding()));
|
||||
return getIconFromIcnsFile (icnsFile, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,103 +1,103 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
#ifndef _WINDEF_
|
||||
class HWND__; // Forward or never
|
||||
typedef HWND__* HWND;
|
||||
#endif
|
||||
|
||||
class Direct2DLowLevelGraphicsContext : public LowLevelGraphicsContext
|
||||
{
|
||||
public:
|
||||
Direct2DLowLevelGraphicsContext (HWND);
|
||||
~Direct2DLowLevelGraphicsContext();
|
||||
|
||||
//==============================================================================
|
||||
bool isVectorDevice() const override { return false; }
|
||||
|
||||
void setOrigin (Point<int>) override;
|
||||
void addTransform (const AffineTransform&) override;
|
||||
float getPhysicalPixelScaleFactor() override;
|
||||
bool clipToRectangle (const Rectangle<int>&) override;
|
||||
bool clipToRectangleList (const RectangleList<int>&) override;
|
||||
void excludeClipRectangle (const Rectangle<int>&) override;
|
||||
void clipToPath (const Path&, const AffineTransform&) override;
|
||||
void clipToImageAlpha (const Image&, const AffineTransform&) override;
|
||||
bool clipRegionIntersects (const Rectangle<int>&) override;
|
||||
Rectangle<int> getClipBounds() const override;
|
||||
bool isClipEmpty() const override;
|
||||
|
||||
//==============================================================================
|
||||
void saveState() override;
|
||||
void restoreState() override;
|
||||
void beginTransparencyLayer (float opacity) override;
|
||||
void endTransparencyLayer() override;
|
||||
|
||||
//==============================================================================
|
||||
void setFill (const FillType&) override;
|
||||
void setOpacity (float) override;
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality) override;
|
||||
|
||||
//==============================================================================
|
||||
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
|
||||
void fillRect (const Rectangle<float>&) override;
|
||||
void fillRectList (const RectangleList<float>&) override;
|
||||
void fillPath (const Path&, const AffineTransform&) override;
|
||||
void drawImage (const Image& sourceImage, const AffineTransform&) override;
|
||||
|
||||
//==============================================================================
|
||||
void drawLine (const Line<float>&) override;
|
||||
void setFont (const Font&) override;
|
||||
const Font& getFont() override;
|
||||
void drawGlyph (int glyphNumber, const AffineTransform&) override;
|
||||
bool drawTextLayout (const AttributedString&, const Rectangle<float>&) override;
|
||||
|
||||
void resized();
|
||||
void clear();
|
||||
|
||||
void start();
|
||||
void end();
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
struct SavedState;
|
||||
|
||||
HWND hwnd;
|
||||
|
||||
SavedState* currentState;
|
||||
OwnedArray<SavedState> states;
|
||||
|
||||
Rectangle<int> bounds;
|
||||
|
||||
struct Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DLowLevelGraphicsContext)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
#ifndef _WINDEF_
|
||||
class HWND__; // Forward or never
|
||||
typedef HWND__* HWND;
|
||||
#endif
|
||||
|
||||
class Direct2DLowLevelGraphicsContext : public LowLevelGraphicsContext
|
||||
{
|
||||
public:
|
||||
Direct2DLowLevelGraphicsContext (HWND);
|
||||
~Direct2DLowLevelGraphicsContext();
|
||||
|
||||
//==============================================================================
|
||||
bool isVectorDevice() const override { return false; }
|
||||
|
||||
void setOrigin (Point<int>) override;
|
||||
void addTransform (const AffineTransform&) override;
|
||||
float getPhysicalPixelScaleFactor() override;
|
||||
bool clipToRectangle (const Rectangle<int>&) override;
|
||||
bool clipToRectangleList (const RectangleList<int>&) override;
|
||||
void excludeClipRectangle (const Rectangle<int>&) override;
|
||||
void clipToPath (const Path&, const AffineTransform&) override;
|
||||
void clipToImageAlpha (const Image&, const AffineTransform&) override;
|
||||
bool clipRegionIntersects (const Rectangle<int>&) override;
|
||||
Rectangle<int> getClipBounds() const override;
|
||||
bool isClipEmpty() const override;
|
||||
|
||||
//==============================================================================
|
||||
void saveState() override;
|
||||
void restoreState() override;
|
||||
void beginTransparencyLayer (float opacity) override;
|
||||
void endTransparencyLayer() override;
|
||||
|
||||
//==============================================================================
|
||||
void setFill (const FillType&) override;
|
||||
void setOpacity (float) override;
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality) override;
|
||||
|
||||
//==============================================================================
|
||||
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
|
||||
void fillRect (const Rectangle<float>&) override;
|
||||
void fillRectList (const RectangleList<float>&) override;
|
||||
void fillPath (const Path&, const AffineTransform&) override;
|
||||
void drawImage (const Image& sourceImage, const AffineTransform&) override;
|
||||
|
||||
//==============================================================================
|
||||
void drawLine (const Line<float>&) override;
|
||||
void setFont (const Font&) override;
|
||||
const Font& getFont() override;
|
||||
void drawGlyph (int glyphNumber, const AffineTransform&) override;
|
||||
bool drawTextLayout (const AttributedString&, const Rectangle<float>&) override;
|
||||
|
||||
void resized();
|
||||
void clear();
|
||||
|
||||
void start();
|
||||
void end();
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
struct SavedState;
|
||||
|
||||
HWND hwnd;
|
||||
|
||||
SavedState* currentState;
|
||||
OwnedArray<SavedState> states;
|
||||
|
||||
Rectangle<int> bounds;
|
||||
|
||||
struct Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DLowLevelGraphicsContext)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,335 +1,337 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
namespace
|
||||
{
|
||||
static String getLocalisedName (IDWriteLocalizedStrings* names)
|
||||
{
|
||||
jassert (names != nullptr);
|
||||
|
||||
uint32 index = 0;
|
||||
BOOL exists = false;
|
||||
auto hr = names->FindLocaleName (L"en-us", &index, &exists);
|
||||
|
||||
if (! exists)
|
||||
index = 0;
|
||||
|
||||
uint32 length = 0;
|
||||
hr = names->GetStringLength (index, &length);
|
||||
|
||||
HeapBlock<wchar_t> name (length + 1);
|
||||
hr = names->GetString (index, name, length + 1);
|
||||
|
||||
return static_cast<const wchar_t*> (name);
|
||||
}
|
||||
|
||||
static String getFontFamilyName (IDWriteFontFamily* family)
|
||||
{
|
||||
jassert (family != nullptr);
|
||||
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
|
||||
auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
|
||||
jassert (SUCCEEDED (hr)); ignoreUnused (hr);
|
||||
return getLocalisedName (familyNames);
|
||||
}
|
||||
|
||||
static String getFontFaceName (IDWriteFont* font)
|
||||
{
|
||||
jassert (font != nullptr);
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
|
||||
jassert (SUCCEEDED (hr)); ignoreUnused (hr);
|
||||
return getLocalisedName (faceNames);
|
||||
}
|
||||
|
||||
inline Point<float> convertPoint (D2D1_POINT_2F p) noexcept { return Point<float> ((float) p.x, (float) p.y); }
|
||||
}
|
||||
|
||||
class Direct2DFactories
|
||||
{
|
||||
public:
|
||||
Direct2DFactories()
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
if (direct2dDll.open ("d2d1.dll"))
|
||||
{
|
||||
JUCE_LOAD_WINAPI_FUNCTION (direct2dDll, D2D1CreateFactory, d2d1CreateFactory,
|
||||
HRESULT, (D2D1_FACTORY_TYPE, REFIID, D2D1_FACTORY_OPTIONS*, void**))
|
||||
|
||||
if (d2d1CreateFactory != nullptr)
|
||||
{
|
||||
D2D1_FACTORY_OPTIONS options;
|
||||
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
|
||||
|
||||
d2d1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof (ID2D1Factory), &options,
|
||||
(void**) d2dFactory.resetAndGetPointerAddress());
|
||||
}
|
||||
}
|
||||
|
||||
if (directWriteDll.open ("DWrite.dll"))
|
||||
{
|
||||
JUCE_LOAD_WINAPI_FUNCTION (directWriteDll, DWriteCreateFactory, dWriteCreateFactory,
|
||||
HRESULT, (DWRITE_FACTORY_TYPE, REFIID, IUnknown**))
|
||||
|
||||
if (dWriteCreateFactory != nullptr)
|
||||
{
|
||||
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||
(IUnknown**) directWriteFactory.resetAndGetPointerAddress());
|
||||
|
||||
if (directWriteFactory != nullptr)
|
||||
directWriteFactory->GetSystemFontCollection (systemFonts.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
if (d2dFactory != nullptr)
|
||||
{
|
||||
auto d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE,
|
||||
D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
D2D1_ALPHA_MODE_IGNORE),
|
||||
0, 0,
|
||||
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
|
||||
D2D1_FEATURE_LEVEL_DEFAULT);
|
||||
|
||||
d2dFactory->CreateDCRenderTarget (&d2dRTProp, directWriteRenderTarget.resetAndGetPointerAddress());
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
~Direct2DFactories()
|
||||
{
|
||||
d2dFactory = nullptr; // (need to make sure these are released before deleting the DynamicLibrary objects)
|
||||
directWriteFactory = nullptr;
|
||||
systemFonts = nullptr;
|
||||
directWriteRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
ComSmartPtr<ID2D1Factory> d2dFactory;
|
||||
ComSmartPtr<IDWriteFactory> directWriteFactory;
|
||||
ComSmartPtr<IDWriteFontCollection> systemFonts;
|
||||
ComSmartPtr<ID2D1DCRenderTarget> directWriteRenderTarget;
|
||||
|
||||
private:
|
||||
DynamicLibrary direct2dDll, directWriteDll;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class WindowsDirectWriteTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle())
|
||||
{
|
||||
jassert (fontCollection != nullptr);
|
||||
|
||||
uint32 fontIndex = 0;
|
||||
auto hr = fontCollection->FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound);
|
||||
|
||||
if (! fontFound)
|
||||
fontIndex = 0;
|
||||
|
||||
// Get the font family using the search results
|
||||
// Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family
|
||||
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
|
||||
hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());
|
||||
|
||||
// Get a specific font in the font family using typeface style
|
||||
{
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
|
||||
for (int i = (int) dwFontFamily->GetFontCount(); --i >= 0;)
|
||||
{
|
||||
hr = dwFontFamily->GetFont ((UINT32) i, dwFont.resetAndGetPointerAddress());
|
||||
|
||||
if (i == 0)
|
||||
break;
|
||||
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress());
|
||||
|
||||
if (font.getTypefaceStyle() == getLocalisedName (faceNames))
|
||||
break;
|
||||
}
|
||||
|
||||
jassert (dwFont != nullptr);
|
||||
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
if (dwFontFace != nullptr)
|
||||
{
|
||||
DWRITE_FONT_METRICS dwFontMetrics;
|
||||
dwFontFace->GetMetrics (&dwFontMetrics);
|
||||
|
||||
// All Font Metrics are in design units so we need to get designUnitsPerEm value
|
||||
// to get the metrics into Em/Design Independent Pixels
|
||||
designUnitsPerEm = dwFontMetrics.designUnitsPerEm;
|
||||
|
||||
ascent = std::abs ((float) dwFontMetrics.ascent);
|
||||
auto totalSize = ascent + std::abs ((float) dwFontMetrics.descent);
|
||||
ascent /= totalSize;
|
||||
unitsToHeightScaleFactor = (float) designUnitsPerEm / totalSize;
|
||||
|
||||
auto tempDC = GetDC (nullptr);
|
||||
auto dpi = (float) (GetDeviceCaps (tempDC, LOGPIXELSX) + GetDeviceCaps (tempDC, LOGPIXELSY)) / 2.0f;
|
||||
heightToPointsFactor = (dpi / (float) GetDeviceCaps (tempDC, LOGPIXELSY)) * unitsToHeightScaleFactor;
|
||||
ReleaseDC (nullptr, tempDC);
|
||||
|
||||
auto pathAscent = (1024.0f * dwFontMetrics.ascent) / (float) designUnitsPerEm;
|
||||
auto pathDescent = (1024.0f * dwFontMetrics.descent) / (float) designUnitsPerEm;
|
||||
auto pathScale = 1.0f / (std::abs (pathAscent) + std::abs (pathDescent));
|
||||
pathTransform = AffineTransform::scale (pathScale);
|
||||
}
|
||||
}
|
||||
|
||||
bool loadedOk() const noexcept { return dwFontFace != nullptr; }
|
||||
BOOL isFontFound() const noexcept { return fontFound; }
|
||||
|
||||
float getAscent() const { return ascent; }
|
||||
float getDescent() const { return 1.0f - ascent; }
|
||||
float getHeightToPointsFactor() const { return heightToPointsFactor; }
|
||||
|
||||
float getStringWidth (const String& text)
|
||||
{
|
||||
auto textUTF32 = text.toUTF32();
|
||||
auto len = textUTF32.length();
|
||||
|
||||
HeapBlock<UINT16> glyphIndices (len);
|
||||
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
|
||||
|
||||
HeapBlock<DWRITE_GLYPH_METRICS> dwGlyphMetrics (len);
|
||||
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
|
||||
return x * unitsToHeightScaleFactor;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
|
||||
{
|
||||
xOffsets.add (0);
|
||||
|
||||
auto textUTF32 = text.toUTF32();
|
||||
auto len = textUTF32.length();
|
||||
|
||||
HeapBlock<UINT16> glyphIndices (len);
|
||||
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
|
||||
HeapBlock<DWRITE_GLYPH_METRICS> dwGlyphMetrics (len);
|
||||
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
{
|
||||
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
|
||||
auto glyphIndex = (UINT16) glyphNumber;
|
||||
ComSmartPtr<PathGeometrySink> pathGeometrySink (new PathGeometrySink());
|
||||
|
||||
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr,
|
||||
1, false, false, pathGeometrySink);
|
||||
path = pathGeometrySink->path;
|
||||
|
||||
if (! pathTransform.isIdentity())
|
||||
path.applyTransform (pathTransform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IDWriteFontFace* getIDWriteFontFace() const noexcept { return dwFontFace; }
|
||||
|
||||
float getUnitsToHeightScaleFactor() const noexcept { return unitsToHeightScaleFactor; }
|
||||
|
||||
private:
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||
float unitsToHeightScaleFactor = 1.0f, heightToPointsFactor = 1.0f, ascent = 0;
|
||||
int designUnitsPerEm = 0;
|
||||
AffineTransform pathTransform;
|
||||
BOOL fontFound = false;
|
||||
|
||||
struct PathGeometrySink : public ComBaseClassHelper<IDWriteGeometrySink>
|
||||
{
|
||||
PathGeometrySink() : ComBaseClassHelper (0) {}
|
||||
|
||||
void STDMETHODCALLTYPE AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < beziersCount; ++i)
|
||||
path.cubicTo (convertPoint (beziers[i].point1),
|
||||
convertPoint (beziers[i].point2),
|
||||
convertPoint (beziers[i].point3));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE AddLines (const D2D1_POINT_2F* points, UINT pointsCount) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < pointsCount; ++i)
|
||||
path.lineTo (convertPoint (points[i]));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE BeginFigure (D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) noexcept override
|
||||
{
|
||||
path.startNewSubPath (convertPoint (startPoint));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE EndFigure (D2D1_FIGURE_END figureEnd) noexcept override
|
||||
{
|
||||
if (figureEnd == D2D1_FIGURE_END_CLOSED)
|
||||
path.closeSubPath();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SetFillMode (D2D1_FILL_MODE fillMode) noexcept override
|
||||
{
|
||||
path.setUsingNonZeroWinding (fillMode == D2D1_FILL_MODE_WINDING);
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SetSegmentFlags (D2D1_PATH_SEGMENT) noexcept override {}
|
||||
JUCE_COMRESULT Close() noexcept override { return S_OK; }
|
||||
|
||||
Path path;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathGeometrySink)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDirectWriteTypeface)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
namespace
|
||||
{
|
||||
static String getLocalisedName (IDWriteLocalizedStrings* names)
|
||||
{
|
||||
jassert (names != nullptr);
|
||||
|
||||
uint32 index = 0;
|
||||
BOOL exists = false;
|
||||
auto hr = names->FindLocaleName (L"en-us", &index, &exists);
|
||||
ignoreUnused (hr);
|
||||
|
||||
if (! exists)
|
||||
index = 0;
|
||||
|
||||
uint32 length = 0;
|
||||
hr = names->GetStringLength (index, &length);
|
||||
|
||||
HeapBlock<wchar_t> name (length + 1);
|
||||
hr = names->GetString (index, name, length + 1);
|
||||
|
||||
return static_cast<const wchar_t*> (name);
|
||||
}
|
||||
|
||||
static String getFontFamilyName (IDWriteFontFamily* family)
|
||||
{
|
||||
jassert (family != nullptr);
|
||||
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
|
||||
auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
|
||||
jassertquiet (SUCCEEDED (hr));
|
||||
return getLocalisedName (familyNames);
|
||||
}
|
||||
|
||||
static String getFontFaceName (IDWriteFont* font)
|
||||
{
|
||||
jassert (font != nullptr);
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
|
||||
jassertquiet (SUCCEEDED (hr));
|
||||
return getLocalisedName (faceNames);
|
||||
}
|
||||
|
||||
inline Point<float> convertPoint (D2D1_POINT_2F p) noexcept { return Point<float> ((float) p.x, (float) p.y); }
|
||||
}
|
||||
|
||||
class Direct2DFactories
|
||||
{
|
||||
public:
|
||||
Direct2DFactories()
|
||||
{
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
if (direct2dDll.open ("d2d1.dll"))
|
||||
{
|
||||
JUCE_LOAD_WINAPI_FUNCTION (direct2dDll, D2D1CreateFactory, d2d1CreateFactory,
|
||||
HRESULT, (D2D1_FACTORY_TYPE, REFIID, D2D1_FACTORY_OPTIONS*, void**))
|
||||
|
||||
if (d2d1CreateFactory != nullptr)
|
||||
{
|
||||
D2D1_FACTORY_OPTIONS options;
|
||||
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
|
||||
|
||||
d2d1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof (ID2D1Factory), &options,
|
||||
(void**) d2dFactory.resetAndGetPointerAddress());
|
||||
}
|
||||
}
|
||||
|
||||
if (directWriteDll.open ("DWrite.dll"))
|
||||
{
|
||||
JUCE_LOAD_WINAPI_FUNCTION (directWriteDll, DWriteCreateFactory, dWriteCreateFactory,
|
||||
HRESULT, (DWRITE_FACTORY_TYPE, REFIID, IUnknown**))
|
||||
|
||||
if (dWriteCreateFactory != nullptr)
|
||||
{
|
||||
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||
(IUnknown**) directWriteFactory.resetAndGetPointerAddress());
|
||||
|
||||
if (directWriteFactory != nullptr)
|
||||
directWriteFactory->GetSystemFontCollection (systemFonts.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
if (d2dFactory != nullptr)
|
||||
{
|
||||
auto d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE,
|
||||
D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
D2D1_ALPHA_MODE_IGNORE),
|
||||
0, 0,
|
||||
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
|
||||
D2D1_FEATURE_LEVEL_DEFAULT);
|
||||
|
||||
d2dFactory->CreateDCRenderTarget (&d2dRTProp, directWriteRenderTarget.resetAndGetPointerAddress());
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
~Direct2DFactories()
|
||||
{
|
||||
d2dFactory = nullptr; // (need to make sure these are released before deleting the DynamicLibrary objects)
|
||||
directWriteFactory = nullptr;
|
||||
systemFonts = nullptr;
|
||||
directWriteRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
ComSmartPtr<ID2D1Factory> d2dFactory;
|
||||
ComSmartPtr<IDWriteFactory> directWriteFactory;
|
||||
ComSmartPtr<IDWriteFontCollection> systemFonts;
|
||||
ComSmartPtr<ID2D1DCRenderTarget> directWriteRenderTarget;
|
||||
|
||||
private:
|
||||
DynamicLibrary direct2dDll, directWriteDll;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class WindowsDirectWriteTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle())
|
||||
{
|
||||
jassert (fontCollection != nullptr);
|
||||
|
||||
uint32 fontIndex = 0;
|
||||
auto hr = fontCollection->FindFamilyName (font.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound);
|
||||
ignoreUnused (hr);
|
||||
|
||||
if (! fontFound)
|
||||
fontIndex = 0;
|
||||
|
||||
// Get the font family using the search results
|
||||
// Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family
|
||||
ComSmartPtr<IDWriteFontFamily> dwFontFamily;
|
||||
hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());
|
||||
|
||||
// Get a specific font in the font family using typeface style
|
||||
{
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
|
||||
for (int i = (int) dwFontFamily->GetFontCount(); --i >= 0;)
|
||||
{
|
||||
hr = dwFontFamily->GetFont ((UINT32) i, dwFont.resetAndGetPointerAddress());
|
||||
|
||||
if (i == 0)
|
||||
break;
|
||||
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
hr = dwFont->GetFaceNames (faceNames.resetAndGetPointerAddress());
|
||||
|
||||
if (font.getTypefaceStyle() == getLocalisedName (faceNames))
|
||||
break;
|
||||
}
|
||||
|
||||
jassert (dwFont != nullptr);
|
||||
hr = dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
if (dwFontFace != nullptr)
|
||||
{
|
||||
DWRITE_FONT_METRICS dwFontMetrics;
|
||||
dwFontFace->GetMetrics (&dwFontMetrics);
|
||||
|
||||
// All Font Metrics are in design units so we need to get designUnitsPerEm value
|
||||
// to get the metrics into Em/Design Independent Pixels
|
||||
designUnitsPerEm = dwFontMetrics.designUnitsPerEm;
|
||||
|
||||
ascent = std::abs ((float) dwFontMetrics.ascent);
|
||||
auto totalSize = ascent + std::abs ((float) dwFontMetrics.descent);
|
||||
ascent /= totalSize;
|
||||
unitsToHeightScaleFactor = (float) designUnitsPerEm / totalSize;
|
||||
|
||||
auto tempDC = GetDC (nullptr);
|
||||
auto dpi = (float) (GetDeviceCaps (tempDC, LOGPIXELSX) + GetDeviceCaps (tempDC, LOGPIXELSY)) / 2.0f;
|
||||
heightToPointsFactor = (dpi / (float) GetDeviceCaps (tempDC, LOGPIXELSY)) * unitsToHeightScaleFactor;
|
||||
ReleaseDC (nullptr, tempDC);
|
||||
|
||||
auto pathAscent = (1024.0f * dwFontMetrics.ascent) / (float) designUnitsPerEm;
|
||||
auto pathDescent = (1024.0f * dwFontMetrics.descent) / (float) designUnitsPerEm;
|
||||
auto pathScale = 1.0f / (std::abs (pathAscent) + std::abs (pathDescent));
|
||||
pathTransform = AffineTransform::scale (pathScale);
|
||||
}
|
||||
}
|
||||
|
||||
bool loadedOk() const noexcept { return dwFontFace != nullptr; }
|
||||
BOOL isFontFound() const noexcept { return fontFound; }
|
||||
|
||||
float getAscent() const { return ascent; }
|
||||
float getDescent() const { return 1.0f - ascent; }
|
||||
float getHeightToPointsFactor() const { return heightToPointsFactor; }
|
||||
|
||||
float getStringWidth (const String& text)
|
||||
{
|
||||
auto textUTF32 = text.toUTF32();
|
||||
auto len = textUTF32.length();
|
||||
|
||||
HeapBlock<UINT16> glyphIndices (len);
|
||||
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
|
||||
|
||||
HeapBlock<DWRITE_GLYPH_METRICS> dwGlyphMetrics (len);
|
||||
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
|
||||
return x * unitsToHeightScaleFactor;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
|
||||
{
|
||||
xOffsets.add (0);
|
||||
|
||||
auto textUTF32 = text.toUTF32();
|
||||
auto len = textUTF32.length();
|
||||
|
||||
HeapBlock<UINT16> glyphIndices (len);
|
||||
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
|
||||
HeapBlock<DWRITE_GLYPH_METRICS> dwGlyphMetrics (len);
|
||||
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
{
|
||||
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
|
||||
auto glyphIndex = (UINT16) glyphNumber;
|
||||
ComSmartPtr<PathGeometrySink> pathGeometrySink (new PathGeometrySink());
|
||||
|
||||
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr,
|
||||
1, false, false, pathGeometrySink);
|
||||
path = pathGeometrySink->path;
|
||||
|
||||
if (! pathTransform.isIdentity())
|
||||
path.applyTransform (pathTransform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IDWriteFontFace* getIDWriteFontFace() const noexcept { return dwFontFace; }
|
||||
|
||||
float getUnitsToHeightScaleFactor() const noexcept { return unitsToHeightScaleFactor; }
|
||||
|
||||
private:
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||
float unitsToHeightScaleFactor = 1.0f, heightToPointsFactor = 1.0f, ascent = 0;
|
||||
int designUnitsPerEm = 0;
|
||||
AffineTransform pathTransform;
|
||||
BOOL fontFound = false;
|
||||
|
||||
struct PathGeometrySink : public ComBaseClassHelper<IDWriteGeometrySink>
|
||||
{
|
||||
PathGeometrySink() : ComBaseClassHelper (0) {}
|
||||
|
||||
void STDMETHODCALLTYPE AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < beziersCount; ++i)
|
||||
path.cubicTo (convertPoint (beziers[i].point1),
|
||||
convertPoint (beziers[i].point2),
|
||||
convertPoint (beziers[i].point3));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE AddLines (const D2D1_POINT_2F* points, UINT pointsCount) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < pointsCount; ++i)
|
||||
path.lineTo (convertPoint (points[i]));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE BeginFigure (D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) noexcept override
|
||||
{
|
||||
path.startNewSubPath (convertPoint (startPoint));
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE EndFigure (D2D1_FIGURE_END figureEnd) noexcept override
|
||||
{
|
||||
if (figureEnd == D2D1_FIGURE_END_CLOSED)
|
||||
path.closeSubPath();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SetFillMode (D2D1_FILL_MODE fillMode) noexcept override
|
||||
{
|
||||
path.setUsingNonZeroWinding (fillMode == D2D1_FILL_MODE_WINDING);
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SetSegmentFlags (D2D1_PATH_SEGMENT) noexcept override {}
|
||||
JUCE_COMRESULT Close() noexcept override { return S_OK; }
|
||||
|
||||
Path path;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathGeometrySink)
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDirectWriteTypeface)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +1,30 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-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
|
||||
{
|
||||
Image JUCE_API getIconFromApplication (const String&, int);
|
||||
Image JUCE_API getIconFromApplication (const String&, int) { return {}; }
|
||||
}
|
||||
|
Reference in New Issue
Block a user