17dd7cddfSDavid du Colombier /* Copyright (C) 1989, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gspaint.c,v 1.10 2005/10/12 17:59:55 leonardo Exp $ */
187dd7cddfSDavid du Colombier /* Painting procedures for Ghostscript library */
197dd7cddfSDavid du Colombier #include "math_.h" /* for fabs */
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gpcheck.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsropt.h" /* for gxpaint.h */
247dd7cddfSDavid du Colombier #include "gxfixed.h"
257dd7cddfSDavid du Colombier #include "gxmatrix.h" /* for gs_state */
267dd7cddfSDavid du Colombier #include "gspaint.h"
277dd7cddfSDavid du Colombier #include "gspath.h"
287dd7cddfSDavid du Colombier #include "gzpath.h"
297dd7cddfSDavid du Colombier #include "gxpaint.h"
307dd7cddfSDavid du Colombier #include "gzstate.h"
317dd7cddfSDavid du Colombier #include "gxdevice.h"
327dd7cddfSDavid du Colombier #include "gxdevmem.h"
337dd7cddfSDavid du Colombier #include "gzcpath.h"
34*593dc095SDavid du Colombier #include "gxhldevc.h"
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier /* Define the nominal size for alpha buffers. */
377dd7cddfSDavid du Colombier #define abuf_nominal_SMALL 500
387dd7cddfSDavid du Colombier #define abuf_nominal_LARGE 2000
397dd7cddfSDavid du Colombier #if arch_small_memory
407dd7cddfSDavid du Colombier # define abuf_nominal abuf_nominal_SMALL
417dd7cddfSDavid du Colombier #else
427dd7cddfSDavid du Colombier # define abuf_nominal\
437dd7cddfSDavid du Colombier (gs_debug_c('.') ? abuf_nominal_SMALL : abuf_nominal_LARGE)
447dd7cddfSDavid du Colombier #endif
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier /* Erase the page */
477dd7cddfSDavid du Colombier int
gs_erasepage(gs_state * pgs)487dd7cddfSDavid du Colombier gs_erasepage(gs_state * pgs)
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier /*
517dd7cddfSDavid du Colombier * We can't just fill with device white; we must take the
527dd7cddfSDavid du Colombier * transfer function into account.
537dd7cddfSDavid du Colombier */
547dd7cddfSDavid du Colombier int code;
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier if ((code = gs_gsave(pgs)) < 0)
577dd7cddfSDavid du Colombier return code;
587dd7cddfSDavid du Colombier if ((code = gs_setgray(pgs, 1.0)) >= 0) {
597dd7cddfSDavid du Colombier /* Fill the page directly, ignoring clipping. */
607dd7cddfSDavid du Colombier code = gs_fillpage(pgs);
617dd7cddfSDavid du Colombier }
627dd7cddfSDavid du Colombier gs_grestore(pgs);
637dd7cddfSDavid du Colombier return code;
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier /* Fill the page with the current color. */
677dd7cddfSDavid du Colombier int
gs_fillpage(gs_state * pgs)687dd7cddfSDavid du Colombier gs_fillpage(gs_state * pgs)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier gx_device *dev;
71*593dc095SDavid du Colombier int code = 0;
727dd7cddfSDavid du Colombier gs_logical_operation_t save_lop;
73*593dc095SDavid du Colombier bool hl_color_available = gx_hld_is_hl_color_available((gs_imager_state *)pgs,
74*593dc095SDavid du Colombier pgs->dev_color);
757dd7cddfSDavid du Colombier gx_set_dev_color(pgs);
767dd7cddfSDavid du Colombier dev = gs_currentdevice(pgs);
777dd7cddfSDavid du Colombier /* Fill the page directly, ignoring clipping. */
787dd7cddfSDavid du Colombier /* Use the default RasterOp. */
797dd7cddfSDavid du Colombier save_lop = pgs->log_op;
807dd7cddfSDavid du Colombier gs_init_rop(pgs);
81*593dc095SDavid du Colombier if (hl_color_available) {
82*593dc095SDavid du Colombier gs_fixed_rect rect;
83*593dc095SDavid du Colombier
84*593dc095SDavid du Colombier rect.p.x = rect.p.y = 0;
85*593dc095SDavid du Colombier rect.q.x = int2fixed(dev->width);
86*593dc095SDavid du Colombier rect.q.y = int2fixed(dev->height);
87*593dc095SDavid du Colombier code = dev_proc(pgs->device, fill_rectangle_hl_color)(pgs->device,
88*593dc095SDavid du Colombier &rect, (const gs_imager_state *)pgs, pgs->dev_color, NULL);
89*593dc095SDavid du Colombier }
90*593dc095SDavid du Colombier if (!hl_color_available || code == gs_error_rangecheck)
917dd7cddfSDavid du Colombier code = gx_fill_rectangle(0, 0, dev->width, dev->height,
927dd7cddfSDavid du Colombier pgs->dev_color, pgs);
937dd7cddfSDavid du Colombier pgs->log_op = save_lop;
947dd7cddfSDavid du Colombier if (code < 0)
957dd7cddfSDavid du Colombier return code;
967dd7cddfSDavid du Colombier return (*dev_proc(dev, sync_output)) (dev);
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier /*
1007dd7cddfSDavid du Colombier * Determine the number of bits of alpha buffer for a stroke or fill.
1017dd7cddfSDavid du Colombier * We should do alpha buffering iff this value is >1.
1027dd7cddfSDavid du Colombier */
1037dd7cddfSDavid du Colombier private int
alpha_buffer_bits(gs_state * pgs)1047dd7cddfSDavid du Colombier alpha_buffer_bits(gs_state * pgs)
1057dd7cddfSDavid du Colombier {
1067dd7cddfSDavid du Colombier gx_device *dev;
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier if (!color_is_pure(pgs->dev_color))
1097dd7cddfSDavid du Colombier return 0;
1107dd7cddfSDavid du Colombier dev = gs_currentdevice_inline(pgs);
1117dd7cddfSDavid du Colombier if (gs_device_is_abuf(dev)) {
1127dd7cddfSDavid du Colombier /* We're already writing into an alpha buffer. */
1137dd7cddfSDavid du Colombier return 0;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier return (*dev_proc(dev, get_alpha_bits))
1167dd7cddfSDavid du Colombier (dev, (pgs->in_cachedevice ? go_text : go_graphics));
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier /*
1197dd7cddfSDavid du Colombier * Set up an alpha buffer for a stroke or fill operation. Return 0
1207dd7cddfSDavid du Colombier * if no buffer could be allocated, 1 if a buffer was installed,
1217dd7cddfSDavid du Colombier * or the usual negative error code.
1227dd7cddfSDavid du Colombier *
1237dd7cddfSDavid du Colombier * The fill/stroke code sets up a clipping device if needed; however,
1247dd7cddfSDavid du Colombier * since we scale up all the path coordinates, we either need to scale up
1257dd7cddfSDavid du Colombier * the clipping region, or do clipping after, rather than before,
1267dd7cddfSDavid du Colombier * alpha buffering. Either of these is a little inconvenient, but
1277dd7cddfSDavid du Colombier * the former is less inconvenient.
1287dd7cddfSDavid du Colombier */
1297dd7cddfSDavid du Colombier private int
scale_paths(gs_state * pgs,int log2_scale_x,int log2_scale_y,bool do_path)1307dd7cddfSDavid du Colombier scale_paths(gs_state * pgs, int log2_scale_x, int log2_scale_y, bool do_path)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier /*
1337dd7cddfSDavid du Colombier * Because of clip and clippath, any of path, clip_path, and view_clip
1347dd7cddfSDavid du Colombier * may be aliases for each other. The only reliable way to detect
1357dd7cddfSDavid du Colombier * this is by comparing the segments pointers. Note that we must
1367dd7cddfSDavid du Colombier * scale the non-segment parts of the paths even if the segments are
1377dd7cddfSDavid du Colombier * aliased.
1387dd7cddfSDavid du Colombier */
1397dd7cddfSDavid du Colombier const gx_path_segments *seg_clip =
1407dd7cddfSDavid du Colombier (pgs->clip_path->path_valid ? pgs->clip_path->path.segments : 0);
1417dd7cddfSDavid du Colombier const gx_clip_rect_list *list_clip = pgs->clip_path->rect_list;
1427dd7cddfSDavid du Colombier const gx_path_segments *seg_view_clip;
1437dd7cddfSDavid du Colombier const gx_clip_rect_list *list_view_clip;
1447dd7cddfSDavid du Colombier const gx_path_segments *seg_effective_clip =
1457dd7cddfSDavid du Colombier (pgs->effective_clip_path->path_valid ?
1467dd7cddfSDavid du Colombier pgs->effective_clip_path->path.segments : 0);
1477dd7cddfSDavid du Colombier const gx_clip_rect_list *list_effective_clip =
1487dd7cddfSDavid du Colombier pgs->effective_clip_path->rect_list;
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier gx_cpath_scale_exp2_shared(pgs->clip_path, log2_scale_x, log2_scale_y,
1517dd7cddfSDavid du Colombier false, false);
1527dd7cddfSDavid du Colombier if (pgs->view_clip != 0 && pgs->view_clip != pgs->clip_path) {
1537dd7cddfSDavid du Colombier seg_view_clip =
1547dd7cddfSDavid du Colombier (pgs->view_clip->path_valid ? pgs->view_clip->path.segments : 0);
1557dd7cddfSDavid du Colombier list_view_clip = pgs->view_clip->rect_list;
1567dd7cddfSDavid du Colombier gx_cpath_scale_exp2_shared(pgs->view_clip, log2_scale_x, log2_scale_y,
1577dd7cddfSDavid du Colombier list_view_clip == list_clip,
1587dd7cddfSDavid du Colombier seg_view_clip && seg_view_clip == seg_clip);
1597dd7cddfSDavid du Colombier } else
1607dd7cddfSDavid du Colombier seg_view_clip = 0, list_view_clip = 0;
1617dd7cddfSDavid du Colombier if (pgs->effective_clip_path != pgs->clip_path &&
1627dd7cddfSDavid du Colombier pgs->effective_clip_path != pgs->view_clip
1637dd7cddfSDavid du Colombier )
1647dd7cddfSDavid du Colombier gx_cpath_scale_exp2_shared(pgs->effective_clip_path, log2_scale_x,
1657dd7cddfSDavid du Colombier log2_scale_y,
1667dd7cddfSDavid du Colombier list_effective_clip == list_clip ||
1677dd7cddfSDavid du Colombier list_effective_clip == list_view_clip,
1687dd7cddfSDavid du Colombier seg_effective_clip &&
1697dd7cddfSDavid du Colombier (seg_effective_clip == seg_clip ||
1707dd7cddfSDavid du Colombier seg_effective_clip == seg_view_clip));
1717dd7cddfSDavid du Colombier if (do_path) {
1727dd7cddfSDavid du Colombier const gx_path_segments *seg_path = pgs->path->segments;
1737dd7cddfSDavid du Colombier
1747dd7cddfSDavid du Colombier gx_path_scale_exp2_shared(pgs->path, log2_scale_x, log2_scale_y,
1757dd7cddfSDavid du Colombier seg_path == seg_clip ||
1767dd7cddfSDavid du Colombier seg_path == seg_view_clip ||
1777dd7cddfSDavid du Colombier seg_path == seg_effective_clip);
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier return 0;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier private void
scale_dash_pattern(gs_state * pgs,floatp scale)1827dd7cddfSDavid du Colombier scale_dash_pattern(gs_state * pgs, floatp scale)
1837dd7cddfSDavid du Colombier {
1847dd7cddfSDavid du Colombier int i;
1857dd7cddfSDavid du Colombier
1867dd7cddfSDavid du Colombier for (i = 0; i < pgs->line_params.dash.pattern_size; ++i)
1877dd7cddfSDavid du Colombier pgs->line_params.dash.pattern[i] *= scale;
1887dd7cddfSDavid du Colombier pgs->line_params.dash.offset *= scale;
1897dd7cddfSDavid du Colombier pgs->line_params.dash.pattern_length *= scale;
1907dd7cddfSDavid du Colombier pgs->line_params.dash.init_dist_left *= scale;
1917dd7cddfSDavid du Colombier if (pgs->line_params.dot_length_absolute)
1927dd7cddfSDavid du Colombier pgs->line_params.dot_length *= scale;
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier private int
alpha_buffer_init(gs_state * pgs,fixed extra_x,fixed extra_y,int alpha_bits)1957dd7cddfSDavid du Colombier alpha_buffer_init(gs_state * pgs, fixed extra_x, fixed extra_y, int alpha_bits)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier gx_device *dev = gs_currentdevice_inline(pgs);
1987dd7cddfSDavid du Colombier int log2_alpha_bits = ilog2(alpha_bits);
1997dd7cddfSDavid du Colombier gs_fixed_rect bbox;
2007dd7cddfSDavid du Colombier gs_int_rect ibox;
2017dd7cddfSDavid du Colombier uint width, raster, band_space;
2027dd7cddfSDavid du Colombier uint height;
2037dd7cddfSDavid du Colombier gs_log2_scale_point log2_scale;
2047dd7cddfSDavid du Colombier gs_memory_t *mem;
2057dd7cddfSDavid du Colombier gx_device_memory *mdev;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier log2_scale.x = log2_scale.y = log2_alpha_bits;
2087dd7cddfSDavid du Colombier gx_path_bbox(pgs->path, &bbox);
2097dd7cddfSDavid du Colombier ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1;
2107dd7cddfSDavid du Colombier ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1;
2117dd7cddfSDavid du Colombier ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1;
2127dd7cddfSDavid du Colombier ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1;
2137dd7cddfSDavid du Colombier width = (ibox.q.x - ibox.p.x) << log2_scale.x;
2147dd7cddfSDavid du Colombier raster = bitmap_raster(width);
2157dd7cddfSDavid du Colombier band_space = raster << log2_scale.y;
2167dd7cddfSDavid du Colombier height = (abuf_nominal / band_space) << log2_scale.y;
2177dd7cddfSDavid du Colombier if (height == 0)
2187dd7cddfSDavid du Colombier height = 1 << log2_scale.y;
2197dd7cddfSDavid du Colombier mem = pgs->memory;
2207dd7cddfSDavid du Colombier mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
2217dd7cddfSDavid du Colombier "alpha_buffer_init");
2227dd7cddfSDavid du Colombier if (mdev == 0)
2237dd7cddfSDavid du Colombier return 0; /* if no room, don't buffer */
2247dd7cddfSDavid du Colombier gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale,
2257dd7cddfSDavid du Colombier alpha_bits, ibox.p.x << log2_scale.x);
2267dd7cddfSDavid du Colombier mdev->width = width;
2277dd7cddfSDavid du Colombier mdev->height = height;
2287dd7cddfSDavid du Colombier mdev->bitmap_memory = mem;
2297dd7cddfSDavid du Colombier if ((*dev_proc(mdev, open_device)) ((gx_device *) mdev) < 0) {
2307dd7cddfSDavid du Colombier /* No room for bits, punt. */
2317dd7cddfSDavid du Colombier gs_free_object(mem, mdev, "alpha_buffer_init");
2327dd7cddfSDavid du Colombier return 0;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier gx_set_device_only(pgs, (gx_device *) mdev);
2357dd7cddfSDavid du Colombier scale_paths(pgs, log2_scale.x, log2_scale.y, true);
2367dd7cddfSDavid du Colombier return 1;
2377dd7cddfSDavid du Colombier }
2387dd7cddfSDavid du Colombier
2397dd7cddfSDavid du Colombier /* Release an alpha buffer. */
2407dd7cddfSDavid du Colombier private void
alpha_buffer_release(gs_state * pgs,bool newpath)2417dd7cddfSDavid du Colombier alpha_buffer_release(gs_state * pgs, bool newpath)
2427dd7cddfSDavid du Colombier {
2437dd7cddfSDavid du Colombier gx_device_memory *mdev =
2447dd7cddfSDavid du Colombier (gx_device_memory *) gs_currentdevice_inline(pgs);
2457dd7cddfSDavid du Colombier
2467dd7cddfSDavid du Colombier (*dev_proc(mdev, close_device)) ((gx_device *) mdev);
2477dd7cddfSDavid du Colombier scale_paths(pgs, -mdev->log2_scale.x, -mdev->log2_scale.y,
2487dd7cddfSDavid du Colombier !(newpath && !gx_path_is_shared(pgs->path)));
2497dd7cddfSDavid du Colombier /* Reference counting will free mdev. */
2507dd7cddfSDavid du Colombier gx_set_device_only(pgs, mdev->target);
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier
2537dd7cddfSDavid du Colombier /* Fill the current path using a specified rule. */
2547dd7cddfSDavid du Colombier private int
fill_with_rule(gs_state * pgs,int rule)2557dd7cddfSDavid du Colombier fill_with_rule(gs_state * pgs, int rule)
2567dd7cddfSDavid du Colombier {
2577dd7cddfSDavid du Colombier int code;
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier /* If we're inside a charpath, just merge the current path */
2607dd7cddfSDavid du Colombier /* into the parent's path. */
2617dd7cddfSDavid du Colombier if (pgs->in_charpath)
2627dd7cddfSDavid du Colombier code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
2637dd7cddfSDavid du Colombier pgs->in_charpath);
264*593dc095SDavid du Colombier else if (gs_is_null_device(pgs->device)) {
265*593dc095SDavid du Colombier /* Handle separately to prevent gs_state_color_load - bug 688308. */
266*593dc095SDavid du Colombier gs_newpath(pgs);
267*593dc095SDavid du Colombier code = 0;
268*593dc095SDavid du Colombier } else {
2697dd7cddfSDavid du Colombier int abits, acode;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier gx_set_dev_color(pgs);
2727dd7cddfSDavid du Colombier code = gs_state_color_load(pgs);
2737dd7cddfSDavid du Colombier if (code < 0)
2747dd7cddfSDavid du Colombier return code;
2757dd7cddfSDavid du Colombier abits = alpha_buffer_bits(pgs);
2767dd7cddfSDavid du Colombier if (abits > 1) {
2777dd7cddfSDavid du Colombier acode = alpha_buffer_init(pgs, pgs->fill_adjust.x,
2787dd7cddfSDavid du Colombier pgs->fill_adjust.y, abits);
2797dd7cddfSDavid du Colombier if (acode < 0)
2807dd7cddfSDavid du Colombier return acode;
2817dd7cddfSDavid du Colombier } else
2827dd7cddfSDavid du Colombier acode = 0;
2837dd7cddfSDavid du Colombier code = gx_fill_path(pgs->path, pgs->dev_color, pgs, rule,
2847dd7cddfSDavid du Colombier pgs->fill_adjust.x, pgs->fill_adjust.y);
2857dd7cddfSDavid du Colombier if (acode > 0)
2867dd7cddfSDavid du Colombier alpha_buffer_release(pgs, code >= 0);
2877dd7cddfSDavid du Colombier if (code >= 0)
2887dd7cddfSDavid du Colombier gs_newpath(pgs);
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier return code;
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier /* Fill using the winding number rule */
2947dd7cddfSDavid du Colombier int
gs_fill(gs_state * pgs)2957dd7cddfSDavid du Colombier gs_fill(gs_state * pgs)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier return fill_with_rule(pgs, gx_rule_winding_number);
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier /* Fill using the even/odd rule */
3007dd7cddfSDavid du Colombier int
gs_eofill(gs_state * pgs)3017dd7cddfSDavid du Colombier gs_eofill(gs_state * pgs)
3027dd7cddfSDavid du Colombier {
3037dd7cddfSDavid du Colombier return fill_with_rule(pgs, gx_rule_even_odd);
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier
3067dd7cddfSDavid du Colombier /* Stroke the current path */
3077dd7cddfSDavid du Colombier int
gs_stroke(gs_state * pgs)3087dd7cddfSDavid du Colombier gs_stroke(gs_state * pgs)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier int code;
3117dd7cddfSDavid du Colombier
3127dd7cddfSDavid du Colombier /*
3137dd7cddfSDavid du Colombier * If we're inside a charpath, just merge the current path
3147dd7cddfSDavid du Colombier * into the parent's path.
3157dd7cddfSDavid du Colombier */
3167dd7cddfSDavid du Colombier if (pgs->in_charpath) {
3177dd7cddfSDavid du Colombier if (pgs->in_charpath == cpm_true_charpath) {
3187dd7cddfSDavid du Colombier /*
3197dd7cddfSDavid du Colombier * A stroke inside a true charpath should do the
3207dd7cddfSDavid du Colombier * equivalent of strokepath.
3217dd7cddfSDavid du Colombier */
3227dd7cddfSDavid du Colombier code = gs_strokepath(pgs);
3237dd7cddfSDavid du Colombier if (code < 0)
3247dd7cddfSDavid du Colombier return code;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
3277dd7cddfSDavid du Colombier pgs->in_charpath);
328*593dc095SDavid du Colombier } else if (gs_is_null_device(pgs->device)) {
329*593dc095SDavid du Colombier /* Handle separately to prevent gs_state_color_load. */
330*593dc095SDavid du Colombier gs_newpath(pgs);
331*593dc095SDavid du Colombier code = 0;
3327dd7cddfSDavid du Colombier } else {
3337dd7cddfSDavid du Colombier int abits, acode;
3347dd7cddfSDavid du Colombier
3357dd7cddfSDavid du Colombier gx_set_dev_color(pgs);
3367dd7cddfSDavid du Colombier code = gs_state_color_load(pgs);
3377dd7cddfSDavid du Colombier if (code < 0)
3387dd7cddfSDavid du Colombier return code;
3397dd7cddfSDavid du Colombier abits = alpha_buffer_bits(pgs);
3407dd7cddfSDavid du Colombier if (abits > 1) {
3417dd7cddfSDavid du Colombier /*
3427dd7cddfSDavid du Colombier * Expand the bounding box by the line width.
3437dd7cddfSDavid du Colombier * This is expensive to compute, so we only do it
3447dd7cddfSDavid du Colombier * if we know we're going to buffer.
3457dd7cddfSDavid du Colombier */
3467dd7cddfSDavid du Colombier float xxyy = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yy);
3477dd7cddfSDavid du Colombier float xyyx = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yx);
348*593dc095SDavid du Colombier float scale = (float)(1 << (abits / 2));
3497dd7cddfSDavid du Colombier float orig_width = gs_currentlinewidth(pgs);
3507dd7cddfSDavid du Colombier float new_width = orig_width * scale;
3517dd7cddfSDavid du Colombier fixed extra_adjust =
3527dd7cddfSDavid du Colombier float2fixed(max(xxyy, xyyx) * new_width / 2);
3537dd7cddfSDavid du Colombier float orig_flatness = gs_currentflat(pgs);
3547dd7cddfSDavid du Colombier gx_path spath;
3557dd7cddfSDavid du Colombier
3567dd7cddfSDavid du Colombier /* Scale up the line width, dash pattern, and flatness. */
3577dd7cddfSDavid du Colombier if (extra_adjust < fixed_1)
3587dd7cddfSDavid du Colombier extra_adjust = fixed_1;
3597dd7cddfSDavid du Colombier acode = alpha_buffer_init(pgs,
3607dd7cddfSDavid du Colombier pgs->fill_adjust.x + extra_adjust,
3617dd7cddfSDavid du Colombier pgs->fill_adjust.y + extra_adjust,
3627dd7cddfSDavid du Colombier abits);
3637dd7cddfSDavid du Colombier if (acode < 0)
3647dd7cddfSDavid du Colombier return acode;
3657dd7cddfSDavid du Colombier gs_setlinewidth(pgs, new_width);
3667dd7cddfSDavid du Colombier scale_dash_pattern(pgs, scale);
3677dd7cddfSDavid du Colombier gs_setflat(pgs, orig_flatness * scale);
3687dd7cddfSDavid du Colombier /*
3697dd7cddfSDavid du Colombier * The alpha-buffer device requires that we fill the
3707dd7cddfSDavid du Colombier * entire path as a single unit.
3717dd7cddfSDavid du Colombier */
3727dd7cddfSDavid du Colombier gx_path_init_local(&spath, pgs->memory);
3737dd7cddfSDavid du Colombier code = gx_stroke_add(pgs->path, &spath, pgs);
3747dd7cddfSDavid du Colombier gs_setlinewidth(pgs, orig_width);
3757dd7cddfSDavid du Colombier scale_dash_pattern(pgs, 1.0 / scale);
3767dd7cddfSDavid du Colombier if (code >= 0)
3777dd7cddfSDavid du Colombier code = gx_fill_path(&spath, pgs->dev_color, pgs,
3787dd7cddfSDavid du Colombier gx_rule_winding_number,
3797dd7cddfSDavid du Colombier pgs->fill_adjust.x,
3807dd7cddfSDavid du Colombier pgs->fill_adjust.y);
3817dd7cddfSDavid du Colombier gs_setflat(pgs, orig_flatness);
3827dd7cddfSDavid du Colombier gx_path_free(&spath, "gs_stroke");
3837dd7cddfSDavid du Colombier if (acode > 0)
3847dd7cddfSDavid du Colombier alpha_buffer_release(pgs, code >= 0);
3857dd7cddfSDavid du Colombier } else
3867dd7cddfSDavid du Colombier code = gx_stroke_fill(pgs->path, pgs);
3877dd7cddfSDavid du Colombier if (code >= 0)
3887dd7cddfSDavid du Colombier gs_newpath(pgs);
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier return code;
3917dd7cddfSDavid du Colombier }
3927dd7cddfSDavid du Colombier
3937dd7cddfSDavid du Colombier /* Compute the stroked outline of the current path */
3947dd7cddfSDavid du Colombier int
gs_strokepath(gs_state * pgs)3957dd7cddfSDavid du Colombier gs_strokepath(gs_state * pgs)
3967dd7cddfSDavid du Colombier {
3977dd7cddfSDavid du Colombier gx_path spath;
3987dd7cddfSDavid du Colombier int code;
3997dd7cddfSDavid du Colombier
400*593dc095SDavid du Colombier gx_path_init_local(&spath, pgs->path->memory);
4017dd7cddfSDavid du Colombier code = gx_stroke_add(pgs->path, &spath, pgs);
4027dd7cddfSDavid du Colombier if (code < 0) {
4037dd7cddfSDavid du Colombier gx_path_free(&spath, "gs_strokepath");
4047dd7cddfSDavid du Colombier return code;
4057dd7cddfSDavid du Colombier }
406*593dc095SDavid du Colombier code = gx_path_assign_free(pgs->path, &spath);
407*593dc095SDavid du Colombier if (code < 0)
408*593dc095SDavid du Colombier return code;
409*593dc095SDavid du Colombier gx_setcurrentpoint(pgs, fixed2float(spath.position.x), fixed2float(spath.position.y));
410*593dc095SDavid du Colombier return 0;
4117dd7cddfSDavid du Colombier }
412