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.

658 lines
20KB

  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. juce_free (kps);
  207. }
  208. }
  209. static FontDCHolder* getInstance() throw()
  210. {
  211. static FontDCHolder* instance = 0;
  212. if (instance == 0)
  213. instance = new FontDCHolder();
  214. return instance;
  215. }
  216. //==============================================================================
  217. HDC loadFont (const String& fontName_,
  218. const bool bold_,
  219. const bool italic_,
  220. const int size_) throw()
  221. {
  222. if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_)
  223. {
  224. fontName = fontName_;
  225. bold = bold_;
  226. italic = italic_;
  227. size = size_;
  228. if (dc != 0)
  229. {
  230. DeleteDC (dc);
  231. DeleteObject (fontH);
  232. juce_free (kps);
  233. kps = 0;
  234. }
  235. fontH = 0;
  236. dc = CreateCompatibleDC (0);
  237. SetMapperFlags (dc, 0);
  238. SetMapMode (dc, MM_TEXT);
  239. LOGFONT lf;
  240. LOGFONTW lfw;
  241. HFONT standardSizedFont = 0;
  242. if (wCreateFontIndirectW != 0)
  243. {
  244. zerostruct (lfw);
  245. lfw.lfCharSet = DEFAULT_CHARSET;
  246. lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  247. lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
  248. lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  249. lfw.lfQuality = PROOF_QUALITY;
  250. lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
  251. lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
  252. fontName.copyToBuffer (lfw.lfFaceName, LF_FACESIZE - 1);
  253. lfw.lfHeight = size > 0 ? size : -256;
  254. standardSizedFont = wCreateFontIndirectW (&lfw);
  255. }
  256. else
  257. {
  258. zerostruct (lf);
  259. lf.lfCharSet = DEFAULT_CHARSET;
  260. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  261. lf.lfOutPrecision = OUT_OUTLINE_PRECIS;
  262. lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  263. lf.lfQuality = PROOF_QUALITY;
  264. lf.lfItalic = (BYTE) (italic ? TRUE : FALSE);
  265. lf.lfWeight = bold ? FW_BOLD : FW_NORMAL;
  266. fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
  267. lf.lfHeight = size > 0 ? size : -256;
  268. standardSizedFont = CreateFontIndirect (&lf);
  269. }
  270. if (standardSizedFont != 0)
  271. {
  272. if (SelectObject (dc, standardSizedFont) != 0)
  273. {
  274. fontH = standardSizedFont;
  275. if (size == 0)
  276. {
  277. OUTLINETEXTMETRIC otm;
  278. if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
  279. {
  280. if (wCreateFontIndirectW != 0)
  281. {
  282. lfw.lfHeight = -(int) otm.otmEMSquare;
  283. fontH = wCreateFontIndirectW (&lfw);
  284. }
  285. else
  286. {
  287. lf.lfHeight = -(int) otm.otmEMSquare;
  288. fontH = CreateFontIndirect (&lf);
  289. }
  290. SelectObject (dc, fontH);
  291. DeleteObject (standardSizedFont);
  292. }
  293. }
  294. }
  295. else
  296. {
  297. jassertfalse
  298. }
  299. }
  300. else
  301. {
  302. jassertfalse
  303. }
  304. }
  305. return dc;
  306. }
  307. //==============================================================================
  308. KERNINGPAIR* getKerningPairs (int& numKPs_) throw()
  309. {
  310. if (kps == 0)
  311. {
  312. if (wGetKerningPairsW != 0)
  313. {
  314. numKPs = wGetKerningPairsW (dc, 0, 0);
  315. kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
  316. wGetKerningPairsW (dc, numKPs, kps);
  317. }
  318. else
  319. {
  320. numKPs = GetKerningPairs (dc, 0, 0);
  321. kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
  322. GetKerningPairs (dc, numKPs, kps);
  323. }
  324. }
  325. numKPs_ = numKPs;
  326. return kps;
  327. }
  328. };
  329. //==============================================================================
  330. static MAT2 identityMatrix;
  331. static void addGlyphToTypeface (HDC dc,
  332. juce_wchar character,
  333. Typeface& dest,
  334. bool addKerning)
  335. {
  336. Path destShape;
  337. GLYPHMETRICS gm;
  338. float height;
  339. BOOL ok = false;
  340. if (wGetTextMetricsW != 0)
  341. {
  342. TEXTMETRICW tm;
  343. ok = wGetTextMetricsW (dc, &tm);
  344. height = (float) tm.tmHeight;
  345. }
  346. else
  347. {
  348. TEXTMETRIC tm;
  349. ok = GetTextMetrics (dc, &tm);
  350. height = (float) tm.tmHeight;
  351. }
  352. if (! ok)
  353. {
  354. dest.addGlyph (character, destShape, 0);
  355. return;
  356. }
  357. const float scaleX = 1.0f / height;
  358. const float scaleY = -1.0f / height;
  359. int bufSize;
  360. if (wGetGlyphOutlineW != 0)
  361. bufSize = wGetGlyphOutlineW (dc, character, GGO_NATIVE,
  362. &gm, 0, 0, &identityMatrix);
  363. else
  364. bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
  365. &gm, 0, 0, &identityMatrix);
  366. if (bufSize > 0)
  367. {
  368. char* const data = (char*) juce_malloc (bufSize);
  369. if (wGetGlyphOutlineW != 0)
  370. wGetGlyphOutlineW (dc, character, GGO_NATIVE, &gm,
  371. bufSize, data, &identityMatrix);
  372. else
  373. GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
  374. bufSize, data, &identityMatrix);
  375. const TTPOLYGONHEADER* pheader = (TTPOLYGONHEADER*) data;
  376. while ((char*) pheader < data + bufSize)
  377. {
  378. #define remapX(v) (scaleX * (v).x.value)
  379. #define remapY(v) (scaleY * (v).y.value)
  380. float x = remapX (pheader->pfxStart);
  381. float y = remapY (pheader->pfxStart);
  382. destShape.startNewSubPath (x, y);
  383. const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
  384. const char* const curveEnd = ((const char*) pheader) + pheader->cb;
  385. while ((const char*) curve < curveEnd)
  386. {
  387. if (curve->wType == TT_PRIM_LINE)
  388. {
  389. for (int i = 0; i < curve->cpfx; ++i)
  390. {
  391. x = remapX (curve->apfx [i]);
  392. y = remapY (curve->apfx [i]);
  393. destShape.lineTo (x, y);
  394. }
  395. }
  396. else if (curve->wType == TT_PRIM_QSPLINE)
  397. {
  398. for (int i = 0; i < curve->cpfx - 1; ++i)
  399. {
  400. const float x2 = remapX (curve->apfx [i]);
  401. const float y2 = remapY (curve->apfx [i]);
  402. float x3, y3;
  403. if (i < curve->cpfx - 2)
  404. {
  405. x3 = 0.5f * (x2 + remapX (curve->apfx [i + 1]));
  406. y3 = 0.5f * (y2 + remapY (curve->apfx [i + 1]));
  407. }
  408. else
  409. {
  410. x3 = remapX (curve->apfx [i + 1]);
  411. y3 = remapY (curve->apfx [i + 1]);
  412. }
  413. destShape.quadraticTo (x2, y2, x3, y3);
  414. x = x3;
  415. y = y3;
  416. }
  417. }
  418. curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
  419. }
  420. pheader = (const TTPOLYGONHEADER*) curve;
  421. destShape.closeSubPath();
  422. }
  423. juce_free (data);
  424. }
  425. dest.addGlyph (character, destShape, gm.gmCellIncX / height);
  426. if (addKerning)
  427. {
  428. int numKPs;
  429. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  430. for (int i = 0; i < numKPs; ++i)
  431. {
  432. if (kps[i].wFirst == character)
  433. {
  434. dest.addKerningPair (kps[i].wFirst,
  435. kps[i].wSecond,
  436. kps[i].iKernAmount / height);
  437. }
  438. }
  439. }
  440. }
  441. //==============================================================================
  442. void Typeface::findAndAddSystemGlyph (juce_wchar character)
  443. {
  444. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), 0);
  445. addGlyphToTypeface (dc, character, *this, true);
  446. }
  447. /*Image* Typeface::renderGlyphToImage (juce_wchar character, float& topLeftX, float& topLeftY)
  448. {
  449. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), hintingSize);
  450. int bufSize;
  451. GLYPHMETRICS gm;
  452. const UINT format = GGO_GRAY2_BITMAP;
  453. const int shift = 6;
  454. if (wGetGlyphOutlineW != 0)
  455. bufSize = wGetGlyphOutlineW (dc, character, format, &gm, 0, 0, &identityMatrix);
  456. else
  457. bufSize = GetGlyphOutline (dc, character, format, &gm, 0, 0, &identityMatrix);
  458. Image* im = new Image (Image::SingleChannel, jmax (1, gm.gmBlackBoxX), jmax (1, gm.gmBlackBoxY), true);
  459. if (bufSize > 0)
  460. {
  461. topLeftX = (float) gm.gmptGlyphOrigin.x;
  462. topLeftY = (float) -gm.gmptGlyphOrigin.y;
  463. uint8* const data = (uint8*) juce_calloc (bufSize);
  464. if (wGetGlyphOutlineW != 0)
  465. wGetGlyphOutlineW (dc, character, format, &gm, bufSize, data, &identityMatrix);
  466. else
  467. GetGlyphOutline (dc, character, format, &gm, bufSize, data, &identityMatrix);
  468. const int stride = ((gm.gmBlackBoxX + 3) & ~3);
  469. for (int y = gm.gmBlackBoxY; --y >= 0;)
  470. {
  471. for (int x = gm.gmBlackBoxX; --x >= 0;)
  472. {
  473. const int level = data [x + y * stride] << shift;
  474. if (level > 0)
  475. im->setPixelAt (x, y, Colour ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff, (uint8) jmin (0xff, level)));
  476. }
  477. }
  478. juce_free (data);
  479. }
  480. return im;
  481. }*/
  482. //==============================================================================
  483. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  484. bool bold,
  485. bool italic,
  486. bool addAllGlyphsToFont)
  487. {
  488. zerostruct (identityMatrix);
  489. identityMatrix.eM11.value = 1;
  490. identityMatrix.eM22.value = 1;
  491. clear();
  492. HDC dc = FontDCHolder::getInstance()->loadFont (fontName, bold, italic, 0);
  493. float height;
  494. int firstChar, lastChar;
  495. if (wGetTextMetricsW != 0)
  496. {
  497. TEXTMETRICW tm;
  498. wGetTextMetricsW (dc, &tm);
  499. height = (float) tm.tmHeight;
  500. firstChar = tm.tmFirstChar;
  501. lastChar = tm.tmLastChar;
  502. setAscent (tm.tmAscent / height);
  503. setDefaultCharacter (tm.tmDefaultChar);
  504. }
  505. else
  506. {
  507. TEXTMETRIC tm;
  508. GetTextMetrics (dc, &tm);
  509. height = (float) tm.tmHeight;
  510. firstChar = tm.tmFirstChar;
  511. lastChar = tm.tmLastChar;
  512. setAscent (tm.tmAscent / height);
  513. setDefaultCharacter (tm.tmDefaultChar);
  514. }
  515. setName (fontName);
  516. setBold (bold);
  517. setItalic (italic);
  518. if (addAllGlyphsToFont)
  519. {
  520. for (int character = firstChar; character <= lastChar; ++character)
  521. addGlyphToTypeface (dc, (juce_wchar) character, *this, false);
  522. int numKPs;
  523. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  524. for (int i = 0; i < numKPs; ++i)
  525. {
  526. addKerningPair (kps[i].wFirst,
  527. kps[i].wSecond,
  528. kps[i].iKernAmount / height);
  529. }
  530. }
  531. }
  532. END_JUCE_NAMESPACE