freetype.pp 23 KB

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