Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/*$Id: gxpath.c,v 1.11 2005/05/26 17:22:17 igor Exp $ */
18
/* Internal path management routines for Ghostscript library */
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsstruct.h"
22
#include "gxfixed.h"
23
#include "gzpath.h"
24
#include "vdtrace.h"
25
 
26
/* These routines all assume that all points are */
27
/* already in device coordinates, and in fixed representation. */
28
/* As usual, they return either 0 or a (negative) error code. */
29
 
30
/* Forward references */
31
private int path_alloc_copy(gx_path *);
32
private int gx_path_new_subpath(gx_path *);
33
 
34
#ifdef DEBUG
35
private void gx_print_segment(const segment *);
36
 
37
#  define trace_segment(msg, pseg)\
38
     if ( gs_debug_c('P') ) dlprintf(msg), gx_print_segment(pseg);
39
#else
40
#  define trace_segment(msg, pseg) DO_NOTHING
41
#endif
42
 
43
/* Check a point against a preset bounding box. */
44
#define outside_bbox(ppath, px, py)\
45
 (px < ppath->bbox.p.x || px > ppath->bbox.q.x ||\
46
  py < ppath->bbox.p.y || py > ppath->bbox.q.y)
47
#define check_in_bbox(ppath, px, py)\
48
  if ( outside_bbox(ppath, px, py) )\
49
	return_error(gs_error_rangecheck)
50
 
51
/* Structure descriptors for paths and path segment types. */
52
public_st_path();
53
private_st_path_segments();
54
private_st_segment();
55
private_st_line();
56
private_st_line_close();
57
private_st_curve();
58
private_st_subpath();
59
 
60
/* ------ Initialize/free paths ------ */
61
 
62
private rc_free_proc(rc_free_path_segments);
63
private rc_free_proc(rc_free_path_segments_local);
64
 
65
/*
66
 * Define the default virtual path interface implementation.
67
 */
68
private int 
69
    gz_path_add_point(gx_path *, fixed, fixed),
70
    gz_path_add_line_notes(gx_path *, fixed, fixed, segment_notes),
71
    gz_path_add_curve_notes(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes),
72
    gz_path_close_subpath_notes(gx_path *, segment_notes);
73
private byte gz_path_state_flags(gx_path *ppath, byte flags);
74
 
75
private gx_path_procs default_path_procs = {
76
    gz_path_add_point,
77
    gz_path_add_line_notes,
78
    gz_path_add_curve_notes,
79
    gz_path_close_subpath_notes,
80
    gz_path_state_flags
81
};
82
 
83
/*
84
 * Define virtual path interface implementation for computing a path bbox.
85
 */
86
private int 
87
    gz_path_bbox_add_point(gx_path *, fixed, fixed),
88
    gz_path_bbox_add_line_notes(gx_path *, fixed, fixed, segment_notes),
89
    gz_path_bbox_add_curve_notes(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes),
90
    gz_path_bbox_close_subpath_notes(gx_path *, segment_notes);
91
 
92
private gx_path_procs path_bbox_procs = {
93
    gz_path_bbox_add_point,
94
    gz_path_bbox_add_line_notes,
95
    gz_path_bbox_add_curve_notes,
96
    gz_path_bbox_close_subpath_notes,
97
    gz_path_state_flags
98
};
99
 
100
private void
101
gx_path_init_contents(gx_path * ppath)
102
{
103
    ppath->box_last = 0;
104
    ppath->first_subpath = ppath->current_subpath = 0;
105
    ppath->subpath_count = 0;
106
    ppath->curve_count = 0;
107
    path_update_newpath(ppath);
108
    ppath->bbox_set = 0;
109
    ppath->bbox_accurate = 0;
110
}
111
 
112
/*
113
 * Initialize a path contained in an already-heap-allocated object,
114
 * optionally allocating its segments.
115
 */
116
private int
117
path_alloc_segments(gx_path_segments ** ppsegs, gs_memory_t * mem,
118
		    client_name_t cname)
119
{
120
    mem = gs_memory_stable(mem);
121
    rc_alloc_struct_1(*ppsegs, gx_path_segments, &st_path_segments,
122
		      mem, return_error(gs_error_VMerror), cname);
123
    (*ppsegs)->rc.free = rc_free_path_segments;
124
    return 0;
125
}
126
int
127
gx_path_init_contained_shared(gx_path * ppath, const gx_path * shared,
128
			      gs_memory_t * mem, client_name_t cname)
129
{
130
    if (shared) {
131
	if (shared->segments == &shared->local_segments) {
132
	    lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
133
		     (ulong) shared);
134
	    return_error(gs_error_Fatal);
135
	}
136
	*ppath = *shared;
137
	rc_increment(ppath->segments);
138
    } else {
139
	int code = path_alloc_segments(&ppath->segments, mem, cname);
140
 
141
	if (code < 0)
142
	    return code;
143
	gx_path_init_contents(ppath);
144
    }
