PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/qwaqvm/platforms/win32/plugins/NativeFontPlugin/sqWin32NativeFontPlugin.c

http://openqwaq.googlecode.com/
C | 428 lines | 317 code | 47 blank | 64 comment | 97 complexity | 2b2b20bec15270fe0dc2f666b9795de8 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0, BSD-3-Clause
  1. /**
  2. * Project OpenQwaq
  3. *
  4. * Copyright (c) 2005-2011, Teleplace, Inc., All Rights Reserved
  5. *
  6. * Redistributions in source code form must reproduce the above
  7. * copyright and this condition.
  8. *
  9. * The contents of this file are subject to the GNU General Public
  10. * License, Version 2 (the "License"); you may not use this file
  11. * except in compliance with the License. A copy of the License is
  12. * available at http://www.opensource.org/licenses/gpl-2.0.php.
  13. *
  14. */
  15. #include <windows.h>
  16. #include "sqVirtualMachine.h"
  17. #include "sqConfig.h"
  18. #include "sqPlatformSpecific.h"
  19. extern struct VirtualMachine *interpreterProxy;
  20. /* Ref to Squeak window for getting DC etc. */
  21. static HWND *theSTWindow;
  22. /* Number of elements in font cache to grow by */
  23. #define FONT_CACHE_SIZE 50
  24. #define FontFlagBold 1
  25. #define FontFlagItalic 2
  26. #define FontFlagUnderline 4
  27. #define FontFlagStrikeout 8
  28. /*****************************************************************************/
  29. /*****************************************************************************/
  30. /*****************************************************************************/
  31. typedef struct sqFont {
  32. HFONT handle;
  33. TEXTMETRIC textMetric;
  34. ABC abcWidths[256];
  35. int nKernPairs;
  36. KERNINGPAIR *kernPairs;
  37. } sqFont;
  38. /* font cache */
  39. static sqFont *fontCache = NULL;
  40. static int maxFonts = 0;
  41. /*****************************************************************/
  42. /*****************************************************************/
  43. /*****************************************************************/
  44. /* font creation */
  45. int ioCreateFont(int fontNameIndex, int fontNameLength, int pixelSize, int flags, int quality)
  46. {
  47. LOGFONT logFont;
  48. HFONT hFont;
  49. int fontIndex, i, nKernPairs;
  50. HDC hDC = NULL;
  51. static int logPixelsY = 0;
  52. #define NumQualityOptions 4
  53. static int qualityOpts[NumQualityOptions] = {
  54. DEFAULT_QUALITY,
  55. PROOF_QUALITY,
  56. ANTIALIASED_QUALITY,
  57. 5, /* CLEARTYPE_QUALITY */
  58. };
  59. if(fontNameLength >= LF_FACESIZE) return -1;
  60. if(quality >= NumQualityOptions) return -1;
  61. if(!logPixelsY) {
  62. hDC = GetDC(*theSTWindow);
  63. logPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
  64. ReleaseDC(*theSTWindow, hDC);
  65. hDC = NULL;
  66. }
  67. logFont.lfHeight = -MulDiv(pixelSize, logPixelsY, 72);
  68. logFont.lfWidth = 0;
  69. logFont.lfEscapement = 0;
  70. logFont.lfOrientation = 0;
  71. logFont.lfWeight = (flags & FontFlagBold) ? FW_BOLD : FW_REGULAR;
  72. logFont.lfItalic = (flags & FontFlagItalic) != 0;
  73. logFont.lfUnderline = (flags & FontFlagUnderline) != 0;
  74. logFont.lfStrikeOut = (flags & FontFlagStrikeout) != 0;
  75. logFont.lfCharSet = DEFAULT_CHARSET;
  76. logFont.lfOutPrecision = OUT_TT_PRECIS;
  77. logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  78. logFont.lfQuality = qualityOpts[quality];
  79. logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  80. for(i=0;i < fontNameLength; i++) {
  81. logFont.lfFaceName[i] = ((char*)fontNameIndex)[i];
  82. }
  83. logFont.lfFaceName[fontNameLength] = 0;
  84. hFont = CreateFontIndirect(&logFont);
  85. if(!hFont) {
  86. MessageBox(*theSTWindow, "Failed to create font", "Font error", MB_OK);
  87. return -1;
  88. }
  89. /* Find free slot in fontCache */
  90. for(fontIndex = 0; fontIndex < maxFonts; fontIndex++)
  91. if(fontCache[fontIndex].handle == NULL) break;
  92. if(fontIndex == maxFonts) {
  93. int i;
  94. maxFonts = maxFonts + FONT_CACHE_SIZE; /* grow linearly */
  95. fontCache = (sqFont*) realloc(fontCache, maxFonts * sizeof(sqFont));
  96. for(i = fontIndex; i < maxFonts; i++) fontCache[i].handle = NULL;
  97. }
  98. fontCache[fontIndex].handle = hFont;
  99. /* Query for the width of each character */
  100. {
  101. HANDLE oldFont;
  102. hDC = GetDC(*theSTWindow);
  103. oldFont = SelectObject(hDC, hFont);
  104. if(!GetCharABCWidths(hDC, 0, 255, fontCache[fontIndex].abcWidths)) {
  105. /* This must have been a bitmap font */
  106. int widthArray[256];
  107. ABC *abc = fontCache[fontIndex].abcWidths;
  108. int i;
  109. GetCharWidth(hDC, 0, 255, widthArray);
  110. for(i=0; i < 256; i++) {
  111. abc[i].abcA = 0;
  112. abc[i].abcB = widthArray[i];
  113. abc[i].abcC = 0;
  114. }
  115. }
  116. GetTextMetrics(hDC, &(fontCache[fontIndex].textMetric));
  117. nKernPairs = GetKerningPairs(hDC, 0, NULL);
  118. fontCache[fontIndex].nKernPairs = nKernPairs;
  119. fontCache[fontIndex].kernPairs = (KERNINGPAIR*) calloc(nKernPairs, sizeof(KERNINGPAIR));
  120. GetKerningPairs(hDC, nKernPairs, fontCache[fontIndex].kernPairs);
  121. SelectObject(hDC, oldFont);
  122. ReleaseDC(*theSTWindow, hDC);
  123. }
  124. return fontIndex;
  125. }
  126. int ioDestroyFont(int fontIndex) {
  127. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  128. if(fontCache[fontIndex].handle == NULL) return 0;
  129. DeleteObject(fontCache[fontIndex].handle);
  130. free(fontCache[fontIndex].kernPairs);
  131. fontCache[fontIndex].kernPairs = NULL;
  132. fontCache[fontIndex].handle = 0;
  133. return 1;
  134. }
  135. /*****************************************************************/
  136. /*****************************************************************/
  137. /*****************************************************************/
  138. /* Font information */
  139. int ioFontEncoding(int fontIndex) {
  140. /* Font encoding is always ANSI - we don't allow anything else */
  141. return 1;
  142. }
  143. int ioFontAscent(int fontIndex) {
  144. TEXTMETRIC *tm;
  145. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  146. if(fontCache[fontIndex].handle == NULL) return 0;
  147. tm = &(fontCache[fontIndex].textMetric);
  148. return tm->tmAscent /* + tm->tmInternalLeading */;
  149. }
  150. int ioFontDescent(int fontIndex) {
  151. TEXTMETRIC *tm;
  152. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  153. if(fontCache[fontIndex].handle == NULL) return 0;
  154. tm = &(fontCache[fontIndex].textMetric);
  155. return tm->tmDescent /* + tm->tmExternalLeading */;
  156. }
  157. int ioFontEmbeddingFlags(int fontIndex) {
  158. HDC hDC;
  159. HANDLE hFont;
  160. DWORD size;
  161. OUTLINETEXTMETRIC otm;
  162. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  163. if(fontCache[fontIndex].handle == NULL) return 0;
  164. hDC = GetDC(*theSTWindow);
  165. hFont = SelectObject(hDC, fontCache[fontIndex].handle);
  166. otm.otmSize = sizeof(otm);
  167. if(GetOutlineTextMetrics(hDC, sizeof(otm), &otm) == 0) {
  168. /* no embedding if function fails */
  169. otm.otmfsType = 1;
  170. }
  171. SelectObject(hDC, hFont);
  172. ReleaseDC(*theSTWindow, hDC);
  173. return otm.otmfsType;
  174. }
  175. int ioGetFontDataSize(int fontIndex) {
  176. HDC hDC;
  177. HANDLE hFont;
  178. DWORD size;
  179. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  180. if(fontCache[fontIndex].handle == NULL) return 0;
  181. hDC = GetDC(*theSTWindow);
  182. hFont = SelectObject(hDC, fontCache[fontIndex].handle);
  183. size = GetFontData(hDC, 0, 0, NULL, -1);
  184. SelectObject(hDC, hFont);
  185. ReleaseDC(*theSTWindow, hDC);
  186. return size;
  187. }
  188. int ioGetFontData(int fontIndex, char *fontDataBuffer, int bufferSize) {
  189. HDC hDC;
  190. HANDLE hFont;
  191. DWORD size;
  192. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  193. if(fontCache[fontIndex].handle == NULL) return 0;
  194. hDC = GetDC(*theSTWindow);
  195. hFont = SelectObject(hDC, fontCache[fontIndex].handle);
  196. size = GetFontData(hDC, 0, 0, fontDataBuffer, bufferSize);
  197. SelectObject(hDC, hFont);
  198. ReleaseDC(*theSTWindow, hDC);
  199. return size;
  200. }
  201. /*****************************************************************/
  202. /*****************************************************************/
  203. /*****************************************************************/
  204. /* character measuring */
  205. int ioFontWidthOfChar(int fontIndex, int characterIndex)
  206. { ABC abcWidth;
  207. int width;
  208. if(fontIndex < 0 || fontIndex >= maxFonts) return -1;
  209. if(fontCache[fontIndex].handle == NULL) return -1;
  210. if(characterIndex < 0 || characterIndex > 255) return -1;
  211. return fontCache[fontIndex].abcWidths[characterIndex].abcB;
  212. }
  213. int ioFontFullWidthOfChar(int fontIndex, int characterIndex, int fullWidth[3])
  214. {
  215. ABC abcWidth;
  216. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  217. if(fontCache[fontIndex].handle == NULL) return 0;
  218. if(characterIndex < 0 || characterIndex > 255) return 0;
  219. abcWidth = fontCache[fontIndex].abcWidths[characterIndex];
  220. fullWidth[0] = abcWidth.abcA;
  221. fullWidth[1] = abcWidth.abcB;
  222. fullWidth[2] = abcWidth.abcC;
  223. return 1;
  224. }
  225. /*****************************************************************/
  226. /*****************************************************************/
  227. /*****************************************************************/
  228. /* Kerning support */
  229. int ioFontNumKernPairs(int fontIndex)
  230. {
  231. if(fontIndex < 0 || fontIndex >= maxFonts) return -1;
  232. if(fontCache[fontIndex].handle == NULL) return -1;
  233. return fontCache[fontIndex].nKernPairs;
  234. }
  235. int ioFontGetKernPair(int fontIndex, int kernIndex, int kernPair[3])
  236. {
  237. KERNINGPAIR kp;
  238. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  239. if(fontCache[fontIndex].handle == NULL) return 0;
  240. if(kernIndex < 1 || kernIndex > fontCache[fontIndex].nKernPairs) return 0;
  241. kp = fontCache[fontIndex].kernPairs[kernIndex-1];
  242. kernPair[0] = kp.wFirst;
  243. kernPair[1] = kp.wSecond;
  244. kernPair[2] = kp.iKernAmount;
  245. return 1;
  246. }
  247. /*****************************************************************/
  248. /*****************************************************************/
  249. /*****************************************************************/
  250. /* Glyph retrieval */
  251. int ioFontGlyphOfChar(int fontIndex, int characterIndex,
  252. int formBitsIndex, int formWidth, int formHeight, int formDepth)
  253. {
  254. HDC hDC;
  255. HDC mDC;
  256. HBITMAP hBM;
  257. HANDLE oldBM, oldFont;
  258. unsigned int *dibBits;
  259. static BITMAPINFO *bmi = NULL;
  260. char string[1];
  261. int xPos;
  262. if((formDepth != 1) && (formDepth != 32)) return 0; /* unsupported */
  263. if(fontIndex < 0 || fontIndex >= maxFonts) return 0;
  264. if(fontCache[fontIndex].handle == NULL) return 0;
  265. if(characterIndex < 0 || characterIndex > 255) return 0;
  266. if(!bmi) {
  267. bmi = (BITMAPINFO*) calloc(1, sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
  268. bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  269. }
  270. bmi->bmiHeader.biWidth = formWidth;
  271. bmi->bmiHeader.biHeight = -formHeight;
  272. bmi->bmiHeader.biPlanes = 1;
  273. bmi->bmiHeader.biBitCount = formDepth;
  274. bmi->bmiHeader.biCompression = BI_RGB;
  275. bmi->bmiColors[0].rgbRed = 255;
  276. bmi->bmiColors[0].rgbGreen = 255;
  277. bmi->bmiColors[0].rgbBlue = 255;
  278. bmi->bmiColors[1].rgbRed = 0;
  279. bmi->bmiColors[1].rgbGreen = 0;
  280. bmi->bmiColors[1].rgbBlue = 0;
  281. string[0] = characterIndex;
  282. /* Draw the character glyph */
  283. hDC = GetDC(*theSTWindow);
  284. mDC = CreateCompatibleDC(hDC);
  285. hBM = CreateDIBSection(mDC, bmi, DIB_RGB_COLORS, (void*)&dibBits, NULL, 0);
  286. oldBM = SelectObject(mDC, hBM);
  287. oldFont = SelectObject(mDC, fontCache[fontIndex].handle);
  288. PatBlt(mDC, 0, 0, formWidth, formHeight, BLACKNESS);
  289. SetTextAlign(mDC, TA_TOP | TA_LEFT | TA_NOUPDATECP);
  290. SetTextColor(mDC, RGB(0, 0, 0));
  291. /* Adjust for underhang, but don't trim insets. */
  292. /* Trimming insets will clip underlines and strikeouts. */
  293. xPos = -(fontCache[fontIndex].abcWidths[characterIndex].abcA);
  294. if(xPos < 0) xPos = 0;
  295. TextOut(mDC, xPos, 0, string, 1);
  296. /* BitBlt(hDC, (characterIndex & 15) * formWidth, (characterIndex >> 4) * formHeight, formWidth, formHeight, mDC, 0, 0, SRCCOPY); */
  297. /* And swap those bits */
  298. {
  299. unsigned int *bits = (unsigned int*) formBitsIndex;
  300. int numWords = ((formWidth * formDepth) + 31) / 32;
  301. int i;
  302. # define BYTE_SWAP(w) ((w << 24) | ((w & 0xFF00) << 8) | ((w >> 8) & 0xFF00) | (w >> 24))
  303. for(i=0; i < formHeight*numWords; i++) {
  304. if(formDepth == 1) bits[i] = BYTE_SWAP(dibBits[i]);
  305. if(formDepth == 32) bits[i] = dibBits[i];
  306. }
  307. # undef BYTE_SWAP
  308. }
  309. /* done it. */
  310. SelectObject(mDC, oldBM);
  311. SelectObject(mDC, oldFont);
  312. DeleteDC(mDC);
  313. DeleteObject(hBM);
  314. ReleaseDC(*theSTWindow, hDC);
  315. }
  316. /*****************************************************************************/
  317. /*****************************************************************************/
  318. /*****************************************************************************/
  319. /* Font name cache */
  320. static LOGFONT *fontNameCache = NULL;
  321. static int numFontNames = 0;
  322. static int maxFontNames = 0;
  323. int CALLBACK enumFontsCallback(ENUMLOGFONTEX *logFont, NEWTEXTMETRICEX *textMetric, int fontType, LPARAM param)
  324. {
  325. int i;
  326. if(numFontNames == maxFontNames) {
  327. /* Resize font cache */
  328. maxFontNames = maxFontNames + FONT_CACHE_SIZE; /* grow linearly */
  329. fontNameCache = (LOGFONT*) realloc(fontNameCache, maxFontNames * sizeof(LOGFONT));
  330. }
  331. /* We check for unique names here since fonts will be listed in all available char sets */
  332. for(i = 0; i < numFontNames; i++) {
  333. if(strcmp(fontNameCache[i].lfFaceName, logFont->elfLogFont.lfFaceName) == 0) {
  334. /* we had this guy already */
  335. return 1; /* but continue enumerating */
  336. }
  337. }
  338. fontNameCache[numFontNames++] = logFont->elfLogFont;
  339. return 1; /* continue enumeration */
  340. }
  341. char *ioListFont(int fontIndex) {
  342. static char taggedName[256];
  343. /* Enumerate fonts on index 0 or first use */
  344. if(fontIndex == 0 || !fontNameCache) {
  345. LOGFONT logFont;
  346. HDC hDC;
  347. numFontNames = 0; /* start over with enumeration */
  348. hDC = GetDC(*theSTWindow);
  349. if(!hDC) return NULL;
  350. ZeroMemory(&logFont, sizeof(logFont));
  351. logFont.lfCharSet = DEFAULT_CHARSET;
  352. logFont.lfFaceName;
  353. EnumFontFamiliesEx(hDC, &logFont, enumFontsCallback, 0, 0);
  354. ReleaseDC(*theSTWindow, hDC);
  355. }
  356. if(!fontNameCache) return NULL;
  357. if(fontIndex >= numFontNames) return NULL;
  358. return fontNameCache[fontIndex].lfFaceName;
  359. }
  360. /*****************************************************************/
  361. /*****************************************************************/
  362. /*****************************************************************/
  363. /* initialize/shutdown */
  364. int ioFontInit(void) {
  365. /* lookup the necessary things from interpreter */
  366. theSTWindow = (HWND*) interpreterProxy->ioLoadFunctionFrom("stWindow","");
  367. if(!theSTWindow) return 0;
  368. numFontNames = maxFontNames = 0;
  369. fontNameCache = NULL;
  370. maxFonts = 0;
  371. fontCache = NULL;
  372. return 1;
  373. }
  374. int ioFontShutdown(void) {
  375. int i;
  376. if(fontNameCache) free(fontNameCache);
  377. for(i=0; i < maxFonts; i++)
  378. if(fontCache[i].handle) DeleteObject(fontCache[i].handle);
  379. if(fontCache) free(fontCache);
  380. return 1;
  381. }