diff options
Diffstat (limited to 'pdf/pdf_path.c')
-rw-r--r-- | pdf/pdf_path.c | 458 |
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); } |