145
    ppath->memory = mem;
146
    ppath->allocation = path_allocated_contained;
147
    ppath->procs = &default_path_procs;
148
    return 0;
149
}
150
 
151
/*
152
 * Allocate a path on the heap, and initialize it.  If shared is NULL,
153
 * allocate a segments object; if shared is an existing path, share its
154
 * segments.
155
 */
156
gx_path *
157
gx_path_alloc_shared(const gx_path * shared, gs_memory_t * mem,
158
		     client_name_t cname)
159
{
160
    gx_path *ppath = gs_alloc_struct(mem, gx_path, &st_path, cname);
161
 
162
    if (ppath == 0)
163
	return 0;
164
    ppath->procs = &default_path_procs;
165
    if (shared) {
166
	if (shared->segments == &shared->local_segments) {
167
	    lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
168
		     (ulong) shared);
169
	    gs_free_object(mem, ppath, cname);
170
	    return 0;
171
	}
172
	*ppath = *shared;
173
	rc_increment(ppath->segments);
174
    } else {
175
	int code = path_alloc_segments(&ppath->segments, mem, cname);
176
 
177
	if (code < 0) {
178
	    gs_free_object(mem, ppath, cname);
179
	    return 0;
180
	}
181
	gx_path_init_contents(ppath);
182
    }
183
    ppath->memory = mem;
184
    ppath->allocation = path_allocated_on_heap;
185
    return ppath;
186
}
187
 
188
/*
189
 * Initialize a stack-allocated path.  This doesn't allocate anything,
190
 * but may still share the segments.
191
 */
192
int
193
gx_path_init_local_shared(gx_path * ppath, const gx_path * shared,
194
			  gs_memory_t * mem)
195
{
196
    if (shared) {
197
	if (shared->segments == &shared->local_segments) {
198
	    lprintf1("Attempt to share (local) segments of path 0x%lx!\n",
199
		     (ulong) shared);
200
	    return_error(gs_error_Fatal);
201
	}
202
	*ppath = *shared;
203
	rc_increment(ppath->segments);
204
    } else {
205
	rc_init_free(&ppath->local_segments, mem, 1,
206
		     rc_free_path_segments_local);
207
	ppath->segments = &ppath->local_segments;
208
	gx_path_init_contents(ppath);
209
    }
210
    ppath->memory = mem;
211
    ppath->allocation = path_allocated_on_stack;
212
    ppath->procs = &default_path_procs;
213
    return 0;
214
}
215
 
216
/*
217
 * Initialize a stack-allocated pseudo-path for computing a bbox
218
 * for a dynamic path.
219
 */
220
void
221
gx_path_init_bbox_accumulator(gx_path * ppath)
222
{
223
    ppath->box_last = 0;
224
    ppath->subpath_count = 0;
225
    ppath->curve_count = 0;
226
    ppath->local_segments.contents.subpath_first = 0;
227
    ppath->local_segments.contents.subpath_current = 0;
228
    ppath->segments = 0;
229
    path_update_newpath(ppath);
230
    ppath->bbox.p.x = ppath->bbox.q.x = 0;
231
    ppath->bbox.p.y = ppath->bbox.q.y = 0;
232
    ppath->bbox_set = 0;
233
    ppath->bbox_accurate = 1;
234
    ppath->memory = NULL; /* Won't allocate anything. */
235
    ppath->allocation = path_allocated_on_stack;
236
    ppath->procs = &path_bbox_procs;
237
}
238
 
239
/*
240
 * Ensure that a path owns its segments, by copying the segments if
241
 * they currently have multiple references.
242
 */
243
int
244
gx_path_unshare(gx_path * ppath)
245
{
246
    int code = 0;
247
 
248
    if (gx_path_is_shared(ppath))
249
	code = path_alloc_copy(ppath);
250
    return code;
251
}
252
 
253
/*
254
 * Free a path by releasing its segments if they have no more references.
255
 * This also frees the path object iff it was allocated by gx_path_alloc.
256
 */
257
void
258
gx_path_free(gx_path * ppath, client_name_t cname)
259
{
260
    rc_decrement(ppath->segments, cname);
261
    /* Clean up pointers for GC. */
262
    ppath->box_last = 0;
263
    ppath->segments = 0;	/* Nota bene */
264
    if (ppath->allocation == path_allocated_on_heap)
265
	gs_free_object(ppath->memory, ppath, cname);
266
}
267
 
268
/*
269
 * Assign one path to another, adjusting reference counts appropriately.
270
 * Note that this requires that segments of the two paths (but not the path
271
 * objects themselves) were allocated with the same allocator.  Note also
272
 * that since it does the equivalent of a gx_path_new(ppto), it may allocate
273
 * a new segments object for ppto.
274
 */
