1
/***************************************************************************/
5
/* The FreeType glyph rasterizer (body). */
7
/* Copyright 1996-2001, 2002, 2003 by */
8
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10
/* This file is part of the FreeType project, and may only be used, */
11
/* modified, and distributed under the terms of the FreeType project */
12
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13
/* this file you indicate that you have read the license and */
14
/* understand and accept it fully. */
16
/***************************************************************************/
18
/*************************************************************************/
20
/* This is a rewrite of the FreeType 1.x scan-line converter */
22
/*************************************************************************/
27
#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
30
/*************************************************************************/
32
/* A simple technical note on how the raster works */
33
/* ----------------------------------------------- */
35
/* Converting an outline into a bitmap is achieved in several steps: */
37
/* 1 - Decomposing the outline into successive `profiles'. Each */
38
/* profile is simply an array of scanline intersections on a given */
39
/* dimension. A profile's main attributes are */
41
/* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
43
/* o an array of intersection coordinates for each scanline */
44
/* between `Ymin' and `Ymax'. */
46
/* o a direction, indicating whether it was built going `up' or */
47
/* `down', as this is very important for filling rules. */
49
/* 2 - Sweeping the target map's scanlines in order to compute segment */
50
/* `spans' which are then filled. Additionally, this pass */
51
/* performs drop-out control. */
53
/* The outline data is parsed during step 1 only. The profiles are */
54
/* built from the bottom of the render pool, used as a stack. The */
55
/* following graphics shows the profile list under construction: */
57
/* ____________________________________________________________ _ _ */
59
/* | profile | coordinates for | profile | coordinates for |--> */
60
/* | 1 | profile 1 | 2 | profile 2 |--> */
61
/* |_________|___________________|_________|_________________|__ _ _ */
65
/* start of render pool top */
67
/* The top of the profile stack is kept in the `top' variable. */
69
/* As you can see, a profile record is pushed on top of the render */
70
/* pool, which is then followed by its coordinates/intersections. If */
71
/* a change of direction is detected in the outline, a new profile is */
72
/* generated until the end of the outline. */
74
/* Note that when all profiles have been generated, the function */
75
/* Finalize_Profile_Table() is used to record, for each profile, its */
76
/* bottom-most scanline as well as the scanline above its upmost */
77
/* boundary. These positions are called `y-turns' because they (sort */
78
/* of) correspond to local extrema. They are stored in a sorted list */
79
/* built from the top of the render pool as a downwards stack: */
81
/* _ _ _______________________________________ */
83
/* <--| sorted list of | */
84
/* <--| extrema scanlines | */
85
/* _ _ __________________|____________________| */
89
/* maxBuff sizeBuff = end of pool */
91
/* This list is later used during the sweep phase in order to */
92
/* optimize performance (see technical note on the sweep below). */
94
/* Of course, the raster detects whether the two stacks collide and */
95
/* handles the situation propertly. */
97
/*************************************************************************/
100
/*************************************************************************/
101
/*************************************************************************/
103
/** CONFIGURATION MACROS **/
105
/*************************************************************************/
106
/*************************************************************************/
108
/* define DEBUG_RASTER if you want to compile a debugging version */
109
#define xxxDEBUG_RASTER
111
/* The default render pool size in bytes */
112
#define RASTER_RENDER_POOL 8192
114
/* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
115
/* 5-levels anti-aliasing */
116
#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
117
#define FT_RASTER_OPTION_ANTI_ALIASING
120
/* The size of the two-lines intermediate bitmap used */
121
/* for anti-aliasing, in bytes. */
122
#define RASTER_GRAY_LINES 2048
125
/*************************************************************************/
126
/*************************************************************************/
128
/** OTHER MACROS (do not change) **/
130
/*************************************************************************/
131
/*************************************************************************/
133
/*************************************************************************/
135
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
136
/* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
137
/* messages during execution. */
140
#define FT_COMPONENT trace_raster
146
/* This macro is used to indicate that a function parameter is unused. */
147
/* Its purpose is simply to reduce compiler warnings. Note also that */
148
/* simply defining it as `(void)x' doesn't avoid warnings with certain */
149
/* ANSI compilers (e.g. LCC). */
150
#define FT_UNUSED( x ) (x) = (x)
152
/* Disable the tracing mechanism for simplicity -- developers can */
153
/* activate it easily by redefining these two macros. */
155
#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
159
#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
162
#define Raster_Err_None 0
163
#define Raster_Err_Not_Ini -1
164
#define Raster_Err_Overflow -2
165
#define Raster_Err_Neg_Height -3
166
#define Raster_Err_Invalid -4
167
#define Raster_Err_Unsupported -5
170
#else /* _STANDALONE_ */
173
#include FT_INTERNAL_OBJECTS_H
174
#include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
176
#include "rasterrs.h"
178
#define Raster_Err_None Raster_Err_Ok
179
#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
180
#define Raster_Err_Overflow Raster_Err_Raster_Overflow
181
#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
182
#define Raster_Err_Invalid Raster_Err_Invalid_Outline
183
#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
186
#endif /* _STANDALONE_ */
190
#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
194
/* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
195
/* typically a small value and the result of a*b is known to fit into */
197
#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
199
/* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
200
/* for clipping computations. It simply uses the FT_MulDiv() function */
201
/* defined in `ftcalc.h'. */
202
#define SMulDiv FT_MulDiv
204
/* The rasterizer is a very general purpose component; please leave */
205
/* the following redefinitions there (you never know your target */
217
#define NULL (void*)0
229
#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
230
/* Setting this constant to more than 32 is a */
231
/* pure waste of space. */
233
#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
236
/*************************************************************************/
237
/*************************************************************************/
239
/** SIMPLE TYPE DECLARATIONS **/
241
/*************************************************************************/
242
/*************************************************************************/
245
typedef unsigned int UInt;
247
typedef unsigned short UShort, *PUShort;
248
typedef long Long, *PLong;
249
typedef unsigned long ULong;
251
typedef unsigned char Byte, *PByte;
255
typedef union Alignment_
261
} Alignment, *PAlignment;
264
typedef struct TPoint_
281
/* States of each line, arc, and profile */
282
typedef enum TStates_
292
typedef struct TProfile_ TProfile;
293
typedef TProfile* PProfile;
297
FT_F26Dot6 X; /* current coordinate during sweep */
298
PProfile link; /* link to next profile - various purpose */
299
PLong offset; /* start of profile's data in render pool */
300
int flow; /* Profile orientation: Asc/Descending */
301
long height; /* profile's height in scanlines */
302
long start; /* profile's starting scanline */
304
unsigned countL; /* number of lines to step before this */
305
/* profile becomes drawable */
307
PProfile next; /* next profile in same contour, used */
308
/* during drop-out control */
311
typedef PProfile TProfileList;
312
typedef PProfile* PProfileList;
315
/* Simple record used to implement a stack of bands, required */
316
/* by the sub-banding mechanism */
317
typedef struct TBand_
319
Short y_min; /* band's minimum */
320
Short y_max; /* band's maximum */
325
#define AlignProfileSize \
326
( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
329
#ifdef TT_STATIC_RASTER
332
#define RAS_ARGS /* void */
333
#define RAS_ARG /* void */
335
#define RAS_VARS /* void */
336
#define RAS_VAR /* void */
338
#define FT_UNUSED_RASTER do ; while ( 0 )
341
#else /* TT_STATIC_RASTER */
344
#define RAS_ARGS TRaster_Instance* raster,
345
#define RAS_ARG TRaster_Instance* raster
347
#define RAS_VARS raster,
348
#define RAS_VAR raster
350
#define FT_UNUSED_RASTER FT_UNUSED( raster )
353
#endif /* TT_STATIC_RASTER */
356
typedef struct TRaster_Instance_ TRaster_Instance;
359
/* prototypes used for sweep function dispatch */
361
Function_Sweep_Init( RAS_ARGS Short* min,
365
Function_Sweep_Span( RAS_ARGS Short y,
372
Function_Sweep_Step( RAS_ARG );
375
/* NOTE: These operations are only valid on 2's complement processors */
377
#define FLOOR( x ) ( (x) & -ras.precision )
378
#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
379
#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
380
#define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
381
#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
383
/* Note that I have moved the location of some fields in the */
384
/* structure to ensure that the most used variables are used */
385
/* at the top. Thus, their offset can be coded with less */
386
/* opcodes, and it results in a smaller executable. */
388
struct TRaster_Instance_
390
Int precision_bits; /* precision related variables */
396
Int precision_jitter;
398
Int scale_shift; /* == precision_shift for bitmaps */
399
/* == precision_shift+1 for pixmaps */
401
PLong buff; /* The profiles buffer */
402
PLong sizeBuff; /* Render pool size */
403
PLong maxBuff; /* Profiles buffer size */
404
PLong top; /* Current cursor in buffer */
408
Int numTurns; /* number of Y-turns in outline */
410
TPoint* arc; /* current Bezier arc pointer */
412
UShort bWidth; /* target bitmap width */
413
PByte bTarget; /* target bitmap buffer */
414
PByte gTarget; /* target pixmap buffer */
416
Long lastX, lastY, minY, maxY;
418
UShort num_Profs; /* current number of profiles */
420
Bool fresh; /* signals a fresh new profile which */
421
/* 'start' field must be completed */
422
Bool joint; /* signals that the last arc ended */
423
/* exactly on a scanline. Allows */
424
/* removal of doublets */
425
PProfile cProfile; /* current profile */
426
PProfile fProfile; /* head of linked list of profiles */
427
PProfile gProfile; /* contour's first profile in case */
430
TStates state; /* rendering state */
432
FT_Bitmap target; /* description of target bit/pixmap */
435
Long traceOfs; /* current offset in target bitmap */
436
Long traceG; /* current offset in target pixmap */
438
Short traceIncr; /* sweep's increment in target bitmap */
440
Short gray_min_x; /* current min x during gray rendering */
441
Short gray_max_x; /* current max x during gray rendering */
443
/* dispatch variables */
445
Function_Sweep_Init* Proc_Sweep_Init;
446
Function_Sweep_Span* Proc_Sweep_Span;
447
Function_Sweep_Span* Proc_Sweep_Drop;
448
Function_Sweep_Step* Proc_Sweep_Step;
450
Byte dropOutControl; /* current drop_out control method */
452
Bool second_pass; /* indicates wether a horizontal pass */
453
/* should be performed to control */
454
/* drop-out accurately when calling */
455
/* Render_Glyph. Note that there is */
456
/* no horizontal pass during gray */
459
TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
461
TBand band_stack[16]; /* band stack used for sub-banding */
462
Int band_top; /* band stack top */
464
Int count_table[256]; /* Look-up table used to quickly count */
465
/* set bits in a gray 2x2 cell */
469
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
471
Byte grays[5]; /* Palette of gray levels used for */
474
Byte gray_lines[RASTER_GRAY_LINES];
475
/* Intermediate table used to render the */
476
/* graylevels pixmaps. */
477
/* gray_lines is a buffer holding two */
478
/* monochrome scanlines */
480
Short gray_width; /* width in bytes of one monochrome */
481
/* intermediate scanline of gray_lines. */
482
/* Each gray pixel takes 2 bits long there */
484
/* The gray_lines must hold 2 lines, thus with size */
485
/* in bytes of at least `gray_width*2'. */
487
#endif /* FT_RASTER_ANTI_ALIASING */
490
PByte flags; /* current flags table */
491
PUShort outs; /* current outlines table */
494
UShort nPoints; /* number of points in current glyph */
495
Short nContours; /* number of contours in current glyph */
501
#ifdef FT_CONFIG_OPTION_STATIC_RASTER
503
static TRaster_Instance cur_ras;
508
#define ras (*raster)
510
#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
513
/*************************************************************************/
514
/*************************************************************************/
516
/** PROFILES COMPUTATION **/
518
/*************************************************************************/
519
/*************************************************************************/
522
/*************************************************************************/
525
/* Set_High_Precision */
528
/* Sets precision variables according to param flag. */
531
/* High :: Set to True for high precision (typically for ppem < 18), */
532
/* false otherwise. */
535
Set_High_Precision( RAS_ARGS Int High )
539
ras.precision_bits = 10;
540
ras.precision_step = 128;
541
ras.precision_jitter = 24;
545
ras.precision_bits = 6;
546
ras.precision_step = 32;
547
ras.precision_jitter = 2;
550
FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
552
ras.precision = 1 << ras.precision_bits;
553
ras.precision_half = ras.precision / 2;
554
ras.precision_shift = ras.precision_bits - Pixel_Bits;
555
ras.precision_mask = -ras.precision;
559
/*************************************************************************/
565
/* Creates a new profile in the render pool. */
568
/* aState :: The state/orientation of the new profile. */
571
/* SUCCESS on success. FAILURE in case of overflow or of incoherent */
575
New_Profile( RAS_ARGS TStates aState )
579
ras.cProfile = (PProfile)ras.top;
580
ras.fProfile = ras.cProfile;
581
ras.top += AlignProfileSize;
584
if ( ras.top >= ras.maxBuff )
586
ras.error = Raster_Err_Overflow;
592
case Ascending_State:
593
ras.cProfile->flow = Flow_Up;
594
FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
597
case Descending_State:
598
ras.cProfile->flow = Flow_Down;
599
FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
603
FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
604
ras.error = Raster_Err_Invalid;
608
ras.cProfile->start = 0;
609
ras.cProfile->height = 0;
610
ras.cProfile->offset = ras.top;
611
ras.cProfile->link = (PProfile)0;
612
ras.cProfile->next = (PProfile)0;
615
ras.gProfile = ras.cProfile;
625
/*************************************************************************/
631
/* Finalizes the current profile. */
634
/* SUCCESS on success. FAILURE in case of overflow or incoherency. */
637
End_Profile( RAS_ARG )
643
h = (Long)( ras.top - ras.cProfile->offset );
647
FT_ERROR(( "End_Profile: negative height encountered!\n" ));
648
ras.error = Raster_Err_Neg_Height;
654
FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
655
(long)ras.cProfile, ras.cProfile->start, h ));
657
oldProfile = ras.cProfile;
658
ras.cProfile->height = h;
659
ras.cProfile = (PProfile)ras.top;
661
ras.top += AlignProfileSize;
663
ras.cProfile->height = 0;
664
ras.cProfile->offset = ras.top;
665
oldProfile->next = ras.cProfile;
669
if ( ras.top >= ras.maxBuff )
671
FT_TRACE1(( "overflow in End_Profile\n" ));
672
ras.error = Raster_Err_Overflow;
682
/*************************************************************************/
688
/* Inserts a salient into the sorted list placed on top of the render */
692
/* New y scanline position. */
695
/* SUCCESS on success. FAILURE in case of overflow. */
698
Insert_Y_Turn( RAS_ARGS Int y )
704
n = ras.numTurns - 1;
705
y_turns = ras.sizeBuff - ras.numTurns;
707
/* look for first y value that is <= */
708
while ( n >= 0 && y < y_turns[n] )
711
/* if it is <, simply insert it, ignore if == */
712
if ( n >= 0 && y > y_turns[n] )
715
y2 = (Int)y_turns[n];
724
if ( ras.maxBuff <= ras.top )
726
ras.error = Raster_Err_Overflow;
730
ras.sizeBuff[-ras.numTurns] = y;
737
/*************************************************************************/
740
/* Finalize_Profile_Table */
743
/* Adjusts all links in the profiles list. */
746
/* SUCCESS on success. FAILURE in case of overflow. */
749
Finalize_Profile_Table( RAS_ARG )
764
p->link = (PProfile)( p->offset + p->height );
771
bottom = (Int)( p->start - p->height + 1 );
774
p->offset += p->height - 1;
779
bottom = (Int)p->start;
780
top = (Int)( p->start + p->height - 1 );
783
if ( Insert_Y_Turn( RAS_VARS bottom ) ||
784
Insert_Y_Turn( RAS_VARS top + 1 ) )
798
/*************************************************************************/
804
/* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
808
/* None (subdivided Bezier is taken from the top of the stack). */
811
/* This routine is the `beef' of this component. It is _the_ inner */
812
/* loop that should be optimized to hell to get the best performance. */
815
Split_Conic( TPoint* base )
820
base[4].x = base[2].x;
822
a = base[3].x = ( base[2].x + b ) / 2;
823
b = base[1].x = ( base[0].x + b ) / 2;
824
base[2].x = ( a + b ) / 2;
826
base[4].y = base[2].y;
828
a = base[3].y = ( base[2].y + b ) / 2;
829
b = base[1].y = ( base[0].y + b ) / 2;
830
base[2].y = ( a + b ) / 2;
832
/* hand optimized. gcc doesn't seem to be too good at common */
833
/* expression substitution and instruction scheduling ;-) */
837
/*************************************************************************/
843
/* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
847
/* This routine is the `beef' of the component. It is one of _the_ */
848
/* inner loops that should be optimized like hell to get the best */
852
Split_Cubic( TPoint* base )
857
base[6].x = base[3].x;
860
base[1].x = a = ( base[0].x + c + 1 ) >> 1;
861
base[5].x = b = ( base[3].x + d + 1 ) >> 1;
862
c = ( c + d + 1 ) >> 1;
863
base[2].x = a = ( a + c + 1 ) >> 1;
864
base[4].x = b = ( b + c + 1 ) >> 1;
865
base[3].x = ( a + b + 1 ) >> 1;
867
base[6].y = base[3].y;
870
base[1].y = a = ( base[0].y + c + 1 ) >> 1;
871
base[5].y = b = ( base[3].y + d + 1 ) >> 1;
872
c = ( c + d + 1 ) >> 1;
873
base[2].y = a = ( a + c + 1 ) >> 1;
874
base[4].y = b = ( b + c + 1 ) >> 1;
875
base[3].y = ( a + b + 1 ) >> 1;
879
/*************************************************************************/
885
/* Computes the x-coordinates of an ascending line segment and stores */
886
/* them in the render pool. */
889
/* x1 :: The x-coordinate of the segment's start point. */
891
/* y1 :: The y-coordinate of the segment's start point. */
893
/* x2 :: The x-coordinate of the segment's end point. */
895
/* y2 :: The y-coordinate of the segment's end point. */
897
/* miny :: A lower vertical clipping bound value. */
899
/* maxy :: An upper vertical clipping bound value. */
902
/* SUCCESS on success, FAILURE on render pool overflow. */
905
Line_Up( RAS_ARGS Long x1,
913
Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
922
if ( Dy <= 0 || y2 < miny || y1 > maxy )
927
/* Take care: miny-y1 can be a very large value; we use */
928
/* a slow MulDiv function to avoid clipping bugs */
929
x1 += SMulDiv( Dx, miny - y1, Dy );
930
e1 = (Int)TRUNC( miny );
935
e1 = (Int)TRUNC( y1 );
936
f1 = (Int)FRAC( y1 );
941
/* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
942
e2 = (Int)TRUNC( maxy );
947
e2 = (Int)TRUNC( y2 );
948
f2 = (Int)FRAC( y2 );
957
x1 += FMulDiv( Dx, ras.precision - f1, Dy );
968
ras.joint = (char)( f2 == 0 );
972
ras.cProfile->start = e1;
977
if ( ras.top + size >= ras.maxBuff )
979
ras.error = Raster_Err_Overflow;
985
Ix = ( ras.precision * Dx ) / Dy;
986
Rx = ( ras.precision * Dx ) % Dy;
991
Ix = -( ( ras.precision * -Dx ) / Dy );
992
Rx = ( ras.precision * -Dx ) % Dy;
1018
/*************************************************************************/
1024
/* Computes the x-coordinates of an descending line segment and */
1025
/* stores them in the render pool. */
1028
/* x1 :: The x-coordinate of the segment's start point. */
1030
/* y1 :: The y-coordinate of the segment's start point. */
1032
/* x2 :: The x-coordinate of the segment's end point. */
1034
/* y2 :: The y-coordinate of the segment's end point. */
1036
/* miny :: A lower vertical clipping bound value. */
1038
/* maxy :: An upper vertical clipping bound value. */
1041
/* SUCCESS on success, FAILURE on render pool overflow. */
1044
Line_Down( RAS_ARGS Long x1,
1056
result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
1058
if ( fresh && !ras.fresh )
1059
ras.cProfile->start = -ras.cProfile->start;
1065
/* A function type describing the functions used to split Bezier arcs */
1066
typedef void (*TSplitter)( TPoint* base );
1069
/*************************************************************************/
1075
/* Computes the x-coordinates of an ascending Bezier arc and stores */
1076
/* them in the render pool. */
1079
/* degree :: The degree of the Bezier arc (either 2 or 3). */
1081
/* splitter :: The function to split Bezier arcs. */
1083
/* miny :: A lower vertical clipping bound value. */
1085
/* maxy :: An upper vertical clipping bound value. */
1088
/* SUCCESS on success, FAILURE on render pool overflow. */
1091
Bezier_Up( RAS_ARGS Int degree,
1096
Long y1, y2, e, e2, e0;
1110
if ( y2 < miny || y1 > maxy )
1125
f1 = (Short)( FRAC( y1 ) );
1136
*top++ = arc[degree].x;
1144
ras.cProfile->start = TRUNC( e0 );
1151
if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
1154
ras.error = Raster_Err_Overflow;
1160
while ( arc >= start_arc && e <= e2 )
1169
if ( y2 - y1 >= ras.precision_step )
1176
*top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
1202
/*************************************************************************/
1208
/* Computes the x-coordinates of an descending Bezier arc and stores */
1209
/* them in the render pool. */
1212
/* degree :: The degree of the Bezier arc (either 2 or 3). */
1214
/* splitter :: The function to split Bezier arcs. */
1216
/* miny :: A lower vertical clipping bound value. */
1218
/* maxy :: An upper vertical clipping bound value. */
1221
/* SUCCESS on success, FAILURE on render pool overflow. */
1224
Bezier_Down( RAS_ARGS Int degree,
1229
TPoint* arc = ras.arc;
1233
arc[0].y = -arc[0].y;
1234
arc[1].y = -arc[1].y;
1235
arc[2].y = -arc[2].y;
1237
arc[3].y = -arc[3].y;
1241
result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
1243
if ( fresh && !ras.fresh )
1244
ras.cProfile->start = -ras.cProfile->start;
1246
arc[0].y = -arc[0].y;
1251
/*************************************************************************/
1257
/* Injects a new line segment and adjusts Profiles list. */
1260
/* x :: The x-coordinate of the segment's end point (its start point */
1261
/* is stored in `LastX'). */
1263
/* y :: The y-coordinate of the segment's end point (its start point */
1264
/* is stored in `LastY'). */
1267
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1271
Line_To( RAS_ARGS Long x,
1274
/* First, detect a change of direction */
1276
switch ( ras.state )
1279
if ( y > ras.lastY )
1281
if ( New_Profile( RAS_VARS Ascending_State ) )
1286
if ( y < ras.lastY )
1287
if ( New_Profile( RAS_VARS Descending_State ) )
1292
case Ascending_State:
1293
if ( y < ras.lastY )
1295
if ( End_Profile( RAS_VAR ) ||
1296
New_Profile( RAS_VARS Descending_State ) )
1301
case Descending_State:
1302
if ( y > ras.lastY )
1304
if ( End_Profile( RAS_VAR ) ||
1305
New_Profile( RAS_VARS Ascending_State ) )
1314
/* Then compute the lines */
1316
switch ( ras.state )
1318
case Ascending_State:
1319
if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
1320
x, y, ras.minY, ras.maxY ) )
1324
case Descending_State:
1325
if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
1326
x, y, ras.minY, ras.maxY ) )
1341
/*************************************************************************/
1347
/* Injects a new conic arc and adjusts the profile list. */
1350
/* cx :: The x-coordinate of the arc's new control point. */
1352
/* cy :: The y-coordinate of the arc's new control point. */
1354
/* x :: The x-coordinate of the arc's end point (its start point is */
1355
/* stored in `LastX'). */
1357
/* y :: The y-coordinate of the arc's end point (its start point is */
1358
/* stored in `LastY'). */
1361
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1365
Conic_To( RAS_ARGS Long cx,
1370
Long y1, y2, y3, x3, ymin, ymax;
1375
ras.arc[2].x = ras.lastX;
1376
ras.arc[2].y = ras.lastY;
1377
ras.arc[1].x = cx; ras.arc[1].y = cy;
1378
ras.arc[0].x = x; ras.arc[0].y = y;
1387
/* first, categorize the Bezier arc */
1400
if ( y2 < ymin || y2 > ymax )
1402
/* this arc has no given direction, split it! */
1403
Split_Conic( ras.arc );
1406
else if ( y1 == y3 )
1408
/* this arc is flat, ignore it and pop it from the Bezier stack */
1413
/* the arc is y-monotonous, either ascending or descending */
1414
/* detect a change of direction */
1415
state_bez = y1 < y3 ? Ascending_State : Descending_State;
1416
if ( ras.state != state_bez )
1418
/* finalize current profile if any */
1419
if ( ras.state != Unknown_State &&
1420
End_Profile( RAS_VAR ) )
1423
/* create a new profile */
1424
if ( New_Profile( RAS_VARS state_bez ) )
1428
/* now call the appropriate routine */
1429
if ( state_bez == Ascending_State )
1431
if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1435
if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1439
} while ( ras.arc >= ras.arcs );
1451
/*************************************************************************/
1457
/* Injects a new cubic arc and adjusts the profile list. */
1460
/* cx1 :: The x-coordinate of the arc's first new control point. */
1462
/* cy1 :: The y-coordinate of the arc's first new control point. */
1464
/* cx2 :: The x-coordinate of the arc's second new control point. */
1466
/* cy2 :: The y-coordinate of the arc's second new control point. */
1468
/* x :: The x-coordinate of the arc's end point (its start point is */
1469
/* stored in `LastX'). */
1471
/* y :: The y-coordinate of the arc's end point (its start point is */
1472
/* stored in `LastY'). */
1475
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1479
Cubic_To( RAS_ARGS Long cx1,
1486
Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
1491
ras.arc[3].x = ras.lastX;
1492
ras.arc[3].y = ras.lastY;
1493
ras.arc[2].x = cx1; ras.arc[2].y = cy1;
1494
ras.arc[1].x = cx2; ras.arc[1].y = cy2;
1495
ras.arc[0].x = x; ras.arc[0].y = y;
1505
/* first, categorize the Bezier arc */
1529
if ( ymin2 < ymin1 || ymax2 > ymax1 )
1531
/* this arc has no given direction, split it! */
1532
Split_Cubic( ras.arc );
1535
else if ( y1 == y4 )
1537
/* this arc is flat, ignore it and pop it from the Bezier stack */
1542
state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
1544
/* detect a change of direction */
1545
if ( ras.state != state_bez )
1547
if ( ras.state != Unknown_State &&
1548
End_Profile( RAS_VAR ) )
1551
if ( New_Profile( RAS_VARS state_bez ) )
1555
/* compute intersections */
1556
if ( state_bez == Ascending_State )
1558
if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1562
if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1566
} while ( ras.arc >= ras.arcs );
1579
#define SWAP_( x, y ) do \
1589
/*************************************************************************/
1592
/* Decompose_Curve */
1595
/* Scans the outline arays in order to emit individual segments and */
1596
/* Beziers by calling Line_To() and Bezier_To(). It handles all */
1597
/* weird cases, like when the first point is off the curve, or when */
1598
/* there are simply no `on' points in the contour! */
1601
/* first :: The index of the first point in the contour. */
1603
/* last :: The index of the last point in the contour. */
1605
/* flipped :: If set, flip the direction of the curve. */
1608
/* SUCCESS on success, FAILURE on error. */
1611
Decompose_Curve( RAS_ARGS UShort first,
1616
FT_Vector v_control;
1624
unsigned tag; /* current point's state */
1627
points = ras.outline.points;
1628
limit = points + last;
1630
v_start.x = SCALED( points[first].x );
1631
v_start.y = SCALED( points[first].y );
1632
v_last.x = SCALED( points[last].x );
1633
v_last.y = SCALED( points[last].y );
1637
SWAP_( v_start.x, v_start.y );
1638
SWAP_( v_last.x, v_last.y );
1641
v_control = v_start;
1643
point = points + first;
1644
tags = ras.outline.tags + first;
1645
tag = FT_CURVE_TAG( tags[0] );
1647
/* A contour cannot start with a cubic control point! */
1648
if ( tag == FT_CURVE_TAG_CUBIC )
1649
goto Invalid_Outline;
1651
/* check first point to determine origin */
1652
if ( tag == FT_CURVE_TAG_CONIC )
1654
/* first point is conic control. Yes, this happens. */
1655
if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
1657
/* start at last point if it is on the curve */
1663
/* if both first and last points are conic, */
1664
/* start at their middle and record its position */
1666
v_start.x = ( v_start.x + v_last.x ) / 2;
1667
v_start.y = ( v_start.y + v_last.y ) / 2;
1675
ras.lastX = v_start.x;
1676
ras.lastY = v_start.y;
1678
while ( point < limit )
1683
tag = FT_CURVE_TAG( tags[0] );
1687
case FT_CURVE_TAG_ON: /* emit a single line_to */
1692
x = SCALED( point->x );
1693
y = SCALED( point->y );
1697
if ( Line_To( RAS_VARS x, y ) )
1702
case FT_CURVE_TAG_CONIC: /* consume conic arcs */
1703
v_control.x = SCALED( point[0].x );
1704
v_control.y = SCALED( point[0].y );
1707
SWAP_( v_control.x, v_control.y );
1710
if ( point < limit )
1718
tag = FT_CURVE_TAG( tags[0] );
1720
x = SCALED( point[0].x );
1721
y = SCALED( point[0].y );
1726
if ( tag == FT_CURVE_TAG_ON )
1728
if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
1733
if ( tag != FT_CURVE_TAG_CONIC )
1734
goto Invalid_Outline;
1736
v_middle.x = ( v_control.x + x ) / 2;
1737
v_middle.y = ( v_control.y + y ) / 2;
1739
if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1740
v_middle.x, v_middle.y ) )
1749
if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1750
v_start.x, v_start.y ) )
1755
default: /* FT_CURVE_TAG_CUBIC */
1757
Long x1, y1, x2, y2, x3, y3;
1760
if ( point + 1 > limit ||
1761
FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1762
goto Invalid_Outline;
1767
x1 = SCALED( point[-2].x );
1768
y1 = SCALED( point[-2].y );
1769
x2 = SCALED( point[-1].x );
1770
y2 = SCALED( point[-1].y );
1771
x3 = SCALED( point[ 0].x );
1772
y3 = SCALED( point[ 0].y );
1781
if ( point <= limit )
1783
if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
1788
if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
1795
/* close the contour with a line segment */
1796
if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
1803
ras.error = Raster_Err_Invalid;
1810
/*************************************************************************/
1816
/* Converts a glyph into a series of segments and arcs and makes a */
1817
/* profiles list with them. */
1820
/* flipped :: If set, flip the direction of curve. */
1823
/* SUCCESS on success, FAILURE if any error was encountered during */
1827
Convert_Glyph( RAS_ARGS int flipped )
1832
PProfile lastProfile;
1835
ras.fProfile = NULL;
1839
ras.maxBuff = ras.sizeBuff - AlignProfileSize;
1843
ras.cProfile = (PProfile)ras.top;
1844
ras.cProfile->offset = ras.top;
1849
for ( i = 0; i < ras.outline.n_contours; i++ )
1851
ras.state = Unknown_State;
1852
ras.gProfile = NULL;
1854
if ( Decompose_Curve( RAS_VARS (unsigned short)start,
1855
ras.outline.contours[i],
1859
start = ras.outline.contours[i] + 1;
1861
/* We must now see whether the extreme arcs join or not */
1862
if ( FRAC( ras.lastY ) == 0 &&
1863
ras.lastY >= ras.minY &&
1864
ras.lastY <= ras.maxY )
1865
if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
1867
/* Note that ras.gProfile can be nil if the contour was too small */
1870
lastProfile = ras.cProfile;
1871
if ( End_Profile( RAS_VAR ) )
1874
/* close the `next profile in contour' linked list */
1876
lastProfile->next = ras.gProfile;
1879
if ( Finalize_Profile_Table( RAS_VAR ) )
1882
return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
1886
/*************************************************************************/
1887
/*************************************************************************/
1889
/** SCAN-LINE SWEEPS AND DRAWING **/
1891
/*************************************************************************/
1892
/*************************************************************************/
1895
/*************************************************************************/
1899
/* Initializes an empty linked list. */
1902
Init_Linked( TProfileList* l )
1908
/*************************************************************************/
1912
/* Inserts a new profile in a linked list. */
1915
InsNew( PProfileList list,
1918
PProfile *old, current;
1928
if ( x < current->X )
1930
old = ¤t->link;
1934
profile->link = current;
1939
/*************************************************************************/
1943
/* Removes an old profile from a linked list. */
1946
DelOld( PProfileList list,
1949
PProfile *old, current;
1957
if ( current == profile )
1959
*old = current->link;
1963
old = ¤t->link;
1967
/* we should never get there, unless the profile was not part of */
1972
/*************************************************************************/
1976
/* Sorts a trace list. In 95%, the list is already sorted. We need */
1977
/* an algorithm which is fast in this case. Bubble sort is enough */
1981
Sort( PProfileList list )
1983
PProfile *old, current, next;
1986
/* First, set the new X coordinate of each profile */
1990
current->X = *current->offset;
1991
current->offset += current->flow;
1993
current = current->link;
1996
/* Then sort them */
2003
next = current->link;
2007
if ( current->X <= next->X )
2009
old = ¤t->link;
2018
current->link = next->link;
2019
next->link = current;
2025
next = current->link;
2030
/*************************************************************************/
2032
/* Vertical Sweep Procedure Set */
2034
/* These four routines are used during the vertical black/white sweep */
2035
/* phase by the generic Draw_Sweep() function. */
2037
/*************************************************************************/
2040
Vertical_Sweep_Init( RAS_ARGS Short* min,
2043
Long pitch = ras.target.pitch;
2048
ras.traceIncr = (Short)-pitch;
2049
ras.traceOfs = -*min * pitch;
2051
ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
2059
Vertical_Sweep_Span( RAS_ARGS Short y,
2075
/* Drop-out control */
2077
e1 = TRUNC( CEILING( x1 ) );
2079
if ( x2 - x1 - ras.precision <= ras.precision_jitter )
2082
e2 = TRUNC( FLOOR( x2 ) );
2084
if ( e2 >= 0 && e1 < ras.bWidth )
2088
if ( e2 >= ras.bWidth )
2089
e2 = ras.bWidth - 1;
2091
c1 = (Short)( e1 >> 3 );
2092
c2 = (Short)( e2 >> 3 );
2094
f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
2095
f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
2097
if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
2098
if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
2100
target = ras.bTarget + ras.traceOfs + c1;
2107
/* memset() is slower than the following code on many platforms. */
2108
/* This is due to the fact that, in the vast majority of cases, */
2109
/* the span length in bytes is relatively small. */
2119
*target |= ( f1 & f2 );
2125
Vertical_Sweep_Drop( RAS_ARGS Short y,
2135
/* Drop-out control */
2142
if ( e1 == e2 + ras.precision )
2144
switch ( ras.dropOutControl )
2151
e1 = CEILING( (x1 + x2 + 1) / 2 );
2156
/* Drop-out Control Rule #4 */
2158
/* The spec is not very clear regarding rule #4. It */
2159
/* presents a method that is way too costly to implement */
2160
/* while the general idea seems to get rid of `stubs'. */
2162
/* Here, we only get rid of stubs recognized if: */
2166
/* - P_Left and P_Right are in the same contour */
2167
/* - P_Right is the successor of P_Left in that contour */
2168
/* - y is the top of P_Left and P_Right */
2172
/* - P_Left and P_Right are in the same contour */
2173
/* - P_Left is the successor of P_Right in that contour */
2174
/* - y is the bottom of P_Left */
2177
/* FIXXXME: uncommenting this line solves the disappearing */
2178
/* bit problem in the `7' of verdana 10pts, but */
2179
/* makes a new one in the `C' of arial 14pts */
2182
if ( x2 - x1 < ras.precision_half )
2185
/* upper stub test */
2186
if ( left->next == right && left->height <= 0 )
2189
/* lower stub test */
2190
if ( right->next == left && left->start == y )
2194
/* check that the rightmost pixel isn't set */
2198
c1 = (Short)( e1 >> 3 );
2199
f1 = (Short)( e1 & 7 );
2201
if ( e1 >= 0 && e1 < ras.bWidth &&
2202
ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
2205
if ( ras.dropOutControl == 2 )
2208
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2213
return; /* unsupported mode */
2222
if ( e1 >= 0 && e1 < ras.bWidth )
2224
c1 = (Short)( e1 >> 3 );
2225
f1 = (Short)( e1 & 7 );
2227
if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
2228
if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
2230
ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
2236
Vertical_Sweep_Step( RAS_ARG )
2238
ras.traceOfs += ras.traceIncr;
2242
/***********************************************************************/
2244
/* Horizontal Sweep Procedure Set */
2246
/* These four routines are used during the horizontal black/white */
2247
/* sweep phase by the generic Draw_Sweep() function. */
2249
/***********************************************************************/
2252
Horizontal_Sweep_Init( RAS_ARGS Short* min,
2255
/* nothing, really */
2256
FT_UNUSED( raster );
2263
Horizontal_Sweep_Span( RAS_ARGS Short y,
2277
if ( x2 - x1 < ras.precision )
2284
bits = ras.bTarget + ( y >> 3 );
2285
f1 = (Byte)( 0x80 >> ( y & 7 ) );
2289
if ( e1 >= 0 && e1 < ras.target.rows )
2294
p = bits - e1*ras.target.pitch;
2295
if ( ras.target.pitch > 0 )
2296
p += ( ras.target.rows - 1 ) * ras.target.pitch;
2306
Horizontal_Sweep_Drop( RAS_ARGS Short y,
2317
/* During the horizontal sweep, we only take care of drop-outs */
2324
if ( e1 == e2 + ras.precision )
2326
switch ( ras.dropOutControl )
2333
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2339
/* Drop-out Control Rule #4 */
2341
/* The spec is not very clear regarding rule #4. It */
2342
/* presents a method that is way too costly to implement */
2343
/* while the general idea seems to get rid of `stubs'. */
2346
/* rightmost stub test */
2347
if ( left->next == right && left->height <= 0 )
2350
/* leftmost stub test */
2351
if ( right->next == left && left->start == y )
2354
/* check that the rightmost pixel isn't set */
2358
bits = ras.bTarget + ( y >> 3 );
2359
f1 = (Byte)( 0x80 >> ( y & 7 ) );
2361
bits -= e1 * ras.target.pitch;
2362
if ( ras.target.pitch > 0 )
2363
bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2366
e1 < ras.target.rows &&
2370
if ( ras.dropOutControl == 2 )
2373
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2378
return; /* unsupported mode */
2385
bits = ras.bTarget + ( y >> 3 );
2386
f1 = (Byte)( 0x80 >> ( y & 7 ) );
2390
if ( e1 >= 0 && e1 < ras.target.rows )
2392
bits -= e1 * ras.target.pitch;
2393
if ( ras.target.pitch > 0 )
2394
bits += ( ras.target.rows - 1 ) * ras.target.pitch;
2402
Horizontal_Sweep_Step( RAS_ARG )
2404
/* Nothing, really */
2405
FT_UNUSED( raster );
2409
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
2412
/*************************************************************************/
2414
/* Vertical Gray Sweep Procedure Set */
2416
/* These two routines are used during the vertical gray-levels sweep */
2417
/* phase by the generic Draw_Sweep() function. */
2421
/* - The target pixmap's width *must* be a multiple of 4. */
2423
/* - You have to use the function Vertical_Sweep_Span() for the gray */
2426
/*************************************************************************/
2429
Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
2432
Long pitch, byte_len;
2436
*max = ( *max + 3 ) & -2;
2439
pitch = ras.target.pitch;
2441
ras.traceIncr = (Short)byte_len;
2442
ras.traceG = ( *min / 2 ) * byte_len;
2446
ras.traceG += ( ras.target.rows - 1 ) * pitch;
2447
byte_len = -byte_len;
2450
ras.gray_min_x = (Short)byte_len;
2451
ras.gray_max_x = -(Short)byte_len;
2456
Vertical_Gray_Sweep_Step( RAS_ARG )
2459
PByte pix, bit, bit2;
2460
Int* count = ras.count_table;
2464
ras.traceOfs += ras.gray_width;
2466
if ( ras.traceOfs > ras.gray_width )
2468
pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
2471
if ( ras.gray_max_x >= 0 )
2473
Long last_pixel = ras.target.width - 1;
2474
Int last_cell = last_pixel >> 2;
2475
Int last_bit = last_pixel & 3;
2479
if ( ras.gray_max_x >= last_cell && last_bit != 3 )
2481
ras.gray_max_x = last_cell - 1;
2485
if ( ras.gray_min_x < 0 )
2488
bit = ras.bTarget + ras.gray_min_x;
2489
bit2 = bit + ras.gray_width;
2491
c1 = ras.gray_max_x - ras.gray_min_x;
2495
c2 = count[*bit] + count[*bit2];
2499
pix[0] = grays[(c2 >> 12) & 0x000F];
2500
pix[1] = grays[(c2 >> 8 ) & 0x000F];
2501
pix[2] = grays[(c2 >> 4 ) & 0x000F];
2502
pix[3] = grays[ c2 & 0x000F];
2516
c2 = count[*bit] + count[*bit2];
2522
pix[2] = grays[(c2 >> 4 ) & 0x000F];
2524
pix[1] = grays[(c2 >> 8 ) & 0x000F];
2526
pix[0] = grays[(c2 >> 12) & 0x000F];
2536
ras.traceG += ras.traceIncr;
2538
ras.gray_min_x = 32000;
2539
ras.gray_max_x = -32000;
2545
Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
2551
/* nothing, really */
2552
FT_UNUSED( raster );
2562
Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
2573
/* During the horizontal sweep, we only take care of drop-outs */
2579
if ( e1 == e2 + ras.precision )
2581
switch ( ras.dropOutControl )
2588
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2594
/* Drop-out Control Rule #4 */
2596
/* The spec is not very clear regarding rule #4. It */
2597
/* presents a method that is way too costly to implement */
2598
/* while the general idea seems to get rid of `stubs'. */
2601
/* rightmost stub test */
2602
if ( left->next == right && left->height <= 0 )
2605
/* leftmost stub test */
2606
if ( right->next == left && left->start == y )
2609
if ( ras.dropOutControl == 2 )
2612
e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
2617
return; /* unsupported mode */
2626
if ( x2 - x1 >= ras.precision_half )
2627
color = ras.grays[2];
2629
color = ras.grays[1];
2631
e1 = TRUNC( e1 ) / 2;
2632
if ( e1 < ras.target.rows )
2634
pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
2635
if ( ras.target.pitch > 0 )
2636
pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
2638
if ( pixel[0] == ras.grays[0] )
2645
#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
2648
/*************************************************************************/
2650
/* Generic Sweep Drawing routine */
2652
/*************************************************************************/
2655
Draw_Sweep( RAS_ARG )
2657
Short y, y_change, y_height;
2659
PProfile P, Q, P_Left, P_Right;
2661
Short min_Y, max_Y, top, bottom, dropouts;
2663
Long x1, x2, xs, e1, e2;
2665
TProfileList waiting;
2666
TProfileList draw_left, draw_right;
2669
/* Init empty linked lists */
2671
Init_Linked( &waiting );
2673
Init_Linked( &draw_left );
2674
Init_Linked( &draw_right );
2676
/* first, compute min and max Y */
2679
max_Y = (Short)TRUNC( ras.minY );
2680
min_Y = (Short)TRUNC( ras.maxY );
2686
bottom = (Short)P->start;
2687
top = (Short)( P->start + P->height - 1 );
2689
if ( min_Y > bottom ) min_Y = bottom;
2690
if ( max_Y < top ) max_Y = top;
2693
InsNew( &waiting, P );
2698
/* Check the Y-turns */
2699
if ( ras.numTurns == 0 )
2701
ras.error = Raster_Err_Invalid;
2705
/* Now inits the sweep */
2707
ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
2709
/* Then compute the distance of each profile from min_Y */
2715
P->countL = (UShort)( P->start - min_Y );
2724
if ( ras.numTurns > 0 &&
2725
ras.sizeBuff[-ras.numTurns] == min_Y )
2728
while ( ras.numTurns > 0 )
2730
/* look in the waiting list for new activations */
2737
P->countL -= y_height;
2738
if ( P->countL == 0 )
2740
DelOld( &waiting, P );
2745
InsNew( &draw_left, P );
2749
InsNew( &draw_right, P );
2757
/* Sort the drawing lists */
2760
Sort( &draw_right );
2762
y_change = (Short)ras.sizeBuff[-ras.numTurns--];
2763
y_height = (Short)( y_change - y );
2765
while ( y < y_change )
2772
P_Right = draw_right;
2786
if ( x2 - x1 <= ras.precision )
2791
if ( ras.dropOutControl != 0 &&
2792
( e1 > e2 || e2 == e1 + ras.precision ) )
2794
/* a drop out was detected */
2799
/* mark profile for drop-out processing */
2807
ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
2811
P_Left = P_Left->link;
2812
P_Right = P_Right->link;
2815
/* now perform the dropouts _after_ the span drawing -- */
2816
/* drop-outs processing has been moved out of the loop */
2817
/* for performance tuning */
2823
ras.Proc_Sweep_Step( RAS_VAR );
2830
Sort( &draw_right );
2834
/* Now finalize the profiles that needs it */
2840
if ( P->height == 0 )
2841
DelOld( &draw_left, P );
2849
if ( P->height == 0 )
2850
DelOld( &draw_right, P );
2855
/* for gray-scaling, flushes the bitmap scanline cache */
2856
while ( y <= max_Y )
2858
ras.Proc_Sweep_Step( RAS_VAR );
2867
P_Right = draw_right;
2871
if ( P_Left->countL )
2875
dropouts--; /* -- this is useful when debugging only */
2877
ras.Proc_Sweep_Drop( RAS_VARS y,
2884
P_Left = P_Left->link;
2885
P_Right = P_Right->link;
2892
/*************************************************************************/
2895
/* Render_Single_Pass */
2898
/* Performs one sweep with sub-banding. */
2901
/* flipped :: If set, flip the direction of the outline. */
2904
/* Renderer error code. */
2907
Render_Single_Pass( RAS_ARGS Bool flipped )
2912
while ( ras.band_top >= 0 )
2914
ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
2915
ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
2919
ras.error = Raster_Err_None;
2921
if ( Convert_Glyph( RAS_VARS flipped ) )
2923
if ( ras.error != Raster_Err_Overflow )
2926
ras.error = Raster_Err_None;
2931
ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
2934
i = ras.band_stack[ras.band_top].y_min;
2935
j = ras.band_stack[ras.band_top].y_max;
2937
k = (Short)( ( i + j ) / 2 );
2939
if ( ras.band_top >= 7 || k < i )
2942
ras.error = Raster_Err_Invalid;
2947
ras.band_stack[ras.band_top + 1].y_min = k;
2948
ras.band_stack[ras.band_top + 1].y_max = j;
2950
ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
2957
if ( Draw_Sweep( RAS_VAR ) )
2967
/*************************************************************************/
2973
/* Renders a glyph in a bitmap. Sub-banding if needed. */
2976
/* FreeType error code. 0 means success. */
2978
FT_LOCAL_DEF( FT_Error )
2979
Render_Glyph( RAS_ARG )
2984
Set_High_Precision( RAS_VARS ras.outline.flags &
2985
FT_OUTLINE_HIGH_PRECISION );
2986
ras.scale_shift = ras.precision_shift;
2987
ras.dropOutControl = 2;
2988
ras.second_pass = (FT_Byte)( !( ras.outline.flags &
2989
FT_OUTLINE_SINGLE_PASS ) );
2991
/* Vertical Sweep */
2992
ras.Proc_Sweep_Init = Vertical_Sweep_Init;
2993
ras.Proc_Sweep_Span = Vertical_Sweep_Span;
2994
ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
2995
ras.Proc_Sweep_Step = Vertical_Sweep_Step;
2998
ras.band_stack[0].y_min = 0;
2999
ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
3001
ras.bWidth = (unsigned short)ras.target.width;
3002
ras.bTarget = (Byte*)ras.target.buffer;
3004
if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
3007
/* Horizontal Sweep */
3008
if ( ras.second_pass && ras.dropOutControl != 0 )
3010
ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3011
ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
3012
ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
3013
ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3016
ras.band_stack[0].y_min = 0;
3017
ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
3019
if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
3023
return Raster_Err_Ok;
3027
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
3030
/*************************************************************************/
3033
/* Render_Gray_Glyph */
3036
/* Renders a glyph with grayscaling. Sub-banding if needed. */
3039
/* FreeType error code. 0 means success. */
3041
FT_LOCAL_DEF( FT_Error )
3042
Render_Gray_Glyph( RAS_ARG )
3048
Set_High_Precision( RAS_VARS ras.outline.flags &
3049
FT_OUTLINE_HIGH_PRECISION );
3050
ras.scale_shift = ras.precision_shift + 1;
3051
ras.dropOutControl = 2;
3052
ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
3054
/* Vertical Sweep */
3057
ras.band_stack[0].y_min = 0;
3058
ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
3060
ras.bWidth = ras.gray_width;
3061
pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
3063
if ( ras.bWidth > pixel_width )
3064
ras.bWidth = pixel_width;
3066
ras.bWidth = ras.bWidth * 8;
3067
ras.bTarget = (Byte*)ras.gray_lines;
3068
ras.gTarget = (Byte*)ras.target.buffer;
3070
ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
3071
ras.Proc_Sweep_Span = Vertical_Sweep_Span;
3072
ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
3073
ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
3075
error = Render_Single_Pass( RAS_VARS 0 );
3079
/* Horizontal Sweep */
3080
if ( ras.second_pass && ras.dropOutControl != 0 )
3082
ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
3083
ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
3084
ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
3085
ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
3088
ras.band_stack[0].y_min = 0;
3089
ras.band_stack[0].y_max = ras.target.width * 2 - 1;
3091
error = Render_Single_Pass( RAS_VARS 1 );
3096
return Raster_Err_Ok;
3099
#else /* !FT_RASTER_OPTION_ANTI_ALIASING */
3101
FT_LOCAL_DEF( FT_Error )
3102
Render_Gray_Glyph( RAS_ARG )
3106
return Raster_Err_Cannot_Render_Glyph;
3109
#endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
3113
ft_black_init( TRaster_Instance* raster )
3119
/* setup count table */
3120
for ( n = 0; n < 256; n++ )
3122
c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
3124
c = ( ( c << 6 ) & 0x3000 ) |
3125
( ( c << 4 ) & 0x0300 ) |
3126
( ( c << 2 ) & 0x0030 ) |
3129
raster->count_table[n] = (UInt)c;
3132
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
3134
/* set default 5-levels gray palette */
3135
for ( n = 0; n < 5; n++ )
3136
raster->grays[n] = n * 255 / 4;
3138
raster->gray_width = RASTER_GRAY_LINES / 2;
3144
/**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
3145
/**** a static object. *****/
3152
ft_black_new( void* memory,
3153
FT_Raster *araster )
3155
static FT_RasterRec_ the_raster;
3158
*araster = &the_raster;
3159
FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
3160
ft_black_init( &the_raster );
3167
ft_black_done( FT_Raster raster )
3174
#else /* _STANDALONE_ */
3178
ft_black_new( FT_Memory memory,
3179
TRaster_Instance** araster )
3182
TRaster_Instance* raster;
3186
if ( !FT_NEW( raster ) )
3188
raster->memory = memory;
3189
ft_black_init( raster );
3199
ft_black_done( TRaster_Instance* raster )
3201
FT_Memory memory = (FT_Memory)raster->memory;
3206
#endif /* _STANDALONE_ */
3210
ft_black_reset( TRaster_Instance* raster,
3211
const char* pool_base,
3214
if ( raster && pool_base && pool_size >= 4096 )
3217
raster->buff = (PLong)pool_base;
3218
raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
3224
ft_black_set_mode( TRaster_Instance* raster,
3226
const char* palette )
3228
#ifdef FT_RASTER_OPTION_ANTI_ALIASING
3230
if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
3232
/* set 5-levels gray palette */
3233
raster->grays[0] = palette[0];
3234
raster->grays[1] = palette[1];
3235
raster->grays[2] = palette[2];
3236
raster->grays[3] = palette[3];
3237
raster->grays[4] = palette[4];
3242
FT_UNUSED( raster );
3244
FT_UNUSED( palette );
3251
ft_black_render( TRaster_Instance* raster,
3252
FT_Raster_Params* params )
3254
FT_Outline* outline = (FT_Outline*)params->source;
3255
FT_Bitmap* target_map = params->target;
3258
if ( !raster || !raster->buff || !raster->sizeBuff )
3259
return Raster_Err_Not_Ini;
3261
/* return immediately if the outline is empty */
3262
if ( outline->n_points == 0 || outline->n_contours <= 0 )
3263
return Raster_Err_None;
3265
if ( !outline || !outline->contours || !outline->points )
3266
return Raster_Err_Invalid;
3268
if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
3269
return Raster_Err_Invalid;
3271
/* this version of the raster does not support direct rendering, sorry */
3272
if ( params->flags & FT_RASTER_FLAG_DIRECT )
3273
return Raster_Err_Unsupported;
3275
if ( !target_map || !target_map->buffer )
3276
return Raster_Err_Invalid;
3278
ras.outline = *outline;
3279
ras.target = *target_map;
3281
return ( ( params->flags & FT_RASTER_FLAG_AA )
3282
? Render_Gray_Glyph( raster )
3283
: Render_Glyph( raster ) );
3287
const FT_Raster_Funcs ft_standard_raster =
3289
FT_GLYPH_FORMAT_OUTLINE,
3290
(FT_Raster_New_Func) ft_black_new,
3291
(FT_Raster_Reset_Func) ft_black_reset,
3292
(FT_Raster_Set_Mode_Func)ft_black_set_mode,
3293
(FT_Raster_Render_Func) ft_black_render,
3294
(FT_Raster_Done_Func) ft_black_done