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.

503 lines
15KB

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