275
int
276
gx_path_assign_preserve(gx_path * ppto, gx_path * ppfrom)
277
{
278
    gx_path_segments *fromsegs = ppfrom->segments;
279
    gx_path_segments *tosegs = ppto->segments;
280
    gs_memory_t *mem = ppto->memory;
281
    gx_path_allocation_t allocation = ppto->allocation;
282
 
283
    if (fromsegs == &ppfrom->local_segments) {
284
	/* We can't use ppfrom's segments object. */
285
	if (tosegs == &ppto->local_segments || gx_path_is_shared(ppto)) {
286
	    /* We can't use ppto's segments either.  Allocate a new one. */
287
	    int code = path_alloc_segments(&tosegs, ppto->memory,
288
					   "gx_path_assign");
289
 
290
	    if (code < 0)
291
		return code;
292
	    rc_decrement(ppto->segments, "gx_path_assign");
293
	} else {
294
	    /* Use ppto's segments object. */
295
	    rc_free_path_segments_local(tosegs->rc.memory, tosegs,
296
					"gx_path_assign");
297
	}
298
	tosegs->contents = fromsegs->contents;
299
	ppfrom->segments = tosegs;
300
	rc_increment(tosegs);	/* for reference from ppfrom */
301
    } else {
302
	/* We can use ppfrom's segments object. */
303
	rc_increment(fromsegs);
304
	rc_decrement(tosegs, "gx_path_assign");
305
    }
306
    *ppto = *ppfrom;
307
    ppto->memory = mem;
308
    ppto->allocation = allocation;
309
    return 0;
310
}
311
 
312
/*
313
 * Assign one path to another and free the first path at the same time.
314
 * (This may do less work than assign_preserve + free.)
315
 */
316
int
317
gx_path_assign_free(gx_path * ppto, gx_path * ppfrom)
318
{
319
    /*
320
     * Detect the special case where both paths have non-shared local
321
     * segments, since we can avoid allocating new segments in this case.
322
     */
323
    if (ppto->segments == &ppto->local_segments &&
324
	ppfrom->segments == &ppfrom->local_segments &&
325
	!gx_path_is_shared(ppto)
326
	) {
327
#define fromsegs (&ppfrom->local_segments)
328
#define tosegs (&ppto->local_segments)
329
	gs_memory_t *mem = ppto->memory;
330
	gx_path_allocation_t allocation = ppto->allocation;
331
 
332
	rc_free_path_segments_local(tosegs->rc.memory, tosegs,
333
				    "gx_path_assign_free");
334
	/* We record a bogus reference to fromsegs, which */
335
	/* gx_path_free will undo. */
336
	*ppto = *ppfrom;
337
	rc_increment(fromsegs);
338
	ppto->segments = tosegs;
339
	ppto->memory = mem;
340
	ppto->allocation = allocation;
341
#undef fromsegs
342
#undef tosegs
343
    } else {
344
	/* In all other cases, just do assign + free. */
345
	int code = gx_path_assign_preserve(ppto, ppfrom);
346
 
347
	if (code < 0)
348
	    return code;
349
    }
350
    gx_path_free(ppfrom, "gx_path_assign_free");
351
    return 0;
352
}
353
 
354
/*
355
 * Free the segments of a path when their reference count goes to zero.
356
 * We do this in reverse order so as to maximize LIFO allocator behavior.
357
 * We don't have to worry about cleaning up pointers, because we're about
358
 * to free the segments object.
359
 */
360
private void
361
rc_free_path_segments_local(gs_memory_t * mem, void *vpsegs,
362
			    client_name_t cname)
363
{
364
    gx_path_segments *psegs = (gx_path_segments *) vpsegs;
365
    segment *pseg;
366
 
367
    mem = gs_memory_stable(mem);
368
    if (psegs->contents.subpath_first == 0)
369
	return;			/* empty path */
370
    pseg = (segment *) psegs->contents.subpath_current->last;
371
    while (pseg) {
372
	segment *prev = pseg->prev;
373
 
374
	trace_segment("[P]release", pseg);
375
	gs_free_object(mem, pseg, cname);
376
	pseg = prev;
377
    }
378
}
379
private void
380
rc_free_path_segments(gs_memory_t * mem, void *vpsegs, client_name_t cname)
381
{
382
    rc_free_path_segments_local(mem, vpsegs, cname);
383
    gs_free_object(mem, vpsegs, cname);
384
}
385
 
386
/* ------ Incremental path building ------ */
387
 
388
/* Guarantee that a path's segments are not shared with any other path. */
389
#define path_unshare(ppath)\
390
  BEGIN\
