freetype.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2003 by the Free Pascal development team
  5. Basic canvas definitions.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program 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.
  11. **********************************************************************}
  12. {$mode objfpc}{$h+}
  13. unit freetype;
  14. interface
  15. uses sysutils, classes, freetypeh, FPImgCmn;
  16. { TODO : take resolution in account to find the size }
  17. { TODO : speed optimization: search glyphs with a hash-function/tree/binary search/... }
  18. { TODO : memory optimization: TStringBitmaps keeps for each differnet character
  19. only 1 bitmap }
  20. { TODO : load other files depending on the extention }
  21. { possible TODO : different sizes/resolutions for x and y }
  22. { possible TODO : TFontmanager can fill a list of all the fonts he can find
  23. fontfiles and faces available in a fontfile }
  24. // determine if file comparison need to be case sensitive or not
  25. {$ifdef WIN32}
  26. {$undef CaseSense}
  27. {$else}
  28. {$define CaseSense}
  29. {$endif}
  30. type
  31. FreeTypeException = class (exception);
  32. TBitmapType = (btBlackWhite, bt256Gray);
  33. TFontBitmap = record
  34. height, width, pitch,
  35. x,y, advanceX, advanceY : integer;
  36. data : PByteArray;
  37. end;
  38. PFontBitmap = ^TFontBitmap;
  39. TStringBitMaps = class
  40. private
  41. FList : TList;
  42. FBounds : TRect;
  43. FText : string;
  44. FMode : TBitmapType;
  45. function GetCount : integer;
  46. function GetBitmap (index:integer) : PFontBitmap;
  47. procedure CalculateGlobals;
  48. public
  49. constructor Create (ACount : integer);
  50. destructor destroy; override;
  51. procedure GetBoundRect (var aRect : TRect);
  52. property Text : string read FText;
  53. property Mode : TBitmapType read FMode;
  54. property Count : integer read GetCount;
  55. property Bitmaps[index:integer] : PFontBitmap read GetBitmap;
  56. end;
  57. TFontManager = class;
  58. PMgrGlyph = ^TMgrGlyph;
  59. TMgrGlyph = record
  60. Character : char;
  61. GlyphIndex : FT_UInt;
  62. Glyph : PFT_Glyph;
  63. end;
  64. PMgrSize = ^TMgrSize;
  65. TMgrSize = record
  66. Resolution, Size : integer;
  67. Glyphs : TList;
  68. end;
  69. TMgrFont = class
  70. private
  71. Mgr : TFontManager;
  72. Font : PFT_Face;
  73. FSizes : TList;
  74. Filename : string;
  75. LastSize : PMgrSize;
  76. procedure FreeGlyphs;
  77. public
  78. constructor Create (aMgr:TFontManager; afilename:string; anindex:integer);
  79. destructor destroy; override;
  80. end;
  81. TFontManager = class
  82. private
  83. FTLib : PFT_Library;
  84. FList : TList;
  85. FPaths : TStringList;
  86. FExtention : string;
  87. FResolution : integer;
  88. CurFont : TMgrFont;
  89. CurSize : PMgrSize;
  90. CurRenderMode : FT_Render_Mode;
  91. CurTransform : FT_Matrix;
  92. UseKerning : boolean;
  93. function GetSearchPath : string;
  94. procedure SetSearchPath (AValue : string);
  95. procedure SetExtention (AValue : string);
  96. protected
  97. function GetFontId (afilename:string; anindex:integer) : integer;
  98. function CreateFont (afilename:string; anindex:integer) : integer;
  99. function SearchFont (afilename:string) : string;
  100. function GetFont (FontID:integer) : TMgrFont;
  101. procedure GetSize (aSize, aResolution : integer);
  102. function CreateSize (aSize, aResolution : integer) : PMgrSize;
  103. procedure SetPixelSize (aSize, aResolution : integer);
  104. function GetGlyph (c : char) : PMgrGlyph;
  105. function CreateGlyph (c : char) : PMgrGlyph;
  106. procedure MakeTransformation (angle:real; var Transformation:FT_Matrix);
  107. procedure InitMakeString (FontID, Size:integer);
  108. function MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  109. function MakeString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  110. public
  111. constructor Create;
  112. destructor destroy; override;
  113. function RequestFont (afilename:string) : integer;
  114. function RequestFont (afilename:string; anindex:integer) : integer;
  115. function GetFreeTypeFont (aFontID:integer) : PFT_Face;
  116. function GetString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  117. // Black and white
  118. function GetStringGray (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  119. // Anti Aliased gray scale
  120. function GetString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  121. // Black and white, following the direction of the font (left to right, top to bottom, ...)
  122. function GetStringGray (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  123. // Anti Aliased gray scale, following the direction of the font (left to right, top to bottom, ...)
  124. property SearchPath : string read GetSearchPath write SetSearchPath;
  125. property DefaultExtention : string read FExtention write SetExtention;
  126. property Resolution : integer read Fresolution write FResolution;
  127. end;
  128. const
  129. sErrErrorsInCleanup : string = '%d errors detected while freeing a Font Manager object';
  130. sErrFontFileNotFound : string = 'Font file "%s" not found';
  131. sErrFreeType : string = 'Error %d while %s';
  132. sInitializing : string = 'initializing font engine';
  133. sDestroying : string = 'destroying font engine';
  134. sErrErrorInCleanup : string = 'freeing Font Manager object';
  135. sErrSetPixelSize : string = 'setting pixel size %d (resolution %d)';
  136. sErrSetCharSize : string = 'setting char size %d (resolution %d)';
  137. sErrLoadingGlyph : string = 'loading glyph';
  138. sErrKerning : string = 'determining kerning distance';
  139. sErrMakingString : string = 'making string bitmaps';
  140. sErrLoadFont : string = 'loading font %d from file %s';
  141. sErrInitializing : string = 'initializing FreeType';
  142. sErrDestroying : string = 'finalizing FreeType';
  143. DefaultFontExtention : string = '.ttf';
  144. DefaultSearchPath : string = '';
  145. {$IFDEF MAC}
  146. DefaultResolution : integer = 72;
  147. {$ELSE}
  148. DefaultResolution : integer = 97;
  149. {$ENDIF}
  150. implementation
  151. {$IFDEF win32}uses dos;{$ENDIF}
  152. procedure FTError (Event:string; Err:integer);
  153. begin
  154. raise FreeTypeException.CreateFmt (sErrFreeType, [Event,Err]);
  155. end;
  156. { TMgrFont }
  157. constructor TMgrFont.Create (aMgr:TFontManager; afilename:string; anindex:integer);
  158. var e : integer;
  159. begin
  160. inherited create;
  161. Filename := afilename;
  162. Mgr := aMgr;
  163. FSizes := TList.create;
  164. LastSize := nil;
  165. e := FT_New_Face (aMgr.FTLib, pchar(afilename), anindex, font);
  166. if e <> 0 then
  167. begin
  168. Font := nil;
  169. FTError (format (sErrLoadFont,[afilename,anindex]), e);
  170. end;
  171. end;
  172. destructor TMgrFont.destroy;
  173. begin
  174. try
  175. FreeGlyphs;
  176. finally
  177. FSizes.Free;
  178. inherited Destroy;
  179. end;
  180. end;
  181. procedure TMgrFont.FreeGlyphs;
  182. var r,t : integer;
  183. S : PMgrSize;
  184. G : PMgrGlyph;
  185. begin
  186. for r := FSizes.count-1 downto 0 do
  187. begin
  188. with PMgrSize(FSizes[r])^ do
  189. begin
  190. for t := Glyphs.count-1 downto 0 do
  191. begin
  192. with PMgrGlyph(Glyphs[t])^ do
  193. FT_Done_Glyph (Glyph);
  194. G := PMgrGlyph(Glyphs[t]);
  195. dispose (G);
  196. end;
  197. Glyphs.Free;
  198. end;
  199. S := PMgrSize(FSizes[r]);
  200. dispose (S);
  201. end;
  202. end;
  203. { TFontManager }
  204. constructor TFontManager.Create;
  205. var r : integer;
  206. begin
  207. inherited create;
  208. FList := Tlist.Create;
  209. FPaths := TStringList.Create;
  210. r := FT_Init_FreeType(FTLib);
  211. if r <> 0 then
  212. begin
  213. FTLib := nil;
  214. FTError (sErrInitializing, r);
  215. end;
  216. SearchPath := DefaultSearchPath;
  217. DefaultExtention := DefaultFontExtention;
  218. Resolution := DefaultResolution;
  219. end;
  220. destructor TFontManager.Destroy;
  221. procedure FreeFontObjects;
  222. var r : integer;
  223. begin
  224. for r := FList.Count-1 downto 0 do
  225. begin
  226. GetFont(r).Free;
  227. end;
  228. end;
  229. procedure FreeLibrary;
  230. var r : integer;
  231. begin
  232. r := FT_Done_FreeType (FTlib);
  233. if r <> 0 then
  234. FTError (sErrDestroying, r);
  235. end;
  236. begin
  237. FreeFontObjects;
  238. FList.Free;
  239. FPaths.Free;
  240. try
  241. if assigned(FTLib) then
  242. FreeLibrary;
  243. finally
  244. inherited Destroy;
  245. end;
  246. end;
  247. function TFontManager.GetSearchPath : string;
  248. var r : integer;
  249. begin
  250. if FPaths.count > 0 then
  251. begin
  252. result := FPaths[0];
  253. for r := 1 to FPaths.count-1 do
  254. result := result + ';' + FPaths[r];
  255. end
  256. else
  257. result := '';
  258. end;
  259. procedure TFontManager.SetSearchPath (AValue : string);
  260. procedure AddPath (apath : string);
  261. begin
  262. FPaths.Add (IncludeTrailingBackslash(Apath));
  263. end;
  264. var p : integer;
  265. begin
  266. while (AValue <> '') do
  267. begin
  268. p := pos (';', AValue);
  269. if p = 0 then
  270. begin
  271. AddPath (AValue);
  272. AValue := '';
  273. end
  274. else
  275. begin
  276. AddPath (copy(AValue,1,p-1));
  277. delete (AVAlue,1,p);
  278. end;
  279. end;
  280. end;
  281. procedure TFontManager.SetExtention (AValue : string);
  282. begin
  283. if AValue <> '' then
  284. if AValue[1] <> '.' then
  285. FExtention := '.' + AValue
  286. else
  287. FExtention := AValue
  288. else
  289. AValue := '';
  290. end;
  291. function TFontManager.SearchFont (afilename:string) : string;
  292. // returns full filename of font, taking SearchPath in account
  293. var p,fn : string;
  294. r : integer;
  295. begin
  296. if (pos('.', afilename)=0) and (DefaultFontExtention<>'') then
  297. fn := afilename + DefaultFontExtention
  298. else
  299. fn := aFilename;
  300. if FileExists(fn) then
  301. result := ExpandFilename(fn)
  302. else
  303. begin
  304. p := ExtractFilepath(fn);
  305. if p = '' then
  306. begin // no path given, look in SearchPaths
  307. r := FPaths.Count;
  308. repeat
  309. dec (r);
  310. until (r < 0) or FileExists(FPaths[r]+fn);
  311. if r < 0 then
  312. raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [fn])
  313. else
  314. result := FPaths[r]+fn;
  315. end
  316. else
  317. raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [afilename]);
  318. end;
  319. end;
  320. function TFontManager.GetFontId (afilename:string; anindex:integer) : integer;
  321. begin
  322. result := FList.count-1;
  323. while (result >= 0) and
  324. ( ({$ifdef CaseSense}CompareText{$else}CompareStr{$endif}
  325. (TMgrFont(FList[anIndex]).Filename, afilename) <> 0) or
  326. (anIndex <> TMgrFont(FList[anIndex]).font^.face_index)
  327. ) do
  328. dec (result);
  329. end;
  330. function TFontManager.CreateFont (afilename:string; anindex:integer) : integer;
  331. var f : TMgrFont;
  332. begin
  333. writeln ('creating font ',afilename,' (',anindex,')');
  334. f := TMgrFont.Create (self, afilename, anindex);
  335. result := FList.Count;
  336. Flist.Add (f);
  337. end;
  338. function TFontManager.GetFont (FontID:integer) : TMgrFont;
  339. begin
  340. result := TMgrFont(FList[FontID]);
  341. if result <> CurFont then // set last used size of the font as current size
  342. begin
  343. CurSize := result.LastSize;
  344. end;
  345. end;
  346. procedure TFontManager.GetSize (aSize, aResolution : integer);
  347. var r : integer;
  348. begin
  349. if not ( assigned(CurSize) and
  350. (CurSize^.Size = aSize) and (CurSize^.resolution = aResolution)) then
  351. begin
  352. r := CurFont.FSizes.count;
  353. repeat
  354. dec (r)
  355. until (r < 0) or ( (PMgrSize(CurFont.FSizes[r])^.size = aSize) and
  356. (PMgrSize(CurFont.FSizes[r])^.resolution = FResolution) );
  357. if r < 0 then
  358. CurSize := CreateSize (aSize,aResolution)
  359. else
  360. CurSize := PMgrSize(CurFont.FSizes[r]);
  361. CurFont.LastSize := CurSize;
  362. end;
  363. end;
  364. function TFontManager.CreateSize (aSize, aResolution : integer) : PMgrSize;
  365. begin
  366. new (result);
  367. result^.Size := aSize;
  368. result^.Size := aResolution;
  369. result^.Glyphs := Tlist.Create;
  370. SetPixelSize (aSize,aResolution);
  371. CurFont.FSizes.Add (result);
  372. end;
  373. procedure TFontManager.SetPixelSize (aSize, aResolution : integer);
  374. procedure CheckSize;
  375. var r : integer;
  376. begin
  377. with Curfont.Font^ do
  378. begin
  379. r := Num_fixed_sizes;
  380. repeat
  381. dec (r);
  382. until (r < 0) or
  383. ( (available_sizes^[r].height=asize) and
  384. (available_sizes^[r].width=asize) );
  385. if r >= 0 then
  386. raise FreeTypeException.CreateFmt ('Size %d not available for %s %s',
  387. [aSize, style_name, family_name]);
  388. end;
  389. end;
  390. var s : longint;
  391. Err : integer;
  392. begin
  393. with Curfont, Font^ do
  394. if (face_flags and FT_Face_Flag_Fixed_Sizes) <> 0 then
  395. begin
  396. CheckSize;
  397. Err := FT_Set_pixel_sizes (Font, aSize, aSize);
  398. if Err <> 0 then
  399. FTError (format(sErrSetPixelSize,[aSize,aResolution]), Err);
  400. end
  401. else
  402. begin
  403. s := aSize shl 6;
  404. Err := FT_Set_char_size (Font, s, s, aResolution, aResolution);
  405. if Err <> 0 then
  406. FTError (format(sErrSetCharSize,[aSize,aResolution]), Err);
  407. end;
  408. end;
  409. procedure TFontManager.MakeTransformation (angle:real; var Transformation:FT_Matrix);
  410. begin
  411. with Transformation do
  412. begin
  413. xx := round( cos(angle)*$10000);
  414. xy := round(-sin(angle)*$10000);
  415. yx := round( sin(angle)*$10000);
  416. yy := round( cos(angle)*$10000);
  417. end;
  418. end;
  419. function TFontManager.CreateGlyph (c : char) : PMgrGlyph;
  420. var e : integer;
  421. begin
  422. new (result);
  423. result^.character := c;
  424. result^.GlyphIndex := FT_Get_Char_Index (CurFont.font, ord(c));
  425. e := FT_Load_Glyph (CurFont.font, result^.GlyphIndex, FT_Load_Default);
  426. if e <> 0 then
  427. begin
  428. FTError (sErrLoadingGlyph, e);
  429. end;
  430. e := FT_Get_Glyph (Curfont.font^.glyph, result^.glyph);
  431. if e <> 0 then
  432. begin
  433. FTError (sErrLoadingGlyph, e);
  434. end;
  435. CurSize^.Glyphs.Add (result);
  436. end;
  437. function TFontManager.GetGlyph (c : char) : PMgrGlyph;
  438. var r : integer;
  439. begin
  440. With CurSize^ do
  441. begin
  442. r := FList.Count;
  443. repeat
  444. dec (r)
  445. until (r < 0) or (PMgrGlyph(Flist[r])^.character = c);
  446. if r < 0 then
  447. result := CreateGlyph (c)
  448. else
  449. result := PMgrGlyph(Flist[r]);
  450. end;
  451. end;
  452. procedure TFontManager.InitMakeString (FontID, Size:integer);
  453. begin
  454. GetSize (size,Resolution);
  455. UseKerning := ((Curfont.font^.face_flags and FT_FACE_FLAG_KERNING) <> 0);
  456. end;
  457. function TFontManager.MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  458. var g : PMgrGlyph;
  459. bm : PFT_BitmapGlyph;
  460. gl : PFT_Glyph;
  461. e, prevIndex, prevx, c, r, rx : integer;
  462. pre, adv, pos, kern : FT_Vector;
  463. buf : PByteArray;
  464. reverse : boolean;
  465. trans : FT_Matrix;
  466. begin
  467. CurFont := GetFont(FontID);
  468. if (Angle = 0) or // no angle asked, or can't work with angles (not scalable)
  469. ((CurFont.Font^.face_flags and FT_FACE_FLAG_SCALABLE)=0) then
  470. result := MakeString (FontID, Text, Size)
  471. else
  472. begin
  473. InitMakeString (FontID, Size);
  474. c := length(text);
  475. result := TStringBitmaps.Create(c);
  476. if (CurRenderMode = FT_RENDER_MODE_MONO) then
  477. result.FMode := btBlackWhite
  478. else
  479. result.FMode := bt256Gray;
  480. MakeTransformation (angle, trans);
  481. prevIndex := 0;
  482. prevx := 0;
  483. pos.x := 0;
  484. pos.y := 0;
  485. pre.x := 0;
  486. pre.y := 0;
  487. for r := 0 to c-1 do
  488. begin
  489. // retrieve loaded glyph
  490. g := GetGlyph (Text[r+1]);
  491. // check kerning
  492. if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
  493. begin
  494. prevx := pre.x;
  495. e := FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern);
  496. if e <> 0 then
  497. FTError (sErrKerning, e);
  498. pre.x := pre.x + kern.x;
  499. end;
  500. // render the glyph
  501. e := FT_Glyph_Copy (g^.glyph, gl);
  502. if e <> 0 then
  503. FTError (sErrMakingString, e);
  504. // placing the glyph
  505. e := FT_Glyph_Transform (gl, nil, @pre);
  506. if e <> 0 then
  507. FTError (sErrMakingString, e);
  508. adv := gl^.advance;
  509. // rotating the glyph
  510. e := FT_Glyph_Transform (gl, @trans, nil);
  511. if e <> 0 then
  512. FTError (sErrMakingString, e);
  513. // rendering the glyph
  514. e := FT_Glyph_To_Bitmap (gl, CurRenderMode, nil, true);
  515. if e <> 0 then
  516. FTError (sErrMakingString, e);
  517. // Copy what is needed to record
  518. bm := PFT_BitmapGlyph(gl);
  519. with result.Bitmaps[r]^ do
  520. begin
  521. with gl^.advance do
  522. begin
  523. advanceX := x div 64;
  524. advanceY := y div 64;
  525. end;
  526. with bm^ do
  527. begin
  528. height := bitmap.rows;
  529. width := bitmap.width;
  530. x := {(pos.x div 64)} + left; // transformed bitmap has correct x,y
  531. y := {(pos.y div 64)} - top; // not transformed has only a relative correction
  532. buf := PByteArray(bitmap.buffer);
  533. reverse := (bitmap.pitch < 0);
  534. if reverse then
  535. begin
  536. pitch := -bitmap.pitch;
  537. getmem (data, pitch*height);
  538. for rx := height-1 downto 0 do
  539. move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
  540. end
  541. else
  542. begin
  543. pitch := bitmap.pitch;
  544. rx := pitch*height;
  545. getmem (data, rx);
  546. move (buf^[0], data^[0], rx);
  547. end;
  548. end;
  549. end;
  550. // place position for next glyph
  551. with gl^.advance do
  552. begin
  553. pos.x := pos.x + (x div 1024);
  554. pos.y := pos.y + (y div 1024);
  555. end;
  556. with adv do
  557. pre.x := pre.x + (x div 1024);
  558. if prevx > pre.x then
  559. pre.x := prevx;
  560. // finish rendered glyph
  561. FT_Done_Glyph (gl);
  562. end;
  563. result.FText := Text;
  564. result.CalculateGlobals;
  565. end;
  566. end;
  567. function TFontManager.MakeString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  568. var g : PMgrGlyph;
  569. bm : PFT_BitmapGlyph;
  570. gl : PFT_Glyph;
  571. e, prevIndex, prevx, c, r, rx : integer;
  572. pos, kern : FT_Vector;
  573. buf : PByteArray;
  574. reverse : boolean;
  575. begin
  576. CurFont := GetFont(FontID);
  577. InitMakeString (FontID, Size);
  578. c := length(text);
  579. result := TStringBitmaps.Create(c);
  580. if (CurRenderMode = FT_RENDER_MODE_MONO) then
  581. result.FMode := btBlackWhite
  582. else
  583. result.FMode := bt256Gray;
  584. prevIndex := 0;
  585. prevx := 0;
  586. pos.x := 0;
  587. pos.y := 0;
  588. for r := 0 to c-1 do
  589. begin
  590. // retrieve loaded glyph
  591. g := GetGlyph (Text[r+1]);
  592. // check kerning
  593. if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
  594. begin
  595. prevx := pos.x;
  596. e := FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern);
  597. if e <> 0 then
  598. FTError (sErrKerning, e);
  599. pos.x := pos.x + kern.x;
  600. end;
  601. // render the glyph
  602. e := FT_Glyph_Copy (g^.glyph, gl);
  603. if e <> 0 then
  604. FTError (sErrMakingString, e);
  605. e := FT_Glyph_To_Bitmap (gl, CurRenderMode, @pos, true);
  606. if e <> 0 then
  607. FTError (sErrMakingString, e);
  608. // Copy what is needed to record
  609. bm := PFT_BitmapGlyph(gl);
  610. with result.Bitmaps[r]^ do
  611. begin
  612. with gl^.advance do
  613. begin
  614. advanceX := x shr 6;
  615. advanceY := y shr 6;
  616. end;
  617. with bm^ do
  618. begin
  619. height := bitmap.rows;
  620. width := bitmap.width;
  621. x := (pos.x shr 6) + left; // transformed bitmap has correct x,y
  622. y := (pos.y shr 6) - top; // not transformed has only a relative correction
  623. buf := PByteArray(bitmap.buffer);
  624. reverse := (bitmap.pitch < 0);
  625. if reverse then
  626. begin
  627. pitch := -bitmap.pitch;
  628. getmem (data, pitch*height);
  629. for rx := height-1 downto 0 do
  630. move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
  631. end
  632. else
  633. begin
  634. pitch := bitmap.pitch;
  635. rx := pitch*height;
  636. getmem (data, rx);
  637. move (buf^[0], data^[0], rx);
  638. end;
  639. end;
  640. end;
  641. // place position for next glyph
  642. pos.x := pos.x + (gl^.advance.x shr 10);
  643. // pos.y := pos.y + (gl^.advance.y shr 6); // for angled texts also
  644. if prevx > pos.x then
  645. pos.x := prevx;
  646. // finish rendered glyph
  647. FT_Done_Glyph (gl);
  648. end;
  649. result.FText := Text;
  650. result.CalculateGlobals;
  651. end;
  652. function TFontManager.GetString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  653. // Black and white
  654. begin
  655. CurRenderMode := FT_RENDER_MODE_MONO;
  656. result := MakeString (FontID, text, Size, angle);
  657. end;
  658. function TFontManager.GetStringGray (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  659. // Anti Aliased gray scale
  660. begin
  661. CurRenderMode := FT_RENDER_MODE_NORMAL;
  662. result := MakeString (FontID, text, Size, angle);
  663. end;
  664. { Procedures without angle have own implementation to have better speed }
  665. function TFontManager.GetString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  666. // Black and white, following the direction of the font (left to right, top to bottom, ...)
  667. begin
  668. CurRenderMode := FT_RENDER_MODE_MONO;
  669. result := MakeString (FontID, text, Size);
  670. end;
  671. function TFontManager.GetStringGray (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  672. // Anti Aliased gray scale, following the direction of the font (left to right, top to bottom, ...)
  673. begin
  674. CurRenderMode := FT_RENDER_MODE_NORMAL;
  675. result := MakeString (FontID, text, Size);
  676. end;
  677. function TFontManager.RequestFont (afilename:string) : integer;
  678. begin
  679. result := RequestFont (afilename,0);
  680. end;
  681. function TFontManager.RequestFont (afilename:string; anindex:integer) : integer;
  682. var s : string;
  683. begin
  684. if afilename = '' then
  685. result := -1
  686. else
  687. begin
  688. s := SearchFont (afilename);
  689. result := GetFontID (s,anindex);
  690. if result < 0 then
  691. result := CreateFont (s,anindex);
  692. end;
  693. end;
  694. function TFontManager.GetFreeTypeFont (aFontID:integer) : PFT_Face;
  695. begin
  696. result := GetFont(aFontID).font;
  697. end;
  698. { TStringBitmaps }
  699. function TStringBitmaps.GetCount : integer;
  700. begin
  701. result := FList.Count;
  702. end;
  703. function TStringBitmaps.GetBitmap (index:integer) : PFontBitmap;
  704. begin
  705. result := PFontBitmap(FList[index]);
  706. end;
  707. constructor TStringBitmaps.Create (ACount : integer);
  708. var r : integer;
  709. bm : PFontBitmap;
  710. begin
  711. inherited create;
  712. FList := Tlist.Create;
  713. FList.Capacity := ACount;
  714. for r := 0 to ACount-1 do
  715. begin
  716. new (bm);
  717. FList.Add (bm);
  718. end;
  719. end;
  720. destructor TStringBitmaps.destroy;
  721. var r : integer;
  722. bm : PFontBitmap;
  723. begin
  724. for r := 0 to Flist.count-1 do
  725. begin
  726. bm := PFontBitmap(FList[r]);
  727. freemem (bm^.data);
  728. dispose (bm);
  729. end;
  730. FList.Free;
  731. inherited;
  732. end;
  733. procedure TStringBitmaps.CalculateGlobals;
  734. var r : integer;
  735. begin
  736. if count = 0 then
  737. Exit;
  738. // check first 2 bitmaps for left side
  739. // check last 2 bitmaps for right side
  740. with BitMaps[0]^ do
  741. begin
  742. FBounds.left := x;
  743. FBounds.top := y + height;
  744. FBounds.bottom := y;
  745. end;
  746. with Bitmaps[count-1]^ do
  747. FBounds.right := x + width;
  748. if count > 1 then
  749. begin
  750. with Bitmaps[1]^ do
  751. r := x;
  752. if r < FBounds.left then
  753. FBounds.left := r;
  754. with Bitmaps[count-2]^ do
  755. r := x + width;
  756. if r > FBounds.right then
  757. FBounds.right := r;
  758. end;
  759. // check top/bottom of other bitmaps
  760. for r := 1 to count-1 do
  761. with Bitmaps[r]^ do
  762. begin
  763. if FBounds.top < y + height then
  764. FBounds.top := y + height;
  765. if FBounds.bottom > y then
  766. FBounds.bottom := y;
  767. end;
  768. end;
  769. procedure TStringBitmaps.GetBoundRect (var aRect : TRect);
  770. begin
  771. aRect := FBounds;
  772. end;
  773. {$ifdef win32}
  774. procedure SetWindowsFontPath;
  775. begin
  776. DefaultSearchPath := includetrailingbackslash(GetEnv('windir')) + 'fonts';
  777. end;
  778. {$endif}
  779. initialization
  780. {$ifdef win32}
  781. SetWindowsFontPath;
  782. {$endif}
  783. end.