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.

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