1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 22:58:07 +02:00

Merge pull request #18825 from agrahn/rbgroups

implementing optional content radiobutton groups
This commit is contained in:
Jonas Jenwald 2024-10-15 13:11:19 +02:00 committed by GitHub
commit 424f81c4db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 78 additions and 15 deletions

View file

@ -486,17 +486,17 @@ class Catalog {
return shadow(this, "optionalContentConfig", null);
}
const groups = [];
const groupRefs = new RefSet();
const groupRefCache = new RefSetCache();
// Ensure all the optional content groups are valid.
for (const groupRef of groupsData) {
if (!(groupRef instanceof Ref) || groupRefs.has(groupRef)) {
if (!(groupRef instanceof Ref) || groupRefCache.has(groupRef)) {
continue;
}
groupRefs.put(groupRef);
groups.push(this.#readOptionalContentGroup(groupRef));
const group = this.#readOptionalContentGroup(groupRef);
groups.push(group);
groupRefCache.put(groupRef, group);
}
config = this.#readOptionalContentConfig(defaultConfig, groupRefs);
config = this.#readOptionalContentConfig(defaultConfig, groupRefCache);
config.groups = groups;
} catch (ex) {
if (ex instanceof MissingDataException) {
@ -517,6 +517,7 @@ class Catalog {
print: null,
view: null,
},
rbGroups: [],
};
const name = group.get("Name");
@ -565,7 +566,7 @@ class Catalog {
return obj;
}
#readOptionalContentConfig(config, contentGroupRefs) {
#readOptionalContentConfig(config, groupRefCache) {
function parseOnOff(refs) {
const onParsed = [];
if (Array.isArray(refs)) {
@ -573,7 +574,7 @@ class Catalog {
if (!(value instanceof Ref)) {
continue;
}
if (contentGroupRefs.has(value)) {
if (groupRefCache.has(value)) {
onParsed.push(value.toString());
}
}
@ -588,7 +589,7 @@ class Catalog {
const order = [];
for (const value of refs) {
if (value instanceof Ref && contentGroupRefs.has(value)) {
if (value instanceof Ref && groupRefCache.has(value)) {
parsedOrderRefs.put(value); // Handle "hidden" groups, see below.
order.push(value.toString());
@ -605,7 +606,7 @@ class Catalog {
return order;
}
const hiddenGroups = [];
for (const groupRef of contentGroupRefs) {
for (const [groupRef] of groupRefCache.items()) {
if (parsedOrderRefs.has(groupRef)) {
continue;
}
@ -638,10 +639,39 @@ class Catalog {
return { name: stringToPDFString(nestedName), order: nestedOrder };
}
function parseRBGroups(rbGroups) {
if (!Array.isArray(rbGroups)) {
return;
}
for (const value of rbGroups) {
const rbGroup = xref.fetchIfRef(value);
if (!Array.isArray(rbGroup) || !rbGroup.length) {
continue;
}
const parsedRbGroup = new Set();
for (const ref of rbGroup) {
if (
ref instanceof Ref &&
groupRefCache.has(ref) &&
!parsedRbGroup.has(ref.toString())
) {
parsedRbGroup.add(ref.toString());
// Keep a record of which RB groups the current OCG belongs to.
groupRefCache.get(ref).rbGroups.push(parsedRbGroup);
}
}
}
}
const xref = this.xref,
parsedOrderRefs = new RefSet(),
MAX_NESTED_LEVELS = 10;
parseRBGroups(config.get("RBGroups"));
return {
name:
typeof config.get("Name") === "string"

View file

@ -33,13 +33,14 @@ class OptionalContentGroup {
#visible = true;
constructor(renderingIntent, { name, intent, usage }) {
constructor(renderingIntent, { name, intent, usage, rbGroups }) {
this.#isDisplay = !!(renderingIntent & RenderingIntentFlag.DISPLAY);
this.#isPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
this.name = name;
this.intent = intent;
this.usage = usage;
this.rbGroups = rbGroups;
}
/**
@ -229,12 +230,26 @@ class OptionalContentConfig {
return true;
}
setVisibility(id, visible = true) {
setVisibility(id, visible = true, preserveRB = true) {
const group = this.#groups.get(id);
if (!group) {
warn(`Optional content group not found: ${id}`);
return;
}
// If the visibility is about to be set to `true` and the group belongs to
// any radiobutton groups, hide all other OCGs in these radiobutton groups,
// provided that radiobutton state relationships are to be preserved.
if (preserveRB && visible && group.rbGroups.length) {
for (const rbGroup of group.rbGroups) {
for (const otherId of rbGroup) {
if (otherId !== id) {
this.#groups.get(otherId)?._setVisible(INTERNAL, false, true);
}
}
}
}
group._setVisible(INTERNAL, !!visible, /* userSet = */ true);
this.#cachedGetHash = null;
@ -258,13 +273,13 @@ class OptionalContentConfig {
}
switch (operator) {
case "ON":
group._setVisible(INTERNAL, true);
this.setVisibility(elem, true, preserveRB);
break;
case "OFF":
group._setVisible(INTERNAL, false);
this.setVisibility(elem, false, preserveRB);
break;
case "Toggle":
group._setVisible(INTERNAL, !group.visible);
this.setVisibility(elem, !group.visible, preserveRB);
break;
}
}

View file

@ -589,6 +589,7 @@
!issue15690.pdf
!bug1802888.pdf
!issue15759.pdf
!issue18823.pdf
!issue15753.pdf
!issue15789.pdf
!fields_order.pdf

BIN
test/pdfs/issue18823.pdf Normal file

Binary file not shown.

View file

@ -6875,6 +6875,23 @@
"7R": false
}
},
{
"id": "issue18823-default",
"file": "pdfs/issue18823.pdf",
"md5": "f5246c476516c96df106ced0c5839da3",
"rounds": 1,
"type": "eq"
},
{
"id": "issue18823-group-three",
"file": "pdfs/issue18823.pdf",
"md5": "f5246c476516c96df106ced0c5839da3",
"rounds": 1,
"type": "eq",
"optionalContent": {
"15R": true
}
},
{
"id": "issue2829",
"file": "pdfs/issue2829.pdf",