~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gspaint.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
  
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: gspaint.c 9288 2008-12-13 20:05:37Z leonardo $ */
 
15
/* Painting procedures for Ghostscript library */
 
16
#include "math_.h"              /* for fabs */
 
17
#include "gx.h"
 
18
#include "gpcheck.h"
 
19
#include "gserrors.h"
 
20
#include "gsropt.h"             /* for gxpaint.h */
 
21
#include "gxfixed.h"
 
22
#include "gxmatrix.h"           /* for gs_state */
 
23
#include "gspaint.h"
 
24
#include "gspath.h"
 
25
#include "gzpath.h"
 
26
#include "gxpaint.h"
 
27
#include "gzstate.h"
 
28
#include "gxdevice.h"
 
29
#include "gxdevmem.h"
 
30
#include "gzcpath.h"
 
31
#include "gxhldevc.h"
 
32
#include "gsutil.h"
 
33
 
 
34
extern bool CPSI_mode;
 
35
 
 
36
/* Define the nominal size for alpha buffers. */
 
37
#define abuf_nominal_SMALL 500
 
38
#define abuf_nominal_LARGE 2000
 
39
#if arch_small_memory
 
40
#  define abuf_nominal abuf_nominal_SMALL
 
41
#else
 
42
#  define abuf_nominal\
 
43
     (gs_debug_c('.') ? abuf_nominal_SMALL : abuf_nominal_LARGE)
 
44
#endif
 
45
 
 
46
/* Erase the page */
 
47
int
 
48
gs_erasepage(gs_state * pgs)
 
49
{
 
50
    /*
 
51
     * We can't just fill with device white; we must take the
 
52
     * transfer function into account.
 
53
     */
 
54
    int code;
 
55
 
 
56
    if ((code = gs_gsave(pgs)) < 0)
 
57
        return code;
 
58
    if ((code = gs_setgray(pgs, 1.0)) >= 0) {
 
59
        /* Fill the page directly, ignoring clipping. */
 
60
        code = gs_fillpage(pgs);
 
61
    }
 
62
    gs_grestore(pgs);
 
63
    return code;
 
64
}
 
65
 
 
66
/* Fill the page with the current color. */
 
67
int
 
68
gs_fillpage(gs_state * pgs)
 
69
{
 
70
    gx_device *dev = gs_currentdevice(pgs);
 
71
    int code;
 
72
 
 
73
    /* If we get here without a valid get_color_mapping_procs, fail */
 
74
    if (dev_proc(dev, get_color_mapping_procs) == NULL || 
 
75
        dev_proc(dev, get_color_mapping_procs) == gx_error_get_color_mapping_procs) {
 
76
        eprintf1("\n   *** Error: No get_color_mapping_procs for device: %s\n", dev->dname);
 
77
        return_error(gs_error_Fatal);
 
78
    }
 
79
    /* Processing a fill object operation */
 
80
    gs_set_object_tag(pgs, GS_PATH_TAG);
 
81
 
 
82
    gx_set_dev_color(pgs);
 
83
 
 
84
    code = (*dev_proc(dev, fillpage))(dev, (gs_imager_state *)pgs, pgs->dev_color);
 
85
    if (code < 0)
 
86
        return code;
 
87
    return (*dev_proc(dev, sync_output)) (dev);
 
88
}
 
89
 
 
90
/*
 
91
 * Determine the number of bits of alpha buffer for a stroke or fill.
 
92
 * We should do alpha buffering iff this value is >1.
 
93
 */
 
94
static int
 
95
alpha_buffer_bits(gs_state * pgs)
 
96
{
 
97
    gx_device *dev;
 
98
 
 
99
    if (!color_is_pure(pgs->dev_color))
 
100
        return 0;
 
101
    dev = gs_currentdevice_inline(pgs);
 
102
    if (gs_device_is_abuf(dev)) {
 
103
        /* We're already writing into an alpha buffer. */
 
104
        return 0;
 
105
    }
 
106
    return (*dev_proc(dev, get_alpha_bits))
 
107
        (dev, (pgs->in_cachedevice ? go_text : go_graphics));
 
108
}
 
109
/*
 
110
 * Set up an alpha buffer for a stroke or fill operation.  Return 0
 
111
 * if no buffer could be allocated, 1 if a buffer was installed,
 
112
 * or the usual negative error code.
 
113
 *
 
114
 * The fill/stroke code sets up a clipping device if needed; however,
 
115
 * since we scale up all the path coordinates, we either need to scale up
 
116
 * the clipping region, or do clipping after, rather than before,
 
117
 * alpha buffering.  Either of these is a little inconvenient, but
 
118
 * the former is less inconvenient.
 
119
 */
 
