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.

496 lines
15KB

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