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.

510 lines
16KB

  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_core/basics/juce_Singleton.h"
  30. #include "../../../src/juce_appframework/gui/graphics/imaging/juce_Image.h"
  31. //==============================================================================
  32. static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe,
  33. NEWTEXTMETRICEXW*,
  34. int type,
  35. LPARAM lParam)
  36. {
  37. if (lpelfe != 0 && type == TRUETYPE_FONTTYPE)
  38. {
  39. const String fontName (lpelfe->elfLogFont.lfFaceName);
  40. ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters (T("@")));
  41. }
  42. return 1;
  43. }
  44. static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe,
  45. NEWTEXTMETRICEXW*,
  46. int type,
  47. LPARAM lParam)
  48. {
  49. if (lpelfe != 0
  50. && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0))
  51. {
  52. LOGFONTW lf;
  53. zerostruct (lf);
  54. lf.lfWeight = FW_DONTCARE;
  55. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  56. lf.lfQuality = DEFAULT_QUALITY;
  57. lf.lfCharSet = DEFAULT_CHARSET;
  58. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  59. lf.lfPitchAndFamily = FF_DONTCARE;
  60. const String fontName (lpelfe->elfLogFont.lfFaceName);
  61. fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
  62. HDC dc = CreateCompatibleDC (0);
  63. EnumFontFamiliesEx (dc, &lf,
  64. (FONTENUMPROCW) &wfontEnum2,
  65. lParam, 0);
  66. DeleteDC (dc);
  67. }
  68. return 1;
  69. }
  70. const StringArray Font::findAllTypefaceNames() throw()
  71. {
  72. StringArray results;
  73. HDC dc = CreateCompatibleDC (0);
  74. {
  75. LOGFONTW lf;
  76. zerostruct (lf);
  77. lf.lfWeight = FW_DONTCARE;
  78. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  79. lf.lfQuality = DEFAULT_QUALITY;
  80. lf.lfCharSet = DEFAULT_CHARSET;
  81. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  82. lf.lfPitchAndFamily = FF_DONTCARE;
  83. lf.lfFaceName[0] = 0;
  84. EnumFontFamiliesEx (dc, &lf,
  85. (FONTENUMPROCW) &wfontEnum1,
  86. (LPARAM) &results, 0);
  87. }
  88. DeleteDC (dc);
  89. results.sort (true);
  90. return results;
  91. }
  92. extern bool juce_IsRunningInWine() throw();
  93. void Font::getDefaultFontNames (String& defaultSans,
  94. String& defaultSerif,
  95. String& defaultFixed) throw()
  96. {
  97. if (juce_IsRunningInWine())
  98. {
  99. // If we're running in Wine, then use fonts that might be available on Linux..
  100. defaultSans = "Bitstream Vera Sans";
  101. defaultSerif = "Bitstream Vera Serif";
  102. defaultFixed = "Bitstream Vera Sans Mono";
  103. }
  104. else
  105. {
  106. defaultSans = "Verdana";
  107. defaultSerif = "Times";
  108. defaultFixed = "Lucida Console";
  109. }
  110. }
  111. //==============================================================================
  112. class FontDCHolder : private DeletedAtShutdown
  113. {
  114. HDC dc;
  115. String fontName;
  116. KERNINGPAIR* kps;
  117. int numKPs;
  118. bool bold, italic;
  119. int size;
  120. FontDCHolder (const FontDCHolder&);
  121. const FontDCHolder& operator= (const FontDCHolder&);
  122. public:
  123. HFONT fontH;
  124. //==============================================================================
  125. FontDCHolder() throw()
  126. : dc (0),
  127. kps (0),
  128. numKPs (0),
  129. bold (false),
  130. italic (false),
  131. size (0)
  132. {
  133. }
  134. ~FontDCHolder() throw()
  135. {
  136. if (dc != 0)
  137. {
  138. DeleteDC (dc);
  139. DeleteObject (fontH);
  140. juce_free (kps);
  141. }
  142. clearSingletonInstance();
  143. }
  144. juce_DeclareSingleton_SingleThreaded_Minimal (FontDCHolder);
  145. //==============================================================================
  146. HDC loadFont (const String& fontName_,
  147. const bool bold_,
  148. const bool italic_,
  149. const int size_) throw()
  150. {
  151. if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_)
  152. {
  153. fontName = fontName_;
  154. bold = bold_;
  155. italic = italic_;
  156. size = size_;
  157. if (dc != 0)
  158. {
  159. DeleteDC (dc);
  160. DeleteObject (fontH);
  161. juce_free (kps);
  162. kps = 0;
  163. }
  164. fontH = 0;
  165. dc = CreateCompatibleDC (0);
  166. SetMapperFlags (dc, 0);
  167. SetMapMode (dc, MM_TEXT);
  168. LOGFONTW lfw;
  169. zerostruct (lfw);
  170. lfw.lfCharSet = DEFAULT_CHARSET;
  171. lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  172. lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
  173. lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  174. lfw.lfQuality = PROOF_QUALITY;
  175. lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
  176. lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
  177. fontName.copyToBuffer (lfw.lfFaceName, LF_FACESIZE - 1);
  178. lfw.lfHeight = size > 0 ? size : -256;
  179. HFONT standardSizedFont = CreateFontIndirect (&lfw);
  180. if (standardSizedFont != 0)
  181. {
  182. if (SelectObject (dc, standardSizedFont) != 0)
  183. {
  184. fontH = standardSizedFont;
  185. if (size == 0)
  186. {
  187. OUTLINETEXTMETRIC otm;
  188. if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
  189. {
  190. lfw.lfHeight = -(int) otm.otmEMSquare;
  191. fontH = CreateFontIndirect (&lfw);
  192. SelectObject (dc, fontH);
  193. DeleteObject (standardSizedFont);
  194. }
  195. }
  196. }
  197. else
  198. {
  199. jassertfalse
  200. }
  201. }
  202. else
  203. {
  204. jassertfalse
  205. }
  206. }
  207. return dc;
  208. }
  209. //==============================================================================
  210. KERNINGPAIR* getKerningPairs (int& numKPs_) throw()
  211. {
  212. if (kps == 0)
  213. {
  214. numKPs = GetKerningPairs (dc, 0, 0);
  215. kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
  216. GetKerningPairs (dc, numKPs, kps);
  217. }
  218. numKPs_ = numKPs;
  219. return kps;
  220. }
  221. };
  222. juce_ImplementSingleton_SingleThreaded (FontDCHolder);
  223. //==============================================================================
  224. static bool addGlyphToTypeface (HDC dc,
  225. juce_wchar character,
  226. Typeface& dest,
  227. bool addKerning)
  228. {
  229. Path destShape;
  230. GLYPHMETRICS gm;
  231. float height;
  232. BOOL ok = false;
  233. {
  234. const WCHAR charToTest[] = { (WCHAR) character, 0 };
  235. WORD index = 0;
  236. if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR
  237. && index == 0xffff)
  238. {
  239. return false;
  240. }
  241. }
  242. TEXTMETRIC tm;
  243. ok = GetTextMetrics (dc, &tm);
  244. height = (float) tm.tmHeight;
  245. if (! ok)
  246. {
  247. dest.addGlyph (character, destShape, 0);
  248. return true;
  249. }
  250. const float scaleX = 1.0f / height;
  251. const float scaleY = -1.0f / height;
  252. static const MAT2 identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
  253. const int bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
  254. &gm, 0, 0, &identityMatrix);
  255. if (bufSize > 0)
  256. {
  257. char* const data = (char*) juce_malloc (bufSize);
  258. GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
  259. bufSize, data, &identityMatrix);
  260. const TTPOLYGONHEADER* pheader = (TTPOLYGONHEADER*) data;
  261. while ((char*) pheader < data + bufSize)
  262. {
  263. #define remapX(v) (scaleX * (v).x.value)
  264. #define remapY(v) (scaleY * (v).y.value)
  265. float x = remapX (pheader->pfxStart);
  266. float y = remapY (pheader->pfxStart);
  267. destShape.startNewSubPath (x, y);
  268. const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
  269. const char* const curveEnd = ((const char*) pheader) + pheader->cb;
  270. while ((const char*) curve < curveEnd)
  271. {
  272. if (curve->wType == TT_PRIM_LINE)
  273. {
  274. for (int i = 0; i < curve->cpfx; ++i)
  275. {
  276. x = remapX (curve->apfx [i]);
  277. y = remapY (curve->apfx [i]);
  278. destShape.lineTo (x, y);
  279. }
  280. }
  281. else if (curve->wType == TT_PRIM_QSPLINE)
  282. {
  283. for (int i = 0; i < curve->cpfx - 1; ++i)
  284. {
  285. const float x2 = remapX (curve->apfx [i]);
  286. const float y2 = remapY (curve->apfx [i]);
  287. float x3, y3;
  288. if (i < curve->cpfx - 2)
  289. {
  290. x3 = 0.5f * (x2 + remapX (curve->apfx [i + 1]));
  291. y3 = 0.5f * (y2 + remapY (curve->apfx [i + 1]));
  292. }
  293. else
  294. {
  295. x3 = remapX (curve->apfx [i + 1]);
  296. y3 = remapY (curve->apfx [i + 1]);
  297. }
  298. destShape.quadraticTo (x2, y2, x3, y3);
  299. x = x3;
  300. y = y3;
  301. }
  302. }
  303. curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
  304. }
  305. pheader = (const TTPOLYGONHEADER*) curve;
  306. destShape.closeSubPath();
  307. }
  308. juce_free (data);
  309. }
  310. dest.addGlyph (character, destShape, gm.gmCellIncX / height);
  311. if (addKerning)
  312. {
  313. int numKPs;
  314. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  315. for (int i = 0; i < numKPs; ++i)
  316. {
  317. if (kps[i].wFirst == character)
  318. {
  319. dest.addKerningPair (kps[i].wFirst,
  320. kps[i].wSecond,
  321. kps[i].iKernAmount / height);
  322. }
  323. }
  324. }
  325. return true;
  326. }
  327. //==============================================================================
  328. bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
  329. {
  330. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), 0);
  331. return addGlyphToTypeface (dc, character, *this, true);
  332. }
  333. /*Image* Typeface::renderGlyphToImage (juce_wchar character, float& topLeftX, float& topLeftY)
  334. {
  335. HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), hintingSize);
  336. int bufSize;
  337. GLYPHMETRICS gm;
  338. const UINT format = GGO_GRAY2_BITMAP;
  339. const int shift = 6;
  340. if (wGetGlyphOutlineW != 0)
  341. bufSize = wGetGlyphOutlineW (dc, character, format, &gm, 0, 0, &identityMatrix);
  342. else
  343. bufSize = GetGlyphOutline (dc, character, format, &gm, 0, 0, &identityMatrix);
  344. Image* im = new Image (Image::SingleChannel, jmax (1, gm.gmBlackBoxX), jmax (1, gm.gmBlackBoxY), true);
  345. if (bufSize > 0)
  346. {
  347. topLeftX = (float) gm.gmptGlyphOrigin.x;
  348. topLeftY = (float) -gm.gmptGlyphOrigin.y;
  349. uint8* const data = (uint8*) juce_calloc (bufSize);
  350. if (wGetGlyphOutlineW != 0)
  351. wGetGlyphOutlineW (dc, character, format, &gm, bufSize, data, &identityMatrix);
  352. else
  353. GetGlyphOutline (dc, character, format, &gm, bufSize, data, &identityMatrix);
  354. const int stride = ((gm.gmBlackBoxX + 3) & ~3);
  355. for (int y = gm.gmBlackBoxY; --y >= 0;)
  356. {
  357. for (int x = gm.gmBlackBoxX; --x >= 0;)
  358. {
  359. const int level = data [x + y * stride] << shift;
  360. if (level > 0)
  361. im->setPixelAt (x, y, Colour ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff, (uint8) jmin (0xff, level)));
  362. }
  363. }
  364. juce_free (data);
  365. }
  366. return im;
  367. }*/
  368. //==============================================================================
  369. void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
  370. bool bold,
  371. bool italic,
  372. bool addAllGlyphsToFont) throw()
  373. {
  374. clear();
  375. HDC dc = FontDCHolder::getInstance()->loadFont (fontName, bold, italic, 0);
  376. float height;
  377. int firstChar, lastChar;
  378. {
  379. TEXTMETRIC tm;
  380. GetTextMetrics (dc, &tm);
  381. height = (float) tm.tmHeight;
  382. firstChar = tm.tmFirstChar;
  383. lastChar = tm.tmLastChar;
  384. setAscent (tm.tmAscent / height);
  385. setDefaultCharacter (tm.tmDefaultChar);
  386. }
  387. setName (fontName);
  388. setBold (bold);
  389. setItalic (italic);
  390. if (addAllGlyphsToFont)
  391. {
  392. for (int character = firstChar; character <= lastChar; ++character)
  393. addGlyphToTypeface (dc, (juce_wchar) character, *this, false);
  394. int numKPs;
  395. const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
  396. for (int i = 0; i < numKPs; ++i)
  397. {
  398. addKerningPair (kps[i].wFirst,
  399. kps[i].wSecond,
  400. kps[i].iKernAmount / height);
  401. }
  402. }
  403. }
  404. END_JUCE_NAMESPACE