120
static int
 
121
scale_paths(gs_state * pgs, int log2_scale_x, int log2_scale_y, bool do_path)
 
122
{
 
123
    /*
 
124
     * Because of clip and clippath, any of path, clip_path, and view_clip
 
125
     * may be aliases for each other.  The only reliable way to detect
 
126
     * this is by comparing the segments pointers.  Note that we must
 
127
     * scale the non-segment parts of the paths even if the segments are
 
128
     * aliased.
 
129
     */
 
130
    const gx_path_segments *seg_clip =
 
131
        (pgs->clip_path->path_valid ? pgs->clip_path->path.segments : 0);
 
132
    const gx_clip_rect_list *list_clip = pgs->clip_path->rect_list;
 
133
    const gx_path_segments *seg_view_clip;
 
134
    const gx_clip_rect_list *list_view_clip;
 
135
    const gx_path_segments *seg_effective_clip =
 
136
        (pgs->effective_clip_path->path_valid ?
 
137
         pgs->effective_clip_path->path.segments : 0);
 
138
    const gx_clip_rect_list *list_effective_clip =
 
139
        pgs->effective_clip_path->rect_list;
 
140
 
 
141
    gx_cpath_scale_exp2_shared(pgs->clip_path, log2_scale_x, log2_scale_y,
 
142
                               false, false);
 
143
    if (pgs->view_clip != 0 && pgs->view_clip != pgs->clip_path) {
 
144
        seg_view_clip =
 
145
            (pgs->view_clip->path_valid ? pgs->view_clip->path.segments : 0);
 
146
        list_view_clip = pgs->view_clip->rect_list;
 
147
        gx_cpath_scale_exp2_shared(pgs->view_clip, log2_scale_x, log2_scale_y,
 
148
                                   list_view_clip == list_clip,
 
149
                                   seg_view_clip && seg_view_clip == seg_clip);
 
150
    } else
 
151
        seg_view_clip = 0, list_view_clip = 0;
 
152
    if (pgs->effective_clip_path != pgs->clip_path &&
 
153
        pgs->effective_clip_path != pgs->view_clip
 
154
        )
 
155
        gx_cpath_scale_exp2_shared(pgs->effective_clip_path, log2_scale_x,
 
156
                                   log2_scale_y,
 
157
                                   list_effective_clip == list_clip ||
 
158
                                   list_effective_clip == list_view_clip,
 
159
                                   seg_effective_clip &&
 
160
                                   (seg_effective_clip == seg_clip ||
 
161
                                    seg_effective_clip == seg_view_clip));
 
162
    if (do_path) {
 
163
        const gx_path_segments *seg_path = pgs->path->segments;
 
164
 
 
165
        gx_path_scale_exp2_shared(pgs->path, log2_scale_x, log2_scale_y,
 
166
                                  seg_path == seg_clip ||
 
167
                                  seg_path == seg_view_clip ||
 
168
                                  seg_path == seg_effective_clip);
 
169
    }
 
170
    return 0;
 
171
}
 
172
static void
 
173
scale_dash_pattern(gs_state * pgs, floatp scale)
 
174
{
 
175
    int i;
 
176
 
 
177
    for (i = 0; i < pgs->line_params.dash.pattern_size; ++i)
 
178
        pgs->line_params.dash.pattern[i] *= scale;
 
179
    pgs->line_params.dash.offset *= scale;
 
180
    pgs->line_params.dash.pattern_length *= scale;
 
181
    pgs->line_params.dash.init_dist_left *= scale;
 
182
    if (pgs->line_params.dot_length_absolute)
 
183
        pgs->line_params.dot_length *= scale;
 
184
}
 
185
static int
 
186
alpha_buffer_init(gs_state * pgs, fixed extra_x, fixed extra_y, int alpha_bits)
 
