mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Typeface: Implement platform typefaces using Harfbuzz hb_font_t
This commit is contained in:
parent
080ac6e7e7
commit
0d2e34f34c
56 changed files with 8359 additions and 2985 deletions
|
|
@ -4,6 +4,30 @@
|
|||
|
||||
## Change
|
||||
|
||||
CustomTypeface has been removed.
|
||||
|
||||
**Possible Issues**
|
||||
|
||||
Code that interacts with CustomTypeface will fail to compile.
|
||||
|
||||
**Workaround**
|
||||
|
||||
There is currently no workaround. If you were using CustomTypeface to
|
||||
implement typeface fallback, there is a new API,
|
||||
Font::findSuitableFontForText, that you can use to locate fonts capable
|
||||
of rendering given strings.
|
||||
|
||||
**Rationale**
|
||||
|
||||
The CustomTypeface class is difficult/impossible to support with the new
|
||||
HarfBuzz Typeface implementation. New support for automatic font fallback
|
||||
will be introduced in JUCE 8, and this will obviate much of the need for
|
||||
CustomTypeface.
|
||||
|
||||
>>>>>>> 94454123d6 (Typeface: Implement platform typefaces using Harfbuzz hb_font_t)
|
||||
|
||||
## Change
|
||||
|
||||
The Android implementations of Typeface::getStringWidth(), getGlyphPositions(),
|
||||
and getEdgeTableForGlyph() have been updated to return correctly-normalised
|
||||
results. The effect of this change is to change (in practice, slightly reduce)
|
||||
|
|
|
|||
|
|
@ -1814,8 +1814,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -1826,6 +1824,7 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -1948,7 +1947,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
@ -4278,8 +4276,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -4290,6 +4286,7 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -4412,7 +4409,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
|
|||
|
|
@ -2096,9 +2096,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2111,6 +2108,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2351,9 +2351,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -4131,7 +4128,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2839,9 +2839,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2854,6 +2851,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -3100,9 +3100,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -7125,9 +7122,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -2096,9 +2096,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2111,6 +2108,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2351,9 +2351,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -4131,7 +4128,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2839,9 +2839,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2854,6 +2851,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -3100,9 +3100,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -7125,9 +7122,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -2096,9 +2096,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2111,6 +2108,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2351,9 +2351,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -4131,7 +4128,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2839,9 +2839,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2854,6 +2851,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -3100,9 +3100,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -7125,9 +7122,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1576,8 +1576,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -1588,6 +1586,7 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -1710,7 +1709,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
@ -3722,8 +3720,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -3734,6 +3730,7 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -3856,7 +3853,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
|
|||
|
|
@ -1789,9 +1789,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1804,6 +1801,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2044,9 +2044,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3602,7 +3599,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2383,9 +2383,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2398,6 +2395,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2644,9 +2644,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6180,9 +6177,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1706,8 +1706,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -1718,6 +1716,7 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -1840,7 +1839,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
@ -4005,8 +4003,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -4017,6 +4013,7 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -4139,7 +4136,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
|
|||
|
|
@ -1923,9 +1923,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1938,6 +1935,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2178,9 +2178,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3835,7 +3832,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2590,9 +2590,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2605,6 +2602,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2851,9 +2851,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6615,9 +6612,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1923,9 +1923,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1938,6 +1935,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2178,9 +2178,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3835,7 +3832,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2590,9 +2590,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2605,6 +2602,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2851,9 +2851,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6615,9 +6612,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1923,9 +1923,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1938,6 +1935,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2178,9 +2178,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3835,7 +3832,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2590,9 +2590,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2605,6 +2602,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2851,9 +2851,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6615,9 +6612,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1595,8 +1595,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -1607,6 +1605,7 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -1729,7 +1728,6 @@ add_library( ${BINARY_NAME}
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
@ -3821,8 +3819,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/harfbuzz/hb.hh"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_AttributedString.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Font.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h"
|
||||
|
|
@ -3833,6 +3829,7 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/fonts/juce_TextLayout.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.cpp"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_Typeface.h"
|
||||
"../../../../../modules/juce_graphics/fonts/juce_TypefaceTestData.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.cpp"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"
|
||||
"../../../../../modules/juce_graphics/geometry/juce_BorderSize.h"
|
||||
|
|
@ -3955,7 +3952,6 @@ set_source_files_properties(
|
|||
"../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm"
|
||||
"../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp"
|
||||
"../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp"
|
||||
|
|
|
|||
|
|
@ -1810,9 +1810,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1825,6 +1822,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2065,9 +2065,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3700,7 +3697,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2437,9 +2437,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2452,6 +2449,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2698,9 +2698,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6342,9 +6339,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -992,9 +992,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1007,6 +1004,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1247,9 +1247,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2517,7 +2514,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -1381,9 +1381,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1396,6 +1393,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1642,9 +1642,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -4320,9 +4317,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -992,9 +992,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1007,6 +1004,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1247,9 +1247,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2517,7 +2514,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -1381,9 +1381,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1396,6 +1393,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1642,9 +1642,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -4320,9 +4317,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -992,9 +992,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1007,6 +1004,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1247,9 +1247,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2517,7 +2514,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -1381,9 +1381,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1396,6 +1393,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -1642,9 +1642,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -4320,9 +4317,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1931,9 +1931,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1946,6 +1943,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2186,9 +2186,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3931,7 +3928,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2611,9 +2611,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2626,6 +2623,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2872,9 +2872,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6729,9 +6726,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1931,9 +1931,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1946,6 +1943,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2186,9 +2186,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3931,7 +3928,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2611,9 +2611,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2626,6 +2623,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2872,9 +2872,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6729,9 +6726,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1931,9 +1931,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1946,6 +1943,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2186,9 +2186,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3931,7 +3928,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2611,9 +2611,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2626,6 +2623,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2872,9 +2872,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6729,9 +6726,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -1809,9 +1809,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -1824,6 +1821,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -2064,9 +2064,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_linux.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
|
@ -3676,7 +3673,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\harfbuzz\hb.hh"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_FunctionPointerDestructor.h"/>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_GlyphArrangement.h"/>
|
||||
|
|
|
|||
|
|
@ -2434,9 +2434,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2449,6 +2446,9 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_Typeface.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\fonts\juce_TypefaceTestData.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\geometry\juce_AffineTransform.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\geometry</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2695,9 +2695,6 @@
|
|||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_mac.mm">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_Fonts_windows.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\..\modules\juce_graphics\native\juce_GraphicsContext_android.cpp">
|
||||
<Filter>JUCE Modules\juce_graphics\native</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -6309,9 +6306,6 @@
|
|||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_AttributedString.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_CustomTypeface.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\..\modules\juce_graphics\fonts\juce_Font.h">
|
||||
<Filter>JUCE Modules\juce_graphics\fonts</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
|
|
@ -430,8 +430,10 @@ struct AndroidDocument::Utils
|
|||
|
||||
std::unique_ptr<InputStream> createInputStream() const override
|
||||
{
|
||||
auto result = std::make_unique<AndroidContentUriInputStream> (uri);
|
||||
return result->openedSuccessfully() ? std::move (result) : nullptr;
|
||||
if (auto opened = AndroidContentUriInputStream::fromUri (uri))
|
||||
return std::make_unique<AndroidContentUriInputStream> (std::move (*opened));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<OutputStream> createOutputStream() const override
|
||||
|
|
|
|||
|
|
@ -584,14 +584,33 @@ struct AndroidStreamHelpers
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
struct AndroidContentUriInputStream final : public InputStream
|
||||
class AndroidInputStreamWrapper final : public InputStream
|
||||
{
|
||||
explicit AndroidContentUriInputStream (const GlobalRef& uriIn)
|
||||
: uri (uriIn),
|
||||
stream (AndroidStreamHelpers::createStream (uri, AndroidStreamHelpers::StreamKind::input))
|
||||
{}
|
||||
public:
|
||||
explicit AndroidInputStreamWrapper (jobject streamIn)
|
||||
: stream (LocalRef<jobject> { streamIn })
|
||||
{
|
||||
}
|
||||
|
||||
~AndroidContentUriInputStream() override
|
||||
AndroidInputStreamWrapper (AndroidInputStreamWrapper&& other) noexcept
|
||||
: byteArray (std::exchange (other.byteArray, {})),
|
||||
stream (std::exchange (other.stream, {})),
|
||||
pos (std::exchange (other.pos, {})),
|
||||
exhausted (std::exchange (other.exhausted, {}))
|
||||
{
|
||||
}
|
||||
|
||||
AndroidInputStreamWrapper (const AndroidInputStreamWrapper&) = delete;
|
||||
|
||||
AndroidInputStreamWrapper& operator= (AndroidInputStreamWrapper&& other) noexcept
|
||||
{
|
||||
std::swap (*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AndroidInputStreamWrapper& operator= (const AndroidInputStreamWrapper&) = delete;
|
||||
|
||||
~AndroidInputStreamWrapper() override
|
||||
{
|
||||
getEnv()->CallVoidMethod (stream.get(), AndroidInputStream.close);
|
||||
jniCheckHasExceptionOccurredAndClear();
|
||||
|
|
@ -625,16 +644,9 @@ struct AndroidContentUriInputStream final : public InputStream
|
|||
return result;
|
||||
}
|
||||
|
||||
bool setPosition (int64 newPos) override
|
||||
bool setPosition (int64) override
|
||||
{
|
||||
if (newPos == pos)
|
||||
return true;
|
||||
|
||||
if (pos < newPos)
|
||||
return skipImpl (newPos - pos);
|
||||
|
||||
AndroidContentUriInputStream (uri).swap (*this);
|
||||
return skipImpl (newPos);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64 getPosition() override
|
||||
|
|
@ -642,8 +654,6 @@ struct AndroidContentUriInputStream final : public InputStream
|
|||
return pos;
|
||||
}
|
||||
|
||||
bool openedSuccessfully() const { return stream != nullptr; }
|
||||
|
||||
void skipNextBytes (int64 num) override
|
||||
{
|
||||
skipImpl (num);
|
||||
|
|
@ -664,21 +674,107 @@ private:
|
|||
return skipped == num;
|
||||
}
|
||||
|
||||
auto tie() { return std::tie (uri, byteArray, stream, pos, exhausted); }
|
||||
|
||||
void swap (AndroidContentUriInputStream& other) noexcept
|
||||
{
|
||||
auto toSwap = other.tie();
|
||||
tie().swap (toSwap);
|
||||
}
|
||||
|
||||
GlobalRef uri;
|
||||
CachedByteArray byteArray;
|
||||
GlobalRef stream;
|
||||
int64 pos = 0;
|
||||
bool exhausted = false;
|
||||
};
|
||||
|
||||
std::unique_ptr<InputStream> makeAndroidInputStreamWrapper (jobject stream);
|
||||
std::unique_ptr<InputStream> makeAndroidInputStreamWrapper (jobject stream)
|
||||
{
|
||||
return std::make_unique<AndroidInputStreamWrapper> (stream);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct AndroidContentUriInputStream final : public InputStream
|
||||
{
|
||||
AndroidContentUriInputStream (AndroidContentUriInputStream&& other) noexcept
|
||||
: stream (std::move (other.stream)),
|
||||
uri (std::exchange (other.uri, {}))
|
||||
{
|
||||
}
|
||||
|
||||
AndroidContentUriInputStream (const AndroidContentUriInputStream&) = delete;
|
||||
|
||||
AndroidContentUriInputStream& operator= (AndroidContentUriInputStream&& other) noexcept
|
||||
{
|
||||
std::swap (*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AndroidContentUriInputStream& operator= (const AndroidContentUriInputStream&) = delete;
|
||||
|
||||
int64 getTotalLength() override
|
||||
{
|
||||
return stream.getTotalLength();
|
||||
}
|
||||
|
||||
bool isExhausted() override
|
||||
{
|
||||
return stream.isExhausted();
|
||||
}
|
||||
|
||||
int read (void* destBuffer, int maxBytesToRead) override
|
||||
{
|
||||
return stream.read (destBuffer, maxBytesToRead);
|
||||
}
|
||||
|
||||
bool setPosition (int64 newPos) override
|
||||
{
|
||||
if (newPos == getPosition())
|
||||
return true;
|
||||
|
||||
if (getPosition() < newPos)
|
||||
return skipImpl (newPos - getPosition());
|
||||
|
||||
auto newStream = fromUri (uri);
|
||||
|
||||
if (! newStream.has_value())
|
||||
return false;
|
||||
|
||||
*this = std::move (*newStream);
|
||||
return skipImpl (newPos);
|
||||
}
|
||||
|
||||
int64 getPosition() override
|
||||
{
|
||||
return stream.getPosition();
|
||||
}
|
||||
|
||||
void skipNextBytes (int64 num) override
|
||||
{
|
||||
stream.skipNextBytes (num);
|
||||
}
|
||||
|
||||
static std::optional<AndroidContentUriInputStream> fromUri (const GlobalRef& uriIn)
|
||||
{
|
||||
const auto nativeStream = AndroidStreamHelpers::createStream (uriIn, AndroidStreamHelpers::StreamKind::input);
|
||||
|
||||
if (nativeStream == nullptr)
|
||||
return {};
|
||||
|
||||
return AndroidContentUriInputStream { AndroidInputStreamWrapper { nativeStream }, uriIn };
|
||||
}
|
||||
|
||||
private:
|
||||
AndroidContentUriInputStream (AndroidInputStreamWrapper streamIn, const GlobalRef& uriIn)
|
||||
: stream (std::move (streamIn)),
|
||||
uri (uriIn)
|
||||
{
|
||||
}
|
||||
|
||||
bool skipImpl (int64 num)
|
||||
{
|
||||
const auto oldPosition = getPosition();
|
||||
skipNextBytes (num);
|
||||
return getPosition() == oldPosition + num;
|
||||
}
|
||||
|
||||
AndroidInputStreamWrapper stream;
|
||||
GlobalRef uri;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class MediaScannerConnectionClient : public AndroidInterfaceImplementer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,407 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class CustomTypeface::GlyphInfo
|
||||
{
|
||||
public:
|
||||
GlyphInfo (juce_wchar c, const Path& p, float w) noexcept
|
||||
: character (c), path (p), width (w)
|
||||
{
|
||||
}
|
||||
|
||||
struct KerningPair
|
||||
{
|
||||
juce_wchar character2;
|
||||
float kerningAmount;
|
||||
};
|
||||
|
||||
void addKerningPair (juce_wchar subsequentCharacter, float extraKerningAmount) noexcept
|
||||
{
|
||||
kerningPairs.add ({ subsequentCharacter, extraKerningAmount });
|
||||
}
|
||||
|
||||
float getHorizontalSpacing (juce_wchar subsequentCharacter) const noexcept
|
||||
{
|
||||
if (subsequentCharacter != 0)
|
||||
for (auto& kp : kerningPairs)
|
||||
if (kp.character2 == subsequentCharacter)
|
||||
return width + kp.kerningAmount;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
const juce_wchar character;
|
||||
const Path path;
|
||||
float width;
|
||||
Array<KerningPair> kerningPairs;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphInfo)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
namespace CustomTypefaceHelpers
|
||||
{
|
||||
static juce_wchar readChar (InputStream& in)
|
||||
{
|
||||
auto n = (uint32) (uint16) in.readShort();
|
||||
|
||||
if (n >= 0xd800 && n <= 0xdfff)
|
||||
{
|
||||
auto nextWord = (uint32) (uint16) in.readShort();
|
||||
jassert (nextWord >= 0xdc00); // illegal unicode character!
|
||||
|
||||
n = 0x10000 + (((n - 0xd800) << 10) | (nextWord - 0xdc00));
|
||||
}
|
||||
|
||||
return (juce_wchar) n;
|
||||
}
|
||||
|
||||
static void writeChar (OutputStream& out, juce_wchar charToWrite)
|
||||
{
|
||||
if (charToWrite >= 0x10000)
|
||||
{
|
||||
charToWrite -= 0x10000;
|
||||
out.writeShort ((short) (uint16) (0xd800 + (charToWrite >> 10)));
|
||||
out.writeShort ((short) (uint16) (0xdc00 + (charToWrite & 0x3ff)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.writeShort ((short) (uint16) charToWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
CustomTypeface::CustomTypeface()
|
||||
: Typeface (String(), String())
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
CustomTypeface::CustomTypeface (InputStream& serialisedTypefaceStream)
|
||||
: Typeface (String(), String())
|
||||
{
|
||||
clear();
|
||||
|
||||
GZIPDecompressorInputStream gzin (serialisedTypefaceStream);
|
||||
BufferedInputStream in (gzin, 32768);
|
||||
|
||||
name = in.readString();
|
||||
|
||||
const bool isBold = in.readBool();
|
||||
const bool isItalic = in.readBool();
|
||||
style = FontStyleHelpers::getStyleName (isBold, isItalic);
|
||||
|
||||
ascent = in.readFloat();
|
||||
defaultCharacter = CustomTypefaceHelpers::readChar (in);
|
||||
|
||||
auto numChars = in.readInt();
|
||||
|
||||
for (int i = 0; i < numChars; ++i)
|
||||
{
|
||||
auto c = CustomTypefaceHelpers::readChar (in);
|
||||
auto width = in.readFloat();
|
||||
|
||||
Path p;
|
||||
p.loadPathFromStream (in);
|
||||
addGlyph (c, p, width);
|
||||
}
|
||||
|
||||
auto numKerningPairs = in.readInt();
|
||||
|
||||
for (int i = 0; i < numKerningPairs; ++i)
|
||||
{
|
||||
auto char1 = CustomTypefaceHelpers::readChar (in);
|
||||
auto char2 = CustomTypefaceHelpers::readChar (in);
|
||||
|
||||
addKerningPair (char1, char2, in.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
CustomTypeface::~CustomTypeface()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CustomTypeface::clear()
|
||||
{
|
||||
defaultCharacter = 0;
|
||||
ascent = 1.0f;
|
||||
style = "Regular";
|
||||
zeromem (lookupTable, sizeof (lookupTable));
|
||||
glyphs.clear();
|
||||
}
|
||||
|
||||
void CustomTypeface::setCharacteristics (const String& newName, float newAscent, bool isBold,
|
||||
bool isItalic, juce_wchar newDefaultCharacter) noexcept
|
||||
{
|
||||
name = newName;
|
||||
defaultCharacter = newDefaultCharacter;
|
||||
ascent = newAscent;
|
||||
style = FontStyleHelpers::getStyleName (isBold, isItalic);
|
||||
}
|
||||
|
||||
void CustomTypeface::setCharacteristics (const String& newName, const String& newStyle,
|
||||
float newAscent, juce_wchar newDefaultCharacter) noexcept
|
||||
{
|
||||
name = newName;
|
||||
style = newStyle;
|
||||
defaultCharacter = newDefaultCharacter;
|
||||
ascent = newAscent;
|
||||
}
|
||||
|
||||
void CustomTypeface::addGlyph (juce_wchar character, const Path& path, float width) noexcept
|
||||
{
|
||||
// Check that you're not trying to add the same character twice..
|
||||
jassert (findGlyph (character, false) == nullptr);
|
||||
|
||||
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)))
|
||||
lookupTable [character] = (short) glyphs.size();
|
||||
|
||||
glyphs.add (new GlyphInfo (character, path, width));
|
||||
}
|
||||
|
||||
void CustomTypeface::addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept
|
||||
{
|
||||
if (! approximatelyEqual (extraAmount, 0.0f))
|
||||
{
|
||||
if (auto* g = findGlyph (char1, true))
|
||||
g->addKerningPair (char2, extraAmount);
|
||||
else
|
||||
jassertfalse; // can only add kerning pairs for characters that exist!
|
||||
}
|
||||
}
|
||||
|
||||
CustomTypeface::GlyphInfo* CustomTypeface::findGlyph (juce_wchar character, bool loadIfNeeded) noexcept
|
||||
{
|
||||
if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)) && lookupTable [character] > 0)
|
||||
return glyphs [(int) lookupTable [(int) character]];
|
||||
|
||||
for (auto* g : glyphs)
|
||||
if (g->character == character)
|
||||
return g;
|
||||
|
||||
if (loadIfNeeded && loadGlyphIfPossible (character))
|
||||
return findGlyph (character, false);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CustomTypeface::loadGlyphIfPossible (juce_wchar)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CustomTypeface::addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept
|
||||
{
|
||||
setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter);
|
||||
|
||||
for (int i = 0; i < numCharacters; ++i)
|
||||
{
|
||||
auto c = (juce_wchar) (characterStartIndex + static_cast<juce_wchar> (i));
|
||||
|
||||
Array<int> glyphIndexes;
|
||||
Array<float> offsets;
|
||||
typefaceToCopy.getGlyphPositions (String::charToString (c), glyphIndexes, offsets);
|
||||
|
||||
const int glyphIndex = glyphIndexes.getFirst();
|
||||
|
||||
if (glyphIndex >= 0 && glyphIndexes.size() > 0)
|
||||
{
|
||||
auto glyphWidth = offsets[1];
|
||||
|
||||
Path p;
|
||||
typefaceToCopy.getOutlineForGlyph (glyphIndex, p);
|
||||
|
||||
addGlyph (c, p, glyphWidth);
|
||||
|
||||
for (int j = glyphs.size() - 1; --j >= 0;)
|
||||
{
|
||||
auto char2 = glyphs.getUnchecked (j)->character;
|
||||
glyphIndexes.clearQuick();
|
||||
offsets.clearQuick();
|
||||
typefaceToCopy.getGlyphPositions (String::charToString (c) + String::charToString (char2), glyphIndexes, offsets);
|
||||
|
||||
if (offsets.size() > 1)
|
||||
addKerningPair (c, char2, offsets[1] - glyphWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomTypeface::writeToStream (OutputStream& outputStream)
|
||||
{
|
||||
GZIPCompressorOutputStream out (outputStream);
|
||||
|
||||
out.writeString (name);
|
||||
out.writeBool (FontStyleHelpers::isBold (style));
|
||||
out.writeBool (FontStyleHelpers::isItalic (style));
|
||||
out.writeFloat (ascent);
|
||||
CustomTypefaceHelpers::writeChar (out, defaultCharacter);
|
||||
out.writeInt (glyphs.size());
|
||||
|
||||
int numKerningPairs = 0;
|
||||
|
||||
for (auto* g : glyphs)
|
||||
{
|
||||
CustomTypefaceHelpers::writeChar (out, g->character);
|
||||
out.writeFloat (g->width);
|
||||
g->path.writePathToStream (out);
|
||||
|
||||
numKerningPairs += g->kerningPairs.size();
|
||||
}
|
||||
|
||||
out.writeInt (numKerningPairs);
|
||||
|
||||
for (auto* g : glyphs)
|
||||
{
|
||||
for (auto& p : g->kerningPairs)
|
||||
{
|
||||
CustomTypefaceHelpers::writeChar (out, g->character);
|
||||
CustomTypefaceHelpers::writeChar (out, p.character2);
|
||||
out.writeFloat (p.kerningAmount);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
float CustomTypeface::getAscent() const { return ascent; }
|
||||
float CustomTypeface::getDescent() const { return 1.0f - ascent; }
|
||||
float CustomTypeface::getHeightToPointsFactor() const { return ascent; }
|
||||
|
||||
float CustomTypeface::getStringWidth (const String& text)
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
for (auto t = text.getCharPointer(); ! t.isEmpty();)
|
||||
{
|
||||
auto c = t.getAndAdvance();
|
||||
|
||||
if (auto* glyph = findGlyph (c, true))
|
||||
{
|
||||
x += glyph->getHorizontalSpacing (*t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto fallbackTypeface = Typeface::getFallbackTypeface())
|
||||
if (fallbackTypeface.get() != this)
|
||||
x += fallbackTypeface->getStringWidth (String::charToString (c));
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void CustomTypeface::getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
|
||||
{
|
||||
xOffsets.add (0);
|
||||
float x = 0;
|
||||
|
||||
for (auto t = text.getCharPointer(); ! t.isEmpty();)
|
||||
{
|
||||
float width = 0.0f;
|
||||
int glyphChar = 0;
|
||||
|
||||
auto c = t.getAndAdvance();
|
||||
|
||||
if (auto* glyph = findGlyph (c, true))
|
||||
{
|
||||
width = glyph->getHorizontalSpacing (*t);
|
||||
glyphChar = (int) glyph->character;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto fallbackTypeface = getFallbackTypeface();
|
||||
|
||||
if (fallbackTypeface != nullptr && fallbackTypeface.get() != this)
|
||||
{
|
||||
Array<int> subGlyphs;
|
||||
Array<float> subOffsets;
|
||||
fallbackTypeface->getGlyphPositions (String::charToString (c), subGlyphs, subOffsets);
|
||||
|
||||
if (subGlyphs.size() > 0)
|
||||
{
|
||||
glyphChar = subGlyphs.getFirst();
|
||||
width = subOffsets[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += width;
|
||||
resultGlyphs.add (glyphChar);
|
||||
xOffsets.add (x);
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomTypeface::getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
{
|
||||
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
|
||||
{
|
||||
path = glyph->path;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto fallbackTypeface = getFallbackTypeface())
|
||||
if (fallbackTypeface.get() != this)
|
||||
return fallbackTypeface->getOutlineForGlyph (glyphNumber, path);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EdgeTable* CustomTypeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
|
||||
{
|
||||
if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
|
||||
{
|
||||
if (! glyph->path.isEmpty())
|
||||
return new EdgeTable (glyph->path.getBoundsTransformed (transform)
|
||||
.getSmallestIntegerContainer().expanded (1, 0),
|
||||
glyph->path, transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto fallbackTypeface = getFallbackTypeface())
|
||||
if (fallbackTypeface.get() != this)
|
||||
return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A typeface that can be populated with custom glyphs.
|
||||
|
||||
You can create a CustomTypeface if you need one that contains your own glyphs,
|
||||
or if you need to load a typeface from a Juce-formatted binary stream.
|
||||
|
||||
If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface()
|
||||
to copy glyphs into this face.
|
||||
|
||||
NOTE! For most people this class is almost certainly NOT the right tool to use!
|
||||
If what you want to do is to embed a font into your exe, then your best plan is
|
||||
probably to embed your TTF/OTF font file into your binary using the Projucer,
|
||||
and then call Typeface::createSystemTypefaceFor() to load it from memory.
|
||||
|
||||
@see Typeface, Font
|
||||
|
||||
@tags{Graphics}
|
||||
*/
|
||||
class JUCE_API CustomTypeface : public Typeface
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new, empty typeface. */
|
||||
CustomTypeface();
|
||||
|
||||
/** Loads a typeface from a previously saved stream.
|
||||
The stream must have been created by writeToStream().
|
||||
|
||||
NOTE! Since this class was written, support was added for loading real font files from
|
||||
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
|
||||
is more appropriate than using this class to store it in a proprietary format.
|
||||
|
||||
@see writeToStream
|
||||
*/
|
||||
explicit CustomTypeface (InputStream& serialisedTypefaceStream);
|
||||
|
||||
/** Destructor. */
|
||||
~CustomTypeface() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Resets this typeface, deleting all its glyphs and settings. */
|
||||
void clear();
|
||||
|
||||
/** Sets the vital statistics for the typeface.
|
||||
@param fontFamily the typeface's font family
|
||||
@param ascent the ascent - this is normalised to a height of 1.0 and this is
|
||||
the value that will be returned by Typeface::getAscent(). The
|
||||
descent is assumed to be (1.0 - ascent)
|
||||
@param isBold should be true if the typeface is bold
|
||||
@param isItalic should be true if the typeface is italic
|
||||
@param defaultCharacter the character to be used as a replacement if there's
|
||||
no glyph available for the character that's being drawn
|
||||
*/
|
||||
void setCharacteristics (const String& fontFamily, float ascent,
|
||||
bool isBold, bool isItalic,
|
||||
juce_wchar defaultCharacter) noexcept;
|
||||
|
||||
/** Sets the vital statistics for the typeface.
|
||||
@param fontFamily the typeface's font family
|
||||
@param fontStyle the typeface's font style
|
||||
@param ascent the ascent - this is normalised to a height of 1.0 and this is
|
||||
the value that will be returned by Typeface::getAscent(). The
|
||||
descent is assumed to be (1.0 - ascent)
|
||||
@param defaultCharacter the character to be used as a replacement if there's
|
||||
no glyph available for the character that's being drawn
|
||||
*/
|
||||
void setCharacteristics (const String& fontFamily, const String& fontStyle,
|
||||
float ascent, juce_wchar defaultCharacter) noexcept;
|
||||
|
||||
/** Adds a glyph to the typeface.
|
||||
|
||||
The path that is passed in is normalised so that the font height is 1.0, and its
|
||||
origin is the anchor point of the character on its baseline.
|
||||
|
||||
The width is the nominal width of the character, and any extra kerning values that
|
||||
are specified will be added to this width.
|
||||
*/
|
||||
void addGlyph (juce_wchar character, const Path& path, float width) noexcept;
|
||||
|
||||
/** Specifies an extra kerning amount to be used between a pair of characters.
|
||||
The amount will be added to the nominal width of the first character when laying out a string.
|
||||
*/
|
||||
void addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept;
|
||||
|
||||
/** Adds a range of glyphs from another typeface.
|
||||
This will attempt to pull in the paths and kerning information from another typeface and
|
||||
add it to this one.
|
||||
*/
|
||||
void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept;
|
||||
|
||||
/** Saves this typeface as a Juce-formatted font file.
|
||||
A CustomTypeface can be created to reload the data that is written - see the CustomTypeface
|
||||
constructor.
|
||||
|
||||
NOTE! Since this class was written, support was added for loading real font files from
|
||||
memory, so for most people, using Typeface::createSystemTypefaceFor() to load a real font
|
||||
is more appropriate than using this class to store it in a proprietary format.
|
||||
*/
|
||||
bool writeToStream (OutputStream& outputStream);
|
||||
|
||||
//==============================================================================
|
||||
// The following methods implement the basic Typeface behaviour.
|
||||
float getAscent() const override;
|
||||
float getDescent() const override;
|
||||
float getHeightToPointsFactor() const override;
|
||||
float getStringWidth (const String&) override;
|
||||
void getGlyphPositions (const String&, Array<int>& glyphs, Array<float>& xOffsets) override;
|
||||
bool getOutlineForGlyph (int glyphNumber, Path&) override;
|
||||
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform&, float fontHeight) override;
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
juce_wchar defaultCharacter;
|
||||
float ascent;
|
||||
|
||||
//==============================================================================
|
||||
/** If a subclass overrides this, it can load glyphs into the font on-demand.
|
||||
When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a
|
||||
particular character and there's no corresponding glyph, they'll call this
|
||||
method so that a subclass can try to add that glyph, returning true if it
|
||||
manages to do so.
|
||||
*/
|
||||
virtual bool loadGlyphIfPossible (juce_wchar characterNeeded);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class GlyphInfo;
|
||||
OwnedArray<GlyphInfo> glyphs;
|
||||
short lookupTable[128];
|
||||
|
||||
GlyphInfo* findGlyph (juce_wchar character, bool loadIfNeeded) noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -35,6 +35,12 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
class Font::Native
|
||||
{
|
||||
public:
|
||||
HbFont font{};
|
||||
};
|
||||
|
||||
namespace FontValues
|
||||
{
|
||||
static float limitFontHeight (const float height) noexcept
|
||||
|
|
@ -48,12 +54,130 @@ namespace FontValues
|
|||
String fallbackFontStyle;
|
||||
}
|
||||
|
||||
class HbScale
|
||||
{
|
||||
static constexpr float factor = 1 << 16;
|
||||
|
||||
public:
|
||||
HbScale() = delete;
|
||||
|
||||
static constexpr hb_position_t juceToHb (float pos)
|
||||
{
|
||||
return (hb_position_t) (pos * factor);
|
||||
}
|
||||
|
||||
static constexpr float hbToJuce (hb_position_t pos)
|
||||
{
|
||||
return (float) pos / (float) factor;
|
||||
}
|
||||
};
|
||||
|
||||
using GetTypefaceForFont = Typeface::Ptr (*)(const Font&);
|
||||
GetTypefaceForFont juce_getTypefaceForFont = nullptr;
|
||||
|
||||
float Font::getDefaultMinimumHorizontalScaleFactor() noexcept { return FontValues::minimumHorizontalScale; }
|
||||
void Font::setDefaultMinimumHorizontalScaleFactor (float newValue) noexcept { FontValues::minimumHorizontalScale = newValue; }
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
template <CTFontOrientation orientation>
|
||||
void getAdvancesForGlyphs (hb_font_t* hbFont, CTFontRef ctFont, Span<const CGGlyph> glyphs, Span<CGSize> advances)
|
||||
{
|
||||
jassert (glyphs.size() == advances.size());
|
||||
|
||||
int x, y;
|
||||
hb_font_get_scale (hbFont, &x, &y);
|
||||
const auto scaleAdjustment = HbScale::hbToJuce (orientation == kCTFontOrientationHorizontal ? x : y) / CTFontGetSize (ctFont);
|
||||
|
||||
CTFontGetAdvancesForGlyphs (ctFont, orientation, std::data (glyphs), std::data (advances), (CFIndex) std::size (glyphs));
|
||||
|
||||
for (auto& advance : advances)
|
||||
(orientation == kCTFontOrientationHorizontal ? advance.width : advance.height) *= scaleAdjustment;
|
||||
}
|
||||
|
||||
template <CTFontOrientation orientation>
|
||||
static auto getAdvanceFn()
|
||||
{
|
||||
return [] (hb_font_t* f, void*, hb_codepoint_t glyph, void* voidFontRef) -> hb_position_t
|
||||
{
|
||||
auto* fontRef = static_cast<CTFontRef> (voidFontRef);
|
||||
|
||||
const CGGlyph glyphs[] { (CGGlyph) glyph };
|
||||
CGSize advances[std::size (glyphs)]{};
|
||||
getAdvancesForGlyphs<orientation> (f, fontRef, glyphs, advances);
|
||||
|
||||
return HbScale::juceToHb ((float) (orientation == kCTFontOrientationHorizontal ? advances->width : advances->height));
|
||||
};
|
||||
}
|
||||
|
||||
template <CTFontOrientation orientation>
|
||||
static auto getAdvancesFn()
|
||||
{
|
||||
return [] (hb_font_t* f,
|
||||
void*,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t* firstGlyph,
|
||||
unsigned int glyphStride,
|
||||
hb_position_t* firstAdvance,
|
||||
unsigned int advanceStride,
|
||||
void* voidFontRef)
|
||||
{
|
||||
auto* fontRef = static_cast<CTFontRef> (voidFontRef);
|
||||
|
||||
std::vector<CGGlyph> glyphs (count);
|
||||
|
||||
for (auto [index, glyph] : enumerate (glyphs))
|
||||
glyph = (CGGlyph) *addBytesToPointer (firstGlyph, glyphStride * index);
|
||||
|
||||
std::vector<CGSize> advances (count);
|
||||
|
||||
getAdvancesForGlyphs<orientation> (f, fontRef, glyphs, advances);
|
||||
|
||||
for (auto [index, advance] : enumerate (advances))
|
||||
*addBytesToPointer (firstAdvance, advanceStride * index) = HbScale::juceToHb ((float) (orientation == kCTFontOrientationHorizontal ? advance.width : advance.height));
|
||||
};
|
||||
}
|
||||
|
||||
/* This function overrides the callbacks that fetch glyph advances for fonts on macOS.
|
||||
The built-in OpenType glyph metric callbacks that HarfBuzz uses by default for fonts such as
|
||||
"Apple Color Emoji" don't always return correct advances, resulting in emoji that may overlap
|
||||
with subsequent characters. This may be to do with ignoring the 'trak' table, but I'm not an
|
||||
expert, so I'm not sure!
|
||||
|
||||
In any case, using CTFontGetAdvancesForGlyphs produces much nicer advances for emoji on Apple
|
||||
platforms, as long as the CTFont is set to the size that will eventually be rendered.
|
||||
|
||||
This might need a bit of testing to make sure that it correctly handles advances for
|
||||
custom (non-Apple?) fonts.
|
||||
|
||||
@param hb a hb_font_t to update with Apple-specific advances
|
||||
@param fontRef the CTFontRef (normally with a custom point size) that will be queried when computing advances
|
||||
*/
|
||||
static void overrideCTFontAdvances (hb_font_t* hb, CTFontRef fontRef)
|
||||
{
|
||||
using HbFontFuncs = std::unique_ptr<hb_font_funcs_t, FunctionPointerDestructor<hb_font_funcs_destroy>>;
|
||||
const HbFontFuncs funcs { hb_font_funcs_create() };
|
||||
|
||||
// We pass the CTFontRef as user data to each of these functions.
|
||||
// We don't pass a custom destructor for the user data, as that will be handled by the custom
|
||||
// destructor for the hb_font_funcs_t.
|
||||
hb_font_funcs_set_glyph_h_advance_func (funcs.get(), getAdvanceFn <kCTFontOrientationHorizontal>(), (void*) fontRef, nullptr);
|
||||
hb_font_funcs_set_glyph_v_advance_func (funcs.get(), getAdvanceFn <kCTFontOrientationVertical>(), (void*) fontRef, nullptr);
|
||||
hb_font_funcs_set_glyph_h_advances_func (funcs.get(), getAdvancesFn<kCTFontOrientationHorizontal>(), (void*) fontRef, nullptr);
|
||||
hb_font_funcs_set_glyph_v_advances_func (funcs.get(), getAdvancesFn<kCTFontOrientationVertical>(), (void*) fontRef, nullptr);
|
||||
|
||||
// We want to keep a copy of the font around so that all of our custom callbacks can query it,
|
||||
// so retain it here and release it once the custom functions are no longer in use.
|
||||
jassert (fontRef != nullptr);
|
||||
CFRetain (fontRef);
|
||||
|
||||
hb_font_set_funcs (hb, funcs.get(), (void*) fontRef, [] (void* ptr)
|
||||
{
|
||||
CFRelease ((CTFontRef) ptr);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class TypefaceCache final : private DeletedAtShutdown
|
||||
{
|
||||
|
|
@ -102,8 +226,7 @@ public:
|
|||
|
||||
if (face.typefaceName == faceName
|
||||
&& face.typefaceStyle == faceStyle
|
||||
&& face.typeface != nullptr
|
||||
&& face.typeface->isSuitableForFont (font))
|
||||
&& face.typeface != nullptr)
|
||||
{
|
||||
face.lastUsageCount = ++counter;
|
||||
return face.typeface;
|
||||
|
|
@ -287,12 +410,34 @@ public:
|
|||
return typeface;
|
||||
}
|
||||
|
||||
void checkTypefaceSuitability (const Font& f)
|
||||
HbFont getFontPtr (const Font& f)
|
||||
{
|
||||
const ScopedLock lock (mutex);
|
||||
|
||||
if (typeface != nullptr && ! typeface->isSuitableForFont (f))
|
||||
typeface = nullptr;
|
||||
if (auto ptr = getTypefacePtr (f))
|
||||
{
|
||||
if (HbFont subFont { hb_font_create_sub_font (ptr->getNativeDetails().getFont()) })
|
||||
{
|
||||
const auto points = legacyHeightToPoints (ptr, height);
|
||||
|
||||
hb_font_set_ptem (subFont.get(), points);
|
||||
hb_font_set_scale (subFont.get(), HbScale::juceToHb (points * horizontalScale), HbScale::juceToHb (points));
|
||||
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
overrideCTFontAdvances (subFont.get(), hb_coretext_font_get_ct_font (subFont.get()));
|
||||
#endif
|
||||
|
||||
return subFont;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void resetTypeface()
|
||||
{
|
||||
const ScopedLock lock (mutex);
|
||||
typeface = nullptr;
|
||||
}
|
||||
|
||||
float getAscent (const Font& f)
|
||||
|
|
@ -373,6 +518,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
static float legacyHeightToPoints (Typeface::Ptr p, float h)
|
||||
{
|
||||
return h * p->getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
}
|
||||
|
||||
Typeface::Ptr typeface;
|
||||
String typefaceName, typefaceStyle;
|
||||
float height = 0.0f, horizontalScale = 1.0f, kerning = 0.0f, ascent = 0.0f;
|
||||
|
|
@ -442,11 +592,6 @@ void Font::dupeInternalIfShared()
|
|||
font = *new SharedFontInternal (*font);
|
||||
}
|
||||
|
||||
void Font::checkTypefaceSuitability()
|
||||
{
|
||||
font->checkTypefaceSuitability (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct FontPlaceholderNames
|
||||
{
|
||||
|
|
@ -581,7 +726,7 @@ void Font::setHeight (float newHeight)
|
|||
{
|
||||
dupeInternalIfShared();
|
||||
font->setHeight (newHeight);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +739,7 @@ void Font::setHeightWithoutChangingWidth (float newHeight)
|
|||
dupeInternalIfShared();
|
||||
font->setHorizontalScale (font->getHorizontalScale() * (font->getHeight() / newHeight));
|
||||
font->setHeight (newHeight);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +787,7 @@ void Font::setSizeAndStyle (float newHeight,
|
|||
font->setHeight (newHeight);
|
||||
font->setHorizontalScale (newHorizontalScale);
|
||||
font->setKerning (newKerningAmount);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
|
||||
setStyleFlags (newStyleFlags);
|
||||
|
|
@ -663,7 +808,7 @@ void Font::setSizeAndStyle (float newHeight,
|
|||
font->setHeight (newHeight);
|
||||
font->setHorizontalScale (newHorizontalScale);
|
||||
font->setKerning (newKerningAmount);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
|
||||
setTypefaceStyle (newStyle);
|
||||
|
|
@ -680,7 +825,7 @@ void Font::setHorizontalScale (const float scaleFactor)
|
|||
{
|
||||
dupeInternalIfShared();
|
||||
font->setHorizontalScale (scaleFactor);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
|
||||
float Font::getHorizontalScale() const noexcept
|
||||
|
|
@ -704,7 +849,7 @@ void Font::setExtraKerningFactor (const float extraKerning)
|
|||
{
|
||||
dupeInternalIfShared();
|
||||
font->setKerning (extraKerning);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
|
||||
Font Font::boldened() const { return withStyle (getStyleFlags() | bold); }
|
||||
|
|
@ -732,7 +877,7 @@ void Font::setUnderline (const bool shouldBeUnderlined)
|
|||
{
|
||||
dupeInternalIfShared();
|
||||
font->setUnderline (shouldBeUnderlined);
|
||||
checkTypefaceSuitability();
|
||||
font->resetTypeface();
|
||||
}
|
||||
|
||||
float Font::getAscent() const
|
||||
|
|
@ -837,4 +982,9 @@ Font Font::fromString (const String& fontDescription)
|
|||
return Font (name, style, height);
|
||||
}
|
||||
|
||||
Font::Native Font::getNativeDetails() const
|
||||
{
|
||||
return { font->getFontPtr (*this) };
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -478,12 +478,23 @@ public:
|
|||
*/
|
||||
static Font fromString (const String& fontDescription);
|
||||
|
||||
/** @internal */
|
||||
class Native;
|
||||
|
||||
/** @internal
|
||||
|
||||
At the moment, this is a way to get at the hb_font_t that backs this font.
|
||||
The typeface's hb_font_t is sized appropriately for this font instance.
|
||||
The font may also have synthetic slant and bold applied.
|
||||
This is only for internal use!
|
||||
*/
|
||||
Native getNativeDetails() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
static bool compare (const Font&, const Font&) noexcept;
|
||||
|
||||
void dupeInternalIfShared();
|
||||
void checkTypefaceSuitability();
|
||||
float getHeightToPointsFactor() const;
|
||||
|
||||
friend struct GraphicsFontHelpers;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,76 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
struct TypefaceLegacyMetrics
|
||||
{
|
||||
float ascent{}; // in em units
|
||||
float descent{}; // in em units
|
||||
|
||||
float getScaledAscent() const { return ascent * getHeightToPointsFactor(); }
|
||||
float getScaledDescent() const { return descent * getHeightToPointsFactor(); }
|
||||
|
||||
float getPointsToHeightFactor() const { return ascent + descent; }
|
||||
float getHeightToPointsFactor() const { return 1.0f / getPointsToHeightFactor(); }
|
||||
};
|
||||
|
||||
using HbFont = std::unique_ptr<hb_font_t, FunctionPointerDestructor<hb_font_destroy>>;
|
||||
using HbFace = std::unique_ptr<hb_face_t, FunctionPointerDestructor<hb_face_destroy>>;
|
||||
using HbBuffer = std::unique_ptr<hb_buffer_t, FunctionPointerDestructor<hb_buffer_destroy>>;
|
||||
|
||||
class Typeface::Native
|
||||
{
|
||||
public:
|
||||
explicit Native (hb_font_t* fontRef)
|
||||
: Native (fontRef, findLegacyMetrics (fontRef)) {}
|
||||
|
||||
Native (hb_font_t* fontRef, TypefaceLegacyMetrics metrics)
|
||||
: font (fontRef), legacyMetrics (metrics) {}
|
||||
|
||||
auto* getFont() const { return font; }
|
||||
|
||||
auto getLegacyMetrics() const { return legacyMetrics; }
|
||||
|
||||
private:
|
||||
static TypefaceLegacyMetrics findLegacyMetrics (hb_font_t* f)
|
||||
{
|
||||
hb_font_extents_t extents{};
|
||||
|
||||
if (! hb_font_get_h_extents (f, &extents))
|
||||
{
|
||||
// jassertfalse;
|
||||
return { 0.5f, 0.5f };
|
||||
}
|
||||
|
||||
const auto ascent = std::abs ((float) extents.ascender);
|
||||
const auto descent = std::abs ((float) extents.descender);
|
||||
const auto upem = (float) hb_face_get_upem (hb_font_get_face (f));
|
||||
|
||||
TypefaceLegacyMetrics result;
|
||||
result.ascent = ascent / upem;
|
||||
result.descent = descent / upem;
|
||||
return result;
|
||||
}
|
||||
|
||||
hb_font_t* font = nullptr;
|
||||
TypefaceLegacyMetrics legacyMetrics;
|
||||
};
|
||||
|
||||
struct FontStyleHelpers
|
||||
{
|
||||
static void initSynthetics (hb_font_t* hb, const Font& font)
|
||||
{
|
||||
const auto styles = Font::findAllTypefaceStyles (font.getTypefaceName());
|
||||
|
||||
if (styles.contains (font.getTypefaceStyle()))
|
||||
return;
|
||||
|
||||
if (font.isItalic())
|
||||
hb_font_set_synthetic_slant (hb, 0.1f);
|
||||
|
||||
if (font.isBold())
|
||||
hb_font_set_synthetic_bold (hb, 0.04f, 0.04f, true);
|
||||
}
|
||||
|
||||
static const char* getStyleName (const bool bold,
|
||||
const bool italic) noexcept
|
||||
{
|
||||
|
|
@ -60,7 +128,7 @@ struct FontStyleHelpers
|
|||
static bool isItalic (const String& style) noexcept
|
||||
{
|
||||
return style.containsWholeWordIgnoreCase ("Italic")
|
||||
|| style.containsWholeWordIgnoreCase ("Oblique");
|
||||
|| style.containsWholeWordIgnoreCase ("Oblique");
|
||||
}
|
||||
|
||||
static bool isPlaceholderFamilyName (const String& family)
|
||||
|
|
@ -91,7 +159,7 @@ struct FontStyleHelpers
|
|||
private:
|
||||
static String findName (const String& placeholder)
|
||||
{
|
||||
const Font f (placeholder, Font::getDefaultStyle(), 15.0f);
|
||||
const Font f (placeholder, 15.0f, Font::plain);
|
||||
return Font::getDefaultTypefaceForFont (f)->getName();
|
||||
}
|
||||
|
||||
|
|
@ -111,162 +179,223 @@ struct FontStyleHelpers
|
|||
return isPlaceholderFamilyName (family) ? getConcreteFamilyNameFromPlaceholder (family)
|
||||
: family;
|
||||
}
|
||||
|
||||
static HbFace getFaceForBlob (Span<const char> bytes, unsigned int index)
|
||||
{
|
||||
auto* blob = hb_blob_create_or_fail (bytes.data(),
|
||||
(unsigned int) bytes.size(),
|
||||
HB_MEMORY_MODE_DUPLICATE,
|
||||
nullptr,
|
||||
nullptr);
|
||||
const ScopeGuard scope { [&] { hb_blob_destroy (blob); } };
|
||||
|
||||
const auto count = hb_face_count (blob);
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
// Attempted to create a font from invalid data. Perhaps the font format was unrecognised.
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
return HbFace { hb_face_create (blob, index) };
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Typeface (const String& faceName, const String& styleName) noexcept
|
||||
: name (faceName), style (styleName)
|
||||
Typeface::Typeface (const String& faceName, const String& faceStyle) noexcept
|
||||
: name (faceName),
|
||||
style (faceStyle)
|
||||
{
|
||||
}
|
||||
|
||||
Typeface::~Typeface() = default;
|
||||
|
||||
Typeface::Ptr Typeface::getFallbackTypeface()
|
||||
using HbDrawFuncs = std::unique_ptr<hb_draw_funcs_t, FunctionPointerDestructor<hb_draw_funcs_destroy>>;
|
||||
|
||||
static HbDrawFuncs getPathDrawFuncs()
|
||||
{
|
||||
const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f);
|
||||
return fallbackFont.getTypefacePtr();
|
||||
HbDrawFuncs funcs { hb_draw_funcs_create() };
|
||||
|
||||
hb_draw_funcs_set_move_to_func (funcs.get(), [] (auto*, void* data, auto*, float x, float y, auto*)
|
||||
{
|
||||
auto& path = *static_cast<Path*> (data);
|
||||
path.startNewSubPath ({ x, y });
|
||||
}, nullptr, nullptr);
|
||||
hb_draw_funcs_set_line_to_func (funcs.get(), [] (auto*, void* data, auto*, float x, float y, auto*)
|
||||
{
|
||||
auto& path = *static_cast<Path*> (data);
|
||||
path.lineTo ({ x, y });
|
||||
}, nullptr, nullptr);
|
||||
hb_draw_funcs_set_quadratic_to_func (funcs.get(), [] (auto*, void* data, auto*, float ctlX, float ctlY, float toX, float toY, auto*)
|
||||
{
|
||||
auto& path = *static_cast<Path*> (data);
|
||||
path.quadraticTo ({ ctlX, ctlY }, { toX, toY });
|
||||
}, nullptr, nullptr);
|
||||
hb_draw_funcs_set_cubic_to_func (funcs.get(), [] (auto*, void* data, auto*, float ctlX1, float ctlY1, float ctlX2, float ctlY2, float toX, float toY, auto*)
|
||||
{
|
||||
auto& path = *static_cast<Path*> (data);
|
||||
path.cubicTo ({ ctlX1, ctlY1 }, { ctlX2, ctlY2 }, { toX, toY });
|
||||
}, nullptr, nullptr);
|
||||
hb_draw_funcs_set_close_path_func (funcs.get(), [] (auto*, void* data, auto*, auto*)
|
||||
{
|
||||
auto& path = *static_cast<Path*> (data);
|
||||
path.closeSubPath();
|
||||
}, nullptr, nullptr);
|
||||
|
||||
return funcs;
|
||||
}
|
||||
|
||||
EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
|
||||
static Path getTypefaceGlyph (const Typeface& typeface, int glyphNumber)
|
||||
{
|
||||
static const auto funcs = getPathDrawFuncs();
|
||||
|
||||
auto* font = typeface.getNativeDetails().getFont();
|
||||
|
||||
Path result;
|
||||
hb_font_draw_glyph (font, (hb_codepoint_t) glyphNumber, funcs.get(), &result);
|
||||
|
||||
// Convert to em units
|
||||
result.applyTransform (AffineTransform::scale (1.0f / (float) hb_face_get_upem (hb_font_get_face (font))).scaled (1.0f, -1.0f));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Typeface::getOutlineForGlyph (int glyphNumber, Path& path)
|
||||
{
|
||||
const auto metrics = getNativeDetails().getLegacyMetrics();
|
||||
|
||||
// getTypefaceGlyph returns glyphs in em space, getOutlineForGlyph returns glyphs in "special JUCE units" space
|
||||
path = getTypefaceGlyph (*this, glyphNumber);
|
||||
path.applyTransform (AffineTransform::scale (metrics.getHeightToPointsFactor()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Typeface::applyVerticalHintingTransform (float, Path&)
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float)
|
||||
{
|
||||
Path path;
|
||||
|
||||
if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
|
||||
{
|
||||
applyVerticalHintingTransform (fontHeight, path);
|
||||
if (! getOutlineForGlyph (glyphNumber, path) || path.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
|
||||
path, transform);
|
||||
}
|
||||
return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
|
||||
path, transform);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
float Typeface::getAscent() const { return getNativeDetails().getLegacyMetrics().getScaledAscent(); }
|
||||
float Typeface::getDescent() const { return getNativeDetails().getLegacyMetrics().getScaledDescent(); }
|
||||
float Typeface::getHeightToPointsFactor() const { return getNativeDetails().getLegacyMetrics().getHeightToPointsFactor(); }
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize)
|
||||
{
|
||||
return createSystemTypefaceFor (Span (static_cast<const std::byte*> (fontFileData), fontFileDataSize));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Typeface::HintingParams
|
||||
std::optional<uint32_t> Typeface::getNominalGlyphForCodepoint (juce_wchar cp) const
|
||||
{
|
||||
HintingParams (Typeface& t)
|
||||
{
|
||||
Font font (t);
|
||||
font = font.withHeight ((float) standardHeight);
|
||||
auto* font = getNativeDetails().getFont();
|
||||
|
||||
top = getAverageY (font, "BDEFPRTZOQ", true);
|
||||
middle = getAverageY (font, "acegmnopqrsuvwxy", true);
|
||||
bottom = getAverageY (font, "BDELZOC", false);
|
||||
}
|
||||
if (font == nullptr)
|
||||
return {};
|
||||
|
||||
void applyVerticalHintingTransform (float fontSize, Path& path)
|
||||
{
|
||||
if (! approximatelyEqual (cachedSize, fontSize))
|
||||
{
|
||||
cachedSize = fontSize;
|
||||
cachedScale = Scaling (top, middle, bottom, fontSize);
|
||||
}
|
||||
hb_codepoint_t result{};
|
||||
|
||||
if (bottom < top + 3.0f / fontSize)
|
||||
return;
|
||||
if (! hb_font_get_nominal_glyph (font, static_cast<hb_codepoint_t> (cp), &result))
|
||||
return {};
|
||||
|
||||
Path result;
|
||||
|
||||
for (Path::Iterator i (path); i.next();)
|
||||
{
|
||||
switch (i.elementType)
|
||||
{
|
||||
case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break;
|
||||
case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break;
|
||||
case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1),
|
||||
i.x2, cachedScale.apply (i.y2)); break;
|
||||
case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1),
|
||||
i.x2, cachedScale.apply (i.y2),
|
||||
i.x3, cachedScale.apply (i.y3)); break;
|
||||
case Path::Iterator::closePath: result.closeSubPath(); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
result.swapWithPath (path);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Scaling
|
||||
{
|
||||
Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {}
|
||||
|
||||
Scaling (float t, float m, float b, float fontSize) noexcept : middle (m)
|
||||
{
|
||||
const float newT = std::floor (fontSize * t + 0.5f) / fontSize;
|
||||
const float newB = std::floor (fontSize * b + 0.5f) / fontSize;
|
||||
const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters
|
||||
// are more likely to become taller than shorter.
|
||||
upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t));
|
||||
lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m));
|
||||
|
||||
upperOffset = newM - m * upperScale;
|
||||
lowerOffset = newB - b * lowerScale;
|
||||
}
|
||||
|
||||
float apply (float y) const noexcept
|
||||
{
|
||||
return y < middle ? (y * upperScale + upperOffset)
|
||||
: (y * lowerScale + lowerOffset);
|
||||
}
|
||||
|
||||
float middle, upperScale, upperOffset, lowerScale, lowerOffset;
|
||||
};
|
||||
|
||||
float cachedSize = 0;
|
||||
Scaling cachedScale;
|
||||
|
||||
static float getAverageY (const Font& font, const char* chars, bool getTop)
|
||||
{
|
||||
GlyphArrangement ga;
|
||||
ga.addLineOfText (font, chars, 0, 0);
|
||||
|
||||
Array<float> yValues;
|
||||
|
||||
for (auto& glyph : ga)
|
||||
{
|
||||
Path p;
|
||||
glyph.createPath (p);
|
||||
auto bounds = p.getBounds();
|
||||
|
||||
if (! p.isEmpty())
|
||||
yValues.add (getTop ? bounds.getY() : bounds.getBottom());
|
||||
}
|
||||
|
||||
std::sort (yValues.begin(), yValues.end());
|
||||
|
||||
auto median = yValues[yValues.size() / 2];
|
||||
float total = 0;
|
||||
int num = 0;
|
||||
|
||||
for (auto y : yValues)
|
||||
{
|
||||
if (std::abs (median - y) < 0.05f * (float) standardHeight)
|
||||
{
|
||||
total += y;
|
||||
++num;
|
||||
}
|
||||
}
|
||||
|
||||
return num < 4 ? 0.0f : total / ((float) num * (float) standardHeight);
|
||||
}
|
||||
|
||||
enum { standardHeight = 100 };
|
||||
float top = 0, middle = 0, bottom = 0;
|
||||
};
|
||||
|
||||
void Typeface::applyVerticalHintingTransform (float fontSize, Path& path)
|
||||
{
|
||||
if (fontSize > 3.0f && fontSize < 25.0f)
|
||||
{
|
||||
ScopedLock sl (hintingLock);
|
||||
|
||||
if (hintingParams == nullptr)
|
||||
hintingParams.reset (new HintingParams (*this));
|
||||
|
||||
return hintingParams->applyVerticalHintingTransform (fontSize, path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class TypefaceTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
TypefaceTests() : UnitTest ("Typeface", UnitTestCategories::graphics) {}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
// If we're running these tests standalone, we want singletons to be cleared before the app
|
||||
// exists, so as not to alarm th leak detector.
|
||||
const ScopedJuceInitialiser_GUI scope;
|
||||
|
||||
const auto systemNames = getFontFamilyNamesAsSet();
|
||||
|
||||
auto ptr = loadTypeface (FontBinaryData::Karla_Regular_Typo_On_Offsets_Off);
|
||||
const auto ptrName = ptr->getName();
|
||||
|
||||
// These tests assume that you don't have a font named "karla" installed.
|
||||
beginTest ("Setup");
|
||||
{
|
||||
expect (systemNames.count (ptr->getName()) == 0);
|
||||
}
|
||||
|
||||
beginTest ("Creating a font from memory allows it to be discovered by Font::findAllTypefaceNames()");
|
||||
{
|
||||
const auto newNames = getFontFamilyNamesAsSet();
|
||||
|
||||
expect (newNames.size() == systemNames.size() + 1);
|
||||
expect (newNames.count (ptr->getName()) == 1);
|
||||
}
|
||||
|
||||
beginTest ("The available styles of memory fonts can be found");
|
||||
{
|
||||
const auto styles = Font::findAllTypefaceStyles (ptr->getName());
|
||||
expect (styles == StringArray { ptr->getStyle() });
|
||||
}
|
||||
|
||||
beginTest ("Typefaces loaded from memory are found when creating font instances by name");
|
||||
{
|
||||
Font font (ptr->getName(), ptr->getStyle(), 12.0f);
|
||||
|
||||
expect (font.getTypefacePtr() != nullptr);
|
||||
expect (font.getTypefacePtr()->getName() == ptr->getName());
|
||||
expect (font.getTypefacePtr()->getStyle() == ptr->getStyle());
|
||||
}
|
||||
|
||||
// Unload font
|
||||
ptr = nullptr;
|
||||
|
||||
beginTest ("After a memory font is no longer referenced, it is not returned from Font::findAllTypefaceNames()");
|
||||
{
|
||||
const auto newNames = getFontFamilyNamesAsSet();
|
||||
expect (newNames == systemNames);
|
||||
}
|
||||
|
||||
beginTest ("After a memory font is no longer referenced, it has no styles");
|
||||
{
|
||||
const auto styles = Font::findAllTypefaceStyles (ptrName);
|
||||
expect (styles.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
static std::set<String> getFontFamilyNamesAsSet()
|
||||
{
|
||||
std::set<String> result;
|
||||
|
||||
for (const auto& name : Font::findAllTypefaceNames())
|
||||
result.insert (name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static Typeface::Ptr loadTypeface (Span<const unsigned char> data)
|
||||
{
|
||||
return Typeface::createSystemTypefaceFor (data.data(), data.size());
|
||||
}
|
||||
};
|
||||
|
||||
static TypefaceTests typefaceTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -42,19 +42,18 @@ namespace juce
|
|||
This base class is abstract, but calling createSystemTypefaceFor() will return
|
||||
a platform-specific subclass that can be used.
|
||||
|
||||
The CustomTypeface subclass allow you to build your own typeface, and to
|
||||
load and save it in the JUCE typeface format.
|
||||
|
||||
Normally you should never need to deal directly with Typeface objects - the Font
|
||||
class does everything you typically need for rendering text.
|
||||
|
||||
@see CustomTypeface, Font
|
||||
@see Font
|
||||
|
||||
@tags{Graphics}
|
||||
*/
|
||||
class JUCE_API Typeface : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
Typeface (const String& name, const String& newStyle) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** A handy typedef for a pointer to a typeface. */
|
||||
using Ptr = ReferenceCountedObjectPtr<Typeface>;
|
||||
|
|
@ -63,13 +62,13 @@ public:
|
|||
/** Returns the font family of the typeface.
|
||||
@see Font::getTypefaceName
|
||||
*/
|
||||
const String& getName() const noexcept { return name; }
|
||||
const String& getName() const noexcept { return name; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the font style of the typeface.
|
||||
@see Font::getTypefaceStyle
|
||||
*/
|
||||
const String& getStyle() const noexcept { return style; }
|
||||
const String& getStyle() const noexcept { return style; }
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a new system typeface. */
|
||||
|
|
@ -78,60 +77,97 @@ public:
|
|||
/** Attempts to create a font from some raw font file data (e.g. a TTF or OTF file image).
|
||||
The system will take its own internal copy of the data, so you can free the block once
|
||||
this method has returned.
|
||||
|
||||
The typeface will remain registered with the system for as long as there is at least one
|
||||
owner of the returned Ptr. This allows typefaces registered with createSystemTypefaceFor to
|
||||
be created using just a typeface family name, e.g. in font fallback lists.
|
||||
*/
|
||||
static Ptr createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize);
|
||||
|
||||
/** Attempts to create a font from some raw font file data (e.g. a TTF or OTF file image).
|
||||
The system will take its own internal copy of the data.
|
||||
|
||||
The typeface will remain registered with the system for as long as there is at least one
|
||||
owner of the returned Ptr. This allows typefaces registered with createSystemTypefaceFor to
|
||||
be created using just a typeface family name, e.g. in font fallback lists.
|
||||
*/
|
||||
static Ptr createSystemTypefaceFor (Span<const std::byte>);
|
||||
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
~Typeface() override;
|
||||
|
||||
/** Returns true if this typeface can be used to render the specified font.
|
||||
When called, the font will already have been checked to make sure that its name and
|
||||
style flags match the typeface.
|
||||
*/
|
||||
virtual bool isSuitableForFont (const Font&) const { return true; }
|
||||
|
||||
/** Returns the ascent of the font, as a proportion of its height.
|
||||
The height is considered to always be normalised as 1.0, so this will be a
|
||||
value less that 1.0, indicating the proportion of the font that lies above
|
||||
its baseline.
|
||||
*/
|
||||
virtual float getAscent() const = 0;
|
||||
float getAscent() const;
|
||||
|
||||
/** Returns the descent of the font, as a proportion of its height.
|
||||
The height is considered to always be normalised as 1.0, so this will be a
|
||||
value less that 1.0, indicating the proportion of the font that lies below
|
||||
its baseline.
|
||||
*/
|
||||
virtual float getDescent() const = 0;
|
||||
float getDescent() const;
|
||||
|
||||
/** Returns the value by which you should multiply a JUCE font-height value to
|
||||
convert it to the equivalent point-size.
|
||||
*/
|
||||
virtual float getHeightToPointsFactor() const = 0;
|
||||
float getHeightToPointsFactor() const;
|
||||
|
||||
/** Measures the width of a line of text.
|
||||
/** @deprecated
|
||||
This function has several shortcomings:
|
||||
- The returned value is based on a font with a normalised JUCE height of 1.0,
|
||||
which will normally differ from the value that would be expected for a font
|
||||
with a height of 1 pt.
|
||||
- This function is unsuitable for measuring text with spacing that doesn't
|
||||
scale linearly with point size, which might be the case for fonts that
|
||||
implement optical sizing.
|
||||
- The result is computed assuming that ligatures and other font features will
|
||||
not be used when rendering the string. There's also no way of specifying a
|
||||
language used for the string, which may affect the widths of CJK text.
|
||||
- If the typeface doesn't contain suitable glyphs for all characters in the
|
||||
string, missing characters will be substituted with the notdef/tofu glyph
|
||||
instead of attempting to use a different font that contains suitable
|
||||
glyphs.
|
||||
|
||||
Measures the width of a line of text.
|
||||
The distance returned is based on the font having an normalised height of 1.0.
|
||||
You should never need to call this directly! Use Font::getStringWidth() instead!
|
||||
You should never need to call this!
|
||||
*/
|
||||
virtual float getStringWidth (const String& text) = 0;
|
||||
|
||||
/** Converts a line of text into its glyph numbers and their positions.
|
||||
/** @deprecated
|
||||
This function has several shortcomings:
|
||||
- The returned values are based on a font with a normalised JUCE height of 1.0,
|
||||
which will normally differ from the value that would be expected for a font
|
||||
with a height of 1 pt.
|
||||
- This function is unsuitable for measuring text with spacing that doesn't
|
||||
scale linearly with point size, which might be the case for fonts that
|
||||
implement optical sizing.
|
||||
- Ligatures are deliberately ignored, which will lead to ugly results if the
|
||||
positions are used to paint text using latin scripts, and potentially
|
||||
illegible results for other scripts. There's also no way of specifying a
|
||||
language used for the string, which may affect the rendering of CJK text.
|
||||
- If the typeface doesn't contain suitable glyphs for all characters in the
|
||||
string, missing characters will be substituted with the notdef/tofu glyph
|
||||
instead of attempting to use a different font that contains suitable
|
||||
glyphs.
|
||||
|
||||
Converts a line of text into its glyph numbers and their positions.
|
||||
The distances returned are based on the font having an normalised height of 1.0.
|
||||
You should never need to call this directly! Use Font::getGlyphPositions() instead!
|
||||
You should never need to call this!
|
||||
*/
|
||||
virtual void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) = 0;
|
||||
|
||||
/** Returns the outline for a glyph.
|
||||
The path returned will be normalised to a font height of 1.0.
|
||||
*/
|
||||
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path);
|
||||
|
||||
/** Returns a new EdgeTable that contains the path for the given glyph, with the specified transform applied. */
|
||||
virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight);
|
||||
|
||||
/** Returns true if the typeface uses hinting. */
|
||||
virtual bool isHinted() const { return false; }
|
||||
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight);
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the number of fonts that are cached in memory. */
|
||||
|
|
@ -149,20 +185,29 @@ public:
|
|||
the given size to align vertically with the pixel grid. The path should be an unscaled
|
||||
(i.e. normalised to height of 1.0) path for a glyph.
|
||||
*/
|
||||
[[deprecated]]
|
||||
void applyVerticalHintingTransform (float fontHeight, Path& path);
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
String name, style;
|
||||
/** Returns the glyph index corresponding to the provided codepoint, or nullopt if no
|
||||
such glyph is found.
|
||||
*/
|
||||
std::optional<uint32_t> getNominalGlyphForCodepoint (juce_wchar) const;
|
||||
|
||||
Typeface (const String& name, const String& style) noexcept;
|
||||
/** @internal */
|
||||
class Native;
|
||||
|
||||
static Ptr getFallbackTypeface();
|
||||
/** @internal
|
||||
|
||||
At the moment, this is a way to get at the hb_font_t that backs this typeface.
|
||||
The typeface's hb_font_t has a size of 1 pt (i.e. 1 pt per em).
|
||||
This is only for internal use!
|
||||
*/
|
||||
virtual Native getNativeDetails() const = 0;
|
||||
|
||||
private:
|
||||
struct HintingParams;
|
||||
std::unique_ptr<HintingParams> hintingParams;
|
||||
CriticalSection hintingLock;
|
||||
//==============================================================================
|
||||
String name;
|
||||
String style;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface)
|
||||
};
|
||||
|
|
|
|||
6051
modules/juce_graphics/fonts/juce_TypefaceTestData.cpp
Normal file
6051
modules/juce_graphics/fonts/juce_TypefaceTestData.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -81,6 +81,7 @@
|
|||
#if JUCE_USE_FREETYPE
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_ADVANCES_H
|
||||
#endif
|
||||
|
||||
#undef SIZEOF
|
||||
|
|
@ -103,6 +104,10 @@
|
|||
|
||||
#include <juce_graphics/fonts/harfbuzz/hb-ot.h>
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
#include "fonts/juce_TypefaceTestData.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#include "fonts/juce_FunctionPointerDestructor.h"
|
||||
#include "fonts/juce_LruCache.h"
|
||||
|
|
@ -151,8 +156,6 @@
|
|||
|
||||
#elif JUCE_WINDOWS
|
||||
#include "native/juce_DirectWriteTypeface_windows.cpp"
|
||||
#include "native/juce_DirectWriteTypeLayout_windows.cpp"
|
||||
#include "native/juce_Fonts_windows.cpp"
|
||||
#include "native/juce_IconHelpers_windows.cpp"
|
||||
#if JUCE_DIRECT2D
|
||||
#include "native/juce_Direct2DGraphicsContext_windows.cpp"
|
||||
|
|
|
|||
|
|
@ -121,8 +121,7 @@ public:
|
|||
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 drawGlyph (int glyphNumber, const AffineTransform& transform) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
|
|
@ -131,22 +130,7 @@ private:
|
|||
detail::ColorSpacePtr rgbColourSpace, greyColourSpace;
|
||||
mutable std::optional<Rectangle<int>> lastClipRect;
|
||||
|
||||
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 = {};
|
||||
};
|
||||
|
||||
struct SavedState;
|
||||
std::unique_ptr<SavedState> state;
|
||||
OwnedArray<SavedState> stateStack;
|
||||
|
||||
|
|
|
|||
|
|
@ -192,6 +192,33 @@ struct ScopedCGContextState
|
|||
CGContextRef context;
|
||||
};
|
||||
|
||||
struct CoreGraphicsContext::SavedState
|
||||
{
|
||||
SavedState() = default;
|
||||
|
||||
SavedState (const SavedState& other)
|
||||
: fillType (other.fillType), font (other.font),
|
||||
textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix),
|
||||
gradient (other.gradient.get() != nullptr ? CGGradientRetain (other.gradient.get()) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~SavedState() = default;
|
||||
|
||||
void setFill (const FillType& newFill)
|
||||
{
|
||||
fillType = newFill;
|
||||
gradient = nullptr;
|
||||
}
|
||||
|
||||
FillType fillType;
|
||||
Font font { 1.0f };
|
||||
CFUniquePtr<CTFontRef> fontRef{};
|
||||
CGAffineTransform textMatrix = CGAffineTransformIdentity,
|
||||
inverseTextMatrix = CGAffineTransformIdentity;
|
||||
detail::GradientPtr gradient = {};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, float h)
|
||||
: context (c),
|
||||
|
|
@ -630,22 +657,19 @@ void CoreGraphicsContext::setFont (const Font& newFont)
|
|||
{
|
||||
if (state->font != newFont)
|
||||
{
|
||||
state->fontRef = nullptr;
|
||||
state->font = newFont;
|
||||
state->fontRef = nullptr;
|
||||
|
||||
auto typeface = state->font.getTypefacePtr();
|
||||
const auto hbFont = state->font.getNativeDetails().font;
|
||||
|
||||
if (auto osxTypeface = dynamic_cast<OSXTypeface*> (typeface.get()))
|
||||
{
|
||||
state->fontRef = osxTypeface->fontRef;
|
||||
CGContextSetFont (context.get(), state->fontRef);
|
||||
CGContextSetFontSize (context.get(), state->font.getHeight() * osxTypeface->fontHeightToPointsFactor);
|
||||
state->fontRef.reset (hb_coretext_font_get_ct_font (hbFont.get()));
|
||||
CFRetain (state->fontRef.get());
|
||||
|
||||
state->textMatrix = osxTypeface->renderingTransform;
|
||||
state->textMatrix.a *= state->font.getHorizontalScale();
|
||||
CGContextSetTextMatrix (context.get(), state->textMatrix);
|
||||
state->inverseTextMatrix = CGAffineTransformInvert (state->textMatrix);
|
||||
}
|
||||
const auto slant = hb_font_get_synthetic_slant (hbFont.get());
|
||||
|
||||
state->textMatrix = CGAffineTransformMake (state->font.getHorizontalScale(), 0, slant * state->font.getHorizontalScale(), 1.0f, 0, 0);
|
||||
CGContextSetTextMatrix (context.get(), state->textMatrix);
|
||||
state->inverseTextMatrix = CGAffineTransformInvert (state->textMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -658,72 +682,27 @@ void CoreGraphicsContext::drawGlyph (int glyphNumber, const AffineTransform& tra
|
|||
{
|
||||
if (state->fontRef != nullptr && state->fillType.isColour())
|
||||
{
|
||||
auto cgTransformIsOnlyTranslation = [] (CGAffineTransform t)
|
||||
{
|
||||
return t.a == 1.0f && t.d == 1.0f && t.b == 0.0f && t.c == 0.0f;
|
||||
};
|
||||
const CGGlyph glyphs[] { (CGGlyph) glyphNumber };
|
||||
|
||||
if (transform.isOnlyTranslation() && cgTransformIsOnlyTranslation (state->inverseTextMatrix))
|
||||
{
|
||||
auto x = transform.mat02 + state->inverseTextMatrix.tx;
|
||||
auto y = transform.mat12 + state->inverseTextMatrix.ty;
|
||||
ScopedCGContextState scopedState (context.get());
|
||||
|
||||
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };
|
||||
CGPoint positions[1] = { { x, flipHeight - roundToInt (y) } };
|
||||
CGContextShowGlyphsAtPositions (context.get(), glyphs, positions, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScopedCGContextState scopedState (context.get());
|
||||
flip();
|
||||
applyTransform (AffineTransform::scale (1.0f, -1.0f).followedBy (transform));
|
||||
|
||||
flip();
|
||||
applyTransform (transform);
|
||||
CGContextConcatCTM (context.get(), state->inverseTextMatrix);
|
||||
auto cgTransform = state->textMatrix;
|
||||
cgTransform.d = -cgTransform.d;
|
||||
CGContextConcatCTM (context.get(), cgTransform);
|
||||
|
||||
CGGlyph glyphs[1] = { (CGGlyph) glyphNumber };
|
||||
CGPoint positions[1] = { { 0.0f, 0.0f } };
|
||||
CGContextShowGlyphsAtPositions (context.get(), glyphs, positions, 1);
|
||||
}
|
||||
const CGPoint positions[] { { 0.0f, 0.0f } };
|
||||
CTFontDrawGlyphs (state->fontRef.get(), glyphs, positions, std::size (glyphs), context.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
Path p;
|
||||
auto& f = state->font;
|
||||
f.getTypefacePtr()->getOutlineForGlyph (glyphNumber, p);
|
||||
const auto scale = f.getHeight();
|
||||
|
||||
fillPath (p, AffineTransform::scale (f.getHeight() * f.getHorizontalScale(), f.getHeight())
|
||||
.followedBy (transform));
|
||||
fillPath (p, AffineTransform::scale (scale * f.getHorizontalScale(), scale).followedBy (transform));
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle<float>& area)
|
||||
{
|
||||
return CoreTextTypeLayout::drawToCGContext (text, area, context.get(), (float) flipHeight);
|
||||
}
|
||||
|
||||
CoreGraphicsContext::SavedState::SavedState()
|
||||
: font (1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
CoreGraphicsContext::SavedState::SavedState (const SavedState& other)
|
||||
: fillType (other.fillType), font (other.font), fontRef (other.fontRef),
|
||||
textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix),
|
||||
gradient (other.gradient.get() != nullptr ? CGGradientRetain (other.gradient.get()) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CoreGraphicsContext::SavedState::~SavedState() = default;
|
||||
|
||||
void CoreGraphicsContext::SavedState::setFill (const FillType& newFill)
|
||||
{
|
||||
fillType = newFill;
|
||||
gradient = nullptr;
|
||||
}
|
||||
|
||||
static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace)
|
||||
{
|
||||
auto numColours = g.getNumColours();
|
||||
|
|
|
|||
|
|
@ -773,17 +773,4 @@ void Direct2DLowLevelGraphicsContext::drawGlyph (int glyphNumber, const AffineTr
|
|||
pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
bool Direct2DLowLevelGraphicsContext::drawTextLayout (const AttributedString& text, const Rectangle<float>& area)
|
||||
{
|
||||
pimpl->renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
|
||||
DirectWriteTypeLayout::drawToD2DContext (text, area,
|
||||
*(pimpl->renderingTarget),
|
||||
*(pimpl->factories->directWriteFactory),
|
||||
*(pimpl->factories->systemFonts));
|
||||
|
||||
pimpl->renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ public:
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -35,50 +35,331 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
namespace
|
||||
static String getLocalisedName (IDWriteLocalizedStrings* names)
|
||||
{
|
||||
static String getLocalisedName (IDWriteLocalizedStrings* names)
|
||||
{
|
||||
jassert (names != nullptr);
|
||||
jassert (names != nullptr);
|
||||
|
||||
uint32 index = 0;
|
||||
BOOL exists = false;
|
||||
[[maybe_unused]] auto hr = names->FindLocaleName (L"en-us", &index, &exists);
|
||||
uint32 index = 0;
|
||||
BOOL exists = false;
|
||||
[[maybe_unused]] auto hr = names->FindLocaleName (L"en-us", &index, &exists);
|
||||
|
||||
if (! exists)
|
||||
index = 0;
|
||||
if (! exists)
|
||||
index = 0;
|
||||
|
||||
uint32 length = 0;
|
||||
hr = names->GetStringLength (index, &length);
|
||||
uint32 length = 0;
|
||||
hr = names->GetStringLength (index, &length);
|
||||
|
||||
HeapBlock<wchar_t> name (length + 1);
|
||||
hr = names->GetString (index, name, length + 1);
|
||||
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;
|
||||
[[maybe_unused]] auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
|
||||
jassert (SUCCEEDED (hr));
|
||||
return getLocalisedName (familyNames);
|
||||
}
|
||||
|
||||
static String getFontFaceName (IDWriteFont* font)
|
||||
{
|
||||
jassert (font != nullptr);
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
[[maybe_unused]] auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
|
||||
jassert (SUCCEEDED (hr));
|
||||
return getLocalisedName (faceNames);
|
||||
}
|
||||
|
||||
inline Point<float> convertPoint (D2D1_POINT_2F p) noexcept { return Point<float> ((float) p.x, (float) p.y); }
|
||||
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);
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
static StringArray stringArrayFromRange (Range&& range)
|
||||
{
|
||||
StringArray result;
|
||||
|
||||
for (const auto& item : range)
|
||||
result.add (item);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class AggregateFontCollection
|
||||
{
|
||||
public:
|
||||
explicit AggregateFontCollection (ComSmartPtr<IDWriteFontCollection> baseCollection)
|
||||
: collections { std::move (baseCollection) } {}
|
||||
|
||||
StringArray findAllTypefaceNames()
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
std::set<String> strings;
|
||||
|
||||
for (const auto& collection : collections)
|
||||
{
|
||||
const auto count = collection->GetFontFamilyCount();
|
||||
|
||||
for (auto i = decltype (count){}; i < count; ++i)
|
||||
{
|
||||
ComSmartPtr<IDWriteFontFamily> family;
|
||||
|
||||
if (FAILED (collection->GetFontFamily (i, family.resetAndGetPointerAddress())) || family == nullptr)
|
||||
continue;
|
||||
|
||||
strings.insert (getFontFamilyName (family));
|
||||
}
|
||||
}
|
||||
|
||||
return stringArrayFromRange (strings);
|
||||
}
|
||||
|
||||
StringArray findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
for (const auto& collection : collections)
|
||||
{
|
||||
BOOL fontFound = false;
|
||||
uint32 fontIndex = 0;
|
||||
|
||||
if (FAILED (collection->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound)) || ! fontFound)
|
||||
continue;
|
||||
|
||||
ComSmartPtr<IDWriteFontFamily> fontFamily;
|
||||
|
||||
if (FAILED (collection->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress())) || fontFamily == nullptr)
|
||||
continue;
|
||||
|
||||
// Get the font faces
|
||||
const auto fontFacesCount = fontFamily->GetFontCount();
|
||||
std::set<String> results;
|
||||
|
||||
for (uint32 i = 0; i < fontFacesCount; ++i)
|
||||
{
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
|
||||
if (FAILED (fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress())) || dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
|
||||
continue;
|
||||
|
||||
results.insert (getFontFaceName (dwFont));
|
||||
}
|
||||
|
||||
return stringArrayFromRange (results);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ComSmartPtr<IDWriteFontFamily> getFamilyByName (const wchar_t* name)
|
||||
{
|
||||
for (const auto& collection : collections)
|
||||
{
|
||||
const auto fontIndex = [&]
|
||||
{
|
||||
BOOL found = false;
|
||||
UINT32 index = 0;
|
||||
|
||||
return (SUCCEEDED (collection->FindFamilyName (name, &index, &found)) && found)
|
||||
? index
|
||||
: (UINT32) -1;
|
||||
}();
|
||||
|
||||
if (fontIndex == (UINT32) -1)
|
||||
continue;
|
||||
|
||||
ComSmartPtr<IDWriteFontFamily> family;
|
||||
|
||||
if (FAILED (collection->GetFontFamily (fontIndex, family.resetAndGetPointerAddress())) || family == nullptr)
|
||||
continue;
|
||||
|
||||
return family;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void addCollection (ComSmartPtr<IDWriteFontCollection> collection)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
collections.push_back (std::move (collection));
|
||||
}
|
||||
|
||||
void removeCollection (ComSmartPtr<IDWriteFontCollection> collection)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
const auto iter = std::find (collections.begin(), collections.end(), collection);
|
||||
|
||||
if (iter != collections.end())
|
||||
collections.erase (iter);
|
||||
}
|
||||
|
||||
struct MapResult
|
||||
{
|
||||
ComSmartPtr<IDWriteFont> font;
|
||||
UINT32 length{};
|
||||
float scale{};
|
||||
};
|
||||
|
||||
/* Tries matching against each collection in turn.
|
||||
If any collection is able to match the entire string, then uses the appropriate font
|
||||
from that collection.
|
||||
Otherwise, returns the font that is able to match the longest sequence of characters,
|
||||
preferring user-provided fonts.
|
||||
*/
|
||||
MapResult mapCharacters (IDWriteFontFallback* fallback,
|
||||
IDWriteTextAnalysisSource* analysisSource,
|
||||
UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
wchar_t const* baseFamilyName,
|
||||
DWRITE_FONT_WEIGHT baseWeight,
|
||||
DWRITE_FONT_STYLE baseStyle,
|
||||
DWRITE_FONT_STRETCH baseStretch) noexcept
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
// For reasons I don't understand, the system may pick better substitutions when passing
|
||||
// nullptr, instead of the system collection, as the "default collection to use".
|
||||
auto collectionsToCheck = collections;
|
||||
collectionsToCheck.insert (collectionsToCheck.begin(), nullptr);
|
||||
|
||||
MapResult bestMatch;
|
||||
for (const auto& collection : collectionsToCheck)
|
||||
{
|
||||
MapResult result;
|
||||
const auto status = fallback->MapCharacters (analysisSource,
|
||||
textPosition,
|
||||
textLength,
|
||||
collection,
|
||||
baseFamilyName,
|
||||
baseWeight,
|
||||
baseStyle,
|
||||
baseStretch,
|
||||
&result.length,
|
||||
result.font.resetAndGetPointerAddress(),
|
||||
&result.scale);
|
||||
|
||||
if (FAILED (status) || result.font == nullptr)
|
||||
continue;
|
||||
|
||||
if (result.length == textLength)
|
||||
return result;
|
||||
|
||||
if (result.length >= bestMatch.length)
|
||||
bestMatch = result;
|
||||
}
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ComSmartPtr<IDWriteFontCollection>> collections;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
class MemoryFontFileStream final : public ComBaseClassHelper<IDWriteFontFileStream>
|
||||
{
|
||||
public:
|
||||
explicit MemoryFontFileStream (MemoryBlock d) : rawData (std::move (d)) {}
|
||||
|
||||
JUCE_COMRESULT GetFileSize (UINT64* fileSize) noexcept override
|
||||
{
|
||||
*fileSize = rawData.getSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
JUCE_COMRESULT GetLastWriteTime (UINT64* lastWriteTime) noexcept override
|
||||
{
|
||||
*lastWriteTime = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
JUCE_COMRESULT ReadFileFragment (const void** fragmentStart,
|
||||
UINT64 fileOffset,
|
||||
UINT64 fragmentSize,
|
||||
void** fragmentContext) noexcept override
|
||||
{
|
||||
if (fileOffset + fragmentSize > rawData.getSize())
|
||||
{
|
||||
*fragmentStart = nullptr;
|
||||
*fragmentContext = nullptr;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*fragmentStart = addBytesToPointer (rawData.getData(), fileOffset);
|
||||
*fragmentContext = this;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void WINAPI ReleaseFileFragment (void*) noexcept override {}
|
||||
|
||||
private:
|
||||
MemoryBlock rawData;
|
||||
};
|
||||
|
||||
class MemoryFontFileLoader final : public ComBaseClassHelper<IDWriteFontFileLoader>
|
||||
{
|
||||
public:
|
||||
HRESULT WINAPI CreateStreamFromKey (const void* fontFileReferenceKey,
|
||||
UINT32 keySize,
|
||||
IDWriteFontFileStream** fontFileStream) noexcept override
|
||||
{
|
||||
*fontFileStream = new MemoryFontFileStream { MemoryBlock { fontFileReferenceKey, keySize } };
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class FontFileEnumerator final : public ComBaseClassHelper<IDWriteFontFileEnumerator>
|
||||
{
|
||||
public:
|
||||
FontFileEnumerator (IDWriteFactory& factoryIn, IDWriteFontFileLoader& loaderIn, MemoryBlock keyIn)
|
||||
: factory (factoryIn), loader (loaderIn), key (keyIn) {}
|
||||
|
||||
HRESULT WINAPI GetCurrentFontFile (IDWriteFontFile** fontFile) noexcept override
|
||||
{
|
||||
*fontFile = nullptr;
|
||||
|
||||
if (! isPositiveAndBelow (rawDataIndex, 1))
|
||||
return E_FAIL;
|
||||
|
||||
return factory.CreateCustomFontFileReference (key.getData(),
|
||||
(UINT32) key.getSize(),
|
||||
&loader,
|
||||
fontFile);
|
||||
}
|
||||
|
||||
HRESULT WINAPI MoveNext (BOOL* hasCurrentFile) noexcept override
|
||||
{
|
||||
++rawDataIndex;
|
||||
*hasCurrentFile = rawDataIndex < 1 ? TRUE : FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IDWriteFactory& factory;
|
||||
IDWriteFontFileLoader& loader;
|
||||
MemoryBlock key;
|
||||
size_t rawDataIndex = std::numeric_limits<size_t>::max();
|
||||
};
|
||||
|
||||
class DirectWriteCustomFontCollectionLoader final : public ComBaseClassHelper<IDWriteFontCollectionLoader>
|
||||
{
|
||||
public:
|
||||
explicit DirectWriteCustomFontCollectionLoader (IDWriteFontFileLoader& loaderIn)
|
||||
: loader (loaderIn) {}
|
||||
|
||||
HRESULT WINAPI CreateEnumeratorFromKey (IDWriteFactory* factory,
|
||||
const void* collectionKey,
|
||||
UINT32 collectionKeySize,
|
||||
IDWriteFontFileEnumerator** fontFileEnumerator) noexcept override
|
||||
{
|
||||
*fontFileEnumerator = new FontFileEnumerator { *factory, loader, MemoryBlock { collectionKey, collectionKeySize } };
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
IDWriteFontFileLoader& loader;
|
||||
};
|
||||
|
||||
class Direct2DFactories
|
||||
{
|
||||
public:
|
||||
|
|
@ -106,13 +387,29 @@ public:
|
|||
JUCE_LOAD_WINAPI_FUNCTION (directWriteDll, DWriteCreateFactory, dWriteCreateFactory,
|
||||
HRESULT, (DWRITE_FACTORY_TYPE, REFIID, IUnknown**))
|
||||
|
||||
if (dWriteCreateFactory != nullptr)
|
||||
if (dWriteCreateFactory == nullptr)
|
||||
return;
|
||||
|
||||
for (const auto uuid : { __uuidof (IDWriteFactory3), __uuidof (IDWriteFactory2), __uuidof (IDWriteFactory) })
|
||||
{
|
||||
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, uuid,
|
||||
(IUnknown**) directWriteFactory.resetAndGetPointerAddress());
|
||||
|
||||
if (directWriteFactory != nullptr)
|
||||
directWriteFactory->GetSystemFontCollection (systemFonts.resetAndGetPointerAddress());
|
||||
break;
|
||||
}
|
||||
|
||||
if (directWriteFactory != nullptr)
|
||||
{
|
||||
directWriteFactory->RegisterFontFileLoader (fileLoader);
|
||||
directWriteFactory->RegisterFontCollectionLoader (collectionLoader);
|
||||
|
||||
ComSmartPtr<IDWriteFontCollection> collection;
|
||||
|
||||
if (SUCCEEDED (directWriteFactory->GetSystemFontCollection (collection.resetAndGetPointerAddress(), FALSE)) && collection != nullptr)
|
||||
fonts.emplace (collection);
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
if (d2dFactory != nullptr)
|
||||
|
|
@ -133,212 +430,379 @@ public:
|
|||
|
||||
~Direct2DFactories()
|
||||
{
|
||||
d2dFactory = nullptr; // (need to make sure these are released before deleting the DynamicLibrary objects)
|
||||
directWriteFactory = nullptr;
|
||||
systemFonts = nullptr;
|
||||
directWriteRenderTarget = nullptr;
|
||||
if (directWriteFactory != nullptr)
|
||||
{
|
||||
directWriteFactory->UnregisterFontCollectionLoader (collectionLoader);
|
||||
directWriteFactory->UnregisterFontFileLoader (fileLoader);
|
||||
}
|
||||
}
|
||||
|
||||
ComSmartPtr<ID2D1Factory> d2dFactory;
|
||||
ComSmartPtr<IDWriteFactory> directWriteFactory;
|
||||
ComSmartPtr<IDWriteFontCollection> systemFonts;
|
||||
ComSmartPtr<ID2D1DCRenderTarget> directWriteRenderTarget;
|
||||
[[nodiscard]] ComSmartPtr<ID2D1Factory> getD2D1Factory() const { return d2dFactory; }
|
||||
[[nodiscard]] ComSmartPtr<IDWriteFactory> getDWriteFactory() const { return directWriteFactory; }
|
||||
[[nodiscard]] ComSmartPtr<ID2D1DCRenderTarget> getD2D1DCRenderTarget() const { return directWriteRenderTarget; }
|
||||
[[nodiscard]] AggregateFontCollection& getFonts() { jassert (fonts.has_value()); return *fonts; }
|
||||
[[nodiscard]] ComSmartPtr<IDWriteFontCollectionLoader> getCollectionLoader() const { return collectionLoader; }
|
||||
|
||||
private:
|
||||
DynamicLibrary direct2dDll, directWriteDll;
|
||||
ComSmartPtr<ID2D1Factory> d2dFactory;
|
||||
ComSmartPtr<IDWriteFactory> directWriteFactory;
|
||||
ComSmartPtr<ID2D1DCRenderTarget> directWriteRenderTarget;
|
||||
std::optional<AggregateFontCollection> fonts;
|
||||
|
||||
ComSmartPtr<IDWriteFontFileLoader> fileLoader = becomeComSmartPtrOwner (new MemoryFontFileLoader);
|
||||
ComSmartPtr<IDWriteFontCollectionLoader> collectionLoader = becomeComSmartPtrOwner (new DirectWriteCustomFontCollectionLoader (*fileLoader));
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
return factories->getFonts().findAllTypefaceNames();
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
if (FontStyleHelpers::isPlaceholderFamilyName (family))
|
||||
return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family));
|
||||
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
return factories->getFonts().findAllTypefaceStyles (family);
|
||||
}
|
||||
|
||||
extern bool juce_isRunningInWine();
|
||||
|
||||
class WindowsDirectWriteTypeface final : public Typeface
|
||||
{
|
||||
public:
|
||||
WindowsDirectWriteTypeface (const Font& font, IDWriteFontCollection* fontCollection)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle())
|
||||
~WindowsDirectWriteTypeface() override
|
||||
{
|
||||
jassert (fontCollection != nullptr);
|
||||
|
||||
uint32 fontIndex = 0;
|
||||
[[maybe_unused]] 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);
|
||||
}
|
||||
if (collection != nullptr)
|
||||
factories->getFonts().removeCollection (collection);
|
||||
}
|
||||
|
||||
bool loadedOk() const noexcept { return dwFontFace != nullptr; }
|
||||
BOOL isFontFound() const noexcept { return fontFound; }
|
||||
|
||||
float getAscent() const override { return ascent; }
|
||||
float getDescent() const override { return 1.0f - ascent; }
|
||||
float getHeightToPointsFactor() const override { return heightToPointsFactor; }
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
auto textUTF32 = text.toUTF32();
|
||||
auto len = textUTF32.length();
|
||||
auto utf32 = text.toUTF32();
|
||||
auto numChars = utf32.length();
|
||||
std::vector<UINT16> results (numChars);
|
||||
|
||||
HeapBlock<UINT16> glyphIndices (len);
|
||||
dwFontFace->GetGlyphIndices (textUTF32, (UINT32) len, glyphIndices);
|
||||
|
||||
HeapBlock<DWRITE_GLYPH_METRICS> dwGlyphMetrics (len);
|
||||
dwFontFace->GetDesignGlyphMetrics (glyphIndices, (UINT32) len, dwGlyphMetrics, false);
|
||||
if (FAILED (dwFontFace->GetGlyphIndices (utf32, (UINT32) numChars, results.data())))
|
||||
return {};
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
for (size_t i = 0; i < numChars; ++i)
|
||||
x += getKerning (results[i], (i + 1) < numChars ? results[i + 1] : -1);
|
||||
|
||||
return x * unitsToHeightScaleFactor;
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
return x * heightToPoints;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets) override
|
||||
{
|
||||
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);
|
||||
|
||||
auto utf32 = text.toUTF32();
|
||||
auto numChars = utf32.length();
|
||||
std::vector<UINT16> results (numChars);
|
||||
float x = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
|
||||
if (SUCCEEDED (dwFontFace->GetGlyphIndices (utf32, (UINT32) numChars, results.data())))
|
||||
{
|
||||
x += (float) dwGlyphMetrics[i].advanceWidth / (float) designUnitsPerEm;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
resultGlyphs.add (glyphIndices[i]);
|
||||
resultGlyphs.ensureStorageAllocated ((int) numChars);
|
||||
xOffsets.ensureStorageAllocated ((int) numChars + 1);
|
||||
|
||||
for (size_t i = 0; i < numChars; ++i)
|
||||
{
|
||||
resultGlyphs.add (results[i]);
|
||||
xOffsets.add (x * heightToPoints);
|
||||
x += getKerning (results[i], (i + 1) < numChars ? results[i + 1] : -1);
|
||||
}
|
||||
}
|
||||
|
||||
xOffsets.add (x * heightToPoints);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path) override
|
||||
static Typeface::Ptr from (const Font& f)
|
||||
{
|
||||
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
|
||||
auto glyphIndex = (UINT16) glyphNumber;
|
||||
auto pathGeometrySink = becomeComSmartPtrOwner (new PathGeometrySink());
|
||||
const auto name = f.getTypefaceName();
|
||||
const auto style = f.getTypefaceStyle();
|
||||
|
||||
dwFontFace->GetGlyphRunOutline (1024.0f, &glyphIndex, nullptr, nullptr,
|
||||
1, false, false, pathGeometrySink);
|
||||
path = pathGeometrySink->path;
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
const auto family = factories->getFonts().getFamilyByName (name.toWideCharPointer());
|
||||
|
||||
if (! pathTransform.isIdentity())
|
||||
path.applyTransform (pathTransform);
|
||||
if (family == nullptr)
|
||||
return {};
|
||||
|
||||
return true;
|
||||
const auto weight = f.isBold() ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL;
|
||||
const auto italic = f.isItalic() ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
|
||||
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
|
||||
if (FAILED (family->GetFirstMatchingFont (weight, DWRITE_FONT_STRETCH_NORMAL, italic, dwFont.resetAndGetPointerAddress())) || dwFont == nullptr)
|
||||
return {};
|
||||
|
||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||
|
||||
if (FAILED (dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress())) || dwFontFace == nullptr)
|
||||
return {};
|
||||
|
||||
const HbFace hbFace { hb_directwrite_face_create (dwFontFace) };
|
||||
HbFont hbFont { hb_font_create (hbFace.get()) };
|
||||
|
||||
FontStyleHelpers::initSynthetics (hbFont.get(), f);
|
||||
return new WindowsDirectWriteTypeface (name, style, dwFont, dwFontFace, std::move (hbFont));
|
||||
}
|
||||
|
||||
IDWriteFontFace* getIDWriteFontFace() const noexcept { return dwFontFace; }
|
||||
static Typeface::Ptr from (Span<const std::byte> blob)
|
||||
{
|
||||
return from (MemoryBlock { blob.data(), blob.size() });
|
||||
}
|
||||
|
||||
float getUnitsToHeightScaleFactor() const noexcept { return unitsToHeightScaleFactor; }
|
||||
Native getNativeDetails() const override
|
||||
{
|
||||
return Native { hbFont.get() };
|
||||
}
|
||||
|
||||
IDWriteFontFace* getIDWriteFontFace() const { return dwFontFace; }
|
||||
|
||||
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 final : public ComBaseClassHelper<IDWriteGeometrySink>
|
||||
float getKerning (int glyph1, int glyph2) const
|
||||
{
|
||||
PathGeometrySink() = default;
|
||||
const auto face = dwFontFace.getInterface<IDWriteFontFace1>();
|
||||
|
||||
void STDMETHODCALLTYPE AddBeziers (const D2D1_BEZIER_SEGMENT* beziers, UINT beziersCount) noexcept override
|
||||
const UINT16 glyphs[] { (UINT16) glyph1, (UINT16) glyph2 };
|
||||
INT32 advances [std::size (glyphs)]{};
|
||||
|
||||
if (FAILED (face->GetDesignGlyphAdvances ((UINT32) std::size (glyphs), std::data (glyphs), std::data (advances))))
|
||||
return {};
|
||||
|
||||
DWRITE_FONT_METRICS metrics{};
|
||||
face->GetMetrics (&metrics);
|
||||
|
||||
// TODO(reuk) incorrect
|
||||
return (float) advances[0] / (float) metrics.designUnitsPerEm;
|
||||
}
|
||||
|
||||
static UINT32 numUtf16Words (const CharPointer_UTF16& str)
|
||||
{
|
||||
return (UINT32) (str.findTerminatingNull().getAddress() - str.getAddress());
|
||||
}
|
||||
|
||||
class AnalysisSource final : public ComBaseClassHelper<IDWriteTextAnalysisSource>
|
||||
{
|
||||
public:
|
||||
AnalysisSource (String cIn, String langIn)
|
||||
: character (cIn), language (langIn) {}
|
||||
|
||||
~AnalysisSource() override = default;
|
||||
|
||||
JUCE_COMCALL GetLocaleName (UINT32, UINT32*, const WCHAR** localeName) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < beziersCount; ++i)
|
||||
path.cubicTo (convertPoint (beziers[i].point1),
|
||||
convertPoint (beziers[i].point2),
|
||||
convertPoint (beziers[i].point3));
|
||||
*localeName = language.isNotEmpty() ? language.toWideCharPointer() : nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE AddLines (const D2D1_POINT_2F* points, UINT pointsCount) noexcept override
|
||||
JUCE_COMCALL GetNumberSubstitution (UINT32, UINT32*, IDWriteNumberSubstitution** substitution) noexcept override
|
||||
{
|
||||
for (UINT i = 0; i < pointsCount; ++i)
|
||||
path.lineTo (convertPoint (points[i]));
|
||||
*substitution = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE BeginFigure (D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) noexcept override
|
||||
DWRITE_READING_DIRECTION STDMETHODCALLTYPE GetParagraphReadingDirection() noexcept override
|
||||
{
|
||||
path.startNewSubPath (convertPoint (startPoint));
|
||||
return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE EndFigure (D2D1_FIGURE_END figureEnd) noexcept override
|
||||
JUCE_COMCALL GetTextAtPosition (UINT32 textPosition, const WCHAR** textString, UINT32* textLength) noexcept override
|
||||
{
|
||||
if (figureEnd == D2D1_FIGURE_END_CLOSED)
|
||||
path.closeSubPath();
|
||||
if (textPosition == 0)
|
||||
{
|
||||
const auto utf16 = character.toUTF16();
|
||||
*textString = utf16.getAddress();
|
||||
*textLength = numUtf16Words (utf16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't expect this to be hit. If you see this, alert the JUCE team!
|
||||
jassertfalse;
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SetFillMode (D2D1_FILL_MODE fillMode) noexcept override
|
||||
JUCE_COMCALL GetTextBeforePosition (UINT32, const WCHAR** textString, UINT32* textLength) noexcept override
|
||||
{
|
||||
path.setUsingNonZeroWinding (fillMode == D2D1_FILL_MODE_WINDING);
|
||||
// We don't expect this to be hit. If you see this, alert the JUCE team!
|
||||
jassertfalse;
|
||||
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
private:
|
||||
String character;
|
||||
String language;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDirectWriteTypeface)
|
||||
static Typeface::Ptr from (MemoryBlock blob)
|
||||
{
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
|
||||
const auto dwFactory = factories->getDWriteFactory();
|
||||
|
||||
if (dwFactory == nullptr)
|
||||
return {};
|
||||
|
||||
ComSmartPtr<IDWriteFontCollection> customFontCollection;
|
||||
|
||||
if (FAILED (dwFactory->CreateCustomFontCollection (factories->getCollectionLoader(),
|
||||
blob.getData(),
|
||||
(UINT32) blob.getSize(),
|
||||
customFontCollection.resetAndGetPointerAddress())))
|
||||
return {};
|
||||
|
||||
if (customFontCollection == nullptr)
|
||||
return {};
|
||||
|
||||
ComSmartPtr<IDWriteFontFamily> fontFamily;
|
||||
|
||||
if (FAILED (customFontCollection->GetFontFamily (0, fontFamily.resetAndGetPointerAddress())) || fontFamily == nullptr)
|
||||
return {};
|
||||
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
|
||||
if (FAILED (fontFamily->GetFont (0, dwFont.resetAndGetPointerAddress())) || dwFont == nullptr)
|
||||
return {};
|
||||
|
||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||
|
||||
if (FAILED (dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress())) || dwFontFace == nullptr)
|
||||
return {};
|
||||
|
||||
const auto name = getLocalisedFamilyName (*fontFamily);
|
||||
const auto style = getLocalisedStyle (*dwFont);
|
||||
|
||||
const HbFace hbFace { hb_directwrite_face_create (dwFontFace) };
|
||||
|
||||
return new WindowsDirectWriteTypeface (name, style, dwFont, dwFontFace, HbFont { hb_font_create (hbFace.get()) }, std::move (customFontCollection));
|
||||
}
|
||||
|
||||
static String getLocalisedFamilyName (IDWriteFont& font)
|
||||
{
|
||||
ComSmartPtr<IDWriteFontFamily> family;
|
||||
if (FAILED (font.GetFontFamily (family.resetAndGetPointerAddress())) || family == nullptr)
|
||||
return {};
|
||||
|
||||
return getLocalisedFamilyName (*family);
|
||||
}
|
||||
|
||||
static String getLocalisedFamilyName (IDWriteFontFamily& fontFamily)
|
||||
{
|
||||
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
|
||||
if (FAILED (fontFamily.GetFamilyNames (familyNames.resetAndGetPointerAddress())) || familyNames == nullptr)
|
||||
return {};
|
||||
|
||||
return getLocalisedName (familyNames);
|
||||
}
|
||||
|
||||
static String getLocalisedStyle (IDWriteFont& font)
|
||||
{
|
||||
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
|
||||
if (FAILED (font.GetFaceNames (faceNames.resetAndGetPointerAddress())) || faceNames == nullptr)
|
||||
return {};
|
||||
|
||||
return getLocalisedName (faceNames);
|
||||
}
|
||||
|
||||
WindowsDirectWriteTypeface (const String& name,
|
||||
const String& style,
|
||||
ComSmartPtr<IDWriteFont> font,
|
||||
ComSmartPtr<IDWriteFontFace> face,
|
||||
HbFont hbFontIn,
|
||||
ComSmartPtr<IDWriteFontCollection> collectionIn = nullptr)
|
||||
: Typeface (name, style),
|
||||
collection (std::move (collectionIn)),
|
||||
dwFont (font),
|
||||
dwFontFace (face),
|
||||
hbFont (std::move (hbFontIn))
|
||||
{
|
||||
if (collection != nullptr)
|
||||
factories->getFonts().addCollection (collection);
|
||||
}
|
||||
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
ComSmartPtr<IDWriteFontCollection> collection;
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||
HbFont hbFont;
|
||||
};
|
||||
|
||||
#endif
|
||||
struct DefaultFontNames
|
||||
{
|
||||
DefaultFontNames()
|
||||
{
|
||||
if (juce_isRunningInWine())
|
||||
{
|
||||
// If we're running in Wine, then use fonts that might be available on Linux.
|
||||
defaultSans = "Bitstream Vera Sans";
|
||||
defaultSerif = "Bitstream Vera Serif";
|
||||
defaultFixed = "Bitstream Vera Sans Mono";
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultSans = "Verdana";
|
||||
defaultSerif = "Times New Roman";
|
||||
defaultFixed = "Lucida Console";
|
||||
defaultFallback = "Tahoma"; // (contains plenty of unicode characters)
|
||||
}
|
||||
}
|
||||
|
||||
String defaultSans, defaultSerif, defaultFixed, defaultFallback;
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static DefaultFontNames defaultNames;
|
||||
|
||||
Font newFont (font);
|
||||
auto faceName = font.getTypefaceName();
|
||||
|
||||
if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans);
|
||||
else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif);
|
||||
else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed);
|
||||
|
||||
if (font.getTypefaceStyle() == getDefaultStyle())
|
||||
newFont.setTypefaceStyle ("Regular");
|
||||
|
||||
return Typeface::createSystemTypefaceFor (newFont);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return WindowsDirectWriteTypeface::from (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
|
||||
{
|
||||
return WindowsDirectWriteTypeface::from (data);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File&)
|
||||
{
|
||||
// TODO(reuk)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool TextLayout::createNativeLayout ([[maybe_unused]] const AttributedString& text)
|
||||
{
|
||||
// TODO(reuk) Currently unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -35,72 +35,23 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
struct DefaultFontNames
|
||||
{
|
||||
DefaultFontNames()
|
||||
: defaultSans ("sans"),
|
||||
defaultSerif ("serif"),
|
||||
defaultFixed ("monospace"),
|
||||
defaultFallback ("sans")
|
||||
{
|
||||
}
|
||||
|
||||
String getRealFontName (const String& faceName) const
|
||||
{
|
||||
if (faceName == Font::getDefaultSansSerifFontName()) return defaultSans;
|
||||
if (faceName == Font::getDefaultSerifFontName()) return defaultSerif;
|
||||
if (faceName == Font::getDefaultMonospacedFontName()) return defaultFixed;
|
||||
|
||||
return faceName;
|
||||
}
|
||||
|
||||
String defaultSans, defaultSerif, defaultFixed, defaultFallback;
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static DefaultFontNames defaultNames;
|
||||
|
||||
Font f (font);
|
||||
f.setTypefaceName (defaultNames.getRealFontName (font.getTypefaceName()));
|
||||
f.setTypefaceName ([&]() -> String
|
||||
{
|
||||
const auto faceName = font.getTypefaceName();
|
||||
|
||||
if (faceName == Font::getDefaultSansSerifFontName()) return "Roboto";
|
||||
if (faceName == Font::getDefaultSerifFontName()) return "Roboto";
|
||||
if (faceName == Font::getDefaultMonospacedFontName()) return "Roboto";
|
||||
|
||||
return faceName;
|
||||
}());
|
||||
|
||||
return Typeface::createSystemTypefaceFor (f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_FREETYPE
|
||||
|
||||
StringArray FTTypefaceList::getDefaultFontDirectories()
|
||||
{
|
||||
return StringArray ("/system/fonts");
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new FreeTypeTypeface (font);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File& folder)
|
||||
{
|
||||
FTTypefaceList::getInstance()->scanFontPaths (StringArray (folder.getFullPathName()));
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
return FTTypefaceList::getInstance()->findAllFamilyNames();
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
return FTTypefaceList::getInstance()->findAllTypefaceStyles (family);
|
||||
}
|
||||
|
||||
bool TextLayout::createNativeLayout (const AttributedString&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \
|
||||
|
|
@ -135,417 +86,363 @@ DECLARE_JNI_CLASS (AndroidRectF, "android/graphics/RectF")
|
|||
DECLARE_JNI_CLASS (JavaMessageDigest, "java/security/MessageDigest")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
METHOD (open, "open", "(Ljava/lang/String;)Ljava/io/InputStream;") \
|
||||
|
||||
DECLARE_JNI_CLASS (AndroidAssetManager, "android/content/res/AssetManager")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
// Defined in juce_core
|
||||
std::unique_ptr<InputStream> makeAndroidInputStreamWrapper (jobject stream);
|
||||
|
||||
//==============================================================================
|
||||
class MemoryFontCache : public DeletedAtShutdown
|
||||
{
|
||||
public:
|
||||
~MemoryFontCache()
|
||||
{
|
||||
clearSingletonInstance();
|
||||
}
|
||||
|
||||
struct Key
|
||||
{
|
||||
String name, style;
|
||||
auto tie() const { return std::tuple (name, style); }
|
||||
bool operator< (const Key& other) const { return tie() < other.tie(); }
|
||||
bool operator== (const Key& other) const { return tie() == other.tie(); }
|
||||
};
|
||||
|
||||
void add (const Key& key, std::shared_ptr<hb_font_t> ptr)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
cache.emplace (key, ptr);
|
||||
}
|
||||
|
||||
void remove (const Key& p)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
cache.erase (p);
|
||||
}
|
||||
|
||||
std::set<String> getAllNames() const
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
std::set<String> result;
|
||||
|
||||
for (const auto& item : cache)
|
||||
result.insert (item.first.name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<String> getStylesForFamily (const String& family) const
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
const auto lower = std::lower_bound (cache.begin(), cache.end(), family, [] (const auto& a, const String& b)
|
||||
{
|
||||
return a.first.name < b;
|
||||
});
|
||||
const auto upper = std::upper_bound (cache.begin(), cache.end(), family, [] (const String& a, const auto& b)
|
||||
{
|
||||
return a < b.first.name;
|
||||
});
|
||||
|
||||
std::set<String> result;
|
||||
|
||||
for (const auto& item : makeRange (lower, upper))
|
||||
result.insert (item.first.style);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<hb_font_t> find (const Key& key)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
const auto iter = cache.find (key);
|
||||
|
||||
if (iter != cache.end())
|
||||
return iter->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_SINGLETON (MemoryFontCache, true)
|
||||
|
||||
private:
|
||||
std::map<Key, std::shared_ptr<hb_font_t>> cache;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
JUCE_IMPLEMENT_SINGLETON (MemoryFontCache)
|
||||
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
StringArray results;
|
||||
auto results = [&]
|
||||
{
|
||||
if (auto* cache = MemoryFontCache::getInstance())
|
||||
return cache->getAllNames();
|
||||
|
||||
return std::set<String>{};
|
||||
}();
|
||||
|
||||
for (auto& f : File ("/system/fonts").findChildFiles (File::findFiles, false, "*.ttf"))
|
||||
results.addIfNotAlreadyThere (f.getFileNameWithoutExtension().upToLastOccurrenceOf ("-", false, false));
|
||||
results.insert (f.getFileNameWithoutExtension().upToLastOccurrenceOf ("-", false, false));
|
||||
|
||||
return results;
|
||||
StringArray s;
|
||||
|
||||
for (const auto& family : results)
|
||||
s.add (family);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
StringArray results ("Regular");
|
||||
auto results = [&]
|
||||
{
|
||||
if (auto* cache = MemoryFontCache::getInstance())
|
||||
return cache->getStylesForFamily (family);
|
||||
|
||||
return std::set<String>{};
|
||||
}();
|
||||
|
||||
for (auto& f : File ("/system/fonts").findChildFiles (File::findFiles, false, family + "-*.ttf"))
|
||||
results.addIfNotAlreadyThere (f.getFileNameWithoutExtension().fromLastOccurrenceOf ("-", false, false));
|
||||
results.insert (f.getFileNameWithoutExtension().fromLastOccurrenceOf ("-", false, false));
|
||||
|
||||
return results;
|
||||
StringArray s;
|
||||
|
||||
for (const auto& style : results)
|
||||
s.add (style);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const float referenceFontSize = 256.0f;
|
||||
const float referenceFontToUnits = 1.0f / referenceFontSize;
|
||||
|
||||
//==============================================================================
|
||||
class AndroidTypeface final : public Typeface
|
||||
{
|
||||
public:
|
||||
AndroidTypeface (const Font& font)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle()),
|
||||
ascent (0), descent (0), heightToPointsFactor (1.0f)
|
||||
static Typeface::Ptr from (const Font& font)
|
||||
{
|
||||
JNIEnv* const env = getEnv();
|
||||
if (auto* cache = MemoryFontCache::getInstance())
|
||||
if (auto result = cache->find ({ font.getTypefaceName(), font.getTypefaceStyle() }))
|
||||
return new AndroidTypeface (DoCache::no, result, font.getTypefaceName(), font.getTypefaceStyle());
|
||||
|
||||
// First check whether there's an embedded asset with this font name:
|
||||
typeface = GlobalRef (getTypefaceFromAsset (name));
|
||||
auto blob = getBlobForFont (font);
|
||||
auto face = FontStyleHelpers::getFaceForBlob ({ static_cast<const char*> (blob.getData()), blob.getSize() }, 0);
|
||||
|
||||
if (typeface.get() == nullptr)
|
||||
if (face == nullptr)
|
||||
{
|
||||
const bool isBold = style.contains ("Bold");
|
||||
const bool isItalic = style.contains ("Italic");
|
||||
|
||||
File fontFile (getFontFile (name, style));
|
||||
|
||||
if (! fontFile.exists())
|
||||
fontFile = findFontFile (name, isBold, isItalic);
|
||||
|
||||
if (fontFile.exists())
|
||||
typeface = GlobalRef (LocalRef<jobject> (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
|
||||
javaString (fontFile.getFullPathName()).get())));
|
||||
else
|
||||
typeface = GlobalRef (LocalRef<jobject> (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create,
|
||||
javaString (getName()).get(),
|
||||
(isBold ? 1 : 0) + (isItalic ? 2 : 0))));
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
initialise (env);
|
||||
HbFont hbFont { hb_font_create (face.get()) };
|
||||
FontStyleHelpers::initSynthetics (hbFont.get(), font);
|
||||
|
||||
return new AndroidTypeface (DoCache::no, std::move (hbFont), font.getTypefaceName(), font.getTypefaceStyle());
|
||||
}
|
||||
|
||||
AndroidTypeface (const void* data, size_t size)
|
||||
: Typeface (String (static_cast<uint64> (reinterpret_cast<uintptr_t> (data))), String())
|
||||
enum class DoCache
|
||||
{
|
||||
auto* env = getEnv();
|
||||
auto cacheFile = getCacheFileForData (data, size);
|
||||
no,
|
||||
yes
|
||||
};
|
||||
|
||||
typeface = GlobalRef (LocalRef<jobject> (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile,
|
||||
javaString (cacheFile.getFullPathName()).get())));
|
||||
|
||||
initialise (env);
|
||||
}
|
||||
|
||||
void initialise (JNIEnv* const env)
|
||||
static Typeface::Ptr from (Span<const std::byte> blob, unsigned int index = 0)
|
||||
{
|
||||
rect = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidRect, AndroidRect.constructor, 0, 0, 0, 0)));
|
||||
|
||||
paint = GlobalRef (GraphicsHelpers::createPaint (Graphics::highResamplingQuality));
|
||||
const LocalRef<jobject> ignored (paint.callObjectMethod (AndroidPaint.setTypeface, typeface.get()));
|
||||
|
||||
charArray = GlobalRef (LocalRef<jobject> ((jobject) env->NewCharArray (2)));
|
||||
|
||||
paint.callVoidMethod (AndroidPaint.setTextSize, referenceFontSize);
|
||||
|
||||
const float fullAscent = std::abs (paint.callFloatMethod (AndroidPaint.ascent));
|
||||
const float fullDescent = paint.callFloatMethod (AndroidPaint.descent);
|
||||
const float totalHeight = fullAscent + fullDescent;
|
||||
|
||||
ascent = fullAscent / totalHeight;
|
||||
descent = fullDescent / totalHeight;
|
||||
heightToPointsFactor = referenceFontSize / totalHeight;
|
||||
return fromMemory (DoCache::yes, blob, index);
|
||||
}
|
||||
|
||||
float getAscent() const override { return ascent; }
|
||||
float getDescent() const override { return descent; }
|
||||
float getHeightToPointsFactor() const override { return heightToPointsFactor; }
|
||||
Native getNativeDetails() const override
|
||||
{
|
||||
return Native { hbFont.get() };
|
||||
}
|
||||
|
||||
~AndroidTypeface() override
|
||||
{
|
||||
if (doCache == DoCache::yes)
|
||||
if (auto* c = MemoryFontCache::getInstance())
|
||||
c->remove ({ getName(), getStyle() });
|
||||
}
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
auto numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
|
||||
jfloatArray widths = env->NewFloatArray ((int) numChars);
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
const auto upem = hb_face_get_upem (hb_font_get_face (hbFont.get()));
|
||||
|
||||
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
|
||||
|
||||
HeapBlock<jfloat> localWidths (static_cast<size_t> (numDone));
|
||||
env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
|
||||
env->DeleteLocalRef (widths);
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (int i = 0; i < numDone; ++i)
|
||||
x += localWidths[i];
|
||||
|
||||
return x * referenceFontToUnits * heightToPointsFactor;
|
||||
hb_position_t x{};
|
||||
doSimpleShape (text, [&] (const auto&, const auto& position)
|
||||
{
|
||||
x += position.x_advance;
|
||||
});
|
||||
return heightToPoints * (float) x / (float) upem;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& glyphs, Array<float>& xOffsets) override
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
auto numChars = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
|
||||
jfloatArray widths = env->NewFloatArray ((int) numChars);
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
const auto upem = hb_face_get_upem (hb_font_get_face (hbFont.get()));
|
||||
|
||||
const int numDone = paint.callIntMethod (AndroidPaint.getTextWidths, javaString (text).get(), widths);
|
||||
Point<hb_position_t> cursor{};
|
||||
|
||||
HeapBlock<jfloat> localWidths (static_cast<size_t> (numDone));
|
||||
env->GetFloatArrayRegion (widths, 0, numDone, localWidths);
|
||||
env->DeleteLocalRef (widths);
|
||||
|
||||
auto s = text.getCharPointer();
|
||||
|
||||
xOffsets.add (0);
|
||||
float x = 0;
|
||||
|
||||
for (int i = 0; i < numDone; ++i)
|
||||
doSimpleShape (text, [&] (const auto& info, const auto& position)
|
||||
{
|
||||
const float local = localWidths[i];
|
||||
glyphs.add ((int) info.codepoint);
|
||||
xOffsets.add (heightToPoints * ((float) cursor.x + (float) position.x_offset) / (float) upem);
|
||||
cursor += Point { position.x_advance, position.y_advance };
|
||||
});
|
||||
|
||||
// Android uses jchar (UTF-16) characters
|
||||
jchar ch = (jchar) s.getAndAdvance();
|
||||
|
||||
// Android has no proper glyph support, so we have to do
|
||||
// a hacky workaround for ligature detection
|
||||
|
||||
#if JUCE_STRING_UTF_TYPE <= 16
|
||||
static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two java chars in one glyph");
|
||||
|
||||
// if the width of this glyph is zero inside the string but has
|
||||
// a width on it's own, then it's probably due to ligature
|
||||
if (local == 0.0f && glyphs.size() > 0 && getStringWidth (String (ch)) > 0.0f)
|
||||
{
|
||||
// modify the previous glyph
|
||||
int& glyphNumber = glyphs.getReference (glyphs.size() - 1);
|
||||
|
||||
// make sure this is not a three character ligature
|
||||
if (glyphNumber < std::numeric_limits<jchar>::max())
|
||||
{
|
||||
const unsigned int previousGlyph
|
||||
= static_cast<unsigned int> (glyphNumber) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
const unsigned int thisGlyph
|
||||
= static_cast<unsigned int> (ch) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
|
||||
glyphNumber = static_cast<int> ((thisGlyph << (sizeof (jchar) * 8U)) | previousGlyph);
|
||||
ch = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glyphs.add ((int) ch);
|
||||
x += local;
|
||||
xOffsets.add (x * referenceFontToUnits * heightToPointsFactor);
|
||||
}
|
||||
xOffsets.add (heightToPoints * (float) cursor.x / (float) upem);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int /*glyphNumber*/, Path& /*destPath*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& t, float /*fontHeight*/) override
|
||||
{
|
||||
#if JUCE_STRING_UTF_TYPE <= 16
|
||||
static_assert (sizeof (int) >= (sizeof (jchar) * 2), "Unable store two jni chars in one int");
|
||||
|
||||
// glyphNumber of zero is used to indicate that the last character was a ligature
|
||||
if (glyphNumber == 0) return nullptr;
|
||||
|
||||
jchar ch1 = (static_cast<unsigned int> (glyphNumber) >> 0) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
jchar ch2 = (static_cast<unsigned int> (glyphNumber) >> (sizeof (jchar) * 8U)) & ((1U << (sizeof (jchar) * 8U)) - 1U);
|
||||
#else
|
||||
jchar ch1 = glyphNumber, ch2 = 0;
|
||||
#endif
|
||||
Rectangle<int> bounds;
|
||||
auto* env = getEnv();
|
||||
|
||||
{
|
||||
LocalRef<jobject> matrix (GraphicsHelpers::createMatrix (env, AffineTransform::scale (referenceFontToUnits * heightToPointsFactor).followedBy (t)));
|
||||
|
||||
jboolean isCopy;
|
||||
auto* buffer = env->GetCharArrayElements ((jcharArray) charArray.get(), &isCopy);
|
||||
|
||||
buffer[0] = ch1; buffer[1] = ch2;
|
||||
env->ReleaseCharArrayElements ((jcharArray) charArray.get(), buffer, 0);
|
||||
|
||||
LocalRef<jobject> path (env->NewObject (AndroidPath, AndroidPath.constructor));
|
||||
LocalRef<jobject> boundsF (env->NewObject (AndroidRectF, AndroidRectF.constructor));
|
||||
|
||||
|
||||
env->CallVoidMethod (paint.get(), AndroidPaint.getCharsPath, charArray.get(), 0, (ch2 != 0 ? 2 : 1), 0.0f, 0.0f, path.get());
|
||||
|
||||
env->CallVoidMethod (path.get(), AndroidPath.computeBounds, boundsF.get(), 1);
|
||||
|
||||
env->CallBooleanMethod (matrix.get(), AndroidMatrix.mapRect, boundsF.get());
|
||||
|
||||
env->CallVoidMethod (boundsF.get(), AndroidRectF.roundOut, rect.get());
|
||||
|
||||
bounds = Rectangle<int>::leftTopRightBottom (env->GetIntField (rect.get(), AndroidRect.left) - 1,
|
||||
env->GetIntField (rect.get(), AndroidRect.top),
|
||||
env->GetIntField (rect.get(), AndroidRect.right) + 1,
|
||||
env->GetIntField (rect.get(), AndroidRect.bottom));
|
||||
|
||||
auto w = bounds.getWidth();
|
||||
auto h = jmax (1, bounds.getHeight());
|
||||
|
||||
LocalRef<jobject> bitmapConfig (env->CallStaticObjectMethod (AndroidBitmapConfig, AndroidBitmapConfig.valueOf, javaString ("ARGB_8888").get()));
|
||||
LocalRef<jobject> bitmap (env->CallStaticObjectMethod (AndroidBitmap, AndroidBitmap.createBitmap, w, h, bitmapConfig.get()));
|
||||
LocalRef<jobject> canvas (env->NewObject (AndroidCanvas, AndroidCanvas.create, bitmap.get()));
|
||||
|
||||
env->CallBooleanMethod (matrix.get(), AndroidMatrix.postTranslate, (float) -bounds.getX(), (float) -bounds.getY());
|
||||
env->CallVoidMethod (canvas.get(), AndroidCanvas.setMatrix, matrix.get());
|
||||
env->CallVoidMethod (canvas.get(), AndroidCanvas.drawPath, path.get(), paint.get());
|
||||
|
||||
int requiredRenderArraySize = w * h;
|
||||
if (requiredRenderArraySize > lastCachedRenderArraySize)
|
||||
{
|
||||
cachedRenderArray = GlobalRef (LocalRef<jobject> ((jobject) env->NewIntArray (requiredRenderArraySize)));
|
||||
lastCachedRenderArraySize = requiredRenderArraySize;
|
||||
}
|
||||
|
||||
env->CallVoidMethod (bitmap.get(), AndroidBitmap.getPixels, cachedRenderArray.get(), 0, w, 0, 0, w, h);
|
||||
env->CallVoidMethod (bitmap.get(), AndroidBitmap.recycle);
|
||||
}
|
||||
|
||||
EdgeTable* et = nullptr;
|
||||
|
||||
if (! bounds.isEmpty())
|
||||
{
|
||||
et = new EdgeTable (bounds);
|
||||
|
||||
jint* const maskDataElements = env->GetIntArrayElements ((jintArray) cachedRenderArray.get(), nullptr);
|
||||
const jint* mask = maskDataElements;
|
||||
|
||||
for (int y = bounds.getY(); y < bounds.getBottom(); ++y)
|
||||
{
|
||||
#if JUCE_LITTLE_ENDIAN
|
||||
const uint8* const lineBytes = ((const uint8*) mask) + 3;
|
||||
#else
|
||||
const uint8* const lineBytes = (const uint8*) mask;
|
||||
#endif
|
||||
|
||||
et->clipLineToMask (bounds.getX(), y, lineBytes, 4, bounds.getWidth());
|
||||
mask += bounds.getWidth();
|
||||
}
|
||||
|
||||
env->ReleaseIntArrayElements ((jintArray) cachedRenderArray.get(), maskDataElements, 0);
|
||||
}
|
||||
|
||||
return et;
|
||||
}
|
||||
|
||||
GlobalRef typeface, paint, rect, charArray, cachedRenderArray;
|
||||
float ascent, descent, heightToPointsFactor;
|
||||
int lastCachedRenderArraySize = -1;
|
||||
|
||||
private:
|
||||
static File findFontFile (const String& family,
|
||||
const bool bold, const bool italic)
|
||||
template <typename Consumer>
|
||||
void doSimpleShape (const String& text, Consumer&& consumer)
|
||||
{
|
||||
File file;
|
||||
HbBuffer buffer { hb_buffer_create() };
|
||||
hb_buffer_add_utf8 (buffer.get(), text.toRawUTF8(), -1, 0, -1);
|
||||
hb_buffer_guess_segment_properties (buffer.get());
|
||||
|
||||
if (bold || italic)
|
||||
{
|
||||
String suffix;
|
||||
if (bold) suffix = "Bold";
|
||||
if (italic) suffix << "Italic";
|
||||
hb_shape (hbFont.get(), buffer.get(), nullptr, 0);
|
||||
|
||||
file = getFontFile (family, suffix);
|
||||
unsigned int numGlyphs{};
|
||||
auto* infos = hb_buffer_get_glyph_infos (buffer.get(), &numGlyphs);
|
||||
auto* positions = hb_buffer_get_glyph_positions (buffer.get(), &numGlyphs);
|
||||
|
||||
if (file.exists())
|
||||
return file;
|
||||
}
|
||||
for (auto i = decltype (numGlyphs){}; i < numGlyphs; ++i)
|
||||
consumer (infos[i], positions[i]);
|
||||
}
|
||||
|
||||
file = getFontFile (family, "Regular");
|
||||
static Typeface::Ptr fromMemory (DoCache cache, Span<const std::byte> blob, unsigned int index = 0)
|
||||
{
|
||||
auto face = FontStyleHelpers::getFaceForBlob ({ reinterpret_cast<const char*> (blob.data()), blob.size() }, index);
|
||||
|
||||
if (face == nullptr)
|
||||
return {};
|
||||
|
||||
return new AndroidTypeface (cache,
|
||||
HbFont { hb_font_create (face.get()) },
|
||||
readFontName (face.get(), HB_OT_NAME_ID_FONT_FAMILY, nullptr),
|
||||
{});
|
||||
}
|
||||
|
||||
static String readFontName (hb_face_t* face, hb_ot_name_id_t nameId, hb_language_t language)
|
||||
{
|
||||
unsigned int textSize{};
|
||||
textSize = hb_ot_name_get_utf8 (face, nameId, language, &textSize, nullptr);
|
||||
std::vector<char> nameString (textSize + 1, 0);
|
||||
textSize = (unsigned int) nameString.size();
|
||||
hb_ot_name_get_utf8 (face, nameId, language, &textSize, nameString.data());
|
||||
|
||||
return nameString.data();
|
||||
}
|
||||
|
||||
AndroidTypeface (DoCache cache, std::shared_ptr<hb_font_t> fontIn, const String& name, const String& style)
|
||||
: Typeface (name, style),
|
||||
hbFont (std::move (fontIn)),
|
||||
doCache (cache)
|
||||
{
|
||||
if (doCache == DoCache::yes)
|
||||
if (auto* c = MemoryFontCache::getInstance())
|
||||
c->add ({ name, style }, hbFont);
|
||||
}
|
||||
|
||||
static MemoryBlock getBlobForFont (const Font& font)
|
||||
{
|
||||
auto memory = loadFontAsset (font.getTypefaceName());
|
||||
|
||||
if (! memory.isEmpty())
|
||||
return memory;
|
||||
|
||||
const auto file = findFontFile (font);
|
||||
|
||||
if (! file.exists())
|
||||
file = getFontFile (family, String());
|
||||
{
|
||||
// Failed to find file corresponding to this font
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
return file;
|
||||
FileInputStream stream { file };
|
||||
|
||||
MemoryBlock result;
|
||||
stream.readIntoMemoryBlock (result);
|
||||
|
||||
return stream.isExhausted() ? result : MemoryBlock{};
|
||||
}
|
||||
|
||||
static File findFontFile (const Font& font)
|
||||
{
|
||||
const String styles[] { font.getTypefaceStyle(),
|
||||
FontStyleHelpers::getStyleName (font.isBold(), font.isItalic()),
|
||||
{} };
|
||||
|
||||
for (const auto& style : styles)
|
||||
if (auto file = getFontFile (font.getTypefaceName(), style); file.exists())
|
||||
return file;
|
||||
|
||||
for (auto& file : File ("/system/fonts").findChildFiles (File::findFiles, false, "*.ttf"))
|
||||
if (file.getFileName().startsWith (font.getTypefaceName()))
|
||||
return file;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static File getFontFile (const String& family, const String& fontStyle)
|
||||
{
|
||||
String path ("/system/fonts/" + family);
|
||||
|
||||
if (fontStyle.isNotEmpty())
|
||||
path << '-' << fontStyle;
|
||||
|
||||
return File (path + ".ttf");
|
||||
return "/system/fonts/" + family + (fontStyle.isNotEmpty() ? ("-" + fontStyle) : String{}) + ".ttf";
|
||||
}
|
||||
|
||||
static LocalRef<jobject> getTypefaceFromAsset (const String& typefaceName)
|
||||
static MemoryBlock loadFontAsset (const String& typefaceName)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
LocalRef<jobject> assetManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getAssets));
|
||||
const LocalRef<jobject> assetManager { env->CallObjectMethod (getAppContext().get(), AndroidContext.getAssets) };
|
||||
|
||||
if (assetManager == nullptr)
|
||||
return LocalRef<jobject>();
|
||||
return {};
|
||||
|
||||
auto assetTypeface = env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromAsset, assetManager.get(),
|
||||
javaString ("fonts/" + typefaceName).get());
|
||||
const LocalRef<jobject> inputStream { env->CallObjectMethod (assetManager,
|
||||
AndroidAssetManager.open,
|
||||
javaString ("fonts/" + typefaceName).get()) };
|
||||
|
||||
// this may throw
|
||||
if (env->ExceptionCheck() != 0)
|
||||
{
|
||||
env->ExceptionClear();
|
||||
return LocalRef<jobject>();
|
||||
}
|
||||
// Opening an input stream for an asset might throw if the asset isn't found
|
||||
jniCheckHasExceptionOccurredAndClear();
|
||||
|
||||
return LocalRef<jobject> (assetTypeface);
|
||||
if (inputStream == nullptr)
|
||||
return {};
|
||||
|
||||
auto streamWrapper = makeAndroidInputStreamWrapper (inputStream);
|
||||
|
||||
if (streamWrapper == nullptr)
|
||||
return {};
|
||||
|
||||
MemoryBlock result;
|
||||
streamWrapper->readIntoMemoryBlock (result);
|
||||
|
||||
return streamWrapper->isExhausted() ? result : MemoryBlock{};
|
||||
}
|
||||
|
||||
static File getCacheDirectory()
|
||||
{
|
||||
static File result = []()
|
||||
{
|
||||
auto appContext = getAppContext();
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
LocalRef<jobject> cacheFile (env->CallObjectMethod (appContext.get(), AndroidContext.getCacheDir));
|
||||
LocalRef<jstring> jPath ((jstring) env->CallObjectMethod (cacheFile.get(), JavaFile.getAbsolutePath));
|
||||
|
||||
return File (juceString (env, jPath.get()));
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return File();
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HashMap<String, File>& getInMemoryFontCache()
|
||||
{
|
||||
static HashMap<String, File> cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
static File getCacheFileForData (const void* data, size_t size)
|
||||
{
|
||||
static CriticalSection cs;
|
||||
JNIEnv* const env = getEnv();
|
||||
|
||||
String key;
|
||||
{
|
||||
LocalRef<jobject> digest (env->CallStaticObjectMethod (JavaMessageDigest, JavaMessageDigest.getInstance, javaString ("MD5").get()));
|
||||
LocalRef<jbyteArray> bytes (env->NewByteArray ((int) size));
|
||||
|
||||
jboolean ignore;
|
||||
auto* jbytes = env->GetByteArrayElements (bytes.get(), &ignore);
|
||||
memcpy (jbytes, data, size);
|
||||
env->ReleaseByteArrayElements (bytes.get(), jbytes, 0);
|
||||
|
||||
env->CallVoidMethod (digest.get(), JavaMessageDigest.update, bytes.get());
|
||||
LocalRef<jbyteArray> result ((jbyteArray) env->CallObjectMethod (digest.get(), JavaMessageDigest.digest));
|
||||
|
||||
auto* md5Bytes = env->GetByteArrayElements (result.get(), &ignore);
|
||||
key = String::toHexString (md5Bytes, env->GetArrayLength (result.get()), 0);
|
||||
env->ReleaseByteArrayElements (result.get(), md5Bytes, 0);
|
||||
}
|
||||
|
||||
ScopedLock lock (cs);
|
||||
auto& mapEntry = getInMemoryFontCache().getReference (key);
|
||||
|
||||
if (mapEntry == File())
|
||||
{
|
||||
mapEntry = getCacheDirectory().getChildFile ("bindata_" + key);
|
||||
mapEntry.replaceWithData (data, size);
|
||||
}
|
||||
|
||||
return mapEntry;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidTypeface)
|
||||
std::shared_ptr<hb_font_t> hbFont;
|
||||
DoCache doCache;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return new AndroidTypeface (font);
|
||||
return AndroidTypeface::from (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size)
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
|
||||
{
|
||||
return new AndroidTypeface (data, size);
|
||||
return AndroidTypeface::from (data);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File&)
|
||||
{
|
||||
jassertfalse; // not available unless using FreeType
|
||||
jassertfalse; // not currently available
|
||||
}
|
||||
|
||||
bool TextLayout::createNativeLayout (const AttributedString&)
|
||||
|
|
@ -553,6 +450,4 @@ bool TextLayout::createNativeLayout (const AttributedString&)
|
|||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_GLYPH_H
|
||||
#include FT_COLOR_H
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
|
|
@ -62,41 +66,62 @@ struct FTLibWrapper final : public ReferenceCountedObject
|
|||
//==============================================================================
|
||||
struct FTFaceWrapper final : public ReferenceCountedObject
|
||||
{
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
|
||||
: library (ftLib)
|
||||
using Ptr = ReferenceCountedObjectPtr<FTFaceWrapper>;
|
||||
|
||||
static FTFaceWrapper::Ptr selectUnicodeCharmap (FTFaceWrapper::Ptr face)
|
||||
{
|
||||
if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &face) != 0)
|
||||
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 (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex)
|
||||
: library (ftLib), savedFaceData (data, dataSize)
|
||||
static FTFaceWrapper::Ptr from (const FTLibWrapper::Ptr& ftLib, const File& file, int faceIndex)
|
||||
{
|
||||
if (FT_New_Memory_Face (ftLib->library, (const FT_Byte*) savedFaceData.getData(),
|
||||
(FT_Long) savedFaceData.getSize(), faceIndex, &face) != 0)
|
||||
face = {};
|
||||
FT_Face result{};
|
||||
|
||||
if (FT_New_Face (ftLib->library, file.getFullPathName().toUTF8(), faceIndex, &result) != 0)
|
||||
return {};
|
||||
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (ftLib, result));
|
||||
}
|
||||
|
||||
static FTFaceWrapper::Ptr from (const FTLibWrapper::Ptr& ftLib, const void* data, size_t dataSize, int faceIndex)
|
||||
{
|
||||
MemoryBlock storage (data, dataSize);
|
||||
FT_Face result{};
|
||||
if (FT_New_Memory_Face (ftLib->library,
|
||||
static_cast<const FT_Byte*> (storage.getData()),
|
||||
(FT_Long) storage.getSize(),
|
||||
faceIndex,
|
||||
&result) != 0)
|
||||
return {};
|
||||
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (ftLib, result, std::move (storage)));
|
||||
}
|
||||
|
||||
FTFaceWrapper (const FTLibWrapper::Ptr& ftLib, FT_Face faceIn, MemoryBlock mb = {})
|
||||
: library (ftLib), savedFaceData (std::move (mb)), face (faceIn) {}
|
||||
|
||||
~FTFaceWrapper()
|
||||
{
|
||||
if (face != nullptr)
|
||||
FT_Done_Face (face);
|
||||
}
|
||||
|
||||
FT_Face face = {};
|
||||
FTLibWrapper::Ptr library;
|
||||
MemoryBlock savedFaceData;
|
||||
FT_Face face = {};
|
||||
|
||||
using Ptr = ReferenceCountedObjectPtr<FTFaceWrapper>;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FTFaceWrapper)
|
||||
JUCE_HEAVYWEIGHT_LEAK_DETECTOR(FTFaceWrapper)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FTTypefaceList final : private DeletedAtShutdown
|
||||
{
|
||||
public:
|
||||
FTTypefaceList() : library (new FTLibWrapper())
|
||||
FTTypefaceList()
|
||||
{
|
||||
scanFontPaths (getDefaultFontDirectories());
|
||||
}
|
||||
|
|
@ -109,42 +134,76 @@ public:
|
|||
//==============================================================================
|
||||
struct KnownTypeface
|
||||
{
|
||||
KnownTypeface (const File& f, int index, const FTFaceWrapper& face)
|
||||
: file (f),
|
||||
family (face.face->family_name),
|
||||
explicit KnownTypeface (const FTFaceWrapper& face)
|
||||
: 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))
|
||||
faceIndex ((int) face.face->face_index),
|
||||
flags (((face.face->style_flags & FT_STYLE_FLAG_BOLD) ? bold : 0)
|
||||
| ((face.face->style_flags & FT_STYLE_FLAG_ITALIC) ? italic : 0)
|
||||
| ((face.face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? monospaced : 0)
|
||||
| (isFaceSansSerif (family) ? sansSerif : 0))
|
||||
{
|
||||
}
|
||||
|
||||
const File file;
|
||||
virtual ~KnownTypeface() = default;
|
||||
virtual FTFaceWrapper::Ptr create (FTLibWrapper::Ptr) const = 0;
|
||||
virtual bool holdsFace (FTFaceWrapper::Ptr) const { return false; }
|
||||
|
||||
enum Flag
|
||||
{
|
||||
bold = 1 << 0,
|
||||
italic = 1 << 1,
|
||||
monospaced = 1 << 2,
|
||||
sansSerif = 1 << 3,
|
||||
};
|
||||
|
||||
const String family, style;
|
||||
const int faceIndex;
|
||||
const bool isMonospaced, isSansSerif;
|
||||
const int flags;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownTypeface)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static FTFaceWrapper::Ptr selectUnicodeCharmap (FTFaceWrapper* face)
|
||||
struct FileTypeface : public KnownTypeface
|
||||
{
|
||||
if (face != nullptr)
|
||||
if (FT_Select_Charmap (face->face, ft_encoding_unicode) != 0)
|
||||
FT_Set_Charmap (face->face, face->face->charmaps[0]);
|
||||
FileTypeface (const FTFaceWrapper& face, const File& fileIn)
|
||||
: KnownTypeface (face), file (fileIn) {}
|
||||
|
||||
return face;
|
||||
}
|
||||
FTFaceWrapper::Ptr create (FTLibWrapper::Ptr lib) const override
|
||||
{
|
||||
return FTFaceWrapper::from (lib, file, faceIndex);
|
||||
}
|
||||
|
||||
const File file;
|
||||
};
|
||||
|
||||
struct CachedTypeface : public KnownTypeface
|
||||
{
|
||||
explicit CachedTypeface (FTFaceWrapper::Ptr ptr)
|
||||
: KnownTypeface (*ptr), face (ptr) {}
|
||||
|
||||
FTFaceWrapper::Ptr create (FTLibWrapper::Ptr) const override
|
||||
{
|
||||
return face;
|
||||
}
|
||||
|
||||
bool holdsFace (FTFaceWrapper::Ptr p) const override
|
||||
{
|
||||
return face == p;
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr face;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
FTFaceWrapper::Ptr createFace (const void* data, size_t dataSize, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, data, dataSize, index));
|
||||
return FTFaceWrapper::from (library, data, dataSize, index);
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const File& file, int index)
|
||||
{
|
||||
return selectUnicodeCharmap (new FTFaceWrapper (library, file, index));
|
||||
return FTFaceWrapper::from (library, file, index);
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr createFace (const String& fontName, const String& fontStyle)
|
||||
|
|
@ -155,7 +214,7 @@ public:
|
|||
if (ftFace == nullptr) ftFace = matchTypeface (fontName, {});
|
||||
|
||||
if (ftFace != nullptr)
|
||||
return createFace (ftFace->file, ftFace->faceIndex);
|
||||
return ftFace->create (library);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -165,7 +224,7 @@ public:
|
|||
{
|
||||
std::set<String> set;
|
||||
|
||||
for (auto* face : faces)
|
||||
for (const auto& face : faces)
|
||||
set.insert (face->family);
|
||||
|
||||
StringArray s;
|
||||
|
|
@ -180,7 +239,7 @@ public:
|
|||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* face : faces)
|
||||
for (const auto& face : faces)
|
||||
if (face->family == family)
|
||||
s.addIfNotAlreadyThere (face->style);
|
||||
|
||||
|
|
@ -199,38 +258,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::sort (faces.begin(), faces.end(), [] (const auto* a, const auto* b)
|
||||
std::sort (faces.begin(), faces.end(), [] (const auto& a, const auto& b)
|
||||
{
|
||||
const auto tie = [] (const KnownTypeface& t)
|
||||
{
|
||||
// Used to order styles like "Regular", "Roman" etc. before "Bold", "Italic", etc.
|
||||
const auto computeStyleNormalcy = [] (const String& style)
|
||||
{
|
||||
if (style == "Regular")
|
||||
return 0;
|
||||
|
||||
if (style == "Roman")
|
||||
return 1;
|
||||
|
||||
if (style == "Book")
|
||||
return 2;
|
||||
|
||||
if (style.containsIgnoreCase ("Bold"))
|
||||
return 3;
|
||||
|
||||
if (style.containsIgnoreCase ("Italic"))
|
||||
return 4;
|
||||
|
||||
return 5;
|
||||
};
|
||||
|
||||
return std::make_tuple (t.family,
|
||||
computeStyleNormalcy (t.style),
|
||||
t.flags,
|
||||
t.style,
|
||||
t.isSansSerif,
|
||||
t.isMonospaced,
|
||||
t.faceIndex,
|
||||
t.file);
|
||||
t.faceIndex);
|
||||
};
|
||||
|
||||
return tie (*a) < tie (*b);
|
||||
|
|
@ -239,30 +274,46 @@ public:
|
|||
|
||||
void getMonospacedNames (StringArray& monoSpaced) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isMonospaced)
|
||||
for (const auto& face : faces)
|
||||
if (face->flags & KnownTypeface::monospaced)
|
||||
monoSpaced.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSerifNames (StringArray& serif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (! (face->isSansSerif || face->isMonospaced))
|
||||
for (const auto& face : faces)
|
||||
if ((face->flags & (KnownTypeface::sansSerif | KnownTypeface::monospaced)) == 0)
|
||||
serif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void getSansSerifNames (StringArray& sansSerif) const
|
||||
{
|
||||
for (auto* face : faces)
|
||||
if (face->isSansSerif)
|
||||
for (const auto& face : faces)
|
||||
if (face->flags & KnownTypeface::sansSerif)
|
||||
sansSerif.addIfNotAlreadyThere (face->family);
|
||||
}
|
||||
|
||||
void addMemoryFace (FTFaceWrapper::Ptr ptr)
|
||||
{
|
||||
faces.insert (faces.begin(), std::make_unique<CachedTypeface> (ptr));
|
||||
}
|
||||
|
||||
void removeMemoryFace (FTFaceWrapper::Ptr ptr)
|
||||
{
|
||||
const auto iter = std::find_if (faces.begin(), faces.end(), [&] (const auto& face)
|
||||
{
|
||||
return face->holdsFace (ptr);
|
||||
});
|
||||
|
||||
if (iter != faces.end())
|
||||
faces.erase (iter);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FTTypefaceList)
|
||||
|
||||
private:
|
||||
FTLibWrapper::Ptr library;
|
||||
OwnedArray<KnownTypeface> faces;
|
||||
FTLibWrapper::Ptr library = new FTLibWrapper;
|
||||
std::vector<std::unique_ptr<KnownTypeface>> faces;
|
||||
|
||||
static StringArray getDefaultFontDirectories();
|
||||
|
||||
|
|
@ -273,15 +324,16 @@ private:
|
|||
|
||||
do
|
||||
{
|
||||
FTFaceWrapper face (library, file, faceIndex);
|
||||
|
||||
if (face.face != nullptr)
|
||||
if (auto face = FTFaceWrapper::from (library, file, faceIndex))
|
||||
{
|
||||
if (faceIndex == 0)
|
||||
numFaces = (int) face.face->num_faces;
|
||||
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));
|
||||
if ((face->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0)
|
||||
faces.push_back (std::make_unique<FileTypeface> (*face, file));
|
||||
}
|
||||
}
|
||||
|
||||
++faceIndex;
|
||||
|
|
@ -291,10 +343,10 @@ private:
|
|||
|
||||
const KnownTypeface* matchTypeface (const String& familyName, const String& style) const noexcept
|
||||
{
|
||||
for (auto* face : faces)
|
||||
for (const auto& face : faces)
|
||||
if (face->family == familyName
|
||||
&& (face->style.equalsIgnoreCase (style) || style.isEmpty()))
|
||||
return face;
|
||||
return face.get();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -315,173 +367,164 @@ private:
|
|||
|
||||
JUCE_IMPLEMENT_SINGLETON (FTTypefaceList)
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FreeTypeTypeface final : public CustomTypeface
|
||||
class FreeTypeTypeface final : public Typeface
|
||||
{
|
||||
using Ptr = ReferenceCountedObjectPtr<FreeTypeTypeface>;
|
||||
enum class DoCache
|
||||
{
|
||||
no,
|
||||
yes,
|
||||
};
|
||||
|
||||
public:
|
||||
FreeTypeTypeface (const Font& font)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (font.getTypefaceName(),
|
||||
font.getTypefaceStyle()))
|
||||
static Typeface::Ptr from (const Font& font)
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (font.getTypefaceName(),
|
||||
font.getTypefaceStyle());
|
||||
const auto name = font.getTypefaceName();
|
||||
const auto style = font.getTypefaceStyle();
|
||||
|
||||
auto face = FTTypefaceList::getInstance()->createFace (name, style);
|
||||
|
||||
if (face == nullptr)
|
||||
return {};
|
||||
|
||||
auto* hbFace = hb_ft_face_create_referenced (face->face);
|
||||
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
|
||||
|
||||
HbFont hb { hb_font_create (hbFace) };
|
||||
|
||||
if (hb == nullptr)
|
||||
return {};
|
||||
|
||||
FontStyleHelpers::initSynthetics (hb.get(), font);
|
||||
return new FreeTypeTypeface (DoCache::no, face, std::move (hb), name, style);
|
||||
}
|
||||
|
||||
FreeTypeTypeface (const void* data, size_t dataSize)
|
||||
: faceWrapper (FTTypefaceList::getInstance()->createFace (data, dataSize, 0))
|
||||
static Typeface::Ptr from (Span<const std::byte> data, int index = 0)
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
initialiseCharacteristics (faceWrapper->face->family_name,
|
||||
faceWrapper->face->style_name);
|
||||
auto face = FTTypefaceList::getInstance()->createFace (data.data(), data.size(), index);
|
||||
|
||||
if (face == nullptr)
|
||||
return {};
|
||||
|
||||
auto* hbFace = hb_ft_face_create_referenced (face->face);
|
||||
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
|
||||
|
||||
HbFont hb { hb_font_create (hbFace) };
|
||||
|
||||
if (hb == nullptr)
|
||||
return {};
|
||||
|
||||
return new FreeTypeTypeface (DoCache::yes, face, std::move (hb), face->face->family_name, face->face->style_name);
|
||||
}
|
||||
|
||||
void initialiseCharacteristics (const String& fontName, const String& fontStyle)
|
||||
|
||||
Native getNativeDetails() const override
|
||||
{
|
||||
setCharacteristics (fontName, fontStyle,
|
||||
faceWrapper->face->ascender / (float) (faceWrapper->face->ascender - faceWrapper->face->descender),
|
||||
L' ');
|
||||
return Native { hb.get() };
|
||||
}
|
||||
|
||||
bool loadGlyphIfPossible (const juce_wchar character) override
|
||||
~FreeTypeTypeface() override
|
||||
{
|
||||
if (faceWrapper != nullptr)
|
||||
if (doCache == DoCache::yes)
|
||||
if (auto* list = FTTypefaceList::getInstance())
|
||||
list->removeMemoryFace (ftFace);
|
||||
}
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
|
||||
float x = 0;
|
||||
|
||||
for (auto iter = text.begin(), end = text.end(); iter != end; ++iter)
|
||||
{
|
||||
auto face = faceWrapper->face;
|
||||
auto glyphIndex = FT_Get_Char_Index (face, (FT_ULong) character);
|
||||
const auto currentChar = *iter;
|
||||
const auto nextIter = iter + 1;
|
||||
const auto nextChar = nextIter == end ? 0 : *nextIter;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
x += getSpacingForGlyphs (getNominalGlyphForCharacter (currentChar),
|
||||
getNominalGlyphForCharacter (nextChar));
|
||||
}
|
||||
|
||||
return false;
|
||||
return x * heightToPoints;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets) override
|
||||
{
|
||||
for (auto c : text)
|
||||
resultGlyphs.add ((int) getNominalGlyphForCharacter (c));
|
||||
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
|
||||
xOffsets.add (0);
|
||||
|
||||
for (auto iter = resultGlyphs.begin(); iter != resultGlyphs.end(); ++iter)
|
||||
{
|
||||
const auto currentGlyph = *iter;
|
||||
const auto nextIter = iter + 1;
|
||||
const auto nextGlyph = nextIter == resultGlyphs.end() ? 0 : *nextIter;
|
||||
|
||||
xOffsets.add (xOffsets.getLast() + getSpacingForGlyphs ((FT_UInt) currentGlyph, (FT_UInt) nextGlyph) * heightToPoints);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FTFaceWrapper::Ptr faceWrapper;
|
||||
|
||||
bool getGlyphShape (Path& destShape, const FT_Outline& outline, float scaleX)
|
||||
FreeTypeTypeface (DoCache cache,
|
||||
FTFaceWrapper::Ptr ftFaceIn,
|
||||
HbFont hbIn,
|
||||
const String& nameIn,
|
||||
const String& styleIn)
|
||||
: Typeface (nameIn, styleIn),
|
||||
ftFace (ftFaceIn),
|
||||
hb (std::move (hbIn)),
|
||||
doCache (cache)
|
||||
{
|
||||
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;
|
||||
if (doCache == DoCache::yes)
|
||||
if (auto* list = FTTypefaceList::getInstance())
|
||||
list->addMemoryFace (ftFace);
|
||||
}
|
||||
|
||||
void addKerning (FT_Face face, const uint32 character, const uint32 glyphIndex)
|
||||
float getKerningForGlyphs (FT_UInt a, FT_UInt b) const
|
||||
{
|
||||
auto height = (float) (face->ascender - face->descender);
|
||||
FT_Vector kerning{};
|
||||
|
||||
uint32 rightGlyphIndex;
|
||||
auto rightCharCode = FT_Get_First_Char (face, &rightGlyphIndex);
|
||||
if (FT_Get_Kerning (ftFace->face, a, b, FT_KERNING_UNSCALED, &kerning) != 0)
|
||||
return {};
|
||||
|
||||
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);
|
||||
}
|
||||
return ((float) kerning.x / (float) ftFace->face->units_per_EM);
|
||||
}
|
||||
|
||||
float getSpacingForGlyphs (FT_UInt a, FT_UInt b) const
|
||||
{
|
||||
FT_Fixed advance{};
|
||||
|
||||
if (FT_Get_Advance (ftFace->face, a, FT_LOAD_ADVANCE_ONLY | FT_LOAD_NO_SCALE, &advance) != 0)
|
||||
return {};
|
||||
|
||||
return getKerningForGlyphs (a, b) + ((float) advance / (float) ftFace->face->units_per_EM);
|
||||
}
|
||||
|
||||
FT_UInt getNominalGlyphForCharacter (juce_wchar c) const
|
||||
{
|
||||
return FT_Get_Char_Index (ftFace->face, (FT_ULong) c);
|
||||
}
|
||||
|
||||
FTFaceWrapper::Ptr ftFace;
|
||||
HbFont hb;
|
||||
DoCache doCache;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
|
||||
};
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return FreeTypeTypeface::from (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
|
||||
{
|
||||
return FreeTypeTypeface::from (data);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -89,16 +89,6 @@ StringArray FTTypefaceList::getDefaultFontDirectories()
|
|||
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()));
|
||||
|
|
@ -217,11 +207,6 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
|||
const auto realName = defaultInfo.getRealFontName (name);
|
||||
f.setTypefaceName (realName);
|
||||
|
||||
const auto styles = findAllTypefaceStyles (realName);
|
||||
|
||||
if (! styles.contains (font.getTypefaceStyle()))
|
||||
f.setTypefaceStyle (styles[0]);
|
||||
|
||||
return Typeface::createSystemTypefaceFor (f);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,35 +37,19 @@ namespace juce
|
|||
|
||||
static constexpr float referenceFontSize = 1024.0f;
|
||||
|
||||
static CTFontRef getCTFontFromTypeface (const Font&);
|
||||
CTFontRef getCTFontFromTypeface (const Font& f);
|
||||
|
||||
namespace CoreTextTypeLayout
|
||||
{
|
||||
static String findBestAvailableStyle (const Font& font, CGAffineTransform& requiredTransform)
|
||||
{
|
||||
auto availableStyles = Font::findAllTypefaceStyles (font.getTypefaceName());
|
||||
auto style = font.getTypefaceStyle();
|
||||
|
||||
if (! availableStyles.contains (style))
|
||||
{
|
||||
if (font.isItalic()) // Fake-up an italic font if there isn't a real one.
|
||||
requiredTransform = CGAffineTransformMake (1.0f, 0, 0.1f, 1.0f, 0, 0);
|
||||
|
||||
return availableStyles[0];
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
static float getFontTotalHeight (CTFontRef font)
|
||||
{
|
||||
return std::abs ((float) CTFontGetAscent (font))
|
||||
+ std::abs ((float) CTFontGetDescent (font));
|
||||
+ std::abs ((float) CTFontGetDescent (font));
|
||||
}
|
||||
|
||||
static float getHeightToPointsFactor (CTFontRef font)
|
||||
{
|
||||
return referenceFontSize / getFontTotalHeight (font);
|
||||
return (float) CTFontGetSize (font) / (float) getFontTotalHeight (font);
|
||||
}
|
||||
|
||||
static CFUniquePtr<CTFontRef> getFontWithPointSize (CTFontRef font, float pointSize)
|
||||
|
|
@ -73,25 +57,6 @@ namespace CoreTextTypeLayout
|
|||
return CFUniquePtr<CTFontRef> (CTFontCreateCopyWithAttributes (font, pointSize, nullptr, nullptr));
|
||||
}
|
||||
|
||||
static CFUniquePtr<CTFontRef> createCTFont (const Font& font, const float fontSizePoints, CGAffineTransform& transformRequired)
|
||||
{
|
||||
CFUniquePtr<CFStringRef> cfFontFamily (FontStyleHelpers::getConcreteFamilyName (font).toCFString());
|
||||
CFUniquePtr<CFStringRef> cfFontStyle (findBestAvailableStyle (font, transformRequired).toCFString());
|
||||
CFStringRef keys[] = { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute };
|
||||
CFTypeRef values[] = { cfFontFamily.get(), cfFontStyle.get() };
|
||||
|
||||
CFUniquePtr<CFDictionaryRef> fontDescAttributes (CFDictionaryCreate (nullptr,
|
||||
(const void**) &keys,
|
||||
(const void**) &values,
|
||||
numElementsInArray (keys),
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
|
||||
CFUniquePtr<CTFontDescriptorRef> ctFontDescRef (CTFontDescriptorCreateWithAttributes (fontDescAttributes.get()));
|
||||
|
||||
return CFUniquePtr<CTFontRef> (CTFontCreateWithFontDescriptor (ctFontDescRef.get(), fontSizePoints, nullptr));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct Advances
|
||||
{
|
||||
|
|
@ -161,8 +126,7 @@ namespace CoreTextTypeLayout
|
|||
return CFUniquePtr<CTFontRef> (ctf);
|
||||
}
|
||||
|
||||
CGAffineTransform transform;
|
||||
return createCTFont (f, referenceFontSize, transform);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -384,101 +348,6 @@ namespace CoreTextTypeLayout
|
|||
std::move (framesetterAndMap.fontMap) };
|
||||
}
|
||||
|
||||
static Range<float> getLineVerticalRange (CTFrameRef frame, CFArrayRef lines, int lineIndex)
|
||||
{
|
||||
LineInfo info (frame, (CTLineRef) CFArrayGetValueAtIndex (lines, lineIndex), lineIndex);
|
||||
|
||||
return { (float) (info.origin.y - info.descent),
|
||||
(float) (info.origin.y + info.ascent) };
|
||||
}
|
||||
|
||||
static float findCTFrameHeight (CTFrameRef frame)
|
||||
{
|
||||
auto lines = CTFrameGetLines (frame);
|
||||
auto numLines = CFArrayGetCount (lines);
|
||||
|
||||
if (numLines == 0)
|
||||
return 0;
|
||||
|
||||
auto range = getLineVerticalRange (frame, lines, 0);
|
||||
|
||||
if (numLines > 1)
|
||||
range = range.getUnionWith (getLineVerticalRange (frame, lines, (int) numLines - 1));
|
||||
|
||||
return range.getLength();
|
||||
}
|
||||
|
||||
static bool areAllFontsDefaultWidth (const AttributedString& text)
|
||||
{
|
||||
auto numCharacterAttributes = text.getNumAttributes();
|
||||
|
||||
for (int i = 0; i < numCharacterAttributes; ++i)
|
||||
if (text.getAttribute (i).font.getHorizontalScale() != 1.0f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drawToCGContext (const AttributedString& text, const Rectangle<float>& area,
|
||||
const CGContextRef& context, float flipHeight)
|
||||
{
|
||||
if (! areAllFontsDefaultWidth (text))
|
||||
return false;
|
||||
|
||||
auto framesetter = createCTFramesetter (text).framesetter;
|
||||
|
||||
// Ugly hack to fix a bug in OS X Sierra where the CTFrame needs to be slightly
|
||||
// larger than the font height - otherwise the CTFrame will be invalid
|
||||
|
||||
CFRange fitrange;
|
||||
auto suggestedSingleLineFrameSize =
|
||||
CTFramesetterSuggestFrameSizeWithConstraints (framesetter.get(), CFRangeMake (0, 0), nullptr,
|
||||
CGSizeMake (CGFLOAT_MAX, CGFLOAT_MAX), &fitrange);
|
||||
auto minCTFrameHeight = (float) suggestedSingleLineFrameSize.height;
|
||||
|
||||
auto verticalJustification = text.getJustification().getOnlyVerticalFlags();
|
||||
|
||||
auto ctFrameArea = [area, minCTFrameHeight, verticalJustification]
|
||||
{
|
||||
if (minCTFrameHeight < area.getHeight())
|
||||
return area;
|
||||
|
||||
if (verticalJustification == Justification::verticallyCentred)
|
||||
return area.withSizeKeepingCentre (area.getWidth(), minCTFrameHeight);
|
||||
|
||||
auto frameArea = area.withHeight (minCTFrameHeight);
|
||||
|
||||
if (verticalJustification == Justification::bottom)
|
||||
return frameArea.withBottomY (area.getBottom());
|
||||
|
||||
return frameArea;
|
||||
}();
|
||||
|
||||
auto frame = createCTFrame (framesetter.get(), CGRectMake ((CGFloat) ctFrameArea.getX(), flipHeight - (CGFloat) ctFrameArea.getBottom(),
|
||||
(CGFloat) ctFrameArea.getWidth(), (CGFloat) ctFrameArea.getHeight()));
|
||||
|
||||
auto textMatrix = CGContextGetTextMatrix (context);
|
||||
CGContextSaveGState (context);
|
||||
|
||||
if (verticalJustification == Justification::verticallyCentred
|
||||
|| verticalJustification == Justification::bottom)
|
||||
{
|
||||
auto adjust = ctFrameArea.getHeight() - findCTFrameHeight (frame.get());
|
||||
|
||||
if (verticalJustification == Justification::verticallyCentred)
|
||||
adjust *= 0.5f;
|
||||
|
||||
CGContextTranslateCTM (context, 0, -adjust);
|
||||
}
|
||||
|
||||
CTFrameDraw (frame.get(), context);
|
||||
|
||||
CGContextRestoreGState (context);
|
||||
CGContextSetTextMatrix (context, textMatrix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void createLayout (TextLayout& glyphLayout, const AttributedString& text)
|
||||
{
|
||||
auto boundsHeight = glyphLayout.getHeight();
|
||||
|
|
@ -567,7 +436,7 @@ namespace CoreTextTypeLayout
|
|||
CGColorRef cgRunColor;
|
||||
|
||||
if (CFDictionaryGetValueIfPresent (runAttributes, kCTForegroundColorAttributeName, (const void**) &cgRunColor)
|
||||
&& CGColorGetNumberOfComponents (cgRunColor) == 4)
|
||||
&& CGColorGetNumberOfComponents (cgRunColor) == 4)
|
||||
{
|
||||
auto* components = CGColorGetComponents (cgRunColor);
|
||||
|
||||
|
|
@ -592,31 +461,115 @@ namespace CoreTextTypeLayout
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class OSXTypeface final : public Typeface
|
||||
class CoreTextTypeface final : public Typeface
|
||||
{
|
||||
public:
|
||||
OSXTypeface (const Font& font)
|
||||
: Typeface (font.getTypefaceName(), font.getTypefaceStyle()), canBeUsedForLayout (true)
|
||||
static auto& getRegistered()
|
||||
{
|
||||
ctFontRef = CoreTextTypeLayout::createCTFont (font, referenceFontSize, renderingTransform);
|
||||
|
||||
if (ctFontRef != nullptr)
|
||||
class Registered
|
||||
{
|
||||
fontRef = CTFontCopyGraphicsFont (ctFontRef.get(), nullptr);
|
||||
initialiseMetrics();
|
||||
}
|
||||
public:
|
||||
void add (CTFontRef ref)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
CFUniquePtr<CGFontRef> cgFont { CTFontCopyGraphicsFont (ref, nullptr) };
|
||||
|
||||
if (CTFontManagerRegisterGraphicsFont (cgFont.get(), nullptr))
|
||||
map.emplace (ref, std::move (cgFont));
|
||||
}
|
||||
|
||||
void remove (CTFontRef ref)
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
if (const auto iter = map.find (ref); iter != map.end())
|
||||
{
|
||||
CTFontManagerUnregisterGraphicsFont (iter->second.get(), nullptr);
|
||||
map.erase (iter);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<String> getRegisteredFamilies() const
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
std::set<String> result;
|
||||
|
||||
for (const auto& item : map)
|
||||
{
|
||||
const CFUniquePtr<CFStringRef> family { CTFontCopyName (item.first, kCTFontFamilyNameKey) };
|
||||
result.insert (String::fromCFString (family.get()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<CTFontRef, CFUniquePtr<CGFontRef>> map;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
static Registered registered;
|
||||
return registered;
|
||||
}
|
||||
|
||||
OSXTypeface (const void* data, size_t dataSize)
|
||||
: Typeface ({}, {}), canBeUsedForLayout (false), dataCopy (data, dataSize)
|
||||
public:
|
||||
static Typeface::Ptr from (const Font& font)
|
||||
{
|
||||
CFUniquePtr<CFStringRef> cfFontFamily (FontStyleHelpers::getConcreteFamilyName (font).toCFString());
|
||||
|
||||
if (cfFontFamily == nullptr)
|
||||
return {};
|
||||
|
||||
CFUniquePtr<CFStringRef> cfFontStyle (findBestAvailableStyle (font).toCFString());
|
||||
|
||||
if (cfFontStyle == nullptr)
|
||||
return {};
|
||||
|
||||
CFStringRef keys[] { kCTFontFamilyNameAttribute, kCTFontStyleNameAttribute };
|
||||
CFTypeRef values[] { cfFontFamily.get(), cfFontStyle.get() };
|
||||
|
||||
CFUniquePtr<CFDictionaryRef> fontDescAttributes (CFDictionaryCreate (nullptr,
|
||||
(const void**) &keys,
|
||||
(const void**) &values,
|
||||
numElementsInArray (keys),
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
|
||||
if (fontDescAttributes == nullptr)
|
||||
return {};
|
||||
|
||||
CFUniquePtr<CTFontDescriptorRef> ctFontDescRef (CTFontDescriptorCreateWithAttributes (fontDescAttributes.get()));
|
||||
|
||||
if (ctFontDescRef == nullptr)
|
||||
return {};
|
||||
|
||||
CFUniquePtr<CTFontRef> ctFont { CTFontCreateWithFontDescriptor (ctFontDescRef.get(), 1, nullptr) };
|
||||
|
||||
if (ctFont == nullptr)
|
||||
return {};
|
||||
|
||||
HbFont result { hb_coretext_font_create (ctFont.get()) };
|
||||
|
||||
if (result == nullptr)
|
||||
return {};
|
||||
|
||||
FontStyleHelpers::initSynthetics (result.get(), font);
|
||||
|
||||
return new CoreTextTypeface (std::move (ctFont), std::move (result), font.getTypefaceName(), font.getTypefaceStyle());
|
||||
}
|
||||
|
||||
static Typeface::Ptr from (Span<const std::byte> data)
|
||||
{
|
||||
// We can't use CFDataCreate here as this triggers a false positive in ASAN
|
||||
// so copy the data manually and use CFDataCreateWithBytesNoCopy
|
||||
CFUniquePtr<CFDataRef> cfData (CFDataCreateWithBytesNoCopy (kCFAllocatorDefault, (const UInt8*) dataCopy.getData(),
|
||||
(CFIndex) dataCopy.getSize(), kCFAllocatorNull));
|
||||
auto provider = CGDataProviderCreateWithCFData (cfData.get());
|
||||
MemoryBlock copy { data.data(), data.size() };
|
||||
|
||||
const CFUniquePtr<CFDataRef> cfData { CFDataCreateWithBytesNoCopy (kCFAllocatorDefault,
|
||||
static_cast<const UInt8*> (copy.getData()),
|
||||
(CFIndex) copy.getSize(),
|
||||
kCFAllocatorNull) };
|
||||
|
||||
if (cfData == nullptr)
|
||||
return {};
|
||||
|
||||
#if JUCE_IOS
|
||||
// Workaround for a an obscure iOS bug which can cause the app to dead-lock
|
||||
|
|
@ -625,79 +578,65 @@ public:
|
|||
[UIFont systemFontOfSize: 12];
|
||||
#endif
|
||||
|
||||
fontRef = CGFontCreateWithDataProvider (provider);
|
||||
CGDataProviderRelease (provider);
|
||||
const CFUniquePtr<CGDataProviderRef> provider { CGDataProviderCreateWithCFData (cfData.get()) };
|
||||
|
||||
if (fontRef != nullptr)
|
||||
{
|
||||
if (@available (macOS 10.11, *))
|
||||
canBeUsedForLayout = CTFontManagerRegisterGraphicsFont (fontRef, nullptr);
|
||||
if (provider == nullptr)
|
||||
return {};
|
||||
|
||||
ctFontRef.reset (CTFontCreateWithGraphicsFont (fontRef, referenceFontSize, nullptr, nullptr));
|
||||
const CFUniquePtr<CGFontRef> font { CGFontCreateWithDataProvider (provider.get()) };
|
||||
|
||||
if (ctFontRef != nullptr)
|
||||
{
|
||||
if (auto fontName = CFUniquePtr<CFStringRef> (CTFontCopyName (ctFontRef.get(), kCTFontFamilyNameKey)))
|
||||
name = String::fromCFString (fontName.get());
|
||||
if (font == nullptr)
|
||||
return {};
|
||||
|
||||
if (auto fontStyle = CFUniquePtr<CFStringRef> (CTFontCopyName (ctFontRef.get(), kCTFontStyleNameKey)))
|
||||
style = String::fromCFString (fontStyle.get());
|
||||
CFUniquePtr<CTFontRef> ctFont { CTFontCreateWithGraphicsFont (font.get(), 1.0f, {}, {}) };
|
||||
|
||||
initialiseMetrics();
|
||||
}
|
||||
}
|
||||
if (ctFont == nullptr)
|
||||
return {};
|
||||
|
||||
HbFont result { hb_coretext_font_create (ctFont.get()) };
|
||||
|
||||
if (result == nullptr)
|
||||
return {};
|
||||
|
||||
const CFUniquePtr<CFStringRef> family { CTFontCopyName (ctFont.get(), kCTFontFamilyNameKey) };
|
||||
const CFUniquePtr<CFStringRef> style { CTFontCopyName (ctFont.get(), kCTFontStyleNameKey) };
|
||||
|
||||
return new CoreTextTypeface (std::move (ctFont),
|
||||
std::move (result),
|
||||
String::fromCFString (family.get()),
|
||||
String::fromCFString (style.get()),
|
||||
std::move (copy));
|
||||
}
|
||||
|
||||
void initialiseMetrics()
|
||||
Native getNativeDetails() const override
|
||||
{
|
||||
auto ctAscent = std::abs ((float) CTFontGetAscent (ctFontRef.get()));
|
||||
auto ctDescent = std::abs ((float) CTFontGetDescent (ctFontRef.get()));
|
||||
auto ctTotalHeight = ctAscent + ctDescent;
|
||||
|
||||
ascent = ctAscent / ctTotalHeight;
|
||||
unitsToHeightScaleFactor = 1.0f / ctTotalHeight;
|
||||
pathTransform = AffineTransform::scale (unitsToHeightScaleFactor);
|
||||
|
||||
fontHeightToPointsFactor = referenceFontSize / ctTotalHeight;
|
||||
|
||||
const short zero = 0;
|
||||
CFUniquePtr<CFNumberRef> numberRef (CFNumberCreate (nullptr, kCFNumberShortType, &zero));
|
||||
|
||||
CFStringRef keys[] = { kCTFontAttributeName, kCTLigatureAttributeName };
|
||||
CFTypeRef values[] = { ctFontRef.get(), numberRef.get() };
|
||||
attributedStringAtts.reset (CFDictionaryCreate (nullptr, (const void**) &keys,
|
||||
(const void**) &values, numElementsInArray (keys),
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||
return Native { hb.get() };
|
||||
}
|
||||
|
||||
~OSXTypeface() override
|
||||
static std::set<String> getRegisteredFamilies()
|
||||
{
|
||||
if (fontRef != nullptr)
|
||||
{
|
||||
if (@available (macOS 10.8, *))
|
||||
if (dataCopy.getSize() != 0)
|
||||
CTFontManagerUnregisterGraphicsFont (fontRef, nullptr);
|
||||
|
||||
CGFontRelease (fontRef);
|
||||
}
|
||||
return getRegistered().getRegisteredFamilies();
|
||||
}
|
||||
|
||||
float getAscent() const override { return ascent; }
|
||||
float getDescent() const override { return 1.0f - ascent; }
|
||||
float getHeightToPointsFactor() const override { return fontHeightToPointsFactor; }
|
||||
~CoreTextTypeface() override
|
||||
{
|
||||
getRegistered().remove (ctFont.get());
|
||||
}
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
if (ctFontRef != nullptr && text.isNotEmpty())
|
||||
if (ctFont != nullptr && text.isNotEmpty())
|
||||
{
|
||||
CFUniquePtr<CFStringRef> cfText (text.toCFString());
|
||||
CFUniquePtr<CFAttributedStringRef> attribString (CFAttributedStringCreate (kCFAllocatorDefault, cfText.get(), attributedStringAtts.get()));
|
||||
CFUniquePtr<CFAttributedStringRef> attribString (CFAttributedStringCreate (kCFAllocatorDefault, cfText.get(), getAttributedStringAtts().get()));
|
||||
|
||||
CFUniquePtr<CTLineRef> line (CTLineCreateWithAttributedString (attribString.get()));
|
||||
auto runArray = CTLineGetGlyphRuns (line.get());
|
||||
|
||||
const auto heightToPoints = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
|
||||
for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i)
|
||||
{
|
||||
auto run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i);
|
||||
|
|
@ -709,7 +648,7 @@ public:
|
|||
x += (float) advances.advances[j].width;
|
||||
}
|
||||
|
||||
x *= unitsToHeightScaleFactor;
|
||||
x *= heightToPoints;
|
||||
}
|
||||
|
||||
return x;
|
||||
|
|
@ -719,16 +658,18 @@ public:
|
|||
{
|
||||
xOffsets.add (0);
|
||||
|
||||
if (ctFontRef != nullptr && text.isNotEmpty())
|
||||
if (ctFont != nullptr && text.isNotEmpty())
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
CFUniquePtr<CFStringRef> cfText (text.toCFString());
|
||||
CFUniquePtr<CFAttributedStringRef> attribString (CFAttributedStringCreate (kCFAllocatorDefault, cfText.get(), attributedStringAtts.get()));
|
||||
CFUniquePtr<CFAttributedStringRef> attribString (CFAttributedStringCreate (kCFAllocatorDefault, cfText.get(), getAttributedStringAtts().get()));
|
||||
|
||||
CFUniquePtr<CTLineRef> line (CTLineCreateWithAttributedString (attribString.get()));
|
||||
auto runArray = CTLineGetGlyphRuns (line.get());
|
||||
|
||||
const auto heightToPointsFactor = getNativeDetails().getLegacyMetrics().getHeightToPointsFactor();
|
||||
|
||||
for (CFIndex i = 0; i < CFArrayGetCount (runArray); ++i)
|
||||
{
|
||||
auto run = (CTRunRef) CFArrayGetValueAtIndex (runArray, i);
|
||||
|
|
@ -740,93 +681,101 @@ public:
|
|||
for (int j = 0; j < length; ++j)
|
||||
{
|
||||
x += (float) advances.advances[j].width;
|
||||
xOffsets.add (x * unitsToHeightScaleFactor);
|
||||
xOffsets.add (x * heightToPointsFactor);
|
||||
resultGlyphs.add (glyphs.glyphs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& path) override
|
||||
CTFontRef getFontRef() const
|
||||
{
|
||||
jassert (path.isEmpty()); // we might need to apply a transform to the path, so this must be empty
|
||||
|
||||
if (auto pathRef = CFUniquePtr<CGPathRef> (CTFontCreatePathForGlyph (ctFontRef.get(), (CGGlyph) glyphNumber, &renderingTransform)))
|
||||
{
|
||||
CGPathApply (pathRef.get(), &path, pathApplier);
|
||||
|
||||
if (! pathTransform.isIdentity())
|
||||
path.applyTransform (pathTransform);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return ctFont.get();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
CGFontRef fontRef = {};
|
||||
CFUniquePtr<CTFontRef> ctFontRef;
|
||||
|
||||
float fontHeightToPointsFactor = 1.0f;
|
||||
CGAffineTransform renderingTransform = CGAffineTransformIdentity;
|
||||
|
||||
bool canBeUsedForLayout;
|
||||
|
||||
private:
|
||||
MemoryBlock dataCopy;
|
||||
CFUniquePtr<CFDictionaryRef> attributedStringAtts;
|
||||
float ascent = 0, unitsToHeightScaleFactor = 0;
|
||||
AffineTransform pathTransform;
|
||||
|
||||
static void pathApplier (void* info, const CGPathElement* element)
|
||||
CFUniquePtr<CFDictionaryRef> getAttributedStringAtts() const
|
||||
{
|
||||
auto& path = *static_cast<Path*> (info);
|
||||
auto* p = element->points;
|
||||
const short zero = 0;
|
||||
CFUniquePtr<CFNumberRef> numberRef (CFNumberCreate (nullptr, kCFNumberShortType, &zero));
|
||||
|
||||
switch (element->type)
|
||||
{
|
||||
case kCGPathElementMoveToPoint: path.startNewSubPath ((float) p[0].x, (float) -p[0].y); break;
|
||||
case kCGPathElementAddLineToPoint: path.lineTo ((float) p[0].x, (float) -p[0].y); break;
|
||||
case kCGPathElementAddQuadCurveToPoint: path.quadraticTo ((float) p[0].x, (float) -p[0].y,
|
||||
(float) p[1].x, (float) -p[1].y); break;
|
||||
case kCGPathElementAddCurveToPoint: path.cubicTo ((float) p[0].x, (float) -p[0].y,
|
||||
(float) p[1].x, (float) -p[1].y,
|
||||
(float) p[2].x, (float) -p[2].y); break;
|
||||
case kCGPathElementCloseSubpath: path.closeSubPath(); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
CFStringRef keys[] = { kCTFontAttributeName, kCTLigatureAttributeName };
|
||||
CFTypeRef values[] = { ctFont.get(), numberRef.get() };
|
||||
return CFUniquePtr<CFDictionaryRef> (CFDictionaryCreate (nullptr, (const void**) &keys,
|
||||
(const void**) &values, numElementsInArray (keys),
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface)
|
||||
CoreTextTypeface (CFUniquePtr<CTFontRef> nativeFont,
|
||||
HbFont fontIn,
|
||||
const String& name,
|
||||
const String& style,
|
||||
MemoryBlock data = {})
|
||||
: Typeface (name, style),
|
||||
ctFont (std::move (nativeFont)),
|
||||
hb (std::move (fontIn)),
|
||||
storage (std::move (data))
|
||||
{
|
||||
if (! storage.isEmpty())
|
||||
getRegistered().add (ctFont.get());
|
||||
}
|
||||
|
||||
static String findBestAvailableStyle (const Font& font)
|
||||
{
|
||||
const auto availableStyles = Font::findAllTypefaceStyles (font.getTypefaceName());
|
||||
const auto style = font.getTypefaceStyle();
|
||||
|
||||
if (availableStyles.contains (style))
|
||||
return style;
|
||||
|
||||
return availableStyles[0];
|
||||
}
|
||||
|
||||
// We store this, rather than calling hb_coretext_font_get_ct_font, because harfbuzz may
|
||||
// override the font cascade list in the returned font.
|
||||
CFUniquePtr<CTFontRef> ctFont;
|
||||
HbFont hb;
|
||||
MemoryBlock storage;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreTextTypeface)
|
||||
};
|
||||
|
||||
CTFontRef getCTFontFromTypeface (const Font& f)
|
||||
{
|
||||
const auto typeface = f.getTypefacePtr();
|
||||
|
||||
if (auto* tf = dynamic_cast<OSXTypeface*> (typeface.get()))
|
||||
return tf->ctFontRef.get();
|
||||
if (auto* tf = dynamic_cast<CoreTextTypeface*> (typeface.get()))
|
||||
return tf->getFontRef();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
return CoreTextTypeface::from (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
|
||||
{
|
||||
return CoreTextTypeface::from (data);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File& folder)
|
||||
{
|
||||
for (auto& file : folder.findChildFiles (File::findFiles, false, "*.otf;*.ttf"))
|
||||
if (auto urlref = CFUniquePtr<CFURLRef> (CFURLCreateWithFileSystemPath (kCFAllocatorDefault, file.getFullPathName().toCFString(), kCFURLPOSIXPathStyle, true)))
|
||||
CTFontManagerRegisterFontsForURL (urlref.get(), kCTFontManagerScopeProcess, nullptr);
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
StringArray names;
|
||||
|
||||
#if JUCE_MAC
|
||||
// CTFontManager only exists on OS X 10.6 and later, it does not exist on iOS
|
||||
CFUniquePtr<CFArrayRef> fontFamilyArray (CTFontManagerCopyAvailableFontFamilyNames());
|
||||
// The collection returned from CTFontCollectionCreateFromAvailableFonts doesn't include fonts registered by
|
||||
// CTFontManagerRegisterGraphicsFont on iOS, so we need to keep track of registered fonts ourselves.
|
||||
auto nameSet = CoreTextTypeface::getRegisteredFamilies();
|
||||
|
||||
for (CFIndex i = 0; i < CFArrayGetCount (fontFamilyArray.get()); ++i)
|
||||
{
|
||||
auto family = String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (fontFamilyArray.get(), i));
|
||||
|
||||
if (! family.startsWithChar ('.')) // ignore fonts that start with a '.'
|
||||
names.addIfNotAlreadyThere (family);
|
||||
}
|
||||
#else
|
||||
CFUniquePtr<CTFontCollectionRef> fontCollectionRef (CTFontCollectionCreateFromAvailableFonts (nullptr));
|
||||
CFUniquePtr<CFArrayRef> fontDescriptorArray (CTFontCollectionCreateMatchingFontDescriptors (fontCollectionRef.get()));
|
||||
|
||||
|
|
@ -835,11 +784,12 @@ StringArray Font::findAllTypefaceNames()
|
|||
auto ctFontDescriptorRef = (CTFontDescriptorRef) CFArrayGetValueAtIndex (fontDescriptorArray.get(), i);
|
||||
CFUniquePtr<CFStringRef> cfsFontFamily ((CFStringRef) CTFontDescriptorCopyAttribute (ctFontDescriptorRef, kCTFontFamilyNameAttribute));
|
||||
|
||||
names.addIfNotAlreadyThere (String::fromCFString (cfsFontFamily.get()));
|
||||
nameSet.insert (String::fromCFString (cfsFontFamily.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
names.sort (true);
|
||||
for (auto& item : nameSet)
|
||||
names.add (item);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
|
@ -851,8 +801,8 @@ StringArray Font::findAllTypefaceStyles (const String& family)
|
|||
StringArray results;
|
||||
|
||||
CFUniquePtr<CFStringRef> cfsFontFamily (family.toCFString());
|
||||
CFStringRef keys[] = { kCTFontFamilyNameAttribute };
|
||||
CFTypeRef values[] = { cfsFontFamily.get() };
|
||||
CFStringRef keys[] { kCTFontFamilyNameAttribute };
|
||||
CFTypeRef values[] { cfsFontFamily.get() };
|
||||
|
||||
CFUniquePtr<CFDictionaryRef> fontDescAttributes (CFDictionaryCreate (nullptr, (const void**) &keys, (const void**) &values, numElementsInArray (keys),
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||
|
|
@ -875,18 +825,6 @@ StringArray Font::findAllTypefaceStyles (const String& family)
|
|||
return results;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) { return *new OSXTypeface (font); }
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t size) { return *new OSXTypeface (data, size); }
|
||||
|
||||
void Typeface::scanFolderForFonts (const File& folder)
|
||||
{
|
||||
for (auto& file : folder.findChildFiles (File::findFiles, false, "*.otf;*.ttf"))
|
||||
if (auto urlref = CFUniquePtr<CFURLRef> (CFURLCreateWithFileSystemPath (kCFAllocatorDefault, file.getFullPathName().toCFString(), kCFURLPOSIXPathStyle, true)))
|
||||
CTFontManagerRegisterFontsForURL (urlref.get(), kCTFontManagerScopeProcess, nullptr);
|
||||
}
|
||||
|
||||
struct DefaultFontNames
|
||||
{
|
||||
#if JUCE_IOS
|
||||
|
|
@ -917,33 +855,10 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
|||
return Typeface::createSystemTypefaceFor (newFont);
|
||||
}
|
||||
|
||||
static bool canAllTypefacesBeUsedInLayout (const AttributedString& text)
|
||||
bool TextLayout::createNativeLayout (const AttributedString& text)
|
||||
{
|
||||
auto numCharacterAttributes = text.getNumAttributes();
|
||||
|
||||
for (int i = 0; i < numCharacterAttributes; ++i)
|
||||
{
|
||||
auto typeface = text.getAttribute (i).font.getTypefacePtr();
|
||||
|
||||
if (auto tf = dynamic_cast<OSXTypeface*> (typeface.get()))
|
||||
if (tf->canBeUsedForLayout)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CoreTextTypeLayout::createLayout (*this, text);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextLayout::createNativeLayout (const AttributedString& text)
|
||||
{
|
||||
if (canAllTypefacesBeUsedInLayout (text) && CoreTextTypeLayout::areAllFontsDefaultWidth (text))
|
||||
{
|
||||
CoreTextTypeLayout::createLayout (*this, text);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -1,642 +0,0 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/* This is some quick-and-dirty code to extract the typeface name from a lump of TTF file data.
|
||||
It's needed because although win32 will happily load a TTF file from in-memory data, it won't
|
||||
tell you the name of the damned font that it just loaded.. and in order to actually use the font,
|
||||
you need to know its name!! Anyway, this awful hack seems to work for most fonts.
|
||||
*/
|
||||
namespace TTFNameExtractor
|
||||
{
|
||||
struct OffsetTable
|
||||
{
|
||||
uint32 version;
|
||||
uint16 numTables, searchRange, entrySelector, rangeShift;
|
||||
};
|
||||
|
||||
struct TableDirectory
|
||||
{
|
||||
char tag[4];
|
||||
uint32 checkSum, offset, length;
|
||||
};
|
||||
|
||||
struct NamingTable
|
||||
{
|
||||
uint16 formatSelector;
|
||||
uint16 numberOfNameRecords;
|
||||
uint16 offsetStartOfStringStorage;
|
||||
};
|
||||
|
||||
struct NameRecord
|
||||
{
|
||||
uint16 platformID, encodingID, languageID;
|
||||
uint16 nameID, stringLength, offsetFromStorageArea;
|
||||
};
|
||||
|
||||
static String parseNameRecord (MemoryInputStream& input, const NameRecord& nameRecord,
|
||||
const int64 directoryOffset, const int64 offsetOfStringStorage)
|
||||
{
|
||||
String result;
|
||||
auto oldPos = input.getPosition();
|
||||
input.setPosition (directoryOffset + offsetOfStringStorage + ByteOrder::swapIfLittleEndian (nameRecord.offsetFromStorageArea));
|
||||
auto stringLength = (int) ByteOrder::swapIfLittleEndian (nameRecord.stringLength);
|
||||
auto platformID = ByteOrder::swapIfLittleEndian (nameRecord.platformID);
|
||||
|
||||
if (platformID == 0 || platformID == 3)
|
||||
{
|
||||
auto numChars = stringLength / 2 + 1;
|
||||
HeapBlock<uint16> buffer;
|
||||
buffer.calloc (numChars + 1);
|
||||
input.read (buffer, stringLength);
|
||||
|
||||
for (int i = 0; i < numChars; ++i)
|
||||
buffer[i] = ByteOrder::swapIfLittleEndian (buffer[i]);
|
||||
|
||||
static_assert (sizeof (CharPointer_UTF16::CharType) == sizeof (uint16), "Sanity check UTF-16 type");
|
||||
result = CharPointer_UTF16 ((CharPointer_UTF16::CharType*) buffer.getData());
|
||||
}
|
||||
else
|
||||
{
|
||||
HeapBlock<char> buffer;
|
||||
buffer.calloc (stringLength + 1);
|
||||
input.read (buffer, stringLength);
|
||||
result = CharPointer_UTF8 (buffer.getData());
|
||||
}
|
||||
|
||||
input.setPosition (oldPos);
|
||||
return result;
|
||||
}
|
||||
|
||||
static String parseNameTable (MemoryInputStream& input, int64 directoryOffset)
|
||||
{
|
||||
input.setPosition (directoryOffset);
|
||||
|
||||
NamingTable namingTable = {};
|
||||
input.read (&namingTable, sizeof (namingTable));
|
||||
|
||||
for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (namingTable.numberOfNameRecords); ++i)
|
||||
{
|
||||
NameRecord nameRecord = {};
|
||||
input.read (&nameRecord, sizeof (nameRecord));
|
||||
|
||||
if (ByteOrder::swapIfLittleEndian (nameRecord.nameID) == 4)
|
||||
{
|
||||
const String result (parseNameRecord (input, nameRecord, directoryOffset,
|
||||
ByteOrder::swapIfLittleEndian (namingTable.offsetStartOfStringStorage)));
|
||||
|
||||
if (result.isNotEmpty())
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static String getTypefaceNameFromFile (MemoryInputStream& input)
|
||||
{
|
||||
OffsetTable offsetTable = {};
|
||||
input.read (&offsetTable, sizeof (offsetTable));
|
||||
|
||||
for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (offsetTable.numTables); ++i)
|
||||
{
|
||||
TableDirectory tableDirectory;
|
||||
zerostruct (tableDirectory);
|
||||
input.read (&tableDirectory, sizeof (tableDirectory));
|
||||
|
||||
if (String (tableDirectory.tag, sizeof (tableDirectory.tag)).equalsIgnoreCase ("name"))
|
||||
return parseNameTable (input, ByteOrder::swapIfLittleEndian (tableDirectory.offset));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
namespace FontEnumerators
|
||||
{
|
||||
static int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
|
||||
{
|
||||
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
|
||||
{
|
||||
const String fontName (lpelfe->elfLogFont.lfFaceName);
|
||||
((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@"));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
|
||||
{
|
||||
if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
|
||||
{
|
||||
LOGFONTW lf = {};
|
||||
lf.lfWeight = FW_DONTCARE;
|
||||
lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
lf.lfQuality = DEFAULT_QUALITY;
|
||||
lf.lfCharSet = DEFAULT_CHARSET;
|
||||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
lf.lfPitchAndFamily = FF_DONTCARE;
|
||||
|
||||
const String fontName (lpelfe->elfLogFont.lfFaceName);
|
||||
fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
|
||||
|
||||
auto dc = CreateCompatibleDC (nullptr);
|
||||
EnumFontFamiliesEx (dc, &lf, (FONTENUMPROCW) &fontEnum2, lParam, 0);
|
||||
DeleteDC (dc);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceNames()
|
||||
{
|
||||
StringArray results;
|
||||
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
|
||||
if (factories->systemFonts != nullptr)
|
||||
{
|
||||
ComSmartPtr<IDWriteFontFamily> fontFamily;
|
||||
uint32 fontFamilyCount = 0;
|
||||
fontFamilyCount = factories->systemFonts->GetFontFamilyCount();
|
||||
|
||||
for (uint32 i = 0; i < fontFamilyCount; ++i)
|
||||
{
|
||||
auto hr = factories->systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress());
|
||||
|
||||
if (SUCCEEDED (hr))
|
||||
results.addIfNotAlreadyThere (getFontFamilyName (fontFamily));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
auto dc = CreateCompatibleDC (nullptr);
|
||||
|
||||
{
|
||||
LOGFONTW lf = {};
|
||||
lf.lfWeight = FW_DONTCARE;
|
||||
lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
lf.lfQuality = DEFAULT_QUALITY;
|
||||
lf.lfCharSet = DEFAULT_CHARSET;
|
||||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
lf.lfPitchAndFamily = FF_DONTCARE;
|
||||
|
||||
EnumFontFamiliesEx (dc, &lf,
|
||||
(FONTENUMPROCW) &FontEnumerators::fontEnum1,
|
||||
(LPARAM) &results, 0);
|
||||
}
|
||||
|
||||
DeleteDC (dc);
|
||||
}
|
||||
|
||||
results.sort (true);
|
||||
return results;
|
||||
}
|
||||
|
||||
StringArray Font::findAllTypefaceStyles (const String& family)
|
||||
{
|
||||
if (FontStyleHelpers::isPlaceholderFamilyName (family))
|
||||
return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family));
|
||||
|
||||
StringArray results;
|
||||
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
|
||||
if (factories->systemFonts != nullptr)
|
||||
{
|
||||
BOOL fontFound = false;
|
||||
uint32 fontIndex = 0;
|
||||
[[maybe_unused]] auto hr = factories->systemFonts->FindFamilyName (family.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> fontFamily;
|
||||
hr = factories->systemFonts->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());
|
||||
|
||||
// Get the font faces
|
||||
ComSmartPtr<IDWriteFont> dwFont;
|
||||
uint32 fontFacesCount = 0;
|
||||
fontFacesCount = fontFamily->GetFontCount();
|
||||
|
||||
for (uint32 i = 0; i < fontFacesCount; ++i)
|
||||
{
|
||||
hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());
|
||||
|
||||
// Ignore any algorithmically generated bold and oblique styles..
|
||||
if (dwFont->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE)
|
||||
results.addIfNotAlreadyThere (getFontFaceName (dwFont));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
results.add ("Regular");
|
||||
results.add ("Italic");
|
||||
results.add ("Bold");
|
||||
results.add ("Bold Italic");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
extern bool juce_isRunningInWine();
|
||||
|
||||
struct DefaultFontNames
|
||||
{
|
||||
DefaultFontNames()
|
||||
{
|
||||
if (juce_isRunningInWine())
|
||||
{
|
||||
// If we're running in Wine, then use fonts that might be available on Linux..
|
||||
defaultSans = "Bitstream Vera Sans";
|
||||
defaultSerif = "Bitstream Vera Serif";
|
||||
defaultFixed = "Bitstream Vera Sans Mono";
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultSans = "Verdana";
|
||||
defaultSerif = "Times New Roman";
|
||||
defaultFixed = "Lucida Console";
|
||||
defaultFallback = "Tahoma"; // (contains plenty of unicode characters)
|
||||
}
|
||||
}
|
||||
|
||||
String defaultSans, defaultSerif, defaultFixed, defaultFallback;
|
||||
};
|
||||
|
||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||
{
|
||||
static DefaultFontNames defaultNames;
|
||||
|
||||
Font newFont (font);
|
||||
auto faceName = font.getTypefaceName();
|
||||
|
||||
if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans);
|
||||
else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif);
|
||||
else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed);
|
||||
|
||||
if (font.getTypefaceStyle() == getDefaultStyle())
|
||||
newFont.setTypefaceStyle ("Regular");
|
||||
|
||||
return Typeface::createSystemTypefaceFor (newFont);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class WindowsTypeface final : public Typeface
|
||||
{
|
||||
public:
|
||||
WindowsTypeface (const Font& font) : Typeface (font.getTypefaceName(),
|
||||
font.getTypefaceStyle())
|
||||
{
|
||||
loadFont();
|
||||
}
|
||||
|
||||
WindowsTypeface (const void* data, size_t dataSize)
|
||||
: Typeface (String(), String())
|
||||
{
|
||||
DWORD numInstalled = 0;
|
||||
memoryFont = AddFontMemResourceEx (const_cast<void*> (data), (DWORD) dataSize,
|
||||
nullptr, &numInstalled);
|
||||
|
||||
MemoryInputStream m (data, dataSize, false);
|
||||
name = TTFNameExtractor::getTypefaceNameFromFile (m);
|
||||
loadFont();
|
||||
}
|
||||
|
||||
~WindowsTypeface() override
|
||||
{
|
||||
SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker
|
||||
DeleteDC (dc);
|
||||
|
||||
if (fontH != nullptr)
|
||||
DeleteObject (fontH);
|
||||
|
||||
if (memoryFont != nullptr)
|
||||
RemoveFontMemResourceEx (memoryFont);
|
||||
}
|
||||
|
||||
float getAscent() const override { return ascent; }
|
||||
float getDescent() const override { return 1.0f - ascent; }
|
||||
float getHeightToPointsFactor() const override { return heightToPointsFactor; }
|
||||
|
||||
float getStringWidth (const String& text) override
|
||||
{
|
||||
auto utf16 = text.toUTF16();
|
||||
auto numChars = utf16.length();
|
||||
HeapBlock<uint16> results (numChars);
|
||||
float x = 0;
|
||||
|
||||
if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast<WORD*> (results.getData()),
|
||||
GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
|
||||
{
|
||||
for (size_t i = 0; i < numChars; ++i)
|
||||
x += getKerning (dc, results[i], (i + 1) < numChars ? results[i + 1] : -1);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets) override
|
||||
{
|
||||
auto utf16 = text.toUTF16();
|
||||
auto numChars = utf16.length();
|
||||
HeapBlock<uint16> results (numChars);
|
||||
float x = 0;
|
||||
|
||||
if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast<WORD*> (results.getData()),
|
||||
GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
|
||||
{
|
||||
resultGlyphs.ensureStorageAllocated ((int) numChars);
|
||||
xOffsets.ensureStorageAllocated ((int) numChars + 1);
|
||||
|
||||
for (size_t i = 0; i < numChars; ++i)
|
||||
{
|
||||
resultGlyphs.add (results[i]);
|
||||
xOffsets.add (x);
|
||||
x += getKerning (dc, results[i], (i + 1) < numChars ? results[i + 1] : -1);
|
||||
}
|
||||
}
|
||||
|
||||
xOffsets.add (x);
|
||||
}
|
||||
|
||||
bool getOutlineForGlyph (int glyphNumber, Path& glyphPath) override
|
||||
{
|
||||
if (glyphNumber < 0)
|
||||
glyphNumber = defaultGlyph;
|
||||
|
||||
GLYPHMETRICS gm;
|
||||
// (although GetGlyphOutline returns a DWORD, it may be -1 on failure, so treat it as signed int..)
|
||||
auto bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX,
|
||||
&gm, 0, nullptr, &identityMatrix);
|
||||
|
||||
if (bufSize > 0)
|
||||
{
|
||||
HeapBlock<char> data (bufSize);
|
||||
GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm,
|
||||
(DWORD) bufSize, data, &identityMatrix);
|
||||
|
||||
auto pheader = reinterpret_cast<const TTPOLYGONHEADER*> (data.getData());
|
||||
|
||||
auto scaleX = 1.0f / (float) tm.tmHeight;
|
||||
auto scaleY = -scaleX;
|
||||
|
||||
while ((char*) pheader < data + bufSize)
|
||||
{
|
||||
glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value,
|
||||
scaleY * pheader->pfxStart.y.value);
|
||||
|
||||
auto curve = unalignedPointerCast<const TTPOLYCURVE*> ((const char*) pheader + sizeof (TTPOLYGONHEADER));
|
||||
auto curveEnd = ((const char*) pheader) + pheader->cb;
|
||||
|
||||
while ((const char*) curve < curveEnd)
|
||||
{
|
||||
if (curve->wType == TT_PRIM_LINE)
|
||||
{
|
||||
for (int i = 0; i < curve->cpfx; ++i)
|
||||
glyphPath.lineTo (scaleX * curve->apfx[i].x.value,
|
||||
scaleY * curve->apfx[i].y.value);
|
||||
}
|
||||
else if (curve->wType == TT_PRIM_QSPLINE)
|
||||
{
|
||||
for (int i = 0; i < curve->cpfx - 1; ++i)
|
||||
{
|
||||
auto x2 = scaleX * curve->apfx[i].x.value;
|
||||
auto y2 = scaleY * curve->apfx[i].y.value;
|
||||
auto x3 = scaleX * curve->apfx[i + 1].x.value;
|
||||
auto y3 = scaleY * curve->apfx[i + 1].y.value;
|
||||
|
||||
if (i < curve->cpfx - 2)
|
||||
{
|
||||
x3 = 0.5f * (x2 + x3);
|
||||
y3 = 0.5f * (y2 + y3);
|
||||
}
|
||||
|
||||
glyphPath.quadraticTo (x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
|
||||
}
|
||||
|
||||
pheader = unalignedPointerCast<const TTPOLYGONHEADER*> (curve);
|
||||
|
||||
glyphPath.closeSubPath();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static const MAT2 identityMatrix;
|
||||
HFONT fontH = {};
|
||||
HGDIOBJ previousFontH = {};
|
||||
HDC dc { CreateCompatibleDC (nullptr) };
|
||||
TEXTMETRIC tm;
|
||||
HANDLE memoryFont = {};
|
||||
float ascent = 1.0f, heightToPointsFactor = 1.0f;
|
||||
int defaultGlyph = -1, heightInPoints = 0;
|
||||
std::unordered_map<uint64, float> kerningPairs;
|
||||
|
||||
static uint64 kerningPairIndex (int glyph1, int glyph2)
|
||||
{
|
||||
return (((uint64) (uint32) glyph1) << 32) | (uint64) (uint32) glyph2;
|
||||
}
|
||||
|
||||
void loadFont()
|
||||
{
|
||||
SetMapperFlags (dc, 0);
|
||||
SetMapMode (dc, MM_TEXT);
|
||||
|
||||
LOGFONTW lf = {};
|
||||
lf.lfCharSet = DEFAULT_CHARSET;
|
||||
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
||||
lf.lfQuality = PROOF_QUALITY;
|
||||
lf.lfItalic = (BYTE) (style.contains ("Italic") ? TRUE : FALSE);
|
||||
lf.lfWeight = style.contains ("Bold") ? FW_BOLD : FW_NORMAL;
|
||||
lf.lfHeight = -256;
|
||||
name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
|
||||
|
||||
auto standardSizedFont = CreateFontIndirect (&lf);
|
||||
|
||||
if (standardSizedFont != nullptr)
|
||||
{
|
||||
if ((previousFontH = SelectObject (dc, standardSizedFont)) != nullptr)
|
||||
{
|
||||
fontH = standardSizedFont;
|
||||
OUTLINETEXTMETRIC otm;
|
||||
|
||||
if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
|
||||
{
|
||||
heightInPoints = (int) otm.otmEMSquare;
|
||||
lf.lfHeight = -heightInPoints;
|
||||
fontH = CreateFontIndirect (&lf);
|
||||
|
||||
SelectObject (dc, fontH);
|
||||
DeleteObject (standardSizedFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetTextMetrics (dc, &tm))
|
||||
{
|
||||
auto dpi = (float) (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f;
|
||||
heightToPointsFactor = (dpi / (float) GetDeviceCaps (dc, LOGPIXELSY)) * (float) heightInPoints / (float) tm.tmHeight;
|
||||
ascent = (float) tm.tmAscent / (float) tm.tmHeight;
|
||||
std::unordered_map<int, int> glyphsForChars;
|
||||
defaultGlyph = getGlyphForChar (dc, glyphsForChars, tm.tmDefaultChar);
|
||||
createKerningPairs (dc, glyphsForChars, (float) tm.tmHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void createKerningPairs (HDC hdc, std::unordered_map<int, int>& glyphsForChars, float height)
|
||||
{
|
||||
HeapBlock<KERNINGPAIR> rawKerning;
|
||||
auto numKPs = GetKerningPairs (hdc, 0, nullptr);
|
||||
rawKerning.calloc (numKPs);
|
||||
GetKerningPairs (hdc, numKPs, rawKerning);
|
||||
|
||||
std::unordered_map<int, int> widthsForGlyphs;
|
||||
|
||||
for (DWORD i = 0; i < numKPs; ++i)
|
||||
{
|
||||
auto glyph1 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wFirst);
|
||||
auto glyph2 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wSecond);
|
||||
auto standardWidth = getGlyphWidth (hdc, widthsForGlyphs, glyph1);
|
||||
|
||||
kerningPairs[kerningPairIndex (glyph1, glyph2)] = (float) (standardWidth + rawKerning[i].iKernAmount) / height;
|
||||
kerningPairs[kerningPairIndex (glyph1, -1)] = (float) standardWidth / height;
|
||||
}
|
||||
}
|
||||
|
||||
static int getGlyphForChar (HDC dc, std::unordered_map<int, int>& cache, juce_wchar character)
|
||||
{
|
||||
auto existing = cache.find ((int) character);
|
||||
|
||||
if (existing != cache.end())
|
||||
return existing->second;
|
||||
|
||||
const WCHAR charToTest[] = { (WCHAR) character, 0 };
|
||||
WORD index = 0;
|
||||
|
||||
if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR
|
||||
|| index == 0xffff)
|
||||
return -1;
|
||||
|
||||
cache[(int) character] = index;
|
||||
return index;
|
||||
}
|
||||
|
||||
static int getGlyphWidth (HDC dc, std::unordered_map<int, int>& cache, int glyphNumber)
|
||||
{
|
||||
auto existing = cache.find (glyphNumber);
|
||||
|
||||
if (existing != cache.end())
|
||||
return existing->second;
|
||||
|
||||
auto width = getGlyphWidth (dc, glyphNumber);
|
||||
cache[glyphNumber] = width;
|
||||
return width;
|
||||
}
|
||||
|
||||
static int getGlyphWidth (HDC dc, int glyphNumber)
|
||||
{
|
||||
GLYPHMETRICS gm;
|
||||
gm.gmCellIncX = 0;
|
||||
GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &identityMatrix);
|
||||
return gm.gmCellIncX;
|
||||
}
|
||||
|
||||
float getKerning (HDC hdc, int glyph1, int glyph2)
|
||||
{
|
||||
auto pair = kerningPairs.find (kerningPairIndex (glyph1, glyph2));
|
||||
|
||||
if (pair != kerningPairs.end())
|
||||
return pair->second;
|
||||
|
||||
auto single = kerningPairs.find (kerningPairIndex (glyph1, -1));
|
||||
|
||||
if (single != kerningPairs.end())
|
||||
return single->second;
|
||||
|
||||
auto width = (float) getGlyphWidth (hdc, glyph1) / (float) tm.tmHeight;
|
||||
kerningPairs[kerningPairIndex (glyph1, -1)] = width;
|
||||
return width;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface)
|
||||
};
|
||||
|
||||
const MAT2 WindowsTypeface::identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
|
||||
{
|
||||
#if JUCE_USE_DIRECTWRITE
|
||||
SharedResourcePointer<Direct2DFactories> factories;
|
||||
|
||||
if (factories->systemFonts != nullptr)
|
||||
{
|
||||
std::unique_ptr<WindowsDirectWriteTypeface> wtf (new WindowsDirectWriteTypeface (font, factories->systemFonts));
|
||||
|
||||
if (wtf->loadedOk() && wtf->isFontFound())
|
||||
return wtf.release();
|
||||
}
|
||||
#endif
|
||||
|
||||
return new WindowsTypeface (font);
|
||||
}
|
||||
|
||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize)
|
||||
{
|
||||
return new WindowsTypeface (data, dataSize);
|
||||
}
|
||||
|
||||
void Typeface::scanFolderForFonts (const File&)
|
||||
{
|
||||
jassertfalse; // not implemented on this platform
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -35,6 +35,49 @@
|
|||
namespace juce::RenderingHelpers
|
||||
{
|
||||
|
||||
template <typename Context>
|
||||
void drawGlyphImpl (Context& context, int glyphNumber, const AffineTransform& trans)
|
||||
{
|
||||
using GlyphCacheType = typename Context::GlyphCacheType;
|
||||
using EdgeTableRegionType = typename Context::EdgeTableRegionType;
|
||||
|
||||
if (context.clip == nullptr)
|
||||
return;
|
||||
|
||||
if (trans.isOnlyTranslation() && ! context.transform.isRotated)
|
||||
{
|
||||
auto& cache = GlyphCacheType::getInstance();
|
||||
const Point pos (trans.getTranslationX(), trans.getTranslationY());
|
||||
|
||||
if (context.transform.isOnlyTranslated)
|
||||
{
|
||||
cache.drawGlyph (context, context.font, glyphNumber, pos + context.transform.offset.toFloat());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto f = context.font;
|
||||
f.setHeight (f.getHeight() * context.transform.complexTransform.mat11);
|
||||
|
||||
auto xScale = context.transform.complexTransform.mat00 / context.transform.complexTransform.mat11;
|
||||
|
||||
if (std::abs (xScale - 1.0f) > 0.01f)
|
||||
f.setHorizontalScale (xScale);
|
||||
|
||||
cache.drawGlyph (context, f, glyphNumber, context.transform.transformed (pos));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto fontHeight = context.font.getHeight();
|
||||
const auto fontTransform = AffineTransform::scale (fontHeight * context.font.getHorizontalScale(),
|
||||
fontHeight).followedBy (trans);
|
||||
const auto fullTransform = context.transform.getTransformWith (fontTransform);
|
||||
|
||||
if (auto et = rawToUniquePtr (context.font.getTypefacePtr()->getEdgeTableForGlyph (glyphNumber, fullTransform, fontHeight)))
|
||||
context.fillShape (*new EdgeTableRegionType (*et), false);
|
||||
}
|
||||
}
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127)
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -190,6 +233,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedArray<CachedGlyphType> glyphs;
|
||||
Atomic<int> accessCounter, hits, misses;
|
||||
CriticalSection lock;
|
||||
|
||||
ReferenceCountedObjectPtr<CachedGlyphType> findOrCreateGlyph (const Font& font, int glyphNumber)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
|
@ -207,11 +255,6 @@ public:
|
|||
return g;
|
||||
}
|
||||
|
||||
private:
|
||||
ReferenceCountedArray<CachedGlyphType> glyphs;
|
||||
Atomic<int> accessCounter, hits, misses;
|
||||
CriticalSection lock;
|
||||
|
||||
ReferenceCountedObjectPtr<CachedGlyphType> findExistingGlyph (const Font& font, int glyphNumber) const noexcept
|
||||
{
|
||||
for (auto g : glyphs)
|
||||
|
|
@ -287,9 +330,6 @@ public:
|
|||
|
||||
void draw (RendererType& state, Point<float> pos) const
|
||||
{
|
||||
if (snapToIntegerCoordinate)
|
||||
pos.x = std::floor (pos.x + 0.5f);
|
||||
|
||||
if (edgeTable != nullptr)
|
||||
state.fillEdgeTable (*edgeTable, pos.x, roundToInt (pos.y));
|
||||
}
|
||||
|
|
@ -298,7 +338,6 @@ public:
|
|||
{
|
||||
font = newFont;
|
||||
auto typeface = newFont.getTypefacePtr();
|
||||
snapToIntegerCoordinate = typeface->isHinted();
|
||||
glyph = glyphNumber;
|
||||
|
||||
auto fontHeight = font.getHeight();
|
||||
|
|
@ -310,7 +349,6 @@ public:
|
|||
Font font;
|
||||
std::unique_ptr<EdgeTable> edgeTable;
|
||||
int glyph = 0, lastAccessCount = 0;
|
||||
bool snapToIntegerCoordinate = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable)
|
||||
};
|
||||
|
|
@ -2542,45 +2580,7 @@ public:
|
|||
//==============================================================================
|
||||
void drawGlyph (int glyphNumber, const AffineTransform& trans)
|
||||
{
|
||||
if (clip != nullptr)
|
||||
{
|
||||
if (trans.isOnlyTranslation() && ! transform.isRotated)
|
||||
{
|
||||
auto& cache = GlyphCacheType::getInstance();
|
||||
Point<float> pos (trans.getTranslationX(), trans.getTranslationY());
|
||||
|
||||
if (transform.isOnlyTranslated)
|
||||
{
|
||||
cache.drawGlyph (*this, font, glyphNumber, pos + transform.offset.toFloat());
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = transform.transformed (pos);
|
||||
|
||||
Font f (font);
|
||||
f.setHeight (font.getHeight() * transform.complexTransform.mat11);
|
||||
|
||||
auto xScale = transform.complexTransform.mat00 / transform.complexTransform.mat11;
|
||||
|
||||
if (std::abs (xScale - 1.0f) > 0.01f)
|
||||
f.setHorizontalScale (xScale);
|
||||
|
||||
cache.drawGlyph (*this, f, glyphNumber, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto fontHeight = font.getHeight();
|
||||
|
||||
auto t = transform.getTransformWith (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)
|
||||
.followedBy (trans));
|
||||
|
||||
std::unique_ptr<EdgeTable> et (font.getTypefacePtr()->getEdgeTableForGlyph (glyphNumber, t, fontHeight));
|
||||
|
||||
if (et != nullptr)
|
||||
fillShape (*new EdgeTableRegionType (*et), false);
|
||||
}
|
||||
}
|
||||
drawGlyphImpl (*this, glyphNumber, trans);
|
||||
}
|
||||
|
||||
Rectangle<int> getMaximumBounds() const { return image.getBounds(); }
|
||||
|
|
@ -2706,34 +2706,35 @@ template <class SavedStateType>
|
|||
class StackBasedLowLevelGraphicsContext : public LowLevelGraphicsContext
|
||||
{
|
||||
public:
|
||||
bool isVectorDevice() const override { return false; }
|
||||
void setOrigin (Point<int> o) override { stack->transform.setOrigin (o); }
|
||||
void addTransform (const AffineTransform& t) override { stack->transform.addTransform (t); }
|
||||
float getPhysicalPixelScaleFactor() override { return stack->transform.getPhysicalPixelScaleFactor(); }
|
||||
Rectangle<int> getClipBounds() const override { return stack->getClipBounds(); }
|
||||
bool isClipEmpty() const override { return stack->clip == nullptr; }
|
||||
bool clipRegionIntersects (const Rectangle<int>& r) override { return stack->clipRegionIntersects (r); }
|
||||
bool clipToRectangle (const Rectangle<int>& r) override { return stack->clipToRectangle (r); }
|
||||
bool clipToRectangleList (const RectangleList<int>& r) override { return stack->clipToRectangleList (r); }
|
||||
void excludeClipRectangle (const Rectangle<int>& r) override { stack->excludeClipRectangle (r); }
|
||||
void clipToPath (const Path& path, const AffineTransform& t) override { stack->clipToPath (path, t); }
|
||||
void clipToImageAlpha (const Image& im, const AffineTransform& t) override { stack->clipToImageAlpha (im, t); }
|
||||
void saveState() override { stack.save(); }
|
||||
void restoreState() override { stack.restore(); }
|
||||
void beginTransparencyLayer (float opacity) override { stack.beginTransparencyLayer (opacity); }
|
||||
void endTransparencyLayer() override { stack.endTransparencyLayer(); }
|
||||
void setFill (const FillType& fillType) override { stack->setFillType (fillType); }
|
||||
void setOpacity (float newOpacity) override { stack->fillType.setOpacity (newOpacity); }
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality quality) override { stack->interpolationQuality = quality; }
|
||||
void fillRect (const Rectangle<int>& r, bool replace) override { stack->fillRect (r, replace); }
|
||||
void fillRect (const Rectangle<float>& r) override { stack->fillRect (r); }
|
||||
void fillRectList (const RectangleList<float>& list) override { stack->fillRectList (list); }
|
||||
void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); }
|
||||
void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); }
|
||||
void drawGlyph (int glyphNumber, const AffineTransform& t) override { stack->drawGlyph (glyphNumber, t); }
|
||||
void drawLine (const Line<float>& line) override { stack->drawLine (line); }
|
||||
void setFont (const Font& newFont) override { stack->font = newFont; }
|
||||
const Font& getFont() override { return stack->font; }
|
||||
bool isVectorDevice() const override { return false; }
|
||||
Rectangle<int> getClipBounds() const override { return stack->getClipBounds(); }
|
||||
bool isClipEmpty() const override { return stack->clip == nullptr; }
|
||||
|
||||
void setOrigin (Point<int> o) override { stack->transform.setOrigin (o); }
|
||||
void addTransform (const AffineTransform& t) override { stack->transform.addTransform (t); }
|
||||
float getPhysicalPixelScaleFactor() override { return stack->transform.getPhysicalPixelScaleFactor(); }
|
||||
bool clipRegionIntersects (const Rectangle<int>& r) override { return stack->clipRegionIntersects (r); }
|
||||
bool clipToRectangle (const Rectangle<int>& r) override { return stack->clipToRectangle (r); }
|
||||
bool clipToRectangleList (const RectangleList<int>& r) override { return stack->clipToRectangleList (r); }
|
||||
void excludeClipRectangle (const Rectangle<int>& r) override { stack->excludeClipRectangle (r); }
|
||||
void clipToPath (const Path& path, const AffineTransform& t) override { stack->clipToPath (path, t); }
|
||||
void clipToImageAlpha (const Image& im, const AffineTransform& t) override { stack->clipToImageAlpha (im, t); }
|
||||
void saveState() override { stack.save(); }
|
||||
void restoreState() override { stack.restore(); }
|
||||
void beginTransparencyLayer (float opacity) override { stack.beginTransparencyLayer (opacity); }
|
||||
void endTransparencyLayer() override { stack.endTransparencyLayer(); }
|
||||
void setFill (const FillType& fillType) override { stack->setFillType (fillType); }
|
||||
void setOpacity (float newOpacity) override { stack->fillType.setOpacity (newOpacity); }
|
||||
void setInterpolationQuality (Graphics::ResamplingQuality quality) override { stack->interpolationQuality = quality; }
|
||||
void fillRect (const Rectangle<int>& r, bool replace) override { stack->fillRect (r, replace); }
|
||||
void fillRect (const Rectangle<float>& r) override { stack->fillRect (r); }
|
||||
void fillRectList (const RectangleList<float>& list) override { stack->fillRectList (list); }
|
||||
void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); }
|
||||
void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); }
|
||||
void drawGlyph (int i, const AffineTransform& t) override { stack->drawGlyph (i, t); }
|
||||
void drawLine (const Line<float>& line) override { stack->drawLine (line); }
|
||||
void setFont (const Font& newFont) override { stack->font = newFont; }
|
||||
const Font& getFont() override { return stack->font; }
|
||||
|
||||
protected:
|
||||
StackBasedLowLevelGraphicsContext (SavedStateType* initialState) : stack (initialState) {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue