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

[api-minor] Replace various getAll methods with iterators

These `getAll` methods are not used anywhere within the PDF.js code-base, outside of tests, and were mostly added (speculatively) for third-party users.
To still allow access to the same data we instead introduce iterators on these classes, which (slightly) shortens the code and allows us to remove the `objectFromMap` helper function.

A summary of the changes in this patch:
 - Replace the `getAll` methods with iterators in the following classes: `AnnotationStorage`, `Metadata`, and `OptionalContentGroup`.

 - Change, and also re-name, `AnnotationStorage.prototype.setAll` into a test-only method since it's not used elsewhere.

 - Remove the `Metadata.prototype.has` method, since it's only used in tests and can be trivially replaced by calling `Metadata.prototype.get` and checking if the returned value is `null`.
This commit is contained in:
Jonas Jenwald 2025-04-06 17:38:24 +02:00
parent 72feb4c256
commit 2c593b06e4
7 changed files with 53 additions and 92 deletions

View file

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { objectFromMap, shadow, unreachable } from "../shared/util.js"; import { shadow, unreachable } from "../shared/util.js";
import { AnnotationEditor } from "./editor/editor.js"; import { AnnotationEditor } from "./editor/editor.js";
import { MurmurHash3_64 } from "../shared/murmurhash3.js"; import { MurmurHash3_64 } from "../shared/murmurhash3.js";
@ -41,6 +41,17 @@ class AnnotationStorage {
this.onSetModified = null; this.onSetModified = null;
this.onResetModified = null; this.onResetModified = null;
this.onAnnotationEditor = null; this.onAnnotationEditor = null;
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
// For testing purposes.
Object.defineProperty(this, "_setValues", {
value: obj => {
for (const [key, val] of Object.entries(obj)) {
this.setValue(key, val);
}
},
});
}
} }
/** /**
@ -128,22 +139,6 @@ class AnnotationStorage {
return this.#storage.has(key); return this.#storage.has(key);
} }
/**
* @returns {Object | null}
*/
getAll() {
return this.#storage.size > 0 ? objectFromMap(this.#storage) : null;
}
/**
* @param {Object} obj
*/
setAll(obj) {
for (const [key, val] of Object.entries(obj)) {
this.setValue(key, val);
}
}
get size() { get size() {
return this.#storage.size; return this.#storage.size;
} }
@ -278,6 +273,10 @@ class AnnotationStorage {
hash: ids.join(","), hash: ids.join(","),
}); });
} }
[Symbol.iterator]() {
return this.#storage.entries();
}
} }
/** /**

View file

@ -13,15 +13,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { objectFromMap } from "../shared/util.js";
class Metadata { class Metadata {
#metadataMap; #map;
#data; #data;
constructor({ parsedData, rawData }) { constructor({ parsedData, rawData }) {
this.#metadataMap = parsedData; this.#map = parsedData;
this.#data = rawData; this.#data = rawData;
} }
@ -30,15 +28,11 @@ class Metadata {
} }
get(name) { get(name) {
return this.#metadataMap.get(name) ?? null; return this.#map.get(name) ?? null;
} }
getAll() { [Symbol.iterator]() {
return objectFromMap(this.#metadataMap); return this.#map.entries();
}
has(name) {
return this.#metadataMap.has(name);
} }
} }

View file

@ -15,7 +15,6 @@
import { import {
info, info,
objectFromMap,
RenderingIntentFlag, RenderingIntentFlag,
unreachable, unreachable,
warn, warn,
@ -301,10 +300,6 @@ class OptionalContentConfig {
return [...this.#groups.keys()]; return [...this.#groups.keys()];
} }
getGroups() {
return this.#groups.size > 0 ? objectFromMap(this.#groups) : null;
}
getGroup(id) { getGroup(id) {
return this.#groups.get(id) || null; return this.#groups.get(id) || null;
} }
@ -320,6 +315,10 @@ class OptionalContentConfig {
} }
return (this.#cachedGetHash = hash.hexdigest()); return (this.#cachedGetHash = hash.hexdigest());
} }
[Symbol.iterator]() {
return this.#groups.entries();
}
} }
export { OptionalContentConfig }; export { OptionalContentConfig };

View file

@ -578,16 +578,6 @@ function objectSize(obj) {
return Object.keys(obj).length; return Object.keys(obj).length;
} }
// Ensure that the returned Object has a `null` prototype; hence why
// `Object.fromEntries(...)` is not used.
function objectFromMap(map) {
const obj = Object.create(null);
for (const [key, value] of map) {
obj[key] = value;
}
return obj;
}
// Checks the endianness of the platform. // Checks the endianness of the platform.
function isLittleEndian() { function isLittleEndian() {
const buffer8 = new Uint8Array(4); const buffer8 = new Uint8Array(4);
@ -1313,7 +1303,6 @@ export {
LINE_FACTOR, LINE_FACTOR,
MathClamp, MathClamp,
normalizeUnicode, normalizeUnicode,
objectFromMap,
objectSize, objectSize,
OPS, OPS,
PageActionEventType, PageActionEventType,

View file

@ -738,7 +738,7 @@ class Driver {
await page.getAnnotations({ intent: "display" }); await page.getAnnotations({ intent: "display" });
} }
} }
doc.annotationStorage.setAll(task.annotationStorage); doc.annotationStorage._setValues(task.annotationStorage);
const data = await doc.saveDocument(); const data = await doc.saveDocument();
await loadingTask.destroy(); await loadingTask.destroy();
@ -919,7 +919,7 @@ class Driver {
pageColors = null; pageColors = null;
if (task.annotationStorage) { if (task.annotationStorage) {
task.pdfDoc.annotationStorage.setAll(task.annotationStorage); task.pdfDoc.annotationStorage._setValues(task.annotationStorage);
} }
let textLayerCanvas, annotationLayerCanvas, annotationLayerContext; let textLayerCanvas, annotationLayerCanvas, annotationLayerContext;

View file

@ -59,7 +59,7 @@ describe("AnnotationStorage", function () {
it("should set a new value in the annotation storage", function () { it("should set a new value in the annotation storage", function () {
const annotationStorage = new AnnotationStorage(); const annotationStorage = new AnnotationStorage();
annotationStorage.setValue("123A", { value: "an other string" }); annotationStorage.setValue("123A", { value: "an other string" });
const value = annotationStorage.getAll()["123A"].value; const { value } = annotationStorage.getRawValue("123A");
expect(value).toEqual("an other string"); expect(value).toEqual("an other string");
}); });

View file

@ -16,8 +16,6 @@
import { Metadata } from "../../src/display/metadata.js"; import { Metadata } from "../../src/display/metadata.js";
import { MetadataParser } from "../../src/core/metadata_parser.js"; import { MetadataParser } from "../../src/core/metadata_parser.js";
const emptyObj = Object.create(null);
function createMetadata(data) { function createMetadata(data) {
const metadataParser = new MetadataParser(data); const metadataParser = new MetadataParser(data);
return new Metadata(metadataParser.serializable); return new Metadata(metadataParser.serializable);
@ -33,13 +31,10 @@ describe("metadata", function () {
"</rdf:Alt></dc:title></rdf:Description></rdf:RDF></x:xmpmeta>"; "</rdf:Alt></dc:title></rdf:Description></rdf:RDF></x:xmpmeta>";
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual("Foo bar baz"); expect(metadata.get("dc:title")).toEqual("Foo bar baz");
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ "dc:title": "Foo bar baz" }); expect([...metadata]).toEqual([["dc:title", "Foo bar baz"]]);
}); });
it("should repair and handle invalid metadata", function () { it("should repair and handle invalid metadata", function () {
@ -51,13 +46,10 @@ describe("metadata", function () {
"</rdf:Description></rdf:RDF></x:xmpmeta>"; "</rdf:Description></rdf:RDF></x:xmpmeta>";
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual("PDF&"); expect(metadata.get("dc:title")).toEqual("PDF&");
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ "dc:title": "PDF&" }); expect([...metadata]).toEqual([["dc:title", "PDF&"]]);
}); });
it("should repair and handle invalid metadata (bug 1424938)", function () { it("should repair and handle invalid metadata (bug 1424938)", function () {
@ -94,19 +86,16 @@ describe("metadata", function () {
"</x:xmpmeta>"; "</x:xmpmeta>";
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual( expect(metadata.get("dc:title")).toEqual(
"L'Odissee thématique logo Odisséé - décembre 2008.pub" "L'Odissee thématique logo Odisséé - décembre 2008.pub"
); );
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ expect([...metadata].sort()).toEqual([
"dc:creator": ["ODIS"], ["dc:creator", ["ODIS"]],
"dc:title": "L'Odissee thématique logo Odisséé - décembre 2008.pub", ["dc:title", "L'Odissee thématique logo Odisséé - décembre 2008.pub"],
"xap:creatortool": "PDFCreator Version 0.9.6", ["xap:creatortool", "PDFCreator Version 0.9.6"],
}); ]);
}); });
it("should gracefully handle incomplete tags (issue 8884)", function () { it("should gracefully handle incomplete tags (issue 8884)", function () {
@ -137,7 +126,7 @@ describe("metadata", function () {
'<?xpacket end="w"?>'; '<?xpacket end="w"?>';
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.getAll()).toEqual(emptyObj); expect([...metadata]).toEqual([]);
}); });
it('should gracefully handle "junk" before the actual metadata (issue 10395)', function () { it('should gracefully handle "junk" before the actual metadata (issue 10395)', function () {
@ -168,26 +157,23 @@ describe("metadata", function () {
'</rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end="w"?>'; '</rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end="w"?>';
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual(""); expect(metadata.get("dc:title")).toEqual("");
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ expect([...metadata].sort()).toEqual([
"dc:creator": [""], ["dc:creator", [""]],
"dc:description": "", ["dc:description", ""],
"dc:format": "application/pdf", ["dc:format", "application/pdf"],
"dc:subject": [], ["dc:subject", []],
"dc:title": "", ["dc:title", ""],
"pdf:keywords": "", ["pdf:keywords", ""],
"pdf:pdfversion": "1.7", ["pdf:pdfversion", "1.7"],
"pdf:producer": "PDFKit.NET 4.0.102.0", ["pdf:producer", "PDFKit.NET 4.0.102.0"],
"xap:createdate": "2018-12-27T13:50:36-08:00", ["xap:createdate", "2018-12-27T13:50:36-08:00"],
"xap:creatortool": "", ["xap:creatortool", ""],
"xap:metadatadate": "2018-12-27T13:50:38-08:00", ["xap:metadatadate", "2018-12-27T13:50:38-08:00"],
"xap:modifydate": "2018-12-27T13:50:38-08:00", ["xap:modifydate", "2018-12-27T13:50:38-08:00"],
}); ]);
}); });
it('should correctly handle metadata containing "&apos" (issue 10407)', function () { it('should correctly handle metadata containing "&apos" (issue 10407)', function () {
@ -200,13 +186,10 @@ describe("metadata", function () {
"</rdf:Alt></dc:title></rdf:Description></rdf:RDF></x:xmpmeta>"; "</rdf:Alt></dc:title></rdf:Description></rdf:RDF></x:xmpmeta>";
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual("'Foo bar baz'"); expect(metadata.get("dc:title")).toEqual("'Foo bar baz'");
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ "dc:title": "'Foo bar baz'" }); expect([...metadata]).toEqual([["dc:title", "'Foo bar baz'"]]);
}); });
it("should gracefully handle unbalanced end tags (issue 10410)", function () { it("should gracefully handle unbalanced end tags (issue 10410)", function () {
@ -229,7 +212,7 @@ describe("metadata", function () {
'</rdf:RDF></x:xmpmeta><?xpacket end="w"?>'; '</rdf:RDF></x:xmpmeta><?xpacket end="w"?>';
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.getAll()).toEqual(emptyObj); expect([...metadata]).toEqual([]);
}); });
it("should not be vulnerable to the billion laughs attack", function () { it("should not be vulnerable to the billion laughs attack", function () {
@ -258,12 +241,9 @@ describe("metadata", function () {
"</rdf:RDF>"; "</rdf:RDF>";
const metadata = createMetadata(data); const metadata = createMetadata(data);
expect(metadata.has("dc:title")).toBeTruthy();
expect(metadata.has("dc:qux")).toBeFalsy();
expect(metadata.get("dc:title")).toEqual("a&lol9;b"); expect(metadata.get("dc:title")).toEqual("a&lol9;b");
expect(metadata.get("dc:qux")).toEqual(null); expect(metadata.get("dc:qux")).toEqual(null);
expect(metadata.getAll()).toEqual({ "dc:title": "a&lol9;b" }); expect([...metadata]).toEqual([["dc:title", "a&lol9;b"]]);
}); });
}); });