187
{
 
188
    gx_device *dev = gs_currentdevice_inline(pgs);
 
189
    int log2_alpha_bits = ilog2(alpha_bits);
 
190
    gs_fixed_rect bbox;
 
191
    gs_int_rect ibox;
 
192
    uint width, raster, band_space;
 
193
    uint height;
 
194
    gs_log2_scale_point log2_scale;
 
195
    gs_memory_t *mem;
 
196
    gx_device_memory *mdev;
 
197
 
 
198
    log2_scale.x = log2_scale.y = log2_alpha_bits;
 
199
    gx_path_bbox(pgs->path, &bbox);
 
200
    ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1;
 
201
    ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1;
 
202
    ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1;
 
203
    ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1;
 
204
    width = (ibox.q.x - ibox.p.x) << log2_scale.x;
 
205
    raster = bitmap_raster(width);
 
206
    band_space = raster << log2_scale.y;
 
207
    height = (abuf_nominal / band_space) << log2_scale.y;
 
208
    if (height == 0)
 
209
        height = 1 << log2_scale.y;
 
210
    mem = pgs->memory;
 
211
    mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
 
212
                           "alpha_buffer_init");
 
213
    if (mdev == 0)
 
214
        return 0;               /* if no room, don't buffer */
 
215
    gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale,
 
216
                            alpha_bits, ibox.p.x << log2_scale.x);
 
217
    mdev->width = width;
 
218
    mdev->height = height;
 
219
    mdev->bitmap_memory = mem;
 
220
    if ((*dev_proc(mdev, open_device)) ((gx_device *) mdev) < 0) {
 
221
        /* No room for bits, punt. */
 
222
        gs_free_object(mem, mdev, "alpha_buffer_init");
 
223
        return 0;
 
224
    }
 
225
    gx_set_device_only(pgs, (gx_device *) mdev);
 
226
    scale_paths(pgs, log2_scale.x, log2_scale.y, true);
 
227
    return 1;
 
228
}
 
229
 
 
230
/* Release an alpha buffer. */
 
231
static int
 
232
alpha_buffer_release(gs_state * pgs, bool newpath)
 
233
{
 
234
    gx_device_memory *mdev =
 
235
        (gx_device_memory *) gs_currentdevice_inline(pgs);
 
236
    int code = (*dev_proc(mdev, close_device)) ((gx_device *) mdev);
 
237
 
 
238
    if (code >= 0)
 
239
        scale_paths(pgs, -mdev->log2_scale.x, -mdev->log2_scale.y,
 
240
                !(newpath && !gx_path_is_shared(pgs->path)));
 
241
    /* Reference counting will free mdev. */
 
242
    gx_set_device_only(pgs, mdev->target);
 
243
    return code;
 
244
}
 
245
 
 
246
/* Fill the current path using a specified rule. */
 
247
static int
 
248
fill_with_rule(gs_state * pgs, int rule)
 
249
{
 
250
    int code;
 
251
 
 
252
    /* If we're inside a charpath, just merge the current path */
 
253
    /* into the parent's path. */
 
254
    if (pgs->in_charpath)
 
255
        code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
 
256
                                     pgs->in_charpath);
 
257
    else if (gs_is_null_device(pgs->device)) {
 
258
        /* Handle separately to prevent gs_state_color_load - bug 688308. */
 
259
        gs_newpath(pgs);
 
260
        code = 0;
 
261
    } else {
 
262
        int abits, acode, rcode = 0;
 
263
 
 
264
        /* Here we need to distinguish text from vectors to compute the object tag.
 
265
           Actually we need to know whether this function is called to rasterize a character,
 
266
           or to rasterize a vector graphics to the output device.
 
267
           Currently we assume it works for the bitrgbtags device only,
 
268
           which is a low level device with a 4-component color model.
 
269
           We use the fact that with printers a character is usually being rendered 
 
270
           to a 1bpp cache device rather than to the output device.
 
271
           Therefore we hackly look whether the target device
 
272
           "has a color" : either it's a multicomponent color model,
 
273
           or it is not gray (such as a yellow separation).
 
274
 
 
275
           This check has several limitations :
 
276
           1. It doesn't work with -dNOCACHE.
 
277
           2. It doesn't work with large characters,
 
278
              which cannot fit into a cache cell and thus they
 
279
              render directly to the output device.
 
280
           3. It doesn't work for TextAlphaBits=2 or 4.
 
281
              We don't care of this case because
 
282
              text antialiasing usually usn't applied to printers.
 
283
           4. It doesn't work for things like with "(xyz) true charpath stroke".
 
284
              That's unfortunate, we'd like to improve someday.
 
285
           5. It doesn't work for high level devices when a Type 3 character is being constructed.
 
286
              This case is not important for low level devices
 
287
              (which a printer is), because low level device doesn't accept
 
288
              Type 3 charproc streams immediately.
 
289
           6. It doesn't work properly while an insiding testing,
 
290
              which sets gs_hit_device, which is uncolored.
 
291
         */
 
292
        if (gx_device_has_color(gs_currentdevice(pgs))) {
 
293
            gs_set_object_tag(pgs, GS_PATH_TAG);
 
294
        }
 
295
        else {
 
296
            gs_set_object_tag(pgs, GS_TEXT_TAG);
 
297
        }
 
298
        gx_set_dev_color(pgs);
 
299
        code = gs_state_color_load(pgs);
 
300
        if (code < 0)
 
301
            return code;
 
302
        abits = alpha_buffer_bits(pgs);
 
303
        if (abits > 1) {
 
304
            acode = alpha_buffer_init(pgs, pgs->fill_adjust.x,
 
305
                                      pgs->fill_adjust.y, abits);
 
306
            if (acode < 0)
 
307
                return acode;
 
308
        } else
 
309
            acode = 0;
 
310
        code = gx_fill_path(pgs->path, pgs->dev_color, pgs, rule,
 
311
                            pgs->fill_adjust.x, pgs->fill_adjust.y);
 
312
        if (acode > 0)
 
313
            rcode = alpha_buffer_release(pgs, code >= 0);
 
314
        if (code >= 0)
 
315
            gs_newpath(pgs);
 
316
        if (code >= 0 && rcode < 0)
 
317
            code = rcode;
 
318
 
 
319
    }
 
