[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2622-g6a2c040

[email protected] (Nancy Durgin) Wed, 27 Nov 2019 20:51:20 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, pdfi has been updated
       via  6a2c04019be27f199ba107fba125bf04bf8dd1c6 (commit)
       via  ffe4e1104dcf1579779364ae71bd2cd8a137f3d9 (commit)
      from  20de60fb65962ca37cb8d9e9fe45b80a18f8405f (commit)

----------------------------------------------------------------------
commit 6a2c04019be27f199ba107fba125bf04bf8dd1c6
Author: Nancy Durgin <[email protected]>
Date:   Thu Nov 21 15:02:43 2019 -0800

    Code to support Annotations
    
    Some refactoring and added some variables to context.
    
    Working on "/Link".
    
    A bunch of stuff implemented.  Renders simple border, but many things
    not implemented yet.
    
    Fixes fts_02_0203.pdf

diff --git a/pdf/ghostpdf.h b/pdf/ghostpdf.h
index 65d99fc..863955b 100644
--- a/pdf/ghostpdf.h
+++ b/pdf/ghostpdf.h
@@ -200,6 +200,8 @@ typedef struct pdf_context_s
     bool printed;
     bool showacroform;
     bool showannots;
+    bool dopdfmarks;
+    bool preserveannots;
     bool nouserunit;
     bool renderttnotdef;
     bool pdfinfo;
@@ -293,6 +295,12 @@ typedef struct pdf_context_s
     /* Does this page need overprint support? */
     bool page_needs_OP;
 
+    /* Does current output device handle pdfmark */
+    bool writepdfmarks;
+
+    /* Should annotations be preserved or marked for current output device? */
+    bool annotations_preserved;
+
     double PageSize[4];
     double UserUnit;
 
diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 42698c0..3438140 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.c
@@ -29,19 +29,450 @@
 #include "pdf_misc.h"
 #include "pdf_optcontent.h"
 #include "pdf_annot.h"
+#include "pdf_colour.h"
+#include "gspath2.h"
+
+typedef bool (*annot_func)(pdf_context *ctx, pdf_dict *annot, bool *render_done);
+
+typedef struct {
+    const char *subtype;
+    annot_func func;
+} annot_dispatch_t;
+
+
+static int pdfi_annot_start_transparency(pdf_context *ctx, pdf_dict *annot)
+{
+    int code;
+
+    if (!ctx->page_has_transparency)
+        return 0;
+
+    /* TODO: ps code does something with /BM which is apparently the Blend Mode,
+     * but I am not sure that the value is actually used properly.  Look into it.
+     * (see pdf_draw.ps/startannottransparency)
+     */
+    code = gs_clippath(ctx->pgs);
+    if (code < 0)
+        return code;
+    code = pdfi_trans_begin_simple_group(ctx, false, false, false);
+    (void)gs_newpath(ctx->pgs);
+    return code;
+}
+
+static int pdfi_annot_end_transparency(pdf_context *ctx, pdf_dict *annot)
+{
+    if (!ctx->page_has_transparency)
+        return 0;
+
+    return pdfi_trans_end_simple_group(ctx);
+}
+
+/* See pdf_draw.ps/calc_annot_scale */
+static int pdfi_annot_calcscale(pdf_context *ctx, pdf_dict *annot, double *xscale, double *yscale)
+{
+    /* TODO: Implement this */
+
+    *xscale = 1.0;
+    *yscale = 1.0;
+    return 0;
+}
+
+/* See pdf_draw.ps/drawwidget */
+static int pdfi_annot_draw_widget(pdf_context *ctx, pdf_dict *annot, double xscale, double yscale)
+{
+    /* TODO: Implement this */
+
+    return 0;
+}
+
+static int pdfi_annot_setcolor(pdf_context *ctx, pdf_dict *annot, bool *drawit)
+{
+    int code = 0;
+    pdf_array *C = NULL;
+
+    *drawit = true;
+
+    code = pdfi_dict_knownget_type(ctx, annot, "C", PDF_ARRAY, (pdf_obj **)&C);
+    if (code < 0) goto exit;
+
+    if (code == 0) {
+        code = pdfi_gs_setgray(ctx, 0);
+    } else {
+        if (pdfi_array_size(C) == 0) {
+            code = 0;
+            *drawit = false;
+        } else {
+            code = pdfi_setcolor_from_array(ctx, C);
+        }
+    }
+
+ exit:
+    if (code < 0)
+        *drawit = false;
+    pdfi_countdown(C);
+    return code;
+}
+
+static int pdfi_annot_strokeborder(pdf_context *ctx, pdf_dict *annot, double width, pdf_array *dash)
+{
+    int code = 0;
+    bool drawit;
+    gs_rect rect;
+    pdf_array *Rect = NULL;
+
+    if (width <= 0)
+        return 0;
+
+    code = pdfi_gsave(ctx);
+
+    code = pdfi_annot_setcolor(ctx, annot, &drawit);
+    if (code < 0) goto exit;
+    if (!drawit) goto exit;
+
+    code = pdfi_setdash_impl(ctx, dash, 0);
+    if (code < 0) goto exit;
+    code = gs_setlinewidth(ctx->pgs, width);
+    if (code < 0) goto exit;
+
+    code = pdfi_dict_knownget_type(ctx, annot, "Rect", PDF_ARRAY, (pdf_obj **)&Rect);
+    if (code < 0) goto exit;
+
+    code = pdfi_array_to_gs_rect(ctx, Rect, &rect);
+    if (code < 0) goto exit;
+
+    pdfi_normalize_rect(ctx, &rect);
+
+    /* Stroke the rectangle */
+    /* Adjust rectangle by the width */
+    rect.p.x += width/2;
+    rect.p.y += width/2;
+    rect.q.x -= width/2;
+    rect.q.y -= width/2;
+    code = gs_rectstroke(ctx->pgs, &rect, 1, NULL);
+
+ exit:
+    (void)pdfi_grestore(ctx);
+    pdfi_countdown(Rect);
+    return code;
+}
+
+/* Draw border from a Border array
+ * Note: Border can be null
+ */
+static int pdfi_annot_draw_Border(pdf_context *ctx, pdf_dict *annot, pdf_array *Border)
+{
+    pdf_array *dash = NULL;
+    int code = 0;
+    uint64_t size = 0;
+    double width = 0;
+
+    if (Border)
+        size = pdfi_array_size(Border);
+    if (Border &&  size < 3) {
+        /* TODO: set warning flag */
+        dbgmprintf(ctx->memory, "WARNING: Annotation Border array invalid\n");
+        goto exit;
+    }
+    if (!Border) {
+        code = pdfi_array_alloc(ctx, 0, &dash);
+        if (code < 0) goto exit;
+        width = 1;
+    } else {
+        if (size > 3) {
+            code = pdfi_array_get_type(ctx, Border, 3, PDF_ARRAY, (pdf_obj **)&dash);
+            if (code < 0) {
+                /* TODO: set warning flag */
+                dbgmprintf(ctx->memory, "WARNING: Annotation Border Dash array invalid\n");
+                code = pdfi_array_alloc(ctx, 0, &dash);
+                if (code < 0) goto exit;
+            }
+        } else {
+            code = pdfi_array_alloc(ctx, 0, &dash);
+            if (code < 0) goto exit;
+        }
+        code = pdfi_array_get_number(ctx, Border, 2, &width);
+        if (code < 0) goto exit;
+    }
+
+    /* At this point we have a dash array (which could be length 0) and a width */
+    code = pdfi_annot_strokeborder(ctx, annot, width, dash);
+
+ exit:
+    pdfi_countdown(dash);
+    return code;
+}
+
+/* Draw border from a BS dict */
+static int pdfi_annot_draw_BS(pdf_context *ctx, pdf_dict *annot, pdf_dict *BS)
+{
+    double W;
+    int code = 0;
+    pdf_name *S = NULL;
+    pdf_array *dash = NULL;
+
+    /* Get the width */
+    code = pdfi_dict_knownget_number(ctx, BS, "W", &W);
+    if (code < 0) goto exit;
+    if (code == 0)
+        W = 1; /* Default */
+
+    /* TODO: Some junk about scaling to UserUnit */
+    /* ... */
+
+    /* Lookup border style */
+    code = pdfi_dict_knownget_type(ctx, BS, "S", PDF_NAME, (pdf_obj **)&S);
+    if (code < 0) goto exit;
+
+    if (code > 0 && pdfi_name_is(S, "D")) {
+        /* Handle Dash array */
+        code = pdfi_dict_knownget_type(ctx, BS, "D", PDF_ARRAY, (pdf_obj **)&dash);
+        if (code < 0) goto exit;
+
+        /* If there is no Dash array, then create one containing a 3 (the default) */
+        if (code == 0) {
+            code = pdfi_array_alloc(ctx, 1, &dash);
+            if (code < 0) goto exit;
+
+            code = pdfi_array_put_int(ctx, dash, 0, 3);
+            if (code < 0) goto exit;
+        }
+    } else {
+        /* Empty array */
+        code = pdfi_array_alloc(ctx, 0, &dash);
+        if (code < 0) goto exit;
+    }
+
+    /* At this point we have a dash array (which could be length 0) and a width */
+    code = pdfi_annot_strokeborder(ctx, annot, W, dash);
+
+ exit:
+    pdfi_countdown(S);
+    pdfi_countdown(dash);
+    return code;
+}
+
+/* Draw the border
+ * This spec seems to be scattered around.  There might be:
+ *  /Border -- an array of 3-4 elements, where the optional 4th element is a "dash array"
+ *   (default value: [0 0 1])
+ *  /BS -- a Border Style dictionary
+ *  Spec says /Border would be ignored in favor of /BS
+ *
+ */
+static int pdfi_annot_draw_border(pdf_context *ctx, pdf_dict *annot)
+{
+    int code, code1;
+    pdf_dict *BS = NULL;
+    pdf_array *Border = NULL;
+
+    code = pdfi_dict_knownget_type(ctx, annot, "BS", PDF_DICT, (pdf_obj **)&BS);
+    if (code < 0) goto exit;
+    code = pdfi_dict_knownget_type(ctx, annot, "Border", PDF_ARRAY, (pdf_obj **)&Border);
+    if (code < 0) goto exit;
+
+    code = pdfi_gsave(ctx);
+    if (code < 0) goto exit;
+
+    if (BS) {
+        code = pdfi_annot_draw_BS(ctx, annot, BS);
+    } else {
+        /* Note: Border can be null */
+        code = pdfi_annot_draw_Border(ctx, annot, Border);
+    }
+    code1 = pdfi_grestore(ctx);
+    if (code == 0) code = code1;
+
+ exit:
+    pdfi_countdown(BS);
+    pdfi_countdown(Border);
+    return code;
+}
+
+static bool pdfi_annot_draw_Link(pdf_context *ctx, pdf_dict *annot, bool *render_done)
+{
+    int code;
+    int code1;
+    double xscale, yscale;
+
+    dbgmprintf(ctx->memory, "ANNOT: Drawing Link\n");
+
+    code = pdfi_annot_start_transparency(ctx, annot);
+    if (code < 0)
+        return code;
+
+    code = pdfi_annot_draw_border(ctx, annot);
+    if (code < 0) goto exit;
+
+    code = pdfi_annot_calcscale(ctx, annot, &xscale, &yscale);
+    if (code < 0) goto exit;
+
+    if (xscale * yscale > 0.0) {
+        code = pdfi_annot_draw_widget(ctx, annot, xscale, yscale);
+    } else {
+        dbgmprintf(ctx->memory, "ANNOT: Ignoring annotation with scale factor of 0\n");
+    }
+
+ exit:
+    code1 = pdfi_annot_end_transparency(ctx, annot);
+    if (code < 0) code = code1;
+
+    *render_done = true;
+    return code;
+}
+
+static bool pdfi_annot_draw_Ink(pdf_context *ctx, pdf_dict *annot, bool *render_done)
+{
+    return false;
+}
+
+static bool pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, bool *render_done)
+{
+    return false;
+}
+
+annot_dispatch_t annot_dispatch[] = {
+    {"Link", pdfi_annot_draw_Link},
+    {"Ink", pdfi_annot_draw_Ink},
+    { NULL, NULL},
+};
+
+/* Check if annotation is visible
+ * (from ps code:)
+%
+%   The PDF annotation F (flags) integer is bit encoded.
+%   Bit 1 (LSB) Invisible:  1 --> Do not display if no handler.
+%         Note:  We have no handlers but we ignore this bit.
+%   Bit 2 Hidden:  1 --> Do not display.  We will not display if this bit is set.
+%   Bit 3 Print:  1 --> Display if printing.  We will display if this bit set
+%         (and not hidden) and Printed is true
+%   Bit 4 NoZoom:  1 --> Do not zoom annotation even if image is zoomed.
+%   Bit 5 NoRotate:  1 --> Do not rotate annotation even if image is rotated.
+%   Bit 6 NoView:  0 --> Display if this is a 'viewer'.  We will display
+%         if this bit is not set (and not hidden) and Printed is false
+%   Bit 7 Read Only - 1 --> No interaction.  We ignore this bit
+%
+%   AR8 and AR9 print 3D annotations even if Print flag is off. Bug 691486.
+%
+*/
+static bool pdfi_annot_visible(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
+{
+    int code;
+    bool is_3D = false;
+    bool is_visible = true;
+    int64_t F;
+
+    if (pdfi_name_is(subtype, "3D"))
+        is_3D = true;
+
+    code = pdfi_dict_get_int(ctx, annot, "F", &F);
+    if (code < 0)
+        F = 0;
+
+    if ((F & 0x2) != 0) { /* Bit 2 -- Hidden */
+        is_visible = false; /* Hidden */
+        goto exit;
+    }
+
+    if (ctx->printed) {
+        /* Even if Print flag (bit 3) is off, will print if 3D */
+        is_visible = ((F & 0x4) != 0) || is_3D;
+    } else {
+        /* Not NoView (bit 7) */
+        is_visible = (F & 0x80) == 0;
+    }
+
+ exit:
+    return is_visible;
+}
+
+/* Check to see if subtype is on the ShowAnnotTypes list
+ * Defaults to true if there is no list
+ */
+static bool pdfi_annot_check_type(pdf_context *ctx, pdf_name *subtype)
+{
+    /* TODO: Need to implement */
+    return true;
+}
+
+static int pdfi_annot_preserve(pdf_context *ctx, pdf_dict *annot)
+{
+    return 0;
+}
+
+static int pdfi_annot_draw(pdf_context *ctx, pdf_dict *annot)
+{
+    pdf_name *Subtype = NULL;
+    int code;
+    annot_dispatch_t *dispatch_ptr;
+    bool render_done = false;
+
+    code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
+    if (code != 0) {
+        /* TODO: Set warning flag */
+        dbgmprintf(ctx->memory, "WARNING: Ignoring annotation with missing Subtype\n");
+        code = 0;
+        goto exit;
+    }
+
+    /* See if annotation is visible */
+    if (!pdfi_annot_visible(ctx, annot, Subtype))
+        goto exit;
+
+    /* See if we are rendering this type of annotation */
+    if (!pdfi_annot_check_type(ctx, Subtype))
+        goto exit;
+
+    code = pdfi_gsave(ctx);
+    if (code < 0)
+        goto exit;
+
+    /* Draw the annotation */
+    for (dispatch_ptr = annot_dispatch; dispatch_ptr->subtype; dispatch_ptr ++) {
+        if (pdfi_name_is(Subtype, dispatch_ptr->subtype)) {
+            code = dispatch_ptr->func(ctx, annot, &render_done);
+            break;
+        }
+    }
+    if (!render_done)
+        code = pdfi_annot_draw_Widget(ctx, annot, &render_done);
+
+    (void)pdfi_grestore(ctx);
+
+ exit:
+    pdfi_countdown(Subtype);
+    return code;
+}
 
 int pdfi_do_annotations(pdf_context *ctx, pdf_dict *page_dict)
 {
     int code = 0;
     pdf_array *Annots = NULL;
+    pdf_dict *annot = NULL;
+    int i;
 
     if (!ctx->showannots)
         return 0;
 
     code = pdfi_dict_knownget_type(ctx, page_dict, "Annots", PDF_ARRAY, (pdf_obj **)&Annots);
-    if (code == 0)
+    if (code <= 0)
         return code;
 
+    for (i = 0; i < pdfi_array_size(Annots); i++) {
+        code = pdfi_array_get_type(ctx, Annots, i, PDF_DICT, (pdf_obj **)&annot);
+        if (code < 0)
+            continue;
+        if (ctx->preserveannots && ctx->annotations_preserved)
+            code = pdfi_annot_preserve(ctx, annot);
+        else
+            code = pdfi_annot_draw(ctx, annot);
+        if (code < 0)
+            goto exit;
+        pdfi_countdown(annot);
+        annot = NULL;
+    }
+
+ exit:
+    pdfi_countdown(annot);
     pdfi_countdown(Annots);
     return code;
 }
diff --git a/pdf/pdf_colour.c b/pdf/pdf_colour.c
index ba811e9..690c875 100644
--- a/pdf/pdf_colour.c
+++ b/pdf/pdf_colour.c
@@ -298,7 +298,7 @@ int pdfi_ri(pdf_context *ctx)
  * functions to 'wrap' these with code to check for replacement of Patterns.
  * This comment is duplicated in pdf_pattern.c
  */
-static int pdfi_gs_setgray(pdf_context *ctx, double d)
+int pdfi_gs_setgray(pdf_context *ctx, double d)
 {
     /* PDF Reference 1.7 p423, any colour operators in a CharProc, following a d1, should be ignored */
     if (ctx->inside_CharProc && ctx->CharProc_is_d1)
@@ -565,6 +565,47 @@ int pdfi_setcmykfill(pdf_context *ctx)
         return 0;
 }
 
+/* Do a setcolor using values in an array
+ * Will do gray, rgb, cmyk for sizes 1,3,4
+ * Anything else is an error
+ */
+int pdfi_setcolor_from_array(pdf_context *ctx, pdf_array *array)
+{
+    int code = 0;
+    uint64_t size;
+    double values[4];
+    int i;
+
+    size = pdfi_array_size(array);
+    if (size != 1 && size != 3 && size != 4) {
+        code = gs_note_error(gs_error_rangecheck);
+        goto exit;
+    }
+
+    for (i=0; i<size; i++) {
+        code = pdfi_array_get_number(ctx, array, i, &values[i]);
+        if (code < 0)
+            goto exit;
+    }
+
+    switch (size) {
+    case 1:
+        code = pdfi_gs_setgray(ctx, values[0]);
+        break;
+    case 3:
+        code = pdfi_gs_setrgbcolor(ctx, values[0], values[1], values[2]);
+        break;
+    case 4:
+        code = pdfi_gs_setcmykcolor(ctx, values[0], values[1], values[2], values[3]);
+        break;
+    default:
+        break;
+    }
+
+ exit:
+    return code;
+}
+
 /* Get colors from top of stack into a client color */
 static int
 pdfi_get_color_from_stack(pdf_context *ctx, gs_client_color *cc, int ncomps)
diff --git a/pdf/pdf_colour.h b/pdf/pdf_colour.h
index ebb0d20..7539121 100644
--- a/pdf/pdf_colour.h
+++ b/pdf/pdf_colour.h
@@ -33,6 +33,9 @@ int pdfi_setfillcolor(pdf_context *ctx);
 int pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, bool is_fill);
 int pdfi_ri(pdf_context *ctx);
 
