lazarus/components/aggpas/src/agg_font_win32_tt.pas
mattias 36a2b1ea07 added aggpas
git-svn-id: trunk@21942 -
2009-10-01 12:24:32 +00:00

1775 lines
38 KiB
ObjectPascal

//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4 (Public License)
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
// Pascal Port By: Milan Marusinec alias Milano
// milan@marusinec.sk
// http://www.aggpas.org
// Copyright (c) 2005-2006
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//
// [Pascal Port History] -----------------------------------------------------
//
// 23.06.2006-Milano: ptrcomp adjustments
// 18.02.2006-Milano: Complete unit port
// 17.02.2006-Milano: Unit port establishment
//
{ agg_font_win32_tt.pas }
unit
agg_font_win32_tt ;
INTERFACE
{$I agg_mode.inc }
uses
Windows ,SysUtils ,Math ,
agg_basics ,
agg_array ,
agg_bitset_iterator ,
agg_scanline_storage_aa ,
agg_scanline_storage_bin ,
agg_scanline ,
agg_scanline_u ,
agg_scanline_bin ,
agg_renderer_scanline ,
agg_render_scanlines ,
agg_path_storage_integer ,
agg_rasterizer_scanline_aa ,
agg_conv_curve ,
agg_trans_affine ,
agg_font_cache_manager ,
agg_font_engine ,
agg_vertex_source ;
{ TYPES DEFINITION }
const
buf_size = 32768 - 32;
type
winapi_GetGlyphOutlineX = function (DC: HDC; p2, p3: UINT; const p4: TGlyphMetrics; p5: DWORD; p6: Pointer; const p7: TMat2): DWORD; stdcall;
HFONT_ptr = ^HFONT;
PChar_ptr = ^PChar;
KERNINGPAIR_ptr = ^KERNINGPAIR;
FIXED_ptr = ^FIXED;
TTPOLYGONHEADER_ptr = ^TTPOLYGONHEADER;
TTPOLYCURVE_ptr = ^TTPOLYCURVE;
POINTFX_ptr = ^POINTFX;
font_name_ptr = ^font_name;
font_name = record
name : char_ptr; //PChar;
size : unsigned;
end;
//-----------------------------------------------font_engine_win32_tt_base
font_engine_win32_tt_base = object(font_engine )
m_flag32 : boolean;
m_dc : HDC;
m_old_font : HFONT;
m_fonts : HFONT_ptr;
m_num_fonts ,
m_max_fonts : unsigned;
m_font_names : font_name_ptr;
m_cur_font : HFONT;
m_change_stamp : int;
m_typeface : font_name;
m_typeface_len : unsigned;
m_signature : font_name;
m_height ,
m_width : unsigned;
m_weight : int;
m_italic : boolean;
m_char_set : DWORD;
m_pitch_and_family : DWORD;
m_hinting ,
m_flip_y : boolean;
m_font_created : boolean;
m_resolution : unsigned;
m_glyph_rendering : glyph_rendering;
m_glyph_index : unsigned;
m_data_size ,
m_data_type : unsigned;
m_bounds : rect;
m_advance_x ,
m_advance_y : double;
m_matrix : TMAT2;
m_gbuf : int8u_ptr;
m_kerning_pairs : KERNINGPAIR_ptr;
m_num_kerning_pairs ,
m_max_kerning_pairs : unsigned;
m_affine : trans_affine;
m_path16 : path_storage_int16;
m_path32 : path_storage_int32;
m_curves16 ,
m_curves32 : conv_curve;
m_scanline_aa : scanline_u8;
m_scanline_bin : scanline_bin;
m_scanlines_aa : scanlines_aa_type;
m_scanlines_bin : scanlines_bin_type;
m_rasterizer : rasterizer_scanline_aa;
constructor Construct(flag32_ : boolean; dc : HDC; max_fonts : unsigned = 32 );
destructor Destruct;
// Set font parameters
procedure resolution_(dpi : unsigned );
procedure height_ (h : double );
procedure width_ (w : double );
procedure weight_ (w : int );
procedure italic_ (it : boolean );
procedure char_set_ (c : DWORD );
procedure pitch_and_family_(p : DWORD );
procedure flip_y_ (flip : boolean );
procedure hinting_(h : boolean );
function create_font (typeface_ : PChar; ren_type : glyph_rendering ) : boolean;
function create_font_(
typeface : PChar;
ren_type : glyph_rendering;
height : double;
width : double = 0.0;
weight : int = FW_REGULAR;
italic : boolean = false;
char_set : DWORD = ANSI_CHARSET;
pitch_and_family : DWORD = FF_DONTCARE ) : boolean;
// Set Gamma
procedure gamma_ (f : vertex_source_ptr );
procedure transform_(mtx : trans_affine_ptr );
// Accessors
function _resolution : unsigned;
function _typeface : PChar;
function _height : double;
function _width : double;
function _weight : int;
function _italic : boolean;
function _char_set : DWORD;
function _pitch_and_family : DWORD;
function _hinting : boolean;
function _flip_y : boolean;
// Interface mandatory to implement for font_cache_manager
function font_signature : PChar; virtual;
function change_stamp : int; virtual;
function prepare_glyph(glyph_code : unsigned ) : boolean; virtual;
function glyph_index : unsigned; virtual;
function data_size : unsigned; virtual;
function data_type : unsigned; virtual;
function bounds : rect_ptr; virtual;
function advance_x : double; virtual;
function advance_y : double; virtual;
procedure write_glyph_to(data : int8u_ptr ); virtual;
function add_kerning (first ,second : unsigned; x ,y : double_ptr ) : boolean; virtual;
function flag32 : boolean; virtual;
// Private
procedure update_signature;
function pair_less(v1 ,v2 : KERNINGPAIR_ptr ) : boolean;
procedure load_kerning_pairs;
procedure sort_kerning_pairs;
function find_font(name : PChar ) : int;
end;
//------------------------------------------------font_engine_win32_tt_int16
// This class uses values of type int16 (10.6 format) for the vector cache.
// The vector cache is compact, but when rendering glyphs of height
// more that 200 there integer overflow can occur.
font_engine_win32_tt_int16 = object(font_engine_win32_tt_base )
constructor Construct(dc : HDC; max_fonts : unsigned = 32 );
end;
//------------------------------------------------font_engine_win32_tt_int32
// This class uses values of type int32 (26.6 format) for the vector cache.
// The vector cache is twice larger than in font_engine_win32_tt_int16,
// but it allows you to render glyphs of very large sizes.
font_engine_win32_tt_int32 = object(font_engine_win32_tt_base )
constructor Construct(dc : HDC; max_fonts : unsigned = 32 );
end;
var
GetGlyphOutlineX : winapi_GetGlyphOutlineX;
{ GLOBAL PROCEDURES }
IMPLEMENTATION
{ LOCAL VARIABLES & CONSTANTS }
//------------------------------------------------------------------------------
//
// This code implements the AUTODIN II polynomial
// The variable corresponding to the macro argument "crc" should
// be an unsigned long.
// Oroginal code by Spencer Garrett <srg@quick.com>
//
// generated using the AUTODIN II polynomial
// x^32 + x^26 + x^23 + x^22 + x^16 +
// x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
//
//------------------------------------------------------------------------------
const
crc32tab : array[0..255 ] of unsigned = (
$00000000, $77073096, $ee0e612c, $990951ba,
$076dc419, $706af48f, $e963a535, $9e6495a3,
$0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988,
$09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
$1db71064, $6ab020f2, $f3b97148, $84be41de,
$1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
$136c9856, $646ba8c0, $fd62f97a, $8a65c9ec,
$14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
$3b6e20c8, $4c69105e, $d56041e4, $a2677172,
$3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
$35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940,
$32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
$26d930ac, $51de003a, $c8d75180, $bfd06116,
$21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
$2802b89e, $5f058808, $c60cd9b2, $b10be924,
$2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
$76dc4190, $01db7106, $98d220bc, $efd5102a,
$71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
$7807c9a2, $0f00f934, $9609a88e, $e10e9818,
$7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
$6b6b51f4, $1c6c6162, $856530d8, $f262004e,
$6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
$65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c,
$62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
$4db26158, $3ab551ce, $a3bc0074, $d4bb30e2,
$4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
$4369e96a, $346ed9fc, $ad678846, $da60b8d0,
$44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
$5005713c, $270241aa, $be0b1010, $c90c2086,
$5768b525, $206f85b3, $b966d409, $ce61e49f,
$5edef90e, $29d9c998, $b0d09822, $c7d7a8b4,
$59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
$edb88320, $9abfb3b6, $03b6e20c, $74b1d29a,
$ead54739, $9dd277af, $04db2615, $73dc1683,
$e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8,
$e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
$f00f9344, $8708a3d2, $1e01f268, $6906c2fe,
$f762575d, $806567cb, $196c3671, $6e6b06e7,
$fed41b76, $89d32be0, $10da7a5a, $67dd4acc,
$f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
$d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252,
$d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
$d80d2bda, $af0a1b4c, $36034af6, $41047a60,
$df60efc3, $a867df55, $316e8eef, $4669be79,
$cb61b38c, $bc66831a, $256fd2a0, $5268e236,
$cc0c7795, $bb0b4703, $220216b9, $5505262f,
$c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04,
$c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
$9b64c2b0, $ec63f226, $756aa39c, $026d930a,
$9c0906a9, $eb0e363f, $72076785, $05005713,
$95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38,
$92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
$86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e,
$81be16cd, $f6b9265b, $6fb077e1, $18b74777,
$88085ae6, $ff0f6a70, $66063bca, $11010b5c,
$8f659eff, $f862ae69, $616bffd3, $166ccf45,
$a00ae278, $d70dd2ee, $4e048354, $3903b3c2,
$a7672661, $d06016f7, $4969474d, $3e6e77db,
$aed16a4a, $d9d65adc, $40df0b66, $37d83bf0,
$a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
$bdbdf21c, $cabac28a, $53b39330, $24b4a3a6,
$bad03605, $cdd70693, $54de5729, $23d967bf,
$b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94,
$b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d );
{ UNIT IMPLEMENTATION }
{ calc_crc32 }
function calc_crc32(buf : int8u_ptr; size : unsigned ) : unsigned;
var
crc ,len ,nr : unsigned;
p : int8u_ptr;
begin
crc:=unsigned(not 0 );
len:=0;
nr :=size;
len:=len + nr;
p :=buf;
while nr <> 0 do
begin
dec(nr );
crc:=(crc shr 8 ) xor crc32tab[(crc xor p^ ) and $ff ];
inc(ptrcomp(p ) ,sizeof(int8u ) );
end;
result:=not crc;
end;
{ dbl_to_fx }
function dbl_to_fx(d : double ) : FIXED;
var
l : int;
begin
l:=trunc(d * 65536.0 );
move(l ,result ,sizeof(int ) );
end;
{ dbl_to_plain_fx }
function dbl_to_plain_fx(d : double ) : int;
begin
result:=trunc(d * 65536.0 );
end;
{ negate_fx }
function negate_fx(fx : FIXED_ptr ) : FIXED;
var
l : int;
begin
l:=-int(fx );
move(l ,result ,sizeof(int ) );
end;
{ fx_to_dbl }
function fx_to_dbl(p : FIXED_ptr ) : double;
begin
result:=p.value + p.fract * (1.0 / 65536.0 );
end;
{ fx_to_plain_int }
function fx_to_plain_int(fx : FIXED_ptr ) : int;
begin
result:=int(fx );
end;
{ fx_to_int26p6 }
function fx_to_int26p6(p : FIXED_ptr ) : int;
begin
result:=(int(p.value ) shl 6 ) + (shr_int32(int(p.fract ) ,10 ) );
end;
{ dbl_to_int26p6 }
function dbl_to_int26p6(p : double ) : int;
begin
result:=trunc(p * 64.0 + 0.5 );
end;
{ decompose_win32_glyph_bitmap_mono }
procedure decompose_win32_glyph_bitmap_mono(
gbuf : int8u_ptr;
w ,h ,x ,y : int;
flip_y : boolean;
sl : scanline_ptr;
storage : renderer_scanline_ptr );
var
i ,pitch ,j : int;
buf : int8u_ptr;
bits : bitset_iterator;
begin
pitch:=shr_int32(w + 31 ,5 ) shl 2;
buf :=gbuf;
sl.reset (x ,x + w );
storage.prepare(w + 2 );
if flip_y then
begin
inc(ptrcomp(buf ) ,(pitch * (h - 1 ) ) * sizeof(int8u ) );
inc(y ,h );
pitch:=-pitch;
end;
i:=0;
while i < h do
begin
sl.reset_spans;
bits.Construct(buf ,0 );
j:=0;
while j < w do
begin
if bits.bit <> 0 then
sl.add_cell(x + j ,cover_full );
bits.inc_operator;
inc(j );
end;
inc(ptrcomp(buf ) ,pitch * sizeof(int8u ) );
if sl.num_spans <> 0 then
begin
sl.finalize (y - i - 1 );
storage.render(sl );
end;
inc(i );
end;
end;
{ decompose_win32_glyph_bitmap_gray8 }
procedure decompose_win32_glyph_bitmap_gray8(
gbuf : int8u_ptr;
w ,h ,x ,y : int;
flip_y : boolean;
ras : rasterizer_scanline_aa_ptr;
sl : scanline_ptr;
storage : renderer_scanline_ptr );
var
i ,j ,pitch : int;
buf ,p : int8u_ptr;
v : unsigned;
begin
pitch:=shr_int32(w + 3 ,2 ) shl 2;
buf :=gbuf;
sl.reset (x ,x + w );
storage.prepare(w + 2 );
if flip_y then
begin
inc(ptrcomp(buf ) ,(pitch * (h - 1 ) ) * sizeof(int8u ) );
inc(y ,h );
pitch:=-pitch;
end;
i:=0;
while i < h do
begin
sl.reset_spans;
p:=buf;
j:=0;
while j < w do
begin
if p^ <> 0 then
begin
v:=p^;
if v = 64 then
v:=255
else
v:=v shl 2;
sl.add_cell(x + j ,ras.apply_gamma(v ) );
end;
inc(ptrcomp(p ) ,sizeof(int8u ) );
inc(j );
end;
inc(ptrcomp(buf ) ,pitch * sizeof(int8u ) );
if sl.num_spans <> 0 then
begin
sl.finalize (y - i - 1 );
storage.render(sl );
end;
inc(i );
end;
end;
{ decompose_win32_glyph_outline }
function decompose_win32_glyph_outline(
gbuf : int8u_ptr;
total_size : unsigned;
flip_y : boolean;
mtx : trans_affine_ptr;
path : path_storage_integer_ptr ) : boolean;
var
cur_glyph ,end_glyph ,end_poly ,cur_poly : int8u_ptr;
x ,y ,x2 ,y2 : double;
i ,u : int;
th : TTPOLYGONHEADER_ptr;
pc : TTPOLYCURVE_ptr;
pnt_b ,pnt_c : POINTFX;
cx ,cy ,bx ,by : int;
begin
cur_glyph:=gbuf;
end_glyph:=int8u_ptr(ptrcomp(gbuf ) + total_size * sizeof(int8u ) );
while ptrcomp(cur_glyph ) < ptrcomp(end_glyph ) do
begin
th:=TTPOLYGONHEADER_ptr(cur_glyph );
end_poly:=int8u_ptr(ptrcomp(cur_glyph ) + th.cb );
cur_poly:=int8u_ptr(ptrcomp(cur_glyph ) + sizeof(TTPOLYGONHEADER ) );
x:=fx_to_dbl(@th.pfxStart.x );
y:=fx_to_dbl(@th.pfxStart.y );
if flip_y then
y:=-y;
mtx.transform(mtx ,@x ,@y );
path.move_to (dbl_to_int26p6(x ) ,dbl_to_int26p6(y ) );
while ptrcomp(cur_poly ) < ptrcomp(end_poly ) do
begin
pc:=TTPOLYCURVE_ptr(cur_poly );
if pc.wType = TT_PRIM_LINE then
begin
i:=0;
while i < pc.cpfx do
begin
x:=fx_to_dbl(@POINTFX_ptr(ptrcomp(@pc.apfx ) + i * sizeof(POINTFX ) ).x );
y:=fx_to_dbl(@POINTFX_ptr(ptrcomp(@pc.apfx ) + i * sizeof(POINTFX ) ).y );
if flip_y then
y:=-y;
mtx.transform(mtx ,@x ,@y );
path.line_to (dbl_to_int26p6(x ) ,dbl_to_int26p6(y ) );
inc(i );
end;
end;
if pc.wType = TT_PRIM_QSPLINE then
begin
u:=0;
while u < pc.cpfx - 1 do // Walk through points in spline
begin
// B is always the current point
pnt_b:=POINTFX_ptr(ptrcomp(@pc.apfx ) + u * sizeof(POINTFX ) )^;
pnt_c:=POINTFX_ptr(ptrcomp(@pc.apfx ) + (u + 1 ) * sizeof(POINTFX ) )^;
if u < pc.cpfx - 2 then // If not on last spline, compute C
begin
// midpoint (x,y)
// int(pnt_c.x ):=int(pnt_b.x ) + int(pnt_c.x ) div 2;
// int(pnt_c.y ):=int(pnt_b.y ) + int(pnt_c.y ) div 2;
move(pnt_b.x ,bx ,sizeof(int ) );
move(pnt_b.y ,by ,sizeof(int ) );
move(pnt_c.x ,cx ,sizeof(int ) );
move(pnt_c.y ,cy ,sizeof(int ) );
cx:=(bx + cx ) div 2;
cy:=(by + cy ) div 2;
move(cx ,pnt_c.x ,sizeof(int ) );
move(cy ,pnt_c.y ,sizeof(int ) );
end;
x :=fx_to_dbl(@pnt_b.x );
y :=fx_to_dbl(@pnt_b.y );
x2:=fx_to_dbl(@pnt_c.x );
y2:=fx_to_dbl(@pnt_c.y );
if flip_y then
begin
y :=-y;
y2:=-y2;
end;
mtx.transform(mtx ,@x ,@y );
mtx.transform(mtx ,@x2 ,@y2 );
path.curve3(
dbl_to_int26p6(x ) ,dbl_to_int26p6(y ) ,
dbl_to_int26p6(x2 ) ,dbl_to_int26p6(y2 ) );
inc(u );
end;
end;
inc(ptrcomp(cur_poly ) ,sizeof(WORD ) * 2 + sizeof(POINTFX ) * pc.cpfx );
end;
inc(ptrcomp(cur_glyph ) ,th.cb );
end;
result:=true;
end;
{ CONSTRUCT }
constructor font_engine_win32_tt_base.Construct;
begin
m_flag32:=flag32_;
m_dc :=dc;
if m_dc <> 0 then
m_old_font:=GetCurrentObject(m_dc ,OBJ_FONT )
else
m_old_font:=0;
agg_getmem(pointer(m_fonts ) ,sizeof(HFONT ) * max_fonts );
m_num_fonts:=0;
m_max_fonts:=max_fonts;
agg_getmem(pointer(m_font_names ) ,sizeof(font_name ) * max_fonts );
m_cur_font :=0;
m_change_stamp:=0;
m_typeface.size:=sizeof(char ) * (256 - 16 );
agg_getmem(pointer(m_typeface.name ) ,m_typeface.size );
m_typeface_len:=256 - 16 - 1;
m_signature.size:=sizeof(char ) * (256 + 256 - 16 );
agg_getmem(pointer(m_signature.name ) ,m_signature.size );
m_height :=0;
m_width :=0;
m_weight :=FW_REGULAR;
m_italic :=false;
m_char_set:=DEFAULT_CHARSET;
m_pitch_and_family:=FF_DONTCARE;
m_hinting:=true;
m_flip_y :=false;
m_font_created :=false;
m_resolution :=0;
m_glyph_rendering:=glyph_ren_native_gray8;
m_glyph_index:=0;
m_data_size :=0;
m_data_type :=glyph_data_invalid;
m_bounds.Construct(1 ,1 ,0 ,0 );
m_advance_x:=0.0;
m_advance_y:=0.0;
agg_getmem(pointer(m_gbuf ) ,sizeof(int8u ) * buf_size );
m_kerning_pairs :=NIL;
m_num_kerning_pairs:=0;
m_max_kerning_pairs:=0;
m_affine.Construct;
m_path16.Construct;
m_path32.Construct;
m_curves16.Construct(@m_path16 );
m_curves32.Construct(@m_path32 );
m_scanline_aa.Construct;
m_scanline_bin.Construct;
m_scanlines_aa.Construct;
m_scanlines_bin.Construct;
m_rasterizer.Construct;
m_curves16.approximation_scale_(4.0 );
m_curves32.approximation_scale_(4.0 );
fillchar(m_matrix ,sizeof(m_matrix ) ,0 );
m_matrix.eM11.value:=1;
m_matrix.eM22.value:=1;
end;
{ DESTRUCT }
destructor font_engine_win32_tt_base.Destruct;
var
i : unsigned;
f : HFONT_ptr;
n : font_name_ptr;
begin
agg_freemem(pointer(m_kerning_pairs ) ,m_max_kerning_pairs * sizeof(KERNINGPAIR ) );
agg_freemem(pointer(m_gbuf ) ,sizeof(int8u ) * buf_size );
agg_freemem(pointer(m_signature.name ) ,m_signature.size );
agg_freemem(pointer(m_typeface.name ) ,m_typeface.size );
if (m_dc <> 0 ) and
(m_old_font <> 0 ) then
SelectObject(m_dc ,m_old_font );
i:=0;
f:=m_fonts;
n:=m_font_names;
while i < m_num_fonts do
begin
agg_freemem (pointer(n.name ) ,n.size );
DeleteObject(f^ );
inc(ptrcomp(n ) ,sizeof(font_name ) );
inc(ptrcomp(f ) ,sizeof(HFONT ) );
inc(i );
end;
agg_freemem(pointer(m_font_names ) ,sizeof(font_name ) * m_max_fonts );
agg_freemem(pointer(m_fonts ) ,sizeof(HFONT ) * m_max_fonts );
m_path16.Destruct;
m_path32.Destruct;
m_curves16.Destruct;
m_curves32.Destruct;
m_scanline_aa.Destruct;
m_scanline_bin.Destruct;
m_scanlines_aa.Destruct;
m_scanlines_bin.Destruct;
m_rasterizer.Destruct;
end;
{ RESOLUTION_ }
procedure font_engine_win32_tt_base.resolution_;
begin
m_resolution:=dpi;
end;
{ HEIGHT_ }
procedure font_engine_win32_tt_base.height_;
begin
m_height:=trunc(h );
end;
{ WIDTH_ }
procedure font_engine_win32_tt_base.width_;
begin
m_width:=trunc(w );
end;
{ WEIGHT_ }
procedure font_engine_win32_tt_base.weight_;
begin
m_weight:=w;
end;
{ ITALIC_ }
procedure font_engine_win32_tt_base.italic_;
begin
m_italic:=it;
end;
{ CHAR_SET_ }
procedure font_engine_win32_tt_base.char_set_;
begin
m_char_set:=c;
end;
{ PITCH_AND_FAMILY_ }
procedure font_engine_win32_tt_base.pitch_and_family_;
begin
m_pitch_and_family:=p;
end;
{ FLIP_Y_ }
procedure font_engine_win32_tt_base.flip_y_;
begin
m_flip_y:=flip;
end;
{ HINTING_ }
procedure font_engine_win32_tt_base.hinting_;
begin
m_hinting:=h;
end;
{ CREATE_FONT }
function font_engine_win32_tt_base.create_font;
var
len : unsigned;
h ,w ,idx : int;
f : HFONT_ptr;
n : font_name_ptr;
begin
if m_dc <> 0 then
begin
len:=StrLen(typeface_ );
if len > m_typeface_len then
begin
agg_freemem(pointer(m_signature.name ) ,m_signature.size );
agg_freemem(pointer(m_typeface.name ) ,m_typeface.size );
m_typeface.size :=sizeof(char ) * (len + 32 );
m_signature.size:=sizeof(char ) * (len + 32 + 256 );
agg_getmem(pointer(m_typeface.name ) ,m_typeface.size );
agg_getmem(pointer(m_signature.name ) ,m_signature.size );
m_typeface_len:=len + 32 - 1;
end;
StrCopy(PChar(m_typeface.name ) ,typeface_ );
h:=m_height;
w:=m_width;
if m_resolution <> 0 then
begin
h:=MulDiv(m_height ,m_resolution ,72 );
w:=MulDiv(m_width ,m_resolution ,72 );
end;
m_glyph_rendering:=ren_type;
update_signature;
idx:=find_font(PChar(m_signature.name ) );
if idx >= 0 then
begin
m_cur_font:=HFONT_ptr(ptrcomp(m_fonts ) + idx * sizeof(HFONT ) )^;
SelectObject(m_dc ,m_cur_font );
m_num_kerning_pairs:=0;
result:=true;
exit;
end
else
begin
m_cur_font:=
CreateFont(
-h , // height of font
w , // average character width
0 , // angle of escapement
0 , // base-line orientation angle
m_weight , // font weight
unsigned(m_italic ) , // italic attribute option
0 , // underline attribute option
0 , // strikeout attribute option
m_char_set , // character set identifier
OUT_DEFAULT_PRECIS , // output precision
CLIP_DEFAULT_PRECIS , // clipping precision
ANTIALIASED_QUALITY , // output quality
m_pitch_and_family , // pitch and family
PChar(m_typeface.name ) // typeface name
);
if m_cur_font <> 0 then
begin
if m_num_fonts >= m_max_fonts then
begin
agg_freemem(pointer(m_font_names.name ) ,m_font_names.size );
if m_old_font <> 0 then
SelectObject(m_dc ,m_old_font );
DeleteObject(m_fonts^ );
move(
HFONT_ptr(ptrcomp(m_fonts ) + 1 * sizeof(HFONT ) )^ ,
m_fonts^ ,
(m_max_fonts - 1 ) * sizeof(HFONT ) );
move(
font_name_ptr(ptrcomp(m_font_names ) + 1 * sizeof(font_name ) )^ ,
m_font_names^ ,
(m_max_fonts - 1 ) * sizeof(font_name ) );
m_num_fonts:=m_max_fonts - 1;
end;
update_signature;
n:=font_name_ptr(ptrcomp(m_font_names ) + m_num_fonts * sizeof(font_name ) );
f:=HFONT_ptr(ptrcomp(m_fonts ) + m_num_fonts * sizeof(HFONT ) );
n.size:=sizeof(char ) * (StrLen(PChar(m_signature.name ) ) + 1 );
agg_getmem(pointer(n.name ) ,n.size );
StrCopy (PChar(n.name ) ,PChar(m_signature.name ) );
f^:=m_cur_font;
inc(m_num_fonts );
SelectObject(m_dc ,m_cur_font );
m_num_kerning_pairs:=0;
result:=true;
exit;
end;
end;
end;
result:=false;
end;
{ CREATE_FONT_ }
function font_engine_win32_tt_base.create_font_;
begin
height_ (height );
width_ (width );
weight_ (weight );
italic_ (italic );
char_set_(char_set );
pitch_and_family_(pitch_and_family );
result:=create_font(typeface ,ren_type );
end;
{ GAMMA_ }
procedure font_engine_win32_tt_base.gamma_;
begin
m_rasterizer.gamma(f );
end;
{ TRANSFORM_ }
procedure font_engine_win32_tt_base.transform_;
begin
m_affine.assign_all(mtx );
end;
{ _RESOLUTION }
function font_engine_win32_tt_base._resolution;
begin
result:=m_resolution;
end;
{ _TYPEFACE }
function font_engine_win32_tt_base._typeface;
begin
result:=PChar(m_typeface.name );
end;
{ _HEIGHT }
function font_engine_win32_tt_base._height;
begin
result:=m_height;
end;
{ _WIDTH }
function font_engine_win32_tt_base._width;
begin
result:=m_width;
end;
{ _WEIGHT }
function font_engine_win32_tt_base._weight;
begin
result:=m_weight;
end;
{ _ITALIC }
function font_engine_win32_tt_base._italic;
begin
result:=m_italic;
end;
{ _CHAR_SET }
function font_engine_win32_tt_base._char_set;
begin
result:=m_char_set;
end;
{ _PITCH_AND_FAMILY }
function font_engine_win32_tt_base._pitch_and_family;
begin
result:=m_pitch_and_family;
end;
{ _HINTING }
function font_engine_win32_tt_base._hinting;
begin
result:=m_hinting;
end;
{ _FLIP_Y }
function font_engine_win32_tt_base._flip_y;
begin
result:=m_flip_y;
end;
{ FONT_SIGNATURE }
function font_engine_win32_tt_base.font_signature;
begin
result:=PChar(m_signature.name );
end;
{ CHANGE_STAMP }
function font_engine_win32_tt_base.change_stamp;
begin
result:=m_change_stamp;
end;
{ PREPARE_GLYPH }
function font_engine_win32_tt_base.prepare_glyph;
const
GGO_UNHINTED = $0100; // For compatibility with old SDKs.
var
format ,total_size : int;
gm : TGLYPHMETRICS;
fl : longint;
ts : DWORD;
bnd : rect_d;
begin
if (m_dc <> 0 ) and
(m_cur_font <> 0 ) then
begin
format:=GGO_BITMAP;
case m_glyph_rendering of
glyph_ren_native_gray8 :
format:=GGO_GRAY8_BITMAP;
glyph_ren_outline ,
glyph_ren_agg_mono ,
glyph_ren_agg_gray8 :
format:=GGO_NATIVE;
end;
if not m_hinting then
format:=format or GGO_UNHINTED;
ts:=
GetGlyphOutlineX(
m_dc ,
glyph_code ,
format ,
gm ,
buf_size ,
m_gbuf ,
m_matrix );
move(ts ,total_size ,sizeof(int ) );
if total_size < 0 then
begin
// GetGlyphOutline() fails when being called for
// GGO_GRAY8_BITMAP and white space (stupid Microsoft).
// It doesn't even initialize the glyph metrics
// structure. So, we have to query the metrics
// separately (basically we need gmCellIncX).
ts:=
GetGlyphOutlineX(
m_dc ,
glyph_code ,
GGO_METRICS ,
gm ,
buf_size ,
m_gbuf ,
m_matrix );
move(ts ,total_size ,sizeof(int ) );
if total_size < 0 then
begin
result:=false;
exit;
end;
gm.gmBlackBoxX:=0;
gm.gmBlackBoxY:=0;
total_size:=0;
end;
m_glyph_index:=glyph_code;
m_advance_x :=gm.gmCellIncX;
m_advance_y :=-gm.gmCellIncY;
case m_glyph_rendering of
glyph_ren_native_mono :
begin
if m_flip_y then
fl:=-gm.gmptGlyphOrigin.y
else
fl:=gm.gmptGlyphOrigin.y;
decompose_win32_glyph_bitmap_mono(
m_gbuf ,
gm.gmBlackBoxX ,
gm.gmBlackBoxY ,
gm.gmptGlyphOrigin.x ,
fl ,
m_flip_y ,
@m_scanline_bin ,
@m_scanlines_bin );
m_bounds.x1:=m_scanlines_bin._min_x;
m_bounds.y1:=m_scanlines_bin._min_y;
m_bounds.x2:=m_scanlines_bin._max_x;
m_bounds.y2:=m_scanlines_bin._max_y;
m_data_size:=m_scanlines_bin.byte_size;
m_data_type:=glyph_data_mono;
result:=true;
exit;
end;
glyph_ren_native_gray8 :
begin
if m_flip_y then
fl:=-gm.gmptGlyphOrigin.y
else
fl:=gm.gmptGlyphOrigin.y;
decompose_win32_glyph_bitmap_gray8(
m_gbuf ,
gm.gmBlackBoxX ,
gm.gmBlackBoxY ,
gm.gmptGlyphOrigin.x ,
fl ,
m_flip_y ,
@m_rasterizer ,
@m_scanline_aa ,
@m_scanlines_aa );
m_bounds.x1:=m_scanlines_aa._min_x;
m_bounds.y1:=m_scanlines_aa._min_y;
m_bounds.x2:=m_scanlines_aa._max_x;
m_bounds.y2:=m_scanlines_aa._max_y;
m_data_size:=m_scanlines_aa.byte_size;
m_data_type:=glyph_data_gray8;
result:=true;
exit;
end;
glyph_ren_outline :
begin
m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
if m_flag32 then
begin
m_path32.remove_all;
if decompose_win32_glyph_outline(
m_gbuf ,
total_size ,
m_flip_y ,
@m_affine ,
@m_path32 ) then
begin
bnd:=m_path32.bounding_rect;
m_data_size:=m_path32.byte_size;
m_data_type:=glyph_data_outline;
m_bounds.x1:=Floor(bnd.x1 );
m_bounds.y1:=Floor(bnd.y1 );
m_bounds.x2:=Ceil(bnd.x2 );
m_bounds.y2:=Ceil(bnd.y2 );
result:=true;
exit;
end;
end
else
begin
m_path16.remove_all;
if decompose_win32_glyph_outline(
m_gbuf ,
total_size ,
m_flip_y ,
@m_affine ,
@m_path16 ) then
begin
bnd:=m_path16.bounding_rect;
m_data_size:=m_path16.byte_size;
m_data_type:=glyph_data_outline;
m_bounds.x1:=Floor(bnd.x1 );
m_bounds.y1:=Floor(bnd.y1 );
m_bounds.x2:=Ceil(bnd.x2 );
m_bounds.y2:=Ceil(bnd.y2 );
result:=true;
exit;
end;
end;
end;
glyph_ren_agg_mono :
begin
m_rasterizer.reset;
m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
if m_flag32 then
begin
m_path32.remove_all;
decompose_win32_glyph_outline(
m_gbuf ,
total_size ,
m_flip_y ,
@m_affine ,
@m_path32 );
m_rasterizer.add_path(@m_curves32 );
end
else
begin
m_path16.remove_all;
decompose_win32_glyph_outline(
m_gbuf ,
total_size ,
m_flip_y ,
@m_affine ,
@m_path16 );
m_rasterizer.add_path(@m_curves16 );
end;
m_scanlines_bin.prepare(1 ); // Remove all
render_scanlines(@m_rasterizer ,@m_scanline_bin ,@m_scanlines_bin );
m_bounds.x1:=m_scanlines_bin._min_x;
m_bounds.y1:=m_scanlines_bin._min_y;
m_bounds.x2:=m_scanlines_bin._max_x;
m_bounds.y2:=m_scanlines_bin._max_y;
m_data_size:=m_scanlines_bin.byte_size;
m_data_type:=glyph_data_mono;
result:=true;
exit;
end;
glyph_ren_agg_gray8 :
begin
m_rasterizer.reset;
m_affine.transform(@m_affine ,@m_advance_x ,@m_advance_y );
if m_flag32 then
begin
m_path32.remove_all;
decompose_win32_glyph_outline(
m_gbuf ,
total_size ,
m_flip_y ,
@m_affine ,
@m_path32 );
m_rasterizer.add_path(@m_curves32 );
end
else
begin
m_path16.remove_all;
decompose_win32_glyph_outline(
m_gbuf ,
total_size,
m_flip_y ,
@m_affine ,
@m_path16 );
m_rasterizer.add_path(@m_curves16 );
end;
m_scanlines_aa.prepare(1 ); // Remove all
render_scanlines(@m_rasterizer ,@m_scanline_aa ,@m_scanlines_aa );
m_bounds.x1:=m_scanlines_aa._min_x;
m_bounds.y1:=m_scanlines_aa._min_y;
m_bounds.x2:=m_scanlines_aa._max_x;
m_bounds.y2:=m_scanlines_aa._max_y;
m_data_size:=m_scanlines_aa.byte_size;
m_data_type:=glyph_data_gray8;
result:=true;
exit;
end;
end;
end;
result:=false;
end;
{ GLYPH_INDEX }
function font_engine_win32_tt_base.glyph_index;
begin
result:=m_glyph_index;
end;
{ DATA_SIZE }
function font_engine_win32_tt_base.data_size;
begin
result:=m_data_size;
end;
{ DATA_TYPE }
function font_engine_win32_tt_base.data_type;
begin
result:=m_data_type;
end;
{ BOUNDS }
function font_engine_win32_tt_base.bounds;
begin
result:=@m_bounds;
end;
{ ADVANCE_X }
function font_engine_win32_tt_base.advance_x;
begin
result:=m_advance_x;
end;
{ ADVANCE_Y }
function font_engine_win32_tt_base.advance_y;
begin
result:=m_advance_y;
end;
{ WRITE_GLYPH_TO }
procedure font_engine_win32_tt_base.write_glyph_to;
begin
if (data <> NIL ) and
(m_data_size <> 0 ) then
case m_data_type of
glyph_data_mono :
m_scanlines_bin.serialize(data );
glyph_data_gray8 :
m_scanlines_aa.serialize(data );
glyph_data_outline :
if m_flag32 then
m_path32.serialize(data )
else
m_path16.serialize(data );
end;
end;
{ ADD_KERNING }
function font_engine_win32_tt_base.add_kerning;
var
end_ ,beg_ ,mid : int;
dx ,dy : double;
t : KERNINGPAIR;
kp : KERNINGPAIR_ptr;
begin
if (m_dc <> 0 ) and
(m_cur_font <> 0 ) then
begin
if m_num_kerning_pairs = 0 then
load_kerning_pairs;
end_:=m_num_kerning_pairs; dec(end_ );
beg_:=0;
t.wFirst :=WORD(first );
t.wSecond:=WORD(second );
while beg_ <= end_ do
begin
mid:=(end_ + beg_ ) div 2;
kp :=KERNINGPAIR_ptr(ptrcomp(m_kerning_pairs ) + mid * sizeof(KERNINGPAIR ) );
if (kp.wFirst = t.wFirst ) and
(kp.wSecond = t.wSecond ) then
begin
dx:=kp.iKernAmount;
dy:=0.0;
if (m_glyph_rendering = glyph_ren_outline ) or
(m_glyph_rendering = glyph_ren_agg_mono ) or
(m_glyph_rendering = glyph_ren_agg_gray8 ) then
m_affine.transform_2x2(@m_affine ,@dx ,@dy );
x^:=x^ + dx;
y^:=y^ + dy;
result:=true;
exit;
end
else
if pair_less(@t ,kp ) then
end_:=mid - 1
else
beg_:=mid + 1;
end;
end;
result:=false;
end;
{ FLAG32 }
function font_engine_win32_tt_base.flag32;
begin
result:=m_flag32;
end;
{ UPDATE_SIGNATURE }
procedure font_engine_win32_tt_base.update_signature;
var
gamma_hash ,i : unsigned;
gamma_table : array[0..aa_num - 1 ] of int8u;
mtx : array[0..5 ] of double;
buf : array[0..99 ] of char;
str : char_ptr;
begin
m_signature.name^:=#0;
if (m_dc <> 0 ) and
(m_cur_font <> 0 ) then
begin
gamma_hash:=0;
if (m_glyph_rendering = glyph_ren_native_gray8 ) or
(m_glyph_rendering = glyph_ren_agg_mono ) or
(m_glyph_rendering = glyph_ren_agg_gray8 ) then
begin
for i:=0 to aa_num - 1 do
gamma_table[i ]:=m_rasterizer.apply_gamma(i );
gamma_hash:=calc_crc32(@gamma_table ,sizeof(gamma_table ) );
end;
str:=m_signature.name;
sprintf(str ,'%s,' ,ptrcomp(m_typeface.name ) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%u,' ,m_char_set );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,int(m_glyph_rendering ) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d:' ,m_resolution );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%dx' ,m_height );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,m_width );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,m_weight );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,int(m_italic ) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,int(m_hinting) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,int(m_flip_y ) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%d,' ,int(m_pitch_and_family ) );
sprintf(char_ptr(ptrcomp(str ) + StrLen(PChar(str ) ) ) ,'%08X' ,gamma_hash );
if (m_glyph_rendering = glyph_ren_outline ) or
(m_glyph_rendering = glyph_ren_agg_mono ) or
(m_glyph_rendering = glyph_ren_agg_gray8 ) then
begin
m_affine.store_to(@mtx );
sprintf(@buf[0 ] ,',%08X' ,dbl_to_plain_fx(mtx[0 ] ) );
sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X' ,dbl_to_plain_fx(mtx[1 ] ) );
sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X' ,dbl_to_plain_fx(mtx[2 ] ) );
sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X' ,dbl_to_plain_fx(mtx[3 ] ) );
sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X' ,dbl_to_plain_fx(mtx[4 ] ) );
sprintf(@buf[StrLen(@buf[0 ] ) ] ,'%08X' ,dbl_to_plain_fx(mtx[5 ] ) );
StrCat(PChar(m_signature.name ) ,buf );
end;
inc(m_change_stamp );
end;
end;
{ PAIR_LESS }
function font_engine_win32_tt_base.pair_less;
begin
if v1.wFirst <> v2.wFirst then
result:=v1.wFirst < v2.wFirst
else
result:=v1.wSecond < v2.wSecond;
end;
{ LOAD_KERNING_PAIRS }
procedure font_engine_win32_tt_base.load_kerning_pairs;
var
i : unsigned;
begin
if (m_dc <> 0 ) and
(m_cur_font <> 0 ) then
begin
if m_kerning_pairs = NIL then
begin
m_max_kerning_pairs:=16384 - 16;
agg_getmem(pointer(m_kerning_pairs ) ,m_max_kerning_pairs * sizeof(KERNINGPAIR ) );
end;
m_num_kerning_pairs:=
GetKerningPairs(m_dc ,m_max_kerning_pairs ,m_kerning_pairs^ );
if m_num_kerning_pairs <> 0 then
begin
// Check to see if the kerning pairs are sorted and
// sort them if they are not.
i:=1;
while i < m_num_kerning_pairs do
begin
if not pair_less(
KERNINGPAIR_ptr(ptrcomp(m_kerning_pairs ) + (i - 1 ) * sizeof(KERNINGPAIR ) ) ,
KERNINGPAIR_ptr(ptrcomp(m_kerning_pairs ) + i * sizeof(KERNINGPAIR ) ) ) then
begin
sort_kerning_pairs;
break;
end;
inc(i );
end;
end;
end;
end;
{ _pair_less }
function _pair_less(v1 ,v2 : KERNINGPAIR_ptr ) : boolean;
begin
if v1.wFirst <> v2.wFirst then
result:=v1.wFirst < v2.wFirst
else
result:=v1.wSecond < v2.wSecond;
end;
{ SORT_KERNING_PAIRS }
procedure font_engine_win32_tt_base.sort_kerning_pairs;
var
pairs : pod_array_adaptor;
begin
pairs.Construct(m_kerning_pairs ,m_num_kerning_pairs ,sizeof(KERNINGPAIR ) );
quick_sort(@pairs ,@_pair_less );
end;
{ FIND_FONT }
function font_engine_win32_tt_base.find_font;
var
i : unsigned;
n : font_name_ptr;
begin
n:=m_font_names;
i:=0;
while i < m_num_fonts do
begin
if StrComp(name ,PChar(n.name ) ) = 0 then
begin
result:=i;
exit;
end;
inc(ptrcomp(n ) ,sizeof(font_name ) );
inc(i );
end;
result:=-1;
end;
{ CONSTRUCT }
constructor font_engine_win32_tt_int16.Construct;
begin
inherited Construct(false ,dc ,max_fonts );
end;
{ CONSTRUCT }
constructor font_engine_win32_tt_int32.Construct;
begin
inherited Construct(true ,dc ,max_fonts );
end;
{ UNIT CONSTRUCTOR }
INITIALIZATION
{$IFDEF AGG_WIN9X_COMPLIANT }
GetGlyphOutlineX:=@GetGlyphOutline;
{$ELSE }
GetGlyphOutlineX:=@GetGlyphOutlineW;
{$ENDIF }
END.