320
    return code;
 
321
}
 
322
/* Fill using the winding number rule */
 
323
int
 
324
gs_fill(gs_state * pgs)
 
325
{
 
326
    pgs->device->sgr.stroke_stored = false;
 
327
    return fill_with_rule(pgs, gx_rule_winding_number);
 
328
}
 
329
/* Fill using the even/odd rule */
 
330
int
 
331
gs_eofill(gs_state * pgs)
 
332
{
 
333
    pgs->device->sgr.stroke_stored = false;
 
334
    return fill_with_rule(pgs, gx_rule_even_odd);
 
335
}
 
336
 
 
337
/* Stroke the current path */
 
338
int
 
339
gs_stroke(gs_state * pgs)
 
340
{
 
341
    int code;
 
342
 
 
343
    /*
 
344
     * If we're inside a charpath, just merge the current path
 
345
     * into the parent's path.
 
346
     */
 
347
    if (pgs->in_charpath) {
 
348
        if (pgs->in_charpath == cpm_true_charpath) {
 
349
            /*
 
350
             * A stroke inside a true charpath should do the
 
351
             * equivalent of strokepath.
 
352
             */
 
353
            code = gs_strokepath(pgs);
 
354
            if (code < 0)
 
355
                return code;
 
356
        }
 
357
        code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
 
358
                                     pgs->in_charpath);
 
359
    }
 
360
    if (gs_is_null_device(pgs->device)) {
 
361
        /* Handle separately to prevent gs_state_color_load. */
 
362
        gs_newpath(pgs);
 
363
        code = 0;
 
364
    } else {
 
365
        int abits, acode, rcode = 0;
 
366
 
 
367
        /* to distinguish text from vectors we hackly look at the
 
368
           target device 1 bit per component is a cache and this is
 
369
           text else it is a path */
 
370
        if (gx_device_has_color(gs_currentdevice(pgs)))
 
371
            gs_set_object_tag(pgs, GS_PATH_TAG);
 
372
        else
 
373
            gs_set_object_tag(pgs, GS_TEXT_TAG);
 
374
 
 
375
        /* Here we need to distinguish text from vectors to compute the object tag.
 
376
           Actually we need to know whether this function is called to rasterize a character,
 
377
           or to rasterize a vector graphics to the output device.
 
378
           Currently we assume it works for the bitrgbtags device only,
 
379
           which is a low level device with a 4-component color model.
 
380
           We use the fact that with printers a character is usually being rendered 
 
381
           to a 1bpp cache device rather than to the output device.
 
382
           Therefore we hackly look whether the target device
 
383
           "has a color" : either it's a multicomponent color model,
 
384
           or it is not gray (such as a yellow separation).
 
385
 
 
386
           This check has several limitations :
 
387
           1. It doesn't work with -dNOCACHE.
 
388
           2. It doesn't work with large characters,
 
389
              which cannot fit into a cache cell and thus they
 
390
              render directly to the output device.
 
391
           3. It doesn't work for TextAlphaBits=2 or 4.
 
392
              We don't care of this case because
 
393
              text antialiasing usually usn't applied to printers.
 
394
           4. It doesn't work for things like with "(xyz) true charpath stroke".
 
395
              That's unfortunate, we'd like to improve someday.
 
396
           5. It doesn't work for high level devices when a Type 3 character is being constructed.
 
397
              This case is not important for low level devices
 
398
              (which a printer is), because low level device doesn't accept
 
399
              Type 3 charproc streams immediately.
 
400
         */
 
401
        if (gx_device_has_color(gs_currentdevice(pgs))) {
 
402
            gs_set_object_tag(pgs, GS_PATH_TAG);
 
403
        }
 
404
        else {
 
405
            gs_set_object_tag(pgs, GS_TEXT_TAG);
 
406
        }
 
407
        gx_set_dev_color(pgs);
 
408
        code = gs_state_color_load(pgs);
 
409
        if (code < 0)
 
410
            return code;
 
411
        abits = alpha_buffer_bits(pgs);
 
412
        if (abits > 1) {
 
413
            /*
 
414
             * Expand the bounding box by the line width.
 
415
             * This is expensive to compute, so we only do it
 
416
             * if we know we're going to buffer.
 
417
             */
 
418
            float xxyy = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yy);
 
419
            float xyyx = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yx);
 
