summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/pdf_path.c')
-rw-r--r--pdf/pdf_path.c458
1 files changed, 262 insertions, 196 deletions
diff --git a/pdf/pdf_path.c b/pdf/pdf_path.c
index a9724def..56a59b07 100644
--- a/pdf/pdf_path.c
+++ b/pdf/pdf_path.c
@@ -26,88 +26,227 @@
#include "gspath.h" /* For gs_moveto() and friends */
#include "gspaint.h" /* For gs_fill() and friends */
-int pdfi_moveto (pdf_context *ctx)
+typedef enum path_segment_e {
+ pdfi_moveto_seg,
+ pdfi_lineto_seg,
+ pdfi_curveto_seg,
+ pdfi_re_seg,
+ pdfi_v_curveto_seg,
+ pdfi_y_curveto_seg,
+ pdfi_closepath_seg
+} pdfi_path_segment;
+
+static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts)
{
- pdf_num *n1, *n2;
- int code;
- double x, y;
+ int size = 0;
+
+ switch (segment)
+ {
+ case pdfi_moveto_seg:
+ case pdfi_lineto_seg:
+ size = 2;
+ break;
+ case pdfi_re_seg:
+ case pdfi_v_curveto_seg:
+ case pdfi_y_curveto_seg:
+ size = 4;
+ break;
+ case pdfi_curveto_seg:
+ size = 6;
+ break;
+ case pdfi_closepath_seg:
+ break;
+ default:
+ return_error(gs_error_undefined);
+ break;
+ }
+ if (ctx->PathSegments == NULL) {
+ ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment");
+ if (ctx->PathSegments == NULL)
+ return_error(gs_error_VMerror);
+ ctx->PathSegmentsCurrent = ctx->PathSegments;
+ ctx->PathSegmentsTop = ctx->PathSegments + 1024;
+ }
+ if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) {
+ char *new_accumulator = NULL;
+ uint64_t old_size;
+
+ old_size = ctx->PathSegmentsCurrent - ctx->PathSegments;
+ new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment");
+ if (new_accumulator == NULL)
+ return_error(gs_error_VMerror);
+ memcpy(new_accumulator, ctx->PathSegments, old_size);
+ ctx->PathSegmentsCurrent = new_accumulator + old_size;
+ gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment");
+ ctx->PathSegments = new_accumulator;
+ ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024;
+ }
- if (ctx->text.BlockDepth != 0)
- pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
+ if (ctx->PathPts == NULL) {
+ ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment");
+ if (ctx->PathPts == NULL)
+ return_error(gs_error_VMerror);
+ ctx->PathPtsCurrent = ctx->PathPts;
+ ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double));
+ }
+ if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) {
+ double *new_accumulator = NULL;
+ uint64_t old_size;
+
+ old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts;
+ new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment");
+ if (new_accumulator == NULL)
+ return_error(gs_error_VMerror);
+ memcpy(new_accumulator, ctx->PathPts, old_size);
+ ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double));
+ gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment");
+ ctx->PathPts = new_accumulator;
+ ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double));
+ }
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
+ *(ctx->PathSegmentsCurrent++) = (char)segment;
+ switch (segment)
+ {
+ case pdfi_moveto_seg:
+ case pdfi_lineto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double));
+ ctx->PathPtsCurrent += 2;
+ break;
+ case pdfi_re_seg:
+ case pdfi_v_curveto_seg:
+ case pdfi_y_curveto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double));
+ ctx->PathPtsCurrent += 4;
+ break;
+ case pdfi_curveto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double));
+ ctx->PathPtsCurrent += 6;
+ break;
+ case pdfi_closepath_seg:
+ break;
}
+ return 0;
+}
- n1 = (pdf_num *)ctx->stack_top[-1];
- n2 = (pdf_num *)ctx->stack_top[-2];
- if (n1->type == PDF_INT){
- y = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- y = n1->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
+static int ApplyStoredPath(pdf_context *ctx)
+{
+ int code = 0;
+ char *op = NULL;
+ double *dpts = NULL;
+
+ if (ctx->PathSegments == NULL)
+ return 0;
+
+ if (ctx->PathPts == NULL) {
+ code = gs_note_error(gs_error_unknownerror);
+ goto error;
+ }
+
+ if (ctx->pgs->current_point_valid) {
+ code = gs_newpath(ctx->pgs);
+ if (code < 0)
+ goto error;
}
- if (n2->type == PDF_INT){
- x = (double)n2->value.i;
- } else{
- if (n2->type == PDF_REAL) {
- x = n2->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
+
+ op = ctx->PathSegments;
+ dpts = ctx->PathPts;
+
+ while (op < ctx->PathSegmentsCurrent) {
+ if (dpts > ctx->PathPtsCurrent) {
+ code = gs_note_error(gs_error_unknownerror);
+ goto error;
}
+
+ switch(*op++) {
+ case pdfi_moveto_seg:
+ code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
+ dpts+= 2;
+ break;
+ case pdfi_lineto_seg:
+ code = gs_lineto(ctx->pgs, dpts[0], dpts[1]);
+ dpts+= 2;
+ break;
+ case pdfi_re_seg:
+ code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, dpts[2], 0);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, 0, dpts[3]);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, -dpts[2], 0);
+ if (code >= 0)
+ code = gs_closepath(ctx->pgs);
+ }
+ }
+ }
+ dpts+= 4;
+ break;
+ case pdfi_v_curveto_seg:
+ {
+ gs_point pt;
+
+ code = gs_currentpoint(ctx->pgs, &pt);
+ if (code >= 0) {
+ code = gs_curveto(ctx->pgs, pt.x, pt.y, dpts[0], dpts[1], dpts[2], dpts[3]);
+ dpts+= 4;
+ }
+ }
+ break;
+ case pdfi_y_curveto_seg:
+ code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]);
+ dpts+= 4;
+ break;
+ case pdfi_curveto_seg:
+ code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]);
+ dpts+= 6;
+ break;
+ case pdfi_closepath_seg:
+ code = gs_closepath(ctx->pgs);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if (code < 0)
+ break;
}
- code = gs_moveto(ctx->pgs, x, y);
- pdfi_pop(ctx, 2);
+error:
+ gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
+ ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
+ gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
+ ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
return code;
}
+int pdfi_moveto (pdf_context *ctx)
+{
+ int code;
+ double xy[2];
+
+ if (ctx->text.BlockDepth != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
+
+ code = pdfi_destack_reals(ctx, xy, 2);
+ if (code < 0)
+ return code;
+
+ return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy);
+}
+
int pdfi_lineto (pdf_context *ctx)
{
- pdf_num *n1, *n2;
int code;
- double x, y;
+ double xy[2];
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL);
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- n1 = (pdf_num *)ctx->stack_top[-1];
- n2 = (pdf_num *)ctx->stack_top[-2];
- if (n1->type == PDF_INT){
- y = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- y = n1->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
- }
- if (n2->type == PDF_INT){
- x = (double)n2->value.i;
- } else{
- if (n2->type == PDF_REAL) {
- x = n2->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
- }
+ code = pdfi_destack_reals(ctx, xy, 2);
+ if (code < 0)
+ return code;
- code = gs_lineto(ctx->pgs, x, y);
- pdfi_pop(ctx, 2);
- return code;
+ return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy);
}
static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
@@ -121,6 +260,10 @@ static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill);
if (code == 0) {
/* If we don't gsave/grestore round the fill, then the file
@@ -171,8 +314,9 @@ int pdfi_stroke(pdf_context *ctx)
if (pdfi_oc_is_off(ctx))
goto exit;
-/* code = pdfi_gsave(ctx);
- if (code < 0) goto exit;*/
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
gs_swapcolors_quick(ctx->pgs);
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke);
@@ -190,9 +334,6 @@ int pdfi_stroke(pdf_context *ctx)
}
gs_swapcolors_quick(ctx->pgs);
-/* code1 = pdfi_grestore(ctx);
- if (code == 0) code = code1;*/
-
exit:
code1 = pdfi_newpath(ctx);
if (code == 0) code = code1;
@@ -207,127 +348,64 @@ int pdfi_closepath_stroke(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL);
- code = gs_closepath(ctx->pgs);
- if (code == 0)
- code = pdfi_stroke(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_stroke(ctx);
}
int pdfi_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[6];
- if (pdfi_count_stack(ctx) < 6) {
- pdfi_clearstack(ctx);
- pdfi_set_error(ctx, 0, NULL, E_PDF_STACKUNDERFLOWERROR, "pdfi_curveto", NULL);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 6;i++){
- num = (pdf_num *)ctx->stack_top[i - 6];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 6);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 6);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL);
- code = gs_curveto(ctx->pgs, Values[0], Values[1], Values[2], Values[3], Values[4], Values[5]);
- pdfi_pop(ctx, 6);
- return code;
+ return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values);
}
int pdfi_v_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- gs_point pt;
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL);
- code = gs_currentpoint(ctx->pgs, &pt);
- if (code < 0) {
- pdfi_pop(ctx, 4);
- return code;
- }
-
- code = gs_curveto(ctx->pgs, pt.x, pt.y, Values[0], Values[1], Values[2], Values[3]);
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values);
}
int pdfi_y_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL);
- code = gs_curveto(ctx->pgs, Values[0], Values[1], Values[2], Values[3], Values[2], Values[3]);
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values);
}
int pdfi_closepath(pdf_context *ctx)
{
- int code = gs_closepath(ctx->pgs);
-
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL);
- return code;
+ return StorePathSegment(ctx, pdfi_closepath_seg, NULL);
}
int pdfi_newpath(pdf_context *ctx)
@@ -335,8 +413,13 @@ int pdfi_newpath(pdf_context *ctx)
int code = 0, code1;
/* This code is to deal with the wacky W and W* operators */
- if (ctx->pgs->current_point_valid) {
- if (ctx->clip_active) {
+ if (ctx->clip_active) {
+ if (ctx->PathSegments != NULL) {
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+ }
+ if (ctx->pgs->current_point_valid) {
if (ctx->do_eoclip)
code = gs_eoclip(ctx->pgs);
else
@@ -345,6 +428,13 @@ int pdfi_newpath(pdf_context *ctx)
}
ctx->clip_active = false;
+ if (ctx->PathSegments != NULL){
+ gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
+ ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
+ gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
+ ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
+ }
+
code1 = gs_newpath(ctx->pgs);
if (code == 0) code = code1;
@@ -361,10 +451,11 @@ int pdfi_b(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL);
- code = gs_closepath(ctx->pgs);
- if (code >= 0)
- code = pdfi_B(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_B(ctx);
}
int pdfi_b_star(pdf_context *ctx)
@@ -374,10 +465,11 @@ int pdfi_b_star(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL);
- code = gs_closepath(ctx->pgs);
- if (code >= 0)
- code = pdfi_B_star(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_B_star(ctx);
}
/* common code for B and B* */
@@ -392,6 +484,10 @@ static int pdfi_B_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke);
if (code == 0) {
code = pdfi_gsave(ctx);
@@ -448,45 +544,15 @@ int pdfi_eoclip(pdf_context *ctx)
int pdfi_rectpath(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL);
- code = gs_moveto(ctx->pgs, Values[0], Values[1]);
- if (code == 0) {
- code = gs_rlineto(ctx->pgs, Values[2], 0);
- if (code == 0){
- code = gs_rlineto(ctx->pgs, 0, Values[3]);
- if (code == 0) {
- code = gs_rlineto(ctx->pgs, -Values[2], 0);
- if (code == 0){
- code = gs_closepath(ctx->pgs);
- }
- }
- }
- }
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values);
}