mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-10 06:02:33 +02:00
613 lines
12 KiB
ObjectPascal
613 lines
12 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
|
|
// 16.02.2006-Milano: Unit port establishment
|
|
//
|
|
{ agg_font_cache_manager.pas }
|
|
unit
|
|
agg_font_cache_manager ;
|
|
|
|
INTERFACE
|
|
|
|
{$I agg_mode.inc }
|
|
|
|
uses
|
|
SysUtils ,
|
|
agg_basics ,
|
|
agg_array ,
|
|
agg_font_engine ,
|
|
agg_path_storage_integer ;
|
|
|
|
{ TYPES DEFINITION }
|
|
const
|
|
glyph_data_invalid = 0;
|
|
glyph_data_mono = 1;
|
|
glyph_data_gray8 = 2;
|
|
glyph_data_outline = 3;
|
|
|
|
block_size = 16384 - 16;
|
|
|
|
type
|
|
glyph_cache_ptr_ptr = ^glyph_cache_ptr;
|
|
glyph_cache_ptr = ^glyph_cache;
|
|
glyph_cache = record
|
|
glyph_index : unsigned;
|
|
|
|
data : int8u_ptr;
|
|
|
|
data_size ,
|
|
data_type : unsigned;//: int8u;
|
|
|
|
bounds : rect;
|
|
|
|
advance_x ,
|
|
advance_y : double;
|
|
|
|
end;
|
|
|
|
font_cache_ptr_ptr = ^font_cache_ptr;
|
|
font_cache_ptr = ^font_cache;
|
|
font_cache = object
|
|
m_allocator : pod_allocator;
|
|
m_glyphs : array[0..256] of glyph_cache_ptr_ptr;
|
|
m_font_signature : PChar;
|
|
|
|
constructor Construct(font_signature : PChar );
|
|
destructor Destruct;
|
|
|
|
function font_is(font_signature : PChar ) : boolean;
|
|
|
|
function find_glyph(glyph_code : unsigned ) : glyph_cache_ptr;
|
|
|
|
function cache_glyph(
|
|
glyph_code ,
|
|
glyph_index ,
|
|
data_size : unsigned;
|
|
data_type : int8u;
|
|
bounds : rect_ptr;
|
|
advance_x ,
|
|
advance_y : double ) : glyph_cache_ptr;
|
|
|
|
end;
|
|
|
|
font_cache_pool = object
|
|
m_fonts : font_cache_ptr_ptr;
|
|
m_max_fonts ,
|
|
m_num_fonts : unsigned;
|
|
m_cur_font : font_cache_ptr;
|
|
|
|
constructor Construct(max_fonts : unsigned = 32 );
|
|
destructor Destruct;
|
|
|
|
procedure font_(font_signature : PChar; reset_cache : boolean = false );
|
|
function _font : font_cache_ptr;
|
|
|
|
function find_glyph(glyph_code : unsigned ) : glyph_cache_ptr;
|
|
|
|
function cache_glyph(
|
|
glyph_code ,
|
|
glyph_index ,
|
|
data_size : unsigned;
|
|
data_type : int8u;
|
|
bounds : rect_ptr;
|
|
advance_x ,
|
|
advance_y : double ) : glyph_cache_ptr;
|
|
|
|
function find_font(font_signature : PChar ) : int;
|
|
|
|
end;
|
|
|
|
glyph_rendering = (
|
|
glyph_ren_native_mono ,
|
|
glyph_ren_native_gray8 ,
|
|
glyph_ren_outline ,
|
|
glyph_ren_agg_mono ,
|
|
glyph_ren_agg_gray8 );
|
|
|
|
font_cache_manager_ptr = ^font_cache_manager;
|
|
font_cache_manager = object
|
|
m_fonts : font_cache_pool;
|
|
m_engine : font_engine_ptr;
|
|
|
|
m_change_stamp : int;
|
|
|
|
m_dx ,
|
|
m_dy : double;
|
|
|
|
m_prev_glyph ,
|
|
m_last_glyph : glyph_cache_ptr;
|
|
|
|
m_path_adaptor : path_adaptor_type_ptr;
|
|
m_gray8_adaptor : gray8_adaptor_type;
|
|
m_gray8_scanline : gray8_scanline_type;
|
|
m_mono_adaptor : mono_adaptor_type;
|
|
m_mono_scanline : mono_scanline_type;
|
|
|
|
constructor Construct(engine : font_engine_ptr; max_fonts : unsigned = 32 );
|
|
destructor Destruct;
|
|
|
|
function glyph(glyph_code : unsigned ) : glyph_cache_ptr;
|
|
|
|
procedure init_embedded_adaptors(gl : glyph_cache_ptr; x ,y : double; scale : double = 1.0 );
|
|
|
|
function path_adaptor : path_adaptor_type_ptr;
|
|
function gray8_adaptor : gray8_adaptor_type_ptr;
|
|
function gray8_scanline : gray8_scanline_type_ptr;
|
|
function mono_adaptor : mono_adaptor_type_ptr;
|
|
function mono_scanline : mono_scanline_type_ptr;
|
|
|
|
function prev_glyph : glyph_cache_ptr;
|
|
function last_glyph : glyph_cache_ptr;
|
|
|
|
function add_kerning(x ,y : double_ptr ) : boolean;
|
|
|
|
procedure precache(from ,to_ : unsigned );
|
|
procedure reset_cache;
|
|
procedure synchronize;
|
|
|
|
end;
|
|
|
|
{ GLOBAL PROCEDURES }
|
|
|
|
|
|
IMPLEMENTATION
|
|
{ LOCAL VARIABLES & CONSTANTS }
|
|
{ UNIT IMPLEMENTATION }
|
|
{ CONSTRUCT }
|
|
constructor font_cache.Construct;
|
|
begin
|
|
m_allocator.Construct(block_size );
|
|
|
|
m_font_signature:=PChar(m_allocator.allocate(StrLen(font_signature ) + 1 ) );
|
|
|
|
StrCopy (m_font_signature ,font_signature );
|
|
fillchar(m_glyphs ,sizeof(m_glyphs ) ,0 );
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor font_cache.Destruct;
|
|
begin
|
|
m_allocator.Destruct;
|
|
|
|
end;
|
|
|
|
{ FONT_IS }
|
|
function font_cache.font_is;
|
|
begin
|
|
result:=StrComp(font_signature ,m_font_signature ) = 0;
|
|
|
|
end;
|
|
|
|
{ FIND_GLYPH }
|
|
function font_cache.find_glyph;
|
|
var
|
|
msb : unsigned;
|
|
|
|
begin
|
|
msb:=(glyph_code shr 8 ) and $FF;
|
|
|
|
if m_glyphs[msb ] <> NIL then
|
|
result:=
|
|
glyph_cache_ptr_ptr(
|
|
ptrcomp(m_glyphs[msb ] ) + (glyph_code and $FF ) * sizeof(glyph_cache_ptr ) )^
|
|
else
|
|
result:=NIL;
|
|
|
|
end;
|
|
|
|
{ CACHE_GLYPH }
|
|
function font_cache.cache_glyph;
|
|
var
|
|
msb ,lsb : unsigned;
|
|
|
|
glyph : glyph_cache_ptr;
|
|
|
|
begin
|
|
msb:=(glyph_code shr 8 ) and $FF;
|
|
|
|
if m_glyphs[msb ] = NIL then
|
|
begin
|
|
m_glyphs[msb ]:=glyph_cache_ptr_ptr(
|
|
m_allocator.allocate(sizeof(glyph_cache_ptr ) * 256 ,sizeof(glyph_cache_ptr ) ) );
|
|
|
|
fillchar(m_glyphs[msb ]^ ,sizeof(glyph_cache_ptr ) * 256 ,0 );
|
|
|
|
end;
|
|
|
|
lsb:=glyph_code and $FF;
|
|
|
|
if glyph_cache_ptr_ptr(ptrcomp(m_glyphs[msb ] ) + lsb * sizeof(glyph_cache_ptr ) )^ <> NIL then
|
|
begin
|
|
result:=NIL; // Already exists, do not overwrite
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
glyph:=glyph_cache_ptr(m_allocator.allocate(sizeof(glyph_cache ) ,sizeof(double ) ) );
|
|
|
|
glyph.glyph_index:=glyph_index;
|
|
glyph.data :=m_allocator.allocate(data_size );
|
|
glyph.data_size :=data_size;
|
|
glyph.data_type :=data_type;
|
|
glyph.bounds :=bounds^;
|
|
glyph.advance_x :=advance_x;
|
|
glyph.advance_y :=advance_y;
|
|
|
|
glyph_cache_ptr_ptr(ptrcomp(m_glyphs[msb ] ) + lsb * sizeof(glyph_cache_ptr ) )^:=glyph;
|
|
|
|
result:=glyph;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor font_cache_pool.Construct;
|
|
begin
|
|
agg_getmem(pointer(m_fonts ) ,max_fonts * sizeof(font_cache_ptr ) );
|
|
|
|
m_max_fonts:=max_fonts;
|
|
m_num_fonts:=0;
|
|
m_cur_font :=NIL;
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor font_cache_pool.Destruct;
|
|
var
|
|
i : unsigned;
|
|
|
|
fnt : font_cache_ptr_ptr;
|
|
|
|
begin
|
|
fnt:=m_fonts;
|
|
i :=0;
|
|
|
|
while i < m_num_fonts do
|
|
begin
|
|
dispose(fnt^ ,Destruct );
|
|
|
|
inc(ptrcomp(fnt ) ,sizeof(font_cache_ptr ) );
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
agg_freemem(pointer(m_fonts ) ,m_max_fonts * sizeof(font_cache_ptr ) );
|
|
|
|
end;
|
|
|
|
{ FONT_ }
|
|
procedure font_cache_pool.font_;
|
|
var
|
|
idx : int;
|
|
fnt : font_cache_ptr_ptr;
|
|
|
|
begin
|
|
idx:=find_font(font_signature );
|
|
|
|
if idx >= 0 then
|
|
begin
|
|
fnt:=font_cache_ptr_ptr(ptrcomp(m_fonts ) + idx * sizeof(font_cache_ptr ) );
|
|
|
|
if reset_cache then
|
|
begin
|
|
dispose(fnt^ ,Destruct );
|
|
|
|
fnt^:=new(font_cache_ptr ,Construct(font_signature ) );
|
|
|
|
end;
|
|
|
|
m_cur_font:=fnt^;
|
|
|
|
end
|
|
else
|
|
begin
|
|
if m_num_fonts >= m_max_fonts then
|
|
begin
|
|
fnt:=font_cache_ptr_ptr(ptrcomp(m_fonts ) + 1 * sizeof(font_cache_ptr ) );
|
|
|
|
dispose(m_fonts^ ,Destruct );
|
|
move (fnt^ ,m_fonts^ ,(m_max_fonts - 1 ) * sizeof(font_cache_ptr ) );
|
|
|
|
m_num_fonts:=m_max_fonts - 1;
|
|
|
|
end;
|
|
|
|
fnt :=font_cache_ptr_ptr(ptrcomp(m_fonts ) + m_num_fonts * sizeof(font_cache_ptr ) );
|
|
fnt^:=new(font_cache_ptr ,Construct(font_signature ) );
|
|
|
|
m_cur_font:=fnt^;
|
|
|
|
inc(m_num_fonts );
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
{ _FONT }
|
|
function font_cache_pool._font;
|
|
begin
|
|
result:=m_cur_font;
|
|
|
|
end;
|
|
|
|
{ FIND_GLYPH }
|
|
function font_cache_pool.find_glyph;
|
|
begin
|
|
if m_cur_font <> NIL then
|
|
result:=m_cur_font.find_glyph(glyph_code )
|
|
else
|
|
result:=NIL;
|
|
|
|
end;
|
|
|
|
{ CACHE_GLYPH }
|
|
function font_cache_pool.cache_glyph;
|
|
begin
|
|
if m_cur_font <> NIL then
|
|
result:=
|
|
m_cur_font.cache_glyph(
|
|
glyph_code ,
|
|
glyph_index ,
|
|
data_size ,
|
|
data_type ,
|
|
bounds ,
|
|
advance_x ,
|
|
advance_y )
|
|
else
|
|
result:=NIL;
|
|
|
|
end;
|
|
|
|
{ FIND_FONT }
|
|
function font_cache_pool.find_font;
|
|
var
|
|
i : unsigned;
|
|
f : font_cache_ptr_ptr;
|
|
|
|
begin
|
|
i:=0;
|
|
f:=m_fonts;
|
|
|
|
while i < m_num_fonts do
|
|
begin
|
|
if f^.font_is(font_signature ) then
|
|
begin
|
|
result:=i;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
inc(ptrcomp(f ) ,sizeof(font_cache_ptr ) );
|
|
inc(i );
|
|
|
|
end;
|
|
|
|
result:=-1;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor font_cache_manager.Construct(engine : font_engine_ptr; max_fonts : unsigned);
|
|
begin
|
|
m_fonts.Construct(max_fonts );
|
|
|
|
m_engine:=engine;
|
|
|
|
m_change_stamp:=-1;
|
|
|
|
m_prev_glyph:=NIL;
|
|
m_last_glyph:=NIL;
|
|
|
|
if m_engine.flag32 then
|
|
m_path_adaptor:=new(serialized_int32_path_adaptor_ptr ,Construct )
|
|
else
|
|
m_path_adaptor:=new(serialized_int16_path_adaptor_ptr ,Construct );
|
|
|
|
m_gray8_adaptor.Construct;
|
|
m_gray8_scanline.Construct(m_gray8_adaptor.m_sz );
|
|
m_mono_adaptor.Construct;
|
|
m_mono_scanline.Construct;
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor font_cache_manager.Destruct;
|
|
begin
|
|
m_fonts.Destruct;
|
|
|
|
dispose(m_path_adaptor ,Destruct );
|
|
|
|
end;
|
|
|
|
{ GLYPH }
|
|
function font_cache_manager.glyph;
|
|
var
|
|
gl : glyph_cache_ptr;
|
|
|
|
begin
|
|
synchronize;
|
|
|
|
gl:=m_fonts.find_glyph(glyph_code );
|
|
|
|
if gl <> NIL then
|
|
begin
|
|
m_prev_glyph:=m_last_glyph;
|
|
m_last_glyph:=gl;
|
|
|
|
result:=gl;
|
|
|
|
exit;
|
|
|
|
end
|
|
else
|
|
if m_engine.prepare_glyph(glyph_code ) then
|
|
begin
|
|
m_prev_glyph:=m_last_glyph;
|
|
m_last_glyph:=
|
|
m_fonts.cache_glyph(
|
|
glyph_code ,
|
|
m_engine.glyph_index ,
|
|
m_engine.data_size ,
|
|
m_engine.data_type ,
|
|
m_engine.bounds ,
|
|
m_engine.advance_x ,
|
|
m_engine.advance_y );
|
|
|
|
m_engine.write_glyph_to(m_last_glyph.data );
|
|
|
|
result:=m_last_glyph;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
result:=NIL;
|
|
|
|
end;
|
|
|
|
{ INIT_EMBEDDED_ADAPTORS }
|
|
procedure font_cache_manager.init_embedded_adaptors;
|
|
begin
|
|
if gl <> NIL then
|
|
case gl.data_type of
|
|
glyph_data_mono :
|
|
m_mono_adaptor.init(gl.data ,gl.data_size ,x ,y );
|
|
|
|
glyph_data_gray8 :
|
|
m_gray8_adaptor.init(gl.data ,gl.data_size ,x ,y );
|
|
|
|
glyph_data_outline :
|
|
m_path_adaptor.init(gl.data ,gl.data_size ,x ,y ,scale );
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
{ PATH_ADAPTOR }
|
|
function font_cache_manager.path_adaptor;
|
|
begin
|
|
result:=m_path_adaptor;
|
|
|
|
end;
|
|
|
|
{ GRAY8_ADAPTOR }
|
|
function font_cache_manager.gray8_adaptor;
|
|
begin
|
|
result:=@m_gray8_adaptor;
|
|
|
|
end;
|
|
|
|
{ GRAY8_SCANLINE }
|
|
function font_cache_manager.gray8_scanline;
|
|
begin
|
|
result:=@m_gray8_scanline;
|
|
|
|
end;
|
|
|
|
{ MONO_ADAPTOR }
|
|
function font_cache_manager.mono_adaptor;
|
|
begin
|
|
result:=@m_mono_adaptor;
|
|
|
|
end;
|
|
|
|
{ MONO_SCANLINE }
|
|
function font_cache_manager.mono_scanline;
|
|
begin
|
|
result:=@m_mono_scanline;
|
|
|
|
end;
|
|
|
|
{ PREV_GLYPH }
|
|
function font_cache_manager.prev_glyph;
|
|
begin
|
|
result:=m_prev_glyph;
|
|
|
|
end;
|
|
|
|
{ LAST_GLYPH }
|
|
function font_cache_manager.last_glyph;
|
|
begin
|
|
result:=@m_last_glyph;
|
|
|
|
end;
|
|
|
|
{ ADD_KERNING }
|
|
function font_cache_manager.add_kerning;
|
|
begin
|
|
if (m_prev_glyph <> NIL ) and
|
|
(m_last_glyph <> NIL ) then
|
|
result:=
|
|
m_engine.add_kerning(
|
|
m_prev_glyph.glyph_index ,
|
|
m_last_glyph.glyph_index ,x ,y )
|
|
else
|
|
result:=false;
|
|
|
|
end;
|
|
|
|
{ PRECACHE }
|
|
procedure font_cache_manager.precache;
|
|
begin
|
|
while from <= to_ do
|
|
begin
|
|
glyph(from );
|
|
inc (from );
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
{ RESET_CACHE }
|
|
procedure font_cache_manager.reset_cache;
|
|
begin
|
|
m_fonts.font_(m_engine.font_signature ,true );
|
|
|
|
m_change_stamp:=m_engine.change_stamp;
|
|
|
|
m_prev_glyph:=NIL;
|
|
m_last_glyph:=NIL;
|
|
|
|
end;
|
|
|
|
{ SYNCHRONIZE }
|
|
procedure font_cache_manager.synchronize;
|
|
begin
|
|
if m_change_stamp <> m_engine.change_stamp then
|
|
begin
|
|
m_fonts.font_(m_engine.font_signature );
|
|
|
|
m_change_stamp:=m_engine.change_stamp;
|
|
|
|
m_prev_glyph:=NIL;
|
|
m_last_glyph:=NIL;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
END.
|
|
|