+int pdfi_setcolor_from_array(pdf_context *ctx, pdf_array *array);
+int pdfi_gs_setgray(pdf_context *ctx, double d);
+
 /* For potential use by other types of object (images etc) */
 int pdfi_setcolorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_dict, pdf_dict *page_dict);
 int pdfi_create_colorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_dict, pdf_dict *page_dict, gs_color_space **ppcs, bool inline_image);
diff --git a/pdf/pdf_device.c b/pdf/pdf_device.c
index 8ac470b..fc41027 100644
--- a/pdf/pdf_device.c
+++ b/pdf/pdf_device.c
@@ -36,6 +36,7 @@ static int pdfi_device_check_param(gx_device *dev, const char *param, gs_c_param
     return 0;
 }
 
+/* Check value of boolean device parameter */
 bool pdfi_device_check_param_bool(gx_device *dev, const char *param)
 {
     int code;
@@ -52,3 +53,35 @@ bool pdfi_device_check_param_bool(gx_device *dev, const char *param)
     gs_c_param_list_release(&list);
     return value;
 }
+
+/* Checks whether a parameter exists for the device */
+bool pdfi_device_check_param_exists(gx_device *dev, const char *param)
+{
+    int code;
+    gs_c_param_list list;
+
+    code = pdfi_device_check_param(dev, param, &list);
+    if (code < 0)
+        return false;
+    gs_c_param_list_release(&list);
+    return true;
+}
+
+/* Config some device-related variables */
+void pdfi_device_set_flags(pdf_context *ctx)
+{
+    bool has_pdfmark;
+    bool has_ForOPDFRead;
+
+    has_pdfmark = pdfi_device_check_param_exists(ctx->pgs->device, "pdfmark");
+    has_ForOPDFRead = pdfi_device_check_param_bool(ctx->pgs->device, "ForOPDFRead");
+
+    /* Cache these so they don't have to constantly be calculated */
+    ctx->writepdfmarks = has_pdfmark || ctx->dopdfmarks;
+    ctx->annotations_preserved = ctx->writepdfmarks && !has_ForOPDFRead;
+
+    dbgmprintf2(ctx->memory, "Device writepdfmarks=%s, annotations_preserved=%s\n",
+                ctx->writepdfmarks ? "TRUE" : "FALSE",
+                ctx->annotations_preserved ? "TRUE" : "FALSE");
+
+}
diff --git a/pdf/pdf_device.h b/pdf/pdf_device.h
index 72187a3..c482738 100644
--- a/pdf/pdf_device.h
+++ b/pdf/pdf_device.h
@@ -17,5 +17,7 @@
 #define PDF_DEVICE
 
 bool pdfi_device_check_param_bool(gx_device *dev, const char *param);