391
    if ( gx_path_is_shared(ppath) ) {\
392
      int code_;\
393
      if( (code_ = path_alloc_copy(ppath)) < 0 ) return code_;\
394
    }\
395
  END
396
 
397
/* Macro for opening the current subpath. */
398
/* ppath points to the path; sets psub to ppath->current_subpath. */
399
#define path_open()\
400
  BEGIN\
401
    if ( !path_is_drawing(ppath) ) {\
402
      int code_;\
403
      if ( !path_position_valid(ppath) )\
404
	return_error(gs_error_nocurrentpoint);\
405
      code_ = gx_path_new_subpath(ppath);\
406
      if ( code_ < 0 ) return code_;\
407
    }\
408
  END
409
 
410
/* Macros for allocating path segments. */
411
/* Note that they assume that ppath points to the path. */
412
/* We have to split the macro into two because of limitations */
413
/* on the size of a single statement (sigh). */
414
#define path_alloc_segment(pseg,ctype,pstype,stype,snotes,cname)\
415
  path_unshare(ppath);\
416
  psub = ppath->current_subpath;\
417
  if( !(pseg = gs_alloc_struct(gs_memory_stable(ppath->memory), ctype,\
418
			       pstype, cname)) )\
419
    return_error(gs_error_VMerror);\
420
  pseg->type = stype, pseg->notes = snotes, pseg->next = 0
421
#define path_alloc_link(pseg)\
422
  { segment *prev = psub->last;\
423
    prev->next = (segment *)pseg;\
424
    pseg->prev = prev;\
425
    psub->last = (segment *)pseg;\
426
  }
427
 
428
/* Make a new path (newpath). */
429
int
430
gx_path_new(gx_path * ppath)
431
{
432
    gx_path_segments *psegs = ppath->segments;
433
 
434
    if (gx_path_is_shared(ppath)) {
435
	int code = path_alloc_segments(&ppath->segments, ppath->memory,
436
				       "gx_path_new");
437
 
438
	if (code < 0)
439
	    return code;
440
	rc_decrement(psegs, "gx_path_new");
441
    } else {
442
	rc_free_path_segments_local(psegs->rc.memory, psegs, "gx_path_new");
443
    }
444
    gx_path_init_contents(ppath);
445
    return 0;
446
}
447
 
448
/* Open a new subpath. */
449
/* The client must invoke path_update_xxx. */
450
private int
451
gx_path_new_subpath(gx_path * ppath)
452
{
453
    subpath *psub;
454
    subpath *spp;
455
 
456
    path_alloc_segment(spp, subpath, &st_subpath, s_start, sn_none,
457
		       "gx_path_new_subpath");
458
    spp->last = (segment *) spp;
459
    spp->curve_count = 0;
460
    spp->is_closed = 0;
461
    spp->pt = ppath->position;
462
    if (!psub) {		/* first subpath */
463
	ppath->first_subpath = spp;
464
	spp->prev = 0;
465
    } else {
466
	segment *prev = psub->last;
467
 
468
	prev->next = (segment *) spp;
469
	spp->prev = prev;
470
    }
471
    ppath->current_subpath = spp;
472
    ppath->subpath_count++;
473
    trace_segment("[P]", (const segment *)spp);
474
    return 0;
475
}
476
 
477
private inline void
478
gz_path_bbox_add(gx_path * ppath, fixed x, fixed y)
479
{
480
    if (!ppath->bbox_set) {
481
	ppath->bbox.p.x = ppath->bbox.q.x = x;
482
	ppath->bbox.p.y = ppath->bbox.q.y = y;
483
	ppath->bbox_set = 1;
484
    } else {
485
	if (ppath->bbox.p.x > x)
486
	    ppath->bbox.p.x = x;
487
	if (ppath->bbox.p.y > y)
488
	    ppath->bbox.p.y = y;
489
	if (ppath->bbox.q.x < x)
490
	    ppath->bbox.q.x = x;
491
	if (ppath->bbox.q.y < y)
492
	    ppath->bbox.q.y = y;
493
    }
494
}
495
 
496
private inline void
497
gz_path_bbox_move(gx_path * ppath, fixed x, fixed y)
498
{
499
    /* a trick : we store 'fixed' into 'double'. */
500
    ppath->position.x = x;
501
    ppath->position.y = y;
502
    ppath->state_flags |= psf_position_valid;
503
}
504
 
505
/* Add a point to the current path (moveto). */
506
int
507
gx_path_add_point(gx_path * ppath, fixed x, fixed y)
508
{
509
    return ppath->procs->add_point(ppath, x, y);
510
}
511
private int
512
gz_path_add_point(gx_path * ppath, fixed x, fixed y)
513
{
514
    if (ppath->bbox_set)
515
	check_in_bbox(ppath, x, y);
516
    ppath->position.x = x;
517
    ppath->position.y = y;
518
    path_update_moveto(ppath);
519
    return 0;
520
}
521
private int
522
gz_path_bbox_add_point(gx_path * ppath, fixed x, fixed y)
523
{
524
    gz_path_bbox_move(ppath, x, y);
525
    return 0;
526
}
527
 
