Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftraster.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ftraster.c */ 00004 /* */ 00005 /* The FreeType glyph rasterizer (body). */ 00006 /* */ 00007 /* Copyright 1996-2001, 2002, 2003, 2005, 2007, 2008, 2009, 2010 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 /*************************************************************************/ 00019 /* */ 00020 /* This file can be compiled without the rest of the FreeType engine, by */ 00021 /* defining the _STANDALONE_ macro when compiling it. You also need to */ 00022 /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir) */ 00023 /* directory. Typically, you should do something like */ 00024 /* */ 00025 /* - copy `src/raster/ftraster.c' (this file) to your current directory */ 00026 /* */ 00027 /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */ 00028 /* to your current directory */ 00029 /* */ 00030 /* - compile `ftraster' with the _STANDALONE_ macro defined, as in */ 00031 /* */ 00032 /* cc -c -D_STANDALONE_ ftraster.c */ 00033 /* */ 00034 /* The renderer can be initialized with a call to */ 00035 /* `ft_standard_raster.raster_new'; a bitmap can be generated */ 00036 /* with a call to `ft_standard_raster.raster_render'. */ 00037 /* */ 00038 /* See the comments and documentation in the file `ftimage.h' for more */ 00039 /* details on how the raster works. */ 00040 /* */ 00041 /*************************************************************************/ 00042 00043 00044 /*************************************************************************/ 00045 /* */ 00046 /* This is a rewrite of the FreeType 1.x scan-line converter */ 00047 /* */ 00048 /*************************************************************************/ 00049 00050 #ifdef _STANDALONE_ 00051 00052 #define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h> 00053 00054 #include <string.h> /* for memset */ 00055 00056 #include "ftmisc.h" 00057 #include "ftimage.h" 00058 00059 #else /* !_STANDALONE_ */ 00060 00061 #include <ft2build.h> 00062 #include "ftraster.h" 00063 #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */ 00064 00065 #include "rastpic.h" 00066 00067 #endif /* !_STANDALONE_ */ 00068 00069 00070 /*************************************************************************/ 00071 /* */ 00072 /* A simple technical note on how the raster works */ 00073 /* ----------------------------------------------- */ 00074 /* */ 00075 /* Converting an outline into a bitmap is achieved in several steps: */ 00076 /* */ 00077 /* 1 - Decomposing the outline into successive `profiles'. Each */ 00078 /* profile is simply an array of scanline intersections on a given */ 00079 /* dimension. A profile's main attributes are */ 00080 /* */ 00081 /* o its scanline position boundaries, i.e. `Ymin' and `Ymax' */ 00082 /* */ 00083 /* o an array of intersection coordinates for each scanline */ 00084 /* between `Ymin' and `Ymax' */ 00085 /* */ 00086 /* o a direction, indicating whether it was built going `up' or */ 00087 /* `down', as this is very important for filling rules */ 00088 /* */ 00089 /* o its drop-out mode */ 00090 /* */ 00091 /* 2 - Sweeping the target map's scanlines in order to compute segment */ 00092 /* `spans' which are then filled. Additionally, this pass */ 00093 /* performs drop-out control. */ 00094 /* */ 00095 /* The outline data is parsed during step 1 only. The profiles are */ 00096 /* built from the bottom of the render pool, used as a stack. The */ 00097 /* following graphics shows the profile list under construction: */ 00098 /* */ 00099 /* __________________________________________________________ _ _ */ 00100 /* | | | | | */ 00101 /* | profile | coordinates for | profile | coordinates for |--> */ 00102 /* | 1 | profile 1 | 2 | profile 2 |--> */ 00103 /* |_________|_________________|_________|_________________|__ _ _ */ 00104 /* */ 00105 /* ^ ^ */ 00106 /* | | */ 00107 /* start of render pool top */ 00108 /* */ 00109 /* The top of the profile stack is kept in the `top' variable. */ 00110 /* */ 00111 /* As you can see, a profile record is pushed on top of the render */ 00112 /* pool, which is then followed by its coordinates/intersections. If */ 00113 /* a change of direction is detected in the outline, a new profile is */ 00114 /* generated until the end of the outline. */ 00115 /* */ 00116 /* Note that when all profiles have been generated, the function */ 00117 /* Finalize_Profile_Table() is used to record, for each profile, its */ 00118 /* bottom-most scanline as well as the scanline above its upmost */ 00119 /* boundary. These positions are called `y-turns' because they (sort */ 00120 /* of) correspond to local extrema. They are stored in a sorted list */ 00121 /* built from the top of the render pool as a downwards stack: */ 00122 /* */ 00123 /* _ _ _______________________________________ */ 00124 /* | | */ 00125 /* <--| sorted list of | */ 00126 /* <--| extrema scanlines | */ 00127 /* _ _ __________________|____________________| */ 00128 /* */ 00129 /* ^ ^ */ 00130 /* | | */ 00131 /* maxBuff sizeBuff = end of pool */ 00132 /* */ 00133 /* This list is later used during the sweep phase in order to */ 00134 /* optimize performance (see technical note on the sweep below). */ 00135 /* */ 00136 /* Of course, the raster detects whether the two stacks collide and */ 00137 /* handles the situation properly. */ 00138 /* */ 00139 /*************************************************************************/ 00140 00141 00142 /*************************************************************************/ 00143 /*************************************************************************/ 00147 /*************************************************************************/ 00148 /*************************************************************************/ 00149 00150 /* define DEBUG_RASTER if you want to compile a debugging version */ 00151 /* #define DEBUG_RASTER */ 00152 00153 /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */ 00154 /* 5-levels anti-aliasing */ 00155 /* #define FT_RASTER_OPTION_ANTI_ALIASING */ 00156 00157 /* The size of the two-lines intermediate bitmap used */ 00158 /* for anti-aliasing, in bytes. */ 00159 #define RASTER_GRAY_LINES 2048 00160 00161 00162 /*************************************************************************/ 00163 /*************************************************************************/ 00167 /*************************************************************************/ 00168 /*************************************************************************/ 00169 00170 /*************************************************************************/ 00171 /* */ 00172 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00173 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00174 /* messages during execution. */ 00175 /* */ 00176 #undef FT_COMPONENT 00177 #define FT_COMPONENT trace_raster 00178 00179 00180 #ifdef _STANDALONE_ 00181 00182 00183 /* This macro is used to indicate that a function parameter is unused. */ 00184 /* Its purpose is simply to reduce compiler warnings. Note also that */ 00185 /* simply defining it as `(void)x' doesn't avoid warnings with certain */ 00186 /* ANSI compilers (e.g. LCC). */ 00187 #define FT_UNUSED( x ) (x) = (x) 00188 00189 /* Disable the tracing mechanism for simplicity -- developers can */ 00190 /* activate it easily by redefining these two macros. */ 00191 #ifndef FT_ERROR 00192 #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ 00193 #endif 00194 00195 #ifndef FT_TRACE 00196 #define FT_TRACE( x ) do { } while ( 0 ) /* nothing */ 00197 #define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */ 00198 #define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */ 00199 #endif 00200 00201 #define Raster_Err_None 0 00202 #define Raster_Err_Not_Ini -1 00203 #define Raster_Err_Overflow -2 00204 #define Raster_Err_Neg_Height -3 00205 #define Raster_Err_Invalid -4 00206 #define Raster_Err_Unsupported -5 00207 00208 #define ft_memset memset 00209 00210 #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \ 00211 raster_reset_, raster_set_mode_, \ 00212 raster_render_, raster_done_ ) \ 00213 const FT_Raster_Funcs class_ = \ 00214 { \ 00215 glyph_format_, \ 00216 raster_new_, \ 00217 raster_reset_, \ 00218 raster_set_mode_, \ 00219 raster_render_, \ 00220 raster_done_ \ 00221 }; 00222 00223 #else /* !_STANDALONE_ */ 00224 00225 00226 #include FT_INTERNAL_OBJECTS_H 00227 #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */ 00228 00229 #include "rasterrs.h" 00230 00231 #define Raster_Err_None Raster_Err_Ok 00232 #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized 00233 #define Raster_Err_Overflow Raster_Err_Raster_Overflow 00234 #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height 00235 #define Raster_Err_Invalid Raster_Err_Invalid_Outline 00236 #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph 00237 00238 00239 #endif /* !_STANDALONE_ */ 00240 00241 00242 #ifndef FT_MEM_SET 00243 #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c ) 00244 #endif 00245 00246 #ifndef FT_MEM_ZERO 00247 #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count ) 00248 #endif 00249 00250 /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */ 00251 /* typically a small value and the result of a*b is known to fit into */ 00252 /* 32 bits. */ 00253 #define FMulDiv( a, b, c ) ( (a) * (b) / (c) ) 00254 00255 /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ 00256 /* for clipping computations. It simply uses the FT_MulDiv() function */ 00257 /* defined in `ftcalc.h'. */ 00258 #define SMulDiv FT_MulDiv 00259 00260 /* The rasterizer is a very general purpose component; please leave */ 00261 /* the following redefinitions there (you never know your target */ 00262 /* environment). */ 00263 00264 #ifndef TRUE 00265 #define TRUE 1 00266 #endif 00267 00268 #ifndef FALSE 00269 #define FALSE 0 00270 #endif 00271 00272 #ifndef NULL 00273 #define NULL (void*)0 00274 #endif 00275 00276 #ifndef SUCCESS 00277 #define SUCCESS 0 00278 #endif 00279 00280 #ifndef FAILURE 00281 #define FAILURE 1 00282 #endif 00283 00284 00285 #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */ 00286 /* Setting this constant to more than 32 is a */ 00287 /* pure waste of space. */ 00288 00289 #define Pixel_Bits 6 /* fractional bits of *input* coordinates */ 00290 00291 00292 /*************************************************************************/ 00293 /*************************************************************************/ 00297 /*************************************************************************/ 00298 /*************************************************************************/ 00299 00300 typedef int Int; 00301 typedef unsigned int UInt; 00302 typedef short Short; 00303 typedef unsigned short UShort, *PUShort; 00304 typedef long Long, *PLong; 00305 00306 typedef unsigned char Byte, *PByte; 00307 typedef char Bool; 00308 00309 00310 typedef union Alignment_ 00311 { 00312 long l; 00313 void* p; 00314 void (*f)(void); 00315 00316 } Alignment, *PAlignment; 00317 00318 00319 typedef struct TPoint_ 00320 { 00321 Long x; 00322 Long y; 00323 00324 } TPoint; 00325 00326 00327 /* values for the `flags' bit field */ 00328 #define Flow_Up 0x8 00329 #define Overshoot_Top 0x10 00330 #define Overshoot_Bottom 0x20 00331 00332 00333 /* States of each line, arc, and profile */ 00334 typedef enum TStates_ 00335 { 00336 Unknown_State, 00337 Ascending_State, 00338 Descending_State, 00339 Flat_State 00340 00341 } TStates; 00342 00343 00344 typedef struct TProfile_ TProfile; 00345 typedef TProfile* PProfile; 00346 00347 struct TProfile_ 00348 { 00349 FT_F26Dot6 X; /* current coordinate during sweep */ 00350 PProfile link; /* link to next profile (various purposes) */ 00351 PLong offset; /* start of profile's data in render pool */ 00352 unsigned flags; /* Bit 0-2: drop-out mode */ 00353 /* Bit 3: profile orientation (up/down) */ 00354 /* Bit 4: is top profile? */ 00355 /* Bit 5: is bottom profile? */ 00356 long height; /* profile's height in scanlines */ 00357 long start; /* profile's starting scanline */ 00358 00359 unsigned countL; /* number of lines to step before this */ 00360 /* profile becomes drawable */ 00361 00362 PProfile next; /* next profile in same contour, used */ 00363 /* during drop-out control */ 00364 }; 00365 00366 typedef PProfile TProfileList; 00367 typedef PProfile* PProfileList; 00368 00369 00370 /* Simple record used to implement a stack of bands, required */ 00371 /* by the sub-banding mechanism */ 00372 typedef struct TBand_ 00373 { 00374 Short y_min; /* band's minimum */ 00375 Short y_max; /* band's maximum */ 00376 00377 } TBand; 00378 00379 00380 #define AlignProfileSize \ 00381 ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) ) 00382 00383 00384 #ifdef FT_STATIC_RASTER 00385 00386 00387 #define RAS_ARGS /* void */ 00388 #define RAS_ARG /* void */ 00389 00390 #define RAS_VARS /* void */ 00391 #define RAS_VAR /* void */ 00392 00393 #define FT_UNUSED_RASTER do { } while ( 0 ) 00394 00395 00396 #else /* !FT_STATIC_RASTER */ 00397 00398 00399 #define RAS_ARGS PWorker worker, 00400 #define RAS_ARG PWorker worker 00401 00402 #define RAS_VARS worker, 00403 #define RAS_VAR worker 00404 00405 #define FT_UNUSED_RASTER FT_UNUSED( worker ) 00406 00407 00408 #endif /* !FT_STATIC_RASTER */ 00409 00410 00411 typedef struct TWorker_ TWorker, *PWorker; 00412 00413 00414 /* prototypes used for sweep function dispatch */ 00415 typedef void 00416 Function_Sweep_Init( RAS_ARGS Short* min, 00417 Short* max ); 00418 00419 typedef void 00420 Function_Sweep_Span( RAS_ARGS Short y, 00421 FT_F26Dot6 x1, 00422 FT_F26Dot6 x2, 00423 PProfile left, 00424 PProfile right ); 00425 00426 typedef void 00427 Function_Sweep_Step( RAS_ARG ); 00428 00429 00430 /* NOTE: These operations are only valid on 2's complement processors */ 00431 00432 #define FLOOR( x ) ( (x) & -ras.precision ) 00433 #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision ) 00434 #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits ) 00435 #define FRAC( x ) ( (x) & ( ras.precision - 1 ) ) 00436 #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half ) 00437 00438 #define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half ) 00439 #define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half ) 00440 00441 /* The most used variables are positioned at the top of the structure. */ 00442 /* Thus, their offset can be coded with less opcodes, resulting in a */ 00443 /* smaller executable. */ 00444 00445 struct TWorker_ 00446 { 00447 Int precision_bits; /* precision related variables */ 00448 Int precision; 00449 Int precision_half; 00450 Int precision_shift; 00451 Int precision_step; 00452 Int precision_jitter; 00453 00454 Int scale_shift; /* == precision_shift for bitmaps */ 00455 /* == precision_shift+1 for pixmaps */ 00456 00457 PLong buff; /* The profiles buffer */ 00458 PLong sizeBuff; /* Render pool size */ 00459 PLong maxBuff; /* Profiles buffer size */ 00460 PLong top; /* Current cursor in buffer */ 00461 00462 FT_Error error; 00463 00464 Int numTurns; /* number of Y-turns in outline */ 00465 00466 TPoint* arc; /* current Bezier arc pointer */ 00467 00468 UShort bWidth; /* target bitmap width */ 00469 PByte bTarget; /* target bitmap buffer */ 00470 PByte gTarget; /* target pixmap buffer */ 00471 00472 Long lastX, lastY; 00473 Long minY, maxY; 00474 00475 UShort num_Profs; /* current number of profiles */ 00476 00477 Bool fresh; /* signals a fresh new profile which */ 00478 /* `start' field must be completed */ 00479 Bool joint; /* signals that the last arc ended */ 00480 /* exactly on a scanline. Allows */ 00481 /* removal of doublets */ 00482 PProfile cProfile; /* current profile */ 00483 PProfile fProfile; /* head of linked list of profiles */ 00484 PProfile gProfile; /* contour's first profile in case */ 00485 /* of impact */ 00486 00487 TStates state; /* rendering state */ 00488 00489 FT_Bitmap target; /* description of target bit/pixmap */ 00490 FT_Outline outline; 00491 00492 Long traceOfs; /* current offset in target bitmap */ 00493 Long traceG; /* current offset in target pixmap */ 00494 00495 Short traceIncr; /* sweep's increment in target bitmap */ 00496 00497 Short gray_min_x; /* current min x during gray rendering */ 00498 Short gray_max_x; /* current max x during gray rendering */ 00499 00500 /* dispatch variables */ 00501 00502 Function_Sweep_Init* Proc_Sweep_Init; 00503 Function_Sweep_Span* Proc_Sweep_Span; 00504 Function_Sweep_Span* Proc_Sweep_Drop; 00505 Function_Sweep_Step* Proc_Sweep_Step; 00506 00507 Byte dropOutControl; /* current drop_out control method */ 00508 00509 Bool second_pass; /* indicates whether a horizontal pass */ 00510 /* should be performed to control */ 00511 /* drop-out accurately when calling */ 00512 /* Render_Glyph. Note that there is */ 00513 /* no horizontal pass during gray */ 00514 /* rendering. */ 00515 00516 TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ 00517 00518 TBand band_stack[16]; /* band stack used for sub-banding */ 00519 Int band_top; /* band stack top */ 00520 00521 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 00522 00523 Byte* grays; 00524 00525 Byte gray_lines[RASTER_GRAY_LINES]; 00526 /* Intermediate table used to render the */ 00527 /* graylevels pixmaps. */ 00528 /* gray_lines is a buffer holding two */ 00529 /* monochrome scanlines */ 00530 00531 Short gray_width; /* width in bytes of one monochrome */ 00532 /* intermediate scanline of gray_lines. */ 00533 /* Each gray pixel takes 2 bits long there */ 00534 00535 /* The gray_lines must hold 2 lines, thus with size */ 00536 /* in bytes of at least `gray_width*2'. */ 00537 00538 #endif /* FT_RASTER_ANTI_ALIASING */ 00539 00540 }; 00541 00542 00543 typedef struct TRaster_ 00544 { 00545 char* buffer; 00546 long buffer_size; 00547 void* memory; 00548 PWorker worker; 00549 Byte grays[5]; 00550 Short gray_width; 00551 00552 } TRaster, *PRaster; 00553 00554 #ifdef FT_STATIC_RASTER 00555 00556 static TWorker cur_ras; 00557 #define ras cur_ras 00558 00559 #else /* !FT_STATIC_RASTER */ 00560 00561 #define ras (*worker) 00562 00563 #endif /* !FT_STATIC_RASTER */ 00564 00565 00566 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 00567 00568 /* A lookup table used to quickly count set bits in four gray 2x2 */ 00569 /* cells. The values of the table have been produced with the */ 00570 /* following code: */ 00571 /* */ 00572 /* for ( i = 0; i < 256; i++ ) */ 00573 /* { */ 00574 /* l = 0; */ 00575 /* j = i; */ 00576 /* */ 00577 /* for ( c = 0; c < 4; c++ ) */ 00578 /* { */ 00579 /* l <<= 4; */ 00580 /* */ 00581 /* if ( j & 0x80 ) l++; */ 00582 /* if ( j & 0x40 ) l++; */ 00583 /* */ 00584 /* j = ( j << 2 ) & 0xFF; */ 00585 /* } */ 00586 /* printf( "0x%04X", l ); */ 00587 /* } */ 00588 /* */ 00589 00590 static const short count_table[256] = 00591 { 00592 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012, 00593 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022, 00594 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, 00595 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, 00596 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112, 00597 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122, 00598 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212, 00599 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222, 00600 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, 00601 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, 00602 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 00603 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 00604 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 00605 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 00606 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, 00607 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, 00608 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012, 00609 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022, 00610 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 00611 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 00612 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112, 00613 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122, 00614 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212, 00615 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222, 00616 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012, 00617 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022, 00618 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, 00619 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, 00620 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112, 00621 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122, 00622 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212, 00623 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222 00624 }; 00625 00626 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */ 00627 00628 00629 00630 /*************************************************************************/ 00631 /*************************************************************************/ 00635 /*************************************************************************/ 00636 /*************************************************************************/ 00637 00638 00639 /*************************************************************************/ 00640 /* */ 00641 /* <Function> */ 00642 /* Set_High_Precision */ 00643 /* */ 00644 /* <Description> */ 00645 /* Set precision variables according to param flag. */ 00646 /* */ 00647 /* <Input> */ 00648 /* High :: Set to True for high precision (typically for ppem < 18), */ 00649 /* false otherwise. */ 00650 /* */ 00651 static void 00652 Set_High_Precision( RAS_ARGS Int High ) 00653 { 00654 if ( High ) 00655 { 00656 ras.precision_bits = 12; 00657 ras.precision_step = 256; 00658 ras.precision_jitter = 50; 00659 } 00660 else 00661 { 00662 ras.precision_bits = 6; 00663 ras.precision_step = 32; 00664 ras.precision_jitter = 2; 00665 } 00666 00667 FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" )); 00668 00669 ras.precision = 1 << ras.precision_bits; 00670 ras.precision_half = ras.precision / 2; 00671 ras.precision_shift = ras.precision_bits - Pixel_Bits; 00672 } 00673 00674 00675 /*************************************************************************/ 00676 /* */ 00677 /* <Function> */ 00678 /* New_Profile */ 00679 /* */ 00680 /* <Description> */ 00681 /* Create a new profile in the render pool. */ 00682 /* */ 00683 /* <Input> */ 00684 /* aState :: The state/orientation of the new profile. */ 00685 /* */ 00686 /* overshoot :: Whether the profile's unrounded start position */ 00687 /* differs by at least a half pixel. */ 00688 /* */ 00689 /* <Return> */ 00690 /* SUCCESS on success. FAILURE in case of overflow or of incoherent */ 00691 /* profile. */ 00692 /* */ 00693 static Bool 00694 New_Profile( RAS_ARGS TStates aState, 00695 Bool overshoot ) 00696 { 00697 if ( !ras.fProfile ) 00698 { 00699 ras.cProfile = (PProfile)ras.top; 00700 ras.fProfile = ras.cProfile; 00701 ras.top += AlignProfileSize; 00702 } 00703 00704 if ( ras.top >= ras.maxBuff ) 00705 { 00706 ras.error = Raster_Err_Overflow; 00707 return FAILURE; 00708 } 00709 00710 ras.cProfile->flags = 0; 00711 ras.cProfile->start = 0; 00712 ras.cProfile->height = 0; 00713 ras.cProfile->offset = ras.top; 00714 ras.cProfile->link = (PProfile)0; 00715 ras.cProfile->next = (PProfile)0; 00716 ras.cProfile->flags = ras.dropOutControl; 00717 00718 switch ( aState ) 00719 { 00720 case Ascending_State: 00721 ras.cProfile->flags |= Flow_Up; 00722 if ( overshoot ) 00723 ras.cProfile->flags |= Overshoot_Bottom; 00724 00725 FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile )); 00726 break; 00727 00728 case Descending_State: 00729 if ( overshoot ) 00730 ras.cProfile->flags |= Overshoot_Top; 00731 FT_TRACE6(( "New descending profile = %p\n", ras.cProfile )); 00732 break; 00733 00734 default: 00735 FT_ERROR(( "New_Profile: invalid profile direction\n" )); 00736 ras.error = Raster_Err_Invalid; 00737 return FAILURE; 00738 } 00739 00740 if ( !ras.gProfile ) 00741 ras.gProfile = ras.cProfile; 00742 00743 ras.state = aState; 00744 ras.fresh = TRUE; 00745 ras.joint = FALSE; 00746 00747 return SUCCESS; 00748 } 00749 00750 00751 /*************************************************************************/ 00752 /* */ 00753 /* <Function> */ 00754 /* End_Profile */ 00755 /* */ 00756 /* <Description> */ 00757 /* Finalize the current profile. */ 00758 /* */ 00759 /* <Input> */ 00760 /* overshoot :: Whether the profile's unrounded end position differs */ 00761 /* by at least a half pixel. */ 00762 /* */ 00763 /* <Return> */ 00764 /* SUCCESS on success. FAILURE in case of overflow or incoherency. */ 00765 /* */ 00766 static Bool 00767 End_Profile( RAS_ARGS Bool overshoot ) 00768 { 00769 Long h; 00770 PProfile oldProfile; 00771 00772 00773 h = (Long)( ras.top - ras.cProfile->offset ); 00774 00775 if ( h < 0 ) 00776 { 00777 FT_ERROR(( "End_Profile: negative height encountered\n" )); 00778 ras.error = Raster_Err_Neg_Height; 00779 return FAILURE; 00780 } 00781 00782 if ( h > 0 ) 00783 { 00784 FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n", 00785 ras.cProfile, ras.cProfile->start, h )); 00786 00787 ras.cProfile->height = h; 00788 if ( overshoot ) 00789 { 00790 if ( ras.cProfile->flags & Flow_Up ) 00791 ras.cProfile->flags |= Overshoot_Top; 00792 else 00793 ras.cProfile->flags |= Overshoot_Bottom; 00794 } 00795 00796 oldProfile = ras.cProfile; 00797 ras.cProfile = (PProfile)ras.top; 00798 00799 ras.top += AlignProfileSize; 00800 00801 ras.cProfile->height = 0; 00802 ras.cProfile->offset = ras.top; 00803 00804 oldProfile->next = ras.cProfile; 00805 ras.num_Profs++; 00806 } 00807 00808 if ( ras.top >= ras.maxBuff ) 00809 { 00810 FT_TRACE1(( "overflow in End_Profile\n" )); 00811 ras.error = Raster_Err_Overflow; 00812 return FAILURE; 00813 } 00814 00815 ras.joint = FALSE; 00816 00817 return SUCCESS; 00818 } 00819 00820 00821 /*************************************************************************/ 00822 /* */ 00823 /* <Function> */ 00824 /* Insert_Y_Turn */ 00825 /* */ 00826 /* <Description> */ 00827 /* Insert a salient into the sorted list placed on top of the render */ 00828 /* pool. */ 00829 /* */ 00830 /* <Input> */ 00831 /* New y scanline position. */ 00832 /* */ 00833 /* <Return> */ 00834 /* SUCCESS on success. FAILURE in case of overflow. */ 00835 /* */ 00836 static Bool 00837 Insert_Y_Turn( RAS_ARGS Int y ) 00838 { 00839 PLong y_turns; 00840 Int y2, n; 00841 00842 00843 n = ras.numTurns - 1; 00844 y_turns = ras.sizeBuff - ras.numTurns; 00845 00846 /* look for first y value that is <= */ 00847 while ( n >= 0 && y < y_turns[n] ) 00848 n--; 00849 00850 /* if it is <, simply insert it, ignore if == */ 00851 if ( n >= 0 && y > y_turns[n] ) 00852 while ( n >= 0 ) 00853 { 00854 y2 = (Int)y_turns[n]; 00855 y_turns[n] = y; 00856 y = y2; 00857 n--; 00858 } 00859 00860 if ( n < 0 ) 00861 { 00862 ras.maxBuff--; 00863 if ( ras.maxBuff <= ras.top ) 00864 { 00865 ras.error = Raster_Err_Overflow; 00866 return FAILURE; 00867 } 00868 ras.numTurns++; 00869 ras.sizeBuff[-ras.numTurns] = y; 00870 } 00871 00872 return SUCCESS; 00873 } 00874 00875 00876 /*************************************************************************/ 00877 /* */ 00878 /* <Function> */ 00879 /* Finalize_Profile_Table */ 00880 /* */ 00881 /* <Description> */ 00882 /* Adjust all links in the profiles list. */ 00883 /* */ 00884 /* <Return> */ 00885 /* SUCCESS on success. FAILURE in case of overflow. */ 00886 /* */ 00887 static Bool 00888 Finalize_Profile_Table( RAS_ARG ) 00889 { 00890 Int bottom, top; 00891 UShort n; 00892 PProfile p; 00893 00894 00895 n = ras.num_Profs; 00896 p = ras.fProfile; 00897 00898 if ( n > 1 && p ) 00899 { 00900 while ( n > 0 ) 00901 { 00902 if ( n > 1 ) 00903 p->link = (PProfile)( p->offset + p->height ); 00904 else 00905 p->link = NULL; 00906 00907 if ( p->flags & Flow_Up ) 00908 { 00909 bottom = (Int)p->start; 00910 top = (Int)( p->start + p->height - 1 ); 00911 } 00912 else 00913 { 00914 bottom = (Int)( p->start - p->height + 1 ); 00915 top = (Int)p->start; 00916 p->start = bottom; 00917 p->offset += p->height - 1; 00918 } 00919 00920 if ( Insert_Y_Turn( RAS_VARS bottom ) || 00921 Insert_Y_Turn( RAS_VARS top + 1 ) ) 00922 return FAILURE; 00923 00924 p = p->link; 00925 n--; 00926 } 00927 } 00928 else 00929 ras.fProfile = NULL; 00930 00931 return SUCCESS; 00932 } 00933 00934 00935 /*************************************************************************/ 00936 /* */ 00937 /* <Function> */ 00938 /* Split_Conic */ 00939 /* */ 00940 /* <Description> */ 00941 /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */ 00942 /* stack. */ 00943 /* */ 00944 /* <Input> */ 00945 /* None (subdivided Bezier is taken from the top of the stack). */ 00946 /* */ 00947 /* <Note> */ 00948 /* This routine is the `beef' of this component. It is _the_ inner */ 00949 /* loop that should be optimized to hell to get the best performance. */ 00950 /* */ 00951 static void 00952 Split_Conic( TPoint* base ) 00953 { 00954 Long a, b; 00955 00956 00957 base[4].x = base[2].x; 00958 b = base[1].x; 00959 a = base[3].x = ( base[2].x + b ) / 2; 00960 b = base[1].x = ( base[0].x + b ) / 2; 00961 base[2].x = ( a + b ) / 2; 00962 00963 base[4].y = base[2].y; 00964 b = base[1].y; 00965 a = base[3].y = ( base[2].y + b ) / 2; 00966 b = base[1].y = ( base[0].y + b ) / 2; 00967 base[2].y = ( a + b ) / 2; 00968 00969 /* hand optimized. gcc doesn't seem to be too good at common */ 00970 /* expression substitution and instruction scheduling ;-) */ 00971 } 00972 00973 00974 /*************************************************************************/ 00975 /* */ 00976 /* <Function> */ 00977 /* Split_Cubic */ 00978 /* */ 00979 /* <Description> */ 00980 /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */ 00981 /* Bezier stack. */ 00982 /* */ 00983 /* <Note> */ 00984 /* This routine is the `beef' of the component. It is one of _the_ */ 00985 /* inner loops that should be optimized like hell to get the best */ 00986 /* performance. */ 00987 /* */ 00988 static void 00989 Split_Cubic( TPoint* base ) 00990 { 00991 Long a, b, c, d; 00992 00993 00994 base[6].x = base[3].x; 00995 c = base[1].x; 00996 d = base[2].x; 00997 base[1].x = a = ( base[0].x + c + 1 ) >> 1; 00998 base[5].x = b = ( base[3].x + d + 1 ) >> 1; 00999 c = ( c + d + 1 ) >> 1; 01000 base[2].x = a = ( a + c + 1 ) >> 1; 01001 base[4].x = b = ( b + c + 1 ) >> 1; 01002 base[3].x = ( a + b + 1 ) >> 1; 01003 01004 base[6].y = base[3].y; 01005 c = base[1].y; 01006 d = base[2].y; 01007 base[1].y = a = ( base[0].y + c + 1 ) >> 1; 01008 base[5].y = b = ( base[3].y + d + 1 ) >> 1; 01009 c = ( c + d + 1 ) >> 1; 01010 base[2].y = a = ( a + c + 1 ) >> 1; 01011 base[4].y = b = ( b + c + 1 ) >> 1; 01012 base[3].y = ( a + b + 1 ) >> 1; 01013 } 01014 01015 01016 /*************************************************************************/ 01017 /* */ 01018 /* <Function> */ 01019 /* Line_Up */ 01020 /* */ 01021 /* <Description> */ 01022 /* Compute the x-coordinates of an ascending line segment and store */ 01023 /* them in the render pool. */ 01024 /* */ 01025 /* <Input> */ 01026 /* x1 :: The x-coordinate of the segment's start point. */ 01027 /* */ 01028 /* y1 :: The y-coordinate of the segment's start point. */ 01029 /* */ 01030 /* x2 :: The x-coordinate of the segment's end point. */ 01031 /* */ 01032 /* y2 :: The y-coordinate of the segment's end point. */ 01033 /* */ 01034 /* miny :: A lower vertical clipping bound value. */ 01035 /* */ 01036 /* maxy :: An upper vertical clipping bound value. */ 01037 /* */ 01038 /* <Return> */ 01039 /* SUCCESS on success, FAILURE on render pool overflow. */ 01040 /* */ 01041 static Bool 01042 Line_Up( RAS_ARGS Long x1, 01043 Long y1, 01044 Long x2, 01045 Long y2, 01046 Long miny, 01047 Long maxy ) 01048 { 01049 Long Dx, Dy; 01050 Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ 01051 Long Ix, Rx, Ax; 01052 01053 PLong top; 01054 01055 01056 Dx = x2 - x1; 01057 Dy = y2 - y1; 01058 01059 if ( Dy <= 0 || y2 < miny || y1 > maxy ) 01060 return SUCCESS; 01061 01062 if ( y1 < miny ) 01063 { 01064 /* Take care: miny-y1 can be a very large value; we use */ 01065 /* a slow MulDiv function to avoid clipping bugs */ 01066 x1 += SMulDiv( Dx, miny - y1, Dy ); 01067 e1 = (Int)TRUNC( miny ); 01068 f1 = 0; 01069 } 01070 else 01071 { 01072 e1 = (Int)TRUNC( y1 ); 01073 f1 = (Int)FRAC( y1 ); 01074 } 01075 01076 if ( y2 > maxy ) 01077 { 01078 /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */ 01079 e2 = (Int)TRUNC( maxy ); 01080 f2 = 0; 01081 } 01082 else 01083 { 01084 e2 = (Int)TRUNC( y2 ); 01085 f2 = (Int)FRAC( y2 ); 01086 } 01087 01088 if ( f1 > 0 ) 01089 { 01090 if ( e1 == e2 ) 01091 return SUCCESS; 01092 else 01093 { 01094 x1 += SMulDiv( Dx, ras.precision - f1, Dy ); 01095 e1 += 1; 01096 } 01097 } 01098 else 01099 if ( ras.joint ) 01100 { 01101 ras.top--; 01102 ras.joint = FALSE; 01103 } 01104 01105 ras.joint = (char)( f2 == 0 ); 01106 01107 if ( ras.fresh ) 01108 { 01109 ras.cProfile->start = e1; 01110 ras.fresh = FALSE; 01111 } 01112 01113 size = e2 - e1 + 1; 01114 if ( ras.top + size >= ras.maxBuff ) 01115 { 01116 ras.error = Raster_Err_Overflow; 01117 return FAILURE; 01118 } 01119 01120 if ( Dx > 0 ) 01121 { 01122 Ix = SMulDiv( ras.precision, Dx, Dy); 01123 Rx = ( ras.precision * Dx ) % Dy; 01124 Dx = 1; 01125 } 01126 else 01127 { 01128 Ix = SMulDiv( ras.precision, -Dx, Dy) * -1; 01129 Rx = ( ras.precision * -Dx ) % Dy; 01130 Dx = -1; 01131 } 01132 01133 Ax = -Dy; 01134 top = ras.top; 01135 01136 while ( size > 0 ) 01137 { 01138 *top++ = x1; 01139 01140 x1 += Ix; 01141 Ax += Rx; 01142 if ( Ax >= 0 ) 01143 { 01144 Ax -= Dy; 01145 x1 += Dx; 01146 } 01147 size--; 01148 } 01149 01150 ras.top = top; 01151 return SUCCESS; 01152 } 01153 01154 01155 /*************************************************************************/ 01156 /* */ 01157 /* <Function> */ 01158 /* Line_Down */ 01159 /* */ 01160 /* <Description> */ 01161 /* Compute the x-coordinates of an descending line segment and store */ 01162 /* them in the render pool. */ 01163 /* */ 01164 /* <Input> */ 01165 /* x1 :: The x-coordinate of the segment's start point. */ 01166 /* */ 01167 /* y1 :: The y-coordinate of the segment's start point. */ 01168 /* */ 01169 /* x2 :: The x-coordinate of the segment's end point. */ 01170 /* */ 01171 /* y2 :: The y-coordinate of the segment's end point. */ 01172 /* */ 01173 /* miny :: A lower vertical clipping bound value. */ 01174 /* */ 01175 /* maxy :: An upper vertical clipping bound value. */ 01176 /* */ 01177 /* <Return> */ 01178 /* SUCCESS on success, FAILURE on render pool overflow. */ 01179 /* */ 01180 static Bool 01181 Line_Down( RAS_ARGS Long x1, 01182 Long y1, 01183 Long x2, 01184 Long y2, 01185 Long miny, 01186 Long maxy ) 01187 { 01188 Bool result, fresh; 01189 01190 01191 fresh = ras.fresh; 01192 01193 result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); 01194 01195 if ( fresh && !ras.fresh ) 01196 ras.cProfile->start = -ras.cProfile->start; 01197 01198 return result; 01199 } 01200 01201 01202 /* A function type describing the functions used to split Bezier arcs */ 01203 typedef void (*TSplitter)( TPoint* base ); 01204 01205 01206 /*************************************************************************/ 01207 /* */ 01208 /* <Function> */ 01209 /* Bezier_Up */ 01210 /* */ 01211 /* <Description> */ 01212 /* Compute the x-coordinates of an ascending Bezier arc and store */ 01213 /* them in the render pool. */ 01214 /* */ 01215 /* <Input> */ 01216 /* degree :: The degree of the Bezier arc (either 2 or 3). */ 01217 /* */ 01218 /* splitter :: The function to split Bezier arcs. */ 01219 /* */ 01220 /* miny :: A lower vertical clipping bound value. */ 01221 /* */ 01222 /* maxy :: An upper vertical clipping bound value. */ 01223 /* */ 01224 /* <Return> */ 01225 /* SUCCESS on success, FAILURE on render pool overflow. */ 01226 /* */ 01227 static Bool 01228 Bezier_Up( RAS_ARGS Int degree, 01229 TSplitter splitter, 01230 Long miny, 01231 Long maxy ) 01232 { 01233 Long y1, y2, e, e2, e0; 01234 Short f1; 01235 01236 TPoint* arc; 01237 TPoint* start_arc; 01238 01239 PLong top; 01240 01241 01242 arc = ras.arc; 01243 y1 = arc[degree].y; 01244 y2 = arc[0].y; 01245 top = ras.top; 01246 01247 if ( y2 < miny || y1 > maxy ) 01248 goto Fin; 01249 01250 e2 = FLOOR( y2 ); 01251 01252 if ( e2 > maxy ) 01253 e2 = maxy; 01254 01255 e0 = miny; 01256 01257 if ( y1 < miny ) 01258 e = miny; 01259 else 01260 { 01261 e = CEILING( y1 ); 01262 f1 = (Short)( FRAC( y1 ) ); 01263 e0 = e; 01264 01265 if ( f1 == 0 ) 01266 { 01267 if ( ras.joint ) 01268 { 01269 top--; 01270 ras.joint = FALSE; 01271 } 01272 01273 *top++ = arc[degree].x; 01274 01275 e += ras.precision; 01276 } 01277 } 01278 01279 if ( ras.fresh ) 01280 { 01281 ras.cProfile->start = TRUNC( e0 ); 01282 ras.fresh = FALSE; 01283 } 01284 01285 if ( e2 < e ) 01286 goto Fin; 01287 01288 if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) 01289 { 01290 ras.top = top; 01291 ras.error = Raster_Err_Overflow; 01292 return FAILURE; 01293 } 01294 01295 start_arc = arc; 01296 01297 while ( arc >= start_arc && e <= e2 ) 01298 { 01299 ras.joint = FALSE; 01300 01301 y2 = arc[0].y; 01302 01303 if ( y2 > e ) 01304 { 01305 y1 = arc[degree].y; 01306 if ( y2 - y1 >= ras.precision_step ) 01307 { 01308 splitter( arc ); 01309 arc += degree; 01310 } 01311 else 01312 { 01313 *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, 01314 e - y1, y2 - y1 ); 01315 arc -= degree; 01316 e += ras.precision; 01317 } 01318 } 01319 else 01320 { 01321 if ( y2 == e ) 01322 { 01323 ras.joint = TRUE; 01324 *top++ = arc[0].x; 01325 01326 e += ras.precision; 01327 } 01328 arc -= degree; 01329 } 01330 } 01331 01332 Fin: 01333 ras.top = top; 01334 ras.arc -= degree; 01335 return SUCCESS; 01336 } 01337 01338 01339 /*************************************************************************/ 01340 /* */ 01341 /* <Function> */ 01342 /* Bezier_Down */ 01343 /* */ 01344 /* <Description> */ 01345 /* Compute the x-coordinates of an descending Bezier arc and store */ 01346 /* them in the render pool. */ 01347 /* */ 01348 /* <Input> */ 01349 /* degree :: The degree of the Bezier arc (either 2 or 3). */ 01350 /* */ 01351 /* splitter :: The function to split Bezier arcs. */ 01352 /* */ 01353 /* miny :: A lower vertical clipping bound value. */ 01354 /* */ 01355 /* maxy :: An upper vertical clipping bound value. */ 01356 /* */ 01357 /* <Return> */ 01358 /* SUCCESS on success, FAILURE on render pool overflow. */ 01359 /* */ 01360 static Bool 01361 Bezier_Down( RAS_ARGS Int degree, 01362 TSplitter splitter, 01363 Long miny, 01364 Long maxy ) 01365 { 01366 TPoint* arc = ras.arc; 01367 Bool result, fresh; 01368 01369 01370 arc[0].y = -arc[0].y; 01371 arc[1].y = -arc[1].y; 01372 arc[2].y = -arc[2].y; 01373 if ( degree > 2 ) 01374 arc[3].y = -arc[3].y; 01375 01376 fresh = ras.fresh; 01377 01378 result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny ); 01379 01380 if ( fresh && !ras.fresh ) 01381 ras.cProfile->start = -ras.cProfile->start; 01382 01383 arc[0].y = -arc[0].y; 01384 return result; 01385 } 01386 01387 01388 /*************************************************************************/ 01389 /* */ 01390 /* <Function> */ 01391 /* Line_To */ 01392 /* */ 01393 /* <Description> */ 01394 /* Inject a new line segment and adjust the Profiles list. */ 01395 /* */ 01396 /* <Input> */ 01397 /* x :: The x-coordinate of the segment's end point (its start point */ 01398 /* is stored in `lastX'). */ 01399 /* */ 01400 /* y :: The y-coordinate of the segment's end point (its start point */ 01401 /* is stored in `lastY'). */ 01402 /* */ 01403 /* <Return> */ 01404 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 01405 /* profile. */ 01406 /* */ 01407 static Bool 01408 Line_To( RAS_ARGS Long x, 01409 Long y ) 01410 { 01411 /* First, detect a change of direction */ 01412 01413 switch ( ras.state ) 01414 { 01415 case Unknown_State: 01416 if ( y > ras.lastY ) 01417 { 01418 if ( New_Profile( RAS_VARS Ascending_State, 01419 IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) 01420 return FAILURE; 01421 } 01422 else 01423 { 01424 if ( y < ras.lastY ) 01425 if ( New_Profile( RAS_VARS Descending_State, 01426 IS_TOP_OVERSHOOT( ras.lastY ) ) ) 01427 return FAILURE; 01428 } 01429 break; 01430 01431 case Ascending_State: 01432 if ( y < ras.lastY ) 01433 { 01434 if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || 01435 New_Profile( RAS_VARS Descending_State, 01436 IS_TOP_OVERSHOOT( ras.lastY ) ) ) 01437 return FAILURE; 01438 } 01439 break; 01440 01441 case Descending_State: 01442 if ( y > ras.lastY ) 01443 { 01444 if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || 01445 New_Profile( RAS_VARS Ascending_State, 01446 IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) 01447 return FAILURE; 01448 } 01449 break; 01450 01451 default: 01452 ; 01453 } 01454 01455 /* Then compute the lines */ 01456 01457 switch ( ras.state ) 01458 { 01459 case Ascending_State: 01460 if ( Line_Up( RAS_VARS ras.lastX, ras.lastY, 01461 x, y, ras.minY, ras.maxY ) ) 01462 return FAILURE; 01463 break; 01464 01465 case Descending_State: 01466 if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, 01467 x, y, ras.minY, ras.maxY ) ) 01468 return FAILURE; 01469 break; 01470 01471 default: 01472 ; 01473 } 01474 01475 ras.lastX = x; 01476 ras.lastY = y; 01477 01478 return SUCCESS; 01479 } 01480 01481 01482 /*************************************************************************/ 01483 /* */ 01484 /* <Function> */ 01485 /* Conic_To */ 01486 /* */ 01487 /* <Description> */ 01488 /* Inject a new conic arc and adjust the profile list. */ 01489 /* */ 01490 /* <Input> */ 01491 /* cx :: The x-coordinate of the arc's new control point. */ 01492 /* */ 01493 /* cy :: The y-coordinate of the arc's new control point. */ 01494 /* */ 01495 /* x :: The x-coordinate of the arc's end point (its start point is */ 01496 /* stored in `lastX'). */ 01497 /* */ 01498 /* y :: The y-coordinate of the arc's end point (its start point is */ 01499 /* stored in `lastY'). */ 01500 /* */ 01501 /* <Return> */ 01502 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 01503 /* profile. */ 01504 /* */ 01505 static Bool 01506 Conic_To( RAS_ARGS Long cx, 01507 Long cy, 01508 Long x, 01509 Long y ) 01510 { 01511 Long y1, y2, y3, x3, ymin, ymax; 01512 TStates state_bez; 01513 01514 01515 ras.arc = ras.arcs; 01516 ras.arc[2].x = ras.lastX; 01517 ras.arc[2].y = ras.lastY; 01518 ras.arc[1].x = cx; 01519 ras.arc[1].y = cy; 01520 ras.arc[0].x = x; 01521 ras.arc[0].y = y; 01522 01523 do 01524 { 01525 y1 = ras.arc[2].y; 01526 y2 = ras.arc[1].y; 01527 y3 = ras.arc[0].y; 01528 x3 = ras.arc[0].x; 01529 01530 /* first, categorize the Bezier arc */ 01531 01532 if ( y1 <= y3 ) 01533 { 01534 ymin = y1; 01535 ymax = y3; 01536 } 01537 else 01538 { 01539 ymin = y3; 01540 ymax = y1; 01541 } 01542 01543 if ( y2 < ymin || y2 > ymax ) 01544 { 01545 /* this arc has no given direction, split it! */ 01546 Split_Conic( ras.arc ); 01547 ras.arc += 2; 01548 } 01549 else if ( y1 == y3 ) 01550 { 01551 /* this arc is flat, ignore it and pop it from the Bezier stack */ 01552 ras.arc -= 2; 01553 } 01554 else 01555 { 01556 /* the arc is y-monotonous, either ascending or descending */ 01557 /* detect a change of direction */ 01558 state_bez = y1 < y3 ? Ascending_State : Descending_State; 01559 if ( ras.state != state_bez ) 01560 { 01561 Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) 01562 : IS_TOP_OVERSHOOT( y1 ); 01563 01564 01565 /* finalize current profile if any */ 01566 if ( ras.state != Unknown_State && 01567 End_Profile( RAS_VARS o ) ) 01568 goto Fail; 01569 01570 /* create a new profile */ 01571 if ( New_Profile( RAS_VARS state_bez, o ) ) 01572 goto Fail; 01573 } 01574 01575 /* now call the appropriate routine */ 01576 if ( state_bez == Ascending_State ) 01577 { 01578 if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) 01579 goto Fail; 01580 } 01581 else 01582 if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) 01583 goto Fail; 01584 } 01585 01586 } while ( ras.arc >= ras.arcs ); 01587 01588 ras.lastX = x3; 01589 ras.lastY = y3; 01590 01591 return SUCCESS; 01592 01593 Fail: 01594 return FAILURE; 01595 } 01596 01597 01598 /*************************************************************************/ 01599 /* */ 01600 /* <Function> */ 01601 /* Cubic_To */ 01602 /* */ 01603 /* <Description> */ 01604 /* Inject a new cubic arc and adjust the profile list. */ 01605 /* */ 01606 /* <Input> */ 01607 /* cx1 :: The x-coordinate of the arc's first new control point. */ 01608 /* */ 01609 /* cy1 :: The y-coordinate of the arc's first new control point. */ 01610 /* */ 01611 /* cx2 :: The x-coordinate of the arc's second new control point. */ 01612 /* */ 01613 /* cy2 :: The y-coordinate of the arc's second new control point. */ 01614 /* */ 01615 /* x :: The x-coordinate of the arc's end point (its start point is */ 01616 /* stored in `lastX'). */ 01617 /* */ 01618 /* y :: The y-coordinate of the arc's end point (its start point is */ 01619 /* stored in `lastY'). */ 01620 /* */ 01621 /* <Return> */ 01622 /* SUCCESS on success, FAILURE on render pool overflow or incorrect */ 01623 /* profile. */ 01624 /* */ 01625 static Bool 01626 Cubic_To( RAS_ARGS Long cx1, 01627 Long cy1, 01628 Long cx2, 01629 Long cy2, 01630 Long x, 01631 Long y ) 01632 { 01633 Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; 01634 TStates state_bez; 01635 01636 01637 ras.arc = ras.arcs; 01638 ras.arc[3].x = ras.lastX; 01639 ras.arc[3].y = ras.lastY; 01640 ras.arc[2].x = cx1; 01641 ras.arc[2].y = cy1; 01642 ras.arc[1].x = cx2; 01643 ras.arc[1].y = cy2; 01644 ras.arc[0].x = x; 01645 ras.arc[0].y = y; 01646 01647 do 01648 { 01649 y1 = ras.arc[3].y; 01650 y2 = ras.arc[2].y; 01651 y3 = ras.arc[1].y; 01652 y4 = ras.arc[0].y; 01653 x4 = ras.arc[0].x; 01654 01655 /* first, categorize the Bezier arc */ 01656 01657 if ( y1 <= y4 ) 01658 { 01659 ymin1 = y1; 01660 ymax1 = y4; 01661 } 01662 else 01663 { 01664 ymin1 = y4; 01665 ymax1 = y1; 01666 } 01667 01668 if ( y2 <= y3 ) 01669 { 01670 ymin2 = y2; 01671 ymax2 = y3; 01672 } 01673 else 01674 { 01675 ymin2 = y3; 01676 ymax2 = y2; 01677 } 01678 01679 if ( ymin2 < ymin1 || ymax2 > ymax1 ) 01680 { 01681 /* this arc has no given direction, split it! */ 01682 Split_Cubic( ras.arc ); 01683 ras.arc += 3; 01684 } 01685 else if ( y1 == y4 ) 01686 { 01687 /* this arc is flat, ignore it and pop it from the Bezier stack */ 01688 ras.arc -= 3; 01689 } 01690 else 01691 { 01692 state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; 01693 01694 /* detect a change of direction */ 01695 if ( ras.state != state_bez ) 01696 { 01697 Bool o = state_bez == Ascending_State ? IS_BOTTOM_OVERSHOOT( y1 ) 01698 : IS_TOP_OVERSHOOT( y1 ); 01699 01700 01701 /* finalize current profile if any */ 01702 if ( ras.state != Unknown_State && 01703 End_Profile( RAS_VARS o ) ) 01704 goto Fail; 01705 01706 if ( New_Profile( RAS_VARS state_bez, o ) ) 01707 goto Fail; 01708 } 01709 01710 /* compute intersections */ 01711 if ( state_bez == Ascending_State ) 01712 { 01713 if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) 01714 goto Fail; 01715 } 01716 else 01717 if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) 01718 goto Fail; 01719 } 01720 01721 } while ( ras.arc >= ras.arcs ); 01722 01723 ras.lastX = x4; 01724 ras.lastY = y4; 01725 01726 return SUCCESS; 01727 01728 Fail: 01729 return FAILURE; 01730 } 01731 01732 01733 #undef SWAP_ 01734 #define SWAP_( x, y ) do \ 01735 { \ 01736 Long swap = x; \ 01737 \ 01738 \ 01739 x = y; \ 01740 y = swap; \ 01741 } while ( 0 ) 01742 01743 01744 /*************************************************************************/ 01745 /* */ 01746 /* <Function> */ 01747 /* Decompose_Curve */ 01748 /* */ 01749 /* <Description> */ 01750 /* Scan the outline arrays in order to emit individual segments and */ 01751 /* Beziers by calling Line_To() and Bezier_To(). It handles all */ 01752 /* weird cases, like when the first point is off the curve, or when */ 01753 /* there are simply no `on' points in the contour! */ 01754 /* */ 01755 /* <Input> */ 01756 /* first :: The index of the first point in the contour. */ 01757 /* */ 01758 /* last :: The index of the last point in the contour. */ 01759 /* */ 01760 /* flipped :: If set, flip the direction of the curve. */ 01761 /* */ 01762 /* <Return> */ 01763 /* SUCCESS on success, FAILURE on error. */ 01764 /* */ 01765 static Bool 01766 Decompose_Curve( RAS_ARGS UShort first, 01767 UShort last, 01768 int flipped ) 01769 { 01770 FT_Vector v_last; 01771 FT_Vector v_control; 01772 FT_Vector v_start; 01773 01774 FT_Vector* points; 01775 FT_Vector* point; 01776 FT_Vector* limit; 01777 char* tags; 01778 01779 unsigned tag; /* current point's state */ 01780 01781 01782 points = ras.outline.points; 01783 limit = points + last; 01784 01785 v_start.x = SCALED( points[first].x ); 01786 v_start.y = SCALED( points[first].y ); 01787 v_last.x = SCALED( points[last].x ); 01788 v_last.y = SCALED( points[last].y ); 01789 01790 if ( flipped ) 01791 { 01792 SWAP_( v_start.x, v_start.y ); 01793 SWAP_( v_last.x, v_last.y ); 01794 } 01795 01796 v_control = v_start; 01797 01798 point = points + first; 01799 tags = ras.outline.tags + first; 01800 01801 /* set scan mode if necessary */ 01802 if ( tags[0] & FT_CURVE_TAG_HAS_SCANMODE ) 01803 ras.dropOutControl = (Byte)tags[0] >> 5; 01804 01805 tag = FT_CURVE_TAG( tags[0] ); 01806 01807 /* A contour cannot start with a cubic control point! */ 01808 if ( tag == FT_CURVE_TAG_CUBIC ) 01809 goto Invalid_Outline; 01810 01811 /* check first point to determine origin */ 01812 if ( tag == FT_CURVE_TAG_CONIC ) 01813 { 01814 /* first point is conic control. Yes, this happens. */ 01815 if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) 01816 { 01817 /* start at last point if it is on the curve */ 01818 v_start = v_last; 01819 limit--; 01820 } 01821 else 01822 { 01823 /* if both first and last points are conic, */ 01824 /* start at their middle and record its position */ 01825 /* for closure */ 01826 v_start.x = ( v_start.x + v_last.x ) / 2; 01827 v_start.y = ( v_start.y + v_last.y ) / 2; 01828 01829 v_last = v_start; 01830 } 01831 point--; 01832 tags--; 01833 } 01834 01835 ras.lastX = v_start.x; 01836 ras.lastY = v_start.y; 01837 01838 while ( point < limit ) 01839 { 01840 point++; 01841 tags++; 01842 01843 tag = FT_CURVE_TAG( tags[0] ); 01844 01845 switch ( tag ) 01846 { 01847 case FT_CURVE_TAG_ON: /* emit a single line_to */ 01848 { 01849 Long x, y; 01850 01851 01852 x = SCALED( point->x ); 01853 y = SCALED( point->y ); 01854 if ( flipped ) 01855 SWAP_( x, y ); 01856 01857 if ( Line_To( RAS_VARS x, y ) ) 01858 goto Fail; 01859 continue; 01860 } 01861 01862 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 01863 v_control.x = SCALED( point[0].x ); 01864 v_control.y = SCALED( point[0].y ); 01865 01866 if ( flipped ) 01867 SWAP_( v_control.x, v_control.y ); 01868 01869 Do_Conic: 01870 if ( point < limit ) 01871 { 01872 FT_Vector v_middle; 01873 Long x, y; 01874 01875 01876 point++; 01877 tags++; 01878 tag = FT_CURVE_TAG( tags[0] ); 01879 01880 x = SCALED( point[0].x ); 01881 y = SCALED( point[0].y ); 01882 01883 if ( flipped ) 01884 SWAP_( x, y ); 01885 01886 if ( tag == FT_CURVE_TAG_ON ) 01887 { 01888 if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) ) 01889 goto Fail; 01890 continue; 01891 } 01892 01893 if ( tag != FT_CURVE_TAG_CONIC ) 01894 goto Invalid_Outline; 01895 01896 v_middle.x = ( v_control.x + x ) / 2; 01897 v_middle.y = ( v_control.y + y ) / 2; 01898 01899 if ( Conic_To( RAS_VARS v_control.x, v_control.y, 01900 v_middle.x, v_middle.y ) ) 01901 goto Fail; 01902 01903 v_control.x = x; 01904 v_control.y = y; 01905 01906 goto Do_Conic; 01907 } 01908 01909 if ( Conic_To( RAS_VARS v_control.x, v_control.y, 01910 v_start.x, v_start.y ) ) 01911 goto Fail; 01912 01913 goto Close; 01914 01915 default: /* FT_CURVE_TAG_CUBIC */ 01916 { 01917 Long x1, y1, x2, y2, x3, y3; 01918 01919 01920 if ( point + 1 > limit || 01921 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 01922 goto Invalid_Outline; 01923 01924 point += 2; 01925 tags += 2; 01926 01927 x1 = SCALED( point[-2].x ); 01928 y1 = SCALED( point[-2].y ); 01929 x2 = SCALED( point[-1].x ); 01930 y2 = SCALED( point[-1].y ); 01931 01932 if ( flipped ) 01933 { 01934 SWAP_( x1, y1 ); 01935 SWAP_( x2, y2 ); 01936 } 01937 01938 if ( point <= limit ) 01939 { 01940 x3 = SCALED( point[0].x ); 01941 y3 = SCALED( point[0].y ); 01942 01943 if ( flipped ) 01944 SWAP_( x3, y3 ); 01945 01946 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) 01947 goto Fail; 01948 continue; 01949 } 01950 01951 if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) ) 01952 goto Fail; 01953 goto Close; 01954 } 01955 } 01956 } 01957 01958 /* close the contour with a line segment */ 01959 if ( Line_To( RAS_VARS v_start.x, v_start.y ) ) 01960 goto Fail; 01961 01962 Close: 01963 return SUCCESS; 01964 01965 Invalid_Outline: 01966 ras.error = Raster_Err_Invalid; 01967 01968 Fail: 01969 return FAILURE; 01970 } 01971 01972 01973 /*************************************************************************/ 01974 /* */ 01975 /* <Function> */ 01976 /* Convert_Glyph */ 01977 /* */ 01978 /* <Description> */ 01979 /* Convert a glyph into a series of segments and arcs and make a */ 01980 /* profiles list with them. */ 01981 /* */ 01982 /* <Input> */ 01983 /* flipped :: If set, flip the direction of curve. */ 01984 /* */ 01985 /* <Return> */ 01986 /* SUCCESS on success, FAILURE if any error was encountered during */ 01987 /* rendering. */ 01988 /* */ 01989 static Bool 01990 Convert_Glyph( RAS_ARGS int flipped ) 01991 { 01992 int i; 01993 unsigned start; 01994 01995 PProfile lastProfile; 01996 01997 01998 ras.fProfile = NULL; 01999 ras.joint = FALSE; 02000 ras.fresh = FALSE; 02001 02002 ras.maxBuff = ras.sizeBuff - AlignProfileSize; 02003 02004 ras.numTurns = 0; 02005 02006 ras.cProfile = (PProfile)ras.top; 02007 ras.cProfile->offset = ras.top; 02008 ras.num_Profs = 0; 02009 02010 start = 0; 02011 02012 for ( i = 0; i < ras.outline.n_contours; i++ ) 02013 { 02014 Bool o; 02015 02016 02017 ras.state = Unknown_State; 02018 ras.gProfile = NULL; 02019 02020 if ( Decompose_Curve( RAS_VARS (unsigned short)start, 02021 ras.outline.contours[i], 02022 flipped ) ) 02023 return FAILURE; 02024 02025 start = ras.outline.contours[i] + 1; 02026 02027 /* we must now check whether the extreme arcs join or not */ 02028 if ( FRAC( ras.lastY ) == 0 && 02029 ras.lastY >= ras.minY && 02030 ras.lastY <= ras.maxY ) 02031 if ( ras.gProfile && 02032 ( ras.gProfile->flags & Flow_Up ) == 02033 ( ras.cProfile->flags & Flow_Up ) ) 02034 ras.top--; 02035 /* Note that ras.gProfile can be nil if the contour was too small */ 02036 /* to be drawn. */ 02037 02038 lastProfile = ras.cProfile; 02039 if ( ras.cProfile->flags & Flow_Up ) 02040 o = IS_TOP_OVERSHOOT( ras.lastY ); 02041 else 02042 o = IS_BOTTOM_OVERSHOOT( ras.lastY ); 02043 if ( End_Profile( RAS_VARS o ) ) 02044 return FAILURE; 02045 02046 /* close the `next profile in contour' linked list */ 02047 if ( ras.gProfile ) 02048 lastProfile->next = ras.gProfile; 02049 } 02050 02051 if ( Finalize_Profile_Table( RAS_VAR ) ) 02052 return FAILURE; 02053 02054 return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); 02055 } 02056 02057 02058 /*************************************************************************/ 02059 /*************************************************************************/ 02063 /*************************************************************************/ 02064 /*************************************************************************/ 02065 02066 02067 /*************************************************************************/ 02068 /* */ 02069 /* Init_Linked */ 02070 /* */ 02071 /* Initializes an empty linked list. */ 02072 /* */ 02073 static void 02074 Init_Linked( TProfileList* l ) 02075 { 02076 *l = NULL; 02077 } 02078 02079 02080 /*************************************************************************/ 02081 /* */ 02082 /* InsNew */ 02083 /* */ 02084 /* Inserts a new profile in a linked list. */ 02085 /* */ 02086 static void 02087 InsNew( PProfileList list, 02088 PProfile profile ) 02089 { 02090 PProfile *old, current; 02091 Long x; 02092 02093 02094 old = list; 02095 current = *old; 02096 x = profile->X; 02097 02098 while ( current ) 02099 { 02100 if ( x < current->X ) 02101 break; 02102 old = ¤t->link; 02103 current = *old; 02104 } 02105 02106 profile->link = current; 02107 *old = profile; 02108 } 02109 02110 02111 /*************************************************************************/ 02112 /* */ 02113 /* DelOld */ 02114 /* */ 02115 /* Removes an old profile from a linked list. */ 02116 /* */ 02117 static void 02118 DelOld( PProfileList list, 02119 PProfile profile ) 02120 { 02121 PProfile *old, current; 02122 02123 02124 old = list; 02125 current = *old; 02126 02127 while ( current ) 02128 { 02129 if ( current == profile ) 02130 { 02131 *old = current->link; 02132 return; 02133 } 02134 02135 old = ¤t->link; 02136 current = *old; 02137 } 02138 02139 /* we should never get there, unless the profile was not part of */ 02140 /* the list. */ 02141 } 02142 02143 02144 /*************************************************************************/ 02145 /* */ 02146 /* Sort */ 02147 /* */ 02148 /* Sorts a trace list. In 95%, the list is already sorted. We need */ 02149 /* an algorithm which is fast in this case. Bubble sort is enough */ 02150 /* and simple. */ 02151 /* */ 02152 static void 02153 Sort( PProfileList list ) 02154 { 02155 PProfile *old, current, next; 02156 02157 02158 /* First, set the new X coordinate of each profile */ 02159 current = *list; 02160 while ( current ) 02161 { 02162 current->X = *current->offset; 02163 current->offset += current->flags & Flow_Up ? 1 : -1; 02164 current->height--; 02165 current = current->link; 02166 } 02167 02168 /* Then sort them */ 02169 old = list; 02170 current = *old; 02171 02172 if ( !current ) 02173 return; 02174 02175 next = current->link; 02176 02177 while ( next ) 02178 { 02179 if ( current->X <= next->X ) 02180 { 02181 old = ¤t->link; 02182 current = *old; 02183 02184 if ( !current ) 02185 return; 02186 } 02187 else 02188 { 02189 *old = next; 02190 current->link = next->link; 02191 next->link = current; 02192 02193 old = list; 02194 current = *old; 02195 } 02196 02197 next = current->link; 02198 } 02199 } 02200 02201 02202 /*************************************************************************/ 02203 /* */ 02204 /* Vertical Sweep Procedure Set */ 02205 /* */ 02206 /* These four routines are used during the vertical black/white sweep */ 02207 /* phase by the generic Draw_Sweep() function. */ 02208 /* */ 02209 /*************************************************************************/ 02210 02211 static void 02212 Vertical_Sweep_Init( RAS_ARGS Short* min, 02213 Short* max ) 02214 { 02215 Long pitch = ras.target.pitch; 02216 02217 FT_UNUSED( max ); 02218 02219 02220 ras.traceIncr = (Short)-pitch; 02221 ras.traceOfs = -*min * pitch; 02222 if ( pitch > 0 ) 02223 ras.traceOfs += ( ras.target.rows - 1 ) * pitch; 02224 02225 ras.gray_min_x = 0; 02226 ras.gray_max_x = 0; 02227 } 02228 02229 02230 static void 02231 Vertical_Sweep_Span( RAS_ARGS Short y, 02232 FT_F26Dot6 x1, 02233 FT_F26Dot6 x2, 02234 PProfile left, 02235 PProfile right ) 02236 { 02237 Long e1, e2; 02238 int c1, c2; 02239 Byte f1, f2; 02240 Byte* target; 02241 02242 FT_UNUSED( y ); 02243 FT_UNUSED( left ); 02244 FT_UNUSED( right ); 02245 02246 02247 /* Drop-out control */ 02248 02249 e1 = TRUNC( CEILING( x1 ) ); 02250 02251 if ( x2 - x1 - ras.precision <= ras.precision_jitter ) 02252 e2 = e1; 02253 else 02254 e2 = TRUNC( FLOOR( x2 ) ); 02255 02256 if ( e2 >= 0 && e1 < ras.bWidth ) 02257 { 02258 if ( e1 < 0 ) 02259 e1 = 0; 02260 if ( e2 >= ras.bWidth ) 02261 e2 = ras.bWidth - 1; 02262 02263 c1 = (Short)( e1 >> 3 ); 02264 c2 = (Short)( e2 >> 3 ); 02265 02266 f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); 02267 f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); 02268 02269 if ( ras.gray_min_x > c1 ) 02270 ras.gray_min_x = (short)c1; 02271 if ( ras.gray_max_x < c2 ) 02272 ras.gray_max_x = (short)c2; 02273 02274 target = ras.bTarget + ras.traceOfs + c1; 02275 c2 -= c1; 02276 02277 if ( c2 > 0 ) 02278 { 02279 target[0] |= f1; 02280 02281 /* memset() is slower than the following code on many platforms. */ 02282 /* This is due to the fact that, in the vast majority of cases, */ 02283 /* the span length in bytes is relatively small. */ 02284 c2--; 02285 while ( c2 > 0 ) 02286 { 02287 *(++target) = 0xFF; 02288 c2--; 02289 } 02290 target[1] |= f2; 02291 } 02292 else 02293 *target |= ( f1 & f2 ); 02294 } 02295 } 02296 02297 02298 static void 02299 Vertical_Sweep_Drop( RAS_ARGS Short y, 02300 FT_F26Dot6 x1, 02301 FT_F26Dot6 x2, 02302 PProfile left, 02303 PProfile right ) 02304 { 02305 Long e1, e2, pxl; 02306 Short c1, f1; 02307 02308 02309 /* Drop-out control */ 02310 02311 /* e2 x2 x1 e1 */ 02312 /* */ 02313 /* ^ | */ 02314 /* | | */ 02315 /* +-------------+---------------------+------------+ */ 02316 /* | | */ 02317 /* | v */ 02318 /* */ 02319 /* pixel contour contour pixel */ 02320 /* center center */ 02321 02322 /* drop-out mode scan conversion rules (as defined in OpenType) */ 02323 /* --------------------------------------------------------------- */ 02324 /* 0 1, 2, 3 */ 02325 /* 1 1, 2, 4 */ 02326 /* 2 1, 2 */ 02327 /* 3 same as mode 2 */ 02328 /* 4 1, 2, 5 */ 02329 /* 5 1, 2, 6 */ 02330 /* 6, 7 same as mode 2 */ 02331 02332 e1 = CEILING( x1 ); 02333 e2 = FLOOR ( x2 ); 02334 pxl = e1; 02335 02336 if ( e1 > e2 ) 02337 { 02338 Int dropOutControl = left->flags & 7; 02339 02340 02341 if ( e1 == e2 + ras.precision ) 02342 { 02343 switch ( dropOutControl ) 02344 { 02345 case 0: /* simple drop-outs including stubs */ 02346 pxl = e2; 02347 break; 02348 02349 case 4: /* smart drop-outs including stubs */ 02350 pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02351 break; 02352 02353 case 1: /* simple drop-outs excluding stubs */ 02354 case 5: /* smart drop-outs excluding stubs */ 02355 02356 /* Drop-out Control Rules #4 and #6 */ 02357 02358 /* The specification neither provides an exact definition */ 02359 /* of a `stub' nor gives exact rules to exclude them. */ 02360 /* */ 02361 /* Here the constraints we use to recognize a stub. */ 02362 /* */ 02363 /* upper stub: */ 02364 /* */ 02365 /* - P_Left and P_Right are in the same contour */ 02366 /* - P_Right is the successor of P_Left in that contour */ 02367 /* - y is the top of P_Left and P_Right */ 02368 /* */ 02369 /* lower stub: */ 02370 /* */ 02371 /* - P_Left and P_Right are in the same contour */ 02372 /* - P_Left is the successor of P_Right in that contour */ 02373 /* - y is the bottom of P_Left */ 02374 /* */ 02375 /* We draw a stub if the following constraints are met. */ 02376 /* */ 02377 /* - for an upper or lower stub, there is top or bottom */ 02378 /* overshoot, respectively */ 02379 /* - the covered interval is greater or equal to a half */ 02380 /* pixel */ 02381 02382 /* upper stub test */ 02383 if ( left->next == right && 02384 left->height <= 0 && 02385 !( left->flags & Overshoot_Top && 02386 x2 - x1 >= ras.precision_half ) ) 02387 return; 02388 02389 /* lower stub test */ 02390 if ( right->next == left && 02391 left->start == y && 02392 !( left->flags & Overshoot_Bottom && 02393 x2 - x1 >= ras.precision_half ) ) 02394 return; 02395 02396 if ( dropOutControl == 1 ) 02397 pxl = e2; 02398 else 02399 pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02400 break; 02401 02402 default: /* modes 2, 3, 6, 7 */ 02403 return; /* no drop-out control */ 02404 } 02405 02406 /* check that the other pixel isn't set */ 02407 e1 = pxl == e1 ? e2 : e1; 02408 02409 e1 = TRUNC( e1 ); 02410 02411 c1 = (Short)( e1 >> 3 ); 02412 f1 = (Short)( e1 & 7 ); 02413 02414 if ( e1 >= 0 && e1 < ras.bWidth && 02415 ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) 02416 return; 02417 } 02418 else 02419 return; 02420 } 02421 02422 e1 = TRUNC( pxl ); 02423 02424 if ( e1 >= 0 && e1 < ras.bWidth ) 02425 { 02426 c1 = (Short)( e1 >> 3 ); 02427 f1 = (Short)( e1 & 7 ); 02428 02429 if ( ras.gray_min_x > c1 ) 02430 ras.gray_min_x = c1; 02431 if ( ras.gray_max_x < c1 ) 02432 ras.gray_max_x = c1; 02433 02434 ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); 02435 } 02436 } 02437 02438 02439 static void 02440 Vertical_Sweep_Step( RAS_ARG ) 02441 { 02442 ras.traceOfs += ras.traceIncr; 02443 } 02444 02445 02446 /***********************************************************************/ 02447 /* */ 02448 /* Horizontal Sweep Procedure Set */ 02449 /* */ 02450 /* These four routines are used during the horizontal black/white */ 02451 /* sweep phase by the generic Draw_Sweep() function. */ 02452 /* */ 02453 /***********************************************************************/ 02454 02455 static void 02456 Horizontal_Sweep_Init( RAS_ARGS Short* min, 02457 Short* max ) 02458 { 02459 /* nothing, really */ 02460 FT_UNUSED_RASTER; 02461 FT_UNUSED( min ); 02462 FT_UNUSED( max ); 02463 } 02464 02465 02466 static void 02467 Horizontal_Sweep_Span( RAS_ARGS Short y, 02468 FT_F26Dot6 x1, 02469 FT_F26Dot6 x2, 02470 PProfile left, 02471 PProfile right ) 02472 { 02473 Long e1, e2; 02474 PByte bits; 02475 Byte f1; 02476 02477 FT_UNUSED( left ); 02478 FT_UNUSED( right ); 02479 02480 02481 if ( x2 - x1 < ras.precision ) 02482 { 02483 e1 = CEILING( x1 ); 02484 e2 = FLOOR ( x2 ); 02485 02486 if ( e1 == e2 ) 02487 { 02488 bits = ras.bTarget + ( y >> 3 ); 02489 f1 = (Byte)( 0x80 >> ( y & 7 ) ); 02490 02491 e1 = TRUNC( e1 ); 02492 02493 if ( e1 >= 0 && e1 < ras.target.rows ) 02494 { 02495 PByte p; 02496 02497 02498 p = bits - e1 * ras.target.pitch; 02499 if ( ras.target.pitch > 0 ) 02500 p += ( ras.target.rows - 1 ) * ras.target.pitch; 02501 02502 p[0] |= f1; 02503 } 02504 } 02505 } 02506 } 02507 02508 02509 static void 02510 Horizontal_Sweep_Drop( RAS_ARGS Short y, 02511 FT_F26Dot6 x1, 02512 FT_F26Dot6 x2, 02513 PProfile left, 02514 PProfile right ) 02515 { 02516 Long e1, e2, pxl; 02517 PByte bits; 02518 Byte f1; 02519 02520 02521 /* During the horizontal sweep, we only take care of drop-outs */ 02522 02523 /* e1 + <-- pixel center */ 02524 /* | */ 02525 /* x1 ---+--> <-- contour */ 02526 /* | */ 02527 /* | */ 02528 /* x2 <--+--- <-- contour */ 02529 /* | */ 02530 /* | */ 02531 /* e2 + <-- pixel center */ 02532 02533 e1 = CEILING( x1 ); 02534 e2 = FLOOR ( x2 ); 02535 pxl = e1; 02536 02537 if ( e1 > e2 ) 02538 { 02539 Int dropOutControl = left->flags & 7; 02540 02541 02542 if ( e1 == e2 + ras.precision ) 02543 { 02544 switch ( dropOutControl ) 02545 { 02546 case 0: /* simple drop-outs including stubs */ 02547 pxl = e2; 02548 break; 02549 02550 case 4: /* smart drop-outs including stubs */ 02551 pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02552 break; 02553 02554 case 1: /* simple drop-outs excluding stubs */ 02555 case 5: /* smart drop-outs excluding stubs */ 02556 /* see Vertical_Sweep_Drop for details */ 02557 02558 /* rightmost stub test */ 02559 if ( left->next == right && 02560 left->height <= 0 && 02561 !( left->flags & Overshoot_Top && 02562 x2 - x1 >= ras.precision_half ) ) 02563 return; 02564 02565 /* leftmost stub test */ 02566 if ( right->next == left && 02567 left->start == y && 02568 !( left->flags & Overshoot_Bottom && 02569 x2 - x1 >= ras.precision_half ) ) 02570 return; 02571 02572 if ( dropOutControl == 1 ) 02573 pxl = e2; 02574 else 02575 pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02576 break; 02577 02578 default: /* modes 2, 3, 6, 7 */ 02579 return; /* no drop-out control */ 02580 } 02581 02582 /* check that the other pixel isn't set */ 02583 e1 = pxl == e1 ? e2 : e1; 02584 02585 e1 = TRUNC( e1 ); 02586 02587 bits = ras.bTarget + ( y >> 3 ); 02588 f1 = (Byte)( 0x80 >> ( y & 7 ) ); 02589 02590 bits -= e1 * ras.target.pitch; 02591 if ( ras.target.pitch > 0 ) 02592 bits += ( ras.target.rows - 1 ) * ras.target.pitch; 02593 02594 if ( e1 >= 0 && 02595 e1 < ras.target.rows && 02596 *bits & f1 ) 02597 return; 02598 } 02599 else 02600 return; 02601 } 02602 02603 bits = ras.bTarget + ( y >> 3 ); 02604 f1 = (Byte)( 0x80 >> ( y & 7 ) ); 02605 02606 e1 = TRUNC( pxl ); 02607 02608 if ( e1 >= 0 && e1 < ras.target.rows ) 02609 { 02610 bits -= e1 * ras.target.pitch; 02611 if ( ras.target.pitch > 0 ) 02612 bits += ( ras.target.rows - 1 ) * ras.target.pitch; 02613 02614 bits[0] |= f1; 02615 } 02616 } 02617 02618 02619 static void 02620 Horizontal_Sweep_Step( RAS_ARG ) 02621 { 02622 /* Nothing, really */ 02623 FT_UNUSED_RASTER; 02624 } 02625 02626 02627 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 02628 02629 02630 /*************************************************************************/ 02631 /* */ 02632 /* Vertical Gray Sweep Procedure Set */ 02633 /* */ 02634 /* These two routines are used during the vertical gray-levels sweep */ 02635 /* phase by the generic Draw_Sweep() function. */ 02636 /* */ 02637 /* NOTES */ 02638 /* */ 02639 /* - The target pixmap's width *must* be a multiple of 4. */ 02640 /* */ 02641 /* - You have to use the function Vertical_Sweep_Span() for the gray */ 02642 /* span call. */ 02643 /* */ 02644 /*************************************************************************/ 02645 02646 static void 02647 Vertical_Gray_Sweep_Init( RAS_ARGS Short* min, 02648 Short* max ) 02649 { 02650 Long pitch, byte_len; 02651 02652 02653 *min = *min & -2; 02654 *max = ( *max + 3 ) & -2; 02655 02656 ras.traceOfs = 0; 02657 pitch = ras.target.pitch; 02658 byte_len = -pitch; 02659 ras.traceIncr = (Short)byte_len; 02660 ras.traceG = ( *min / 2 ) * byte_len; 02661 02662 if ( pitch > 0 ) 02663 { 02664 ras.traceG += ( ras.target.rows - 1 ) * pitch; 02665 byte_len = -byte_len; 02666 } 02667 02668 ras.gray_min_x = (Short)byte_len; 02669 ras.gray_max_x = -(Short)byte_len; 02670 } 02671 02672 02673 static void 02674 Vertical_Gray_Sweep_Step( RAS_ARG ) 02675 { 02676 Int c1, c2; 02677 PByte pix, bit, bit2; 02678 short* count = (short*)count_table; 02679 Byte* grays; 02680 02681 02682 ras.traceOfs += ras.gray_width; 02683 02684 if ( ras.traceOfs > ras.gray_width ) 02685 { 02686 pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4; 02687 grays = ras.grays; 02688 02689 if ( ras.gray_max_x >= 0 ) 02690 { 02691 Long last_pixel = ras.target.width - 1; 02692 Int last_cell = last_pixel >> 2; 02693 Int last_bit = last_pixel & 3; 02694 Bool over = 0; 02695 02696 02697 if ( ras.gray_max_x >= last_cell && last_bit != 3 ) 02698 { 02699 ras.gray_max_x = last_cell - 1; 02700 over = 1; 02701 } 02702 02703 if ( ras.gray_min_x < 0 ) 02704 ras.gray_min_x = 0; 02705 02706 bit = ras.bTarget + ras.gray_min_x; 02707 bit2 = bit + ras.gray_width; 02708 02709 c1 = ras.gray_max_x - ras.gray_min_x; 02710 02711 while ( c1 >= 0 ) 02712 { 02713 c2 = count[*bit] + count[*bit2]; 02714 02715 if ( c2 ) 02716 { 02717 pix[0] = grays[(c2 >> 12) & 0x000F]; 02718 pix[1] = grays[(c2 >> 8 ) & 0x000F]; 02719 pix[2] = grays[(c2 >> 4 ) & 0x000F]; 02720 pix[3] = grays[ c2 & 0x000F]; 02721 02722 *bit = 0; 02723 *bit2 = 0; 02724 } 02725 02726 bit++; 02727 bit2++; 02728 pix += 4; 02729 c1--; 02730 } 02731 02732 if ( over ) 02733 { 02734 c2 = count[*bit] + count[*bit2]; 02735 if ( c2 ) 02736 { 02737 switch ( last_bit ) 02738 { 02739 case 2: 02740 pix[2] = grays[(c2 >> 4 ) & 0x000F]; 02741 case 1: 02742 pix[1] = grays[(c2 >> 8 ) & 0x000F]; 02743 default: 02744 pix[0] = grays[(c2 >> 12) & 0x000F]; 02745 } 02746 02747 *bit = 0; 02748 *bit2 = 0; 02749 } 02750 } 02751 } 02752 02753 ras.traceOfs = 0; 02754 ras.traceG += ras.traceIncr; 02755 02756 ras.gray_min_x = 32000; 02757 ras.gray_max_x = -32000; 02758 } 02759 } 02760 02761 02762 static void 02763 Horizontal_Gray_Sweep_Span( RAS_ARGS Short y, 02764 FT_F26Dot6 x1, 02765 FT_F26Dot6 x2, 02766 PProfile left, 02767 PProfile right ) 02768 { 02769 /* nothing, really */ 02770 FT_UNUSED_RASTER; 02771 FT_UNUSED( y ); 02772 FT_UNUSED( x1 ); 02773 FT_UNUSED( x2 ); 02774 FT_UNUSED( left ); 02775 FT_UNUSED( right ); 02776 } 02777 02778 02779 static void 02780 Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y, 02781 FT_F26Dot6 x1, 02782 FT_F26Dot6 x2, 02783 PProfile left, 02784 PProfile right ) 02785 { 02786 Long e1, e2; 02787 PByte pixel; 02788 Byte color; 02789 02790 02791 /* During the horizontal sweep, we only take care of drop-outs */ 02792 02793 e1 = CEILING( x1 ); 02794 e2 = FLOOR ( x2 ); 02795 02796 if ( e1 > e2 ) 02797 { 02798 Int dropOutControl = left->flags & 7; 02799 02800 02801 if ( e1 == e2 + ras.precision ) 02802 { 02803 switch ( dropOutControl ) 02804 { 02805 case 0: /* simple drop-outs including stubs */ 02806 e1 = e2; 02807 break; 02808 02809 case 4: /* smart drop-outs including stubs */ 02810 e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02811 break; 02812 02813 case 1: /* simple drop-outs excluding stubs */ 02814 case 5: /* smart drop-outs excluding stubs */ 02815 /* see Vertical_Sweep_Drop for details */ 02816 02817 /* rightmost stub test */ 02818 if ( left->next == right && left->height <= 0 ) 02819 return; 02820 02821 /* leftmost stub test */ 02822 if ( right->next == left && left->start == y ) 02823 return; 02824 02825 if ( dropOutControl == 1 ) 02826 e1 = e2; 02827 else 02828 e1 = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); 02829 02830 break; 02831 02832 default: /* modes 2, 3, 6, 7 */ 02833 return; /* no drop-out control */ 02834 } 02835 } 02836 else 02837 return; 02838 } 02839 02840 if ( e1 >= 0 ) 02841 { 02842 if ( x2 - x1 >= ras.precision_half ) 02843 color = ras.grays[2]; 02844 else 02845 color = ras.grays[1]; 02846 02847 e1 = TRUNC( e1 ) / 2; 02848 if ( e1 < ras.target.rows ) 02849 { 02850 pixel = ras.gTarget - e1 * ras.target.pitch + y / 2; 02851 if ( ras.target.pitch > 0 ) 02852 pixel += ( ras.target.rows - 1 ) * ras.target.pitch; 02853 02854 if ( pixel[0] == ras.grays[0] ) 02855 pixel[0] = color; 02856 } 02857 } 02858 } 02859 02860 02861 #endif /* FT_RASTER_OPTION_ANTI_ALIASING */ 02862 02863 02864 /*************************************************************************/ 02865 /* */ 02866 /* Generic Sweep Drawing routine */ 02867 /* */ 02868 /*************************************************************************/ 02869 02870 static Bool 02871 Draw_Sweep( RAS_ARG ) 02872 { 02873 Short y, y_change, y_height; 02874 02875 PProfile P, Q, P_Left, P_Right; 02876 02877 Short min_Y, max_Y, top, bottom, dropouts; 02878 02879 Long x1, x2, xs, e1, e2; 02880 02881 TProfileList waiting; 02882 TProfileList draw_left, draw_right; 02883 02884 02885 /* initialize empty linked lists */ 02886 02887 Init_Linked( &waiting ); 02888 02889 Init_Linked( &draw_left ); 02890 Init_Linked( &draw_right ); 02891 02892 /* first, compute min and max Y */ 02893 02894 P = ras.fProfile; 02895 max_Y = (Short)TRUNC( ras.minY ); 02896 min_Y = (Short)TRUNC( ras.maxY ); 02897 02898 while ( P ) 02899 { 02900 Q = P->link; 02901 02902 bottom = (Short)P->start; 02903 top = (Short)( P->start + P->height - 1 ); 02904 02905 if ( min_Y > bottom ) 02906 min_Y = bottom; 02907 if ( max_Y < top ) 02908 max_Y = top; 02909 02910 P->X = 0; 02911 InsNew( &waiting, P ); 02912 02913 P = Q; 02914 } 02915 02916 /* check the Y-turns */ 02917 if ( ras.numTurns == 0 ) 02918 { 02919 ras.error = Raster_Err_Invalid; 02920 return FAILURE; 02921 } 02922 02923 /* now initialize the sweep */ 02924 02925 ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y ); 02926 02927 /* then compute the distance of each profile from min_Y */ 02928 02929 P = waiting; 02930 02931 while ( P ) 02932 { 02933 P->countL = (UShort)( P->start - min_Y ); 02934 P = P->link; 02935 } 02936 02937 /* let's go */ 02938 02939 y = min_Y; 02940 y_height = 0; 02941 02942 if ( ras.numTurns > 0 && 02943 ras.sizeBuff[-ras.numTurns] == min_Y ) 02944 ras.numTurns--; 02945 02946 while ( ras.numTurns > 0 ) 02947 { 02948 /* check waiting list for new activations */ 02949 02950 P = waiting; 02951 02952 while ( P ) 02953 { 02954 Q = P->link; 02955 P->countL -= y_height; 02956 if ( P->countL == 0 ) 02957 { 02958 DelOld( &waiting, P ); 02959 02960 if ( P->flags & Flow_Up ) 02961 InsNew( &draw_left, P ); 02962 else 02963 InsNew( &draw_right, P ); 02964 } 02965 02966 P = Q; 02967 } 02968 02969 /* sort the drawing lists */ 02970 02971 Sort( &draw_left ); 02972 Sort( &draw_right ); 02973 02974 y_change = (Short)ras.sizeBuff[-ras.numTurns--]; 02975 y_height = (Short)( y_change - y ); 02976 02977 while ( y < y_change ) 02978 { 02979 /* let's trace */ 02980 02981 dropouts = 0; 02982 02983 P_Left = draw_left; 02984 P_Right = draw_right; 02985 02986 while ( P_Left ) 02987 { 02988 x1 = P_Left ->X; 02989 x2 = P_Right->X; 02990 02991 if ( x1 > x2 ) 02992 { 02993 xs = x1; 02994 x1 = x2; 02995 x2 = xs; 02996 } 02997 02998 e1 = FLOOR( x1 ); 02999 e2 = CEILING( x2 ); 03000 03001 if ( x2 - x1 <= ras.precision && 03002 e1 != x1 && e2 != x2 ) 03003 { 03004 if ( e1 > e2 || e2 == e1 + ras.precision ) 03005 { 03006 Int dropOutControl = P_Left->flags & 7; 03007 03008 03009 if ( dropOutControl != 2 ) 03010 { 03011 /* a drop-out was detected */ 03012 03013 P_Left ->X = x1; 03014 P_Right->X = x2; 03015 03016 /* mark profile for drop-out processing */ 03017 P_Left->countL = 1; 03018 dropouts++; 03019 } 03020 03021 goto Skip_To_Next; 03022 } 03023 } 03024 03025 ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); 03026 03027 Skip_To_Next: 03028 03029 P_Left = P_Left->link; 03030 P_Right = P_Right->link; 03031 } 03032 03033 /* handle drop-outs _after_ the span drawing -- */ 03034 /* drop-out processing has been moved out of the loop */ 03035 /* for performance tuning */ 03036 if ( dropouts > 0 ) 03037 goto Scan_DropOuts; 03038 03039 Next_Line: 03040 03041 ras.Proc_Sweep_Step( RAS_VAR ); 03042 03043 y++; 03044 03045 if ( y < y_change ) 03046 { 03047 Sort( &draw_left ); 03048 Sort( &draw_right ); 03049 } 03050 } 03051 03052 /* now finalize the profiles that need it */ 03053 03054 P = draw_left; 03055 while ( P ) 03056 { 03057 Q = P->link; 03058 if ( P->height == 0 ) 03059 DelOld( &draw_left, P ); 03060 P = Q; 03061 } 03062 03063 P = draw_right; 03064 while ( P ) 03065 { 03066 Q = P->link; 03067 if ( P->height == 0 ) 03068 DelOld( &draw_right, P ); 03069 P = Q; 03070 } 03071 } 03072 03073 /* for gray-scaling, flush the bitmap scanline cache */ 03074 while ( y <= max_Y ) 03075 { 03076 ras.Proc_Sweep_Step( RAS_VAR ); 03077 y++; 03078 } 03079 03080 return SUCCESS; 03081 03082 Scan_DropOuts: 03083 03084 P_Left = draw_left; 03085 P_Right = draw_right; 03086 03087 while ( P_Left ) 03088 { 03089 if ( P_Left->countL ) 03090 { 03091 P_Left->countL = 0; 03092 #if 0 03093 dropouts--; /* -- this is useful when debugging only */ 03094 #endif 03095 ras.Proc_Sweep_Drop( RAS_VARS y, 03096 P_Left->X, 03097 P_Right->X, 03098 P_Left, 03099 P_Right ); 03100 } 03101 03102 P_Left = P_Left->link; 03103 P_Right = P_Right->link; 03104 } 03105 03106 goto Next_Line; 03107 } 03108 03109 03110 /*************************************************************************/ 03111 /* */ 03112 /* <Function> */ 03113 /* Render_Single_Pass */ 03114 /* */ 03115 /* <Description> */ 03116 /* Perform one sweep with sub-banding. */ 03117 /* */ 03118 /* <Input> */ 03119 /* flipped :: If set, flip the direction of the outline. */ 03120 /* */ 03121 /* <Return> */ 03122 /* Renderer error code. */ 03123 /* */ 03124 static int 03125 Render_Single_Pass( RAS_ARGS Bool flipped ) 03126 { 03127 Short i, j, k; 03128 03129 03130 while ( ras.band_top >= 0 ) 03131 { 03132 ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision; 03133 ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision; 03134 03135 ras.top = ras.buff; 03136 03137 ras.error = Raster_Err_None; 03138 03139 if ( Convert_Glyph( RAS_VARS flipped ) ) 03140 { 03141 if ( ras.error != Raster_Err_Overflow ) 03142 return FAILURE; 03143 03144 ras.error = Raster_Err_None; 03145 03146 /* sub-banding */ 03147 03148 #ifdef DEBUG_RASTER 03149 ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); 03150 #endif 03151 03152 i = ras.band_stack[ras.band_top].y_min; 03153 j = ras.band_stack[ras.band_top].y_max; 03154 03155 k = (Short)( ( i + j ) / 2 ); 03156 03157 if ( ras.band_top >= 7 || k < i ) 03158 { 03159 ras.band_top = 0; 03160 ras.error = Raster_Err_Invalid; 03161 03162 return ras.error; 03163 } 03164 03165 ras.band_stack[ras.band_top + 1].y_min = k; 03166 ras.band_stack[ras.band_top + 1].y_max = j; 03167 03168 ras.band_stack[ras.band_top].y_max = (Short)( k - 1 ); 03169 03170 ras.band_top++; 03171 } 03172 else 03173 { 03174 if ( ras.fProfile ) 03175 if ( Draw_Sweep( RAS_VAR ) ) 03176 return ras.error; 03177 ras.band_top--; 03178 } 03179 } 03180 03181 return SUCCESS; 03182 } 03183 03184 03185 /*************************************************************************/ 03186 /* */ 03187 /* <Function> */ 03188 /* Render_Glyph */ 03189 /* */ 03190 /* <Description> */ 03191 /* Render a glyph in a bitmap. Sub-banding if needed. */ 03192 /* */ 03193 /* <Return> */ 03194 /* FreeType error code. 0 means success. */ 03195 /* */ 03196 FT_LOCAL_DEF( FT_Error ) 03197 Render_Glyph( RAS_ARG ) 03198 { 03199 FT_Error error; 03200 03201 03202 Set_High_Precision( RAS_VARS ras.outline.flags & 03203 FT_OUTLINE_HIGH_PRECISION ); 03204 ras.scale_shift = ras.precision_shift; 03205 03206 if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) 03207 ras.dropOutControl = 2; 03208 else 03209 { 03210 if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) 03211 ras.dropOutControl = 4; 03212 else 03213 ras.dropOutControl = 0; 03214 03215 if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) 03216 ras.dropOutControl += 1; 03217 } 03218 03219 ras.second_pass = (FT_Byte)( !( ras.outline.flags & 03220 FT_OUTLINE_SINGLE_PASS ) ); 03221 03222 /* Vertical Sweep */ 03223 ras.Proc_Sweep_Init = Vertical_Sweep_Init; 03224 ras.Proc_Sweep_Span = Vertical_Sweep_Span; 03225 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; 03226 ras.Proc_Sweep_Step = Vertical_Sweep_Step; 03227 03228 ras.band_top = 0; 03229 ras.band_stack[0].y_min = 0; 03230 ras.band_stack[0].y_max = (short)( ras.target.rows - 1 ); 03231 03232 ras.bWidth = (unsigned short)ras.target.width; 03233 ras.bTarget = (Byte*)ras.target.buffer; 03234 03235 if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) 03236 return error; 03237 03238 /* Horizontal Sweep */ 03239 if ( ras.second_pass && ras.dropOutControl != 2 ) 03240 { 03241 ras.Proc_Sweep_Init = Horizontal_Sweep_Init; 03242 ras.Proc_Sweep_Span = Horizontal_Sweep_Span; 03243 ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop; 03244 ras.Proc_Sweep_Step = Horizontal_Sweep_Step; 03245 03246 ras.band_top = 0; 03247 ras.band_stack[0].y_min = 0; 03248 ras.band_stack[0].y_max = (short)( ras.target.width - 1 ); 03249 03250 if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 ) 03251 return error; 03252 } 03253 03254 return Raster_Err_None; 03255 } 03256 03257 03258 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 03259 03260 /*************************************************************************/ 03261 /* */ 03262 /* <Function> */ 03263 /* Render_Gray_Glyph */ 03264 /* */ 03265 /* <Description> */ 03266 /* Render a glyph with grayscaling. Sub-banding if needed. */ 03267 /* */ 03268 /* <Return> */ 03269 /* FreeType error code. 0 means success. */ 03270 /* */ 03271 FT_LOCAL_DEF( FT_Error ) 03272 Render_Gray_Glyph( RAS_ARG ) 03273 { 03274 Long pixel_width; 03275 FT_Error error; 03276 03277 03278 Set_High_Precision( RAS_VARS ras.outline.flags & 03279 FT_OUTLINE_HIGH_PRECISION ); 03280 ras.scale_shift = ras.precision_shift + 1; 03281 03282 if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) 03283 ras.dropOutControl = 2; 03284 else 03285 { 03286 if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) 03287 ras.dropOutControl = 4; 03288 else 03289 ras.dropOutControl = 0; 03290 03291 if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) 03292 ras.dropOutControl += 1; 03293 } 03294 03295 ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ); 03296 03297 /* Vertical Sweep */ 03298 03299 ras.band_top = 0; 03300 ras.band_stack[0].y_min = 0; 03301 ras.band_stack[0].y_max = 2 * ras.target.rows - 1; 03302 03303 ras.bWidth = ras.gray_width; 03304 pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 ); 03305 03306 if ( ras.bWidth > pixel_width ) 03307 ras.bWidth = pixel_width; 03308 03309 ras.bWidth = ras.bWidth * 8; 03310 ras.bTarget = (Byte*)ras.gray_lines; 03311 ras.gTarget = (Byte*)ras.target.buffer; 03312 03313 ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init; 03314 ras.Proc_Sweep_Span = Vertical_Sweep_Span; 03315 ras.Proc_Sweep_Drop = Vertical_Sweep_Drop; 03316 ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step; 03317 03318 error = Render_Single_Pass( RAS_VARS 0 ); 03319 if ( error ) 03320 return error; 03321 03322 /* Horizontal Sweep */ 03323 if ( ras.second_pass && ras.dropOutControl != 2 ) 03324 { 03325 ras.Proc_Sweep_Init = Horizontal_Sweep_Init; 03326 ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span; 03327 ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop; 03328 ras.Proc_Sweep_Step = Horizontal_Sweep_Step; 03329 03330 ras.band_top = 0; 03331 ras.band_stack[0].y_min = 0; 03332 ras.band_stack[0].y_max = ras.target.width * 2 - 1; 03333 03334 error = Render_Single_Pass( RAS_VARS 1 ); 03335 if ( error ) 03336 return error; 03337 } 03338 03339 return Raster_Err_None; 03340 } 03341 03342 #else /* !FT_RASTER_OPTION_ANTI_ALIASING */ 03343 03344 FT_LOCAL_DEF( FT_Error ) 03345 Render_Gray_Glyph( RAS_ARG ) 03346 { 03347 FT_UNUSED_RASTER; 03348 03349 return Raster_Err_Unsupported; 03350 } 03351 03352 #endif /* !FT_RASTER_OPTION_ANTI_ALIASING */ 03353 03354 03355 static void 03356 ft_black_init( PRaster raster ) 03357 { 03358 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 03359 FT_UInt n; 03360 03361 03362 /* set default 5-levels gray palette */ 03363 for ( n = 0; n < 5; n++ ) 03364 raster->grays[n] = n * 255 / 4; 03365 03366 raster->gray_width = RASTER_GRAY_LINES / 2; 03367 #else 03368 FT_UNUSED( raster ); 03369 #endif 03370 } 03371 03372 03373 /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/ 03374 /**** a static object. *****/ 03375 03376 03377 #ifdef _STANDALONE_ 03378 03379 03380 static int 03381 ft_black_new( void* memory, 03382 FT_Raster *araster ) 03383 { 03384 static TRaster the_raster; 03385 FT_UNUSED( memory ); 03386 03387 03388 *araster = (FT_Raster)&the_raster; 03389 FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) ); 03390 ft_black_init( &the_raster ); 03391 03392 return 0; 03393 } 03394 03395 03396 static void 03397 ft_black_done( FT_Raster raster ) 03398 { 03399 /* nothing */ 03400 FT_UNUSED( raster ); 03401 } 03402 03403 03404 #else /* !_STANDALONE_ */ 03405 03406 03407 static int 03408 ft_black_new( FT_Memory memory, 03409 PRaster *araster ) 03410 { 03411 FT_Error error; 03412 PRaster raster = NULL; 03413 03414 03415 *araster = 0; 03416 if ( !FT_NEW( raster ) ) 03417 { 03418 raster->memory = memory; 03419 ft_black_init( raster ); 03420 03421 *araster = raster; 03422 } 03423 03424 return error; 03425 } 03426 03427 03428 static void 03429 ft_black_done( PRaster raster ) 03430 { 03431 FT_Memory memory = (FT_Memory)raster->memory; 03432 FT_FREE( raster ); 03433 } 03434 03435 03436 #endif /* !_STANDALONE_ */ 03437 03438 03439 static void 03440 ft_black_reset( PRaster raster, 03441 char* pool_base, 03442 long pool_size ) 03443 { 03444 if ( raster ) 03445 { 03446 if ( pool_base && pool_size >= (long)sizeof(TWorker) + 2048 ) 03447 { 03448 PWorker worker = (PWorker)pool_base; 03449 03450 03451 raster->buffer = pool_base + ( ( sizeof ( *worker ) + 7 ) & ~7 ); 03452 raster->buffer_size = pool_base + pool_size - (char*)raster->buffer; 03453 raster->worker = worker; 03454 } 03455 else 03456 { 03457 raster->buffer = NULL; 03458 raster->buffer_size = 0; 03459 raster->worker = NULL; 03460 } 03461 } 03462 } 03463 03464 03465 static void 03466 ft_black_set_mode( PRaster raster, 03467 unsigned long mode, 03468 const char* palette ) 03469 { 03470 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 03471 03472 if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) ) 03473 { 03474 /* set 5-levels gray palette */ 03475 raster->grays[0] = palette[0]; 03476 raster->grays[1] = palette[1]; 03477 raster->grays[2] = palette[2]; 03478 raster->grays[3] = palette[3]; 03479 raster->grays[4] = palette[4]; 03480 } 03481 03482 #else 03483 03484 FT_UNUSED( raster ); 03485 FT_UNUSED( mode ); 03486 FT_UNUSED( palette ); 03487 03488 #endif 03489 } 03490 03491 03492 static int 03493 ft_black_render( PRaster raster, 03494 const FT_Raster_Params* params ) 03495 { 03496 const FT_Outline* outline = (const FT_Outline*)params->source; 03497 const FT_Bitmap* target_map = params->target; 03498 PWorker worker; 03499 03500 03501 if ( !raster || !raster->buffer || !raster->buffer_size ) 03502 return Raster_Err_Not_Ini; 03503 03504 if ( !outline ) 03505 return Raster_Err_Invalid; 03506 03507 /* return immediately if the outline is empty */ 03508 if ( outline->n_points == 0 || outline->n_contours <= 0 ) 03509 return Raster_Err_None; 03510 03511 if ( !outline->contours || !outline->points ) 03512 return Raster_Err_Invalid; 03513 03514 if ( outline->n_points != 03515 outline->contours[outline->n_contours - 1] + 1 ) 03516 return Raster_Err_Invalid; 03517 03518 worker = raster->worker; 03519 03520 /* this version of the raster does not support direct rendering, sorry */ 03521 if ( params->flags & FT_RASTER_FLAG_DIRECT ) 03522 return Raster_Err_Unsupported; 03523 03524 if ( !target_map ) 03525 return Raster_Err_Invalid; 03526 03527 /* nothing to do */ 03528 if ( !target_map->width || !target_map->rows ) 03529 return Raster_Err_None; 03530 03531 if ( !target_map->buffer ) 03532 return Raster_Err_Invalid; 03533 03534 ras.outline = *outline; 03535 ras.target = *target_map; 03536 03537 worker->buff = (PLong) raster->buffer; 03538 worker->sizeBuff = worker->buff + 03539 raster->buffer_size / sizeof ( Long ); 03540 #ifdef FT_RASTER_OPTION_ANTI_ALIASING 03541 worker->grays = raster->grays; 03542 worker->gray_width = raster->gray_width; 03543 03544 FT_MEM_ZERO( worker->gray_lines, worker->gray_width * 2 ); 03545 #endif 03546 03547 return ( params->flags & FT_RASTER_FLAG_AA ) 03548 ? Render_Gray_Glyph( RAS_VAR ) 03549 : Render_Glyph( RAS_VAR ); 03550 } 03551 03552 03553 FT_DEFINE_RASTER_FUNCS( ft_standard_raster, 03554 FT_GLYPH_FORMAT_OUTLINE, 03555 (FT_Raster_New_Func) ft_black_new, 03556 (FT_Raster_Reset_Func) ft_black_reset, 03557 (FT_Raster_Set_Mode_Func)ft_black_set_mode, 03558 (FT_Raster_Render_Func) ft_black_render, 03559 (FT_Raster_Done_Func) ft_black_done 03560 ) 03561 03562 03563 /* END */ Generated on Sat May 26 2012 04:32:55 for ReactOS by
1.7.6.1
|