migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 {}; }
}

View File

@ -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

View File

@ -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

View File

@ -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 {}; }
}

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {}; }
}