+bool pdfi_device_check_param_exists(gx_device *dev, const char *param);
+void pdfi_device_set_flags(pdf_context *ctx);
 
 #endif
diff --git a/pdf/pdf_gstate.c b/pdf/pdf_gstate.c
index fa91fa7..2dfc239 100644
--- a/pdf/pdf_gstate.c
+++ b/pdf/pdf_gstate.c
@@ -414,7 +414,7 @@ int pdfi_setflat(pdf_context *ctx)
         return 0;
 }
 
-static int setdash_impl(pdf_context *ctx, pdf_array *a, double phase_d)
+int pdfi_setdash_impl(pdf_context *ctx, pdf_array *a, double phase_d)
 {
     float *dash_array;
     double temp;
@@ -481,7 +481,7 @@ int pdfi_setdash(pdf_context *ctx)
             return 0;
     }
 
-    code = setdash_impl(ctx, a, phase_d);
+    code = pdfi_setdash_impl(ctx, a, phase_d);
     pdfi_pop(ctx, 2);
     if(code < 0 && ctx->pdfstoponerror)
         return code;
@@ -598,7 +598,7 @@ static int GS_D(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
         return code;
     }
 
-    code = setdash_impl(ctx, a1, d);
+    code = pdfi_setdash_impl(ctx, a1, d);
     pdfi_countdown(a1);
     pdfi_countdown(a);
     return code;
