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