1
/***************************************************************************/
3
/* qblackraster.c, derived from ftraster.c */
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, ../../3rdparty/freetype/docs/FTL.TXT. By continuing to use, */
13
/* modify, or distribute this file you indicate that you have read */
14
/* the license and understand and accept it fully. */
16
/***************************************************************************/
18
/*************************************************************************/
20
/* This is a rewrite of the FreeType 1.x scan-line converter */
22
/*************************************************************************/
24
/* #define Q_RASTER_DEBUG */
28
typedef long QT_FT_F26Dot6;
29
typedef int QT_FT_Error;
30
typedef int QT_FT_Int;
31
typedef unsigned int QT_FT_UInt;
33
#if defined(Q_WS_WIN64)
34
typedef __int64 QT_FT_Long;
35
typedef unsigned __int64 QT_FT_ULong;
37
typedef long QT_FT_Long;
38
typedef unsigned long QT_FT_ULong;
41
#define QT_FT_Int64 qint64
42
#define QT_FT_Byte uchar
44
#define QT_FT_TRACE1 if (0) printf
45
#define QT_FT_TRACE6 if (0) printf
47
#define Raster_Err_Ok 0
48
#define Raster_Err_Cannot_Render_Glyph 1
50
#define QT_FT_LOCAL_DEF(x) static x
52
#define QT_FT_BEGIN_HEADER
53
#define QT_FT_END_HEADER
54
#include <private/qrasterdefs_p.h>
55
#include <private/qblackraster_p.h>
57
static QT_FT_Long QT_FT_MulDiv(QT_FT_Long a, QT_FT_Long b, QT_FT_Long c)
63
if ( a < 0 ) { a = -a; s = -1; }
64
if ( b < 0 ) { b = -b; s = -s; }
65
if ( c < 0 ) { c = -c; s = -s; }
67
d = (QT_FT_Long)( c > 0 ? ( (QT_FT_Int64)a * b + ( c >> 1 ) ) / c
70
return ( s > 0 ) ? d : -d;
74
#define QT_FT_MEM_ZERO(x, len) memset(x, 0, len);
78
#define MAX(x, y) (x > y ? x : y)
79
#define MIN(x, y) (x < y ? x : y)
82
/*************************************************************************/
84
/* A simple technical note on how the raster works */
85
/* ----------------------------------------------- */
87
/* Converting an outline into a bitmap is achieved in several steps: */
89
/* 1 - Decomposing the outline into successive `profiles'. Each */
90
/* profile is simply an array of scanline intersections on a given */
91
/* dimension. A profile's main attributes are */
93
/* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
95
/* o an array of intersection coordinates for each scanline */
96
/* between `Ymin' and `Ymax'. */
98
/* o a direction, indicating whether it was built going `up' or */
99
/* `down', as this is very important for filling rules. */
101
/* 2 - Sweeping the target map's scanlines in order to compute segment */
102
/* `spans' which are then filled. Additionally, this pass */
103
/* performs drop-out control. */
105
/* The outline data is parsed during step 1 only. The profiles are */
106
/* built from the bottom of the render pool, used as a stack. The */
107
/* following graphics shows the profile list under construction: */
109
/* ____________________________________________________________ _ _ */
111
/* | profile | coordinates for | profile | coordinates for |--> */
112
/* | 1 | profile 1 | 2 | profile 2 |--> */
113
/* |_________|___________________|_________|_________________|__ _ _ */
117
/* start of render pool top */
119
/* The top of the profile stack is kept in the `top' variable. */
121
/* As you can see, a profile record is pushed on top of the render */
122
/* pool, which is then followed by its coordinates/intersections. If */
123
/* a change of direction is detected in the outline, a new profile is */
124
/* generated until the end of the outline. */
126
/* Note that when all profiles have been generated, the function */
127
/* Finalize_Profile_Table() is used to record, for each profile, its */
128
/* bottom-most scanline as well as the scanline above its upmost */
129
/* boundary. These positions are called `y-turns' because they (sort */
130
/* of) correspond to local extrema. They are stored in a sorted list */
131
/* built from the top of the render pool as a downwards stack: */
133
/* _ _ _______________________________________ */
135
/* <--| sorted list of | */
136
/* <--| extrema scanlines | */
137
/* _ _ __________________|____________________| */
141
/* maxBuff sizeBuff = end of pool */
143
/* This list is later used during the sweep phase in order to */
144
/* optimize performance (see technical note on the sweep below). */
146
/* Of course, the raster detects whether the two stacks collide and */
147
/* handles the situation propertly. */
149
/*************************************************************************/
152
/*************************************************************************/
153
/*************************************************************************/
155
/** CONFIGURATION MACROS **/
157
/*************************************************************************/
158
/*************************************************************************/
160
/* define DEBUG_RASTER if you want to compile a debugging version */
161
#define xxxDEBUG_RASTER
163
/* The default render pool size in bytes */
164
#define RASTER_RENDER_POOL 8192
167
/* The size of the two-lines intermediate bitmap used */
168
/* for anti-aliasing, in bytes. */
169
#define RASTER_GRAY_LINES 2048
172
/*************************************************************************/
173
/*************************************************************************/
175
/** OTHER MACROS (do not change) **/
177
/*************************************************************************/
178
/*************************************************************************/
180
/*************************************************************************/
182
/* The macro QT_FT_COMPONENT is used in trace mode. It is an implicit */
183
/* parameter of the QT_FT_TRACE() and QT_FT_ERROR() macros, used to print/log */
184
/* messages during execution. */
186
#undef QT_FT_COMPONENT
187
#define QT_FT_COMPONENT trace_raster
190
/* This macro is used to indicate that a function parameter is unused. */
191
/* Its purpose is simply to reduce compiler warnings. Note also that */
192
/* simply defining it as `(void)x' doesn't avoid warnings with certain */
193
/* ANSI compilers (e.g. LCC). */
194
#define QT_FT_UNUSED( x ) (x) = (x)
196
/* Disable the tracing mechanism for simplicity -- developers can */
197
/* activate it easily by redefining these two macros. */
199
#define QT_FT_ERROR( x ) do ; while ( 0 ) /* nothing */
203
#define QT_FT_TRACE( x ) do ; while ( 0 ) /* nothing */
206
#define Raster_Err_None 0
207
#define Raster_Err_Not_Ini -1
208
#define Raster_Err_Overflow -2
209
#define Raster_Err_Neg_Height -3
210
#define Raster_Err_Invalid -4
211
#define Raster_Err_Unsupported -5
215
#ifndef QT_FT_MEM_SET
216
#define QT_FT_MEM_SET( d, s, c ) qt_ft_memset( d, s, c )
220
/* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
221
/* typically a small value and the result of a*b is known to fit into */
223
#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
225
/* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
226
/* for clipping computations. It simply uses the QT_FT_MulDiv() function */
227
/* defined in `ftcalc.h'. */
228
#define SMulDiv QT_FT_MulDiv
230
/* The rasterizer is a very general purpose component; please leave */
231
/* the following redefinitions there (you never know your target */
243
#define NULL (void*)0
255
#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
256
/* Setting this constant to more than 32 is a */
257
/* pure waste of space. */
259
#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
262
/*************************************************************************/
263
/*************************************************************************/
265
/** SIMPLE TYPE DECLARATIONS **/
267
/*************************************************************************/
268
/*************************************************************************/
271
typedef unsigned int UInt;
273
typedef unsigned short UShort, *PUShort;
275
#if defined(Q_WS_WIN64)
276
typedef __int64 Long, *PLong;
277
typedef unsigned __int64 ULong;
279
typedef long Long, *PLong;
280
typedef unsigned long ULong;
283
typedef unsigned char Byte, *PByte;
287
typedef union Alignment_
293
} Alignment, *PAlignment;
296
typedef struct TPoint_
313
/* States of each line, arc, and profile */
314
typedef enum TStates_
324
typedef struct TProfile_ TProfile;
325
typedef TProfile* PProfile;
329
QT_FT_F26Dot6 X; /* current coordinate during sweep */
330
PProfile link; /* link to next profile - various purpose */
331
PLong offset; /* start of profile's data in render pool */
332
int flow; /* Profile orientation: Asc/Descending */
333
long height; /* profile's height in scanlines */
334
long start; /* profile's starting scanline */
336
unsigned countL; /* number of lines to step before this */
337
/* profile becomes drawable */
340
typedef PProfile TProfileList;
341
typedef PProfile* PProfileList;
344
/* Simple record used to implement a stack of bands, required */
345
/* by the sub-banding mechanism */
346
typedef struct TBand_
348
Short y_min; /* band's minimum */
349
Short y_max; /* band's maximum */
354
#define AlignProfileSize \
355
( ( sizeof ( TProfile ) + ( sizeof ( TProfile ) % sizeof ( Alignment ) ) ) / sizeof ( Long ) )
358
#ifdef TT_STATIC_RASTER
361
#define RAS_ARGS /* void */
362
#define RAS_ARG /* void */
364
#define RAS_VARS /* void */
365
#define RAS_VAR /* void */
367
#define QT_FT_UNUSED_RASTER do ; while ( 0 )
370
#else /* TT_STATIC_RASTER */
373
#define RAS_ARGS TRaster_Instance* raster,
374
#define RAS_ARG TRaster_Instance* raster
376
#define RAS_VARS raster,
377
#define RAS_VAR raster
379
#define QT_FT_UNUSED_RASTER QT_FT_UNUSED( raster )
382
#endif /* TT_STATIC_RASTER */
385
typedef struct TRaster_Instance_ TRaster_Instance;
388
/* prototypes used for sweep function dispatch */
390
Function_Sweep_Init( RAS_ARGS Short* min,
394
Function_Sweep_Span( RAS_ARGS Short y,
401
Function_Sweep_Step( RAS_ARG );
404
/* NOTE: These operations are only valid on 2's complement processors */
406
#define FLOOR( x ) ( (x) & -ras.precision )
407
#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
408
#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
409
#define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
410
#define SCALED( x ) ( ( (x) << ras.scale_shift ) )
412
/* Note that I have moved the location of some fields in the */
413
/* structure to ensure that the most used variables are used */
414
/* at the top. Thus, their offset can be coded with less */
415
/* opcodes, and it results in a smaller executable. */
417
struct TRaster_Instance_
419
Int precision_bits; /* precision related variables */
425
Int precision_jitter;
427
Int scale_shift; /* == precision_shift for bitmaps */
428
/* == precision_shift+1 for pixmaps */
430
PLong buff; /* The profiles buffer */
431
PLong sizeBuff; /* Render pool size */
432
PLong maxBuff; /* Profiles buffer size */
433
PLong top; /* Current cursor in buffer */
437
Int numTurns; /* number of Y-turns in outline */
439
TPoint* arc; /* current Bezier arc pointer */
441
UShort bWidth; /* target bitmap width */
442
PByte bTarget; /* target bitmap buffer */
443
PByte gTarget; /* target pixmap buffer */
445
Long lastX, lastY, minY, maxY;
446
Short minX_dev, maxX_dev; /* vertical bounds in device coords */
448
UShort num_Profs; /* current number of profiles */
450
Bool fresh; /* signals a fresh new profile which */
451
/* 'start' field must be completed */
452
PProfile cProfile; /* current profile */
453
PProfile fProfile; /* head of linked list of profiles */
454
PProfile gProfile; /* contour's first profile in case */
457
TStates state; /* rendering state */
459
QT_FT_Outline outline;
461
Long traceOfs; /* current offset in target bitmap */
462
Long traceG; /* current offset in target pixmap */
464
Short traceIncr; /* sweep's increment in target bitmap */
466
Short gray_min_x; /* current min x during gray rendering */
467
Short gray_max_x; /* current max x during gray rendering */
469
/* dispatch variables */
471
Function_Sweep_Init* Proc_Sweep_Init;
472
Function_Sweep_Span* Proc_Sweep_Span;
473
Function_Sweep_Step* Proc_Sweep_Step;
475
TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
477
TBand band_stack[16]; /* band stack used for sub-banding */
478
Int band_top; /* band stack top */
483
PByte flags; /* current flags table */
484
PUShort outs; /* current outlines table */
485
QT_FT_Vector* coords;
487
UShort nPoints; /* number of points in current glyph */
488
Short nContours; /* number of contours in current glyph */
491
QT_FT_SpanFunc black_spans;
493
Bool odd_even; /* True for odd even fills */
494
QT_FT_BBox clip_box; /* The clipping box */
498
#ifdef QT_FT_CONFIG_OPTION_STATIC_RASTER
500
static TRaster_Instance cur_ras;
505
#define ras (*raster)
507
#endif /* QT_FT_CONFIG_OPTION_STATIC_RASTER */
510
/*************************************************************************/
511
/*************************************************************************/
513
/** PROFILES COMPUTATION **/
515
/*************************************************************************/
516
/*************************************************************************/
519
/*************************************************************************/
522
/* Set_High_Precision */
525
/* Sets precision variables according to param flag. */
528
/* High :: Set to True for high precision (typically for ppem < 18), */
529
/* false otherwise. */
532
Set_High_Precision( RAS_ARGS Int High )
536
ras.precision_bits = 10;
537
ras.precision_step = 128;
538
ras.precision_jitter = 24;
542
ras.precision_bits = 6;
543
ras.precision_step = 32;
544
ras.precision_jitter = 2;
547
QT_FT_TRACE6( "Set_High_Precision(%s)\n", High ? "true" : "false" );
549
ras.precision = 1 << ras.precision_bits;
550
ras.precision_half = ras.precision / 2;
551
ras.precision_shift = ras.precision_bits - Pixel_Bits;
552
ras.precision_mask = -ras.precision;
556
/*************************************************************************/
562
/* Creates a new profile in the render pool. */
565
/* aState :: The state/orientation of the new profile. */
568
/* SUCCESS on success. FAILURE in case of overflow or of incoherent */
572
New_Profile( RAS_ARGS TStates aState )
576
ras.cProfile = (PProfile)ras.top;
577
ras.fProfile = ras.cProfile;
578
ras.top += AlignProfileSize;
581
if ( ras.top >= ras.maxBuff )
583
ras.error = Raster_Err_Overflow;
589
case Ascending_State:
590
ras.cProfile->flow = Flow_Up;
591
QT_FT_TRACE6( "\nNew ascending profile = %lx\n", (long)ras.cProfile );
594
case Descending_State:
595
ras.cProfile->flow = Flow_Down;
596
QT_FT_TRACE6( "\nNew descending profile = %lx\n", (long)ras.cProfile );
600
QT_FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
601
ras.error = Raster_Err_Invalid;
605
ras.cProfile->start = 0;
606
ras.cProfile->height = 0;
607
ras.cProfile->offset = ras.top;
608
ras.cProfile->link = (PProfile)0;
611
ras.gProfile = ras.cProfile;
620
/*************************************************************************/
626
/* Finalizes the current profile. */
629
/* SUCCESS on success. FAILURE in case of overflow or incoherency. */
632
End_Profile( RAS_ARG )
637
h = (Long)( ras.top - ras.cProfile->offset );
641
QT_FT_ERROR(( "End_Profile: negative height encountered!\n" ));
642
ras.error = Raster_Err_Neg_Height;
648
QT_FT_TRACE6( "Ending profile %lx, start = %ld, height = %ld top=%p\n\n",
649
(long)ras.cProfile, ras.cProfile->start, h,ras.top );
651
oldProfile = ras.cProfile;
652
ras.cProfile->height = h;
653
ras.cProfile = (PProfile)ras.top;
655
ras.top += AlignProfileSize;
657
ras.cProfile->height = 0;
658
ras.cProfile->offset = ras.top;
662
if ( ras.top >= ras.maxBuff )
664
QT_FT_TRACE1( "overflow in End_Profile\n" );
665
ras.error = Raster_Err_Overflow;
673
/*************************************************************************/
679
/* Inserts a salient into the sorted list placed on top of the render */
683
/* New y scanline position. */
686
/* SUCCESS on success. FAILURE in case of overflow. */
689
Insert_Y_Turn( RAS_ARGS Int y )
695
n = ras.numTurns - 1;
696
y_turns = ras.sizeBuff - ras.numTurns;
698
/* look for first y value that is <= */
699
while ( n >= 0 && y < y_turns[n] )
702
/* if it is <, simply insert it, ignore if == */
703
if ( n >= 0 && y > y_turns[n] )
706
y2 = (Int)y_turns[n];
715
if ( ras.maxBuff <= ras.top )
717
ras.error = Raster_Err_Overflow;
721
ras.sizeBuff[-ras.numTurns] = y;
728
/*************************************************************************/
731
/* Finalize_Profile_Table */
734
/* Adjusts all links in the profiles list. */
737
/* SUCCESS on success. FAILURE in case of overflow. */
740
Finalize_Profile_Table( RAS_ARG )
755
p->link = (PProfile)( p->offset + p->height );
762
bottom = (Int)( p->start - p->height + 1 );
765
p->offset += p->height - 1;
770
bottom = (Int)p->start;
771
top = (Int)( p->start + p->height - 1 );
774
if ( Insert_Y_Turn( RAS_VARS bottom ) ||
775
Insert_Y_Turn( RAS_VARS top + 1 ) )
789
/*************************************************************************/
795
/* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
799
/* None (subdivided Bezier is taken from the top of the stack). */
802
/* This routine is the `beef' of this component. It is _the_ inner */
803
/* loop that should be optimized to hell to get the best performance. */
806
Split_Conic( TPoint* base )
811
base[4].x = base[2].x;
813
a = base[3].x = ( base[2].x + b ) / 2;
814
b = base[1].x = ( base[0].x + b ) / 2;
815
base[2].x = ( a + b ) / 2;
817
base[4].y = base[2].y;
819
a = base[3].y = ( base[2].y + b ) / 2;
820
b = base[1].y = ( base[0].y + b ) / 2;
821
base[2].y = ( a + b ) / 2;
823
/* hand optimized. gcc doesn't seem to be too good at common */
824
/* expression substitution and instruction scheduling ;-) */
828
/*************************************************************************/
834
/* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
838
/* This routine is the `beef' of the component. It is one of _the_ */
839
/* inner loops that should be optimized like hell to get the best */
843
Split_Cubic( TPoint* base )
848
base[6].x = base[3].x;
851
base[1].x = a = ( base[0].x + c + 1 ) >> 1;
852
base[5].x = b = ( base[3].x + d + 1 ) >> 1;
853
c = ( c + d + 1 ) >> 1;
854
base[2].x = a = ( a + c + 1 ) >> 1;
855
base[4].x = b = ( b + c + 1 ) >> 1;
856
base[3].x = ( a + b + 1 ) >> 1;
858
base[6].y = base[3].y;
861
base[1].y = a = ( base[0].y + c + 1 ) >> 1;
862
base[5].y = b = ( base[3].y + d + 1 ) >> 1;
863
c = ( c + d + 1 ) >> 1;
864
base[2].y = a = ( a + c + 1 ) >> 1;
865
base[4].y = b = ( b + c + 1 ) >> 1;
866
base[3].y = ( a + b + 1 ) >> 1;
870
/*************************************************************************/
876
/* Computes the x-coordinates of an ascending line segment and stores */
877
/* them in the render pool. */
880
/* x1 :: The x-coordinate of the segment's start point. */
882
/* y1 :: The y-coordinate of the segment's start point. */
884
/* x2 :: The x-coordinate of the segment's end point. */
886
/* y2 :: The y-coordinate of the segment's end point. */
888
/* miny :: A lower vertical clipping bound value. */
890
/* maxy :: An upper vertical clipping bound value. */
893
/* SUCCESS on success, FAILURE on render pool overflow. */
896
Line_Up( RAS_ARGS Long x1,
904
Int e1, e2, f1, size; /* XXX: is `Short' sufficient? */
914
if ( Dy <= 0 || y2 < miny || y1 > maxy )
919
/* Take care: miny-y1 can be a very large value; we use */
920
/* a slow MulDiv function to avoid clipping bugs */
921
x1 += SMulDiv( Dx, miny - y1, Dy );
922
e1 = (Int)TRUNC( CEILING(miny) );
928
e1 = (Int)TRUNC( CEILING(y1) );
929
f1 = (Int)FRAC( y1 );
934
/* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
935
e2 = (Int)TRUNC( FLOOR(maxy) );
939
e2 = (Int)TRUNC( FLOOR(y2) );
940
if (FRAC(y2) == 0 && ras.cProfile->flow == Flow_Up)
943
QT_FT_TRACE6("Line_Up y1=%f, y2=%f, e1=%d, e2=%d f1=%d\n", y1/64., y2/64., e1, e2, f1);
947
x1 += FMulDiv( Dx, ras.precision - f1, Dy );
948
} else if (ras.cProfile->flow == Flow_Down && !clipped ) {
950
x1 += FMulDiv( Dx, ras.precision, Dy);
955
ras.cProfile->start = e1;
958
QT_FT_TRACE6("e1 = start=%d, e2=%d\n", e1, e2);
961
if ( ras.top + size >= ras.maxBuff )
963
ras.error = Raster_Err_Overflow;
969
Ix = ( ras.precision * Dx ) / Dy;
970
Rx = ( ras.precision * Dx ) % Dy;
975
Ix = -( ( ras.precision * -Dx ) / Dy );
976
Rx = ( ras.precision * -Dx ) % Dy;
983
QT_FT_TRACE6("line_up (%f/%f)->(%f/%f), flow=%s\n",
984
x1/64., y1/64., x2/64., y2/64.,
985
ras.cProfile->flow == Flow_Up ? "Flow_Up" : "Flow_Down");
990
QT_FT_TRACE6(" x=%f y=%d\n", x1/64., e2+1-size);
1008
/*************************************************************************/
1014
/* Computes the x-coordinates of an descending line segment and */
1015
/* stores them in the render pool. */
1018
/* x1 :: The x-coordinate of the segment's start point. */
1020
/* y1 :: The y-coordinate of the segment's start point. */
1022
/* x2 :: The x-coordinate of the segment's end point. */
1024
/* y2 :: The y-coordinate of the segment's end point. */
1026
/* miny :: A lower vertical clipping bound value. */
1028
/* maxy :: An upper vertical clipping bound value. */
1031
/* SUCCESS on success, FAILURE on render pool overflow. */
1034
Line_Down( RAS_ARGS Long x1,
1046
result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
1048
if ( fresh && !ras.fresh )
1049
ras.cProfile->start = -ras.cProfile->start;
1055
/* A function type describing the functions used to split Bezier arcs */
1056
typedef void (*TSplitter)( TPoint* base );
1059
/*************************************************************************/
1065
/* Computes the x-coordinates of an ascending Bezier arc and stores */
1066
/* them in the render pool. */
1069
/* degree :: The degree of the Bezier arc (either 2 or 3). */
1071
/* splitter :: The function to split Bezier arcs. */
1073
/* miny :: A lower vertical clipping bound value. */
1075
/* maxy :: An upper vertical clipping bound value. */
1078
/* SUCCESS on success, FAILURE on render pool overflow. */
1081
Bezier_Up( RAS_ARGS Int degree,
1099
if ( y2 < miny || y1 > maxy )
1105
if (FRAC(y2) == 0 && ras.cProfile->flow == Flow_Up)
1106
e2 -= ras.precision;
1113
if (FRAC(y1) == 0 && ras.cProfile->flow == Flow_Down)
1119
ras.cProfile->start = TRUNC( e );
1123
QT_FT_TRACE6("bezier_up: y1=%f, y2=%f, e1=%f, e2=%f\n", y1/64., y2/64., e/64., e2/64.);
1128
if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
1131
ras.error = Raster_Err_Overflow;
1135
QT_FT_TRACE6(" Flow = %s start=%ld, e=%f, e2=%f y1=%f, y2=%f\n",
1136
ras.cProfile->flow == Flow_Up ? "Flow_Up" : "Flow_Down",
1137
ras.cProfile->start, e/64., e2/64.,y1/64.,y2/64.);
1141
while ( arc >= start_arc && e <= e2 )
1148
if ( y2 - y1 >= ras.precision_step )
1155
*top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
1157
QT_FT_TRACE6(" x=%f y=%f\n",
1158
(arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
1159
e - y1, y2 - y1 ))/64., e/64.);
1169
QT_FT_TRACE6(" x=%f y=%f\n", arc[0].x/64., e/64.);
1180
QT_FT_TRACE6(" currently %d points in profile, start=%ld top=%p\n", (int)(ras.top - ras.cProfile->offset), ras.cProfile->start, ras.top);
1185
/*************************************************************************/
1191
/* Computes the x-coordinates of an descending Bezier arc and stores */
1192
/* them in the render pool. */
1195
/* degree :: The degree of the Bezier arc (either 2 or 3). */
1197
/* splitter :: The function to split Bezier arcs. */
1199
/* miny :: A lower vertical clipping bound value. */
1201
/* maxy :: An upper vertical clipping bound value. */
1204
/* SUCCESS on success, FAILURE on render pool overflow. */
1207
Bezier_Down( RAS_ARGS Int degree,
1212
TPoint* arc = ras.arc;
1216
arc[0].y = -arc[0].y;
1217
arc[1].y = -arc[1].y;
1218
arc[2].y = -arc[2].y;
1220
arc[3].y = -arc[3].y;
1224
result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
1226
if ( fresh && !ras.fresh )
1227
ras.cProfile->start = -ras.cProfile->start;
1229
arc[0].y = -arc[0].y;
1234
/*************************************************************************/
1240
/* Injects a new line segment and adjusts Profiles list. */
1243
/* x :: The x-coordinate of the segment's end point (its start point */
1244
/* is stored in `LastX'). */
1246
/* y :: The y-coordinate of the segment's end point (its start point */
1247
/* is stored in `LastY'). */
1250
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1254
Line_To( RAS_ARGS Long x,
1257
/* First, detect a change of direction */
1258
QT_FT_TRACE6( "Line_To (%f/%f)->(%f/%f)\n", ras.lastX/64., ras.lastY/64., x/64., y/64. );
1260
switch ( ras.state )
1263
if ( y > ras.lastY )
1265
if ( New_Profile( RAS_VARS Ascending_State ) )
1270
if ( y < ras.lastY )
1271
if ( New_Profile( RAS_VARS Descending_State ) )
1276
case Ascending_State:
1277
if ( y < ras.lastY )
1279
if ( End_Profile( RAS_VAR ) ||
1280
New_Profile( RAS_VARS Descending_State ) )
1285
case Descending_State:
1286
if ( y > ras.lastY )
1288
if ( End_Profile( RAS_VAR ) ||
1289
New_Profile( RAS_VARS Ascending_State ) )
1298
/* Then compute the lines */
1300
switch ( ras.state )
1302
case Ascending_State:
1303
if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
1304
x, y, ras.minY, ras.maxY ) )
1308
case Descending_State:
1309
if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
1310
x, y, ras.minY, ras.maxY ) )
1325
/*************************************************************************/
1331
/* Injects a new conic arc and adjusts the profile list. */
1334
/* cx :: The x-coordinate of the arc's new control point. */
1336
/* cy :: The y-coordinate of the arc's new control point. */
1338
/* x :: The x-coordinate of the arc's end point (its start point is */
1339
/* stored in `LastX'). */
1341
/* y :: The y-coordinate of the arc's end point (its start point is */
1342
/* stored in `LastY'). */
1345
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1349
Conic_To( RAS_ARGS Long cx,
1354
Long y1, y2, y3, x3, ymin, ymax;
1357
QT_FT_TRACE6( "Conic_To (%f/%f)-(%f/%f)\n", cx/64., cy/64., x/64., y/64. );
1360
ras.arc[2].x = ras.lastX;
1361
ras.arc[2].y = ras.lastY;
1362
ras.arc[1].x = cx; ras.arc[1].y = cy;
1363
ras.arc[0].x = x; ras.arc[0].y = y;
1372
/* first, categorize the Bezier arc */
1385
if ( y2 < ymin || y2 > ymax )
1387
/* this arc has no given direction, split it! */
1388
Split_Conic( ras.arc );
1391
else if ( y1 == y3 )
1393
/* this arc is flat, ignore it and pop it from the Bezier stack */
1398
/* the arc is y-monotonous, either ascending or descending */
1399
/* detect a change of direction */
1400
state_bez = y1 < y3 ? Ascending_State : Descending_State;
1401
if ( ras.state != state_bez )
1403
/* finalize current profile if any */
1404
if ( ras.state != Unknown_State &&
1405
End_Profile( RAS_VAR ) )
1408
/* create a new profile */
1409
if ( New_Profile( RAS_VARS state_bez ) )
1413
/* now call the appropriate routine */
1414
if ( state_bez == Ascending_State )
1416
if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1420
if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
1424
} while ( ras.arc >= ras.arcs );
1436
/*************************************************************************/
1442
/* Injects a new cubic arc and adjusts the profile list. */
1445
/* cx1 :: The x-coordinate of the arc's first new control point. */
1447
/* cy1 :: The y-coordinate of the arc's first new control point. */
1449
/* cx2 :: The x-coordinate of the arc's second new control point. */
1451
/* cy2 :: The y-coordinate of the arc's second new control point. */
1453
/* x :: The x-coordinate of the arc's end point (its start point is */
1454
/* stored in `LastX'). */
1456
/* y :: The y-coordinate of the arc's end point (its start point is */
1457
/* stored in `LastY'). */
1460
/* SUCCESS on success, FAILURE on render pool overflow or incorrect */
1464
Cubic_To( RAS_ARGS Long cx1,
1471
Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
1474
QT_FT_TRACE6( "Cubic_To (%f/%f)-(%f/%f)-(%f/%f)-(%f/%f)\n",
1475
ras.lastX/64., ras.lastY/64., cx1/64., cy1/64., cx2/64., cy2/64., x/64., y/64. );
1478
ras.arc[3].x = ras.lastX;
1479
ras.arc[3].y = ras.lastY;
1480
ras.arc[2].x = cx1; ras.arc[2].y = cy1;
1481
ras.arc[1].x = cx2; ras.arc[1].y = cy2;
1482
ras.arc[0].x = x; ras.arc[0].y = y;
1492
/* first, categorize the Bezier arc */
1516
if ( ymin2 < ymin1 || ymax2 > ymax1 )
1518
/* this arc has no given direction, split it! */
1519
Split_Cubic( ras.arc );
1522
else if ( y1 == y4 )
1524
/* this arc is flat, ignore it and pop it from the Bezier stack */
1529
state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
1531
/* detect a change of direction */
1532
if ( ras.state != state_bez )
1534
if ( ras.state != Unknown_State &&
1535
End_Profile( RAS_VAR ) )
1538
if ( New_Profile( RAS_VARS state_bez ) )
1542
/* compute intersections */
1543
if ( state_bez == Ascending_State )
1545
if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1549
if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
1553
} while ( ras.arc >= ras.arcs );
1566
#define SWAP_( x, y ) do \
1576
/*************************************************************************/
1579
/* Decompose_Curve */
1582
/* Scans the outline arays in order to emit individual segments and */
1583
/* Beziers by calling Line_To() and Bezier_To(). It handles all */
1584
/* weird cases, like when the first point is off the curve, or when */
1585
/* there are simply no `on' points in the contour! */
1588
/* first :: The index of the first point in the contour. */
1590
/* last :: The index of the last point in the contour. */
1592
/* flipped :: If set, flip the direction of the curve. */
1595
/* SUCCESS on success, FAILURE on error. */
1598
Decompose_Curve( RAS_ARGS UShort first,
1602
QT_FT_Vector v_last;
1603
QT_FT_Vector v_control;
1604
QT_FT_Vector v_start;
1606
QT_FT_Vector* points;
1607
QT_FT_Vector* point;
1608
QT_FT_Vector* limit;
1611
unsigned tag; /* current point's state */
1614
points = ras.outline.points;
1615
limit = points + last;
1617
v_start.x = SCALED( points[first].x );
1618
v_start.y = SCALED( points[first].y );
1619
v_last.x = SCALED( points[last].x );
1620
v_last.y = SCALED( points[last].y );
1624
SWAP_( v_start.x, v_start.y );
1625
SWAP_( v_last.x, v_last.y );
1628
v_control = v_start;
1630
point = points + first;
1631
tags = ras.outline.tags + first;
1632
tag = QT_FT_CURVE_TAG( tags[0] );
1634
/* A contour cannot start with a cubic control point! */
1635
if ( tag == QT_FT_CURVE_TAG_CUBIC )
1636
goto Invalid_Outline;
1638
/* check first point to determine origin */
1639
if ( tag == QT_FT_CURVE_TAG_CONIC )
1641
/* first point is conic control. Yes, this happens. */
1642
if ( QT_FT_CURVE_TAG( ras.outline.tags[last] ) == QT_FT_CURVE_TAG_ON )
1644
/* start at last point if it is on the curve */
1650
/* if both first and last points are conic, */
1651
/* start at their middle and record its position */
1653
v_start.x = ( v_start.x + v_last.x ) / 2;
1654
v_start.y = ( v_start.y + v_last.y ) / 2;
1662
ras.lastX = v_start.x;
1663
ras.lastY = v_start.y;
1665
while ( point < limit )
1670
tag = QT_FT_CURVE_TAG( tags[0] );
1674
case QT_FT_CURVE_TAG_ON: /* emit a single line_to */
1679
x = SCALED( point->x );
1680
y = SCALED( point->y );
1684
if ( Line_To( RAS_VARS x, y ) )
1689
case QT_FT_CURVE_TAG_CONIC: /* consume conic arcs */
1690
v_control.x = SCALED( point[0].x );
1691
v_control.y = SCALED( point[0].y );
1694
SWAP_( v_control.x, v_control.y );
1697
if ( point < limit )
1699
QT_FT_Vector v_middle;
1705
tag = QT_FT_CURVE_TAG( tags[0] );
1707
x = SCALED( point[0].x );
1708
y = SCALED( point[0].y );
1713
if ( tag == QT_FT_CURVE_TAG_ON )
1715
if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
1720
if ( tag != QT_FT_CURVE_TAG_CONIC )
1721
goto Invalid_Outline;
1723
v_middle.x = ( v_control.x + x ) / 2;
1724
v_middle.y = ( v_control.y + y ) / 2;
1726
if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1727
v_middle.x, v_middle.y ) )
1736
if ( Conic_To( RAS_VARS v_control.x, v_control.y,
1737
v_start.x, v_start.y ) )
1742
default: /* QT_FT_CURVE_TAG_CUBIC */
1744
Long x1, y1, x2, y2, x3, y3;
1747
if ( point + 1 > limit ||
1748
QT_FT_CURVE_TAG( tags[1] ) != QT_FT_CURVE_TAG_CUBIC )
1749
goto Invalid_Outline;
1754
x1 = SCALED( point[-2].x );
1755
y1 = SCALED( point[-2].y );
1756
x2 = SCALED( point[-1].x );
1757
y2 = SCALED( point[-1].y );
1758
x3 = SCALED( point[ 0].x );
1759
y3 = SCALED( point[ 0].y );
1768
if ( point <= limit )
1770
if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
1775
if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
1782
/* close the contour with a line segment */
1783
if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
1790
ras.error = Raster_Err_Invalid;
1797
/*************************************************************************/
1803
/* Converts a glyph into a series of segments and arcs and makes a */
1804
/* profiles list with them. */
1807
/* flipped :: If set, flip the direction of curve. */
1810
/* SUCCESS on success, FAILURE if any error was encountered during */
1814
Convert_Glyph( RAS_ARGS int flipped )
1819
PProfile lastProfile;
1822
ras.fProfile = NULL;
1825
ras.maxBuff = ras.sizeBuff - AlignProfileSize;
1829
ras.cProfile = (PProfile)ras.top;
1830
ras.cProfile->offset = ras.top;
1835
for ( i = 0; i < ras.outline.n_contours; i++ )
1837
ras.state = Unknown_State;
1838
ras.gProfile = NULL;
1840
if ( Decompose_Curve( RAS_VARS (unsigned short)start,
1841
ras.outline.contours[i],
1845
start = ras.outline.contours[i] + 1;
1847
/* Note that ras.gProfile can be nil if the contour was too small */
1850
lastProfile = ras.cProfile;
1851
if ( End_Profile( RAS_VAR ) )
1856
if ( Finalize_Profile_Table( RAS_VAR ) )
1859
return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
1863
/*************************************************************************/
1864
/*************************************************************************/
1866
/** SCAN-LINE SWEEPS AND DRAWING **/
1868
/*************************************************************************/
1869
/*************************************************************************/
1872
/*************************************************************************/
1876
/* Initializes an empty linked list. */
1879
Init_Linked( TProfileList* l )
1885
/*************************************************************************/
1889
/* Inserts a new profile in a linked list. */
1892
InsNew( PProfileList list,
1895
PProfile *old, current;
1905
if ( x < current->X )
1907
old = ¤t->link;
1911
profile->link = current;
1916
/*************************************************************************/
1920
/* Removes an old profile from a linked list. */
1923
DelOld( PProfileList list,
1926
PProfile *old, current;
1934
if ( current == profile )
1936
*old = current->link;
1940
old = ¤t->link;
1944
/* we should never get there, unless the profile was not part of */
1949
/*************************************************************************/
1953
/* Sorts a trace list. In 95%, the list is already sorted. We need */
1954
/* an algorithm which is fast in this case. Bubble sort is enough */
1958
Sort( PProfileList list )
1960
PProfile *old, current, next;
1963
/* First, set the new X coordinate of each profile */
1967
current->X = *current->offset;
1968
current->offset += current->flow;
1970
current = current->link;
1973
/* Then sort them */
1980
next = current->link;
1984
if ( current->X <= next->X )
1986
old = ¤t->link;
1995
current->link = next->link;
1996
next->link = current;
2002
next = current->link;
2007
/*************************************************************************/
2009
/* Vertical Sweep Procedure Set */
2011
/* These four routines are used during the vertical black/white sweep */
2012
/* phase by the generic Draw_Sweep() function. */
2014
/*************************************************************************/
2017
Vertical_Sweep_Init( RAS_ARGS Short* min,
2020
QT_FT_UNUSED( min );
2021
QT_FT_UNUSED( max );
2022
QT_FT_UNUSED( raster );
2027
Vertical_Sweep_Step( RAS_ARG )
2029
ras.traceOfs += ras.traceIncr;
2033
/*************************************************************************/
2035
/* Generic Sweep Drawing routine */
2037
/*************************************************************************/
2040
Draw_Sweep( RAS_ARG )
2042
Short y, y_change, y_height;
2044
PProfile P, Q, P_Left, P_Right;
2046
Short min_Y, max_Y, top, bottom;
2048
Long x1, x2, xs, e1, e2, ix1, ix2;
2052
TProfileList waiting;
2053
/* TProfileList draw_left, draw_right; */
2055
TProfileList profile_list;
2057
QT_FT_Span spans[MAX_SPANS];
2060
/* Init empty linked lists */
2062
Init_Linked( &waiting );
2064
/* Init_Linked( &draw_left );*/
2065
/* Init_Linked( &draw_right );*/
2067
Init_Linked( &profile_list );
2069
/* first, compute min and max Y */
2072
max_Y = (Short)TRUNC( ras.minY );
2073
min_Y = (Short)TRUNC( ras.maxY );
2079
bottom = (Short)P->start;
2080
top = (Short)( P->start + P->height - 1 );
2082
if ( min_Y > bottom ) min_Y = bottom;
2083
if ( max_Y < top ) max_Y = top;
2086
InsNew( &waiting, P );
2091
/* Check the Y-turns */
2092
if ( ras.numTurns == 0 )
2094
ras.error = Raster_Err_Invalid;
2098
/* Now inits the sweep */
2100
ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
2102
/* Then compute the distance of each profile from min_Y */
2108
P->countL = (UShort)( P->start - min_Y );
2117
if ( ras.numTurns > 0 &&
2118
ras.sizeBuff[-ras.numTurns] == min_Y )
2121
while ( ras.numTurns > 0 )
2123
/* look in the waiting list for new activations */
2130
P->countL -= y_height;
2131
if ( P->countL == 0 )
2133
DelOld( &waiting, P );
2135
InsNew( &profile_list, P );
2142
/* Sort the drawing lists */
2143
Sort(&profile_list);
2145
y_change = (Short)ras.sizeBuff[-ras.numTurns--];
2146
y_height = (Short)( y_change - y );
2148
while ( y < y_change )
2152
#ifdef Q_RASTER_DEBUG
2154
printf("y=%d ::", y);
2156
printf(" %.2f", Q->X / 64.);
2163
P_Left = profile_list;
2166
winding = P_Left->flow;
2169
P_Right = P_Left->link;
2170
} else { /* Winding fill; */
2172
while (winding && P_Right->link) {
2173
P_Right = P_Right->link;
2174
winding += P_Right->flow;
2178
/* We need an even number of intersections, otherwise there is something */
2181
return Raster_Err_Invalid;
2192
if ( x2 - x1 <= ras.precision ) {
2197
ix1 = MAX(TRUNC(CEILING(x1)), ras.minX_dev);
2198
ix2 = MIN(TRUNC(FLOOR(x2-1)) + 1, ras.maxX_dev);
2200
spans[span_count].x = (short) ix1;
2201
spans[span_count].len = (short) (ix2 - ix1);
2202
spans[span_count].coverage = 255;
2205
if (span_count == MAX_SPANS) {
2206
ras.black_spans(y, span_count, spans, ras.user_data);
2210
P_Left = P_Right->link;
2212
ras.Proc_Sweep_Step( RAS_VAR );
2215
ras.black_spans(y, span_count, spans, ras.user_data);
2220
Sort( &profile_list );
2223
/* Now finalize the profiles that needs it */
2229
if ( P->height == 0 )
2230
DelOld( &profile_list, P );
2236
/* for gray-scaling, flushes the bitmap scanline cache */
2237
while ( y <= max_Y )
2239
ras.Proc_Sweep_Step( RAS_VAR );
2247
/*************************************************************************/
2250
/* Render_Single_Pass */
2253
/* Performs one sweep with sub-banding. */
2256
/* flipped :: If set, flip the direction of the outline. */
2259
/* Renderer error code. */
2262
Render_Single_Pass( RAS_ARGS Bool flipped )
2267
while ( ras.band_top >= 0 )
2269
ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
2270
ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
2274
ras.error = Raster_Err_None;
2276
if ( Convert_Glyph( RAS_VARS flipped ) )
2278
if ( ras.error != Raster_Err_Overflow )
2281
ras.error = Raster_Err_None;
2286
ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
2289
i = ras.band_stack[ras.band_top].y_min;
2290
j = ras.band_stack[ras.band_top].y_max;
2292
k = (Short)( ( i + j ) / 2 );
2294
if ( ras.band_top >= 7 || k < i )
2297
ras.error = Raster_Err_Invalid;
2302
ras.band_stack[ras.band_top + 1].y_min = k;
2303
ras.band_stack[ras.band_top + 1].y_max = j;
2305
ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
2312
if ( Draw_Sweep( RAS_VAR ) )
2322
/*************************************************************************/
2328
/* Renders a glyph in a bitmap. Sub-banding if needed. */
2331
/* FreeType error code. 0 means success. */
2333
QT_FT_LOCAL_DEF( QT_FT_Error )
2334
Render_Glyph( RAS_ARG )
2338
QT_FT_TRACE6("Render_Glyph:\n");
2340
Set_High_Precision( RAS_VARS FALSE );
2341
ras.scale_shift = ras.precision_shift;
2343
/* Vertical Sweep */
2344
ras.Proc_Sweep_Init = Vertical_Sweep_Init;
2345
ras.Proc_Sweep_Step = Vertical_Sweep_Step;
2348
ras.band_stack[0].y_min = (short) (ras.clip_box.yMin);
2349
ras.band_stack[0].y_max = (short) (ras.clip_box.yMax - ras.clip_box.yMin - 1);
2350
ras.bWidth = (unsigned short) (ras.clip_box.xMax - ras.clip_box.xMin - 1);
2352
if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
2355
QT_FT_TRACE6("End Render_Glyph:\n\n");
2357
return Raster_Err_Ok;
2362
QT_FT_LOCAL_DEF( QT_FT_Error )
2363
Render_Gray_Glyph( RAS_ARG )
2365
QT_FT_UNUSED_RASTER;
2367
return Raster_Err_Cannot_Render_Glyph;
2371
/**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
2372
/**** a static object. *****/
2375
/* #### a static instance might be a bad idea... */
2377
qt_ft_black_new( void* memory,
2378
QT_FT_Raster *araster )
2380
static TRaster_Instance the_raster;
2381
QT_FT_UNUSED( memory );
2383
*araster = (QT_FT_Raster) &the_raster;
2384
QT_FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
2391
qt_ft_black_done( QT_FT_Raster raster )
2393
QT_FT_UNUSED( raster );
2395
/* raster->init = 0; */
2400
qt_ft_black_reset( TRaster_Instance* raster,
2401
const char* pool_base,
2404
if ( raster && pool_base && pool_size >= 4096 )
2407
raster->buff = (PLong)pool_base;
2408
raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
2414
qt_ft_black_set_mode( TRaster_Instance* raster,
2416
const char* palette )
2419
QT_FT_UNUSED( raster );
2420
QT_FT_UNUSED( mode );
2421
QT_FT_UNUSED( palette );
2427
qt_ft_black_render( TRaster_Instance* raster,
2428
QT_FT_Raster_Params* params )
2430
QT_FT_Outline* outline = (QT_FT_Outline*)params->source;
2432
if ( !raster || !raster->buff || !raster->sizeBuff )
2433
return Raster_Err_Not_Ini;
2435
/* return immediately if the outline is empty */
2436
if ( outline->n_points == 0 || outline->n_contours <= 0 )
2437
return Raster_Err_None;
2439
if ( !outline || !outline->contours || !outline->points )
2440
return Raster_Err_Invalid;
2442
if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
2443
return Raster_Err_Invalid;
2445
if (!params->black_spans)
2446
return Raster_Err_Invalid;
2447
ras.black_spans = params->black_spans;
2448
ras.user_data = params->user;
2449
ras.outline = *outline;
2451
if (!(params->flags & QT_FT_RASTER_FLAG_CLIP))
2452
return Raster_Err_Invalid;
2454
ras.minX_dev = (short)params->clip_box.xMin;
2455
ras.maxX_dev = (short)params->clip_box.xMax;
2457
ras.clip_box = params->clip_box;
2459
ras.odd_even = (outline->flags & QT_FT_OUTLINE_EVEN_ODD_FILL);
2461
return ( ( params->flags & QT_FT_RASTER_FLAG_AA )
2462
? Render_Gray_Glyph( raster )
2463
: Render_Glyph( raster ) );
2467
const QT_FT_Raster_Funcs qt_ft_standard_raster =
2469
QT_FT_GLYPH_FORMAT_OUTLINE,
2470
(QT_FT_Raster_New_Func) qt_ft_black_new,
2471
(QT_FT_Raster_Reset_Func) qt_ft_black_reset,
2472
(QT_FT_Raster_Set_Mode_Func)qt_ft_black_set_mode,
2473
(QT_FT_Raster_Render_Func) qt_ft_black_render,
2474
(QT_FT_Raster_Done_Func) qt_ft_black_done