57
57
gx_path_bbox(gx_path * ppath, gs_fixed_rect * pbox)
59
59
if (ppath->bbox_accurate) {
60
/* The bounding box was set by setbbox. */
60
/* The bounding box was set by setbbox. */
64
64
if (ppath->first_subpath == 0) {
65
/* The path is empty, use the current point if any. */
66
int code = gx_path_current_point(ppath, &pbox->p);
65
/* The path is empty, use the current point if any. */
66
int code = gx_path_current_point(ppath, &pbox->p);
70
* Don't return garbage, in case the caller doesn't
71
* check the return code.
73
pbox->p.x = pbox->p.y = 0;
70
* Don't return garbage, in case the caller doesn't
71
* check the return code.
73
pbox->p.x = pbox->p.y = 0;
78
78
/* The stored bounding box may not be up to date. */
79
79
/* Correct it now if necessary. */
80
80
if (ppath->box_last == ppath->current_subpath->last) {
81
/* Box is up to date */
81
/* Box is up to date */
85
const segment *pseg = ppath->box_last;
85
const segment *pseg = ppath->box_last;
87
if (pseg == 0) { /* box is uninitialized */
88
pseg = (const segment *)ppath->first_subpath;
92
px = ppath->bbox.p.x, py = ppath->bbox.p.y;
93
qx = ppath->bbox.q.x, qy = ppath->bbox.q.y;
87
if (pseg == 0) { /* box is uninitialized */
88
pseg = (const segment *)ppath->first_subpath;
92
px = ppath->bbox.p.x, py = ppath->bbox.p.y;
93
qx = ppath->bbox.q.x, qy = ppath->bbox.q.y;
96
96
/* Macro for adjusting the bounding box when adding a point */
97
97
#define ADJUST_BBOX(pt)\
100
100
if ((pt).y < py) py = (pt).y;\
101
101
else if ((pt).y > qy) qy = (pt).y
103
while ((pseg = pseg->next) != 0) {
104
switch (pseg->type) {
106
ADJUST_BBOX(((const curve_segment *)pseg)->p1);
107
ADJUST_BBOX(((const curve_segment *)pseg)->p2);
110
ADJUST_BBOX(pseg->pt);
103
while ((pseg = pseg->next) != 0) {
104
switch (pseg->type) {
106
ADJUST_BBOX(((const curve_segment *)pseg)->p1);
107
ADJUST_BBOX(((const curve_segment *)pseg)->p2);
110
ADJUST_BBOX(pseg->pt);
113
113
#undef ADJUST_BBOX
115
115
#define STORE_BBOX(b)\
116
116
(b).p.x = px, (b).p.y = py, (b).q.x = qx, (b).q.y = qy;
118
STORE_BBOX(ppath->bbox);
118
STORE_BBOX(ppath->bbox);
119
119
#undef STORE_BBOX
121
ppath->box_last = ppath->current_subpath->last;
121
ppath->box_last = ppath->current_subpath->last;
176
175
gx_path_rectangular_type
177
176
gx_subpath_is_rectangular(const subpath * pseg0, gs_fixed_rect * pbox,
178
const subpath ** ppnext)
177
const subpath ** ppnext)
180
179
const segment *pseg1, *pseg2, *pseg3, *pseg4;
181
180
gx_path_rectangular_type type;
183
182
if (pseg0->curve_count == 0 &&
184
(pseg1 = pseg0->next) != 0 &&
185
(pseg2 = pseg1->next) != 0 &&
186
(pseg3 = pseg2->next) != 0
188
if ((pseg4 = pseg3->next) == 0 || pseg4->type == s_start)
189
type = prt_open; /* M, L, L, L */
190
else if (pseg4->type != s_line) /* must be s_line_close */
191
type = prt_closed; /* M, L, L, L, C */
192
else if (pseg4->pt.x != pseg0->pt.x ||
193
pseg4->pt.y != pseg0->pt.y
196
else if (pseg4->next == 0 || pseg4->next->type == s_start)
197
type = prt_fake_closed; /* Mo, L, L, L, Lo */
198
else if (pseg4->next->type != s_line) /* must be s_line_close */
199
type = prt_closed; /* Mo, L, L, L, Lo, C */
203
fixed x0 = pseg0->pt.x, y0 = pseg0->pt.y;
204
fixed x2 = pseg2->pt.x, y2 = pseg2->pt.y;
183
(pseg1 = pseg0->next) != 0 &&
184
(pseg2 = pseg1->next) != 0 &&
185
(pseg3 = pseg2->next) != 0
187
if ((pseg4 = pseg3->next) == 0 || pseg4->type == s_start)
188
type = prt_open; /* M, L, L, L */
189
else if (pseg4->type != s_line) /* must be s_line_close */
190
type = prt_closed; /* M, L, L, L, C */
191
else if (pseg4->pt.x != pseg0->pt.x ||
192
pseg4->pt.y != pseg0->pt.y
195
else if (pseg4->next == 0 || pseg4->next->type == s_start)
196
type = prt_fake_closed; /* Mo, L, L, L, Lo */
197
else if (pseg4->next->type != s_line) /* must be s_line_close */
198
type = prt_closed; /* Mo, L, L, L, Lo, C */
202
fixed x0 = pseg0->pt.x, y0 = pseg0->pt.y;
203
fixed x2 = pseg2->pt.x, y2 = pseg2->pt.y;
206
if ((x0 == pseg1->pt.x && pseg1->pt.y == y2 &&
207
x2 == pseg3->pt.x && pseg3->pt.y == y0) ||
208
(x0 == pseg3->pt.x && pseg3->pt.y == y2 &&
209
x2 == pseg1->pt.x && pseg1->pt.y == y0)
210
) { /* Path is a rectangle. Return the bounding box. */
212
pbox->p.x = x0, pbox->q.x = x2;
214
pbox->p.x = x2, pbox->q.x = x0;
216
pbox->p.y = y0, pbox->q.y = y2;
218
pbox->p.y = y2, pbox->q.y = y0;
219
while (pseg4 != 0 && pseg4->type != s_start)
221
*ppnext = (const subpath *)pseg4;
205
if ((x0 == pseg1->pt.x && pseg1->pt.y == y2 &&
206
x2 == pseg3->pt.x && pseg3->pt.y == y0) ||
207
(x0 == pseg3->pt.x && pseg3->pt.y == y2 &&
208
x2 == pseg1->pt.x && pseg1->pt.y == y0)
209
) { /* Path is a rectangle. Return the bounding box. */
211
pbox->p.x = x0, pbox->q.x = x2;
213
pbox->p.x = x2, pbox->q.x = x0;
215
pbox->p.y = y0, pbox->q.y = y2;
217
pbox->p.y = y2, pbox->q.y = y0;
218
while (pseg4 != 0 && pseg4->type != s_start)
220
*ppnext = (const subpath *)pseg4;
349
348
if (gs_debug_c('P'))
350
gx_dump_path(ppath_old, "before reversepath");
349
gx_dump_path(ppath_old, "before reversepath");
354
const segment *prev = psub->last;
356
segment_notes notes =
357
(prev == (const segment *)psub ? sn_none :
359
segment_notes prev_notes;
362
if (!psub->is_closed) {
363
code = gx_path_add_point(ppath, prev->pt.x, prev->pt.y);
368
* The do ... while structure of this loop is artificial,
369
* designed solely to keep compilers from complaining about
370
* 'statement not reached' or 'end-of-loop code not reached'.
371
* The normal exit from this loop is the goto statement in
372
* the s_start arm of the switch.
379
prev_notes = (prev_notes & sn_not_first) |
380
(notes & ~sn_not_first);
381
switch (pseg->type) {
383
/* Finished subpath */
384
if (psub->is_closed) {
386
gx_path_close_subpath_notes(ppath, prev_notes);
391
psub = (const subpath *)psub->prev;
392
} while (psub && psub->type != s_start);
396
const curve_segment *pc =
397
(const curve_segment *)pseg;
399
code = gx_path_add_curve_notes(ppath,
402
prev->pt.x, prev->pt.y, prev_notes);
406
code = gx_path_add_line_notes(ppath,
407
prev->pt.x, prev->pt.y, prev_notes);
410
/* Skip the closing line. */
411
code = gx_path_add_point(ppath, prev->pt.x,
414
default: /* not possible */
415
return_error(gs_error_Fatal);
418
return code; /* only reached if code < 0 */
353
const segment *prev = psub->last;
355
segment_notes notes =
356
(prev == (const segment *)psub ? sn_none :
358
segment_notes prev_notes;
361
if (!psub->is_closed) {
362
code = gx_path_add_point(ppath, prev->pt.x, prev->pt.y);
367
* The do ... while structure of this loop is artificial,
368
* designed solely to keep compilers from complaining about
369
* 'statement not reached' or 'end-of-loop code not reached'.
370
* The normal exit from this loop is the goto statement in
371
* the s_start arm of the switch.
378
prev_notes = (prev_notes & sn_not_first) |
379
(notes & ~sn_not_first);
380
switch (pseg->type) {
382
/* Finished subpath */
383
if (psub->is_closed) {
385
gx_path_close_subpath_notes(ppath, prev_notes);
390
psub = (const subpath *)psub->prev;
391
} while (psub && psub->type != s_start);
395
const curve_segment *pc =
396
(const curve_segment *)pseg;
398
code = gx_path_add_curve_notes(ppath,
401
prev->pt.x, prev->pt.y, prev_notes);
405
code = gx_path_add_line_notes(ppath,
406
prev->pt.x, prev->pt.y, prev_notes);
409
/* Skip the closing line. */
410
code = gx_path_add_point(ppath, prev->pt.x,
413
default: /* not possible */
414
return_error(gs_error_Fatal);
417
return code; /* only reached if code < 0 */
420
419
#undef sn_not_end
448
447
if (gs_debug_c('P'))
449
gx_dump_path(ppath_old, "before reversepath");
448
gx_dump_path(ppath_old, "before reversepath");
453
const segment *prev = psub->last;
455
segment_notes notes =
456
(prev == (const segment *)psub ? sn_none :
458
segment_notes prev_notes;
461
if (!psub->is_closed) {
462
code = gx_path_add_line(ppath, prev->pt.x, prev->pt.y);
467
* The do ... while structure of this loop is artificial,
468
* designed solely to keep compilers from complaining about
469
* 'statement not reached' or 'end-of-loop code not reached'.
470
* The normal exit from this loop is the goto statement in
471
* the s_start arm of the switch.
478
prev_notes = (prev_notes & sn_not_first) |
479
(notes & ~sn_not_first);
480
switch (pseg->type) {
482
/* Finished subpath */
483
if (psub->is_closed) {
485
gx_path_close_subpath_notes(ppath, prev_notes);
490
psub = (const subpath *)psub->prev;
491
} while (psub && psub->type != s_start);
495
const curve_segment *pc =
496
(const curve_segment *)pseg;
498
code = gx_path_add_curve_notes(ppath,
501
prev->pt.x, prev->pt.y, prev_notes);
505
code = gx_path_add_line_notes(ppath,
506
prev->pt.x, prev->pt.y, prev_notes);
509
/* Skip the closing line. */
510
code = gx_path_add_point(ppath, prev->pt.x,
513
default: /* not possible */
514
return_error(gs_error_Fatal);
517
return code; /* only reached if code < 0 */
452
const segment *prev = psub->last;
454
segment_notes notes =
455
(prev == (const segment *)psub ? sn_none :
457
segment_notes prev_notes;
460
if (!psub->is_closed) {
461
code = gx_path_add_line(ppath, prev->pt.x, prev->pt.y);
466
* The do ... while structure of this loop is artificial,
467
* designed solely to keep compilers from complaining about
468
* 'statement not reached' or 'end-of-loop code not reached'.
469
* The normal exit from this loop is the goto statement in
470
* the s_start arm of the switch.
477
prev_notes = (prev_notes & sn_not_first) |
478
(notes & ~sn_not_first);
479
switch (pseg->type) {
481
/* Finished subpath */
482
if (psub->is_closed) {
484
gx_path_close_subpath_notes(ppath, prev_notes);
489
psub = (const subpath *)psub->prev;
490
} while (psub && psub->type != s_start);
494
const curve_segment *pc =
495
(const curve_segment *)pseg;
497
code = gx_path_add_curve_notes(ppath,
500
prev->pt.x, prev->pt.y, prev_notes);
504
code = gx_path_add_line_notes(ppath,
505
prev->pt.x, prev->pt.y, prev_notes);
508
/* Skip the closing line. */
509
code = gx_path_add_point(ppath, prev->pt.x,
512
default: /* not possible */
513
return_error(gs_error_Fatal);
516
return code; /* only reached if code < 0 */
519
518
#undef sn_not_end
569
568
const segment *pseg = penum->pseg;
571
570
if (pseg == 0) { /* We've enumerated all the segments, but there might be */
572
/* a trailing moveto. */
573
const gx_path *ppath = penum->path;
571
/* a trailing moveto. */
572
const gx_path *ppath = penum->path;
575
if (path_last_is_moveto(ppath) && !penum->moveto_done) { /* Handle a trailing moveto */
576
penum->moveto_done = true;
577
penum->notes = sn_none;
578
ppts[0] = ppath->position;
574
if (path_last_is_moveto(ppath) && !penum->moveto_done) { /* Handle a trailing moveto */
575
penum->moveto_done = true;
576
penum->notes = sn_none;
577
ppts[0] = ppath->position;
583
582
penum->pseg = pseg->next;
584
583
penum->notes = pseg->notes;
585
584
switch (pseg->type) {
594
return gs_pe_closepath;
593
return gs_pe_closepath;
596
595
#define pcseg ((const curve_segment *)pseg)
600
return gs_pe_curveto;
599
return gs_pe_curveto;
603
lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type);
604
return_error(gs_error_Fatal);
602
lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type);
603
return_error(gs_error_Fatal);
622
621
const segment *pseg = penum->pseg;
625
if ((pseg = pseg->prev) == 0)
624
if ((pseg = pseg->prev) == 0)
630
629
/* We're at the end of the path. Check to see whether */
631
630
/* we need to back up over a trailing moveto. */
633
const gx_path *ppath = penum->path;
635
if (path_last_is_moveto(ppath) && penum->moveto_done) { /* Back up over the trailing moveto. */
636
penum->moveto_done = false;
639
const subpath *psub = ppath->current_subpath;
641
if (psub == 0) /* empty path */
643
/* Back up to the last segment of the last subpath. */
644
penum->pseg = psub->last;
632
const gx_path *ppath = penum->path;
634
if (path_last_is_moveto(ppath) && penum->moveto_done) { /* Back up over the trailing moveto. */
635
penum->moveto_done = false;
638
const subpath *psub = ppath->current_subpath;
640
if (psub == 0) /* empty path */
642
/* Back up to the last segment of the last subpath. */
643
penum->pseg = psub->last;