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