lazarus/components/aggpas/src/agg_font_cache_manager.pas
mattias 80fb2b2367 aggpas: 64bit fixes from fpgui aggpas
git-svn-id: trunk@47745 -
2015-02-13 17:45:09 +00:00

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.