lazarus/components/freetype/ttraster.pas
2024-03-05 15:44:22 +01:00

1186 lines
34 KiB
ObjectPascal

(*******************************************************************
*
* TTRaster.Pas v 1.2
*
* The FreeType glyph rasterizer.
*
* Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTES : This version supports the following :
*
* - direct grayscaling
* - sub-banding
* - drop-out modes 4 and 5
* - second pass for complete drop-out control ( bitmap only )
* - variable precision
*
* Re-entrancy is _not_ planned.
*
* Changes between 1.1 and 1.2 :
*
* - no more trace tables, now uses linked list to sort
* coordinates.
*
* - reduced code size using function dispatch within a generic
* draw_sweep function.
*
* - added variable precision for finer rendering at small ppems
*
*
* Note that its interface may change in the future.
*
******************************************************************)
Unit TTRaster;
interface
{$R-} // TODO: Fix out-of-bounds accesses.
{$T-} // TODO: Fix compilation with -Sy.
{$I TTCONFIG.INC}
uses
{$IFDEF VIRTUALPASCAL}
Use32,
{$ENDIF}
SysUtils,
TTError,
TTTypes,
TTProfile;
{$IFDEF CONST_PREC}
const
Precision_Bits = 6;
Precision = 1 shl Precision_Bits;
Precision_Half = Precision div 2;
Precision_Step = Precision_Half;
Precision_Shift = 0;
Precision_Mask = -Precision;
Precision_Jitter = 2;
{$ENDIF}
type
Function_Sweep_Init = procedure( var min, max : Int ) of object;
Function_Sweep_Span = procedure( y : Int;
x1 : TT_F26dot6;
x2 : TT_F26dot6;
Left : TProfile;
Right : TProfile ) of object;
Function_Sweep_Step = procedure of object;
{ TFreeTypeRasterizer }
TFreeTypeRasterizer = class(TFreeTypeCustomRasterizer)
private
Precision_Bits : Int; (* Fractional bits of Raster coordinates *)
Precision : Int;
Precision_Half : Int;
Precision_Step : Int; (* Bezier subdivision minimal step *)
Precision_Shift : Int; (* Shift used to convert coordinates *)
Precision_Mask : Longint; (* integer truncatoin mask *)
Precision_Jitter : Int;
Pool : TRenderPool;(* Profiles buffer a.k.a. Render Pool *)
Cible : TT_Raster_Map; (* Description of target map *)
BWidth : integer;
BCible : PByte; (* target bitmap buffer *)
GCible : PByte; (* target pixmap buffer *)
TraceBOfs : Int; (* current offset in target bitmap *)
TraceBIncr : Int; (* increment to next line in target bitmap *)
TraceGOfs : Int; (* current offset in targer pixmap *)
TraceGIncr : Int; (* increment to next line in target pixmap *)
gray_min_x : Int; (* current min x during gray rendering *)
gray_max_x : Int; (* current max x during gray rendering *)
(* Dispatch variables : *)
Proc_Sweep_Init : Function_Sweep_Init; (* Sweep initialisation *)
Proc_Sweep_Span : Function_Sweep_Span; (* Span drawing *)
Proc_Sweep_Drop : Function_Sweep_Span; (* Drop out control *)
Proc_Sweep_Step : Function_Sweep_Step; (* Sweep line step *)
Proc_Sweep_Direct: TDirectRenderingFunction; (* Direct rendering *)
Direct_X, Direct_Y, Direct_TX: integer;
Points : TT_Points;
Flags : PByte; (* current flags array *)
Outs : TT_PConStarts; (* current endpoints array *)
//nPoints, (* current number of points *)
nContours : Int; (* current number of contours *)
DropOutControl : Byte; (* current drop-out control mode *)
Grays : TT_Gray_Palette;
(* gray palette used during gray-levels rendering *)
(* 0 : background .. 4 : foreground *)
BGray_Data : PByte; { temporary bitmap for grayscale }
BGray_Incr : integer; { increment for temp bitmap }
BGray_End : integer; { ending offset of temporary bitmap }
BGray_Capacity: integer; { current capacity of temp bitmap }
Second_Pass : boolean;
(* indicates wether an horizontal pass should be performed *)
(* to control drop-out accurately when calling Render_Glyph *)
(* Note that there is no horizontal pass during gray render *)
(* better set it off at ppem >= 18 *)
procedure BGray_NeedCapacity(c: integer);
function Draw_Sweep(MinY, MaxY: integer; PixelGrain: integer): boolean;
procedure Horizontal_Gray_Sweep_Drop(y: Int; x1, x2: TT_F26dot6; Left,
Right: TProfile);
procedure Horizontal_Gray_Sweep_Span(y: Int; x1, x2: TT_F26dot6; {%H-}Left,
{%H-}Right: TProfile);
procedure Horizontal_Sweep_Drop(y: Int; x1, x2: TT_F26dot6; Left,
Right: TProfile);
procedure Horizontal_Sweep_Init(var {%H-}min, {%H-}max: Int);
procedure Horizontal_Sweep_Span(y: Int; x1, x2: TT_F26dot6; {%H-}Left,
{%H-}Right: TProfile);
procedure Horizontal_Sweep_Step;
function ProcessCoordinate(var List: TProfile): integer;
procedure Raster_Object_Init;
procedure Raster_Object_Done;
function Render_Single_Pass(vertical: Boolean; OutputMinY, OutputMaxY,
PixelGrain: integer): boolean;
{$IFNDEF CONST_PREC}procedure Set_High_Precision(High: boolean);
procedure Set_Second_Pass(Pass: boolean);
procedure Vertical_Gray_Sweep_Init(var min, {%H-}max: Int);
procedure Vertical_Gray_Sweep_Init_Direct(var min, max: Int);
procedure Vertical_Gray_Sweep_Init_Direct_HQ(var min, max: Int);
procedure Vertical_Gray_Sweep_Init_HQ(var min, {%H-}max: Int);
procedure Vertical_Gray_Sweep_Step;
procedure Vertical_Gray_Sweep_Step_Direct;
procedure Vertical_Gray_Sweep_Step_Direct_HQ;
procedure Vertical_Gray_Sweep_Step_HQ;
procedure Vertical_Sweep_Drop(y: Int; x1, x2: TT_F26dot6; Left,
Right: TProfile);
procedure Vertical_Sweep_Init(var min, {%H-}max: Int);
procedure Vertical_Sweep_Span({%H-}y: Int; x1, x2: TT_F26dot6; {%H-}Left,
{%H-}Right: TProfile);
procedure Vertical_Sweep_Step;
{$ENDIF}
public
function Render_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError; override;
(* Render one glyph in the target bitmap (1-bit per pixel) *)
function Render_Gray_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map;
palette : PTT_Gray_Palette ) : TError; override;
(* Render one gray-level glyph in the target pixmap *)
(* palette points to an array of 5 colors used for the rendering *)
(* use nil to reuse the last palette. Default is VGA graylevels *)
function Render_Gray_Glyph_HQ( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError; override;
function Render_Directly_Gray_Glyph( var glyph : TT_Outline;
x,y,tx,ty: integer;
OnRender: TDirectRenderingFunction;
palette : PTT_Gray_Palette) : TError; override;
function Render_Directly_Gray_Glyph_HQ( var glyph : TT_Outline;
x,y,tx,ty: integer;
OnRender: TDirectRenderingFunction) : TError; override;
procedure Set_Raster_Palette(const {%H-}palette: TT_Gray_Palette); override;
constructor Create;
destructor Destroy; override;
end;
{ These functions round up minimum and maximum value of an interval over
data which is organized by grains of constant size. For example, if
the size of the grain is 4, then minimum values can be 0, 4, 8, etc.
and maximum values can be 3, 7, 11, etc. }
function IncludeFullGrainMin(minValue: integer; Grain: integer): integer;
function IncludeFullGrainMax(maxValue: integer; Grain: integer): integer;
function TTRaster_Init: TError;
procedure TTRaster_Done;
function TTGetDefaultRasterizer: TFreeTypeRasterizer;
implementation
const
Pixel_Bits = 6; (* fractional bits of input coordinates *)
const
LMask : array[0..7] of Byte
= ($FF,$7F,$3F,$1F,$0F,$07,$03,$01);
RMask : array[0..7] of Byte
= ($80,$C0,$E0,$F0,$F8,$FC,$FE,$FF);
(* left and right fill bitmasks *)
var
Count_Table : array[0..255] of Word;
(* Look-up table used to quickly count set bits in a gray 2x2 cell *)
BitCountTable: packed array[0..255] of byte; //number of bits 'on' in a byte
function IncludeFullGrainMin(minValue: integer; Grain: integer): integer;
begin
if minValue mod Grain <> 0 then
begin
if minValue > 0 then
result := minValue - (minValue mod Grain)
else
result := minValue - (Grain - (-minValue) mod Grain);
end else
result := minValue;
end;
function IncludeFullGrainMax(maxValue: integer; Grain: integer): integer;
begin
if maxValue mod Grain <> Grain-1 then
begin
if maxValue > 0 then
result := maxValue + (Grain-1 - (maxValue mod Grain))
else
result := maxValue + (((-maxValue) mod Grain) - 1);
end
else
result := maxValue;
end;
{$IFNDEF CONST_PREC}
(****************************************************************************)
(* *)
(* Function: Set_High_Precision *)
(* *)
(* Description: Sets precision variables according to param flag *)
(* *)
(* Input: High set to True for high precision ( typically for *)
(* ppem < 18 ), false otherwise. *)
(* *)
(****************************************************************************)
procedure TFreeTypeRasterizer.Set_High_Precision( High : boolean );
begin
if High then
begin
Precision_Bits := 10;
Precision_Step := 128;
Precision_Jitter := 24;
end
else
begin
Precision_Bits := 6;
Precision_Step := 32;
Precision_Jitter := 2;
end;
Precision := 1 shl Precision_Bits;
Precision_Half := Precision shr 1;
Precision_Shift := Precision_Bits - Pixel_Bits;
Precision_Mask := -Precision;
if Pool <> nil then Pool.SetPrecision(Precision,Precision_Step);
end;
{$ENDIF}
procedure TFreeTypeRasterizer.Set_Second_Pass( Pass : boolean );
begin
second_pass := pass;
end;
(************************************************)
(* *)
(* Process next coordinate *)
(* Returns: count *)
(* *)
(************************************************)
function TFreeTypeRasterizer.ProcessCoordinate( var List : TProfile ): integer;
var
current : TProfile;
begin
result := 0;
if List = nil then exit;
current := list;
repeat
with current do
begin
X := Pool.Data[offset];
inc( offset, flow );
dec( height );
current := nextInList;
inc(result);
end;
until current = nil;
end;
(********************************************************************)
(* *)
(* Generic Sweep Drawing routine *)
(* *)
(* *)
(* *)
(********************************************************************)
function TFreeTypeRasterizer.Draw_Sweep(MinY,MaxY: integer; PixelGrain: integer) : boolean;
label
Skip_To_Next;
var
y : Int;
P, Q : TProfile;
Top,
Bottom,
min_Y,
max_Y: Int;
x1, x2, xs, e1, e2 : LongInt;
Wait : TProfile;
Draw_Left : TProfile;
Draw_Right : TProfile;
Drop_Left : TProfile;
Drop_Right : TProfile;
P_Left, Q_Left : TProfile;
P_Right, Q_Right : TProfile;
dropouts : Int;
countLeft, countRight: integer;
begin
if Pool.ProfileColl.fProfile = nil then
begin
result := true;
exit;
end;
Draw_Sweep := False;
(* Init the empty linked lists *)
ProfileList_Init( Wait );
ProfileList_Init( Draw_Left );
ProfileList_Init( Draw_Right );
ProfileList_Init( Drop_Left );
ProfileList_Init( Drop_Right );
(* First, compute min Y and max Y *)
max_Y := MinY;
min_Y := MaxY;
P := Pool.ProfileColl.fProfile;
while P <> nil do
with P do
begin
Q := P.nextInColl;
if p.Flow = TT_Flow_Down then
begin //flip coordinates
Dec(p.Start, p.Height-1);
Inc(p.Offset, p.Height-1);
end;
Bottom := P.Start;
Top := Bottom + P.Height-1;
if min_Y > Bottom then min_Y := Bottom;
if max_Y < Top then max_Y := Top;
X := 0;
ProfileList_InsertFirstElement( Wait, P );
P := Q;
end;
min_y := IncludeFullGrainMin(min_y,PixelGrain);
max_y := IncludeFullGrainMax(max_y,PixelGrain);
if min_Y < MinY then min_Y := MinY;
if max_Y > MaxY then max_Y := MaxY;
ProfileList_SortByStart( Wait );
(* Now inits the sweeps *)
Proc_Sweep_Init( min_Y, max_Y );
(* Let's go *)
for y := min_Y to max_Y do
begin
(* Look in the wait list for new activations *)
while (Wait <> nil) and (Wait.Start <= y) do
begin
P := Wait;
ProfileList_Remove(Wait, Wait);
if P.Height > 0 then
case P.Flow of
TT_Flow_Up : ProfileList_InsertFirstElement( Draw_Left, P );
TT_Flow_Down : ProfileList_InsertFirstElement( Draw_Right, P );
else
raise Exception.Create('Unexpected flow');
end;
end;
(* Get next coordinate *)
countLeft := ProcessCoordinate( Draw_Left );
countRight := ProcessCoordinate( Draw_Right );
dropouts := 0;
if countLeft = countRight then
begin
(* sort the drawing lists *)
ProfileList_SortByX( Draw_Left );
ProfileList_SortByX( Draw_Right );
(* Let's trace *)
P_Left := Draw_Left;
P_Right := Draw_Right;
while ( P_Left <> nil ) and (P_Right <> nil) do
begin
{$IFDEF ASSERT}
if P_Right = nil then
Halt(13);
{$ENDIF}
Q_Left := P_Left.nextInList;
Q_Right := P_Right.nextInList;
{$IFDEF ASSERT}
if Q_Right = nil then
Halt(11);
{$ENDIF}
x1 := P_Left.X;
x2 := P_Right.X;
if x1 > x2 then
begin
xs := x1;
x1 := x2;
x2 := xs;
end;
if ( x2-x1 <= Precision ) then
begin
e1 := ( x1+Precision-1 ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if (dropOutControl <> 0) and
((e1 > e2) or (e2 = e1 + Precision)) then
begin
P_Left.x := x1;
P_Right.x := x2;
ProfileList_Remove( Draw_Left, P_Left );
ProfileList_Remove( Draw_Right, P_Right );
ProfileList_AppendToList( Drop_Left, P_Left );
ProfileList_AppendToList( Drop_Right, P_Right );
inc( dropouts );
goto Skip_To_Next;
end
end;
Proc_Sweep_Span( y, x1, x2, P_Left, P_Right );
(* We finalize the Profile if needed *)
if P_Left.height = 0 then
ProfileList_Remove( Draw_Left, P_Left );
if P_Right.height = 0 then
ProfileList_Remove( Draw_Right, P_Right );
Skip_To_Next:
P_Left := Q_Left;
P_Right := Q_Right;
end;
end else
begin
P_Left := Draw_Left;
while ( P_Left <> nil ) do
begin
Q_Left := P_Left.nextInList;
{x1 := P_Left.X;
Proc_Sweep_Span( y, x1-Precision_Half, x1+Precision_Half, P_Left, P_Left );}
if P_Left.height = 0 then
ProfileList_Remove( Draw_Left, P_Left );
P_Left := Q_Left;
end;
P_Right := Draw_Right;
while ( P_Right <> nil ) do
begin
Q_Right := P_Right.nextInList;
{x2 := P_Right.X;
Proc_Sweep_Span( y, x2-Precision_Half, x2+Precision_Half, P_Right, P_Right );}
if P_Right.height = 0 then
ProfileList_Remove( Draw_Right, P_Right );
P_Right := Q_Right;
end;
end;
{$IFDEF ASSERT}
if P_Right <> nil then
Halt(10);
{$ENDIF}
(* Now perform the dropouts only _after_ the span drawing *)
P_Left := Drop_Left;
P_Right := Drop_Right;
while ( dropouts > 0 ) do
begin
Q_Left := P_Left.nextInList;
Q_Right := P_Right.nextInList;
ProfileList_Remove( Drop_Left, P_Left );
ProfileList_Remove( Drop_Right, P_Right );
Proc_Sweep_Drop( y, P_Left.x, P_Right.x, P_Left, P_Right );
if P_Left.height > 0 then
ProfileList_InsertFirstElement( Draw_Left, P_Left );
if P_Right.height > 0 then
ProfileList_InsertFirstElement( Draw_Right, P_Right );
P_Left := Q_Left;
P_Right := Q_Right;
dec( dropouts );
end;
(* Step to next line *)
Proc_Sweep_Step;
end;
Draw_Sweep := True;
end;
{$I ttraster_sweep.inc}
(****************************************************************************)
(* *)
(* Function: Render_Single_Pass *)
(* *)
(* Description: Performs one sweep with sub-banding. *)
(* *)
(* Returns: True on success *)
(* False if any error was encountered during render. *)
(* *)
(****************************************************************************)
function TFreeTypeRasterizer.Render_Single_Pass( vertical : Boolean; OutputMinY, OutputMaxY, PixelGrain: integer ) : boolean;
var
OutputY, OutputBandY, BandHeight: Integer;
begin
Render_Single_Pass := False;
OutputY := OutputMinY;
BandHeight := PixelGrain;
while OutputY+BandHeight < OutputMaxY do BandHeight := BandHeight shl 1;
while OutputY <= OutputMaxY do
begin
Error := Err_Ras_None;
OutputBandY := OutputY+BandHeight-1;
if OutputBandY > OutputMaxY then OutputBandY := OutputMaxY;
Pool.SetBounds(OutputY*Precision,OutputBandY*Precision);
Pool.Clear;
if Pool.Convert_Glyph( vertical, points, flags, outs, nContours ) then
begin
if Draw_Sweep(OutputY, OutputBandY, PixelGrain) then
OutputY := OutputBandY + 1
else
begin
Pool.Clear;
Pool.ReduceCapacity;
exit;
end;
end else
begin
if Error <> Err_Ras_Overflow then exit;
Error := Err_Ras_None;
BandHeight := BandHeight shr 1;
if BandHeight < PixelGrain then
begin
Error := Err_Ras_Invalid;
Pool.Clear;
Pool.ReduceCapacity;
exit;
end;
end;
end;
Pool.Clear;
Pool.ReduceCapacity;
Render_Single_Pass := true;
end;
(****************************************************************************)
(* *)
(* Function: Render_Glyph *)
(* *)
(* Description: Renders a glyph in a bitmap. Sub-banding if needed *)
(* *)
(* Input: AGlyph Glyph record *)
(* *)
(* Returns: True on success *)
(* False if any error was encountered during render. *)
(* *)
(****************************************************************************)
function TFreeTypeRasterizer.Render_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
begin
Render_Glyph := Failure;
if Pool = nil then
begin
Error := Err_Ras_NotIni;
exit;
end;
if glyph.conEnds^[glyph.n_contours-1] > glyph.n_points then
begin
Error := Err_Ras_Invalid_Contours;
exit;
end;
Cible := target;
Outs := glyph.conEnds;
Flags := PByte(glyph.flags);
//nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( glyph.high_precision );
pool.SetScaleShift(precision_shift);
DropOutControl := glyph.dropout_mode;
second_pass := glyph.second_pass;
Error := Err_Ras_None;
(* Vertical Sweep *)
{$IFDEF FPC}
Proc_Sweep_Init := @Vertical_Sweep_Init;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Sweep_Step;
{$ELSE}
Proc_Sweep_Init := Vertical_Sweep_Init;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Sweep_Step;
{$ENDIF}
BWidth := Cible.width;
BCible := PByte( Cible.Buffer );
if not Render_Single_Pass( False, 0,Cible.Rows-1, 1 ) then exit;
(* Horizontal Sweep *)
if Second_Pass then
begin
{$IFDEF FPC}
Proc_Sweep_Init := @Horizontal_Sweep_Init;
Proc_Sweep_Span := @Horizontal_Sweep_Span;
Proc_Sweep_Drop := @Horizontal_Sweep_Drop;
Proc_Sweep_Step := @Horizontal_Sweep_Step;
{$ELSE}
Proc_Sweep_Init := Horizontal_Sweep_Init;
Proc_Sweep_Span := Horizontal_Sweep_Span;
Proc_Sweep_Drop := Horizontal_Sweep_Drop;
Proc_Sweep_Step := Horizontal_Sweep_Step;
{$ENDIF}
BWidth := Cible.rows;
BCible := PByte( Cible.Buffer );
if not Render_Single_Pass( True, 0, Cible.Width-1, 1 ) then exit;
end;
Render_Glyph := Success;
end;
procedure TFreeTypeRasterizer.BGray_NeedCapacity(c: integer);
begin
if c > BGray_Capacity then
begin
if BGray_Data <> nil then freemem(BGray_Data);
BGray_Capacity := c*2;
getmem(BGray_Data, BGray_Capacity);
end;
fillchar(BGray_Data^, c, 0);
end;
(****************************************************************************)
(* *)
(* Function: Render_Gray_Glyph *)
(* *)
(* Description: Renders a glyph with grayscaling. Sub-banding if needed *)
(* *)
(* Input: AGlyph Glyph record *)
(* *)
(* Returns: True on success *)
(* False if any error was encountered during render. *)
(* *)
(****************************************************************************)
function TFreeTypeRasterizer.Render_Gray_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map;
palette : PTT_Gray_Palette ) : TError;
const Zoom = 2;
begin
Render_Gray_Glyph := Failure;
cible := target;
if palette <> nil then
move( palette^, Grays, sizeof(TT_Gray_Palette) );
Outs := Glyph.conEnds;
Flags := PByte(glyph.flags);
//nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( glyph.high_precision );
pool.SetScaleShift(precision_shift+1);
DropOutControl := glyph.dropout_mode;
second_pass := glyph.high_precision;
Error := Err_Ras_None;
BGray_Incr := (Cible.Width*Zoom+7) shr 3;
BGray_End := BGray_Incr*Zoom;
BGray_NeedCapacity(BGray_End);
BWidth := BGray_Incr shl 3;
BCible := PByte( BGray_Data );
GCible := PByte( Cible.Buffer );
{$IFDEF FPC}
Proc_Sweep_Init := @Vertical_Gray_Sweep_Init;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Gray_Sweep_Step;
{$ELSE}
Proc_Sweep_Init := Vertical_Gray_Sweep_Init;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Gray_Sweep_Step;
{$ENDIF}
if not Render_Single_Pass( False, 0, Zoom*Cible.Rows - 1, Zoom ) then exit;
(* Horizontal Sweep *)
if Second_Pass then
begin
{$IFDEF FPC}
Proc_Sweep_Init := @Horizontal_Sweep_Init;
Proc_Sweep_Span := @Horizontal_Gray_Sweep_Span;
Proc_Sweep_Drop := @Horizontal_Gray_Sweep_Drop;
Proc_Sweep_Step := @Horizontal_Sweep_Step;
{$ELSE}
Proc_Sweep_Init := Horizontal_Sweep_Init;
Proc_Sweep_Span := Horizontal_Gray_Sweep_Span;
Proc_Sweep_Drop := Horizontal_Gray_Sweep_Drop;
Proc_Sweep_Step := Horizontal_Sweep_Step;
{$ENDIF}
BWidth := Cible.rows;
GCible := PByte( Cible.Buffer );
if not Render_Single_Pass( True, 0,Cible.Width*Zoom-1, Zoom ) then exit;
end;
Render_Gray_Glyph := Success;
exit;
end;
function TFreeTypeRasterizer.Render_Gray_Glyph_HQ( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
const Zoom = 8;
begin
Render_Gray_Glyph_HQ := Failure;
cible := target;
Outs := Glyph.conEnds;
Flags := PByte(glyph.flags);
//nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( false );
pool.SetScaleShift(precision_shift+3);
DropOutControl := glyph.dropout_mode;
second_pass := false;
Error := Err_Ras_None;
BGray_Incr := (Cible.Width*Zoom+7) shr 3;
BGray_End := BGray_Incr*Zoom;
BGray_NeedCapacity(BGray_End);
BWidth := BGray_Incr shl 3;
BCible := PByte( BGray_Data );
GCible := PByte( Cible.Buffer );
{$IFDEF FPC}
Proc_Sweep_Init := @Vertical_Gray_Sweep_Init_HQ;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Gray_Sweep_Step_HQ;
{$ELSE}
Proc_Sweep_Init := Vertical_Gray_Sweep_Init_HQ;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Gray_Sweep_Step_HQ;
{$ENDIF}
if not Render_Single_Pass( False, 0, Zoom*Cible.Rows - 1, Zoom ) then exit;
Render_Gray_Glyph_HQ := Success;
exit;
end;
{************************ direct rendering ********************}
procedure TFreeTypeRasterizer.Vertical_Gray_Sweep_Init_Direct_HQ( var min, max : Int );
begin
Vertical_Gray_Sweep_Init_HQ ( min, max);
dec(Direct_Y, min div 8);
traceGOfs := 0;
TraceGIncr:= 0;
end;
procedure TFreeTypeRasterizer.Vertical_Gray_Sweep_Step_Direct_HQ;
begin
Vertical_Gray_Sweep_Step_HQ;
If TraceBOfs = 0 then
begin
Proc_Sweep_Direct(Direct_X,Direct_Y,Direct_TX,pointer(GCible));
dec(Direct_Y);
fillchar(cible.Buffer^, cible.Cols, 0);
end;
end;
procedure TFreeTypeRasterizer.Vertical_Gray_Sweep_Init_Direct( var min, max : Int );
begin
Vertical_Gray_Sweep_Init ( min, max);
dec(Direct_Y, min div 2);
traceGOfs := 0;
TraceGIncr:= 0;
end;
procedure TFreeTypeRasterizer.Vertical_Gray_Sweep_Step_Direct;
begin
Vertical_Gray_Sweep_Step;
If TraceBOfs = 0 then
begin
Proc_Sweep_Direct(Direct_X,Direct_Y,Direct_TX,pointer(GCible));
dec(Direct_Y);
fillchar(cible.Buffer^, cible.Cols, 0);
end;
end;
function TFreeTypeRasterizer.Render_Directly_Gray_Glyph(var glyph: TT_Outline; x, y, tx,
ty: integer; OnRender: TDirectRenderingFunction; palette : PTT_Gray_Palette): TError;
const Zoom = 2;
begin
Render_Directly_Gray_Glyph := Failure;
if palette <> nil then
move( palette^, Grays, sizeof(TT_Gray_Palette) );
Direct_X := x;
Direct_Y := y+ty-1;
Direct_TX := tx;
cible.Width := tx;
cible.Rows := ty;
cible.Cols := (cible.Width+3) and not 3;
cible.Flow := TT_Flow_Down;
getmem(cible.Buffer, cible.Cols);
fillchar(cible.Buffer^, cible.Cols, 0);
Outs := Glyph.conEnds;
Flags := PByte(glyph.flags);
//nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( glyph.high_precision );
pool.SetScaleShift(precision_shift+1);
DropOutControl := glyph.dropout_mode;
second_pass := false;
Error := Err_Ras_None;
BGray_Incr := (Cible.Width*Zoom+7) shr 3;
BGray_End := BGray_Incr*Zoom;
BGray_NeedCapacity(BGray_End);
BWidth := BGray_Incr shl 3;
BCible := PByte( BGray_Data );
GCible := PByte( Cible.Buffer );
{$IFDEF FPC}
Proc_Sweep_Init := @Vertical_Gray_Sweep_Init_Direct;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Gray_Sweep_Step_Direct;
Proc_Sweep_Direct:= OnRender;
{$ELSE}
Proc_Sweep_Init := Vertical_Gray_Sweep_Init_Direct;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Gray_Sweep_Step_Direct;
Proc_Sweep_Direct:= OnRender;
{$ENDIF}
if Render_Single_Pass( False, 0, Zoom*Cible.Rows - 1, Zoom ) then
Render_Directly_Gray_Glyph := Success;
freemem(cible.Buffer, cible.Cols);
end;
function TFreeTypeRasterizer.Render_Directly_Gray_Glyph_HQ( var glyph : TT_Outline;
x,y,tx,ty: integer;
OnRender: TDirectRenderingFunction) : TError;
const Zoom = 8;
begin
Render_Directly_Gray_Glyph_HQ := Failure;
Direct_X := x;
Direct_Y := y+ty-1;
Direct_TX := tx;
cible.Width := tx;
cible.Rows := ty;
cible.Cols := (cible.Width+3) and not 3;
cible.Flow := TT_Flow_Down;
getmem(cible.Buffer, cible.Cols);
fillchar(cible.Buffer^, cible.Cols, 0);
Outs := Glyph.conEnds;
Flags := PByte(glyph.flags);
//nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( false );
pool.SetScaleShift(precision_shift+3);
DropOutControl := glyph.dropout_mode;
second_pass := false;
Error := Err_Ras_None;
BGray_Incr := (Cible.Width*Zoom+7) shr 3;
BGray_End := BGray_Incr*Zoom;
BGray_NeedCapacity(BGray_End);
BWidth := BGray_Incr shl 3;
BCible := PByte( BGray_Data );
GCible := PByte( Cible.Buffer );
{$IFDEF FPC}
Proc_Sweep_Init := @Vertical_Gray_Sweep_Init_Direct_HQ;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Gray_Sweep_Step_Direct_HQ;
Proc_Sweep_Direct:= OnRender;
{$ELSE}
Proc_Sweep_Init := Vertical_Gray_Sweep_Init_Direct_HQ;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Gray_Sweep_Step_Direct_HQ;
Proc_Sweep_Direct:= OnRender;
{$ENDIF}
if Render_Single_Pass( False, 0, Zoom*Cible.Rows - 1, Zoom ) then
Render_Directly_Gray_Glyph_HQ := Success;
freemem(cible.Buffer, cible.Cols);
end;
procedure TFreeTypeRasterizer.Set_Raster_Palette(const palette: TT_Gray_Palette);
begin
move( palette, Grays, sizeof(TT_Gray_Palette) );
end;
constructor TFreeTypeRasterizer.Create;
begin
Raster_Object_Init;
end;
destructor TFreeTypeRasterizer.Destroy;
begin
Raster_Object_Done;
end;
(****************************************************************************)
(* *)
(* Function: Init_Rasterizer *)
(* *)
(* Description: Initializes the rasterizer. *)
(* *)
(* Input: rasterBlock target bitmap/pixmap description *)
(* profBuffer pointer to the render pool *)
(* profSize size in bytes of the render pool *)
(* *)
(* Returns: 1 ( always, but we should check parameters ) *)
(* *)
(****************************************************************************)
procedure TFreeTypeRasterizer.Raster_Object_Init;
const
Default_Grays : array[0..4] of Byte
= ( 0, 23, 27, 29, 31 );
var i: integer;
begin
Pool := nil;
BGray_Data := nil;
BGray_Capacity := 0;
(* default Grays takes the gray levels of the standard VGA *)
(* 256 colors mode *)
for i := 0 to high(Grays) do
Grays[i] := Default_Grays[i];
Set_High_Precision(False);
Set_Second_Pass(False);
Pool := TRenderPool.Create(Precision,Precision_Step);
DropOutControl := 2;
Error := Err_Ras_None;
end;
procedure TFreeTypeRasterizer.Raster_Object_Done;
begin
Pool.Free;
if BGray_Data <> nil then
FreeMem( BGray_Data, BGray_Capacity );
end;
var
DefaultRasterizer: TFreeTypeRasterizer;
function TTRaster_Init: TError;
var l,c,i,j: integer;
begin
{ Initialisation of Count_Table }
for i := 0 to 255 do
begin
l := 0;
j := i;
for c := 0 to 3 do
begin
l := l shl 4;
if ( j and $80 <> 0 ) then inc(l);
if ( j and $40 <> 0 ) then inc(l);
j := (j shl 2) and $FF;
end;
Count_table[i] := l;
end;
for i := 0 to 255 do
begin
BitCountTable[i] := (i and 1) + (i shr 1 and 1) + (i shr 2 and 1) + (i shr 3 and 1) +
(i shr 4 and 1) + (i shr 5 and 1) + (i shr 6 and 1) + (i shr 7 and 1);
end;
DefaultRasterizer := nil;
result := Success;
end;
procedure TTRaster_Done;
begin
if DefaultRasterizer <> nil then
DefaultRasterizer.Free;
end;
function TTGetDefaultRasterizer: TFreeTypeRasterizer;
begin
if DefaultRasterizer = nil then
DefaultRasterizer := TFreeTypeRasterizer.Create;
result := DefaultRasterizer;
end;
end.