PageRenderTime 95ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/source/libs/paragui/src/font/pgfont.cpp

https://bitbucket.org/val_haris/asc-ai
C++ | 776 lines | 504 code | 153 blank | 119 comment | 117 complexity | f8b0e82423831c27c57c52f3044f1ed0 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. /*
  2. ParaGUI - crossplatform widgetset
  3. Copyright (C) 2000,2001,2002 Alexander Pipelka
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. Alexander Pipelka
  16. pipelka@teleweb.at
  17. Last Update: $Author: mbickel $
  18. Update Date: $Date: 2009-04-18 13:48:40 $
  19. Source File: $Source: /home/martin/asc/v2/svntest/games/asc/source/libs/paragui/src/font/pgfont.cpp,v $
  20. CVS/RCS Revision: $Revision: 1.3 $
  21. Status: $State: Exp $
  22. */
  23. #include "pgfont.h"
  24. #include "pglog.h"
  25. #include "pgfilearchive.h"
  26. #include "facecache.h"
  27. #include "pgstring.h"
  28. //#define OLD_TEXTRENDERING
  29. //SDL_Surface* PG_FontEngine::my_charSurface = NULL;
  30. PG_FontEngine::MAP_FONTS PG_FontEngine::my_fontcache;
  31. FT_Library PG_FontEngine::my_library;
  32. PG_FontEngine::PG_FontEngine() {
  33. FT_Init_FreeType(&my_library);
  34. }
  35. PG_FontEngine::~PG_FontEngine() {
  36. // clean fontcache
  37. for(MAP_FONTS::iterator i = my_fontcache.begin(); i != my_fontcache.end(); i++) {
  38. delete (*i).second;
  39. }
  40. my_fontcache.clear();
  41. FT_Done_FreeType(my_library);
  42. /*if (my_charSurface != NULL) {
  43. SDL_FreeSurface(my_charSurface);
  44. }*/
  45. }
  46. void PG_FontEngine::FontEngineError(FT_Error error) {
  47. #undef __FTERRORS_H__
  48. #define FT_ERRORDEF( e, v, s ) { e, s },
  49. #define FT_ERROR_START_LIST {
  50. #define FT_ERROR_END_LIST { -1, NULL } };
  51. const struct {
  52. int err_code;
  53. const char *err_msg;
  54. }
  55. ft_errors[] =
  56. #include FT_ERRORS_H
  57. int i = 0;
  58. while (ft_errors[i].err_code != -1) {
  59. if (ft_errors[i].err_code == error) {
  60. PG_LogWRN("FreeType error %d : %s",error,ft_errors[i].err_msg);
  61. return;
  62. }
  63. i++;
  64. }
  65. PG_LogWRN("FreeType : Unknown error : %d", error);
  66. return;
  67. }
  68. /*bool PG_FontEngine::PG_GetFontFace(PG_Font* Param) {
  69. PG_FontFaceCacheItem* CacheItem = LoadFontFace(
  70. Param->GetName(),
  71. Param->GetSize());
  72. Param->SetFaceCache(CacheItem);
  73. return (Param->GetFaceCache() != NULL);
  74. }*/
  75. PG_GlyphCacheItem* PG_FontEngine::GetGlyph(PG_Font *Param, int glyph_index) {
  76. PG_FontFaceCacheItem* facecache = Param->GetFaceCache();
  77. PG_GlyphCacheItem *GlyphCacheItem = facecache->GlyphCache[glyph_index];
  78. if(GlyphCacheItem != NULL) {
  79. return GlyphCacheItem;
  80. }
  81. FT_Face face = facecache->Face;
  82. if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER ))
  83. return NULL;
  84. Uint32 bitmapsize = face->glyph->bitmap.pitch * face->glyph->bitmap.rows;
  85. GlyphCacheItem = new PG_GlyphCacheItem(bitmapsize);
  86. GlyphCacheItem->Glyph_Index = glyph_index;
  87. GlyphCacheItem->Bitmap = face->glyph->bitmap;
  88. GlyphCacheItem->Bitmap_left = face->glyph->bitmap_left;
  89. GlyphCacheItem->Bitmap_top = face->glyph->bitmap_top;
  90. GlyphCacheItem->Advance_x = FT_CEIL(face->glyph->metrics.horiAdvance);
  91. memcpy(GlyphCacheItem->data(), face->glyph->bitmap.buffer, bitmapsize);
  92. GlyphCacheItem->Bitmap.buffer = (unsigned char*)GlyphCacheItem->data();
  93. facecache->GlyphCache[glyph_index] = GlyphCacheItem;
  94. return GlyphCacheItem;
  95. }
  96. #ifndef OLD_TEXTRENDERING
  97. template < class DT >
  98. inline void BlitTemplate(DT pixels, SDL_Surface* Surface, FT_Bitmap *Bitmap, int PosX, int PosY, int x0, int x1, int y0, int y1, PG_Font *Param) {
  99. int xw = x1-x0;
  100. SDL_PixelFormat* format = Surface->format;
  101. Uint8 Rloss = format->Rloss;
  102. Uint8 Gloss = format->Gloss;
  103. Uint8 Bloss = format->Bloss;
  104. Uint8 Aloss = format->Aloss;
  105. Uint8 Rloss8 = 8-Rloss;
  106. Uint8 Gloss8 = 8-Gloss;
  107. Uint8 Bloss8 = 8-Bloss;
  108. Uint8 Aloss8 = 8-Aloss;
  109. Uint8 Rshift = format->Rshift;
  110. Uint8 Gshift = format->Gshift;
  111. Uint8 Bshift = format->Bshift;
  112. Uint8 Ashift = format->Ashift;
  113. Uint32 Rmask = format->Rmask;
  114. Uint32 Gmask = format->Gmask;
  115. Uint32 Bmask = format->Bmask;
  116. Uint32 Amask = format->Amask;
  117. Uint8 bpp = format->BytesPerPixel;
  118. Uint32 pitch = Surface->pitch;
  119. Uint32 src_pitch = Bitmap->pitch;
  120. register Uint8* src_pixels = Bitmap->buffer + x0 + y0*Bitmap->pitch;
  121. register Uint8* dst_pixels = (Uint8*)pixels + (PosX+x0)*bpp + (PosY+y0)*pitch /*+ Surface->offset*/;
  122. Uint8* line;
  123. Uint8 r,g,b,a;
  124. unsigned rv,gv,bv,av;
  125. Sint32 cr,cg,cb;
  126. Uint32 color = 0;
  127. Sint32 v;
  128. PG_Color fc = Param->GetColor();
  129. cr = fc.r;
  130. cg = fc.g;
  131. cb = fc.b;
  132. int alpha = Param->GetAlpha();
  133. line = dst_pixels;
  134. for (register int y = y0; y <y1; y++, src_pixels += src_pitch) {
  135. dst_pixels = line;
  136. for (register int x = x0; x < x1; x++, dst_pixels += bpp) {
  137. // get source pixel value
  138. v = *(Uint8 *)(src_pixels++);
  139. // don't do anything if the pixel is fully transparent
  140. if(v == 0) {
  141. continue;
  142. }
  143. if(alpha != 255) {
  144. v = (v * alpha) >> 8;
  145. }
  146. // Get the pixel
  147. color = *((DT) (dst_pixels));
  148. switch(Surface->format->BytesPerPixel) {
  149. default:
  150. // get the RGBA values
  151. rv = (color & Rmask) >> Rshift;
  152. r = (rv << Rloss) + (rv >> Rloss8);
  153. gv = (color & Gmask) >> Gshift;
  154. g = (gv << Gloss) + (gv >> Gloss8);
  155. bv = (color & Bmask) >> Bshift;
  156. b = (bv << Bloss) + (bv >> Bloss8);
  157. if(Amask) {
  158. av = (color & Amask) >> Ashift;
  159. a = (av << Aloss) + (av >> Aloss8);
  160. } else
  161. a = SDL_ALPHA_OPAQUE;
  162. //SDL_GetRGBA(color, format, &r, &g, &b, &a);
  163. // calculate new RGBA values
  164. if(v == 255) {
  165. r = cr;
  166. g = cg;
  167. b = cb;
  168. } else {
  169. //r += ((cr - r) * v) / 255;
  170. //g += ((cg - g) * v) / 255;
  171. //b += ((cb - b) * v) / 255;
  172. r += ((cr - r) * v) >> 8;
  173. g += ((cg - g) * v) >> 8;
  174. b += ((cb - b) * v) >> 8;
  175. }
  176. // if the destination pixel is full transparent
  177. // use the pixel shading as alpha
  178. if(a == 0) {
  179. a = v;
  180. }
  181. // get the destination color
  182. color = (r >> Rloss) << Rshift
  183. | (g >> Gloss) << Gshift
  184. | (b >> Bloss) << Bshift
  185. | ((a >> Aloss) << Ashift & Amask);
  186. // Set the pixel
  187. *((DT) (dst_pixels)) = color;
  188. break;
  189. case 3:
  190. cr = (fc.r << format->Rshift) >> 16 & 0xff;
  191. cg = (fc.g << format->Gshift) >> 8 & 0xff;
  192. cb = fc.b << format->Bshift & 0xff;
  193. if (v == 255) {
  194. r = cr;
  195. g = cg;
  196. b = cb;
  197. }
  198. // calculate new RGB values
  199. else {
  200. b = *(dst_pixels);
  201. g = *(dst_pixels+1);
  202. r = *(dst_pixels+2);
  203. r += ((cr - r) * v) >> 8;
  204. g += ((cg - g) * v) >> 8;
  205. b += ((cb - b) * v) >> 8;
  206. }
  207. *dst_pixels = b;
  208. *(dst_pixels + 1) = g;
  209. *(dst_pixels + 2) = r;
  210. break;
  211. case 1:
  212. SDL_GetRGBA(color, format, &r, &g, &b, &a);
  213. // calculate new RGBA values
  214. if(v == 255) {
  215. r = cr;
  216. g = cg;
  217. b = cb;
  218. } else {
  219. //r += ((cr - r) * v) / 255;
  220. //g += ((cg - g) * v) / 255;
  221. //b += ((cb - b) * v) / 255;
  222. r += ((cr - r) * v) >> 8;
  223. g += ((cg - g) * v) >> 8;
  224. b += ((cb - b) * v) >> 8;
  225. }
  226. // if the destination pixel is full transparent
  227. // use the pixel shading as alpha
  228. if(a == 0) {
  229. a = v;
  230. }
  231. color = SDL_MapRGBA(format, r,g,b, a);
  232. *((DT) (dst_pixels)) = color;
  233. break;
  234. }
  235. }
  236. src_pixels -= xw;
  237. line += pitch;
  238. }
  239. }
  240. bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, const PG_Rect* ClipRect) {
  241. int BitmapRealWidth;
  242. // i think we can skip that test
  243. /*if(Bitmap->pixel_mode != ft_pixel_mode_grays) {
  244. return false;
  245. }*/
  246. // do nothing if we're fully transparent
  247. if (Param->GetAlpha() == 0)
  248. return true;
  249. BitmapRealWidth = Bitmap->width;
  250. // get the cliprectangle of the surface
  251. static PG_Rect srfclip;
  252. SDL_GetClipRect(Surface, &srfclip);
  253. // the real clipping rectangle = surfaceclip / ClipRect
  254. static PG_Rect clip;
  255. clip = *ClipRect / srfclip;
  256. //Italic font is widther than normal
  257. //if (Param->Style & PG_FSTYLE_ITALIC) {
  258. // BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
  259. //}
  260. int x0 = 0;
  261. int x1 = BitmapRealWidth;
  262. int y0 = 0;
  263. int y1 = Bitmap->rows;
  264. if(PosX < clip.x) {
  265. x0 = clip.x - PosX;
  266. }
  267. if(PosX+BitmapRealWidth > clip.x + clip.w) {
  268. x1 = (clip.x + clip.w) - PosX;
  269. }
  270. if(PosY < clip.y) {
  271. y0 = clip.y - PosY;
  272. }
  273. if(PosY+Bitmap->rows > clip.y + clip.h) {
  274. y1 = (clip.y + clip.h) - PosY;
  275. }
  276. if((x1 <= x0) || (y1 <= y0)) {
  277. return false;
  278. }
  279. switch(Surface->format->BytesPerPixel) {
  280. case 1:
  281. case 3:
  282. BlitTemplate((Uint8*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
  283. break;
  284. case 2:
  285. BlitTemplate((Uint16*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
  286. break;
  287. case 4:
  288. BlitTemplate((Uint32*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
  289. break;
  290. default:
  291. PG_LogWRN("Unable to draw font: unsupported bit depth!");
  292. break;
  293. }
  294. return true;
  295. }
  296. #else
  297. bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, PG_Rect *ClipRect) {
  298. int x,y;
  299. Uint32 *raw_pixels;
  300. SDL_Rect TargetPos;
  301. SDL_Rect SourcePos;
  302. int BitmapRealWidth;
  303. if (Param->Alpha == 0)
  304. return true;
  305. TargetPos.x = PosX;
  306. TargetPos.y = PosY;
  307. //Italic font is widther than normal
  308. BitmapRealWidth = Bitmap->width;
  309. if (Param->Style & PG_FSTYLE_ITALIC) {
  310. BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
  311. }
  312. //There is no need to draw
  313. if ((TargetPos.x > (ClipRect->x + ClipRect->w)) || (TargetPos.y > (ClipRect->y +ClipRect->h )) || ((TargetPos.y+Bitmap->rows) < ClipRect->y) || ((TargetPos.x+BitmapRealWidth) < ClipRect->x))
  314. return true;
  315. //Is my_charSurface big enough ??
  316. if (my_charSurface != NULL) {
  317. if ((my_charSurface->w < BitmapRealWidth)||(my_charSurface->h < Bitmap->rows)) {
  318. SDL_FreeSurface(my_charSurface);
  319. my_charSurface = NULL;
  320. }
  321. }
  322. if (my_charSurface == NULL) {
  323. my_charSurface = SDL_CreateRGBSurface(SDL_SRCALPHA , BitmapRealWidth, Bitmap->rows, 32, 0xff0000, 0xff00, 0xff, 0xff000000);
  324. if (my_charSurface == NULL) {
  325. PG_LogWRN("Can`t get char surface : %s",SDL_GetError());
  326. return false;
  327. }
  328. }
  329. if (Param->Style & PG_FSTYLE_ITALIC) {
  330. SDL_FillRect(my_charSurface, NULL, 0);
  331. }
  332. SourcePos.x = 0; // = my_charSurface->clip_rect;
  333. SourcePos.y = 0;
  334. SourcePos.w = BitmapRealWidth;
  335. SourcePos.h = Bitmap->rows;
  336. //Clipping
  337. if ((TargetPos.x + SourcePos.w) > (ClipRect->x + ClipRect->w))
  338. SourcePos.w = ClipRect->w - (TargetPos.x - ClipRect->x);
  339. if ((TargetPos.y + SourcePos.h) > (ClipRect->y + ClipRect->h))
  340. SourcePos.h = ClipRect->h - (TargetPos.y - ClipRect->y);
  341. if (TargetPos.x < ClipRect->x) {
  342. int delta;
  343. delta = ClipRect->x - TargetPos.x;
  344. SourcePos.w -= delta;
  345. TargetPos.x += delta;
  346. SourcePos.x += delta;
  347. }
  348. if (TargetPos.y < ClipRect->y) {
  349. int delta;
  350. delta = ClipRect->y - TargetPos.y;
  351. SourcePos.h -= delta;
  352. TargetPos.y += delta;
  353. SourcePos.y += delta;
  354. }
  355. raw_pixels = (Uint32 *) my_charSurface->pixels;
  356. Uint32 pitch_diff = 0;
  357. switch (Bitmap->pixel_mode) {
  358. case ft_pixel_mode_grays: {
  359. Uint8 *SrcPix = Bitmap->buffer;
  360. int a;
  361. if (Param->Style & PG_FSTYLE_ITALIC) {
  362. double ioffset = Bitmap->rows * PG_FITALIC_ANGLE;
  363. for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch, ioffset -= PG_FITALIC_ANGLE) {
  364. for (x = 0; x < Bitmap->width; x++) {
  365. a = *(Uint8 *)(SrcPix++);
  366. // What the hell should do this ?
  367. //if (Param->Alpha != 255)
  368. // a = (a * Param->Alpha) / 255;
  369. raw_pixels[int(ioffset) + x + (my_charSurface->pitch/4)*(y)] = Param->Color.MapRGBA(my_charSurface->format, a);
  370. }
  371. SrcPix -= x;
  372. }
  373. } else
  374. pitch_diff = (my_charSurface->pitch/4);
  375. for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch) {
  376. for (x = 0; x < Bitmap->width; x++) {
  377. a = *(Uint8 *)(SrcPix++);
  378. // Q: What the hell should do this ?
  379. // A: This allows for alpha
  380. // rendering of text. // Neo
  381. if (Param->Alpha != 255)
  382. a = (a * Param->Alpha) / 255;
  383. *raw_pixels = Param->Color.MapRGBA(my_charSurface->format, a);
  384. raw_pixels++;
  385. }
  386. SrcPix -= x;
  387. raw_pixels -= x;
  388. raw_pixels += pitch_diff;
  389. }
  390. break;
  391. }
  392. default:
  393. PG_LogWRN("Unknown pixel type in font !");
  394. return false;
  395. }
  396. // Final blit
  397. SDL_Rect BoldTarget = TargetPos;
  398. SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &TargetPos);
  399. //BOLD
  400. if (Param->Style & PG_FSTYLE_BOLD) {
  401. BoldTarget.x += Param->FaceCache->Bold_Offset;
  402. SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &BoldTarget);
  403. }
  404. return true;
  405. }
  406. #endif
  407. bool PG_FontEngine::RenderText(SDL_Surface *Surface, const PG_Rect& ClipRect, int BaseLineX, int BaseLineY, const PG_String& Text, PG_Font *ParamIn) {
  408. return RenderText(Surface, (PG_Rect*)&ClipRect, BaseLineX, BaseLineY, Text, ParamIn);
  409. }
  410. bool PG_FontEngine::RenderText(SDL_Surface *Surface, const PG_Rect *ClipRect, int BaseLineX, int BaseLineY, const PG_String& Text, PG_Font* font) {
  411. static bool bRecursion = false;
  412. int OriBaseX = BaseLineX;
  413. FT_UInt previous = 0;
  414. PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
  415. // invalid font ?
  416. if (FaceCache == NULL) {
  417. return false;
  418. }
  419. FT_Face Face = FaceCache->Face;
  420. FT_Vector delta;
  421. if(SDL_MUSTLOCK(Surface)) {
  422. SDL_LockSurface(Surface);
  423. }
  424. Uint32 c0;
  425. //Go thu text and draw characters
  426. int len = Text.size();
  427. for(int i = 0; i < len; i++) {
  428. int glyph_index;
  429. PG_GlyphCacheItem* Glyph;
  430. int OldBaseLineX = BaseLineX;
  431. c0 = (PG_Char)(Text[i]);
  432. //Skip drawing we go non-printable char
  433. if (c0 < 32) {
  434. continue;
  435. }
  436. //Get glyph index
  437. glyph_index = FT_Get_Char_Index(Face, c0);
  438. //Make space between characters == kerneling
  439. if ( FaceCache->Use_Kerning && previous && glyph_index ) {
  440. FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
  441. BaseLineX += delta.x >> 6;
  442. }
  443. previous = glyph_index;
  444. //Get glyph bitmap
  445. Glyph = GetGlyph(font, glyph_index);
  446. //Blit glyph bitmap into the surface
  447. if (c0 != ' ') {
  448. BlitFTBitmap(Surface, &Glyph->Bitmap, BaseLineX + Glyph->Bitmap_left, BaseLineY - Glyph->Bitmap_top, font, ClipRect);
  449. }
  450. BaseLineX += Glyph->Advance_x;
  451. if (font->GetStyle() & PG_Font::BOLD) {
  452. BaseLineX += FaceCache->Bold_Offset;
  453. }
  454. //UNDERLINE
  455. //TO-DO : Underline is not transparent !!!! (Fill must be replaced by Blit)
  456. if (font->GetStyle() & PG_Font::UNDERLINE) {
  457. SDL_Rect und_rect;
  458. und_rect.x = OldBaseLineX;
  459. und_rect.y = BaseLineY;
  460. und_rect.h = FaceCache->Underline_Height;
  461. und_rect.w = BaseLineX - OldBaseLineX;
  462. SDL_FillRect(
  463. Surface,
  464. &und_rect,
  465. font->GetColor().MapRGB(Surface->format)
  466. );
  467. }
  468. }
  469. //BOLD
  470. if (font->GetStyle() & PG_Font::BOLD && !bRecursion) {
  471. bRecursion = true;
  472. RenderText(Surface, ClipRect, OriBaseX+1, BaseLineY, Text, font);
  473. bRecursion = false;
  474. }
  475. if(SDL_MUSTLOCK(Surface)) {
  476. SDL_UnlockSurface(Surface);
  477. }
  478. return true;
  479. }
  480. bool PG_FontEngine::GetTextSize(const PG_String& Text, PG_Font* font, Uint16 *Width, Uint16 *Height, int *BaselineY, int *FontLineSkip, Uint16 *FontHeight, int *Ascent, int *Descent) {
  481. FT_UInt previous = 0;
  482. int BaseLineX = 0;
  483. int preBaseLineY = 0;
  484. int MaxY = 0;
  485. Uint16 preFontHeight = 0;
  486. int preLineSkip = 0;
  487. int preAscent = 0;
  488. int preDescent = 0;
  489. PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
  490. // invalid font ?
  491. if (FaceCache == NULL) {
  492. return false;
  493. }
  494. FT_Face Face = FaceCache->Face;
  495. //Initial parametrs check
  496. if (FaceCache != NULL) {
  497. if (preFontHeight < FaceCache->Height)
  498. preFontHeight = FaceCache->Height;
  499. if (preLineSkip < FaceCache->LineSkip)
  500. preLineSkip = FaceCache->LineSkip;
  501. if (preAscent < FaceCache->Ascent)
  502. preAscent = FaceCache->Ascent;
  503. if (preDescent > FaceCache->Descent)
  504. preDescent = FaceCache->Descent;
  505. }
  506. //Go thu text and get sizes of the characters
  507. Uint32 c0;
  508. int len = Text.size();
  509. for(int i = 0; i < len; i++) {
  510. int glyph_index;
  511. PG_GlyphCacheItem *Glyph;
  512. c0 = Text[i];
  513. //Skip non-printable char
  514. if (c0 < 32) {
  515. continue;
  516. }
  517. //Get glyph index
  518. glyph_index = FT_Get_Char_Index(Face, c0);
  519. //Make space between characters == kerneling
  520. if ( FaceCache->Use_Kerning && previous && glyph_index ) {
  521. FT_Vector delta;
  522. FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
  523. BaseLineX += delta.x >> 6;
  524. }
  525. previous = glyph_index;
  526. //Get glyph bitmap
  527. Glyph = GetGlyph(font, glyph_index);
  528. if (preBaseLineY < Glyph->Bitmap_top) {
  529. preBaseLineY = Glyph->Bitmap_top;
  530. }
  531. if (MaxY < Glyph->Bitmap.rows) {
  532. MaxY = Glyph->Bitmap.rows;
  533. }
  534. BaseLineX += Glyph->Advance_x;
  535. if (font->GetStyle() & PG_Font::BOLD) {
  536. BaseLineX += FaceCache->Bold_Offset;
  537. }
  538. }
  539. if (Height != NULL)
  540. *Height = MaxY;
  541. if (Width != NULL)
  542. *Width = BaseLineX;
  543. if (BaselineY!= NULL)
  544. *BaselineY = preBaseLineY;
  545. if (FontLineSkip!= NULL)
  546. *FontLineSkip = preLineSkip;
  547. if (FontHeight != NULL)
  548. *FontHeight = preFontHeight;
  549. if (Ascent != NULL)
  550. *Ascent = preAscent;
  551. if (Descent != NULL)
  552. *Descent = preDescent;
  553. return true;
  554. }
  555. PG_FontFaceCacheItem* PG_FontEngine::LoadFontFace(const std::string& filename, FT_F26Dot6 fontsize, int index) {
  556. // lets see if the file is already in the cache
  557. FONT_ITEM* item = my_fontcache[filename];
  558. // NO -> Load the face from the file
  559. if(item == NULL) {
  560. // open the fontfile
  561. PG_DataContainer* data = PG_FileArchive::ReadFile(filename);
  562. if(!data) {
  563. return NULL;
  564. }
  565. // create new font item
  566. item = new FONT_ITEM;
  567. item->name = filename;
  568. item->memdata = data;
  569. // add the face to the cache
  570. my_fontcache[filename] = item;
  571. }
  572. // let's see if we already have a face for the given size
  573. PG_FontFaceCacheItem* subitem = item->subitems[fontsize];
  574. // NO -> create new face for the size
  575. if(subitem == NULL) {
  576. subitem = new PG_FontFaceCacheItem;
  577. subitem->fontsize = fontsize;
  578. // create the freetype face
  579. FT_New_Memory_Face(my_library, (FT_Byte*)item->memdata->data(),
  580. item->memdata->size(), 0,
  581. &(subitem->Face));
  582. // check if the font is scaleable
  583. if (!FT_IS_SCALABLE(subitem->Face) ) {
  584. PG_LogWRN("Font %s is not scalable !", filename.c_str());
  585. delete subitem;
  586. return NULL;
  587. }
  588. // set font size
  589. FT_Set_Char_Size(subitem->Face, 0, fontsize*64, 0, 0);
  590. // set subitem params
  591. subitem->Bold_Offset = 1 + fontsize / 20;
  592. subitem->Underline_Height = FT_FLOOR(FT_MulFix(subitem->Face->underline_thickness, subitem->Face->size->metrics.y_scale));
  593. if ( subitem->Underline_Height < 1 ) {
  594. subitem->Underline_Height = 1;
  595. }
  596. subitem->Ascent = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMax, subitem->Face->size->metrics.y_scale));
  597. subitem->Descent = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMin, subitem->Face->size->metrics.y_scale));
  598. subitem->Height = subitem->Ascent - subitem->Descent + 1;
  599. subitem->LineSkip = FT_CEIL(FT_MulFix(subitem->Face->height, subitem->Face->size->metrics.y_scale));
  600. subitem->Use_Kerning = FT_HAS_KERNING(subitem->Face);
  601. // add to subitem list
  602. item->subitems[fontsize] = subitem;
  603. }
  604. return subitem;
  605. }
  606. PG_FontEngine::FONT_ITEM::~FONT_ITEM() {
  607. for(MAP_SUBITEMS::iterator i = subitems.begin(); i != subitems.end(); i++) {
  608. delete (*i).second;
  609. }
  610. delete memdata;
  611. }
  612. /*
  613. * Local Variables:
  614. * c-basic-offset: 8
  615. * End:
  616. */