freetypefont.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. #include "precomp.h"
  2. // ============================================================================================================================================================
  3. // Font abstract class + statics to install TT fonts and Bitmap fonts
  4. // ============================================================================================================================================================
  5. #include "freetypefont.h"
  6. #include <tataki/canvas/ifc_canvas.h>
  7. #include <tataki/bitmap/bitmap.h>
  8. #include <api/config/items/cfgitem.h>
  9. #include <api/memmgr/api_memmgr.h>
  10. #define DO_KERNING // because Keith say so.
  11. // local prototypes
  12. static const wchar_t *find_break(void *f, const wchar_t *str, int width, int antialias);
  13. #define M_PI 3.14159
  14. #define M_2PI (M_PI*2)
  15. #define FAUX_BOLD_RATIO 0.1f
  16. #define FAUX_ITALIC_DEGREES 12
  17. // This was necessary in Freetype 2.1.3 and bellow, but let us rejoice, they've fixed it
  18. //#define NEED_SMALL_KERNING_HACK
  19. static int freetype_width(void *data, const wchar_t *str, int len, int fixed, int antialias);
  20. /**********************************************************************
  21. *
  22. * FreeType Lib
  23. *
  24. **********************************************************************/
  25. int (*FOLDSTRING)(
  26. DWORD dwMapFlags,
  27. LPCWSTR lpSrcStr,
  28. int cchSrc,
  29. LPWSTR lpDestStr,
  30. int cchDest
  31. )=0;
  32. FreeTypeFont::FreeTypeFont()
  33. {
  34. if (!FOLDSTRING)
  35. {
  36. HMODULE lib = LoadLibraryA("kernel32.dll");
  37. if (lib)
  38. {
  39. //*(void **)&FOLDSTRING = GetProcAddress(lib, "FoldStringW");
  40. }
  41. FreeLibrary(lib);
  42. }
  43. fontbuffer = NULL;
  44. font = NULL;
  45. curboldstrength = 2;
  46. }
  47. int FreeTypeFont::addFontResource2(void *data, int datalen, const wchar_t *name)
  48. {
  49. optionsitem = NULL;
  50. if (FT_Init_FreeType(&flib)) {
  51. DebugString("FreeType: Cannot load freetype!\n");
  52. return 0;
  53. }
  54. last_encoding = -1;
  55. facename = name;
  56. fontbuffer = (char *)data;
  57. fontbufferlen = datalen;
  58. if (FT_New_Memory_Face(flib, (FT_Byte *)fontbuffer, fontbufferlen, 0, &font)) {
  59. DebugString("FreeType: Cannot load font!\n");
  60. return 0;
  61. }
  62. updateCharmap();
  63. return 1;
  64. }
  65. int FreeTypeFont::addFontResource(OSFILETYPE file, const wchar_t *name)
  66. {
  67. optionsitem = NULL;
  68. if (FT_Init_FreeType(&flib))
  69. {
  70. DebugString("FreeType: Cannot load freetype!\n");
  71. return 0;
  72. }
  73. last_encoding = -1;
  74. fontbufferlen = (int)FGETSIZE(file);
  75. fontbuffer = (char *)WASABI_API_MEMMGR->sysMalloc(fontbufferlen);
  76. FREAD(fontbuffer, fontbufferlen, 1, file);
  77. facename = name;
  78. if (FT_New_Memory_Face(flib, (FT_Byte *)fontbuffer, fontbufferlen, 0, &font))
  79. {
  80. DebugString("FreeType: Cannot load font!\n");
  81. return 0;
  82. }
  83. updateCharmap();
  84. return 1;
  85. }
  86. FreeTypeFont::~FreeTypeFont()
  87. {
  88. if (fontbuffer) {
  89. WASABI_API_MEMMGR->sysFree(fontbuffer);
  90. FT_Done_Face(font);
  91. FT_Done_FreeType(flib);
  92. }
  93. }
  94. void FreeTypeFont::updateCharmap()
  95. {
  96. if (optionsitem == NULL)
  97. {
  98. const GUID options_guid =
  99. { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } };
  100. optionsitem = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid);
  101. }
  102. int i = 0;
  103. if (optionsitem) i = optionsitem->getDataAsInt( L"Character mapping", 0);
  104. if (i != last_encoding)
  105. {
  106. FT_Done_Face(font);
  107. FT_Done_FreeType(flib);
  108. FT_Init_FreeType(&flib);
  109. FT_New_Memory_Face(flib, (FT_Byte *)fontbuffer, fontbufferlen, 0, &font);
  110. switch (i) {
  111. case -1:
  112. break;
  113. case 0:
  114. FT_Select_Charmap(font, FT_ENCODING_UNICODE);
  115. break;
  116. case 1:
  117. FT_Select_Charmap(font, FT_ENCODING_APPLE_ROMAN);
  118. break;
  119. case 2:
  120. FT_Select_Charmap(font, FT_ENCODING_ADOBE_LATIN_1);
  121. break;
  122. case 3:
  123. FT_Select_Charmap(font, FT_ENCODING_ADOBE_STANDARD);
  124. break;
  125. case 4:
  126. FT_Select_Charmap(font, FT_ENCODING_ADOBE_CUSTOM);
  127. break;
  128. case 5:
  129. FT_Select_Charmap(font, FT_ENCODING_ADOBE_EXPERT);
  130. break;
  131. case 6:
  132. FT_Select_Charmap(font, FT_ENCODING_SJIS);
  133. break;
  134. case 7:
  135. FT_Select_Charmap(font, FT_ENCODING_BIG5);
  136. break;
  137. case 8:
  138. FT_Select_Charmap(font, FT_ENCODING_WANSUNG);
  139. break;
  140. case 9:
  141. FT_Select_Charmap(font, FT_ENCODING_JOHAB);
  142. break;
  143. }
  144. }
  145. last_encoding = i;
  146. }
  147. int FreeTypeFont::tweakSize(const wchar_t *face, int size)
  148. {
  149. if (WCSCASEEQLSAFE(face, L"nonstep")) return size-1;
  150. if (WCSCASEEQLSAFE(face, L"04B_08__")) return size+3;
  151. if (WCSCASEEQLSAFE(face, L"Blocky")) return size+6;
  152. if (WCSCASEEQLSAFE(face, L"04b_03b_")) return size+3;
  153. if (WCSCASEEQLSAFE(face, L"04b_09__")) return size+3;
  154. if (WCSCASEEQLSAFE(face, L"04b_21")) return size+3;
  155. if (WCSCASEEQLSAFE(face, L"Radiosta")) return size+2;
  156. if (WCSCASEEQLSAFE(face, L"ETHNOCENTRIC")) return size+3;
  157. if (WCSCASEEQLSAFE(face, L"ETHNOCEN")) return size+3;
  158. if (WCSCASEEQLSAFE(face, L"pixel")) return size+3;
  159. return size;
  160. }
  161. #define VERTICAL_TPADDING 2
  162. #define VERTICAL_BPADDING 0
  163. #define HORIZONTAL_LPADDING -1
  164. #define HORIZONTAL_RPADDING 1
  165. void FreeTypeFont::prepareCanvas(api_canvas *c, int size, int bold, int opaque, int underline, int italic, COLORREF color, COLORREF bkcolor, const wchar_t *txt, int width, int height)
  166. {
  167. // Our "size" variable is fun to calculate!
  168. //int vRez = GetDeviceCaps(c->getHDC(), LOGPIXELSY); // this needs to be a Canvas method or something.
  169. int fsize = tweakSize(facename, size);
  170. int nHeight = MulDiv(fsize << 6, 72, 96);
  171. FT_Set_Char_Size(font, 0, nHeight, 0, 0);
  172. updateCharmap();
  173. font->style_flags = 0;
  174. if (bold)
  175. {
  176. font->style_flags |= FT_STYLE_FLAG_BOLD;
  177. curboldstrength = bold;//(bold && c->getTextAntialias()) ? 2 : bold;
  178. }
  179. if (italic)
  180. font->style_flags |= FT_STYLE_FLAG_ITALIC;
  181. if (underline)
  182. font->underline_thickness = 1;
  183. else
  184. font->underline_thickness = 0;
  185. if (height == -1 || width == -1) {
  186. getTextExtent(c, txt, &width, &height, size, bold, underline, italic, 0);
  187. }
  188. blt = new SkinBitmap(width+1, height, color & 0xffffff);
  189. blt->setHasAlpha(1);
  190. }
  191. void FreeTypeFont::restoreCanvas(api_canvas *c, int x, int y)
  192. {
  193. unsigned int *bits = (unsigned int *)blt->getBits();
  194. int n = blt->getWidth() * blt->getHeight();
  195. #ifndef NO_MMX
  196. if (Blenders::MMX_AVAILABLE())
  197. for (int i = 0; i < n; i++)
  198. *bits++ = Blenders::BLEND_MUL_MMX(*bits | 0xff000000, *bits >> 24);
  199. else
  200. #endif
  201. for (int i = 0; i < n; i++)
  202. *bits++ = Blenders::BLEND_MUL(*bits | 0xff000000, *bits >> 24);
  203. #ifndef NO_MMX
  204. Blenders::BLEND_MMX_END();
  205. #endif
  206. blt->blit(c, x + HORIZONTAL_LPADDING, y + VERTICAL_TPADDING);
  207. delete blt;
  208. blt = NULL;
  209. }
  210. int FreeTypeFont::getAscent()
  211. {
  212. FT_Glyph glyph;
  213. FT_BBox box;
  214. FT_Load_Glyph(font, FT_Get_Char_Index(font, 'M'), FT_LOAD_DEFAULT);
  215. FT_Get_Glyph(font->glyph, &glyph);
  216. FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &box);
  217. FT_Done_Glyph(glyph);
  218. return box.yMax >> 6;
  219. }
  220. void FreeTypeFont::drawText(int x, int y, const wchar_t *wtxt, int len, COLORREF color, int antialias)
  221. {
  222. POINT pen = { x << 6, y};
  223. // we start left to right
  224. direction = 1;
  225. WCHAR *neutral = NULL;
  226. WCHAR *rtlstr = NULL;
  227. wchar_t *freeme = 0;
  228. /* TODO: change this to be
  229. AutoChar ucs4(txt, 12000, WC_COMPOSITECHECK); // convert from UTF-16 to 'raw' Unicode
  230. However, we have to re-write the LTR part of the code below
  231. */
  232. if (FOLDSTRING)
  233. {
  234. wchar_t *txt = WMALLOC((len+1));
  235. FOLDSTRING(MAP_PRECOMPOSED, wtxt, -1, txt, len+1);
  236. freeme=txt;
  237. wtxt=txt;
  238. }
  239. lastchar = 0;
  240. for (int i=0 ; *wtxt && i<len;)
  241. {
  242. WORD cur_dir;
  243. GetStringTypeExW(LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, wtxt, 1, &cur_dir);
  244. if (cur_dir == C2_RIGHTTOLEFT)
  245. {
  246. // we're now about to write some right-to-left text
  247. // we need to scan the string to determine the length of this right-to-left block
  248. if (!neutral) { neutral = WMALLOC(len+1); }
  249. if (!rtlstr) { rtlstr = WMALLOC(len+1); }
  250. rtlstr[0] = 0;
  251. neutral[0] = 0;
  252. const wchar_t *p = wtxt;
  253. while (1)
  254. {
  255. WORD char_dir;
  256. if (*p)
  257. {
  258. GetStringTypeExW(LOCALE_SYSTEM_DEFAULT, CT_CTYPE2, p, 1, &char_dir);
  259. if (char_dir != C2_RIGHTTOLEFT && char_dir != C2_LEFTTORIGHT)
  260. {
  261. size_t l = wcslen(neutral);
  262. neutral[l] = *p;
  263. neutral[l+1] = 0;
  264. }
  265. }
  266. if (!*p || char_dir == C2_LEFTTORIGHT)
  267. {
  268. // we now need to write rtlstr as right-to-left
  269. int w = freetype_width(font, rtlstr, (int)wcslen(rtlstr), 1, antialias); // this is in fixed point units
  270. // save current pen position
  271. int oldpenx = pen.x;
  272. // jump to the end of the block
  273. pen.x += w;
  274. p = rtlstr;
  275. direction = -1;
  276. while (p && *p)
  277. {
  278. // move to the left by the width of the char
  279. pen.x -= freetype_width(font, p, 1, 1, antialias);
  280. // render the rtl character
  281. drawChar(pen.x, pen.y, *p, color, antialias);
  282. p++;
  283. }
  284. // now jump our to the end of the rtl block
  285. pen.x = oldpenx + w;
  286. // skip what we just printed from the source string
  287. wtxt += wcslen(rtlstr);
  288. // and continue like nothing happened
  289. direction = 1;
  290. break;
  291. }
  292. else if (char_dir == C2_RIGHTTOLEFT)
  293. {
  294. wcscat(rtlstr, neutral);
  295. *neutral = 0;
  296. size_t l = wcslen(rtlstr);
  297. rtlstr[l] = *p;
  298. rtlstr[l+1] = 0;
  299. }
  300. p++;
  301. }
  302. }
  303. else
  304. {
  305. pen.x += drawChar(pen.x, pen.y, *wtxt, color, antialias);
  306. wtxt++;
  307. }
  308. }
  309. if (rtlstr) FREE(rtlstr);
  310. if (neutral) FREE(neutral);
  311. if (freeme) FREE(freeme);
  312. }
  313. int FreeTypeFont::drawChar(int x0, int y0, unsigned long c, COLORREF color, int antialias)
  314. {
  315. unsigned int *bits = (unsigned int *)blt->getBits();
  316. int width = blt->getWidth();
  317. int height = blt->getHeight();
  318. x0;
  319. FT_BitmapGlyph ftg;
  320. int glyph_index = FT_Get_Char_Index(font, c);
  321. FT_Vector delta = { 0, 0 };
  322. #ifdef DO_KERNING
  323. if (lastchar && FT_HAS_KERNING(font)) {
  324. FT_Get_Kerning(font, lastchar, glyph_index, FT_KERNING_DEFAULT, &delta);
  325. x0 += delta.x;
  326. }
  327. #endif
  328. int rc = FT_Load_Glyph(font, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
  329. if (rc)
  330. return 0;
  331. rc = FT_Get_Glyph(font->glyph, (FT_Glyph*)&ftg);
  332. if (rc)
  333. return 0;
  334. if (font->style_flags & FT_STYLE_FLAG_ITALIC)
  335. {
  336. FT_Matrix mat;
  337. // sets up the matrix, 0 degrees
  338. double sintheta = sin(0.0);
  339. double costheta = cos(0.0);
  340. mat.xx = (FT_Fixed)(costheta * (1<<16));
  341. mat.xy = (FT_Fixed)(sintheta * (1<<16));
  342. mat.yx = -mat.xy;
  343. mat.yy = mat.xx;
  344. // shear the vectors for italic, 10 to 12 deg suggested
  345. FT_Fixed f = (FT_Fixed)(tan(M_2PI/(360/FAUX_ITALIC_DEGREES)) * (1<<16));
  346. mat.xy += FT_MulFix(f, mat.xx);
  347. mat.yy += FT_MulFix(f, mat.yx);
  348. // do the transform
  349. FT_Vector v = {0,0};
  350. FT_Vector_Transform(&v, &mat);
  351. FT_Glyph_Transform((FT_Glyph)ftg, &mat, &v);
  352. }
  353. // get the glyph
  354. rc = FT_Glyph_To_Bitmap((FT_Glyph*)&ftg, antialias?ft_render_mode_normal:ft_render_mode_mono, NULL, 1);
  355. if (rc) {
  356. FT_Done_Glyph((FT_Glyph)ftg);
  357. return 0;
  358. }
  359. FT_Bitmap *bmp = &ftg->bitmap;
  360. int r = 1;
  361. if (font->style_flags & FT_STYLE_FLAG_BOLD)
  362. r = MAX((int)((float)(font->glyph->advance.x >> 6) * FAUX_BOLD_RATIO), 2);
  363. int ys = MAX(0, y0 - ftg->top);
  364. int ye = MIN(height, (int)(y0 + bmp->rows - ftg->top));
  365. int xs = MAX(0, (x0 >> 6) + ftg->left);
  366. int xe = MIN(width, (int)((x0 >> 6) + ftg->left + bmp->width));
  367. unsigned char *_bmpbits = bmp->buffer + (ys + ftg->top - y0) * bmp->pitch + (xs - ftg->left - (x0 >> 6));
  368. unsigned int *_linebits = (unsigned int *)(bits + ys * width + xs);
  369. if (ftg->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
  370. for (int z = 0; z < r; z++) {
  371. unsigned char *bmpbits = _bmpbits;
  372. unsigned int *linebits = _linebits + z;
  373. for (int y = ys; y < ye; y++) {
  374. if (z > 0) {
  375. for (int x = xs; x < xe; x++) {
  376. if (x != width-z) {
  377. *linebits |= overlay((int)(*linebits >> 24), (int)*bmpbits, curboldstrength, r, z) << 24;
  378. linebits++; bmpbits++;
  379. } else {
  380. linebits++; bmpbits++;
  381. }
  382. }
  383. } else {
  384. for (int x = xs; x < xe; x++)
  385. *linebits++ |= *bmpbits++ << 24;
  386. }
  387. bmpbits += bmp->pitch - (xe - xs);
  388. linebits += width - (xe - xs);
  389. }
  390. }
  391. } else if (ftg->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
  392. for (int z = 0; z < r; z++) {
  393. unsigned char *bmpbits = _bmpbits;
  394. unsigned int *linebits = _linebits + z;
  395. for (int y = ys; y < ye; y++) {
  396. for (int x = xs; x < xe; x++) {
  397. /* if (y == ys || y == ye-1 || x == xs || x == xe-1)
  398. *linebits++ |= 0xFF << 24;
  399. else
  400. linebits++;*/
  401. int byte = (x-xs)>>3;
  402. *linebits++ |= (*(bmpbits + byte) & (1 << (7-((x-xs)-(byte<<3)))) ? 0xFF : 0) << 24;
  403. }
  404. bmpbits += bmp->pitch;
  405. linebits += width - (xe - xs);
  406. }
  407. }
  408. } else {
  409. // simply draw rectangles
  410. for (int z = 0; z < r; z++) {
  411. unsigned char *bmpbits = _bmpbits;
  412. unsigned int *linebits = _linebits + z;
  413. for (int y = ys; y < ye; y++) {
  414. for (int x = xs; x < xe; x++) {
  415. if (y == ys || y == ye-1 || x == xs || x == xe-1)
  416. *linebits++ |= 0xFF << 24;
  417. else
  418. linebits++;
  419. }
  420. bmpbits += bmp->pitch;
  421. linebits += width - (xe - xs);
  422. }
  423. }
  424. }
  425. FT_Done_Glyph((FT_Glyph)ftg);
  426. lastchar = glyph_index;
  427. return font->glyph->advance.x + delta.x + ((r - 1) << 6);
  428. }
  429. void FreeTypeFont::textOut(api_canvas *c, int x, int y, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  430. {
  431. color = RGBTOBGR(color);
  432. bkcolor = RGBTOBGR(bkcolor);
  433. y++; x++;
  434. prepareCanvas(c, size, bold, opaque, underline, italic, color, bkcolor, txt);
  435. int maxheight = getAscent();
  436. drawText(0, maxheight, txt, (int)wcslen(txt), color, antialias);
  437. /* POINT pen = { 0, maxheight };
  438. lastchar = 0;
  439. for (; *txt; txt++) {
  440. pen.x += drawChar(pen.x, pen.y, *txt, color);
  441. }*/
  442. restoreCanvas(c, x + xoffset , y + yoffset);
  443. }
  444. void FreeTypeFont::textOut2(api_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  445. {
  446. color = RGBTOBGR(color);
  447. bkcolor = RGBTOBGR(bkcolor);
  448. y++; x++;
  449. prepareCanvas(c, size, bold, opaque, underline, italic, color, bkcolor, txt, w, h);
  450. int maxheight = getAscent();
  451. int width = getTextWidth(c,txt,size,bold,underline,italic,antialias);
  452. int xstart = 0;
  453. if (align == DT_RIGHT)
  454. {
  455. xstart = w - width;
  456. }
  457. else if (align == DT_CENTER)
  458. {
  459. xstart = (w - width) / 2;
  460. }
  461. drawText(xstart, maxheight, txt, (int)wcslen(txt), color, antialias);
  462. /* POINT pen = { xstart << 6, maxheight };
  463. lastchar = 0;
  464. for (; *txt; txt++) {
  465. pen.x += drawChar(pen.x, pen.y, *txt, color);
  466. }*/
  467. restoreCanvas(c, x + xoffset , y + yoffset);
  468. }
  469. void FreeTypeFont::textOutEllipsed(api_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  470. {
  471. color = RGBTOBGR(color);
  472. bkcolor = RGBTOBGR(bkcolor);
  473. y++; x++;
  474. if (txt == NULL)
  475. return;
  476. RECT r;
  477. r.left = x+xoffset;
  478. r.top = y+yoffset;
  479. r.right = r.left + w;
  480. r.bottom = r.top + h;
  481. prepareCanvas(c, size, bold, opaque, underline, italic, color, bkcolor, txt, w, h);
  482. int len = ((int)wcslen(txt) + 3);
  483. wchar_t *tmp = (wchar_t *)MALLOC(sizeof(wchar_t) * len);
  484. wcsncpy(tmp, txt, len);
  485. int width, height;
  486. width = getTextWidth(c, txt, size, bold, underline, italic, (int)antialias);
  487. height = getAscent();
  488. int dddw = getTextWidth(c, L"...", size, bold, underline, italic, antialias);
  489. if (width > r.right - r.left)
  490. {
  491. wchar_t *p = tmp + wcslen(tmp);
  492. width = r.right - r.left - dddw;
  493. while(p > tmp &&
  494. getTextWidth(c,tmp,size,bold,underline,italic,antialias) > width)
  495. {
  496. *p-- = '\0';
  497. }
  498. wcscpy(p, L"...");
  499. }
  500. drawText(0, height, tmp, (int)wcslen(tmp), color, antialias);
  501. /* POINT pen = { 0, height };
  502. lastchar = 0;
  503. for (char *p = tmp; *p; p++) {
  504. pen.x += drawChar(pen.x, pen.y, *p, color);
  505. }*/
  506. FREE(tmp);
  507. restoreCanvas(c, r.left, r.top);
  508. }
  509. static int freetype_width(void *data, const wchar_t *str, int len, int fixed, int antialias)
  510. {
  511. FT_Face font = (FT_Face)data;
  512. int w = 0;
  513. int prev, index;
  514. const wchar_t *p;
  515. int count = 0;
  516. for (p = str; *p && count < len;)
  517. {
  518. FT_Vector delta = { 0, 0 };
  519. FT_BitmapGlyph ftg;
  520. index = FT_Get_Char_Index(font, *p);
  521. #ifdef DO_KERNING
  522. if (w > 0 && FT_HAS_KERNING(font)) {
  523. FT_Get_Kerning(font, prev, index, ft_kerning_default, &delta);
  524. }
  525. #endif
  526. int rc = FT_Load_Glyph(font, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
  527. if (rc)
  528. {
  529. p++;
  530. count++;
  531. continue;
  532. }
  533. w += (delta.x + font->glyph->advance.x);
  534. prev = index;
  535. rc = FT_Get_Glyph(font->glyph, (FT_Glyph*)&ftg);
  536. if (rc)
  537. {
  538. p++;
  539. count++;
  540. continue;
  541. }
  542. if (font->style_flags & FT_STYLE_FLAG_ITALIC)
  543. {
  544. FT_Matrix mat;
  545. // sets up the matrix, 0 degrees
  546. double sintheta = sin(0.0);
  547. double costheta = cos(0.0);
  548. mat.xx = (FT_Fixed)(costheta * (1<<16));
  549. mat.xy = (FT_Fixed)(sintheta * (1<<16));
  550. mat.yx = -mat.xy;
  551. mat.yy = mat.xx;
  552. // shear the vectors for italic, 10 to 12 deg suggested
  553. FT_Fixed f = (FT_Fixed)(tan(M_2PI/(360/FAUX_ITALIC_DEGREES)) * (1<<16));
  554. mat.xy += FT_MulFix(f, mat.xx);
  555. mat.yy += FT_MulFix(f, mat.yx);
  556. // do the transform
  557. FT_Vector v = {0,0};
  558. FT_Vector_Transform(&v, &mat);
  559. FT_Glyph_Transform((FT_Glyph)ftg, &mat, &v);
  560. }
  561. // get the glyph
  562. rc = FT_Glyph_To_Bitmap((FT_Glyph*)&ftg, antialias?ft_render_mode_normal:ft_render_mode_mono, NULL, 1);
  563. if (rc)
  564. {
  565. FT_Done_Glyph((FT_Glyph)ftg);
  566. p++;
  567. count++;
  568. continue;
  569. }
  570. FT_Bitmap *bmp = &ftg->bitmap;
  571. int ys = MAX(0, ftg->top);
  572. int ye = bmp->rows - ftg->top;
  573. int xs = MAX(0, ftg->left);
  574. int xe = ftg->left + bmp->width;
  575. FT_Done_Glyph((FT_Glyph)ftg);
  576. int r = 1;
  577. if (font->style_flags & FT_STYLE_FLAG_BOLD)
  578. {
  579. r = MAX((int)((float)(font->glyph->advance.x >> 6) * FAUX_BOLD_RATIO), 2);
  580. }
  581. w += ((r - 1) << 6);
  582. p++;
  583. count++;
  584. }
  585. if (fixed) return w;
  586. return (w >> 6);
  587. }
  588. void FreeTypeFont::textOutWrapped(api_canvas *c, int x, int y, int w, int h, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  589. {
  590. color = RGBTOBGR(color);
  591. bkcolor = RGBTOBGR(bkcolor);
  592. y++; x++;
  593. prepareCanvas(c, size, bold, opaque, underline, italic, color, bkcolor, txt, w, h);
  594. int ascent = getAscent();
  595. int descent = getTextHeight2(c, size, bold, underline, italic, antialias);
  596. descent -= ascent;
  597. int yoff = ascent;
  598. const wchar_t *cur = txt, *next;
  599. int length = (int)wcslen(txt);
  600. //NO.
  601. //for(int yoff = ascent;
  602. for(yoff = ascent;
  603. yoff < h;
  604. yoff += ascent + descent) {
  605. next = find_break(font, cur, w, antialias);
  606. /* POINT pen = { 0, yoff };
  607. lastchar = 0;
  608. for (; cur < next; cur++) {
  609. pen.x += drawChar(pen.x, pen.y, *cur, color);
  610. }*/
  611. drawText(0, yoff, cur, (int)(next-cur), color, antialias);
  612. cur = next;
  613. while (cur && *cur && *cur == ' ')
  614. cur++;
  615. if (*cur == '\r' || *cur == '\n') cur++;
  616. if (cur >= txt + length)
  617. break;
  618. }
  619. restoreCanvas(c, x + xoffset , y + yoffset);
  620. }
  621. void FreeTypeFont::textOutWrappedPathed(api_canvas *c, int x, int y, int w, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  622. {
  623. color = RGBTOBGR(color);
  624. bkcolor = RGBTOBGR(bkcolor);
  625. DebugString("writeme -- FreeTypeFont::textOutWrappedPathed...\n");
  626. }
  627. void FreeTypeFont::textOutCentered(api_canvas *c, RECT *r, const wchar_t *txt, int size, int bold, int opaque, int underline, int italic, int align, COLORREF color, COLORREF bkcolor, int xoffset, int yoffset, int antialias)
  628. {
  629. color = RGBTOBGR(color);
  630. bkcolor = RGBTOBGR(bkcolor);
  631. r->top++;
  632. r->left++;
  633. RECT rr = *r;
  634. rr.left += xoffset;
  635. rr.right += xoffset;
  636. rr.top += yoffset;
  637. rr.bottom += yoffset;
  638. prepareCanvas(c, size, bold, opaque, underline, italic, color, bkcolor, txt, rr.right - rr.left, rr.bottom - rr.top);
  639. int width, height;
  640. height = getAscent();
  641. width = getTextWidth(c, txt, size, bold, underline, italic, (int)antialias);
  642. drawText(((rr.right - rr.left - width) / 2), height, txt, (int)wcslen(txt), color, (int)antialias);
  643. /* POINT pen = { ((rr.right - rr.left - width) / 2) << 6, height };
  644. lastchar = 0;
  645. for (; *txt; txt++) {
  646. pen.x += drawChar(pen.x, pen.y, *txt, color);
  647. }*/
  648. restoreCanvas(c, rr.left, rr.top);
  649. }
  650. int FreeTypeFont::getTextWidth(api_canvas *c, const wchar_t *text, int size, int bold, int underline, int italic, int antialiased)
  651. {
  652. int w;
  653. updateCharmap();
  654. getTextExtent(c, text, &w, NULL, size, bold, underline, italic, antialiased);
  655. return w;
  656. }
  657. int FreeTypeFont::getTextHeight(api_canvas *c, const wchar_t *text, int size, int bold, int underline, int italic, int antialiased) {
  658. int h;
  659. updateCharmap();
  660. getTextExtent(c, text, NULL, &h, size, bold, underline, italic, antialiased);
  661. {
  662. // calcul for multiline text
  663. const wchar_t *p=text;
  664. int n=0;
  665. while(p && *p!=0) if(*p++=='\n') n++;
  666. if(n) h*=(n+1);
  667. }
  668. return h;
  669. }
  670. int FreeTypeFont::getTextHeight2(api_canvas *c, int size, int bold, int underline, int italic, int antialiased)
  671. {
  672. return getTextHeight(c, L"Mg", size, bold, underline, italic, antialiased);
  673. }
  674. void FreeTypeFont::getTextExtent(api_canvas *c, const wchar_t *txt, int *w, int *h, int size, int bold, int underline, int italic, int antialias)
  675. {
  676. updateCharmap();
  677. // Our "size" variable is fun to calculate!
  678. //int vRez = GetDeviceCaps(c->getHDC(), LOGPIXELSY); // this needs to be a Canvas method or something.
  679. int fsize = tweakSize(facename, size);
  680. int nHeight = MulDiv(fsize << 6, 72, 96);
  681. FT_Set_Char_Size(font, 0, nHeight, 0, 0);
  682. font->style_flags = 0;
  683. if (bold)
  684. font->style_flags |= FT_STYLE_FLAG_BOLD;
  685. if (italic)
  686. font->style_flags |= FT_STYLE_FLAG_ITALIC;
  687. if (underline)
  688. font->underline_thickness = 1;
  689. else
  690. font->underline_thickness = 0;
  691. SIZE rsize={0,0};
  692. ASSERT(txt != NULL);
  693. if (*txt == 0)
  694. {
  695. if (w != NULL) *w = 0;
  696. if (h != NULL) *h = 0;
  697. return;
  698. }
  699. FT_BBox box;
  700. FT_Glyph glyph;
  701. int minh = 0, maxh = 0;
  702. if (w)
  703. *w = freetype_width(font, txt, (int)wcslen(txt), 0, antialias) + HORIZONTAL_RPADDING + HORIZONTAL_LPADDING;
  704. if (h)
  705. {
  706. FT_Load_Glyph(font, FT_Get_Char_Index(font, 'M'), FT_LOAD_DEFAULT);
  707. FT_Get_Glyph(font->glyph, &glyph);
  708. FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &box);
  709. maxh = box.yMax;
  710. FT_Done_Glyph(glyph);
  711. FT_Load_Glyph(font, FT_Get_Char_Index(font, 'g'), FT_LOAD_DEFAULT);
  712. FT_Get_Glyph(font->glyph, &glyph);
  713. FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &box);
  714. minh = box.yMin;
  715. FT_Done_Glyph(glyph);
  716. *h = ((maxh - minh) >> 6) + VERTICAL_TPADDING + VERTICAL_BPADDING;
  717. }
  718. }
  719. int FreeTypeFont::isBitmap()
  720. {
  721. return 0;
  722. }
  723. static const wchar_t *find_break(void *f, const wchar_t *str, int width, int antialias)
  724. {
  725. const wchar_t *softret, *lastsoft, *hardret;
  726. if (freetype_width(f, str, (int)wcslen(str), 0, antialias) <= width)
  727. return str + wcslen(str);
  728. for(hardret = str; *hardret; hardret ++)
  729. if (*hardret == '\r' || *hardret == '\n')
  730. break;
  731. if (hardret && freetype_width(f, str, (int)(hardret - str), 0, antialias) <= width) {
  732. return hardret;
  733. }
  734. for(softret = str; *softret && !isspace(*softret); softret++)
  735. ;
  736. if (freetype_width(f, str, (int)(softret - str), 0, antialias) <= width)
  737. {
  738. do
  739. {
  740. lastsoft = softret;
  741. for(softret = lastsoft+1; *softret && !isspace(*softret); softret++)
  742. ;
  743. } while (lastsoft && *lastsoft && freetype_width(f, str, (int)(softret - str), 0, antialias) <= width);
  744. softret = lastsoft;
  745. }
  746. else
  747. {
  748. for(softret = str; *softret; softret++)
  749. if (freetype_width(f, str, (int)(softret - str), 0, antialias) > width)
  750. break;
  751. softret--;
  752. }
  753. return softret;
  754. }