diff --git a/pdf/pdf_gstate.h b/pdf/pdf_gstate.h
index e2333b4..c610803 100644
--- a/pdf/pdf_gstate.h
+++ b/pdf/pdf_gstate.h
@@ -43,6 +43,7 @@ int pdfi_setflat(pdf_context *ctx);
 int pdfi_setdash(pdf_context *ctx);
 int pdfi_setmiterlimit(pdf_context *ctx);
 int pdfi_setgstate(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict);
+int pdfi_setdash_impl(pdf_context *ctx, pdf_array *a, double phase_d);
 
 int pdfi_free_DefaultQState(pdf_context *ctx);
 int pdfi_set_DefaultQState(pdf_context *ctx, gs_gstate *pgs);
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index 6fea12d..504f57b 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -28,6 +28,7 @@
 #include "pdf_gstate.h"
 #include "pdf_misc.h"
 #include "pdf_optcontent.h"
+#include "pdf_device.h"
 #include "pdf_annot.h"
 
 static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
@@ -149,6 +150,8 @@ static int pdfi_process_one_page(pdf_context *ctx, pdf_dict *page_dict)
     if (code > 0)
         code = code1;
 
+    /* TODO: Handle "ShowAcroForm" goes here */
+
     return code;
 }
 
@@ -424,6 +427,7 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num)
      * This needs to be before transparency device is pushed, if applicable
      */
     pdfi_trans_set_needs_OP(ctx);