528
/* Add a relative point to the current path (rmoveto). */
529
int
530
gx_path_add_relative_point(gx_path * ppath, fixed dx, fixed dy)
531
{
532
    if (!path_position_in_range(ppath))
533
	return_error((path_position_valid(ppath) ? gs_error_limitcheck :
534
		      gs_error_nocurrentpoint));
535
    {
536
	fixed nx = ppath->position.x + dx, ny = ppath->position.y + dy;
537
 
538
	/* Check for overflow in addition. */
539
	if (((nx ^ dx) < 0 && (ppath->position.x ^ dx) >= 0) ||
540
	    ((ny ^ dy) < 0 && (ppath->position.y ^ dy) >= 0)
541
	    )
542
	    return_error(gs_error_limitcheck);
543
	if (ppath->bbox_set)
544
	    check_in_bbox(ppath, nx, ny);
545
	ppath->position.x = nx;
546
	ppath->position.y = ny;
547
    }
548
    path_update_moveto(ppath);
549
    return 0;
550
}
551
 
552
/* Set the segment point and the current point in the path. */
553
/* Assumes ppath points to the path. */
554
#define path_set_point(pseg, fx, fy)\
555
	(pseg)->pt.x = ppath->position.x = (fx),\
556
	(pseg)->pt.y = ppath->position.y = (fy)
557
 
558
/* Add a line to the current path (lineto). */
559
int
560
gx_path_add_line_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
561
{
562
    return ppath->procs->add_line(ppath, x, y, notes);
563
}
564
private int
565
gz_path_add_line_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
566
{
567
    subpath *psub;
568
    line_segment *lp;
569
 
570
    if (ppath->bbox_set)
571
	check_in_bbox(ppath, x, y);
572
    path_open();
573
    path_alloc_segment(lp, line_segment, &st_line, s_line, notes,
574
		       "gx_path_add_line");
575
    path_alloc_link(lp);
576
    path_set_point(lp, x, y);
577
    path_update_draw(ppath);
578
    trace_segment("[P]", (segment *) lp);
579
    return 0;
580
}
581
private int
582
gz_path_bbox_add_line_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
583
{
584
    gz_path_bbox_add(ppath, x, y);
585
    gz_path_bbox_move(ppath, x, y);
586
    return 0;
587
}
588
 
589
/* Add multiple lines to the current path. */
590
/* Note that all lines have the same notes. */
591
int
592
gx_path_add_lines_notes(gx_path *ppath, const gs_fixed_point *ppts, int count,
593
			segment_notes notes)
594
{
595
    subpath *psub;
596
    segment *prev;
597
    line_segment *lp = 0;
598
    int i;
599
    int code = 0;
600
 
601
    if (count <= 0)
602
	return 0;
603
    path_unshare(ppath);
604
    path_open();
605
    psub = ppath->current_subpath;
606
    prev = psub->last;
607
    /*
608
     * We could do better than the following, but this is a start.
609
     * Note that we don't make any attempt to undo partial additions
610
     * if we fail partway through; this is equivalent to what would
611
     * happen with multiple calls on gx_path_add_line.
612
     */
613
    for (i = 0; i < count; i++) {
614
	fixed x = ppts[i].x;
615
	fixed y = ppts[i].y;
616
	line_segment *next;
617
 
618
	if (ppath->bbox_set && outside_bbox(ppath, x, y)) {
619
	    code = gs_note_error(gs_error_rangecheck);
620
	    break;
621
	}
622
	if (!(next = gs_alloc_struct(gs_memory_stable(ppath->memory),
623
				     line_segment, &st_line,
624
				     "gx_path_add_lines"))
625
	    ) {
626
	    code = gs_note_error(gs_error_VMerror);
627
	    break;
628
	}
629
	lp = next;
630
	lp->type = s_line;
631
	lp->notes = notes;
632
	prev->next = (segment *) lp;
633
	lp->prev = prev;
634
	lp->pt.x = x;
635
	lp->pt.y = y;
636
	prev = (segment *) lp;
637
	trace_segment("[P]", (segment *) lp);
638
    }
639
    if (lp != 0)
640
	ppath->position.x = lp->pt.x,
641
	    ppath->position.y = lp->pt.y,
642
	    psub->last = (segment *) lp,
643
	    lp->next = 0,
644
	    path_update_draw(ppath);
645
    return code;
646
}
647
 
