diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2023-02-08 17:18:30 +0000 |
---|---|---|
committer | Robin Watts <Robin.Watts@artifex.com> | 2023-02-09 09:59:41 +0000 |
commit | 0b1950025dc8bead227a764717c016dbdf27f2ce (patch) | |
tree | 8c56df7bc04c4270a766c3be46ba67555571b9d7 /pdf | |
parent | 83fdfdac1b730c3183eadf04f4e705e34078e4e5 (diff) | |
download | ghostpdl-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.c | 43 |
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; } |