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.

663 lines
21KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "win32_headers.h"
  24. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  25. BEGIN_JUCE_NAMESPACE
  26. #include "../../../src/juce_appframework/gui/graphics/fonts/juce_Font.h"
  27. #include "../../../src/juce_appframework/application/juce_DeletedAtShutdown.h"
  28. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  29. #include "../../../src/juce_appframework/gui/graphics/imaging/juce_Image.h"
  30. //==============================================================================
  31. UNICODE_FUNCTION (GetGlyphOutlineW, DWORD, (HDC, UINT, UINT, LPGLYPHMETRICS, DWORD, LPVOID, CONST MAT2*))
  32. UNICODE_FUNCTION (GetTextMetricsW, BOOL, (HDC, LPTEXTMETRICW))
  33. UNICODE_FUNCTION (GetKerningPairsW, DWORD, (HDC, DWORD, LPKERNINGPAIR))
  34. UNICODE_FUNCTION (EnumFontFamiliesExW, int, (HDC, LPLOGFONTW, FONTENUMPROCW, LPARAM, DWORD))
  35. UNICODE_FUNCTION (CreateFontIndirectW, HFONT, (CONST LOGFONTW *));
  36. static void juce_initialiseUnicodeFileFontFunctions()
  37. {
  38. static bool initialised = false;
  39. if (! initialised)
  40. {
  41. initialised = true;
  42. if ((SystemStats::getOperatingSystemType() & SystemStats::WindowsNT) != 0)
  43. {
  44. HMODULE h = LoadLibraryA ("gdi32.dll");
  45. UNICODE_FUNCTION_LOAD (GetGlyphOutlineW)
  46. UNICODE_FUNCTION_LOAD (GetTextMetricsW)
  47. UNICODE_FUNCTION_LOAD (GetKerningPairsW)
  48. UNICODE_FUNCTION_LOAD (EnumFontFamiliesExW)
  49. UNICODE_FUNCTION_LOAD (CreateFontIndirectW)
  50. }
  51. }
  52. }
  53. //==============================================================================
  54. static int CALLBACK fontEnum2 (ENUMLOGFONTEX* lpelfe,
  55. NEWTEXTMETRICEX*,
  56. int type,
  57. LPARAM lParam)
  58. {
  59. if (lpelfe != 0 && type == TRUETYPE_FONTTYPE)
  60. {
  61. const String fontName (lpelfe->elfLogFont.lfFaceName);
  62. ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters (T("@")));
  63. }
  64. return 1;
  65. }
  66. static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe,
  67. NEWTEXTMETRICEXW*,
  68. int type,
  69. LPARAM lParam)
  70. {
  71. if (lpelfe != 0 && type == TRUETYPE_FONTTYPE)
  72. {
  73. const String fontName (lpelfe->elfLogFont.lfFaceName);
  74. ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters (T("@")));
  75. }
  76. return 1;
  77. }
  78. static int CALLBACK fontEnum1 (ENUMLOGFONTEX* lpelfe,
  79. NEWTEXTMETRICEX*,
  80. int type,
  81. LPARAM lParam)
  82. {
  83. if (lpelfe != 0
  84. && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0))
  85. {
  86. LOGFONT lf;
  87. zerostruct (lf);
  88. lf.lfWeight = FW_DONTCARE;
  89. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  90. lf.lfQuality = DEFAULT_QUALITY;
  91. lf.lfCharSet = DEFAULT_CHARSET;
  92. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  93. lf.lfPitchAndFamily = FF_DONTCARE;
  94. const String fontName (lpelfe->elfLogFont.lfFaceName);
  95. fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
  96. HDC dc = CreateCompatibleDC (0);
  97. EnumFontFamiliesEx (dc, &lf,
  98. (FONTENUMPROC) &fontEnum2,
  99. lParam, 0);
  100. DeleteDC (dc);
  101. }
  102. return 1;
  103. }
  104. static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe,
  105. NEWTEXTMETRICEXW*,
  106. int type,
  107. LPARAM lParam)
  108. {
  109. if (lpelfe != 0
  110. && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0))
  111. {
  112. LOGFONTW lf;
  113. zerostruct (lf);
  114. lf.lfWeight = FW_DONTCARE;
  115. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  116. lf.lfQuality = DEFAULT_QUALITY;
  117. lf.lfCharSet = DEFAULT_CHARSET;
  118. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  119. lf.lfPitchAndFamily = FF_DONTCARE;
  120. const String fontName (lpelfe->elfLogFont.lfFaceName);
  121. fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
  122. HDC dc = CreateCompatibleDC (0);
  123. wEnumFontFamiliesExW (dc, &lf,
  124. (FONTENUMPROCW) &wfontEnum2,
  125. lParam, 0);
  126. DeleteDC (dc);
  127. }
  128. return 1;
  129. }
  130. const StringArray Font::findAllTypefaceNames()
  131. {
  132. StringArray results;
  133. HDC dc = CreateCompatibleDC (0);
  134. if (wEnumFontFamiliesExW != 0)
  135. {
  136. LOGFONTW lf;
  137. zerostruct (lf);
  138. lf.lfWeight = FW_DONTCARE;
  139. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  140. lf.lfQuality = DEFAULT_QUALITY;
  141. lf.lfCharSet = DEFAULT_CHARSET;
  142. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  143. lf.lfPitchAndFamily = FF_DONTCARE;
  144. lf.lfFaceName[0] = 0;
  145. wEnumFontFamiliesExW (dc, &lf,
  146. (FONTENUMPROCW) &wfontEnum1,
  147. (LPARAM) &results, 0);
  148. }
  149. else
  150. {
  151. LOGFONT lf;
  152. zerostruct (lf);
  153. lf.lfWeight = FW_DONTCARE;
  154. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  155. lf.lfQuality = DEFAULT_QUALITY;
  156. lf.lfCharSet = DEFAULT_CHARSET;
  157. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  158. lf.lfPitchAndFamily = FF_DONTCARE;
  159. lf.lfFaceName[0] = 0;
  160. EnumFontFamiliesEx (dc, &lf,
  161. (FONTENUMPROC) &fontEnum1,
  162. (LPARAM) &results, 0);
  163. }
  164. DeleteDC (dc);
  165. results.sort (true);
  166. return results;
  167. }
  168. void Font::getDefaultFontNames (String& defaultSans,
  169. String& defaultSerif,
  170. String& defaultFixed)
  171. {
  172. defaultSans = T("Verdana");
  173. defaultSerif = T("Times");
  174. defaultFixed = T("Lucida Console");
  175. }
  176. //==============================================================================
  177. class FontDCHolder : private DeletedAtShutdown
  178. {
  179. HDC dc;
  180. String fontName;
  181. KERNINGPAIR* kps;
  182. int numKPs;
  183. bool bold, italic;
  184. int size;
  185. FontDCHolder (const FontDCHolder&);
  186. const FontDCHolder& operator= (const FontDCHolder&);
  187. public:
  188. HFONT fontH;
  189. //==============================================================================
  190. FontDCHolder() throw()
  191. : dc (0),
  192. kps (0),
  193. numKPs (0),
  194. bold (false),
  195. italic (false),
  196. size (0)
  197. {
  198. juce_initialiseUnicodeFileFontFunctions();
  199. }
  200. ~FontDCHolder() throw()
  201. {
  202. if (dc != 0)
  203. {
  204. DeleteDC (dc);
  205. DeleteObject (fontH);
  206. if (kps)
  207. juce_free (kps);
  208. }
  209. }
  210. static FontDCHolder* getInstance() throw()
  211. {
  212. static FontDCHolder* instance = 0;
  213. if (instance == 0)
  214. instance = new FontDCHolder();
  215. return instance;
  216. }
  217. //==============================================================================
  218. HDC loadFont (const String& fontName_,
  219. const bool bold_,
  220. const bool italic_,
  221. const int size_) throw()
  222. {
  223. if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_)
  224. {
  225. fontName = fontName_;
  226. bold = bold_;
  227. italic = italic_;
  228. size = size_;
  229. if (dc != 0)
  230. {
  231. DeleteDC (dc);
  232. DeleteObject (fontH);
  233. if (kps != 0)
  234. {
  235. juce_free (kps);
  236. kps = 0;
  237. }
  238. }
  239. fontH = 0;
  240. dc = CreateCompatibleDC (0);
  241. SetMapperFlags (dc, 0);
  242. SetMapMode (dc, MM_TEXT);
  243. LOGFONT lf;
  244. LOGFONTW lfw;
  245. HFONT standardSizedFont = 0;
  246. if (wCreateFontIndirectW != 0)
  247. {
  248. zerostruct (lfw);
  249. lfw.lfCharSet = DEFAULT_CHARSET;
  250. lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  251. lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
  252. lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  253. lfw.lfQuality = PROOF_QUALITY;
  254. lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
  255. lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
  256. fontName.copyToBuffer (lfw.lfFaceName, LF_FACESIZE - 1);
  257. lfw.lfHeight = size > 0 ? size : -256;
  258. standardSizedFont = wCreateFontIndirectW (&lfw);
  259. }
  260. else
  261. {
  262. zerostruct (lf);
  263. lf.lfCharSet = DEFAULT_CHARSET;
  264. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  265. lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
  266. lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  267. lf.lfQuality = PROOF_QUALITY;
  268. lf.lfItalic = (BYTE) (italic ? TRUE : FALSE);
  269. lf.lfWeight = bold ? FW_BOLD : FW_NORMAL;
  270. fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
  271. lf.lfHeight = size > 0 ? size : -256;
  272. standardSizedFont = CreateFontIndirect (&lf);
  273. }
  274. if (standardSizedFont != 0)
  275. {
  276. if (SelectObject (dc, standardSizedFont) != 0)
  277. {
  278. fontH = standardSizedFont;
  279. if (size == 0)
  280. {
  281. OUTLINETEXTMETRIC otm;
  282. if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
  283. {
  284. if (wCreateFontIndirectW != 0)
  285. {
  286. lfw.lfHeight = -(int) otm.otmEMSquare;
  287. fontH = wCreateFontIndirectW (&lfw);
  288. }
  289. else
  290. {
  291. lf.lfHeight = -(int) otm.otmEMSquare;
  292. fontH = CreateFontIndirect (&lf);
  293. }
  294. SelectObject (dc, fontH);
  295. DeleteObject (standardSizedFont);
  296. }
  297. }
  298. }
  299. else
  300. {
  301. jassertfalse
  302. }
  303. }
  304. else
  305. {
  306. jassertfalse
  307. }
  308. }
  309. return dc;
  310. }
  311. //==============================================================================
  312. KERNINGPAIR* getKerningPairs (int& numKPs_) throw()
  313. {
  314. if (kps == 0)
  315. {
  316. if (wGetKerningPairsW != 0)
  317. {
  318. numKPs = wGetKerningPairsW (dc, 0, 0);
  319. kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
  320. wGetKerningPairsW (dc, numKPs, kps);
  321. }
  322. else
  323. {
  324. numKPs = GetKerningPairs (dc, 0, 0);
  325. kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
  326. GetKerningPairs (dc, numKPs, kps);
  327. }
  328. }
  329. numKPs_ = numKPs;
  330. return kps;
  331. }
  332. };
  333. //==============================================================================
  334. static MAT2 identityMatrix;
  335. static void addGlyphToTypeface (HDC dc,
  336. juce_wchar character,
  337. Typeface& dest,
  338. bool addKerning)
  339. {
  340. Path destShape;
  341. GLYPHMETRICS gm;
  342. float height;
  343. BOOL ok = false;
  344. if (wGetTextMetricsW != 0)
  345. {
  346. TEXTMETRICW tm;
  347. ok = wGetTextMetricsW (dc, &tm);
  348. height = (float) tm.tmHeight;
  349. }
  350. else
  351. {
  352. TEXTMETRIC tm;
  353. ok = GetTextMetrics (dc, &tm);
  354. height = (float) tm.tmHeight;
  355. }
  356. if (! ok)
  357. {
  358. dest.addGlyph (character, destShape, 0);
  359. return;
  360. }
  361. const float scaleX = 1.0f / height;
  362. const float scaleY = -1.0f / height;
  363. int bufSize;
  364. if (wGetGlyphOutlineW != 0)
  365. bufSize = wGetGlyphOutlineW (dc, character, GGO_NATIVE,
  366. &gm, 0, 0, &identityMatrix);
  367. else
  368. bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
  369. &gm, 0, 0, &identityMatrix);
  370. if (bufSize > 0)
  371. {
  372. char* const data = (char*) juce_malloc (bufSize);
  373. if (wGetGlyphOutlineW != 0)
  374. wGetGlyphOutlineW (dc, character, GGO_NATIVE, &gm,
  375. bufSize, data, &identityMatrix);
  376. else
  377. GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
  378. bufSize, data, &identityMatrix);
  379. const TTPOLYGONHEADER* pheader = (TTPOLYGONHEADER*) data;
  380. while ((char*) pheader < data + bufSize)
  381. {
  382. #define remapX(v) (scaleX * (v).x.value)
  383. #define remapY(v) (scaleY * (v).y.value)
  384. float x = remapX (pheader->pfxStart);
  385. float y = remapY (pheader->pfxStart);
  386. destShape.startNewSubPath (x, y);
  387. const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
  388. const char* const curveEnd = ((const char*) pheader) + pheader->cb;
  389. while ((const char*) curve < curveEnd)
  390. {
  391. if (curve->wType == TT_PRIM_LINE)
  392. {
  393. for (int i = 0; i < curve->cpfx; ++i)
  394. {
  395. x = remapX (curve->apfx [i]);
  396. y = remapY (curve->apfx [i]);
  397. destShape.lineTo (x, y);
  398. }
  399. }
  400. else if (curve->wType == TT_PRIM_QSPLINE)
  401. {
  402. for (int i = 0; i < curve->cpfx - 1; ++i)
  403. {
  404. const float x2 = remapX (curve->apfx [i]);
  405. const float y2 = remapY (curve->apfx [i]);
  406. float x3, y3;
  407. if (i < curve->cpfx - 2)
  408. {
  409. x3 = 0.5f * (x2 + remapX (curve->apfx [i + 1]));
  410. y3 = 0.5f * (y2 + remapY (curve->apfx [i + 1]));
  411. }
  412. else
  413. {
  414. x3 = remapX (curve->apfx [i + 1]);
  415. y3 = remapY (curve->apfx [i + 1]);
  416. }
  417. destShape.quadraticTo (x2, y2, x3, y3);
  418. x = x3;
  419. y = y3;
  420. }
  421. }
  422. curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
  423. }
  424. pheader = (const TTPOLYGONHEADER*) curve;
  425. destShape.closeSubPath();
  426. }
  427. juce_free (data);
  428. }
  429. dest.addGlyph (character, destShape, gm.gmCellIncX / height);
  430. if (addKerning)
  431. {
  432. int numKPs;
  433. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  434. for (int i = 0; i < numKPs; ++i)
  435. {
  436. if (kps[i].wFirst == character)
  437. {
  438. dest.addKerningPair (kps[i].wFirst,
  439. kps[i].wSecond,
  440. kps[i].iKernAmount / height);
  441. }
  442. }
  443. }
  444. }
  445. //==============================================================================
  446. void Typeface::findAndAddSystemGlyph (juce_wchar character)
  447. {
  448. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), 0);
  449. addGlyphToTypeface (dc, character, *this, true);
  450. }
  451. /*Image* Typeface::renderGlyphToImage (juce_wchar character, float& topLeftX, float& topLeftY)
  452. {
  453. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), hintingSize);
  454. int bufSize;
  455. GLYPHMETRICS gm;
  456. const UINT format = GGO_GRAY2_BITMAP;
  457. const int shift = 6;
  458. if (wGetGlyphOutlineW != 0)
  459. bufSize = wGetGlyphOutlineW (dc, character, format, &gm, 0, 0, &identityMatrix);
  460. else
  461. bufSize = GetGlyphOutline (dc, character, format, &gm, 0, 0, &identityMatrix);
  462. Image* im = new Image (Image::SingleChannel, jmax (1, gm.gmBlackBoxX), jmax (1, gm.gmBlackBoxY), true);
  463. if (bufSize > 0)
  464. {
  465. topLeftX = (float) gm.gmptGlyphOrigin.x;
  466. topLeftY = (float) -gm.gmptGlyphOrigin.y;
  467. uint8* const data = (uint8*) juce_calloc (bufSize);
  468. if (wGetGlyphOutlineW != 0)
  469. wGetGlyphOutlineW (dc, character, format, &gm, bufSize, data, &identityMatrix);
  470. else
  471. GetGlyphOutline (dc, character, format, &gm, bufSize, data, &identityMatrix);
  472. const int stride = ((gm.gmBlackBoxX + 3) & ~3);
  473. for (int y = gm.gmBlackBoxY; --y >= 0;)
  474. {
  475. for (int x = gm.gmBlackBoxX; --x >= 0;)
  476. {
  477. const int level = data [x + y * stride] << shift;
  478. if (level > 0)
  479. im->setPixelAt (x, y, Colour ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff, (uint8) jmin (0xff, level)));
  480. }
  481. }
  482. juce_free (data);
  483. }
  484. return im;
  485. }*/
  486. //==============================================================================
  487. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  488. bool bold,
  489. bool italic,
  490. bool addAllGlyphsToFont)
  491. {
  492. zerostruct (identityMatrix);
  493. identityMatrix.eM11.value = 1;
  494. identityMatrix.eM22.value = 1;
  495. clear();
  496. HDC dc = FontDCHolder::getInstance()->loadFont (fontName, bold, italic, 0);
  497. float height;
  498. int firstChar, lastChar;
  499. if (wGetTextMetricsW != 0)
  500. {
  501. TEXTMETRICW tm;
  502. wGetTextMetricsW (dc, &tm);
  503. height = (float) tm.tmHeight;
  504. firstChar = tm.tmFirstChar;
  505. lastChar = tm.tmLastChar;
  506. setAscent (tm.tmAscent / height);
  507. setDefaultCharacter (tm.tmDefaultChar);
  508. }
  509. else
  510. {
  511. TEXTMETRIC tm;
  512. GetTextMetrics (dc, &tm);
  513. height = (float) tm.tmHeight;
  514. firstChar = tm.tmFirstChar;
  515. lastChar = tm.tmLastChar;
  516. setAscent (tm.tmAscent / height);
  517. setDefaultCharacter (tm.tmDefaultChar);
  518. }
  519. setName (fontName);
  520. setBold (bold);
  521. setItalic (italic);
  522. if (addAllGlyphsToFont)
  523. {
  524. for (int character = firstChar; character <= lastChar; ++character)
  525. addGlyphToTypeface (dc, (juce_wchar) character, *this, false);
  526. int numKPs;
  527. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  528. for (int i = 0; i < numKPs; ++i)
  529. {
  530. addKerningPair (kps[i].wFirst,
  531. kps[i].wSecond,
  532. kps[i].iKernAmount / height);
  533. }
  534. }
  535. }
  536. END_JUCE_NAMESPACE