JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_Typeface.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
31 static const char* getStyleName (const bool bold,
32 const bool italic) noexcept
33 {
34 if (bold && italic) return "Bold Italic";
35 if (bold) return "Bold";
36 if (italic) return "Italic";
37 return "Regular";
38 }
39
40 static const char* getStyleName (const int styleFlags) noexcept
41 {
42 return getStyleName ((styleFlags & Font::bold) != 0,
43 (styleFlags & Font::italic) != 0);
44 }
45
46 static bool isBold (const String& style) noexcept
47 {
48 return style.containsWholeWordIgnoreCase ("Bold");
49 }
50
51 static bool isItalic (const String& style) noexcept
52 {
53 return style.containsWholeWordIgnoreCase ("Italic")
54 || style.containsWholeWordIgnoreCase ("Oblique");
55 }
56
57 static bool isPlaceholderFamilyName (const String& family)
58 {
59 return family == Font::getDefaultSansSerifFontName()
62 }
63
65 {
67 : sans (findName (Font::getDefaultSansSerifFontName())),
68 serif (findName (Font::getDefaultSerifFontName())),
69 mono (findName (Font::getDefaultMonospacedFontName()))
70 {
71 }
72
73 String lookUp (const String& placeholder)
74 {
76 if (placeholder == Font::getDefaultSerifFontName()) return serif;
78
79 return findName (placeholder);
80 }
81
82 private:
83 static String findName (const String& placeholder)
84 {
85 const Font f (placeholder, Font::getDefaultStyle(), 15.0f);
87 }
88
89 String sans, serif, mono;
90 };
91
92 static String getConcreteFamilyNameFromPlaceholder (const String& placeholder)
93 {
94 static ConcreteFamilyNames names;
95 return names.lookUp (placeholder);
96 }
97
98 static String getConcreteFamilyName (const Font& font)
99 {
100 const String& family = font.getTypefaceName();
101
102 return isPlaceholderFamilyName (family) ? getConcreteFamilyNameFromPlaceholder (family)
103 : family;
104 }
105};
106
107//==============================================================================
109{
111 {
112 Font font (t);
113 font = font.withHeight ((float) standardHeight);
114
115 top = getAverageY (font, "BDEFPRTZOQ", true);
116 middle = getAverageY (font, "acegmnopqrsuvwxy", true);
117 bottom = getAverageY (font, "BDELZOC", false);
118 }
119
120 void applyVerticalHintingTransform (float fontSize, Path& path)
121 {
122 if (! approximatelyEqual (cachedSize, fontSize))
123 {
124 cachedSize = fontSize;
125 cachedScale = Scaling (top, middle, bottom, fontSize);
126 }
127
128 if (bottom < top + 3.0f / fontSize)
129 return;
130
131 Path result;
132
133 for (Path::Iterator i (path); i.next();)
134 {
135 switch (i.elementType)
136 {
137 case Path::Iterator::startNewSubPath: result.startNewSubPath (i.x1, cachedScale.apply (i.y1)); break;
138 case Path::Iterator::lineTo: result.lineTo (i.x1, cachedScale.apply (i.y1)); break;
139 case Path::Iterator::quadraticTo: result.quadraticTo (i.x1, cachedScale.apply (i.y1),
140 i.x2, cachedScale.apply (i.y2)); break;
141 case Path::Iterator::cubicTo: result.cubicTo (i.x1, cachedScale.apply (i.y1),
142 i.x2, cachedScale.apply (i.y2),
143 i.x3, cachedScale.apply (i.y3)); break;
144 case Path::Iterator::closePath: result.closeSubPath(); break;
145 default: jassertfalse; break;
146 }
147 }
148
149 result.swapWithPath (path);
150 }
151
152private:
153 struct Scaling
154 {
155 Scaling() noexcept : middle(), upperScale(), upperOffset(), lowerScale(), lowerOffset() {}
156
157 Scaling (float t, float m, float b, float fontSize) noexcept : middle (m)
158 {
159 const float newT = std::floor (fontSize * t + 0.5f) / fontSize;
160 const float newB = std::floor (fontSize * b + 0.5f) / fontSize;
161 const float newM = std::floor (fontSize * m + 0.3f) / fontSize; // this is slightly biased so that lower-case letters
162 // are more likely to become taller than shorter.
163 upperScale = jlimit (0.9f, 1.1f, (newM - newT) / (m - t));
164 lowerScale = jlimit (0.9f, 1.1f, (newB - newM) / (b - m));
165
166 upperOffset = newM - m * upperScale;
167 lowerOffset = newB - b * lowerScale;
168 }
169
170 float apply (float y) const noexcept
171 {
172 return y < middle ? (y * upperScale + upperOffset)
173 : (y * lowerScale + lowerOffset);
174 }
175
176 float middle, upperScale, upperOffset, lowerScale, lowerOffset;
177 };
178
179 float cachedSize = 0;
180 Scaling cachedScale;
181
182 static float getAverageY (const Font& font, const char* chars, bool getTop)
183 {
185 ga.addLineOfText (font, chars, 0, 0);
186
188
189 for (auto& glyph : ga)
190 {
191 Path p;
192 glyph.createPath (p);
193 auto bounds = p.getBounds();
194
195 if (! p.isEmpty())
196 yValues.add (getTop ? bounds.getY() : bounds.getBottom());
197 }
198
199 std::sort (yValues.begin(), yValues.end());
200
201 auto median = yValues[yValues.size() / 2];
202 float total = 0;
203 int num = 0;
204
205 for (auto y : yValues)
206 {
207 if (std::abs (median - y) < 0.05f * (float) standardHeight)
208 {
209 total += y;
210 ++num;
211 }
212 }
213
214 return num < 4 ? 0.0f : total / ((float) num * (float) standardHeight);
215 }
216
217 enum { standardHeight = 100 };
218 float top = 0, middle = 0, bottom = 0;
219};
220
222{
223 if (fontSize > 3.0f && fontSize < 25.0f)
224 {
225 ScopedLock sl (hintingLock);
226
227 if (hintingParams == nullptr)
228 hintingParams.reset (new HintingParams (*this));
229
230 return hintingParams->applyVerticalHintingTransform (fontSize, path);
231 }
232}
233
234//==============================================================================
235Typeface::Typeface (const String& faceName, const String& styleName) noexcept
236 : name (faceName), style (styleName)
237{
238}
239
240Typeface::~Typeface() = default;
241
242Typeface::Ptr Typeface::getFallbackTypeface()
243{
244 const Font fallbackFont (Font::getFallbackFontName(), Font::getFallbackFontStyle(), 10.0f);
245 return fallbackFont.getTypefacePtr();
246}
247
248EdgeTable* Typeface::getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform, float fontHeight)
249{
250 Path path;
251
252 if (getOutlineForGlyph (glyphNumber, path) && ! path.isEmpty())
253 {
254 applyVerticalHintingTransform (fontHeight, path);
255
256 return new EdgeTable (path.getBoundsTransformed (transform).getSmallestIntegerContainer().expanded (1, 0),
257 path, transform);
258 }
259
260 return nullptr;
261}
262
263} // namespace juce
Represents a 2D affine-transformation matrix.
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
A table of horizontal scan-line segments - used for rasterising Paths.
Represents a particular font, including its size, style, etc.
Definition juce_Font.h:42
static const String & getFallbackFontStyle()
Returns the font style of the typeface to be used for rendering glyphs that aren't found in the reque...
Font withHeight(float height) const
Returns a copy of this font with a new height.
static const String & getDefaultStyle()
Returns a font style name that represents the default style.
static const String & getFallbackFontName()
Returns the font family of the typeface to be used for rendering glyphs that aren't found in the requ...
static Typeface::Ptr getDefaultTypefaceForFont(const Font &font)
Returns the default system typeface for the given font.
static const String & getDefaultSansSerifFontName()
Returns a typeface font family that represents the default sans-serif font.
String getTypefaceName() const noexcept
Returns the font family of the typeface that this font uses.
static const String & getDefaultMonospacedFontName()
Returns a typeface font family that represents the default monospaced font.
@ bold
boldens the font.
Definition juce_Font.h:51
@ italic
finds an italic version of the font.
Definition juce_Font.h:52
static const String & getDefaultSerifFontName()
Returns a typeface font family that represents the default serif font.
Automatically locks and unlocks a mutex object.
A set of glyphs, each with a position.
void addLineOfText(const Font &font, const String &text, float x, float y)
Appends a line of text to the arrangement.
Iterates the lines and curves that a path contains.
Definition juce_Path.h:725
bool next() noexcept
Moves onto the next element in the path.
@ quadraticTo
For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve.
Definition juce_Path.h:745
@ closePath
Indicates that the sub-path is being closed.
Definition juce_Path.h:747
@ lineTo
For this type, x1 and y1 indicate the end point of the line.
Definition juce_Path.h:744
@ cubicTo
For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic cur...
Definition juce_Path.h:746
@ startNewSubPath
For this type, x1 and y1 will be set to indicate the first point in the subpath.
Definition juce_Path.h:743
A path is a sequence of lines and curves that may either form a closed shape or be open-ended.
Definition juce_Path.h:65
void startNewSubPath(float startX, float startY)
Begins a new subpath with a given starting position.
void quadraticTo(float controlPointX, float controlPointY, float endPointX, float endPointY)
Adds a quadratic bezier curve from the shape's last position to a new position.
void cubicTo(float controlPoint1X, float controlPoint1Y, float controlPoint2X, float controlPoint2Y, float endPointX, float endPointY)
Adds a cubic bezier curve from the shape's last position to a new position.
Rectangle< float > getBoundsTransformed(const AffineTransform &transform) const noexcept
Returns the smallest rectangle that contains all points within the path after it's been transformed w...
void closeSubPath()
Closes a the current sub-path with a line back to its start-point.
Rectangle< float > getBounds() const noexcept
Returns the smallest rectangle that contains all points within the path.
void lineTo(float endX, float endY)
Adds a line from the shape's last position to a new end-point.
void swapWithPath(Path &) noexcept
Swaps the contents of this path with another one.
bool isEmpty() const noexcept
Returns true if the path doesn't contain any lines or curves.
Rectangle< int > getSmallestIntegerContainer() const noexcept
Returns the smallest integer-aligned rectangle that completely contains this one.
Rectangle expanded(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is larger than this one by a given amount.
The JUCE String class!
Definition juce_String.h:53
bool containsWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
Tests whether the string contains another substring as a distinct word.
A typeface represents a size-independent font.
void applyVerticalHintingTransform(float fontHeight, Path &path)
Makes an attempt at performing a good overall distortion that will scale a font of the given size to ...
virtual bool getOutlineForGlyph(int glyphNumber, Path &path)=0
Returns the outline for a glyph.
const String & getName() const noexcept
Returns the font family of the typeface.
virtual EdgeTable * getEdgeTableForGlyph(int glyphNumber, const AffineTransform &transform, float fontHeight)
Returns a new EdgeTable that contains the path for the given glyph, with the specified transform appl...
ReferenceCountedObjectPtr< Typeface > Ptr
A handy typedef for a pointer to a typeface.
~Typeface() override
Destructor.
T floor(T... args)
#define jassertfalse
This will always cause an assertion failure.
typedef float
JUCE Namespace.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
T sort(T... args)