The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

499 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. namespace FontEnumerators
  19. {
  20. static int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
  21. {
  22. if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
  23. {
  24. const String fontName (lpelfe->elfLogFont.lfFaceName);
  25. ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@"));
  26. }
  27. return 1;
  28. }
  29. static int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam)
  30. {
  31. if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0)
  32. {
  33. LOGFONTW lf = { 0 };
  34. lf.lfWeight = FW_DONTCARE;
  35. lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
  36. lf.lfQuality = DEFAULT_QUALITY;
  37. lf.lfCharSet = DEFAULT_CHARSET;
  38. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  39. lf.lfPitchAndFamily = FF_DONTCARE;
  40. const String fontName (lpelfe->elfLogFont.lfFaceName);
  41. fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
  42. HDC dc = CreateCompatibleDC (0);
  43. EnumFontFamiliesEx (dc, &lf,
  44. (FONTENUMPROCW) &fontEnum2,
  45. lParam, 0);
  46. DeleteDC (dc);
  47. }
  48. return 1;
  49. }
  50. }
  51. StringArray Font::findAllTypefaceNames()
  52. {
  53. StringArray results;
  54. #if JUCE_USE_DIRECTWRITE
  55. const Direct2DFactories& factories = Direct2DFactories::getInstance();
  56. if (factories.systemFonts != nullptr)
  57. {
  58. ComSmartPtr<IDWriteFontFamily> fontFamily;
  59. uint32 fontFamilyCount = 0;
  60. fontFamilyCount = factories.systemFonts->GetFontFamilyCount();
  61. for (uint32 i = 0; i < fontFamilyCount; ++i)
  62. {
  63. HRESULT hr = factories.systemFonts->GetFontFamily (i, fontFamily.resetAndGetPointerAddress());
  64. if (SUCCEEDED (hr))
  65. results.addIfNotAlreadyThere (getFontFamilyName (fontFamily));
  66. }
  67. }
  68. else
  69. #endif
  70. {
  71. HDC dc = CreateCompatibleDC (0);
  72. {
  73. LOGFONTW lf = { 0 };
  74. lf.lfWeight = FW_DONTCARE;
  75. lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
  76. lf.lfQuality = DEFAULT_QUALITY;
  77. lf.lfCharSet = DEFAULT_CHARSET;
  78. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  79. lf.lfPitchAndFamily = FF_DONTCARE;
  80. EnumFontFamiliesEx (dc, &lf,
  81. (FONTENUMPROCW) &FontEnumerators::fontEnum1,
  82. (LPARAM) &results, 0);
  83. }
  84. DeleteDC (dc);
  85. }
  86. results.sort (true);
  87. return results;
  88. }
  89. StringArray Font::findAllTypefaceStyles (const String& family)
  90. {
  91. if (FontStyleHelpers::isPlaceholderFamilyName (family))
  92. return findAllTypefaceStyles (FontStyleHelpers::getConcreteFamilyNameFromPlaceholder (family));
  93. StringArray results;
  94. #if JUCE_USE_DIRECTWRITE
  95. const Direct2DFactories& factories = Direct2DFactories::getInstance();
  96. if (factories.systemFonts != nullptr)
  97. {
  98. BOOL fontFound = false;
  99. uint32 fontIndex = 0;
  100. HRESULT hr = factories.systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound);
  101. if (! fontFound)
  102. fontIndex = 0;
  103. // Get the font family using the search results
  104. // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family
  105. ComSmartPtr<IDWriteFontFamily> fontFamily;
  106. hr = factories.systemFonts->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());
  107. // Get the font faces
  108. ComSmartPtr<IDWriteFont> dwFont;
  109. uint32 fontFacesCount = 0;
  110. fontFacesCount = fontFamily->GetFontCount();
  111. for (uint32 i = 0; i < fontFacesCount; ++i)
  112. {
  113. hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());
  114. // Ignore any algorithmically generated bold and oblique styles..
  115. if (dwFont->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE)
  116. results.addIfNotAlreadyThere (getFontFaceName (dwFont));
  117. }
  118. }
  119. else
  120. #endif
  121. {
  122. results.add ("Regular");
  123. results.add ("Italic");
  124. results.add ("Bold");
  125. results.add ("Bold Italic");
  126. }
  127. return results;
  128. }
  129. extern bool juce_IsRunningInWine();
  130. struct DefaultFontNames
  131. {
  132. DefaultFontNames()
  133. {
  134. if (juce_IsRunningInWine())
  135. {
  136. // If we're running in Wine, then use fonts that might be available on Linux..
  137. defaultSans = "Bitstream Vera Sans";
  138. defaultSerif = "Bitstream Vera Serif";
  139. defaultFixed = "Bitstream Vera Sans Mono";
  140. }
  141. else
  142. {
  143. defaultSans = "Verdana";
  144. defaultSerif = "Times";
  145. defaultFixed = "Lucida Console";
  146. defaultFallback = "Tahoma"; // (contains plenty of unicode characters)
  147. }
  148. }
  149. String defaultSans, defaultSerif, defaultFixed, defaultFallback;
  150. };
  151. Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
  152. {
  153. static DefaultFontNames defaultNames;
  154. Font newFont (font);
  155. const String& faceName = font.getTypefaceName();
  156. if (faceName == getDefaultSansSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSans);
  157. else if (faceName == getDefaultSerifFontName()) newFont.setTypefaceName (defaultNames.defaultSerif);
  158. else if (faceName == getDefaultMonospacedFontName()) newFont.setTypefaceName (defaultNames.defaultFixed);
  159. if (font.getTypefaceStyle() == getDefaultStyle())
  160. newFont.setTypefaceStyle ("Regular");
  161. return Typeface::createSystemTypefaceFor (newFont);
  162. }
  163. //==============================================================================
  164. class WindowsTypeface : public Typeface
  165. {
  166. public:
  167. WindowsTypeface (const Font& font)
  168. : Typeface (font.getTypefaceName(),
  169. font.getTypefaceStyle()),
  170. fontH (0),
  171. previousFontH (0),
  172. dc (CreateCompatibleDC (0)),
  173. ascent (1.0f),
  174. defaultGlyph (-1)
  175. {
  176. loadFont();
  177. if (GetTextMetrics (dc, &tm))
  178. {
  179. ascent = tm.tmAscent / (float) tm.tmHeight;
  180. defaultGlyph = getGlyphForChar (dc, tm.tmDefaultChar);
  181. createKerningPairs (dc, (float) tm.tmHeight);
  182. }
  183. }
  184. ~WindowsTypeface()
  185. {
  186. SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker
  187. DeleteDC (dc);
  188. if (fontH != 0)
  189. DeleteObject (fontH);
  190. }
  191. float getAscent() const { return ascent; }
  192. float getDescent() const { return 1.0f - ascent; }
  193. float getStringWidth (const String& text)
  194. {
  195. const CharPointer_UTF16 utf16 (text.toUTF16());
  196. const size_t numChars = utf16.length();
  197. HeapBlock<int16> results (numChars + 1);
  198. results[numChars] = -1;
  199. float x = 0;
  200. if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast <WORD*> (results.getData()),
  201. GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
  202. {
  203. for (size_t i = 0; i < numChars; ++i)
  204. x += getKerning (dc, results[i], results[i + 1]);
  205. }
  206. return x;
  207. }
  208. void getGlyphPositions (const String& text, Array <int>& resultGlyphs, Array <float>& xOffsets)
  209. {
  210. const CharPointer_UTF16 utf16 (text.toUTF16());
  211. const size_t numChars = utf16.length();
  212. HeapBlock<int16> results (numChars + 1);
  213. results[numChars] = -1;
  214. float x = 0;
  215. if (GetGlyphIndices (dc, utf16, (int) numChars, reinterpret_cast <WORD*> (results.getData()),
  216. GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
  217. {
  218. resultGlyphs.ensureStorageAllocated ((int) numChars);
  219. xOffsets.ensureStorageAllocated ((int) numChars + 1);
  220. for (size_t i = 0; i < numChars; ++i)
  221. {
  222. resultGlyphs.add (results[i]);
  223. xOffsets.add (x);
  224. x += getKerning (dc, results[i], results[i + 1]);
  225. }
  226. }
  227. xOffsets.add (x);
  228. }
  229. bool getOutlineForGlyph (int glyphNumber, Path& glyphPath)
  230. {
  231. if (glyphNumber < 0)
  232. glyphNumber = defaultGlyph;
  233. GLYPHMETRICS gm;
  234. // (although GetGlyphOutline returns a DWORD, it may be -1 on failure, so treat it as signed int..)
  235. const int bufSize = (int) GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX,
  236. &gm, 0, 0, &identityMatrix);
  237. if (bufSize > 0)
  238. {
  239. HeapBlock<char> data (bufSize);
  240. GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm,
  241. bufSize, data, &identityMatrix);
  242. const TTPOLYGONHEADER* pheader = reinterpret_cast<TTPOLYGONHEADER*> (data.getData());
  243. const float scaleX = 1.0f / tm.tmHeight;
  244. const float scaleY = -scaleX;
  245. while ((char*) pheader < data + bufSize)
  246. {
  247. glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value,
  248. scaleY * pheader->pfxStart.y.value);
  249. const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
  250. const char* const curveEnd = ((const char*) pheader) + pheader->cb;
  251. while ((const char*) curve < curveEnd)
  252. {
  253. if (curve->wType == TT_PRIM_LINE)
  254. {
  255. for (int i = 0; i < curve->cpfx; ++i)
  256. glyphPath.lineTo (scaleX * curve->apfx[i].x.value,
  257. scaleY * curve->apfx[i].y.value);
  258. }
  259. else if (curve->wType == TT_PRIM_QSPLINE)
  260. {
  261. for (int i = 0; i < curve->cpfx - 1; ++i)
  262. {
  263. const float x2 = scaleX * curve->apfx[i].x.value;
  264. const float y2 = scaleY * curve->apfx[i].y.value;
  265. float x3 = scaleX * curve->apfx[i + 1].x.value;
  266. float y3 = scaleY * curve->apfx[i + 1].y.value;
  267. if (i < curve->cpfx - 2)
  268. {
  269. x3 = 0.5f * (x2 + x3);
  270. y3 = 0.5f * (y2 + y3);
  271. }
  272. glyphPath.quadraticTo (x2, y2, x3, y3);
  273. }
  274. }
  275. curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
  276. }
  277. pheader = (const TTPOLYGONHEADER*) curve;
  278. glyphPath.closeSubPath();
  279. }
  280. }
  281. return true;
  282. }
  283. private:
  284. static const MAT2 identityMatrix;
  285. HFONT fontH;
  286. HGDIOBJ previousFontH;
  287. HDC dc;
  288. TEXTMETRIC tm;
  289. float ascent;
  290. int defaultGlyph;
  291. struct KerningPair
  292. {
  293. int glyph1, glyph2;
  294. float kerning;
  295. bool operator== (const KerningPair& other) const noexcept
  296. {
  297. return glyph1 == other.glyph1 && glyph2 == other.glyph2;
  298. }
  299. bool operator< (const KerningPair& other) const noexcept
  300. {
  301. return glyph1 < other.glyph1
  302. || (glyph1 == other.glyph1 && glyph2 < other.glyph2);
  303. }
  304. };
  305. SortedSet<KerningPair> kerningPairs;
  306. void loadFont()
  307. {
  308. SetMapperFlags (dc, 0);
  309. SetMapMode (dc, MM_TEXT);
  310. LOGFONTW lf = { 0 };
  311. lf.lfCharSet = DEFAULT_CHARSET;
  312. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  313. lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
  314. lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  315. lf.lfQuality = PROOF_QUALITY;
  316. lf.lfItalic = (BYTE) (style == "Italic" ? TRUE : FALSE);
  317. lf.lfWeight = style == "Bold" ? FW_BOLD : FW_NORMAL;
  318. lf.lfHeight = -256;
  319. name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName));
  320. HFONT standardSizedFont = CreateFontIndirect (&lf);
  321. if (standardSizedFont != 0)
  322. {
  323. if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0)
  324. {
  325. fontH = standardSizedFont;
  326. OUTLINETEXTMETRIC otm;
  327. if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
  328. {
  329. lf.lfHeight = -(int) otm.otmEMSquare;
  330. fontH = CreateFontIndirect (&lf);
  331. SelectObject (dc, fontH);
  332. DeleteObject (standardSizedFont);
  333. }
  334. }
  335. }
  336. }
  337. void createKerningPairs (HDC dc, const float height)
  338. {
  339. HeapBlock<KERNINGPAIR> rawKerning;
  340. const DWORD numKPs = GetKerningPairs (dc, 0, 0);
  341. rawKerning.calloc (numKPs);
  342. GetKerningPairs (dc, numKPs, rawKerning);
  343. kerningPairs.ensureStorageAllocated ((int) numKPs);
  344. for (DWORD i = 0; i < numKPs; ++i)
  345. {
  346. KerningPair kp;
  347. kp.glyph1 = getGlyphForChar (dc, rawKerning[i].wFirst);
  348. kp.glyph2 = getGlyphForChar (dc, rawKerning[i].wSecond);
  349. const int standardWidth = getGlyphWidth (dc, kp.glyph1);
  350. kp.kerning = (standardWidth + rawKerning[i].iKernAmount) / height;
  351. kerningPairs.add (kp);
  352. kp.glyph2 = -1; // add another entry for the standard width version..
  353. kp.kerning = standardWidth / height;
  354. kerningPairs.add (kp);
  355. }
  356. }
  357. static int getGlyphForChar (HDC dc, juce_wchar character)
  358. {
  359. const WCHAR charToTest[] = { (WCHAR) character, 0 };
  360. WORD index = 0;
  361. if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR
  362. || index == 0xffff)
  363. return -1;
  364. return index;
  365. }
  366. static int getGlyphWidth (HDC dc, int glyphNumber)
  367. {
  368. GLYPHMETRICS gm;
  369. gm.gmCellIncX = 0;
  370. GetGlyphOutline (dc, (UINT) glyphNumber, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, 0, &identityMatrix);
  371. return gm.gmCellIncX;
  372. }
  373. float getKerning (HDC dc, const int glyph1, const int glyph2)
  374. {
  375. KerningPair kp;
  376. kp.glyph1 = glyph1;
  377. kp.glyph2 = glyph2;
  378. int index = kerningPairs.indexOf (kp);
  379. if (index < 0)
  380. {
  381. kp.glyph2 = -1;
  382. index = kerningPairs.indexOf (kp);
  383. if (index < 0)
  384. {
  385. kp.glyph2 = -1;
  386. kp.kerning = getGlyphWidth (dc, kp.glyph1) / (float) tm.tmHeight;
  387. kerningPairs.add (kp);
  388. return kp.kerning;
  389. }
  390. }
  391. return kerningPairs.getReference (index).kerning;
  392. }
  393. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface);
  394. };
  395. const MAT2 WindowsTypeface::identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
  396. Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font)
  397. {
  398. #if JUCE_USE_DIRECTWRITE
  399. const Direct2DFactories& factories = Direct2DFactories::getInstance();
  400. if (factories.systemFonts != nullptr)
  401. return new WindowsDirectWriteTypeface (font, factories.systemFonts);
  402. else
  403. #endif
  404. return new WindowsTypeface (font);
  405. }