summaryrefslogtreecommitdiff
path: root/pdf
diff options
context:
space:
mode:
authorKen Sharp <ken.sharp@artifex.com>2023-02-08 17:18:30 +0000
committerRobin Watts <Robin.Watts@artifex.com>2023-02-09 09:59:41 +0000
commit0b1950025dc8bead227a764717c016dbdf27f2ce (patch)
tree8c56df7bc04c4270a766c3be46ba67555571b9d7 /pdf
parent83fdfdac1b730c3183eadf04f4e705e34078e4e5 (diff)
downloadghostpdl-0b1950025dc8bead227a764717c016dbdf27f2ce.tar.gz
GhostPDF - Fix visibility of some OCMDs
Bug #706399 "Optional content not drawn when OCMD has empty OCGs" The file uses the BDC operator and the named optional content references an Optional Content Management Dictionary rather than an Optional Content Group. The OCMD has an OCGs member whose value is an empty array. Because it also has no 'P' entry we were defaulting to the 'AnyOn' value. Then we checked each of the (non-existent) OCGs to see if any are 'on'. Since none are, we determined the visibility to be 'off'. However, according to the PDF 1.7 specification, p366, table 4.49, the OCGs entry, if the OCGs are empty (or not present) then the OCMD should 'have no effect'. Its not obvious what that means, exactly, so I've chosen to interpret it as 'should use the OCProperties->D->BaseState as the visibility state'. The BaseState is optional and so (as in this case) may not be present in which case we use the default value of 'on'.
Diffstat (limited to 'pdf')
-rw-r--r--pdf/pdf_optcontent.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/pdf/pdf_optcontent.c b/pdf/pdf_optcontent.c
index 022b1f553..f33617fe4 100644
--- a/pdf/pdf_optcontent.c
+++ b/pdf/pdf_optcontent.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019-2022 Artifex Software, Inc.
+/* Copyright (C) 2019-2023 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -142,10 +142,35 @@ typedef enum {
P_AnyOff
} ocmd_p_type;
+static bool pdfi_oc_default_visibility(pdf_context *ctx)
+{
+ int code;
+ pdf_dict *D_dict = NULL;
+ pdf_name *B = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, ctx->OCProperties, "D", PDF_DICT, (pdf_obj **)&D_dict);
+ if (code < 0 || D_dict == NULL)
+ return true;
+
+ code = pdfi_dict_knownget_type(ctx, D_dict, "BaseState", PDF_NAME, (pdf_obj **)&B);
+ (void)pdfi_countdown(D_dict);
+ D_dict = NULL;
+ if (code < 0 || B == NULL)
+ return true;
+
+ if (pdfi_name_is(B, "OFF")) {
+ (void)pdfi_countdown(B);
+ return false;
+ }
+
+ (void)pdfi_countdown(B);
+ return true;
+}
+
static bool
pdfi_oc_check_OCMD_array(pdf_context *ctx, pdf_array *array, ocmd_p_type type)
{
- bool is_visible;
+ bool is_visible, hit = false;
uint64_t i;
int code;
pdf_obj *val = NULL;
@@ -174,6 +199,7 @@ pdfi_oc_check_OCMD_array(pdf_context *ctx, pdf_array *array, ocmd_p_type type)
continue;
}
+ hit = true;
vis = pdfi_get_default_OCG_val(ctx, (pdf_dict *)val);
switch (type) {
case P_AnyOn:
@@ -209,7 +235,17 @@ pdfi_oc_check_OCMD_array(pdf_context *ctx, pdf_array *array, ocmd_p_type type)
val = NULL;
}
- cleanup:
+ /* If the array was empty, or contained only null or deleted entries, then it has no effect
+ * PDF Reference 1.7 p366, table 4.49, OCGs entry. I'm interpreting this to mean that we should use
+ * the OCProperties 'D' dictionary, set the visibility state to the BaseState. Since this is an OCMD
+ * I'm assuming that the ON and OFF arrays (which apply to Optional Content Groups) shouold not be
+ * consulted. We need to cater for the fact that BaseState is optional (but default is ON). D is
+ * specified as 'Required' but it seems best not to take any chances on that!
+ */
+ if (!hit)
+ is_visible = pdfi_oc_default_visibility(ctx);
+
+cleanup:
pdfi_countdown(val);
return is_visible;
}
@@ -242,6 +278,7 @@ pdfi_oc_check_OCMD(pdf_context *ctx, pdf_dict *ocdict)
} else if (pdfi_type_of(obj) == PDF_DICT) {
OCGs_dict = (pdf_dict *)obj;
} else {
+ is_visible = pdfi_oc_default_visibility(ctx);
goto cleanup;
}