420
            float scale = (float)(1 << (abits / 2));
 
421
            float orig_width = gs_currentlinewidth(pgs);
 
422
            float new_width = orig_width * scale;
 
423
            fixed extra_adjust =
 
424
                float2fixed(max(xxyy, xyyx) * new_width / 2);
 
425
            float orig_flatness = gs_currentflat(pgs);
 
426
            gx_path spath;
 
427
 
 
428
            /* Scale up the line width, dash pattern, and flatness. */
 
429
            if (extra_adjust < fixed_1)
 
430
                extra_adjust = fixed_1;
 
431
            acode = alpha_buffer_init(pgs,
 
432
                                      pgs->fill_adjust.x + extra_adjust,
 
433
                                      pgs->fill_adjust.y + extra_adjust,
 
434
                                      abits);
 
435
            if (acode < 0)
 
436
                return acode;
 
437
            gs_setlinewidth(pgs, new_width);
 
438
            scale_dash_pattern(pgs, scale);
 
439
            gs_setflat(pgs, orig_flatness * scale);
 
440
            /*
 
441
             * The alpha-buffer device requires that we fill the
 
442
             * entire path as a single unit.
 
443
             */
 
444
            gx_path_init_local(&spath, pgs->memory);
 
445
            code = gx_stroke_add(pgs->path, &spath, pgs);
 
446
            gs_setlinewidth(pgs, orig_width);
 
447
            scale_dash_pattern(pgs, 1.0 / scale);
 
448
            if (code >= 0)
 
449
                code = gx_fill_path(&spath, pgs->dev_color, pgs,
 
450
                                    gx_rule_winding_number,
 
451
                                    pgs->fill_adjust.x,
 
452
                                    pgs->fill_adjust.y);
 
453
            gs_setflat(pgs, orig_flatness);
 
454
            gx_path_free(&spath, "gs_stroke");
 
455
            if (acode > 0)
 
456
                rcode = alpha_buffer_release(pgs, code >= 0);
 
457
        } else
 
458
            code = gx_stroke_fill(pgs->path, pgs);
 
459
        if (code >= 0)
 
460
            gs_newpath(pgs);
 
461
        if (code >= 0 && rcode < 0)
 
462
            code = rcode;
 
463
    }
 
464
    return code;
 
465
}
 
466
 
 
467
/* Compute the stroked outline of the current path */
 
468
int
 
469
gs_strokepath(gs_state * pgs)
 
470
{
 
471
    gx_path spath;
 
472
    int code;
 
473
 
 
474
    gx_path_init_local(&spath, pgs->path->memory);
 
475
    code = gx_stroke_add(pgs->path, &spath, pgs);
 
476
    if (code < 0) {
 
477
        gx_path_free(&spath, "gs_strokepath");
 
478
        return code;
 
479
    }
 
480
    pgs->device->sgr.stroke_stored = false;
 
481
    code = gx_path_assign_free(pgs->path, &spath);
 
482
    if (code < 0)
 
483
        return code;
 
484
    /* NB: needs testing with PCL */
 
485
    if (CPSI_mode && gx_path_is_void(pgs->path))
 
486
        pgs->current_point_valid = false;
 
487
    else
 
488
        gx_setcurrentpoint(pgs, fixed2float(spath.position.x), fixed2float(spath.position.y));
 
489
    return 0;
 
490
 
 
491
}