1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4 (Public License)
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
6 // Pascal Port By: Milan Marusinec alias Milano
7 //                 milan@marusinec.sk
8 //                 http://www.aggpas.org
9 // Copyright (c) 2005-2007
10 //
11 // Permission to copy, use, modify, sell and distribute this software
12 // is granted provided this copyright notice appears in all copies.
13 // This software is provided "as is" without express or implied
14 // warranty, and with no claim as to its suitability for any purpose.
15 //
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 //          mcseemagg@yahoo.com
19 //          http://www.antigrain.com
20 //
21 // [Pascal Port History] -----------------------------------------------------
22 //
23 // 17.09.2007-Milano: Porting & Finished OK
24 // 16.09.2007-Milano: Unit port establishment
25 //
26 
27 unit
28  agg_font_freetype ;
29 
30 INTERFACE
31 
32 {$I agg_mode.inc }
33 
34 uses
35  SysUtils ,Math ,
36  agg_font_freetype_lib ,
37  agg_basics ,
38  agg_font_engine ,
39  agg_font_cache_manager ,
40  agg_trans_affine ,
41  agg_vertex_source ,
42  agg_path_storage_integer ,
43  agg_conv_curve ,
44  agg_scanline ,
45  agg_scanline_u ,
46  agg_scanline_bin ,
47  agg_rasterizer_scanline_aa ,
48  agg_renderer_scanline ,
49  agg_render_scanlines ,
50  agg_bitset_iterator ;
51 
52 { GLOBAL VARIABLES & CONSTANTS }
53 { TYPES DEFINITION }
54 type
55  face_name_ptr = ^face_name;
56  face_name = record
57    name : PChar;
58    size : unsigned;
59 
60   end;
61 
62 //-----------------------------------------------font_engine_freetype_base
63  font_engine_freetype_base = object(font_engine )
64    m_flag32 : boolean;
65 
66    m_change_stamp ,
67    m_last_error   : int;
68 
69    m_name       : PChar;
70    m_name_len   ,
71    m_face_index : unsigned;
72    m_char_map   : FT_Encoding;
73    m_signature  : face_name;
74 
75    m_height ,
76    m_width  : unsigned;
77 
78    m_hinting             ,
79    m_flip_y              ,
80    m_library_initialized : boolean;
81 
82    m_library : FT_Library_ptr;    // handle to library
83    m_faces   : FT_Face_ptr_ptr;   // A pool of font faces
84 
85    m_face_names : face_name_ptr;
86    m_num_faces  ,
87    m_max_faces  : unsigned;
88    m_cur_face   : FT_Face_ptr;    // handle to the current face object
89    m_resolution : int;
90 
91    m_glyph_rendering : glyph_rendering;
92    m_glyph_index     ,
93    m_data_size       ,
94    m_data_type       : unsigned;
95 
96    m_bounds    : agg_basics.rect;
97    m_advance_x ,
98    m_advance_y : double;
99    m_affine    : trans_affine;
100 
101    m_path16   : path_storage_int16;
102    m_path32   : path_storage_int32;
103    m_curves16 ,
104    m_curves32 : conv_curve;
105 
106    m_scanline_aa   : scanline_u8;
107    m_scanline_bin  : scanline_bin;
108    m_scanlines_aa  : scanlines_aa_type;
109    m_scanlines_bin : scanlines_bin_type;
110    m_rasterizer    : rasterizer_scanline_aa;
111 
112    constructor Construct(flag32_ : boolean; max_faces : unsigned = 32 );
113    destructor  Destruct;
114 
115   // Set font parameters
116    procedure resolution_(dpi : unsigned );
117 
load_fontnull118    function  load_font(
119               font_name : PChar; face_index : unsigned; ren_type : glyph_rendering;
120               font_mem : PChar = NIL; font_mem_size : int = 0 ) : boolean;
121 
attachnull122    function  attach(file_name : PChar ) : boolean;
123 
char_map_null124    function  char_map_ (map : FT_Encoding ) : boolean;
height_null125    function  height_   (h : double ) : boolean;
width_null126    function  width_    (w : double ) : boolean;
127    procedure hinting_  (h : boolean );
128    procedure flip_y_   (flip : boolean );
129    procedure transform_(affine : trans_affine_ptr );
130 
131   // Set Gamma
132    procedure gamma_(f : vertex_source_ptr );
133 
134   // Accessors
_last_errornull135    function  _last_error : int;
_resolutionnull136    function  _resolution : unsigned;
_namenull137    function  _name : PChar;
_num_facesnull138    function  _num_faces : unsigned;
_char_mapnull139    function  _char_map : FT_Encoding;
_heightnull140    function  _height : double;
_widthnull141    function  _width : double;
_ascendernull142    function  _ascender : double;
_descendernull143    function  _descender : double;
_hintingnull144    function  _hinting : boolean;
_flip_ynull145    function  _flip_y : boolean;
146 
147   // Interface mandatory to implement for font_cache_manager
font_signaturenull148    function  font_signature : PChar; virtual;
change_stampnull149    function  change_stamp : int; virtual;
150 
prepare_glyphnull151    function  prepare_glyph(glyph_code : unsigned ) : boolean; virtual;
152 
glyph_indexnull153    function  glyph_index : unsigned; virtual;
data_sizenull154    function  data_size : unsigned; virtual;
data_typenull155    function  data_type : unsigned; virtual;
boundsnull156    function  bounds : rect_ptr; virtual;
advance_xnull157    function  advance_x : double; virtual;
advance_ynull158    function  advance_y : double; virtual;
159 
160    procedure write_glyph_to(data : int8u_ptr ); virtual;
add_kerningnull161    function  add_kerning   (first ,second : unsigned; x ,y : double_ptr ) : boolean; virtual;
162 
flag32null163    function  flag32 : boolean; virtual;
164 
165   // private
166    procedure update_char_size;
167    procedure update_signature;
168 
find_facenull169    function  find_face(name : PChar ) : int;
170 
171   end;
172 
173 //------------------------------------------------font_engine_freetype_int16
174 // This class uses values of type int16 (10.6 format) for the vector cache.
175 // The vector cache is compact, but when rendering glyphs of height
176 // more that 200 there integer overflow can occur.
177  font_engine_freetype_int16 = object(font_engine_freetype_base )
178    constructor Construct(max_faces : unsigned = 32 );
179 
180   end;
181 
182 //------------------------------------------------font_engine_freetype_int32
183 // This class uses values of type int32 (26.6 format) for the vector cache.
184 // The vector cache is twice larger than in font_engine_freetype_int16,
185 // but it allows you to render glyphs of very large sizes.
186  font_engine_freetype_int32 = object(font_engine_freetype_base )
187    constructor Construct(max_faces : unsigned = 32 );
188 
189   end;
190 
191 { GLOBAL PROCEDURES }
192 
193 
194 IMPLEMENTATION
195 { LOCAL VARIABLES & CONSTANTS }
196 //------------------------------------------------------------------------------
197 //
198 // This code implements the AUTODIN II polynomial
199 // The variable corresponding to the macro argument "crc" should
200 // be an unsigned long.
201 // Oroginal code  by Spencer Garrett <srg@quick.com>
202 //
203 // generated using the AUTODIN II polynomial
204 //   x^32 + x^26 + x^23 + x^22 + x^16 +
205 //   x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
206 //
207 //------------------------------------------------------------------------------
208 const
209  crc32tab : array[0..255 ] of unsigned = (
210   $00000000, $77073096, $ee0e612c, $990951ba,
211   $076dc419, $706af48f, $e963a535, $9e6495a3,
212   $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988,
213   $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
214   $1db71064, $6ab020f2, $f3b97148, $84be41de,
215   $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
216   $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec,
217   $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
218   $3b6e20c8, $4c69105e, $d56041e4, $a2677172,
219   $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
220   $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940,
221   $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
222   $26d930ac, $51de003a, $c8d75180, $bfd06116,
223   $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
224   $2802b89e, $5f058808, $c60cd9b2, $b10be924,
225   $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
226   $76dc4190, $01db7106, $98d220bc, $efd5102a,
227   $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
228   $7807c9a2, $0f00f934, $9609a88e, $e10e9818,
229   $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
230   $6b6b51f4, $1c6c6162, $856530d8, $f262004e,
231   $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
232   $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c,
233   $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
234   $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2,
235   $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
236   $4369e96a, $346ed9fc, $ad678846, $da60b8d0,
237   $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
238   $5005713c, $270241aa, $be0b1010, $c90c2086,
239   $5768b525, $206f85b3, $b966d409, $ce61e49f,
240   $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4,
241   $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
242   $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a,
243   $ead54739, $9dd277af, $04db2615, $73dc1683,
244   $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8,
245   $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
246   $f00f9344, $8708a3d2, $1e01f268, $6906c2fe,
247   $f762575d, $806567cb, $196c3671, $6e6b06e7,
248   $fed41b76, $89d32be0, $10da7a5a, $67dd4acc,
249   $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
250   $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252,
251   $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
252   $d80d2bda, $af0a1b4c, $36034af6, $41047a60,
253   $df60efc3, $a867df55, $316e8eef, $4669be79,
254   $cb61b38c, $bc66831a, $256fd2a0, $5268e236,
255   $cc0c7795, $bb0b4703, $220216b9, $5505262f,
256   $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04,
257   $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
258   $9b64c2b0, $ec63f226, $756aa39c, $026d930a,
259   $9c0906a9, $eb0e363f, $72076785, $05005713,
260   $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38,
261   $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
262   $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e,
263   $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
264   $88085ae6, $ff0f6a70, $66063bca, $11010b5c,
265   $8f659eff, $f862ae69, $616bffd3, $166ccf45,
266   $a00ae278, $d70dd2ee, $4e048354, $3903b3c2,
267   $a7672661, $d06016f7, $4969474d, $3e6e77db,
268   $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0,
269   $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
270   $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6,
271   $bad03605, $cdd70693, $54de5729, $23d967bf,
272   $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94,
273   $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d );
274 
275 { UNIT IMPLEMENTATION }
276 { calc_crc32 }
calc_crc32null277 function calc_crc32(buf : int8u_ptr; size : unsigned ) : unsigned;
278 var
279  crc ,len ,nr : unsigned;
280 
281  p : int8u_ptr;
282 
283 begin
284  crc:=unsigned(not 0 );
285  len:=0;
286  nr :=size;
287  len:=len + nr;
288  p  :=buf;
289 
290  while nr <> 0 do
291   begin
292    dec(nr );
293 
294    crc:=(crc shr 8 ) xor crc32tab[(crc xor p^ ) and $ff ];
295 
296    inc(ptrcomp(p ) ,sizeof(int8u ) );
297 
298   end;
299 
300  result:=not crc;
301 
302 end;
303 
304 { dbl_to_plain_fx }
dbl_to_plain_fxnull305 function dbl_to_plain_fx(d : double ) : int;
306 begin
307  result:=Trunc(d * 65536.0 )
308 
309 end;
310 
311 { int26p6_to_dbl }
int26p6_to_dblnull312 function int26p6_to_dbl(p : int ) : double;
313 begin
314  result:=p / 64.0;
315 
316 end;
317 
318 { dbl_to_int26p6 }
dbl_to_int26p6null319 function dbl_to_int26p6(p : double ) : int;
320 begin
321  result:=Trunc(p * 64.0 + 0.5 );
322 
323 end;
324 
325 { decompose_ft_outline }
decompose_ft_outlinenull326 function decompose_ft_outline(
327           outline : FT_Outline_ptr;
328           flip_y : boolean;
329           mtx : trans_affine_ptr;
330           path : path_storage_integer_ptr ) : boolean;
331 var
332  v_last ,v_control ,v_start ,vec ,v_middle ,vec1 ,vec2 : FT_Vector;
333 
334  x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double;
335 
336  point ,limit : FT_Vector_ptr;
337 
338  tags : char_ptr;
339 
340  n     ,      // index of contour in outline
341  first ,      // index of first point in contour
342  last  : int; // index of last point in contour
343 
344  tag : char;  // current point's state
345 
346 label
347  Do_Conic ,Close ;
348 
349 begin
350  first:=0;
351  n    :=0;
352 
353  while n < outline.n_contours do
354   begin
355    last :=FT_Short_ptr(ptrcomp(outline.contours ) + n * sizeof(FT_Short ) )^;
356    limit:=FT_Vector_ptr(ptrcomp(outline.points ) + last * sizeof(FT_Vector ) );
357 
358    v_start:=FT_Vector_ptr(ptrcomp(outline.points ) + first * sizeof(FT_Vector) )^;
359    v_last :=FT_Vector_ptr(ptrcomp(outline.points ) + last * sizeof(FT_Vector) )^;
360 
361    v_control:=v_start;
362 
363    point:=FT_Vector_ptr(ptrcomp(outline.points ) + first * sizeof(FT_Vector ) );
364    tags :=char_ptr     (ptrcomp(outline.tags ) + first * sizeof(char ) );
365    tag  :=FT_CURVE_TAG (tags^ );
366 
367   // A contour cannot start with a cubic control point!
368    if tag = char(FT_CURVE_TAG_CUBIC ) then
369     begin
370      result:=false;
371 
372      exit;
373 
374     end;
375 
376   // check first point to determine origin
377    if tag = char(FT_CURVE_TAG_CONIC ) then
378     begin
379     // first point is conic control. Yes, this happens.
380      if FT_CURVE_TAG(char_ptr(ptrcomp(outline.tags ) + last )^ ) = char(FT_CURVE_TAG_ON ) then
381       begin
382       // start at last point if it is on the curve
383        v_start:=v_last;
384 
385        dec(limit );
386 
387       end
388      else
389       begin
390       // if both first and last points are conic,
391       // start at their middle and record its position
392       // for closure
393        v_start.x:=(v_start.x + v_last.x ) div 2;
394        v_start.y:=(v_start.y + v_last.y ) div 2;
395 
396        v_last:=v_start;
397 
398       end;
399 
400      dec(ptrcomp(point ) ,sizeof(FT_Vector ) );
401      dec(ptrcomp(tags ) );
402 
403     end;
404 
405    x1:=int26p6_to_dbl(v_start.x );
406    y1:=int26p6_to_dbl(v_start.y );
407 
408    if flip_y then
409     y1:=-y1;
410 
411    mtx.transform(mtx ,@x1 ,@y1 );
412    path.move_to (dbl_to_int26p6(x1 ) ,dbl_to_int26p6(y1 ) );
413 
414    while ptrcomp(point ) < ptrcomp(limit ) do
415     begin
416      inc(ptrcomp(point ) ,sizeof(FT_Vector ) );
417      inc(ptrcomp(tags ) );
418 
419      tag:=FT_CURVE_TAG(tags^ );
420 
421      case tag of
422      // emit a single line_to
423       char(FT_CURVE_TAG_ON ) :
424        begin
425         x1:=int26p6_to_dbl(point.x );
426         y1:=int26p6_to_dbl(point.y );
427 
428         if flip_y then
429          y1:=-y1;
430 
431         mtx.transform(mtx ,@x1 ,@y1 );
432         path.line_to (dbl_to_int26p6(x1 ) ,dbl_to_int26p6(y1 ) );
433 
434         continue;
435 
436        end;
437 
438      // consume conic arcs
439       char(FT_CURVE_TAG_CONIC ) :
440        begin
441         v_control.x:=point.x;
442         v_control.y:=point.y;
443 
444        Do_Conic:
445         if ptrcomp(point ) < ptrcomp(limit ) then
446          begin
447           inc(ptrcomp(point ) ,sizeof(FT_Vector ) );
448           inc(ptrcomp(tags ) );
449 
450           tag:=FT_CURVE_TAG(tags^ );
451 
452           vec.x:=point.x;
453           vec.y:=point.y;
454 
455           if tag = char(FT_CURVE_TAG_ON ) then
456            begin
457             x1:=int26p6_to_dbl(v_control.x );
458             y1:=int26p6_to_dbl(v_control.y );
459             x2:=int26p6_to_dbl(vec.x );
460             y2:=int26p6_to_dbl(vec.y );
461 
462             if flip_y then
463              begin
464               y1:=-y1;
465               y2:=-y2;
466 
467              end;
468 
469             mtx.transform(mtx ,@x1 ,@y1 );
470             mtx.transform(mtx ,@x2 ,@y2 );
471 
472             path.curve3(
473              dbl_to_int26p6(x1 ) ,
474              dbl_to_int26p6(y1 ) ,
475              dbl_to_int26p6(x2 ) ,
476              dbl_to_int26p6(y2 ) );
477 
478             continue;
479 
480            end;
481 
482           if tag <> char(FT_CURVE_TAG_CONIC ) then
483            begin
484             result:=false;
485 
486             exit;
487 
488            end;
489 
490           v_middle.x:=(v_control.x + vec.x ) div 2;
491           v_middle.y:=(v_control.y + vec.y ) div 2;
492 
493           x1:=int26p6_to_dbl(v_control.x );
494           y1:=int26p6_to_dbl(v_control.y );
495           x2:=int26p6_to_dbl(v_middle.x );
496           y2:=int26p6_to_dbl(v_middle.y );
497 
498           if flip_y then
499            begin
500             y1:=-y1;
501             y2:=-y2;
502 
503            end;
504 
505           mtx.transform(mtx ,@x1 ,@y1 );
506           mtx.transform(mtx ,@x2 ,@y2 );
507 
508           path.curve3(
509            dbl_to_int26p6(x1 ) ,
510            dbl_to_int26p6(y1 ) ,
511            dbl_to_int26p6(x2 ) ,
512            dbl_to_int26p6(y2 ) );
513 
514           v_control:=vec;
515 
516           goto Do_Conic;
517 
518          end;
519 
520         x1:=int26p6_to_dbl(v_control.x );
521         y1:=int26p6_to_dbl(v_control.y );
522         x2:=int26p6_to_dbl(v_start.x );
523         y2:=int26p6_to_dbl(v_start.y );
524 
525         if flip_y then
526          begin
527           y1:=-y1;
528           y2:=-y2;
529 
530          end;
531 
532         mtx.transform(mtx ,@x1 ,@y1 );
533         mtx.transform(mtx ,@x2 ,@y2 );
534 
535         path.curve3(
536          dbl_to_int26p6(x1 ) ,
537          dbl_to_int26p6(y1 ) ,
538          dbl_to_int26p6(x2 ) ,
539          dbl_to_int26p6(y2 ) );
540 
541         goto Close;
542 
543        end;
544 
545      // FT_CURVE_TAG_CUBIC
546       else
547        begin
548         if (ptrcomp(point ) + sizeof(FT_Vector ) > ptrcomp(limit ) ) or
549            (FT_CURVE_TAG(char_ptr(ptrcomp(tags ) + 1 )^ ) <> char(FT_CURVE_TAG_CUBIC ) ) then
550          begin
551           result:=false;
552 
553           exit;
554 
555          end;
556 
557         vec1.x:=point.x;
558         vec1.y:=point.y;
559         vec2.x:=FT_Vector_ptr(ptrcomp(point ) + sizeof(FT_Vector ) ).x;
560         vec2.y:=FT_Vector_ptr(ptrcomp(point ) + sizeof(FT_Vector ) ).y;
561 
562         inc(ptrcomp(point ) ,2 * sizeof(FT_Vector ) );
563         inc(ptrcomp(tags ) ,2 );
564 
565         if ptrcomp(point ) <= ptrcomp(limit ) then
566          begin
567           vec.x:=point.x;
568           vec.y:=point.y;
569 
570           x1:=int26p6_to_dbl(vec1.x );
571           y1:=int26p6_to_dbl(vec1.y );
572           x2:=int26p6_to_dbl(vec2.x );
573           y2:=int26p6_to_dbl(vec2.y );
574           x3:=int26p6_to_dbl(vec.x );
575           y3:=int26p6_to_dbl(vec.y );
576 
577           if flip_y then
578            begin
579             y1:=-y1;
580             y2:=-y2;
581             y3:=-y3;
582 
583            end;
584 
585           mtx.transform(mtx ,@x1 ,@y1 );
586           mtx.transform(mtx ,@x2 ,@y2 );
587           mtx.transform(mtx ,@x3 ,@y3 );
588 
589           path.curve4(
590            dbl_to_int26p6(x1 ) ,
591            dbl_to_int26p6(y1 ) ,
592            dbl_to_int26p6(x2 ) ,
593            dbl_to_int26p6(y2 ) ,
594            dbl_to_int26p6(x3 ) ,
595            dbl_to_int26p6(y3 ) );
596 
597           continue;
598 
599          end;
600 
601         x1:=int26p6_to_dbl(vec1.x );
602         y1:=int26p6_to_dbl(vec1.y );
603         x2:=int26p6_to_dbl(vec2.x );
604         y2:=int26p6_to_dbl(vec2.y );
605         x3:=int26p6_to_dbl(v_start.x );
606         y3:=int26p6_to_dbl(v_start.y );
607 
608         if flip_y then
609          begin
610           y1:=-y1;
611           y2:=-y2;
612           y3:=-y3;
613 
614          end;
615 
616         mtx.transform(mtx ,@x1 ,@y1 );
617         mtx.transform(mtx ,@x2 ,@y2 );
618         mtx.transform(mtx ,@x3 ,@y3 );
619 
620         path.curve4(
621          dbl_to_int26p6(x1) ,
622          dbl_to_int26p6(y1) ,
623          dbl_to_int26p6(x2) ,
624          dbl_to_int26p6(y2) ,
625          dbl_to_int26p6(x3) ,
626          dbl_to_int26p6(y3) );
627 
628         goto Close;
629 
630        end;
631 
632      end;
633 
634     end;
635 
636    path.close_polygon;
637 
638   Close:
639    first:=last + 1;
640 
641    inc(n );
642 
643   end;
644 
645  result:=true;
646 
647 end;
648 
649 { decompose_ft_bitmap_mono }
650 procedure decompose_ft_bitmap_mono(
651            bitmap : FT_Bitmap_ptr;
652            x ,y : int;
653            flip_y : boolean;
654            sl : scanline_ptr;
655            storage : renderer_scanline_ptr );
656 var
657  i ,pitch ,j : int;
658 
659  buf  : int8u_ptr;
660  bits : bitset_iterator;
661 
662 begin
663  buf  :=int8u_ptr(bitmap.buffer );
664  pitch:=bitmap.pitch;
665 
666  sl.reset       (x ,x + bitmap.width );
667  storage.prepare(bitmap.width + 2 );
668 
669  if flip_y then
670   begin
671    inc(ptrcomp(buf ) ,bitmap.pitch * (bitmap.rows - 1 ) );
672    inc(y ,bitmap.rows );
673 
674    pitch:=-pitch;
675 
676   end;
677 
678  i:=0;
679 
680  while i < bitmap.rows do
681   begin
682    sl.reset_spans;
683 
684    bits.Construct(buf ,0 );
685 
686    j:=0;
687 
688    while j < bitmap.width do
689     begin
690      if bits.bit <> 0 then
691       sl.add_cell(x + j ,cover_full );
692 
693      bits.inc_operator;
694 
695      inc(j );
696 
697     end;
698 
699    inc(ptrcomp(buf ) ,pitch * sizeof(int8u ) );
700 
701    if sl.num_spans <> 0 then
702     begin
703      sl.finalize   (y - i - 1 );
704      storage.render(sl );
705 
706     end;
707 
708    inc(i );
709 
710   end;
711 
712 end;
713 
714 { decompose_ft_bitmap_gray8 }
715 procedure decompose_ft_bitmap_gray8(
716            bitmap : FT_Bitmap_ptr;
717            x ,y : int;
718            flip_y : boolean;
719            ras : rasterizer_scanline_aa_ptr;
720            sl : scanline_ptr;
721            storage : renderer_scanline_ptr );
722 var
723  i ,j ,pitch : int;
724 
725  buf ,p : int8u_ptr;
726 
727 begin
728  buf  :=int8u_ptr(bitmap.buffer );
729  pitch:=bitmap.pitch;
730 
731  sl.reset       (x ,x + bitmap.width );
732  storage.prepare(bitmap.width + 2 );
733 
734  if flip_y then
735   begin
736    inc(ptrcomp(buf ) ,bitmap.pitch * (bitmap.rows - 1 ) );
737    inc(y ,bitmap.rows );
738 
739    pitch:=-pitch;
740 
741   end;
742 
743  i:=0;
744 
745  while i < bitmap.rows do
746   begin
747    sl.reset_spans;
748 
749    p:=buf;
750    j:=0;
751 
752    while j < bitmap.width do
753     begin
754      if p^ <> 0 then
755       sl.add_cell(x + j ,ras.apply_gamma(p^ ) );
756 
757      inc(ptrcomp(p ) ,sizeof(int8u ) );
758      inc(j );
759 
760     end;
761 
762    inc(ptrcomp(buf ) ,pitch * sizeof(int8u ) );
763 
764    if sl.num_spans <> 0 then
765     begin
766      sl.finalize   (y - i - 1 );
767      storage.render(sl );
768 
769     end;
770 
771    inc(i );
772 
773   end;
774 
775 end;
776 
777 { CONSTRUCT }
778 constructor font_engine_freetype_base.Construct(flag32_ : boolean; max_faces : unsigned = 32 );
779 begin
780  m_flag32:=flag32_;
781 
782  m_change_stamp:=0;
783  m_last_error  :=0;
784 
785  m_name      :=NIL;
786  m_name_len  :=256 - 16 - 1;
787  m_face_index:=0;
788 
789  m_char_map:=FT_ENCODING_NONE;
790 
791  m_signature.size:=256 + 256 - 16;
792 
793  agg_getmem(pointer(m_signature.name ) ,m_signature.size );
794 
795  m_height :=0;
796  m_width  :=0;
797  m_hinting:=true;
798  m_flip_y :=false;
799 
800  m_library_initialized:=false;
801 
802  m_library:=NIL;
803 
804  agg_getmem(pointer(m_faces ) ,max_faces * sizeof(FT_Face_ptr ) );
805  agg_getmem(pointer(m_face_names ) ,max_faces * sizeof(face_name ) );
806 
807  m_num_faces :=0;
808  m_max_faces :=max_faces;
809  m_cur_face  :=NIL;
810  m_resolution:=0;
811 
812  m_glyph_rendering:=glyph_ren_native_gray8;
813  m_glyph_index    :=0;
814  m_data_size      :=0;
815  m_data_type      :=glyph_data_invalid;
816 
817  m_bounds.Construct(1 ,1 ,0 ,0 );
818 
819  m_advance_x:=0.0;
820  m_advance_y:=0.0;
821 
822  m_affine.Construct;
823 
824  m_path16.Construct;
825  m_path32.Construct;
826  m_curves16.Construct(@m_path16 );
827  m_curves32.Construct(@m_path32 );
828  m_scanline_aa.Construct;
829  m_scanline_bin.Construct;
830  m_scanlines_aa.Construct;
831  m_scanlines_bin.Construct;
832  m_rasterizer.Construct;
833 
834  m_curves16.approximation_scale_(4.0 );
835  m_curves32.approximation_scale_(4.0 );
836 
837  m_last_error:=FT_Init_FreeType(m_library );
838 
839  if m_last_error = 0 then
840   m_library_initialized:=true;
841 
842 end;
843 
844 { DESTRUCT }
845 destructor font_engine_freetype_base.Destruct;
846 var
847  i : unsigned;
848  n : face_name_ptr;
849 
850 begin
851  i:=0;
852  n:=m_face_names;
853 
854  while i < m_num_faces do
855   begin
856    agg_freemem (pointer(n.name ) ,n.size );
857    FT_Done_Face(FT_Face_ptr_ptr(ptrcomp(m_faces ) + i * sizeof(FT_Face_ptr ) )^ );
858 
859    inc(ptrcomp(n ) ,sizeof(face_name ) );
860    inc(i );
861 
862   end;
863 
864  agg_freemem(pointer(m_face_names ) ,m_max_faces * sizeof(face_name ) );
865  agg_freemem(pointer(m_faces ) ,m_max_faces * sizeof(FT_Face_ptr ) );
866  agg_freemem(pointer(m_signature.name ) ,m_signature.size );
867 
868  if m_library_initialized then
869   FT_Done_FreeType(m_library );
870 
871  m_path16.Destruct;
872  m_path32.Destruct;
873  m_curves16.Destruct;
874  m_curves32.Destruct;
875  m_scanline_aa.Destruct;
876  m_scanline_bin.Destruct;
877  m_scanlines_aa.Destruct;
878  m_scanlines_bin.Destruct;
879  m_rasterizer.Destruct;
880 
881 end;
882 
883 { RESOLUTION_ }
884 procedure font_engine_freetype_base.resolution_(dpi : unsigned );
885 begin
886  m_resolution:=dpi;
887 
888  update_char_size;
889 
890 end;
891 
892 { LOAD_FONT }
893 function font_engine_freetype_base.load_font(
894           font_name : PChar; face_index : unsigned; ren_type : glyph_rendering;
895           font_mem : PChar = NIL; font_mem_size : int = 0 ) : boolean;
896 var
897  idx : int;
898 
899 begin
900  result:=false;
901 
902  if m_library_initialized then
903   begin
904    m_last_error:=0;
905 
906    idx:=find_face(font_name );
907 
908    if idx >= 0 then
909    begin
910      m_cur_face:=FT_Face_ptr_ptr(ptrcomp(m_faces ) + idx * sizeof(FT_Face_ptr ) )^;
911      m_name    :=PChar(face_name_ptr(ptrcomp(m_face_names ) + idx * sizeof(face_name ) ).name );
912 
913    end
914    else
915    begin
916      if m_num_faces >= m_max_faces then
917       begin
918        agg_freemem (pointer(m_face_names.name ) ,m_face_names.size );
919        FT_Done_Face(m_faces^ );
920 
921        move(
922         FT_Face_ptr_ptr(ptrcomp(m_faces ) + sizeof(FT_Face_ptr ) )^ ,
923         m_faces^ ,
924         (m_max_faces - 1 ) * sizeof(FT_Face_ptr ) );
925 
926        move(
927         face_name_ptr(ptrcomp(m_face_names ) + sizeof(face_name ) )^ ,
928         m_face_names^ ,
929         (m_max_faces - 1 ) * sizeof(face_name ) );
930 
931        dec(m_num_faces );
932 
933       end;
934 
935      if (font_mem <> NIL ) and
936         (font_mem_size > 0 ) then
937       m_last_error:=
938        FT_New_Memory_Face(
939         m_library ,
940         FT_Byte_ptr(font_mem ) ,
941         font_mem_size ,
942         face_index ,
943         FT_Face_ptr_ptr(ptrcomp(m_faces ) + m_num_faces * sizeof(FT_Face_ptr ) )^ )
944      else
945       m_last_error:=
946        FT_New_Face(
947         m_library ,
948         font_name ,
949         face_index ,
950         FT_Face_ptr_ptr(ptrcomp(m_faces ) + m_num_faces * sizeof(FT_Face_ptr ) )^ );
951 
952      if m_last_error = 0 then
953       begin
954        face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).size:=
955         StrLen(font_name ) + 1;
956 
957        agg_getmem(
958         pointer(face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).name ) ,
959         face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).size );
960 
961        StrCopy(
962         PChar(face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).name ) ,
963         font_name );
964 
965        m_cur_face:=FT_Face_ptr_ptr(ptrcomp(m_faces ) + m_num_faces * sizeof(FT_Face_ptr ) )^;
966        m_name    :=PChar(face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).name );
967 
968        inc(m_num_faces );
969 
970       end
971      else
972       begin
973        PChar(face_name_ptr(ptrcomp(m_face_names ) + m_num_faces * sizeof(face_name ) ).name ):=NIL;
974 
975        m_cur_face:=NIL;
976        m_name    :=NIL;
977 
978       end;
979 
980    end;
981 
982    if m_last_error = 0 then
983     begin
984      result:=true;
985 
986      case ren_type of
987       glyph_ren_native_mono :
988        m_glyph_rendering:=glyph_ren_native_mono;
989 
990       glyph_ren_native_gray8 :
991        m_glyph_rendering:=glyph_ren_native_gray8;
992 
993       glyph_ren_outline :
994        if FT_IS_SCALABLE(m_cur_face ) then
995         m_glyph_rendering:=glyph_ren_outline
996        else
997         m_glyph_rendering:=glyph_ren_native_gray8;
998 
999       glyph_ren_agg_mono :
1000        if FT_IS_SCALABLE(m_cur_face ) then
1001         m_glyph_rendering:=glyph_ren_agg_mono
1002        else
1003         m_glyph_rendering:=glyph_ren_native_mono;
1004 
1005       glyph_ren_agg_gray8 :
1006        if FT_IS_SCALABLE(m_cur_face ) then
1007         m_glyph_rendering:=glyph_ren_agg_gray8
1008        else
1009         m_glyph_rendering:=glyph_ren_native_gray8;
1010 
1011      end;
1012 
1013      update_signature;
1014 
1015     end;
1016 
1017   end;
1018 
1019 end;
1020 
1021 { ATTACH }
1022 function font_engine_freetype_base.attach(file_name : PChar ) : boolean;
1023 begin
1024  result:=false;
1025 
1026  if m_cur_face <> NIL then
1027   begin
1028    m_last_error:=FT_Attach_File(m_cur_face ,file_name );
1029 
1030    result:=m_last_error = 0;
1031 
1032   end;
1033 
1034 end;
1035 
1036 { CHAR_MAP_ }
1037 function font_engine_freetype_base.char_map_(map : FT_Encoding ) : boolean;
1038 begin
1039  result:=false;
1040 
1041  if m_cur_face <> NIL then
1042   begin
1043    m_last_error:=FT_Select_Charmap(m_cur_face ,map );
1044 
1045    if m_last_error = 0 then
1046     begin
1047      m_char_map:=map;
1048 
1049      update_signature;
1050 
1051      result:=true;
1052 
1053     end;
1054 
1055   end;
1056 
1057 end;
1058 
1059 { HEIGHT_ }
1060 function font_engine_freetype_base.height_(h : double ) : boolean;
1061 begin
1062  result  :=false;
1063  m_height:=Trunc(h * 64.0 );
1064 
1065  if m_cur_face <> NIL then
1066   begin
1067    update_char_size;
1068 
1069    result:=true;
1070 
1071   end;
1072 
1073 end;
1074 
1075 { WIDTH_ }
1076 function font_engine_freetype_base.width_(w : double ) : boolean;
1077 begin
1078  result :=false;
1079  m_width:=Trunc(w * 64.0 );
1080 
1081  if m_cur_face <> NIL then
1082   begin
1083    update_char_size;
1084 
1085    result:=true;
1086 
1087   end;
1088 
1089 end;
1090 
1091 { HINTING_ }
1092 procedure font_engine_freetype_base.hinting_(h : boolean );
1093 begin
1094  m_hinting:=h;
1095 
1096  if m_cur_face <> NIL then
1097   update_signature;
1098 
1099 end;
1100 
1101 { FLIP_Y_ }
1102 procedure font_engine_freetype_base.flip_y_(flip : boolean );
1103 begin
1104  m_flip_y:=flip;
1105 
1106  if m_cur_face <> NIL then
1107   update_signature;
1108 
1109 end;
1110 
1111 { TRANSFORM_ }
1112 procedure font_engine_freetype_base.transform_(affine : trans_affine_ptr );
1113 begin
1114  m_affine.assign_all(affine );
1115 
1116  if m_cur_face <> NIL then
1117   update_signature;
1118 
1119 end;
1120 
1121 { GAMMA_ }
1122 procedure font_engine_freetype_base.gamma_(f : vertex_source_ptr );
1123 begin
1124  m_rasterizer.gamma(f );
1125 
1126 end;
1127 
1128 { LAST_ERROR_ }
1129 function font_engine_freetype_base._last_error : int;
1130 begin
1131  result:=m_last_error;
1132 
1133 end;
1134 
1135 { _RESOLUTION }
1136 function font_engine_freetype_base._resolution : unsigned;
1137 begin
1138  result:=m_resolution;
1139 
1140 end;
1141 
1142 { _NAME }
1143 function font_engine_freetype_base._name : PChar;
1144 begin
1145  result:=m_name;
1146 
1147 end;
1148 
1149 { _NUM_FACES }
1150 function font_engine_freetype_base._num_faces : unsigned;
1151 begin
1152  if m_cur_face <> NIL then
1153   result:=m_cur_face.num_faces
1154  else
1155   result:=0;
1156 
1157 end;
1158 
1159 { _CHAR_MAP }
1160 function font_engine_freetype_base._char_map : FT_Encoding;
1161 begin
1162  result:=m_char_map;
1163 
1164 end;
1165 
1166 { _HEIGHT }
1167 function font_engine_freetype_base._height : double;
1168 begin
1169  result:=m_height / 64.0;
1170 
1171 end;
1172 
1173 { _WIDTH }
1174 function font_engine_freetype_base._width : double;
1175 begin
1176  result:=m_width / 64.0;
1177 
1178 end;
1179 
1180 { _ASCENDER }
1181 function font_engine_freetype_base._ascender : double;
1182 begin
1183  if m_cur_face <> NIL then
1184   result:=m_cur_face.ascender * _height / m_cur_face.height
1185  else
1186   result:=0.0;
1187 
1188 end;
1189 
1190 { _DESCENDER }
1191 function font_engine_freetype_base._descender : double;
1192 begin
1193  if m_cur_face <> NIL then
1194   result:=m_cur_face.descender * _height / m_cur_face.height
1195  else
1196   result:=0.0;
1197 
1198 end;
1199 
1200 { _HINTING }
1201 function font_engine_freetype_base._hinting : boolean;
1202 begin
1203  result:=m_hinting;
1204 
1205 end;
1206 
1207 { _FLIP_Y }
1208 function font_engine_freetype_base._flip_y : boolean;
1209 begin
1210  result:=m_flip_y;
1211 
1212 end;
1213 
1214 { FONT_SIGNATURE }
1215 function font_engine_freetype_base.font_signature : PChar;
1216 begin
1217  result:=PChar(m_signature.name );
1218 
1219 end;
1220 
1221 { CHANGE_STAMP }
1222 function font_engine_freetype_base.change_stamp : int;
1223 begin
1224  result:=m_change_stamp;
1225 
1226 end;
1227 
1228 { PREPARE_GLYPH }
1229 function font_engine_freetype_base.prepare_glyph(glyph_code : unsigned ) : boolean;
1230 var
1231  fl : int;
1232 
1233  bnd : rect_d;
1234 
1235 begin
1236  result:=false;
1237 
1238  m_glyph_index:=FT_Get_Char_Index(m_cur_face ,glyph_code );
1239 
1240  if m_hinting then
1241   m_last_error:=FT_Load_Glyph(m_cur_face ,m_glyph_index ,FT_LOAD_DEFAULT {FT_LOAD_FORCE_AUTOHINT} )
1242  else
1243   m_last_error:=FT_Load_Glyph(m_cur_face ,m_glyph_index ,FT_LOAD_NO_HINTING );
1244 
1245  if m_last_error = 0 then
1246   case m_glyph_rendering of
1247    glyph_ren_native_mono :
1248     begin
1249      m_last_error:=FT_Render_Glyph(m_cur_face.glyph ,FT_RENDER_MODE_MONO );
1250 
1251      if m_last_error = 0 then
1252       begin
1253        if m_flip_y then
1254         fl:=-m_cur_face.glyph.bitmap_top
1255        else
1256         fl:=m_cur_face.glyph.bitmap_top;
1257 
1258        decompose_ft_bitmap_mono(
1259         @m_cur_face.glyph.bitmap ,
1260         m_cur_face.glyph.bitmap_left ,
1261         fl ,
1262         m_flip_y ,
1263         @m_scanline_bin ,
1264         @m_scanlines_bin );
1265 
1266        m_bounds.x1:=m_scanlines_bin._min_x;
1267        m_bounds.y1:=m_scanlines_bin._min_y;
1268        m_bounds.x2:=m_scanlines_bin._max_x;
1269        m_bounds.y2:=m_scanlines_bin._max_y;
1270        m_data_size:=m_scanlines_bin.byte_size;
1271        m_data_type:=glyph_data_mono;
1272        m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1273        m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1274 
1275        result:=true;
1276 
1277       end;
1278 
1279     end;
1280 
1281    glyph_ren_native_gray8 :
1282     begin
1283      m_last_error:=FT_Render_Glyph(m_cur_face.glyph ,FT_RENDER_MODE_NORMAL );
1284 
1285      if m_last_error = 0 then
1286       begin
1287        if m_flip_y then
1288         fl:=-m_cur_face.glyph.bitmap_top
1289        else
1290         fl:=m_cur_face.glyph.bitmap_top;
1291 
1292        decompose_ft_bitmap_gray8(
1293         @m_cur_face.glyph.bitmap ,
1294         m_cur_face.glyph.bitmap_left ,
1295         fl ,
1296         m_flip_y ,
1297         @m_rasterizer ,
1298         @m_scanline_aa ,
1299         @m_scanlines_aa );
1300 
1301        m_bounds.x1:=m_scanlines_aa._min_x;
1302        m_bounds.y1:=m_scanlines_aa._min_y;
1303        m_bounds.x2:=m_scanlines_aa._max_x;
1304        m_bounds.y2:=m_scanlines_aa._max_y;
1305        m_data_size:=m_scanlines_aa.byte_size;
1306        m_data_type:=glyph_data_gray8;
1307        m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1308        m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1309 
1310        result:=true;
1311 
1312       end;
1313 
1314     end;
1315 
1316    glyph_ren_outline :
1317     if m_last_error = 0 then
1318      if m_flag32 then
1319       begin
1320        m_path32.remove_all;
1321 
1322        if decompose_ft_outline(
1323            @m_cur_face.glyph.outline ,
1324            m_flip_y ,
1325            @m_affine ,
1326            @m_path32 ) then
1327         begin
1328          bnd:=m_path32.bounding_rect;
1329 
1330          m_data_size:=m_path32.byte_size;
1331          m_data_type:=glyph_data_outline;
1332          m_bounds.x1:=Floor(bnd.x1 );
1333          m_bounds.y1:=Floor(bnd.y1 );
1334          m_bounds.x2:=Ceil(bnd.x2 );
1335          m_bounds.y2:=Ceil(bnd.y2 );
1336          m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1337          m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1338 
1339          m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
1340 
1341          result:=true;
1342 
1343         end;
1344 
1345       end
1346      else
1347       begin
1348        m_path16.remove_all;
1349 
1350        if decompose_ft_outline(
1351            @m_cur_face.glyph.outline ,
1352            m_flip_y ,
1353            @m_affine ,
1354            @m_path16 ) then
1355         begin
1356          bnd:=m_path16.bounding_rect;
1357 
1358          m_data_size:=m_path16.byte_size;
1359          m_data_type:=glyph_data_outline;
1360          m_bounds.x1:=Floor(bnd.x1 );
1361          m_bounds.y1:=Floor(bnd.y1 );
1362          m_bounds.x2:=Ceil(bnd.x2 );
1363          m_bounds.y2:=Ceil(bnd.y2 );
1364          m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1365          m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1366 
1367          m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
1368 
1369          result:=true;
1370 
1371         end;
1372 
1373       end;
1374 
1375    glyph_ren_agg_mono :
1376     if m_last_error = 0 then
1377      begin
1378       m_rasterizer.reset;
1379 
1380       if m_flag32 then
1381        begin
1382         m_path32.remove_all;
1383 
1384         decompose_ft_outline(
1385          @m_cur_face.glyph.outline ,
1386          m_flip_y ,
1387          @m_affine ,
1388          @m_path32 );
1389 
1390         m_rasterizer.add_path(@m_curves32 );
1391 
1392        end
1393       else
1394        begin
1395         m_path16.remove_all;
1396 
1397         decompose_ft_outline(
1398          @m_cur_face.glyph.outline ,
1399          m_flip_y ,
1400          @m_affine ,
1401          @m_path16 );
1402 
1403         m_rasterizer.add_path(@m_curves16 );
1404 
1405        end;
1406 
1407       m_scanlines_bin.prepare(1 ); // Remove all
1408 
1409       render_scanlines(@m_rasterizer ,@m_scanline_bin ,@m_scanlines_bin );
1410 
1411       m_bounds.x1:=m_scanlines_bin._min_x;
1412       m_bounds.y1:=m_scanlines_bin._min_y;
1413       m_bounds.x2:=m_scanlines_bin._max_x;
1414       m_bounds.y2:=m_scanlines_bin._max_y;
1415       m_data_size:=m_scanlines_bin.byte_size;
1416       m_data_type:=glyph_data_mono;
1417       m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1418       m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1419 
1420       m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
1421 
1422       result:=true;
1423 
1424      end;
1425 
1426    glyph_ren_agg_gray8 :
1427     if m_last_error = 0 then
1428      begin
1429       m_rasterizer.reset;
1430 
1431       if m_flag32 then
1432        begin
1433         m_path32.remove_all;
1434 
1435         decompose_ft_outline(
1436          @m_cur_face.glyph.outline ,
1437          m_flip_y ,
1438          @m_affine ,
1439          @m_path32 );
1440 
1441         m_rasterizer.add_path(@m_curves32 );
1442 
1443        end
1444       else
1445        begin
1446         m_path16.remove_all;
1447 
1448         decompose_ft_outline(
1449          @m_cur_face.glyph.outline ,
1450          m_flip_y ,
1451          @m_affine ,
1452          @m_path16 );
1453 
1454         m_rasterizer.add_path(@m_curves16 );
1455 
1456        end;
1457 
1458       m_scanlines_aa.prepare(1 ); // Remove all
1459 
1460       render_scanlines(@m_rasterizer ,@m_scanline_aa ,@m_scanlines_aa );
1461 
1462       m_bounds.x1:=m_scanlines_aa._min_x;
1463       m_bounds.y1:=m_scanlines_aa._min_y;
1464       m_bounds.x2:=m_scanlines_aa._max_x;
1465       m_bounds.y2:=m_scanlines_aa._max_y;
1466       m_data_size:=m_scanlines_aa.byte_size;
1467       m_data_type:=glyph_data_gray8;
1468       m_advance_x:=int26p6_to_dbl(m_cur_face.glyph.advance.x );
1469       m_advance_y:=int26p6_to_dbl(m_cur_face.glyph.advance.y );
1470 
1471       m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
1472 
1473       result:=true;
1474 
1475      end;
1476 
1477   end;
1478 
1479 end;
1480 
1481 { GLYPH_INDEX }
1482 function font_engine_freetype_base.glyph_index : unsigned;
1483 begin
1484  result:=m_glyph_index;
1485 
1486 end;
1487 
1488 { DATA_SIZE }
1489 function font_engine_freetype_base.data_size : unsigned;
1490 begin
1491  result:=m_data_size;
1492 
1493 end;
1494 
1495 { DATA_TYPE }
1496 function font_engine_freetype_base.data_type : unsigned;
1497 begin
1498  result:=m_data_type;
1499 
1500 end;
1501 
1502 { BOUNDS }
1503 function font_engine_freetype_base.bounds : rect_ptr;
1504 begin
1505  result:=@m_bounds;
1506 
1507 end;
1508 
1509 { ADVANCE_X }
1510 function font_engine_freetype_base.advance_x : double;
1511 begin
1512  result:=m_advance_x;
1513 
1514 end;
1515 
1516 { ADVANCE_Y }
1517 function font_engine_freetype_base.advance_y : double;
1518 begin
1519  result:=m_advance_y;
1520 
1521 end;
1522 
1523 { WRITE_GLYPH_TO }
1524 procedure font_engine_freetype_base.write_glyph_to(data : int8u_ptr );
1525 begin
1526  if (data <> NIL ) and
1527     (m_data_size <> 0 ) then
1528   case m_data_type of
1529    glyph_data_mono :
1530     m_scanlines_bin.serialize(data );
1531 
1532    glyph_data_gray8 :
1533     m_scanlines_aa.serialize(data );
1534 
1535    glyph_data_outline :
1536     if m_flag32 then
1537      m_path32.serialize(data )
1538     else
1539      m_path16.serialize(data );
1540 
1541   end;
1542 
1543 end;
1544 
1545 { ADD_KERNING }
1546 function font_engine_freetype_base.add_kerning(first ,second : unsigned; x ,y : double_ptr ) : boolean;
1547 var
1548  delta  : FT_Vector;
1549  dx ,dy : double;
1550 
1551 begin
1552  if (m_cur_face <> NIL ) and
1553     (first <> 0 ) and
1554     (second <> 0 ) and
1555     FT_HAS_KERNING(m_cur_face ) then
1556   begin
1557    FT_Get_Kerning(m_cur_face ,first ,second ,FT_KERNING_DEFAULT ,@delta );
1558 
1559    dx:=int26p6_to_dbl(delta.x );
1560    dy:=int26p6_to_dbl(delta.y );
1561 
1562    if (m_glyph_rendering = glyph_ren_outline ) or
1563       (m_glyph_rendering = glyph_ren_agg_mono ) or
1564       (m_glyph_rendering = glyph_ren_agg_gray8 ) then
1565     m_affine.transform_2x2(@m_affine ,@dx ,@dy );
1566 
1567    x^:=x^ + dx;
1568    y^:=y^ + dy;
1569 
1570    result:=true;
1571 
1572   end
1573  else
1574   result:=false;
1575 
1576 end;
1577 
1578 { FLAG32 }
1579 function font_engine_freetype_base.flag32;
1580 begin
1581  result:=m_flag32;
1582 
1583 end;
1584 
1585 { UPDATE_CHAR_SIZE }
1586 procedure font_engine_freetype_base.update_char_size;
1587 begin
1588  if m_cur_face <> NIL then
1589   begin
1590    if m_resolution <> 0 then
1591     FT_Set_Char_Size(
1592      m_cur_face ,
1593      m_width ,       // char_width in 1/64th of points
1594      m_height ,      // char_height in 1/64th of points
1595      m_resolution ,  // horizontal device resolution
1596      m_resolution )  // vertical device resolution
1597    else
1598     FT_Set_Pixel_Sizes(
1599      m_cur_face ,
1600      m_width shr 6 ,    // pixel_width
1601      m_height shr 6 );  // pixel_height
1602 
1603    update_signature;
1604 
1605   end;
1606 
1607 end;
1608 
1609 { UPDATE_SIGNATURE }
1610 procedure font_engine_freetype_base.update_signature;
1611 var
1612  name_len ,gamma_hash ,i : unsigned;
1613 
1614  gamma_table : array[0..aa_num - 1 ] of int8u;
1615 
1616  mtx : array[0..5 ] of double;
1617  buf : array[0..99 ] of char;
1618  str : char_ptr;
1619 
1620 begin
1621  if (m_cur_face <> NIL ) and
1622     (m_name <> NIL ) then
1623   begin
1624    name_len:=StrLen(m_name );
1625 
1626    if name_len > m_name_len then
1627     begin
1628      agg_freemem(pointer(m_signature.name ) ,m_signature.size );
1629 
1630      m_signature.size:=name_len + 32 + 256;
1631 
1632      agg_getmem(pointer(m_signature.name ) ,m_signature.size );
1633 
1634      m_name_len:=name_len + 32 - 1;
1635 
1636     end;
1637 
1638    gamma_hash:=0;
1639 
1640    if (m_glyph_rendering = glyph_ren_native_gray8 ) or
1641       (m_glyph_rendering = glyph_ren_agg_mono ) or
1642       (m_glyph_rendering = glyph_ren_agg_gray8 ) then
1643     begin
1644      for i:=0 to aa_num - 1 do
1645       gamma_table[i ]:=m_rasterizer.apply_gamma(i );
1646 
1647      gamma_hash:=calc_crc32(@gamma_table ,sizeof(gamma_table ) );
1648 
1649     end;
1650 
1651    str:=m_signature.name;
1652 
1653    sprintf(str                                             ,'%s,'  ,ptrcomp(m_name ) );
1654    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%u,'  ,int(m_char_map ) );
1655    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,'  ,m_face_index );
1656    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,'  ,int(m_glyph_rendering ) );
1657    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d:'  ,m_resolution );
1658    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%dx'  ,m_height );
1659    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,'  ,m_width );
1660    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,'  ,int(m_hinting ) );
1661    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,'  ,int(m_flip_y ) );
1662    sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%08X' ,gamma_hash );
1663 
1664    if (m_glyph_rendering = glyph_ren_outline ) or
1665       (m_glyph_rendering = glyph_ren_agg_mono ) or
1666       (m_glyph_rendering = glyph_ren_agg_gray8 ) then
1667     begin
1668      m_affine.store_to(@mtx );
1669 
1670      sprintf(@buf[0 ]                 ,',%08X' ,dbl_to_plain_fx(mtx[0 ] ) );
1671      sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X'  ,dbl_to_plain_fx(mtx[1 ] ) );
1672      sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X'  ,dbl_to_plain_fx(mtx[2 ] ) );
1673      sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X'  ,dbl_to_plain_fx(mtx[3 ] ) );
1674      sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X'  ,dbl_to_plain_fx(mtx[4 ] ) );
1675      sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X'  ,dbl_to_plain_fx(mtx[5 ] ) );
1676 
1677      StrCat(PChar(m_signature.name ) ,buf );
1678 
1679     end;
1680 
1681    inc(m_change_stamp );
1682 
1683   end;
1684 
1685 end;
1686 
1687 { FIND_FACE }
1688 function font_engine_freetype_base.find_face(name : PChar ) : int;
1689 var
1690  i : unsigned;
1691  n : face_name_ptr;
1692 
1693 begin
1694  result:=-1;
1695 
1696  n:=m_face_names;
1697  i:=0;
1698 
1699  while i < m_num_faces do
1700   begin
1701    if StrComp(name ,PChar(n.name ) ) = 0 then
1702     begin
1703      result:=i;
1704 
1705      exit;
1706 
1707     end;
1708 
1709    inc(ptrcomp(n ) ,sizeof(face_name ) );
1710    inc(i );
1711 
1712   end;
1713 
1714 end;
1715 
1716 { CONSTRUCT }
1717 constructor font_engine_freetype_int16.Construct(max_faces : unsigned = 32 );
1718 begin
1719  inherited Construct(false ,max_faces );
1720 
1721 end;
1722 
1723 { CONSTRUCT }
1724 constructor font_engine_freetype_int32.Construct(max_faces : unsigned = 32 );
1725 begin
1726  inherited Construct(true ,max_faces );
1727 
1728 end;
1729 
1730 end.
1731 
1732