648
/* Add a rectangle to the current path. */
649
/* This is a special case of adding a closed polygon. */
650
int
651
gx_path_add_rectangle(gx_path * ppath, fixed x0, fixed y0, fixed x1, fixed y1)
652
{
653
    gs_fixed_point pts[3];
654
    int code;
655
 
656
    pts[0].x = x0;
657
    pts[1].x = pts[2].x = x1;
658
    pts[2].y = y0;
659
    pts[0].y = pts[1].y = y1;
660
    if ((code = gx_path_add_point(ppath, x0, y0)) < 0 ||
661
	(code = gx_path_add_lines(ppath, pts, 3)) < 0 ||
662
	(code = gx_path_close_subpath(ppath)) < 0
663
	)
664
	return code;
665
    return 0;
666
}
667
 
668
/* Add a curve to the current path (curveto). */
669
int
670
gx_path_add_curve_notes(gx_path * ppath,
671
		 fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3,
672
			segment_notes notes)
673
{
674
    return ppath->procs->add_curve(ppath, x1, y1, x2, y2, x3, y3, notes);
675
}
676
private int
677
gz_path_add_curve_notes(gx_path * ppath,
678
		 fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3,
679
			segment_notes notes)
680
{
681
    subpath *psub;
682
    curve_segment *lp;
683
 
684
    if (ppath->bbox_set) {
685
	check_in_bbox(ppath, x1, y1);
686
	check_in_bbox(ppath, x2, y2);
687
	check_in_bbox(ppath, x3, y3);
688
    }
689
    path_open();
690
    path_alloc_segment(lp, curve_segment, &st_curve, s_curve, notes,
691
		       "gx_path_add_curve");
692
    path_alloc_link(lp);
693
    lp->p1.x = x1;
694
    lp->p1.y = y1;
695
    lp->p2.x = x2;
696
    lp->p2.y = y2;
697
    path_set_point(lp, x3, y3);
698
    psub->curve_count++;
699
    ppath->curve_count++;
700
    path_update_draw(ppath);
701
    trace_segment("[P]", (segment *) lp);
702
    return 0;
703
}
704
private int
705
gz_path_bbox_add_curve_notes(gx_path * ppath,
706
		 fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3,
707
			segment_notes notes)
708
{
709
    gz_path_bbox_add(ppath, x1, y1);
710
    gz_path_bbox_add(ppath, x2, y2);
711
    gz_path_bbox_add(ppath, x3, y3);
712
    gz_path_bbox_move(ppath, x3, y3);
713
    return 0;
714
}
715
 
716
/*
717
 * Add an approximation of an arc to the current path.
718
 * The current point of the path is the initial point of the arc;
719
 * parameters are the final point of the arc
720
 * and the point at which the extended tangents meet.
721
 * We require that the arc be less than a semicircle.
722
 * The arc may go either clockwise or counterclockwise.
723
 * The approximation is a very simple one: a single curve
724
 * whose other two control points are a fraction F of the way
725
 * to the intersection of the tangents, where
726
 *      F = (4/3)(1 / (1 + sqrt(1+(d/r)^2)))
727
 * where r is the radius and d is the distance from either tangent
728
 * point to the intersection of the tangents.  This produces
729
 * a curve whose center point, as well as its ends, lies on
730
 * the desired arc.
731
 *
732
 * Because F has to be computed in user space, we let the client
733
 * compute it and pass it in as an argument.
734
 */
735
int
736
gx_path_add_partial_arc_notes(gx_path * ppath,
737
fixed x3, fixed y3, fixed xt, fixed yt, floatp fraction, segment_notes notes)
738
{
739
    fixed x0 = ppath->position.x, y0 = ppath->position.y;
740
 
741
    vd_curveto(x0 + (fixed) ((xt - x0) * fraction),
742
				   y0 + (fixed) ((yt - y0) * fraction),
743
				   x3 + (fixed) ((xt - x3) * fraction),
744
				   y3 + (fixed) ((yt - y3) * fraction),
745
				   x3, y3);
746
    return gx_path_add_curve_notes(ppath,
747
				   x0 + (fixed) ((xt - x0) * fraction),
748
				   y0 + (fixed) ((yt - y0) * fraction),
749
				   x3 + (fixed) ((xt - x3) * fraction),
750
				   y3 + (fixed) ((yt - y3) * fraction),
751
				   x3, y3, notes | sn_from_arc);
752
}
753
 