+    pdfi_device_set_flags(ctx);
     pdfi_oc_init(ctx);
 
     pdfi_gsave(ctx);
diff --git a/pdf/pdftop.c b/pdf/pdftop.c
index eb56227..ad0ab23 100644
--- a/pdf/pdftop.c
+++ b/pdf/pdftop.c
@@ -408,10 +408,15 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
         ctx->showacroform = boolval;
         return 0;
     }
+    ctx->showannots = true;;
     if (!strncmp(param, "ShowAnnots", 10)) {
         ctx->showannots = boolval;
         return 0;
     }
+    if (!strncmp(param, "PreserveAnnots", 14)) {
+        ctx->preserveannots = boolval;
+        return 0;
+    }
     if (!strncmp(param, "NoUserUnit", 10)) {
         ctx->nouserunit = boolval;
         return 0;
@@ -424,6 +429,10 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
         ctx->pdfinfo = boolval;
         return 0;
     }
+    if (!strncmp(param, "DOPDFMARKS", 10)) {
+        ctx->dopdfmarks = boolval;
+        return 0;
+    }
     return 0;
 }
 

----------------------------------------------------------------------
commit ffe4e1104dcf1579779364ae71bd2cd8a137f3d9
Author: Nancy Durgin <[email protected]>
Date:   Tue Nov 26 14:25:58 2019 -0800

    Change to not propagate Annotation errors
    
    While checking spots, need to ignore errors
    Fixes tests_private/pdf/sumatra/use_after_free_caused_by_pdf_load_obj_stm.pdf

diff --git a/pdf/pdf_check.c b/pdf/pdf_check.c
index 8c9c269..0bf46b8 100644
--- a/pdf/pdf_check.c
+++ b/pdf/pdf_check.c
@@ -837,6 +837,9 @@ static int pdfi_check_Annots_for_transparency(pdf_context *ctx, pdf_array *annot
             pdfi_countdown(annot);
             annot = NULL;
         }
+        if (code < 0 && ctx->pdfstoponerror)
+            goto exit;
+        code = 0;
     }
 exit:
     pdfi_countdown(annot);


Summary of changes:
 pdf/ghostpdf.h   |   8 +
 pdf/pdf_annot.c  | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 pdf/pdf_check.c  |   3 +
 pdf/pdf_colour.c |  43 +++++-
 pdf/pdf_colour.h |   3 +
 pdf/pdf_device.c |  33 +++++
 pdf/pdf_device.h |   2 +
 pdf/pdf_gstate.c |   6 +-
 pdf/pdf_gstate.h |   1 +
 pdf/pdf_page.c   |   4 +
 pdf/pdftop.c     |   9 ++
 11 files changed, 540 insertions(+), 5 deletions(-)