freetype.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  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. sErrMakingString1 : string = 'making string bitmaps step 1';
  140. sErrMakingString2 : string = 'making string bitmaps step 2';
  141. sErrMakingString3 : string = 'making string bitmaps step 3';
  142. sErrMakingString4 : string = 'making string bitmaps step 4';
  143. sErrLoadFont : string = 'loading font %d from file %s';
  144. sErrInitializing : string = 'initializing FreeType';
  145. sErrDestroying : string = 'finalizing FreeType';
  146. DefaultFontExtention : string = '.ttf';
  147. DefaultSearchPath : string = '';
  148. {$IFDEF MAC}
  149. DefaultResolution : integer = 72;
  150. {$ELSE}
  151. DefaultResolution : integer = 97;
  152. {$ENDIF}
  153. implementation
  154. {$IFDEF win32}uses dos;{$ENDIF}
  155. procedure FTError (Event:string; Err:integer);
  156. begin
  157. raise FreeTypeException.CreateFmt (sErrFreeType, [Err,Event]);
  158. end;
  159. Function FTCheck (Res: Integer; Msg:string) : Integer;
  160. begin
  161. Result:=Res;
  162. If (Result<>0) then
  163. FTError(Msg,Result);
  164. end;
  165. { TMgrFont }
  166. constructor TMgrFont.Create (aMgr:TFontManager; afilename:string; anindex:integer);
  167. begin
  168. inherited create;
  169. Filename := afilename;
  170. Mgr := aMgr;
  171. FSizes := TList.create;
  172. LastSize := nil;
  173. Try
  174. FTCheck(FT_New_Face (aMgr.FTLib, pchar(afilename), anindex, font),format (sErrLoadFont,[anindex,afilename]));
  175. except
  176. Font:=Nil;
  177. Raise;
  178. end;
  179. end;
  180. destructor TMgrFont.destroy;
  181. begin
  182. try
  183. FreeGlyphs;
  184. finally
  185. FSizes.Free;
  186. inherited Destroy;
  187. end;
  188. end;
  189. procedure TMgrFont.FreeGlyphs;
  190. var r,t : integer;
  191. S : PMgrSize;
  192. G : PMgrGlyph;
  193. begin
  194. for r := FSizes.count-1 downto 0 do
  195. begin
  196. with PMgrSize(FSizes[r])^ do
  197. begin
  198. for t := Glyphs.count-1 downto 0 do
  199. begin
  200. with PMgrGlyph(Glyphs[t])^ do
  201. FT_Done_Glyph (Glyph);
  202. G := PMgrGlyph(Glyphs[t]);
  203. dispose (G);
  204. end;
  205. Glyphs.Free;
  206. end;
  207. S := PMgrSize(FSizes[r]);
  208. dispose (S);
  209. end;
  210. end;
  211. { TFontManager }
  212. constructor TFontManager.Create;
  213. var r : integer;
  214. begin
  215. inherited create;
  216. FList := Tlist.Create;
  217. FPaths := TStringList.Create;
  218. r := FT_Init_FreeType(FTLib);
  219. if r <> 0 then
  220. begin
  221. FTLib := nil;
  222. FTError (sErrInitializing, r);
  223. end;
  224. SearchPath := DefaultSearchPath;
  225. DefaultExtention := DefaultFontExtention;
  226. Resolution := DefaultResolution;
  227. end;
  228. destructor TFontManager.Destroy;
  229. procedure FreeFontObjects;
  230. var r : integer;
  231. begin
  232. for r := FList.Count-1 downto 0 do
  233. begin
  234. GetFont(r).Free;
  235. end;
  236. end;
  237. procedure FreeLibrary;
  238. var r : integer;
  239. begin
  240. r := FT_Done_FreeType (FTlib);
  241. if r <> 0 then
  242. FTError (sErrDestroying, r);
  243. end;
  244. begin
  245. FreeFontObjects;
  246. FList.Free;
  247. FPaths.Free;
  248. try
  249. if assigned(FTLib) then
  250. FreeLibrary;
  251. finally
  252. inherited Destroy;
  253. end;
  254. end;
  255. function TFontManager.GetSearchPath : string;
  256. var r : integer;
  257. begin
  258. if FPaths.count > 0 then
  259. begin
  260. result := FPaths[0];
  261. for r := 1 to FPaths.count-1 do
  262. result := result + ';' + FPaths[r];
  263. end
  264. else
  265. result := '';
  266. end;
  267. procedure TFontManager.SetSearchPath (AValue : string);
  268. procedure AddPath (apath : string);
  269. begin
  270. FPaths.Add (IncludeTrailingBackslash(Apath));
  271. end;
  272. var p : integer;
  273. begin
  274. while (AValue <> '') do
  275. begin
  276. p := pos (';', AValue);
  277. if p = 0 then
  278. begin
  279. AddPath (AValue);
  280. AValue := '';
  281. end
  282. else
  283. begin
  284. AddPath (copy(AValue,1,p-1));
  285. delete (AVAlue,1,p);
  286. end;
  287. end;
  288. end;
  289. procedure TFontManager.SetExtention (AValue : string);
  290. begin
  291. if AValue <> '' then
  292. if AValue[1] <> '.' then
  293. FExtention := '.' + AValue
  294. else
  295. FExtention := AValue
  296. else
  297. AValue := '';
  298. end;
  299. function TFontManager.SearchFont (afilename:string) : string;
  300. // returns full filename of font, taking SearchPath in account
  301. var p,fn : string;
  302. r : integer;
  303. begin
  304. if (pos('.', afilename)=0) and (DefaultFontExtention<>'') then
  305. fn := afilename + DefaultFontExtention
  306. else
  307. fn := aFilename;
  308. if FileExists(fn) then
  309. result := ExpandFilename(fn)
  310. else
  311. begin
  312. p := ExtractFilepath(fn);
  313. if p = '' then
  314. begin // no path given, look in SearchPaths
  315. r := FPaths.Count;
  316. repeat
  317. dec (r);
  318. until (r < 0) or FileExists(FPaths[r]+fn);
  319. if r < 0 then
  320. raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [fn])
  321. else
  322. result := FPaths[r]+fn;
  323. end
  324. else
  325. raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [afilename]);
  326. end;
  327. end;
  328. function TFontManager.GetFontId (afilename:string; anindex:integer) : integer;
  329. begin
  330. result := FList.count-1;
  331. while (result >= 0) and
  332. ( ({$ifdef CaseSense}CompareText{$else}CompareStr{$endif}
  333. (TMgrFont(FList[anIndex]).Filename, afilename) <> 0) or
  334. (anIndex <> TMgrFont(FList[anIndex]).font^.face_index)
  335. ) do
  336. dec (result);
  337. end;
  338. function TFontManager.CreateFont (afilename:string; anindex:integer) : integer;
  339. var f : TMgrFont;
  340. begin
  341. // writeln ('creating font ',afilename,' (',anindex,')');
  342. f := TMgrFont.Create (self, afilename, anindex);
  343. result := FList.Count;
  344. Flist.Add (f);
  345. end;
  346. function TFontManager.GetFont (FontID:integer) : TMgrFont;
  347. begin
  348. result := TMgrFont(FList[FontID]);
  349. if result <> CurFont then // set last used size of the font as current size
  350. begin
  351. CurSize := result.LastSize;
  352. end;
  353. end;
  354. procedure TFontManager.GetSize (aSize, aResolution : integer);
  355. var r : integer;
  356. begin
  357. if not ( assigned(CurSize) and
  358. (CurSize^.Size = aSize) and (CurSize^.resolution = aResolution)) then
  359. begin
  360. r := CurFont.FSizes.count;
  361. repeat
  362. dec (r)
  363. until (r < 0) or ( (PMgrSize(CurFont.FSizes[r])^.size = aSize) and
  364. (PMgrSize(CurFont.FSizes[r])^.resolution = FResolution) );
  365. if r < 0 then
  366. CurSize := CreateSize (aSize,aResolution)
  367. else
  368. CurSize := PMgrSize(CurFont.FSizes[r]);
  369. CurFont.LastSize := CurSize;
  370. end;
  371. end;
  372. function TFontManager.CreateSize (aSize, aResolution : integer) : PMgrSize;
  373. begin
  374. new (result);
  375. result^.Size := aSize;
  376. result^.Resolution := aResolution;
  377. result^.Glyphs := Tlist.Create;
  378. SetPixelSize (aSize,aResolution);
  379. CurFont.FSizes.Add (result);
  380. end;
  381. procedure TFontManager.SetPixelSize (aSize, aResolution : integer);
  382. procedure CheckSize;
  383. var r : integer;
  384. begin
  385. with Curfont.Font^ do
  386. begin
  387. r := Num_fixed_sizes;
  388. repeat
  389. dec (r);
  390. until (r < 0) or
  391. ( (available_sizes^[r].height=asize) and
  392. (available_sizes^[r].width=asize) );
  393. if r >= 0 then
  394. raise FreeTypeException.CreateFmt ('Size %d not available for %s %s',
  395. [aSize, style_name, family_name]);
  396. end;
  397. end;
  398. var s : longint;
  399. Err : integer;
  400. begin
  401. with Curfont, Font^ do
  402. if (face_flags and FT_Face_Flag_Fixed_Sizes) <> 0 then
  403. begin
  404. CheckSize;
  405. Err := FT_Set_pixel_sizes (Font, aSize, aSize);
  406. if Err <> 0 then
  407. FTError (format(sErrSetPixelSize,[aSize,aResolution]), Err);
  408. end
  409. else
  410. begin
  411. s := aSize shl 6;
  412. Err := FT_Set_char_size (Font, s, s, aResolution, aResolution);
  413. if Err <> 0 then
  414. FTError (format(sErrSetCharSize,[aSize,aResolution]), Err);
  415. end;
  416. end;
  417. procedure TFontManager.MakeTransformation (angle:real; var Transformation:FT_Matrix);
  418. begin
  419. with Transformation do
  420. begin
  421. xx := round( cos(angle)*$10000);
  422. xy := round(-sin(angle)*$10000);
  423. yx := round( sin(angle)*$10000);
  424. yy := round( cos(angle)*$10000);
  425. end;
  426. end;
  427. function TFontManager.CreateGlyph (c : char) : PMgrGlyph;
  428. var e : integer;
  429. begin
  430. new (result);
  431. result^.character := c;
  432. result^.GlyphIndex := FT_Get_Char_Index (CurFont.font, ord(c));
  433. e := FT_Load_Glyph (CurFont.font, result^.GlyphIndex, FT_Load_Default);
  434. if e <> 0 then
  435. begin
  436. FTError (sErrLoadingGlyph, e);
  437. end;
  438. e := FT_Get_Glyph (Curfont.font^.glyph, result^.glyph);
  439. if e <> 0 then
  440. begin
  441. FTError (sErrLoadingGlyph, e);
  442. end;
  443. CurSize^.Glyphs.Add (result);
  444. end;
  445. function TFontManager.GetGlyph (c : char) : PMgrGlyph;
  446. var r : integer;
  447. begin
  448. With CurSize^ do
  449. begin
  450. r := Glyphs.Count;
  451. repeat
  452. dec (r)
  453. until (r < 0) or (PMgrGlyph(Glyphs[r])^.character = c);
  454. if r < 0 then
  455. result := CreateGlyph (c)
  456. else
  457. result := PMgrGlyph(Glyphs[r]);
  458. end;
  459. end;
  460. procedure TFontManager.InitMakeString (FontID, Size:integer);
  461. begin
  462. GetSize (size,Resolution);
  463. UseKerning := ((Curfont.font^.face_flags and FT_FACE_FLAG_KERNING) <> 0);
  464. end;
  465. function TFontManager.MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  466. var g : PMgrGlyph;
  467. bm : PFT_BitmapGlyph;
  468. gl : PFT_Glyph;
  469. e, prevIndex, prevx, c, r, rx : integer;
  470. pre, adv, pos, kern : FT_Vector;
  471. buf : PByteArray;
  472. reverse : boolean;
  473. trans : FT_Matrix;
  474. begin
  475. CurFont := GetFont(FontID);
  476. if (Angle = 0) or // no angle asked, or can't work with angles (not scalable)
  477. ((CurFont.Font^.face_flags and FT_FACE_FLAG_SCALABLE)=0) then
  478. result := MakeString (FontID, Text, Size)
  479. else
  480. begin
  481. InitMakeString (FontID, Size);
  482. c := length(text);
  483. result := TStringBitmaps.Create(c);
  484. if (CurRenderMode = FT_RENDER_MODE_MONO) then
  485. result.FMode := btBlackWhite
  486. else
  487. result.FMode := bt256Gray;
  488. MakeTransformation (angle, trans);
  489. prevIndex := 0;
  490. prevx := 0;
  491. pos.x := 0;
  492. pos.y := 0;
  493. pre.x := 0;
  494. pre.y := 0;
  495. for r := 0 to c-1 do
  496. begin
  497. // retrieve loaded glyph
  498. g := GetGlyph (Text[r+1]);
  499. // check kerning
  500. if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
  501. begin
  502. prevx := pre.x;
  503. FTCheck(FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern),sErrKerning);
  504. pre.x := pre.x + kern.x;
  505. end;
  506. // render the glyph
  507. Gl:=Nil;
  508. FTCheck(FT_Glyph_Copy (g^.glyph, gl),sErrMakingString1);
  509. // placing the glyph
  510. FTCheck(FT_Glyph_Transform (gl, nil, @pre),sErrMakingString2);
  511. adv := gl^.advance;
  512. // rotating the glyph
  513. FTCheck(FT_Glyph_Transform (gl, @trans, nil),sErrMakingString3);
  514. // rendering the glyph
  515. FTCheck(FT_Glyph_To_Bitmap (gl, CurRenderMode, nil, true),sErrMakingString4);
  516. // Copy what is needed to record
  517. bm := PFT_BitmapGlyph(gl);
  518. with result.Bitmaps[r]^ do
  519. begin
  520. with gl^.advance do
  521. begin
  522. advanceX := x div 64;
  523. advanceY := y div 64;
  524. end;
  525. with bm^ do
  526. begin
  527. height := bitmap.rows;
  528. width := bitmap.width;
  529. x := {(pos.x div 64)} + left; // transformed bitmap has correct x,y
  530. y := {(pos.y div 64)} - top; // not transformed has only a relative correction
  531. buf := PByteArray(bitmap.buffer);
  532. reverse := (bitmap.pitch < 0);
  533. if reverse then
  534. begin
  535. pitch := -bitmap.pitch;
  536. getmem (data, pitch*height);
  537. for rx := height-1 downto 0 do
  538. move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
  539. end
  540. else
  541. begin
  542. pitch := bitmap.pitch;
  543. rx := pitch*height;
  544. getmem (data, rx);
  545. move (buf^[0], data^[0], rx);
  546. end;
  547. end;
  548. end;
  549. // place position for next glyph
  550. with gl^.advance do
  551. begin
  552. pos.x := pos.x + (x div 1024);
  553. pos.y := pos.y + (y div 1024);
  554. end;
  555. with adv do
  556. pre.x := pre.x + (x div 1024);
  557. if prevx > pre.x then
  558. pre.x := prevx;
  559. // finish rendered glyph
  560. FT_Done_Glyph (gl);
  561. end;
  562. result.FText := Text;
  563. result.CalculateGlobals;
  564. end;
  565. end;
  566. function TFontManager.MakeString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  567. var g : PMgrGlyph;
  568. bm : PFT_BitmapGlyph;
  569. gl : PFT_Glyph;
  570. e, prevIndex, prevx, c, r, rx : integer;
  571. pos, kern : FT_Vector;
  572. buf : PByteArray;
  573. reverse : boolean;
  574. begin
  575. CurFont := GetFont(FontID);
  576. InitMakeString (FontID, Size);
  577. c := length(text);
  578. result := TStringBitmaps.Create(c);
  579. if (CurRenderMode = FT_RENDER_MODE_MONO) then
  580. result.FMode := btBlackWhite
  581. else
  582. result.FMode := bt256Gray;
  583. prevIndex := 0;
  584. prevx := 0;
  585. pos.x := 0;
  586. pos.y := 0;
  587. for r := 0 to c-1 do
  588. begin
  589. // retrieve loaded glyph
  590. g := GetGlyph (Text[r+1]);
  591. // check kerning
  592. if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
  593. begin
  594. prevx := pos.x;
  595. e := FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern);
  596. if e <> 0 then
  597. FTError (sErrKerning, e);
  598. pos.x := pos.x + kern.x;
  599. end;
  600. // render the glyph
  601. FTCheck(FT_Glyph_Copy (g^.glyph, gl),sErrMakingString1);
  602. FTCheck(FT_Glyph_To_Bitmap (gl, CurRenderMode, @pos, true),sErrMakingString4);
  603. // Copy what is needed to record
  604. bm := PFT_BitmapGlyph(gl);
  605. with result.Bitmaps[r]^ do
  606. begin
  607. with gl^.advance do
  608. begin
  609. advanceX := x shr 6;
  610. advanceY := y shr 6;
  611. end;
  612. with bm^ do
  613. begin
  614. height := bitmap.rows;
  615. width := bitmap.width;
  616. x := (pos.x shr 6) + left; // transformed bitmap has correct x,y
  617. y := (pos.y shr 6) - top; // not transformed has only a relative correction
  618. buf := PByteArray(bitmap.buffer);
  619. reverse := (bitmap.pitch < 0);
  620. if reverse then
  621. begin
  622. pitch := -bitmap.pitch;
  623. getmem (data, pitch*height);
  624. for rx := height-1 downto 0 do
  625. move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
  626. end
  627. else
  628. begin
  629. pitch := bitmap.pitch;
  630. rx := pitch*height;
  631. getmem (data, rx);
  632. move (buf^[0], data^[0], rx);
  633. end;
  634. end;
  635. end;
  636. // place position for next glyph
  637. pos.x := pos.x + (gl^.advance.x shr 10);
  638. // pos.y := pos.y + (gl^.advance.y shr 6); // for angled texts also
  639. if prevx > pos.x then
  640. pos.x := prevx;
  641. // finish rendered glyph
  642. FT_Done_Glyph (gl);
  643. end;
  644. result.FText := Text;
  645. result.CalculateGlobals;
  646. end;
  647. function TFontManager.GetString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  648. // Black and white
  649. begin
  650. CurRenderMode := FT_RENDER_MODE_MONO;
  651. result := MakeString (FontID, text, Size, angle);
  652. end;
  653. function TFontManager.GetStringGray (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
  654. // Anti Aliased gray scale
  655. begin
  656. CurRenderMode := FT_RENDER_MODE_NORMAL;
  657. result := MakeString (FontID, text, Size, angle);
  658. end;
  659. { Procedures without angle have own implementation to have better speed }
  660. function TFontManager.GetString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  661. // Black and white, following the direction of the font (left to right, top to bottom, ...)
  662. begin
  663. CurRenderMode := FT_RENDER_MODE_MONO;
  664. result := MakeString (FontID, text, Size);
  665. end;
  666. function TFontManager.GetStringGray (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
  667. // Anti Aliased gray scale, following the direction of the font (left to right, top to bottom, ...)
  668. begin
  669. CurRenderMode := FT_RENDER_MODE_NORMAL;
  670. result := MakeString (FontID, text, Size);
  671. end;
  672. function TFontManager.RequestFont (afilename:string) : integer;
  673. begin
  674. result := RequestFont (afilename,0);
  675. end;
  676. function TFontManager.RequestFont (afilename:string; anindex:integer) : integer;
  677. var s : string;
  678. begin
  679. if afilename = '' then
  680. result := -1
  681. else
  682. begin
  683. s := SearchFont (afilename);
  684. result := GetFontID (s,anindex);
  685. if result < 0 then
  686. result := CreateFont (s,anindex);
  687. end;
  688. end;
  689. function TFontManager.GetFreeTypeFont (aFontID:integer) : PFT_Face;
  690. begin
  691. result := GetFont(aFontID).font;
  692. end;
  693. { TStringBitmaps }
  694. function TStringBitmaps.GetCount : integer;
  695. begin
  696. result := FList.Count;
  697. end;
  698. function TStringBitmaps.GetBitmap (index:integer) : PFontBitmap;
  699. begin
  700. result := PFontBitmap(FList[index]);
  701. end;
  702. constructor TStringBitmaps.Create (ACount : integer);
  703. var r : integer;
  704. bm : PFontBitmap;
  705. begin
  706. inherited create;
  707. FList := Tlist.Create;
  708. FList.Capacity := ACount;
  709. for r := 0 to ACount-1 do
  710. begin
  711. new (bm);
  712. FList.Add (bm);
  713. end;
  714. end;
  715. destructor TStringBitmaps.destroy;
  716. var r : integer;
  717. bm : PFontBitmap;
  718. begin
  719. for r := 0 to Flist.count-1 do
  720. begin
  721. bm := PFontBitmap(FList[r]);
  722. freemem (bm^.data);
  723. dispose (bm);
  724. end;
  725. FList.Free;
  726. inherited;
  727. end;
  728. procedure TStringBitmaps.CalculateGlobals;
  729. var r : integer;
  730. begin
  731. if count = 0 then
  732. Exit;
  733. // check first 2 bitmaps for left side
  734. // check last 2 bitmaps for right side
  735. with BitMaps[0]^ do
  736. begin
  737. FBounds.left := x;
  738. FBounds.top := y + height;
  739. FBounds.bottom := y;
  740. end;
  741. with Bitmaps[count-1]^ do
  742. FBounds.right := x + width;
  743. if count > 1 then
  744. begin
  745. with Bitmaps[1]^ do
  746. r := x;
  747. if r < FBounds.left then
  748. FBounds.left := r;
  749. with Bitmaps[count-2]^ do
  750. r := x + width;
  751. if r > FBounds.right then
  752. FBounds.right := r;
  753. end;
  754. // check top/bottom of other bitmaps
  755. for r := 1 to count-1 do
  756. with Bitmaps[r]^ do
  757. begin
  758. if FBounds.top < y + height then
  759. FBounds.top := y + height;
  760. if FBounds.bottom > y then
  761. FBounds.bottom := y;
  762. end;
  763. end;
  764. procedure TStringBitmaps.GetBoundRect (var aRect : TRect);
  765. begin
  766. aRect := FBounds;
  767. end;
  768. {$ifdef win32}
  769. procedure SetWindowsFontPath;
  770. begin
  771. DefaultSearchPath := includetrailingbackslash(GetEnv('windir')) + 'fonts';
  772. end;
  773. {$endif}
  774. initialization
  775. {$ifdef win32}
  776. SetWindowsFontPath;
  777. {$endif}
  778. end.