Skip to content

Commit 6d74dda

Browse files
committed
Encode FontPath data into an ArrayBuffer
Serialize FontPath commands into a binary format and store it in an ArrayBuffer so that it can eventually be stored in a SharedArrayBuffer.
1 parent d83cbb2 commit 6d74dda

File tree

8 files changed

+124
-14
lines changed

8 files changed

+124
-14
lines changed

src/core/evaluator.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
lookupMatrix,
4141
lookupNormalRect,
4242
} from "./core_utils.js";
43+
import { FontInfo, FontPathInfo } from "../shared/obj-bin-transform.js";
4344
import {
4445
getEncoding,
4546
MacRomanEncoding,
@@ -72,7 +73,6 @@ import { BaseStream } from "./base_stream.js";
7273
import { bidi } from "./bidi.js";
7374
import { ColorSpace } from "./colorspace.js";
7475
import { ColorSpaceUtils } from "./colorspace_utils.js";
75-
import { FontInfo } from "../shared/obj-bin-transform.js";
7676
import { getFontSubstitution } from "./font_substitutions.js";
7777
import { getGlyphsUnicode } from "./glyphlist.js";
7878
import { getMetrics } from "./metrics.js";
@@ -4660,11 +4660,8 @@ class PartialEvaluator {
46604660
if (font.renderer.hasBuiltPath(fontChar)) {
46614661
return;
46624662
}
4663-
handler.send("commonobj", [
4664-
glyphName,
4665-
"FontPath",
4666-
font.renderer.getPathJs(fontChar),
4667-
]);
4663+
const buffer = FontPathInfo.write(font.renderer.getPathJs(fontChar));
4664+
handler.send("commonobj", [glyphName, "FontPath", buffer], [buffer]);
46684665
} catch (reason) {
46694666
if (evaluatorOptions.ignoreErrors) {
46704667
warn(`buildFontPaths - ignoring ${glyphName} glyph: "${reason}".`);

src/core/font_renderer.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -770,10 +770,6 @@ class Commands {
770770
restore() {
771771
this.currentTransform = this.transformStack.pop() || [1, 0, 0, 1, 0, 0];
772772
}
773-
774-
getSVG() {
775-
return this.cmds.join("");
776-
}
777773
}
778774

779775
class CompiledFont {
@@ -836,7 +832,7 @@ class CompiledFont {
836832
this.compileGlyphImpl(code, cmds, glyphId);
837833
cmds.add("Z");
838834

839-
return cmds.getSVG();
835+
return cmds.cmds;
840836
}
841837

842838
compileGlyphImpl() {

src/display/api.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
StatTimer,
4646
} from "./display_utils.js";
4747
import { FontFaceObject, FontLoader } from "./font_loader.js";
48+
import { FontInfo, FontPathInfo } from "../shared/obj-bin-transform.js";
4849
import {
4950
getDataProp,
5051
getFactoryUrlProp,
@@ -67,7 +68,6 @@ import { DOMCMapReaderFactory } from "display-cmap_reader_factory";
6768
import { DOMFilterFactory } from "./filter_factory.js";
6869
import { DOMStandardFontDataFactory } from "display-standard_fontdata_factory";
6970
import { DOMWasmFactory } from "display-wasm_factory";
70-
import { FontInfo } from "../shared/obj-bin-transform.js";
7171
import { GlobalWorkerOptions } from "./worker_options.js";
7272
import { Metadata } from "./metadata.js";
7373
import { OptionalContentConfig } from "./optional_content_config.js";
@@ -2803,6 +2803,8 @@ class WorkerTransport {
28032803
}
28042804
break;
28052805
case "FontPath":
2806+
this.commonObjs.resolve(id, new FontPathInfo(exportedData));
2807+
break;
28062808
case "Image":
28072809
case "Pattern":
28082810
this.commonObjs.resolve(id, exportedData);

src/display/font_loader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ class FontFaceObject {
435435
} catch (ex) {
436436
warn(`getPathGenerator - ignoring character: "${ex}".`);
437437
}
438-
const path = new Path2D(cmds || "");
438+
const path = new Path2D(cmds.getSVG() || "");
439439

440440
if (!this.fontExtraProperties) {
441441
// Remove the raw path-string, since we don't need it anymore.

src/shared/obj-bin-transform.js

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,4 +606,74 @@ class FontInfo {
606606
}
607607
}
608608

609-
export { CssFontInfo, FontInfo, SystemFontInfo };
609+
class FontPathInfo {
610+
static write(path) {
611+
let lengthEstimate = 0;
612+
const commands = [];
613+
for (const cmd of path) {
614+
const code = cmd.charCodeAt(0);
615+
const args = cmd.length > 1 ? cmd.slice(1).split(" ") : null;
616+
lengthEstimate += 2 + (args ? args.length * 8 : 0);
617+
commands.push({ code, args });
618+
}
619+
620+
const buffer = new ArrayBuffer(4 + lengthEstimate);
621+
const view = new DataView(buffer);
622+
let offset = 0;
623+
624+
view.setUint32(offset, commands.length);
625+
offset += 4;
626+
for (const { code, args } of commands) {
627+
view.setUint8(offset, code);
628+
offset += 1;
629+
view.setUint8(offset, args ? args.length : 0);
630+
offset += 1;
631+
if (args) {
632+
for (const arg of args) {
633+
view.setFloat64(offset, parseFloat(arg), true);
634+
offset += 8;
635+
}
636+
}
637+
}
638+
639+
assert(offset === buffer.byteLength, "FontPathInfo.write: Buffer overflow");
640+
return buffer;
641+
}
642+
643+
#buffer;
644+
645+
#view;
646+
647+
constructor(buffer) {
648+
this.#buffer = buffer;
649+
this.#view = new DataView(this.#buffer);
650+
}
651+
652+
getSVG() {
653+
const length = this.#view.getUint32(0);
654+
const cmds = [];
655+
let offset = 4;
656+
for (let i = 0; i < length; i++) {
657+
const code = String.fromCharCode(this.#view.getUint8(offset));
658+
offset += 1;
659+
const numArgs = this.#view.getUint8(offset);
660+
offset += 1;
661+
let args = null;
662+
if (numArgs > 0) {
663+
args = [];
664+
for (let j = 0; j < numArgs; j++) {
665+
args.push(this.#view.getFloat64(offset, true));
666+
offset += 8;
667+
}
668+
}
669+
cmds.push(code + (args ? args.join(" ") : ""));
670+
}
671+
assert(
672+
offset === this.#buffer.byteLength,
673+
"FontPathInfo.toString: Buffer overflow"
674+
);
675+
return cmds.join("");
676+
}
677+
}
678+
679+
export { CssFontInfo, FontInfo, FontPathInfo, SystemFontInfo };
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* Copyright 2025 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
import { FontPathInfo } from "../../src/shared/obj-bin-transform.js";
17+
18+
const path = [
19+
"M0.214 0.27",
20+
"L0.23 0.33",
21+
"C0.248 0.395 0.265 0.47100000000000003 0.281 0.54",
22+
"L0.28500000000000003 0.54",
23+
"C0.302 0.47200000000000003 0.32 0.395 0.338 0.33",
24+
"L0.353 0.27",
25+
"L0.214 0.27",
26+
"M0.423 0",
27+
"L0.579 0",
28+
"L0.375 0.652",
29+
"L0.198 0.652",
30+
"L-0.006 0",
31+
"L0.14400000000000002 0",
32+
"L0.184 0.155",
33+
"L0.383 0.155",
34+
"Z",
35+
];
36+
37+
describe("obj-bin-transform FontPathInfo", function () {
38+
it("should create a FontPathInfo instance from an array of path commands", function () {
39+
const buffer = FontPathInfo.write(path);
40+
const fontPathInfo = new FontPathInfo(buffer);
41+
expect(fontPathInfo.getSVG()).toEqual(path.join(""));
42+
});
43+
});

test/unit/clitests.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"autolinker_spec.js",
1212
"bidi_spec.js",
1313
"bin_font_info_spec.js",
14+
"bin_font_path_info_spec.js",
1415
"canvas_factory_spec.js",
1516
"cff_parser_spec.js",
1617
"cmap_spec.js",

test/unit/jasmine-boot.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ async function initializePDFJS(callback) {
5454
"pdfjs-test/unit/autolinker_spec.js",
5555
"pdfjs-test/unit/bidi_spec.js",
5656
"pdfjs-test/unit/bin_font_info_spec.js",
57+
"pdfjs-test/unit/bin_font_path_info_spec.js",
5758
"pdfjs-test/unit/canvas_factory_spec.js",
5859
"pdfjs-test/unit/cff_parser_spec.js",
5960
"pdfjs-test/unit/cmap_spec.js",

0 commit comments

Comments
 (0)