1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2020 - 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 6 End-User License
11 Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12
13 End User License Agreement: www.juce.com/juce-6-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
26 namespace juce
27 {
28
29 /* This is some quick-and-dirty code to extract the typeface name from a lump of TTF file data.
30 It's needed because although win32 will happily load a TTF file from in-memory data, it won't
31 tell you the name of the damned font that it just loaded.. and in order to actually use the font,
32 you need to know its name!! Anyway, this awful hack seems to work for most fonts.
33 */
34 namespace TTFNameExtractor
35 {
36 struct OffsetTable
37 {
38 uint32 version;
39 uint16 numTables, searchRange, entrySelector, rangeShift;
40 };
41
42 struct TableDirectory
43 {
44 char tag[4];
45 uint32 checkSum, offset, length;
46 };
47
48 struct NamingTable
49 {
50 uint16 formatSelector;
51 uint16 numberOfNameRecords;
52 uint16 offsetStartOfStringStorage;
53 };
54
55 struct NameRecord
56 {
57 uint16 platformID, encodingID, languageID;
58 uint16 nameID, stringLength, offsetFromStorageArea;
59 };
60
parseNameRecord(MemoryInputStream & input,const NameRecord & nameRecord,const int64 directoryOffset,const int64 offsetOfStringStorage)61 static String parseNameRecord (MemoryInputStream& input, const NameRecord& nameRecord,
62 const int64 directoryOffset, const int64 offsetOfStringStorage)
63 {
64 String result;
65 auto oldPos = input.getPosition();
66 input.setPosition (directoryOffset + offsetOfStringStorage + ByteOrder::swapIfLittleEndian (nameRecord.offsetFromStorageArea));
67 auto stringLength = (int) ByteOrder::swapIfLittleEndian (nameRecord.stringLength);
68 auto platformID = ByteOrder::swapIfLittleEndian (nameRecord.platformID);
69
70 if (platformID == 0 || platformID == 3)
71 {
72 auto numChars = stringLength / 2 + 1;
73 HeapBlock<uint16> buffer;
74 buffer.calloc (numChars + 1);
75 input.read (buffer, stringLength);
76
77 for (int i = 0; i < numChars; ++i)
78 buffer[i] = ByteOrder::swapIfLittleEndian (buffer[i]);
79
80 static_assert (sizeof (CharPointer_UTF16::CharType) == sizeof (uint16), "Sanity check UTF-16 type");
81 result = CharPointer_UTF16 ((CharPointer_UTF16::CharType*) buffer.getData());
82 }
83 else
84 {
85 HeapBlock<char> buffer;
86 buffer.calloc (stringLength + 1);
87 input.read (buffer, stringLength);
88 result = CharPointer_UTF8 (buffer.getData());
89 }
90
91 input.setPosition (oldPos);
92 return result;
93 }
94
parseNameTable(MemoryInputStream & input,int64 directoryOffset)95 static String parseNameTable (MemoryInputStream& input, int64 directoryOffset)
96 {
97 input.setPosition (directoryOffset);
98
99 NamingTable namingTable = {};
100 input.read (&namingTable, sizeof (namingTable));
101
102 for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (namingTable.numberOfNameRecords); ++i)
103 {
104 NameRecord nameRecord = {};
105 input.read (&nameRecord, sizeof (nameRecord));
106
107 if (ByteOrder::swapIfLittleEndian (nameRecord.nameID) == 4)
108 {
109 const String result (parseNameRecord (input, nameRecord, directoryOffset,
110 ByteOrder::swapIfLittleEndian (namingTable.offsetStartOfStringStorage)));
111
112 if (result.isNotEmpty())
113 return result;
114 }
115 }
116
117 return {};
118 }
119
getTypefaceNameFromFile(MemoryInputStream & input)120 static String getTypefaceNameFromFile (MemoryInputStream& input)
121 {
122 OffsetTable offsetTable = {};
123 input.read (&offsetTable, sizeof (offsetTable));
124
125 for (int i = 0; i < (int) ByteOrder::swapIfLittleEndian (offsetTable.numTables); ++i)
126 {
127 TableDirectory tableDirectory;
128 zerostruct (tableDirectory);
129 input.read (&tableDirectory, sizeof (tableDirectory));
130
131 if (String (tableDirectory.tag, sizeof (tableDirectory.tag)).equalsIgnoreCase ("name"))
132 return parseNameTable (input, ByteOrder::swapIfLittleEndian (tableDirectory.offset));
133 }
134
135 return {};
136 }
137 }
138
139 namespace FontEnumerators
140 {
fontEnum2(ENUMLOGFONTEXW * lpelfe,NEWTEXTMETRICEXW *,int type,LPARAM lParam)141 static int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
142 {
143 if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
144 {
145 const String fontName (lpelfe->elfLogFont.lfFaceName);
146 ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@"));
147 }
148
149 return 1;
150 }
151
fontEnum1(ENUMLOGFONTEXW * lpelfe,NEWTEXTMETRICEXW *,int type,LPARAM lParam)152 static int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
153 {
154 if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
155 {
156 LOGFONTW lf = {};
157 lf.lfWeight = FW_DONTCARE;
158 lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
159 lf.lfQuality = DEFAULT_QUALITY;
160 lf.lfCharSet = DEFAULT_CHARSET;
161 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
162 lf.lfPitchAndFamily = FF_DONTCARE;
163
164 const String fontName (lpelfe->elfLogFont.lfFaceName);
165 fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
166
167 auto dc = CreateCompatibleDC (nullptr);
168 EnumFontFamiliesEx (dc, &lf, (FONTENUMPROCW) &fontEnum2, lParam, 0);
169 DeleteDC (dc);
170 }
171
172 return 1;
173 }
174 }
175
findAllTypefaceNames()176 StringArray Font::findAllTypefaceNames()
177 {
178 StringArray results;
179
180 #if JUCE_USE_DIRECTWRITE
181 SharedResourcePointer<Direct2DFactories> factories;
182
183 if (factories->systemFonts != nullptr)
184 {
185 ComSmartPtr<IDWriteFontFamily> fontFamily;
186 uint32 fontFamilyCount = 0;
187 fontFamilyCount = factories->systemFonts->GetFontFamilyCount();
188
189 for (uint32 i = 0; i < fontFamilyCount; ++i)
190 {
191 auto hr = factories->systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress());
192
193 if (SUCCEEDED (hr))
194 results.addIfNotAlreadyThere (getFontFamilyName (fontFamily));
195 }
196 }
197 else
198 #endif
199 {
200 auto dc = CreateCompatibleDC (nullptr);
201
202 {
203 LOGFONTW lf = {};
204 lf.lfWeight = FW_DONTCARE;
205 lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
206 lf.lfQuality = DEFAULT_QUALITY;
207 lf.lfCharSet = DEFAULT_CHARSET;
208 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
209 lf.lfPitchAndFamily = FF_DONTCARE;
210
211 EnumFontFamiliesEx (dc, &lf,
212 (FONTENUMPROCW) &FontEnumerators::fontEnum1,
213 (LPARAM) &results, 0);
214 }
215
216 DeleteDC (dc);
217 }
218
219 results.sort (true);
220 return results;
221 }
222
findAllTypefaceStyles(const String & family)223 StringArray Font::findAllTypefaceStyles (const String& family)
224 {
225 if (FontStyleHelpers::isPlaceholderFamilyName (family))
226 return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family));
227
228 StringArray results;
229
230 #if JUCE_USE_DIRECTWRITE
231 SharedResourcePointer<Direct2DFactories> factories;
232
233 if (factories->systemFonts != nullptr)
234 {
235 BOOL fontFound = false;
236 uint32 fontIndex = 0;
237 auto hr = factories->systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound);
238
239 if (! fontFound)
240 fontIndex = 0;
241
242 // Get the font family using the search results
243 // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family
244 ComSmartPtr<IDWriteFontFamily> fontFamily;
245 hr = factories->systemFonts->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());
246
247 // Get the font faces
248 ComSmartPtr<IDWriteFont> dwFont;
249 uint32 fontFacesCount = 0;
250 fontFacesCount = fontFamily->GetFontCount();
251
252 for (uint32 i = 0; i < fontFacesCount; ++i)
253 {
254 hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());
255
256 // Ignore any algorithmically generated bold and oblique styles..
257 if (dwFont->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE)
258 results.addIfNotAlreadyThere (getFontFaceName (dwFont));
259 }
260 }
261 else
262 #endif
263 {
264 results.add ("Regular");
265 results.add ("Italic");
266 results.add ("Bold");
267 results.add ("Bold Italic");
268 }
269
270 return results;
271 }
272
273 extern bool juce_isRunningInWine();
274
275 struct DefaultFontNames
276 {
DefaultFontNamesjuce::DefaultFontNames277 DefaultFontNames()
278 {
279 if (juce_isRunningInWine())
280 {
281 // If we're running in Wine, then use fonts that might be available on Linux..
282 defaultSans = "Bitstream Vera Sans";
283 defaultSerif = "Bitstream Vera Serif";
284 defaultFixed = "Bitstream Vera Sans Mono";
285 }
286 else
287 {
288 defaultSans = "Verdana";
289 defaultSerif = "Times New Roman";
290 defaultFixed = "Lucida Console";
291 defaultFallback = "Tahoma"; // (contains plenty of unicode characters)
292 }
293 }
294
295 String defaultSans, defaultSerif, defaultFixed, defaultFallback;
296 };
297
getDefaultTypefaceForFont(const Font & font)298 Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
299 {
300 static DefaultFontNames defaultNames;
301
302 Font newFont (font);
303 auto& faceName = font.getTypefaceName();
304
305 if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans);
306 else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif);
307 else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed);
308
309 if (font.getTypefaceStyle() == getDefaultStyle())
310 newFont.setTypefaceStyle ("Regular");
311
312 return Typeface::createSystemTypefaceFor (newFont);
313 }
314
315 //==============================================================================
316 class WindowsTypeface : public Typeface
317 {
318 public:
WindowsTypeface(const Font & font)319 WindowsTypeface (const Font& font) : Typeface (font.getTypefaceName(),
320 font.getTypefaceStyle())
321 {
322 loadFont();
323 }
324
WindowsTypeface(const void * data,size_t dataSize)325 WindowsTypeface (const void* data, size_t dataSize)
326 : Typeface (String(), String())
327 {
328 DWORD numInstalled = 0;
329 memoryFont = AddFontMemResourceEx (const_cast<void*> (data), (DWORD) dataSize,
330 nullptr, &numInstalled);
331
332 MemoryInputStream m (data, dataSize, false);
333 name = TTFNameExtractor::getTypefaceNameFromFile (m);
334 loadFont();
335 }
336
~WindowsTypeface()337 ~WindowsTypeface()
338 {
339 SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker
340 DeleteDC (dc);
341
342 if (fontH != nullptr)
343 DeleteObject (fontH);
344
345 if (memoryFont != nullptr)
346 RemoveFontMemResourceEx (memoryFont);
347 }
348
getAscent() const349 float getAscent() const { return ascent; }
getDescent() const350 float getDescent() const { return 1.0f - ascent; }
getHeightToPointsFactor() const351 float getHeightToPointsFactor() const { return heightToPointsFactor; }
352
getStringWidth(const String & text)353 float getStringWidth (const String& text)
354 {
355 auto utf16 = text.toUTF16();
356 auto numChars = utf16.length();
357 HeapBlock<uint16> results (numChars);
358 float x = 0;
359
360 if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast<WORD*> (results.getData()),
361 GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
362 {
363 for (size_t i = 0; i < numChars; ++i)
364 x += getKerning (dc, results[i], (i + 1) < numChars ? results[i + 1] : -1);
365 }
366
367 return x;
368 }
369
getGlyphPositions(const String & text,Array<int> & resultGlyphs,Array<float> & xOffsets)370 void getGlyphPositions (const String& text, Array<int>& resultGlyphs, Array<float>& xOffsets)
371 {
372 auto utf16 = text.toUTF16();
373 auto numChars = utf16.length();
374 HeapBlock<uint16> results (numChars);
375 float x = 0;
376
377 if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast<WORD*> (results.getData()),
378 GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
379 {
380 resultGlyphs.ensureStorageAllocated ((int) numChars);
381 xOffsets.ensureStorageAllocated ((int) numChars + 1);
382
383 for (size_t i = 0; i < numChars; ++i)
384 {
385 resultGlyphs.add (results[i]);
386 xOffsets.add (x);
387 x += getKerning (dc, results[i], (i + 1) < numChars ? results[i + 1] : -1);
388 }
389 }
390
391 xOffsets.add (x);
392 }
393
getOutlineForGlyph(int glyphNumber,Path & glyphPath)394 bool getOutlineForGlyph (int glyphNumber, Path& glyphPath)
395 {
396 if (glyphNumber < 0)
397 glyphNumber = defaultGlyph;
398
399 GLYPHMETRICS gm;
400 // (although GetGlyphOutline returns a DWORD, it may be -1 on failure, so treat it as signed int..)
401 auto bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX,
402 &gm, 0, nullptr, &identityMatrix);
403
404 if (bufSize > 0)
405 {
406 HeapBlock<char> data (bufSize);
407 GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm,
408 (DWORD) bufSize, data, &identityMatrix);
409
410 auto pheader = reinterpret_cast<const TTPOLYGONHEADER*> (data.getData());
411
412 auto scaleX = 1.0f / tm.tmHeight;
413 auto scaleY = -scaleX;
414
415 while ((char*) pheader < data + bufSize)
416 {
417 glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value,
418 scaleY * pheader->pfxStart.y.value);
419
420 auto curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
421 auto curveEnd = ((const char*) pheader) + pheader->cb;
422
423 while ((const char*) curve < curveEnd)
424 {
425 if (curve->wType == TT_PRIM_LINE)
426 {
427 for (int i = 0; i < curve->cpfx; ++i)
428 glyphPath.lineTo (scaleX * curve->apfx[i].x.value,
429 scaleY * curve->apfx[i].y.value);
430 }
431 else if (curve->wType == TT_PRIM_QSPLINE)
432 {
433 for (int i = 0; i < curve->cpfx - 1; ++i)
434 {
435 auto x2 = scaleX * curve->apfx[i].x.value;
436 auto y2 = scaleY * curve->apfx[i].y.value;
437 auto x3 = scaleX * curve->apfx[i + 1].x.value;
438 auto y3 = scaleY * curve->apfx[i + 1].y.value;
439
440 if (i < curve->cpfx - 2)
441 {
442 x3 = 0.5f * (x2 + x3);
443 y3 = 0.5f * (y2 + y3);
444 }
445
446 glyphPath.quadraticTo (x2, y2, x3, y3);
447 }
448 }
449
450 curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
451 }
452
453 pheader = (const TTPOLYGONHEADER*) curve;
454
455 glyphPath.closeSubPath();
456 }
457 }
458
459 return true;
460 }
461
462 private:
463 static const MAT2 identityMatrix;
464 HFONT fontH = {};
465 HGDIOBJ previousFontH = {};
466 HDC dc { CreateCompatibleDC (nullptr) };
467 TEXTMETRIC tm;
468 HANDLE memoryFont = {};
469 float ascent = 1.0f, heightToPointsFactor = 1.0f;
470 int defaultGlyph = -1, heightInPoints = 0;
471 std::unordered_map<uint64, float> kerningPairs;
472
kerningPairIndex(int glyph1,int glyph2)473 static uint64 kerningPairIndex (int glyph1, int glyph2)
474 {
475 return (((uint64) (uint32) glyph1) << 32) | (uint64) (uint32) glyph2;
476 }
477
loadFont()478 void loadFont()
479 {
480 SetMapperFlags (dc, 0);
481 SetMapMode (dc, MM_TEXT);
482
483 LOGFONTW lf = {};
484 lf.lfCharSet = DEFAULT_CHARSET;
485 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
486 lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
487 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
488 lf.lfQuality = PROOF_QUALITY;
489 lf.lfItalic = (BYTE) (style.contains ("Italic") ? TRUE : FALSE);
490 lf.lfWeight = style.contains ("Bold") ? FW_BOLD : FW_NORMAL;
491 lf.lfHeight = -256;
492 name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
493
494 auto standardSizedFont = CreateFontIndirect (&lf);
495
496 if (standardSizedFont != nullptr)
497 {
498 if ((previousFontH = SelectObject (dc, standardSizedFont)) != nullptr)
499 {
500 fontH = standardSizedFont;
501 OUTLINETEXTMETRIC otm;
502
503 if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
504 {
505 heightInPoints = (int) otm.otmEMSquare;
506 lf.lfHeight = -heightInPoints;
507 fontH = CreateFontIndirect (&lf);
508
509 SelectObject (dc, fontH);
510 DeleteObject (standardSizedFont);
511 }
512 }
513 }
514
515 if (GetTextMetrics (dc, &tm))
516 {
517 auto dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f;
518 heightToPointsFactor = (dpi / GetDeviceCaps (dc, LOGPIXELSY)) * heightInPoints / (float) tm.tmHeight;
519 ascent = tm.tmAscent / (float) tm.tmHeight;
520 std::unordered_map<int, int> glyphsForChars;
521 defaultGlyph = getGlyphForChar (dc, glyphsForChars, tm.tmDefaultChar);
522 createKerningPairs (dc, glyphsForChars, (float) tm.tmHeight);
523 }
524 }
525
createKerningPairs(HDC hdc,std::unordered_map<int,int> & glyphsForChars,float height)526 void createKerningPairs (HDC hdc, std::unordered_map<int, int>& glyphsForChars, float height)
527 {
528 HeapBlock<KERNINGPAIR> rawKerning;
529 auto numKPs = GetKerningPairs (hdc, 0, nullptr);
530 rawKerning.calloc (numKPs);
531 GetKerningPairs (hdc, numKPs, rawKerning);
532
533 std::unordered_map<int, int> widthsForGlyphs;
534
535 for (DWORD i = 0; i < numKPs; ++i)
536 {
537 auto glyph1 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wFirst);
538 auto glyph2 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wSecond);
539 auto standardWidth = getGlyphWidth (hdc, widthsForGlyphs, glyph1);
540
541 kerningPairs[kerningPairIndex (glyph1, glyph2)] = (standardWidth + rawKerning[i].iKernAmount) / height;
542 kerningPairs[kerningPairIndex (glyph1, -1)] = standardWidth / height;
543 }
544 }
545
getGlyphForChar(HDC dc,std::unordered_map<int,int> & cache,juce_wchar character)546 static int getGlyphForChar (HDC dc, std::unordered_map<int, int>& cache, juce_wchar character)
547 {
548 auto existing = cache.find ((int) character);
549
550 if (existing != cache.end())
551 return existing->second;
552
553 const WCHAR charToTest[] = { (WCHAR) character, 0 };
554 WORD index = 0;
555
556 if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR
557 || index == 0xffff)
558 return -1;
559
560 cache[(int) character] = index;
561 return index;
562 }
563
getGlyphWidth(HDC dc,std::unordered_map<int,int> & cache,int glyphNumber)564 static int getGlyphWidth (HDC dc, std::unordered_map<int, int>& cache, int glyphNumber)
565 {
566 auto existing = cache.find (glyphNumber);
567
568 if (existing != cache.end())
569 return existing->second;
570
571 auto width = getGlyphWidth (dc, glyphNumber);
572 cache[glyphNumber] = width;
573 return width;
574 }
575
getGlyphWidth(HDC dc,int glyphNumber)576 static int getGlyphWidth (HDC dc, int glyphNumber)
577 {
578 GLYPHMETRICS gm;
579 gm.gmCellIncX = 0;
580 GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &identityMatrix);
581 return gm.gmCellIncX;
582 }
583
getKerning(HDC hdc,int glyph1,int glyph2)584 float getKerning (HDC hdc, int glyph1, int glyph2)
585 {
586 auto pair = kerningPairs.find (kerningPairIndex (glyph1, glyph2));
587
588 if (pair != kerningPairs.end())
589 return pair->second;
590
591 auto single = kerningPairs.find (kerningPairIndex (glyph1, -1));
592
593 if (single != kerningPairs.end())
594 return single->second;
595
596 auto width = getGlyphWidth (hdc, glyph1) / (float) tm.tmHeight;
597 kerningPairs[kerningPairIndex (glyph1, -1)] = width;
598 return width;
599 }
600
601 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface)
602 };
603
604 const MAT2 WindowsTypeface::identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
605
createSystemTypefaceFor(const Font & font)606 Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
607 {
608 #if JUCE_USE_DIRECTWRITE
609 SharedResourcePointer<Direct2DFactories> factories;
610
611 if (factories->systemFonts != nullptr)
612 {
613 std::unique_ptr<WindowsDirectWriteTypeface> wtf (new WindowsDirectWriteTypeface (font, factories->systemFonts));
614
615 if (wtf->loadedOk() && wtf->isFontFound())
616 return wtf.release();
617 }
618 #endif
619
620 return new WindowsTypeface (font);
621 }
622
createSystemTypefaceFor(const void * data,size_t dataSize)623 Typeface::Ptr Typeface::createSystemTypefaceFor (const void* data, size_t dataSize)
624 {
625 return new WindowsTypeface (data, dataSize);
626 }
627
scanFolderForFonts(const File &)628 void Typeface::scanFolderForFonts (const File&)
629 {
630 jassertfalse; // not implemented on this platform
631 }
632
633 } // namespace juce
634