754
/* Append a path to another path, and reset the first path. */
755
/* Currently this is only used to append a path to its parent */
756
/* (the path in the previous graphics context). */
757
int
758
gx_path_add_path(gx_path * ppath, gx_path * ppfrom)
759
{
760
    path_unshare(ppfrom);
761
    path_unshare(ppath);
762
    if (ppfrom->first_subpath) {	/* i.e. ppfrom not empty */
763
	if (ppath->first_subpath) {	/* i.e. ppath not empty */
764
	    subpath *psub = ppath->current_subpath;
765
	    segment *pseg = psub->last;
766
	    subpath *pfsub = ppfrom->first_subpath;
767
 
768
	    pseg->next = (segment *) pfsub;
769
	    pfsub->prev = pseg;
770
	} else
771
	    ppath->first_subpath = ppfrom->first_subpath;
772
	ppath->current_subpath = ppfrom->current_subpath;
773
	ppath->subpath_count += ppfrom->subpath_count;
774
	ppath->curve_count += ppfrom->curve_count;
775
    }
776
    /* Transfer the remaining state. */
777
    ppath->position = ppfrom->position;
778
    ppath->state_flags = ppfrom->state_flags;
779
    /* Reset the source path. */
780
    gx_path_init_contents(ppfrom);
781
    return 0;
782
}
783
 
784
/* Add a path or its bounding box to the enclosing path, */
785
/* and reset the first path.  Only used for implementing charpath and its */
786
/* relatives. */
787
int
788
gx_path_add_char_path(gx_path * to_path, gx_path * from_path,
789
		      gs_char_path_mode mode)
790
{
791
    int code;
792
    gs_fixed_rect bbox;
793
 
794
    switch (mode) {
795
	default:		/* shouldn't happen! */
796
	    gx_path_new(from_path);
797
	    return 0;
798
	case cpm_charwidth: {
799
	    gs_fixed_point cpt;
800
 
801
	    code = gx_path_current_point(from_path, &cpt);
802
	    if (code < 0)
803
		break;
804
	    return gx_path_add_point(to_path, cpt.x, cpt.y);
805
	}
806
	case cpm_true_charpath:
807
	case cpm_false_charpath:
808
	    return gx_path_add_path(to_path, from_path);
809
	case cpm_true_charboxpath:
810
	    gx_path_bbox(from_path, &bbox);
811
	    code = gx_path_add_rectangle(to_path, bbox.p.x, bbox.p.y,
812
					 bbox.q.x, bbox.q.y);
813
	    break;
814
	case cpm_false_charboxpath:
815
	    gx_path_bbox(from_path, &bbox);
816
	    code = gx_path_add_point(to_path, bbox.p.x, bbox.p.y);
817
	    if (code >= 0)
818
		code = gx_path_add_line(to_path, bbox.q.x, bbox.q.y);
819
	    break;
820
    }
821
    if (code < 0)
822
	return code;
823
    gx_path_new(from_path);
824
    return 0;
825
}
826
 
827
/* Close the current subpath. */
828
int
829
gx_path_close_subpath_notes(gx_path * ppath, segment_notes notes)
830
{
831
    return ppath->procs->close_subpath(ppath, notes);
832
}
833
private int
834
gz_path_close_subpath_notes(gx_path * ppath, segment_notes notes)
835
{
836
    subpath *psub;
837
    line_close_segment *lp;
838
    int code;
839
 
840
    if (!path_subpath_open(ppath))
841
	return 0;
842
    if (path_last_is_moveto(ppath)) {
843
	/* The last operation was a moveto: create a subpath. */
844
	code = gx_path_new_subpath(ppath);
845
	if (code < 0)
846
	    return code;
847
    }
848
    path_alloc_segment(lp, line_close_segment, &st_line_close,
849
		       s_line_close, notes, "gx_path_close_subpath");
850
    path_alloc_link(lp);
851
    path_set_point(lp, psub->pt.x, psub->pt.y);
852
    lp->sub = psub;
853
    psub->is_closed = 1;
854
    path_update_closepath(ppath);
855
    trace_segment("[P]", (segment *) lp);
856
    return 0;
857
}
858
private int
859
gz_path_bbox_close_subpath_notes(gx_path * ppath, segment_notes notes)
860
{
861
    return 0;
862
}
863
 
864
/* Access path state flags */
865
byte 
866
gz_path_state_flags(gx_path *ppath, byte flags)
867
{
868
    byte flags_old = ppath->state_flags;
869
    ppath->state_flags = flags;
870
    return flags_old;
871
}
872
byte 
873
gx_path_get_state_flags(gx_path *ppath)
874
{
875
    byte flags = ppath->procs->state_flags(ppath, 0);
876
    ppath->procs->state_flags(ppath, flags);
877
    return flags;
878
}
879
void 
880
gx_path_set_state_flags(gx_path *ppath, byte flags)
881
{
882
    ppath->procs->state_flags(ppath, flags);
883
}
884
bool
885
gx_path_is_drawing(gx_path *ppath)
886
{
887
  return path_is_drawing(ppath);
888
}
889
 
890
 
891
 
