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_CustomTypeface.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{
31public:
32 GlyphInfo (juce_wchar c, const Path& p, float w) noexcept
33 : character (c), path (p), width (w)
34 {
35 }
36
38 {
39 juce_wchar character2;
40 float kerningAmount;
41 };
42
43 void addKerningPair (juce_wchar subsequentCharacter, float extraKerningAmount) noexcept
44 {
45 kerningPairs.add ({ subsequentCharacter, extraKerningAmount });
46 }
47
48 float getHorizontalSpacing (juce_wchar subsequentCharacter) const noexcept
49 {
50 if (subsequentCharacter != 0)
51 for (auto& kp : kerningPairs)
52 if (kp.character2 == subsequentCharacter)
53 return width + kp.kerningAmount;
54
55 return width;
56 }
57
58 const juce_wchar character;
59 const Path path;
60 float width;
61 Array<KerningPair> kerningPairs;
62
63private:
65};
66
67//==============================================================================
68namespace CustomTypefaceHelpers
69{
70 static juce_wchar readChar (InputStream& in)
71 {
72 auto n = (uint32) (uint16) in.readShort();
73
74 if (n >= 0xd800 && n <= 0xdfff)
75 {
76 auto nextWord = (uint32) (uint16) in.readShort();
77 jassert (nextWord >= 0xdc00); // illegal unicode character!
78
79 n = 0x10000 + (((n - 0xd800) << 10) | (nextWord - 0xdc00));
80 }
81
82 return (juce_wchar) n;
83 }
84
85 static void writeChar (OutputStream& out, juce_wchar charToWrite)
86 {
87 if (charToWrite >= 0x10000)
88 {
89 charToWrite -= 0x10000;
90 out.writeShort ((short) (uint16) (0xd800 + (charToWrite >> 10)));
91 out.writeShort ((short) (uint16) (0xdc00 + (charToWrite & 0x3ff)));
92 }
93 else
94 {
95 out.writeShort ((short) (uint16) charToWrite);
96 }
97 }
98}
99
100//==============================================================================
106
108 : Typeface (String(), String())
109{
110 clear();
111
113 BufferedInputStream in (gzin, 32768);
114
115 name = in.readString();
116
117 const bool isBold = in.readBool();
118 const bool isItalic = in.readBool();
119 style = FontStyleHelpers::getStyleName (isBold, isItalic);
120
121 ascent = in.readFloat();
122 defaultCharacter = CustomTypefaceHelpers::readChar (in);
123
124 auto numChars = in.readInt();
125
126 for (int i = 0; i < numChars; ++i)
127 {
128 auto c = CustomTypefaceHelpers::readChar (in);
129 auto width = in.readFloat();
130
131 Path p;
132 p.loadPathFromStream (in);
133 addGlyph (c, p, width);
134 }
135
136 auto numKerningPairs = in.readInt();
137
138 for (int i = 0; i < numKerningPairs; ++i)
139 {
140 auto char1 = CustomTypefaceHelpers::readChar (in);
141 auto char2 = CustomTypefaceHelpers::readChar (in);
142
144 }
145}
146
150
151//==============================================================================
153{
154 defaultCharacter = 0;
155 ascent = 1.0f;
156 style = "Regular";
157 zeromem (lookupTable, sizeof (lookupTable));
158 glyphs.clear();
159}
160
161void CustomTypeface::setCharacteristics (const String& newName, float newAscent, bool isBold,
162 bool isItalic, juce_wchar newDefaultCharacter) noexcept
163{
164 name = newName;
165 defaultCharacter = newDefaultCharacter;
166 ascent = newAscent;
167 style = FontStyleHelpers::getStyleName (isBold, isItalic);
168}
169
172{
173 name = newName;
174 style = newStyle;
175 defaultCharacter = newDefaultCharacter;
176 ascent = newAscent;
177}
178
179void CustomTypeface::addGlyph (juce_wchar character, const Path& path, float width) noexcept
180{
181 // Check that you're not trying to add the same character twice..
182 jassert (findGlyph (character, false) == nullptr);
183
184 if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)))
185 lookupTable [character] = (short) glyphs.size();
186
187 glyphs.add (new GlyphInfo (character, path, width));
188}
189
191{
192 if (! approximatelyEqual (extraAmount, 0.0f))
193 {
194 if (auto* g = findGlyph (char1, true))
195 g->addKerningPair (char2, extraAmount);
196 else
197 jassertfalse; // can only add kerning pairs for characters that exist!
198 }
199}
200
201CustomTypeface::GlyphInfo* CustomTypeface::findGlyph (juce_wchar character, bool loadIfNeeded) noexcept
202{
203 if (isPositiveAndBelow ((int) character, numElementsInArray (lookupTable)) && lookupTable [character] > 0)
204 return glyphs [(int) lookupTable [(int) character]];
205
206 for (auto* g : glyphs)
207 if (g->character == character)
208 return g;
209
210 if (loadIfNeeded && loadGlyphIfPossible (character))
211 return findGlyph (character, false);
212
213 return nullptr;
214}
215
217{
218 return false;
219}
220
222{
223 setCharacteristics (name, style, typefaceToCopy.getAscent(), defaultCharacter);
224
225 for (int i = 0; i < numCharacters; ++i)
226 {
227 auto c = (juce_wchar) (characterStartIndex + static_cast<juce_wchar> (i));
228
232
233 const int glyphIndex = glyphIndexes.getFirst();
234
235 if (glyphIndex >= 0 && glyphIndexes.size() > 0)
236 {
237 auto glyphWidth = offsets[1];
238
239 Path p;
240 typefaceToCopy.getOutlineForGlyph (glyphIndex, p);
241
242 addGlyph (c, p, glyphWidth);
243
244 for (int j = glyphs.size() - 1; --j >= 0;)
245 {
246 auto char2 = glyphs.getUnchecked (j)->character;
247 glyphIndexes.clearQuick();
248 offsets.clearQuick();
250
251 if (offsets.size() > 1)
252 addKerningPair (c, char2, offsets[1] - glyphWidth);
253 }
254 }
255 }
256}
257
259{
261
262 out.writeString (name);
263 out.writeBool (FontStyleHelpers::isBold (style));
264 out.writeBool (FontStyleHelpers::isItalic (style));
265 out.writeFloat (ascent);
266 CustomTypefaceHelpers::writeChar (out, defaultCharacter);
267 out.writeInt (glyphs.size());
268
269 int numKerningPairs = 0;
270
271 for (auto* g : glyphs)
272 {
273 CustomTypefaceHelpers::writeChar (out, g->character);
274 out.writeFloat (g->width);
275 g->path.writePathToStream (out);
276
277 numKerningPairs += g->kerningPairs.size();
278 }
279
281
282 for (auto* g : glyphs)
283 {
284 for (auto& p : g->kerningPairs)
285 {
286 CustomTypefaceHelpers::writeChar (out, g->character);
287 CustomTypefaceHelpers::writeChar (out, p.character2);
288 out.writeFloat (p.kerningAmount);
289 }
290 }
291
292 return true;
293}
294
295//==============================================================================
296float CustomTypeface::getAscent() const { return ascent; }
297float CustomTypeface::getDescent() const { return 1.0f - ascent; }
298float CustomTypeface::getHeightToPointsFactor() const { return ascent; }
299
301{
302 float x = 0;
303
304 for (auto t = text.getCharPointer(); ! t.isEmpty();)
305 {
306 auto c = t.getAndAdvance();
307
308 if (auto* glyph = findGlyph (c, true))
309 {
310 x += glyph->getHorizontalSpacing (*t);
311 }
312 else
313 {
314 if (auto fallbackTypeface = Typeface::getFallbackTypeface())
315 if (fallbackTypeface.get() != this)
316 x += fallbackTypeface->getStringWidth (String::charToString (c));
317 }
318 }
319
320 return x;
321}
322
324{
325 xOffsets.add (0);
326 float x = 0;
327
328 for (auto t = text.getCharPointer(); ! t.isEmpty();)
329 {
330 float width = 0.0f;
331 int glyphChar = 0;
332
333 auto c = t.getAndAdvance();
334
335 if (auto* glyph = findGlyph (c, true))
336 {
337 width = glyph->getHorizontalSpacing (*t);
338 glyphChar = (int) glyph->character;
339 }
340 else
341 {
342 auto fallbackTypeface = getFallbackTypeface();
343
344 if (fallbackTypeface != nullptr && fallbackTypeface.get() != this)
345 {
349
350 if (subGlyphs.size() > 0)
351 {
353 width = subOffsets[1];
354 }
355 }
356 }
357
358 x += width;
360 xOffsets.add (x);
361 }
362}
363
365{
366 if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
367 {
368 path = glyph->path;
369 return true;
370 }
371
372 if (auto fallbackTypeface = getFallbackTypeface())
373 if (fallbackTypeface.get() != this)
374 return fallbackTypeface->getOutlineForGlyph (glyphNumber, path);
375
376 return false;
377}
378
380{
381 if (auto* glyph = findGlyph ((juce_wchar) glyphNumber, true))
382 {
383 if (! glyph->path.isEmpty())
384 return new EdgeTable (glyph->path.getBoundsTransformed (transform)
385 .getSmallestIntegerContainer().expanded (1, 0),
386 glyph->path, transform);
387 }
388 else
389 {
390 if (auto fallbackTypeface = getFallbackTypeface())
391 if (fallbackTypeface.get() != this)
392 return fallbackTypeface->getEdgeTableForGlyph (glyphNumber, transform, fontHeight);
393 }
394
395 return nullptr;
396}
397
398} // namespace juce
Represents a 2D affine-transformation matrix.
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
ElementType getFirst() const noexcept
Returns the first element in the array, or a default value if the array is empty.
Definition juce_Array.h:290
Wraps another input stream, and reads from it using an intermediate buffer.
String readString() override
Reads a zero-terminated UTF-8 string from the stream.
void clear()
Resets this typeface, deleting all its glyphs and settings.
float getHeightToPointsFactor() const override
Returns the value by which you should multiply a JUCE font-height value to convert it to the equivale...
CustomTypeface()
Creates a new, empty typeface.
float getAscent() const override
Returns the ascent of the font, as a proportion of its height.
float getDescent() const override
Returns the descent of the font, as a proportion of its height.
virtual bool loadGlyphIfPossible(juce_wchar characterNeeded)
If a subclass overrides this, it can load glyphs into the font on-demand.
void addKerningPair(juce_wchar char1, juce_wchar char2, float extraAmount) noexcept
Specifies an extra kerning amount to be used between a pair of characters.
void addGlyphsFromOtherTypeface(Typeface &typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) noexcept
Adds a range of glyphs from another typeface.
void setCharacteristics(const String &fontFamily, float ascent, bool isBold, bool isItalic, juce_wchar defaultCharacter) noexcept
Sets the vital statistics for the typeface.
void getGlyphPositions(const String &, Array< int > &glyphs, Array< float > &xOffsets) override
Converts a line of text into its glyph numbers and their positions.
float getStringWidth(const String &) override
Measures the width of a line of text.
~CustomTypeface() override
Destructor.
bool getOutlineForGlyph(int glyphNumber, Path &) override
Returns the outline for a glyph.
EdgeTable * getEdgeTableForGlyph(int glyphNumber, const AffineTransform &, float fontHeight) override
Returns a new EdgeTable that contains the path for the given glyph, with the specified transform appl...
void addGlyph(juce_wchar character, const Path &path, float width) noexcept
Adds a glyph to the typeface.
bool writeToStream(OutputStream &outputStream)
Saves this typeface as a Juce-formatted font file.
A table of horizontal scan-line segments - used for rasterising Paths.
A stream which uses zlib to compress the data written into it.
This stream will decompress a source-stream using zlib.
The base class for streams that read data.
virtual float readFloat()
Reads four bytes as a 32-bit floating point value.
virtual bool readBool()
Reads a boolean from the stream.
virtual int readInt()
Reads four bytes from the stream as a little-endian 32-bit value.
The base class for streams that write data to some kind of destination.
virtual bool writeFloat(float value)
Writes a 32-bit floating point value to the stream in a binary format.
virtual bool writeBool(bool boolValue)
Writes a boolean to the stream as a single byte.
virtual bool writeInt(int value)
Writes a 32-bit integer to the stream in a little-endian byte order.
virtual bool writeString(const String &text)
Stores a string in the stream in a binary format.
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 loadPathFromStream(InputStream &source)
Loads a stored path from a data stream.
The JUCE String class!
Definition juce_String.h:53
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
static String charToString(juce_wchar character)
Creates a string from a single character.
A typeface represents a size-independent font.
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
typedef short
JUCE Namespace.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
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 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
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
void zeromem(void *memory, size_t numBytes) noexcept
Fills a block of memory with zeros.
Definition juce_Memory.h:28