/src/freetype/src/raster/ftraster.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 3612 lines · 2079 code · 732 blank · 801 comment · 336 complexity · 7039c09154560704ab85e1459afc4098 MD5 · raw file

Large files are truncated click here to view the full file

  1. /***************************************************************************/
  2. /* */
  3. /* ftraster.c */
  4. /* */
  5. /* The FreeType glyph rasterizer (body). */
  6. /* */
  7. /* Copyright 1996-2003, 2005, 2007-2012 by */
  8. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  9. /* */
  10. /* This file is part of the FreeType project, and may only be used, */
  11. /* modified, and distributed under the terms of the FreeType project */
  12. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  13. /* this file you indicate that you have read the license and */
  14. /* understand and accept it fully. */
  15. /* */
  16. /***************************************************************************/
  17. /*************************************************************************/
  18. /* */
  19. /* This file can be compiled without the rest of the FreeType engine, by */
  20. /* defining the _STANDALONE_ macro when compiling it. You also need to */
  21. /* put the files `ftimage.h' and `ftmisc.h' into the $(incdir) */
  22. /* directory. Typically, you should do something like */
  23. /* */
  24. /* - copy `src/raster/ftraster.c' (this file) to your current directory */
  25. /* */
  26. /* - copy `include/freetype/ftimage.h' and `src/raster/ftmisc.h' */
  27. /* to your current directory */
  28. /* */
  29. /* - compile `ftraster' with the _STANDALONE_ macro defined, as in */
  30. /* */
  31. /* cc -c -D_STANDALONE_ ftraster.c */
  32. /* */
  33. /* The renderer can be initialized with a call to */
  34. /* `ft_standard_raster.raster_new'; a bitmap can be generated */
  35. /* with a call to `ft_standard_raster.raster_render'. */
  36. /* */
  37. /* See the comments and documentation in the file `ftimage.h' for more */
  38. /* details on how the raster works. */
  39. /* */
  40. /*************************************************************************/
  41. /*************************************************************************/
  42. /* */
  43. /* This is a rewrite of the FreeType 1.x scan-line converter */
  44. /* */
  45. /*************************************************************************/
  46. #ifdef _STANDALONE_
  47. #define FT_CONFIG_STANDARD_LIBRARY_H <stdlib.h>
  48. #include <string.h> /* for memset */
  49. #include "ftmisc.h"
  50. #include "ftimage.h"
  51. #else /* !_STANDALONE_ */
  52. #include <ft2build.h>
  53. #include "ftraster.h"
  54. #include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
  55. #include "rastpic.h"
  56. #endif /* !_STANDALONE_ */
  57. /*************************************************************************/
  58. /* */
  59. /* A simple technical note on how the raster works */
  60. /* ----------------------------------------------- */
  61. /* */
  62. /* Converting an outline into a bitmap is achieved in several steps: */
  63. /* */
  64. /* 1 - Decomposing the outline into successive `profiles'. Each */
  65. /* profile is simply an array of scanline intersections on a given */
  66. /* dimension. A profile's main attributes are */
  67. /* */
  68. /* o its scanline position boundaries, i.e. `Ymin' and `Ymax' */
  69. /* */
  70. /* o an array of intersection coordinates for each scanline */
  71. /* between `Ymin' and `Ymax' */
  72. /* */
  73. /* o a direction, indicating whether it was built going `up' or */
  74. /* `down', as this is very important for filling rules */
  75. /* */
  76. /* o its drop-out mode */
  77. /* */
  78. /* 2 - Sweeping the target map's scanlines in order to compute segment */
  79. /* `spans' which are then filled. Additionally, this pass */
  80. /* performs drop-out control. */
  81. /* */
  82. /* The outline data is parsed during step 1 only. The profiles are */
  83. /* built from the bottom of the render pool, used as a stack. The */
  84. /* following graphics shows the profile list under construction: */
  85. /* */
  86. /* __________________________________________________________ _ _ */
  87. /* | | | | | */
  88. /* | profile | coordinates for | profile | coordinates for |--> */
  89. /* | 1 | profile 1 | 2 | profile 2 |--> */
  90. /* |_________|_________________|_________|_________________|__ _ _ */
  91. /* */
  92. /* ^ ^ */
  93. /* | | */
  94. /* start of render pool top */
  95. /* */
  96. /* The top of the profile stack is kept in the `top' variable. */
  97. /* */
  98. /* As you can see, a profile record is pushed on top of the render */
  99. /* pool, which is then followed by its coordinates/intersections. If */
  100. /* a change of direction is detected in the outline, a new profile is */
  101. /* generated until the end of the outline. */
  102. /* */
  103. /* Note that when all profiles have been generated, the function */
  104. /* Finalize_Profile_Table() is used to record, for each profile, its */
  105. /* bottom-most scanline as well as the scanline above its upmost */
  106. /* boundary. These positions are called `y-turns' because they (sort */
  107. /* of) correspond to local extrema. They are stored in a sorted list */
  108. /* built from the top of the render pool as a downwards stack: */
  109. /* */
  110. /* _ _ _______________________________________ */
  111. /* | | */
  112. /* <--| sorted list of | */
  113. /* <--| extrema scanlines | */
  114. /* _ _ __________________|____________________| */
  115. /* */
  116. /* ^ ^ */
  117. /* | | */
  118. /* maxBuff sizeBuff = end of pool */
  119. /* */
  120. /* This list is later used during the sweep phase in order to */
  121. /* optimize performance (see technical note on the sweep below). */
  122. /* */
  123. /* Of course, the raster detects whether the two stacks collide and */
  124. /* handles the situation properly. */
  125. /* */
  126. /*************************************************************************/
  127. /*************************************************************************/
  128. /*************************************************************************/
  129. /** **/
  130. /** CONFIGURATION MACROS **/
  131. /** **/
  132. /*************************************************************************/
  133. /*************************************************************************/
  134. /* define DEBUG_RASTER if you want to compile a debugging version */
  135. /* #define DEBUG_RASTER */
  136. /* define FT_RASTER_OPTION_ANTI_ALIASING if you want to support */
  137. /* 5-levels anti-aliasing */
  138. /* #define FT_RASTER_OPTION_ANTI_ALIASING */
  139. /* The size of the two-lines intermediate bitmap used */
  140. /* for anti-aliasing, in bytes. */
  141. #define RASTER_GRAY_LINES 2048
  142. /*************************************************************************/
  143. /*************************************************************************/
  144. /** **/
  145. /** OTHER MACROS (do not change) **/
  146. /** **/
  147. /*************************************************************************/
  148. /*************************************************************************/
  149. /*************************************************************************/
  150. /* */
  151. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  152. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  153. /* messages during execution. */
  154. /* */
  155. #undef FT_COMPONENT
  156. #define FT_COMPONENT trace_raster
  157. #ifdef _STANDALONE_
  158. /* This macro is used to indicate that a function parameter is unused. */
  159. /* Its purpose is simply to reduce compiler warnings. Note also that */
  160. /* simply defining it as `(void)x' doesn't avoid warnings with certain */
  161. /* ANSI compilers (e.g. LCC). */
  162. #define FT_UNUSED( x ) (x) = (x)
  163. /* Disable the tracing mechanism for simplicity -- developers can */
  164. /* activate it easily by redefining these two macros. */
  165. #ifndef FT_ERROR
  166. #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */
  167. #endif
  168. #ifndef FT_TRACE
  169. #define FT_TRACE( x ) do { } while ( 0 ) /* nothing */
  170. #define FT_TRACE1( x ) do { } while ( 0 ) /* nothing */
  171. #define FT_TRACE6( x ) do { } while ( 0 ) /* nothing */
  172. #endif
  173. #define Raster_Err_None 0
  174. #define Raster_Err_Not_Ini -1
  175. #define Raster_Err_Overflow -2
  176. #define Raster_Err_Neg_Height -3
  177. #define Raster_Err_Invalid -4
  178. #define Raster_Err_Unsupported -5
  179. #define ft_memset memset
  180. #define FT_DEFINE_RASTER_FUNCS( class_, glyph_format_, raster_new_, \
  181. raster_reset_, raster_set_mode_, \
  182. raster_render_, raster_done_ ) \
  183. const FT_Raster_Funcs class_ = \
  184. { \
  185. glyph_format_, \
  186. raster_new_, \
  187. raster_reset_, \
  188. raster_set_mode_, \
  189. raster_render_, \
  190. raster_done_ \
  191. };
  192. #else /* !_STANDALONE_ */
  193. #include FT_INTERNAL_OBJECTS_H
  194. #include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
  195. #include "rasterrs.h"
  196. #define Raster_Err_None Raster_Err_Ok
  197. #define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
  198. #define Raster_Err_Overflow Raster_Err_Raster_Overflow
  199. #define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
  200. #define Raster_Err_Invalid Raster_Err_Invalid_Outline
  201. #define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
  202. #endif /* !_STANDALONE_ */
  203. #ifndef FT_MEM_SET
  204. #define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
  205. #endif
  206. #ifndef FT_MEM_ZERO
  207. #define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
  208. #endif
  209. /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
  210. /* typically a small value and the result of a*b is known to fit into */
  211. /* 32 bits. */
  212. #define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
  213. /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
  214. /* for clipping computations. It simply uses the FT_MulDiv() function */
  215. /* defined in `ftcalc.h'. */
  216. #define SMulDiv FT_MulDiv
  217. /* The rasterizer is a very general purpose component; please leave */
  218. /* the following redefinitions there (you never know your target */
  219. /* environment). */
  220. #ifndef TRUE
  221. #define TRUE 1
  222. #endif
  223. #ifndef FALSE
  224. #define FALSE 0
  225. #endif
  226. #ifndef NULL
  227. #define NULL (void*)0
  228. #endif
  229. #ifndef SUCCESS
  230. #define SUCCESS 0
  231. #endif
  232. #ifndef FAILURE
  233. #define FAILURE 1
  234. #endif
  235. #define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
  236. /* Setting this constant to more than 32 is a */
  237. /* pure waste of space. */
  238. #define Pixel_Bits 6 /* fractional bits of *input* coordinates */
  239. /*************************************************************************/
  240. /*************************************************************************/
  241. /** **/
  242. /** SIMPLE TYPE DECLARATIONS **/
  243. /** **/
  244. /*************************************************************************/
  245. /*************************************************************************/
  246. typedef int Int;
  247. typedef unsigned int UInt;
  248. typedef short Short;
  249. typedef unsigned short UShort, *PUShort;
  250. typedef long Long, *PLong;
  251. typedef unsigned char Byte, *PByte;
  252. typedef char Bool;
  253. typedef union Alignment_
  254. {
  255. long l;
  256. void* p;
  257. void (*f)(void);
  258. } Alignment, *PAlignment;
  259. typedef struct TPoint_
  260. {
  261. Long x;
  262. Long y;
  263. } TPoint;
  264. /* values for the `flags' bit field */
  265. #define Flow_Up 0x8
  266. #define Overshoot_Top 0x10
  267. #define Overshoot_Bottom 0x20
  268. /* States of each line, arc, and profile */
  269. typedef enum TStates_
  270. {
  271. Unknown_State,
  272. Ascending_State,
  273. Descending_State,
  274. Flat_State
  275. } TStates;
  276. typedef struct TProfile_ TProfile;
  277. typedef TProfile* PProfile;
  278. struct TProfile_
  279. {
  280. FT_F26Dot6 X; /* current coordinate during sweep */
  281. PProfile link; /* link to next profile (various purposes) */
  282. PLong offset; /* start of profile's data in render pool */
  283. unsigned flags; /* Bit 0-2: drop-out mode */
  284. /* Bit 3: profile orientation (up/down) */
  285. /* Bit 4: is top profile? */
  286. /* Bit 5: is bottom profile? */
  287. long height; /* profile's height in scanlines */
  288. long start; /* profile's starting scanline */
  289. unsigned countL; /* number of lines to step before this */
  290. /* profile becomes drawable */
  291. PProfile next; /* next profile in same contour, used */
  292. /* during drop-out control */
  293. };
  294. typedef PProfile TProfileList;
  295. typedef PProfile* PProfileList;
  296. /* Simple record used to implement a stack of bands, required */
  297. /* by the sub-banding mechanism */
  298. typedef struct black_TBand_
  299. {
  300. Short y_min; /* band's minimum */
  301. Short y_max; /* band's maximum */
  302. } black_TBand;
  303. #define AlignProfileSize \
  304. ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( long ) )
  305. #undef RAS_ARG
  306. #undef RAS_ARGS
  307. #undef RAS_VAR
  308. #undef RAS_VARS
  309. #ifdef FT_STATIC_RASTER
  310. #define RAS_ARGS /* void */
  311. #define RAS_ARG /* void */
  312. #define RAS_VARS /* void */
  313. #define RAS_VAR /* void */
  314. #define FT_UNUSED_RASTER do { } while ( 0 )
  315. #else /* !FT_STATIC_RASTER */
  316. #define RAS_ARGS black_PWorker worker,
  317. #define RAS_ARG black_PWorker worker
  318. #define RAS_VARS worker,
  319. #define RAS_VAR worker
  320. #define FT_UNUSED_RASTER FT_UNUSED( worker )
  321. #endif /* !FT_STATIC_RASTER */
  322. typedef struct black_TWorker_ black_TWorker, *black_PWorker;
  323. /* prototypes used for sweep function dispatch */
  324. typedef void
  325. Function_Sweep_Init( RAS_ARGS Short* min,
  326. Short* max );
  327. typedef void
  328. Function_Sweep_Span( RAS_ARGS Short y,
  329. FT_F26Dot6 x1,
  330. FT_F26Dot6 x2,
  331. PProfile left,
  332. PProfile right );
  333. typedef void
  334. Function_Sweep_Step( RAS_ARG );
  335. /* NOTE: These operations are only valid on 2's complement processors */
  336. #undef FLOOR
  337. #undef CEILING
  338. #undef TRUNC
  339. #undef SCALED
  340. #define FLOOR( x ) ( (x) & -ras.precision )
  341. #define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
  342. #define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
  343. #define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
  344. #define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
  345. #define IS_BOTTOM_OVERSHOOT( x ) ( CEILING( x ) - x >= ras.precision_half )
  346. #define IS_TOP_OVERSHOOT( x ) ( x - FLOOR( x ) >= ras.precision_half )
  347. /* The most used variables are positioned at the top of the structure. */
  348. /* Thus, their offset can be coded with less opcodes, resulting in a */
  349. /* smaller executable. */
  350. struct black_TWorker_
  351. {
  352. Int precision_bits; /* precision related variables */
  353. Int precision;
  354. Int precision_half;
  355. Int precision_shift;
  356. Int precision_step;
  357. Int precision_jitter;
  358. Int scale_shift; /* == precision_shift for bitmaps */
  359. /* == precision_shift+1 for pixmaps */
  360. PLong buff; /* The profiles buffer */
  361. PLong sizeBuff; /* Render pool size */
  362. PLong maxBuff; /* Profiles buffer size */
  363. PLong top; /* Current cursor in buffer */
  364. FT_Error error;
  365. Int numTurns; /* number of Y-turns in outline */
  366. TPoint* arc; /* current Bezier arc pointer */
  367. UShort bWidth; /* target bitmap width */
  368. PByte bTarget; /* target bitmap buffer */
  369. PByte gTarget; /* target pixmap buffer */
  370. Long lastX, lastY;
  371. Long minY, maxY;
  372. UShort num_Profs; /* current number of profiles */
  373. Bool fresh; /* signals a fresh new profile which */
  374. /* `start' field must be completed */
  375. Bool joint; /* signals that the last arc ended */
  376. /* exactly on a scanline. Allows */
  377. /* removal of doublets */
  378. PProfile cProfile; /* current profile */
  379. PProfile fProfile; /* head of linked list of profiles */
  380. PProfile gProfile; /* contour's first profile in case */
  381. /* of impact */
  382. TStates state; /* rendering state */
  383. FT_Bitmap target; /* description of target bit/pixmap */
  384. FT_Outline outline;
  385. Long traceOfs; /* current offset in target bitmap */
  386. Long traceG; /* current offset in target pixmap */
  387. Short traceIncr; /* sweep's increment in target bitmap */
  388. Short gray_min_x; /* current min x during gray rendering */
  389. Short gray_max_x; /* current max x during gray rendering */
  390. /* dispatch variables */
  391. Function_Sweep_Init* Proc_Sweep_Init;
  392. Function_Sweep_Span* Proc_Sweep_Span;
  393. Function_Sweep_Span* Proc_Sweep_Drop;
  394. Function_Sweep_Step* Proc_Sweep_Step;
  395. Byte dropOutControl; /* current drop_out control method */
  396. Bool second_pass; /* indicates whether a horizontal pass */
  397. /* should be performed to control */
  398. /* drop-out accurately when calling */
  399. /* Render_Glyph. Note that there is */
  400. /* no horizontal pass during gray */
  401. /* rendering. */
  402. TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
  403. black_TBand band_stack[16]; /* band stack used for sub-banding */
  404. Int band_top; /* band stack top */
  405. #ifdef FT_RASTER_OPTION_ANTI_ALIASING
  406. Byte* grays;
  407. Byte gray_lines[RASTER_GRAY_LINES];
  408. /* Intermediate table used to render the */
  409. /* graylevels pixmaps. */
  410. /* gray_lines is a buffer holding two */
  411. /* monochrome scanlines */
  412. Short gray_width; /* width in bytes of one monochrome */
  413. /* intermediate scanline of gray_lines. */
  414. /* Each gray pixel takes 2 bits long there */
  415. /* The gray_lines must hold 2 lines, thus with size */
  416. /* in bytes of at least `gray_width*2'. */
  417. #endif /* FT_RASTER_ANTI_ALIASING */
  418. };
  419. typedef struct black_TRaster_
  420. {
  421. char* buffer;
  422. long buffer_size;
  423. void* memory;
  424. black_PWorker worker;
  425. Byte grays[5];
  426. Short gray_width;
  427. } black_TRaster, *black_PRaster;
  428. #ifdef FT_STATIC_RASTER
  429. static black_TWorker cur_ras;
  430. #define ras cur_ras
  431. #else /* !FT_STATIC_RASTER */
  432. #define ras (*worker)
  433. #endif /* !FT_STATIC_RASTER */
  434. #ifdef FT_RASTER_OPTION_ANTI_ALIASING
  435. /* A lookup table used to quickly count set bits in four gray 2x2 */
  436. /* cells. The values of the table have been produced with the */
  437. /* following code: */
  438. /* */
  439. /* for ( i = 0; i < 256; i++ ) */
  440. /* { */
  441. /* l = 0; */
  442. /* j = i; */
  443. /* */
  444. /* for ( c = 0; c < 4; c++ ) */
  445. /* { */
  446. /* l <<= 4; */
  447. /* */
  448. /* if ( j & 0x80 ) l++; */
  449. /* if ( j & 0x40 ) l++; */
  450. /* */
  451. /* j = ( j << 2 ) & 0xFF; */
  452. /* } */
  453. /* printf( "0x%04X", l ); */
  454. /* } */
  455. /* */
  456. static const short count_table[256] =
  457. {
  458. 0x0000, 0x0001, 0x0001, 0x0002, 0x0010, 0x0011, 0x0011, 0x0012,
  459. 0x0010, 0x0011, 0x0011, 0x0012, 0x0020, 0x0021, 0x0021, 0x0022,
  460. 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
  461. 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
  462. 0x0100, 0x0101, 0x0101, 0x0102, 0x0110, 0x0111, 0x0111, 0x0112,
  463. 0x0110, 0x0111, 0x0111, 0x0112, 0x0120, 0x0121, 0x0121, 0x0122,
  464. 0x0200, 0x0201, 0x0201, 0x0202, 0x0210, 0x0211, 0x0211, 0x0212,
  465. 0x0210, 0x0211, 0x0211, 0x0212, 0x0220, 0x0221, 0x0221, 0x0222,
  466. 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
  467. 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
  468. 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
  469. 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
  470. 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
  471. 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
  472. 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
  473. 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
  474. 0x1000, 0x1001, 0x1001, 0x1002, 0x1010, 0x1011, 0x1011, 0x1012,
  475. 0x1010, 0x1011, 0x1011, 0x1012, 0x1020, 0x1021, 0x1021, 0x1022,
  476. 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
  477. 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
  478. 0x1100, 0x1101, 0x1101, 0x1102, 0x1110, 0x1111, 0x1111, 0x1112,
  479. 0x1110, 0x1111, 0x1111, 0x1112, 0x1120, 0x1121, 0x1121, 0x1122,
  480. 0x1200, 0x1201, 0x1201, 0x1202, 0x1210, 0x1211, 0x1211, 0x1212,
  481. 0x1210, 0x1211, 0x1211, 0x1212, 0x1220, 0x1221, 0x1221, 0x1222,
  482. 0x2000, 0x2001, 0x2001, 0x2002, 0x2010, 0x2011, 0x2011, 0x2012,
  483. 0x2010, 0x2011, 0x2011, 0x2012, 0x2020, 0x2021, 0x2021, 0x2022,
  484. 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
  485. 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
  486. 0x2100, 0x2101, 0x2101, 0x2102, 0x2110, 0x2111, 0x2111, 0x2112,
  487. 0x2110, 0x2111, 0x2111, 0x2112, 0x2120, 0x2121, 0x2121, 0x2122,
  488. 0x2200, 0x2201, 0x2201, 0x2202, 0x2210, 0x2211, 0x2211, 0x2212,
  489. 0x2210, 0x2211, 0x2211, 0x2212, 0x2220, 0x2221, 0x2221, 0x2222
  490. };
  491. #endif /* FT_RASTER_OPTION_ANTI_ALIASING */
  492. /*************************************************************************/
  493. /*************************************************************************/
  494. /** **/
  495. /** PROFILES COMPUTATION **/
  496. /** **/
  497. /*************************************************************************/
  498. /*************************************************************************/
  499. /*************************************************************************/
  500. /* */
  501. /* <Function> */
  502. /* Set_High_Precision */
  503. /* */
  504. /* <Description> */
  505. /* Set precision variables according to param flag. */
  506. /* */
  507. /* <Input> */
  508. /* High :: Set to True for high precision (typically for ppem < 18), */
  509. /* false otherwise. */
  510. /* */
  511. static void
  512. Set_High_Precision( RAS_ARGS Int High )
  513. {
  514. /*
  515. * `precision_step' is used in `Bezier_Up' to decide when to split a
  516. * given y-monotonous Bezier arc that crosses a scanline before
  517. * approximating it as a straight segment. The default value of 32 (for
  518. * low accuracy) corresponds to
  519. *
  520. * 32 / 64 == 0.5 pixels ,
  521. *
  522. * while for the high accuracy case we have
  523. *
  524. * 256/ (1 << 12) = 0.0625 pixels .
  525. *
  526. * `precision_jitter' is an epsilon threshold used in
  527. * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier
  528. * decomposition (after all, we are working with approximations only);
  529. * it avoids switching on additional pixels which would cause artifacts
  530. * otherwise.
  531. *
  532. * The value of `precision_jitter' has been determined heuristically.
  533. *
  534. */
  535. if ( High )
  536. {
  537. ras.precision_bits = 12;
  538. ras.precision_step = 256;
  539. ras.precision_jitter = 30;
  540. }
  541. else
  542. {
  543. ras.precision_bits = 6;
  544. ras.precision_step = 32;
  545. ras.precision_jitter = 2;
  546. }
  547. FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
  548. ras.precision = 1 << ras.precision_bits;
  549. ras.precision_half = ras.precision / 2;
  550. ras.precision_shift = ras.precision_bits - Pixel_Bits;
  551. }
  552. /*************************************************************************/
  553. /* */
  554. /* <Function> */
  555. /* New_Profile */
  556. /* */
  557. /* <Description> */
  558. /* Create a new profile in the render pool. */
  559. /* */
  560. /* <Input> */
  561. /* aState :: The state/orientation of the new profile. */
  562. /* */
  563. /* overshoot :: Whether the profile's unrounded start position */
  564. /* differs by at least a half pixel. */
  565. /* */
  566. /* <Return> */
  567. /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
  568. /* profile. */
  569. /* */
  570. static Bool
  571. New_Profile( RAS_ARGS TStates aState,
  572. Bool overshoot )
  573. {
  574. if ( !ras.fProfile )
  575. {
  576. ras.cProfile = (PProfile)ras.top;
  577. ras.fProfile = ras.cProfile;
  578. ras.top += AlignProfileSize;
  579. }
  580. if ( ras.top >= ras.maxBuff )
  581. {
  582. ras.error = Raster_Err_Overflow;
  583. return FAILURE;
  584. }
  585. ras.cProfile->flags = 0;
  586. ras.cProfile->start = 0;
  587. ras.cProfile->height = 0;
  588. ras.cProfile->offset = ras.top;
  589. ras.cProfile->link = (PProfile)0;
  590. ras.cProfile->next = (PProfile)0;
  591. ras.cProfile->flags = ras.dropOutControl;
  592. switch ( aState )
  593. {
  594. case Ascending_State:
  595. ras.cProfile->flags |= Flow_Up;
  596. if ( overshoot )
  597. ras.cProfile->flags |= Overshoot_Bottom;
  598. FT_TRACE6(( "New ascending profile = %p\n", ras.cProfile ));
  599. break;
  600. case Descending_State:
  601. if ( overshoot )
  602. ras.cProfile->flags |= Overshoot_Top;
  603. FT_TRACE6(( "New descending profile = %p\n", ras.cProfile ));
  604. break;
  605. default:
  606. FT_ERROR(( "New_Profile: invalid profile direction\n" ));
  607. ras.error = Raster_Err_Invalid;
  608. return FAILURE;
  609. }
  610. if ( !ras.gProfile )
  611. ras.gProfile = ras.cProfile;
  612. ras.state = aState;
  613. ras.fresh = TRUE;
  614. ras.joint = FALSE;
  615. return SUCCESS;
  616. }
  617. /*************************************************************************/
  618. /* */
  619. /* <Function> */
  620. /* End_Profile */
  621. /* */
  622. /* <Description> */
  623. /* Finalize the current profile. */
  624. /* */
  625. /* <Input> */
  626. /* overshoot :: Whether the profile's unrounded end position differs */
  627. /* by at least a half pixel. */
  628. /* */
  629. /* <Return> */
  630. /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
  631. /* */
  632. static Bool
  633. End_Profile( RAS_ARGS Bool overshoot )
  634. {
  635. Long h;
  636. PProfile oldProfile;
  637. h = (Long)( ras.top - ras.cProfile->offset );
  638. if ( h < 0 )
  639. {
  640. FT_ERROR(( "End_Profile: negative height encountered\n" ));
  641. ras.error = Raster_Err_Neg_Height;
  642. return FAILURE;
  643. }
  644. if ( h > 0 )
  645. {
  646. FT_TRACE6(( "Ending profile %p, start = %ld, height = %ld\n",
  647. ras.cProfile, ras.cProfile->start, h ));
  648. ras.cProfile->height = h;
  649. if ( overshoot )
  650. {
  651. if ( ras.cProfile->flags & Flow_Up )
  652. ras.cProfile->flags |= Overshoot_Top;
  653. else
  654. ras.cProfile->flags |= Overshoot_Bottom;
  655. }
  656. oldProfile = ras.cProfile;
  657. ras.cProfile = (PProfile)ras.top;
  658. ras.top += AlignProfileSize;
  659. ras.cProfile->height = 0;
  660. ras.cProfile->offset = ras.top;
  661. oldProfile->next = ras.cProfile;
  662. ras.num_Profs++;
  663. }
  664. if ( ras.top >= ras.maxBuff )
  665. {
  666. FT_TRACE1(( "overflow in End_Profile\n" ));
  667. ras.error = Raster_Err_Overflow;
  668. return FAILURE;
  669. }
  670. ras.joint = FALSE;
  671. return SUCCESS;
  672. }
  673. /*************************************************************************/
  674. /* */
  675. /* <Function> */
  676. /* Insert_Y_Turn */
  677. /* */
  678. /* <Description> */
  679. /* Insert a salient into the sorted list placed on top of the render */
  680. /* pool. */
  681. /* */
  682. /* <Input> */
  683. /* New y scanline position. */
  684. /* */
  685. /* <Return> */
  686. /* SUCCESS on success. FAILURE in case of overflow. */
  687. /* */
  688. static Bool
  689. Insert_Y_Turn( RAS_ARGS Int y )
  690. {
  691. PLong y_turns;
  692. Int y2, n;
  693. n = ras.numTurns - 1;
  694. y_turns = ras.sizeBuff - ras.numTurns;
  695. /* look for first y value that is <= */
  696. while ( n >= 0 && y < y_turns[n] )
  697. n--;
  698. /* if it is <, simply insert it, ignore if == */
  699. if ( n >= 0 && y > y_turns[n] )
  700. while ( n >= 0 )
  701. {
  702. y2 = (Int)y_turns[n];
  703. y_turns[n] = y;
  704. y = y2;
  705. n--;
  706. }
  707. if ( n < 0 )
  708. {
  709. ras.maxBuff--;
  710. if ( ras.maxBuff <= ras.top )
  711. {
  712. ras.error = Raster_Err_Overflow;
  713. return FAILURE;
  714. }
  715. ras.numTurns++;
  716. ras.sizeBuff[-ras.numTurns] = y;
  717. }
  718. return SUCCESS;
  719. }
  720. /*************************************************************************/
  721. /* */
  722. /* <Function> */
  723. /* Finalize_Profile_Table */
  724. /* */
  725. /* <Description> */
  726. /* Adjust all links in the profiles list. */
  727. /* */
  728. /* <Return> */
  729. /* SUCCESS on success. FAILURE in case of overflow. */
  730. /* */
  731. static Bool
  732. Finalize_Profile_Table( RAS_ARG )
  733. {
  734. Int bottom, top;
  735. UShort n;
  736. PProfile p;
  737. n = ras.num_Profs;
  738. p = ras.fProfile;
  739. if ( n > 1 && p )
  740. {
  741. while ( n > 0 )
  742. {
  743. if ( n > 1 )
  744. p->link = (PProfile)( p->offset + p->height );
  745. else
  746. p->link = NULL;
  747. if ( p->flags & Flow_Up )
  748. {
  749. bottom = (Int)p->start;
  750. top = (Int)( p->start + p->height - 1 );
  751. }
  752. else
  753. {
  754. bottom = (Int)( p->start - p->height + 1 );
  755. top = (Int)p->start;
  756. p->start = bottom;
  757. p->offset += p->height - 1;
  758. }
  759. if ( Insert_Y_Turn( RAS_VARS bottom ) ||
  760. Insert_Y_Turn( RAS_VARS top + 1 ) )
  761. return FAILURE;
  762. p = p->link;
  763. n--;
  764. }
  765. }
  766. else
  767. ras.fProfile = NULL;
  768. return SUCCESS;
  769. }
  770. /*************************************************************************/
  771. /* */
  772. /* <Function> */
  773. /* Split_Conic */
  774. /* */
  775. /* <Description> */
  776. /* Subdivide one conic Bezier into two joint sub-arcs in the Bezier */
  777. /* stack. */
  778. /* */
  779. /* <Input> */
  780. /* None (subdivided Bezier is taken from the top of the stack). */
  781. /* */
  782. /* <Note> */
  783. /* This routine is the `beef' of this component. It is _the_ inner */
  784. /* loop that should be optimized to hell to get the best performance. */
  785. /* */
  786. static void
  787. Split_Conic( TPoint* base )
  788. {
  789. Long a, b;
  790. base[4].x = base[2].x;
  791. b = base[1].x;
  792. a = base[3].x = ( base[2].x + b ) / 2;
  793. b = base[1].x = ( base[0].x + b ) / 2;
  794. base[2].x = ( a + b ) / 2;
  795. base[4].y = base[2].y;
  796. b = base[1].y;
  797. a = base[3].y = ( base[2].y + b ) / 2;
  798. b = base[1].y = ( base[0].y + b ) / 2;
  799. base[2].y = ( a + b ) / 2;
  800. /* hand optimized. gcc doesn't seem to be too good at common */
  801. /* expression substitution and instruction scheduling ;-) */
  802. }
  803. /*************************************************************************/
  804. /* */
  805. /* <Function> */
  806. /* Split_Cubic */
  807. /* */
  808. /* <Description> */
  809. /* Subdivide a third-order Bezier arc into two joint sub-arcs in the */
  810. /* Bezier stack. */
  811. /* */
  812. /* <Note> */
  813. /* This routine is the `beef' of the component. It is one of _the_ */
  814. /* inner loops that should be optimized like hell to get the best */
  815. /* performance. */
  816. /* */
  817. static void
  818. Split_Cubic( TPoint* base )
  819. {
  820. Long a, b, c, d;
  821. base[6].x = base[3].x;
  822. c = base[1].x;
  823. d = base[2].x;
  824. base[1].x = a = ( base[0].x + c + 1 ) >> 1;
  825. base[5].x = b = ( base[3].x + d + 1 ) >> 1;
  826. c = ( c + d + 1 ) >> 1;
  827. base[2].x = a = ( a + c + 1 ) >> 1;
  828. base[4].x = b = ( b + c + 1 ) >> 1;
  829. base[3].x = ( a + b + 1 ) >> 1;
  830. base[6].y = base[3].y;
  831. c = base[1].y;
  832. d = base[2].y;
  833. base[1].y = a = ( base[0].y + c + 1 ) >> 1;
  834. base[5].y = b = ( base[3].y + d + 1 ) >> 1;
  835. c = ( c + d + 1 ) >> 1;
  836. base[2].y = a = ( a + c + 1 ) >> 1;
  837. base[4].y = b = ( b + c + 1 ) >> 1;
  838. base[3].y = ( a + b + 1 ) >> 1;
  839. }
  840. /*************************************************************************/
  841. /* */
  842. /* <Function> */
  843. /* Line_Up */
  844. /* */
  845. /* <Description> */
  846. /* Compute the x-coordinates of an ascending line segment and store */
  847. /* them in the render pool. */
  848. /* */
  849. /* <Input> */
  850. /* x1 :: The x-coordinate of the segment's start point. */
  851. /* */
  852. /* y1 :: The y-coordinate of the segment's start point. */
  853. /* */
  854. /* x2 :: The x-coordinate of the segment's end point. */
  855. /* */
  856. /* y2 :: The y-coordinate of the segment's end point. */
  857. /* */
  858. /* miny :: A lower vertical clipping bound value. */
  859. /* */
  860. /* maxy :: An upper vertical clipping bound value. */
  861. /* */
  862. /* <Return> */
  863. /* SUCCESS on success, FAILURE on render pool overflow. */
  864. /* */
  865. static Bool
  866. Line_Up( RAS_ARGS Long x1,
  867. Long y1,
  868. Long x2,
  869. Long y2,
  870. Long miny,
  871. Long maxy )
  872. {
  873. Long Dx, Dy;
  874. Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
  875. Long Ix, Rx, Ax;
  876. PLong top;
  877. Dx = x2 - x1;
  878. Dy = y2 - y1;
  879. if ( Dy <= 0 || y2 < miny || y1 > maxy )
  880. return SUCCESS;
  881. if ( y1 < miny )
  882. {
  883. /* Take care: miny-y1 can be a very large value; we use */
  884. /* a slow MulDiv function to avoid clipping bugs */
  885. x1 += SMulDiv( Dx, miny - y1, Dy );
  886. e1 = (Int)TRUNC( miny );
  887. f1 = 0;
  888. }
  889. else
  890. {
  891. e1 = (Int)TRUNC( y1 );
  892. f1 = (Int)FRAC( y1 );
  893. }
  894. if ( y2 > maxy )
  895. {
  896. /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
  897. e2 = (Int)TRUNC( maxy );
  898. f2 = 0;
  899. }
  900. else
  901. {
  902. e2 = (Int)TRUNC( y2 );
  903. f2 = (Int)FRAC( y2 );
  904. }
  905. if ( f1 > 0 )
  906. {
  907. if ( e1 == e2 )
  908. return SUCCESS;
  909. else
  910. {
  911. x1 += SMulDiv( Dx, ras.precision - f1, Dy );
  912. e1 += 1;
  913. }
  914. }
  915. else
  916. if ( ras.joint )
  917. {
  918. ras.top--;
  919. ras.joint = FALSE;
  920. }
  921. ras.joint = (char)( f2 == 0 );
  922. if ( ras.fresh )
  923. {
  924. ras.cProfile->start = e1;
  925. ras.fresh = FALSE;
  926. }
  927. size = e2 - e1 + 1;
  928. if ( ras.top + size >= ras.maxBuff )
  929. {
  930. ras.error = Raster_Err_Overflow;
  931. return FAILURE;
  932. }
  933. if ( Dx > 0 )
  934. {
  935. Ix = SMulDiv( ras.precision, Dx, Dy);
  936. Rx = ( ras.precision * Dx ) % Dy;
  937. Dx = 1;
  938. }
  939. else
  940. {
  941. Ix = SMulDiv( ras.precision, -Dx, Dy) * -1;
  942. Rx = ( ras.precision * -Dx ) % Dy;
  943. Dx = -1;
  944. }
  945. Ax = -Dy;
  946. top = ras.top;
  947. while ( size > 0 )
  948. {
  949. *top++ = x1;
  950. x1 += Ix;
  951. Ax += Rx;
  952. if ( Ax >= 0 )
  953. {
  954. Ax -= Dy;
  955. x1 += Dx;
  956. }
  957. size--;
  958. }
  959. ras.top = top;
  960. return SUCCESS;
  961. }
  962. /*************************************************************************/
  963. /* */
  964. /* <Function> */
  965. /* Line_Down */
  966. /* */
  967. /* <Description> */
  968. /* Compute the x-coordinates of an descending line segment and store */
  969. /* them in the render pool. */
  970. /* */
  971. /* <Input> */
  972. /* x1 :: The x-coordinate of the segment's start point. */
  973. /* */
  974. /* y1 :: The y-coordinate of the segment's start point. */
  975. /* */
  976. /* x2 :: The x-coordinate of the segment's end point. */
  977. /* */
  978. /* y2 :: The y-coordinate of the segment's end point. */
  979. /* */
  980. /* miny :: A lower vertical clipping bound value. */
  981. /* */
  982. /* maxy :: An upper vertical clipping bound value. */
  983. /* */
  984. /* <Return> */
  985. /* SUCCESS on success, FAILURE on render pool overflow. */
  986. /* */
  987. static Bool
  988. Line_Down( RAS_ARGS Long x1,
  989. Long y1,
  990. Long x2,
  991. Long y2,
  992. Long miny,
  993. Long maxy )
  994. {
  995. Bool result, fresh;
  996. fresh = ras.fresh;
  997. result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny