/* Copyright (C) 2001-2006 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at http://www.artifex.com/ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* $Id$ */ /* Dropout prevention for a character rasterization. */ #ifndef gxfdrop_INCLUDED # define gxfdrop_INCLUDED /* The structure margin_set and related structures and functions are used for preventing dropouts rasterizing a character with zero fill adjustment. The purpose is to paint something along thin quazi-horizontal stems, which are composed of multiple small segments (such as a result of flattenpath). We call it "pseudo-rasterization". When fill adjustment takes place, this stuff is not required and is being skipped. To prevent dropouts in thin quazi-horizontal stems we look at raster through 1xN pixels window, where N is the width of the path bounding box. This window moves from bottom to top synchronousely with the motion of the filling loop, but its Y coordinate is always an integer plus one half (actually it moves convulsively). Through this window we can see an upper half of a pixel row, and lower half of the next pixel row. Painted spots are visible through this window as a set of "margins". To handle them we maintain a list of margin_s structures (each of which describes an interval to be painted), and array of "sections" (i-th section corresponds to half-integer X-coordinate Xi = bbox_left + i + 0.5, and stores fraction part of y-coordinate of intersection of the line x == Xi with margin boudaries, being visible through window (only extremal coordinates are stored into a section)). The structure margin_set snaps what has been painted inside window. We handle 2 instances of margin_set : margin_set0 is being prepared and margin_set1 is being refinished. When the filling loop steps down over a pixel center, the refinished window is closed and released, the prapared window becomes the refinished one, and a new one starts to prepare. fixme: The current implementation is not optimised for very bold characters. We could encrease performance for them with maintaining a separate list of "exclusive" margins, which correspond to intervals painted with regular trapezoids and made with complete_margin. Using them we could skip access to 'sect' array elements inside "exclusive" margins, so that the number of small steps sensibly decreeses. fixme: Another optimization could be applied to the regular(old) trapezoid algorithm. Currently it breaks stems at any step of the Y cycle, generating big number of trapezoids. Perhaps we could store trapezoid vertices to active_line, and delay rendering a trapezoid until stem changes boundary segments. This also would make calls to the margin staff less frequent. */ /* * Configuration flags for the dropout prevention code. */ #define ADJUST_SERIF 1 /* See comments near occurances. */ #define CHECK_SPOT_CONTIGUITY 1 /* See comments near occurances. */ #ifndef active_line_DEFINED # define active_line_DEFINED typedef struct active_line_s active_line; #endif #ifndef line_list_DEFINED # define line_list_DEFINED typedef struct line_list_s line_list; #endif typedef struct margin_s { int ibeg, iend; /* Pixel indices of an interval to paint. */ struct margin_s *prev, *next; } margin; typedef struct section_s { short y0, y1; /* Fraction part of y coordinates of intersections of the margin with line x==i + bbox_left */ #if ADJUST_SERIF && CHECK_SPOT_CONTIGUITY short x0, x1; /* Pixel coverage by X for checking the contiguity. */ #endif } section; typedef struct margin_set_s { fixed y; margin *margin_list, *margin_touched; section *sect; } margin_set; extern_st(st_section); /* vd_trace helpers. */ #define VD_SCALE 0.03 #define VD_RECT(x, y, w, h, c) vd_rect(int2fixed(x), int2fixed(y), int2fixed(x + w), int2fixed(y + h), 1, c) #define VD_TRAP_COLOR RGB(0, 255, 255) #define VD_MARG_COLOR RGB(255, 0, 0) void init_section(section *sect, int i0, int i1); void free_all_margins(line_list * ll); int close_margins(gx_device * dev, line_list * ll, margin_set *ms); int process_h_lists(line_list * ll, active_line * plp, active_line * flp, active_line * alp, fixed y0, fixed y1); int margin_interior(line_list * ll, active_line * flp, active_line * alp, fixed y0, fixed y1); int start_margin_set(gx_device * dev, line_list * ll, fixed y0); int continue_margin_common(line_list * ll, margin_set * set, active_line * flp, active_line * alp, fixed y0, fixed y1); #endif /* gxfdrop_INCLUDED */