892
/* Remove the last line from the current subpath, and then close it. */
893
/* The Type 1 font hinting routines use this if a path ends with */
894
/* a line to the start followed by a closepath. */
895
int
896
gx_path_pop_close_notes(gx_path * ppath, segment_notes notes)
897
{
898
    subpath *psub = ppath->current_subpath;
899
    segment *pseg;
900
    segment *prev;
901
 
902
    if (psub == 0 || (pseg = psub->last) == 0 ||
903
	pseg->type != s_line
904
	)
905
	return_error(gs_error_unknownerror);
906
    prev = pseg->prev;
907
    prev->next = 0;
908
    psub->last = prev;
909
    gs_free_object(ppath->memory, pseg, "gx_path_pop_close_subpath");
910
    return gx_path_close_subpath_notes(ppath, notes);
911
}
912
 
913
/* ------ Internal routines ------ */
914
 
915
/*
916
 * Copy the current path, because it was shared.
917
 */
918
private int
919
path_alloc_copy(gx_path * ppath)
920
{
921
    gx_path path_new;
922
    int code;
923
 
924
    gx_path_init_local(&path_new, ppath->memory);
925
    code = gx_path_copy(ppath, &path_new);
926
    if (code < 0) {
927
	gx_path_free(&path_new, "path_alloc_copy error");
928
	return code;
929
    }
930
    return gx_path_assign_free(ppath, &path_new);
931
}
932
 
933
/* ------ Debugging printout ------ */
934
 
935
#ifdef DEBUG
936
 
937
/* Print out a path with a label */
938
void
939
gx_dump_path(const gx_path * ppath, const char *tag)
940
{
941
    dlprintf2("[P]Path 0x%lx %s:\n", (ulong) ppath, tag);
942
    gx_path_print(ppath);
943
}
944
 
945
/* Print a path */
946
void
947
gx_path_print(const gx_path * ppath)
948
{
949
    const segment *pseg = (const segment *)ppath->first_subpath;
950
 
951
    dlprintf5("   state_flags=%d subpaths=%d, curves=%d, point=(%f,%f)\n",
952
	      ppath->state_flags, ppath->subpath_count, ppath->curve_count,
953
	      fixed2float(ppath->position.x),
954
	      fixed2float(ppath->position.y));
955
    dlprintf5("   box=(%f,%f),(%f,%f) last=0x%lx\n",
956
	      fixed2float(ppath->bbox.p.x), fixed2float(ppath->bbox.p.y),
957
	      fixed2float(ppath->bbox.q.x), fixed2float(ppath->bbox.q.y),
958
	      (ulong) ppath->box_last);
959
    dlprintf4("   segments=0x%lx (refct=%ld, first=0x%lx, current=0x%lx)\n",
960
	      (ulong) ppath->segments, (long)ppath->segments->rc.ref_count,
961
	      (ulong) ppath->segments->contents.subpath_first,
962
	      (ulong) ppath->segments->contents.subpath_current);
963
    while (pseg) {
964
	dlputs("");
965
	gx_print_segment(pseg);
966
	pseg = pseg->next;
967
    }
968
}
969
private void
970
gx_print_segment(const segment * pseg)
971
{
972
    double px = fixed2float(pseg->pt.x);
973
    double py = fixed2float(pseg->pt.y);
974
    char out[80];
975
 
976
    sprintf(out, "   0x%lx<0x%lx,0x%lx>:%u",
977
	 (ulong) pseg, (ulong) pseg->prev, (ulong) pseg->next, pseg->notes);
978
    switch (pseg->type) {
979
	case s_start:{
980
		const subpath *const psub = (const subpath *)pseg;
981
 
982
		dprintf5("%s: %1.4f %1.4f moveto\t%% #curves=%d last=0x%lx\n",
983
			 out, px, py, psub->curve_count, (ulong) psub->last);
984
		break;
985
	    }
986
	case s_curve:{
987
		const curve_segment *const pcur = (const curve_segment *)pseg;
988
 
989
		dprintf7("%s: %1.4f %1.4f %1.4f %1.4f %1.4f %1.4f curveto\n",
990
		      out, fixed2float(pcur->p1.x), fixed2float(pcur->p1.y),
991
		  fixed2float(pcur->p2.x), fixed2float(pcur->p2.y), px, py);
992
		break;
993
	    }
994
	case s_line:
995
	    dprintf3("%s: %1.4f %1.4f lineto\n", out, px, py);
996
	    break;
997
	case s_line_close:{
998
		const line_close_segment *const plc =
999
		(const line_close_segment *)pseg;
1000
 
1001
		dprintf4("%s: closepath\t%% %1.4f %1.4f 0x%lx\n",
1002
			 out, px, py, (ulong) (plc->sub));
1003
		break;
1004
	    }
1005
	default:
1006
	    dprintf4("%s: %1.4f %1.4f <type 0x%x>\n", out, px, py, pseg->type);
1007
    }
1008
}
1009
 
1010
#endif /* DEBUG */