fork from https://github.com/mozilla/pdf.js.git
This commit is contained in:
36
test/font/README.md
Normal file
36
test/font/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Font tests
|
||||
|
||||
The font tests check if PDF.js can read font data correctly. For validation
|
||||
the `ttx` tool (from the Python `fonttools` library) is used that can convert
|
||||
font data to an XML format that we can easily use for assertions in the tests.
|
||||
In the font tests we let PDF.js read font data and pass the PDF.js-interpreted
|
||||
font data through `ttx` to check its correctness. The font tests are successful
|
||||
if PDF.js can successfully read the font data and `ttx` can successfully read
|
||||
the PDF.js-interpreted font data back, proving that PDF.js does not apply any
|
||||
transformations that break the font data.
|
||||
|
||||
## Running the font tests
|
||||
|
||||
The font tests are run on GitHub Actions using the workflow defined in
|
||||
`.github/workflows/font_tests.yml`, but it is also possible to run the font
|
||||
tests locally. The current stable versions of the following dependencies are
|
||||
required to be installed on the system:
|
||||
|
||||
- Python 3
|
||||
- `fonttools` (see https://pypi.org/project/fonttools and https://github.com/fonttools/fonttools)
|
||||
|
||||
The recommended way of installing `fonttools` is using `pip` in a virtual
|
||||
environment because it avoids having to do a system-wide installation and
|
||||
therefore improves isolation, but any other way of installing `fonttools`
|
||||
that makes `ttx` available in the `PATH` environment variable also works.
|
||||
|
||||
Using the virtual environment approach the font tests can be run locally by
|
||||
creating and sourcing a virtual environment with `fonttools` installed in
|
||||
it before running the font tests:
|
||||
|
||||
```
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install fonttools
|
||||
npx gulp fonttest
|
||||
```
|
||||
18
test/font/font_core_spec.js
Normal file
18
test/font/font_core_spec.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ttx, verifyTtxOutput } from "./fontutils.js";
|
||||
|
||||
describe("font1", function () {
|
||||
const font1_1 = Uint8Array.fromBase64(
|
||||
// eslint-disable-next-line max-len
|
||||
"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"
|
||||
);
|
||||
|
||||
describe("test harness testing", function () {
|
||||
it("returns output", async function () {
|
||||
const output = await ttx(font1_1);
|
||||
|
||||
verifyTtxOutput(output);
|
||||
expect(/<ttFont /.test(output)).toEqual(true);
|
||||
expect(/<\/ttFont>/.test(output)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
45
test/font/font_fpgm_spec.js
Normal file
45
test/font/font_fpgm_spec.js
Normal file
File diff suppressed because one or more lines are too long
141
test/font/font_glyf_spec.js
Normal file
141
test/font/font_glyf_spec.js
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Copyright 2026 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ttx, verifyTtxOutput } from "./fontutils.js";
|
||||
import { Font } from "../../src/core/fonts.js";
|
||||
import { Stream } from "../../src/core/stream.js";
|
||||
import { ToUnicodeMap } from "../../src/core/to_unicode_map.js";
|
||||
|
||||
// Minimal TrueType font: 4 glyphs (.notdef, space, A, B), OS/2 v1 / 86 bytes,
|
||||
// no hinting tables.
|
||||
const baseFont = Uint8Array.fromBase64(
|
||||
"AAEAAAAKAIAAAwAgT1MvMkTeRDYAAAEoAAAAVmNtYXAAdQBcAAABjAAAADxnbHlmmNLJuAAAAdQAAABKaGVhZC3Q8mwAAACsAAAANmhoZWEFFgH2AAAA5AAAACRobXR4AlgAAAAAAYAAAAAKbG9jYQAyACYAAAHIAAAACm1heHAABgAGAAABCAAAACBuYW1lAJlcyAAAAiAAAAA8cG9zdAAuACQAAAJcAAAAKgABAAAAAQAAfM/c718PPPUAAQPoAAAAAOYyVzYAAAAA5jJXNgAAAAACWAMgAAAAAwACAAAAAAAAAAEAAAMg/zgAAAJYAAAAZAH0AAEAAAAAAAAAAAAAAAAAAAABAAEAAAAEAAQAAQAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAQJYAZAABQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAPz8/PwAAACAAQgMg/zgAAAMgAMgAAAAAAAAAAAAAAlgAAAAAAAAAAAAAAAAAAgAAAAMAAAAUAAMAAQAAABQABAAoAAAABgAEAAEAAgAgAEL//wAAACAAQf///+H/wQABAAAAAAAAAAAADQANABkAJQAAAAEAZAAAAlgDIAADAAAzIREhZAH0/gwDIAAAAQAAAAAB9AK8AAMAADEhESEB9P4MArwAAQAAAAAB9AK8AAMAADEhESEB9P4MArwAAAAAAAQANgABAAAAAAABAAEAAAABAAAAAAACAAEAAQADAAEECQABAAIAAgADAAEECQACAAIABFRSAFQAUgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAADACQAJQAA"
|
||||
);
|
||||
|
||||
function clone(buf) {
|
||||
return new Uint8Array(buf);
|
||||
}
|
||||
|
||||
function readUint16(buf, pos) {
|
||||
return (buf[pos] << 8) | buf[pos + 1];
|
||||
}
|
||||
|
||||
function readUint32(buf, pos) {
|
||||
return (
|
||||
buf[pos] * 0x1000000 +
|
||||
((buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3])
|
||||
);
|
||||
}
|
||||
|
||||
function getTables(buf) {
|
||||
const tables = Object.create(null);
|
||||
const numTables = readUint16(buf, 4);
|
||||
for (let i = 0; i < numTables; i++) {
|
||||
const off = 12 + i * 16;
|
||||
const tag = String.fromCharCode(
|
||||
buf[off],
|
||||
buf[off + 1],
|
||||
buf[off + 2],
|
||||
buf[off + 3]
|
||||
);
|
||||
tables[tag] = {
|
||||
offset: readUint32(buf, off + 8),
|
||||
length: readUint32(buf, off + 12),
|
||||
};
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
function makeProperties(toUnicode) {
|
||||
return {
|
||||
loadedName: "font",
|
||||
type: "TrueType",
|
||||
differences: [],
|
||||
defaultEncoding: [],
|
||||
toUnicode,
|
||||
xHeight: 0,
|
||||
capHeight: 0,
|
||||
italicAngle: 0,
|
||||
firstChar: 0,
|
||||
lastChar: 255,
|
||||
};
|
||||
}
|
||||
|
||||
describe("font_glyf", function () {
|
||||
describe("Cyclic composite glyph 0", function () {
|
||||
it("removes a self-referencing composite glyph 0 (issue 21298)", async function () {
|
||||
const buggy = clone(baseFont);
|
||||
const tables = getTables(buggy);
|
||||
const headOff = tables.head.offset;
|
||||
const indexToLocFormat = readUint16(buggy, headOff + 50);
|
||||
const locaOff = tables.loca.offset;
|
||||
const glyf0 =
|
||||
indexToLocFormat === 0
|
||||
? readUint16(buggy, locaOff) * 2
|
||||
: readUint32(buggy, locaOff);
|
||||
const glyf0End =
|
||||
indexToLocFormat === 0
|
||||
? readUint16(buggy, locaOff + 2) * 2
|
||||
: readUint32(buggy, locaOff + 4);
|
||||
const pos = tables.glyf.offset + glyf0;
|
||||
buggy.fill(0, pos, tables.glyf.offset + glyf0End);
|
||||
buggy[pos] = 0xff;
|
||||
buggy[pos + 1] = 0xff;
|
||||
buggy[pos + 11] = 0x02;
|
||||
|
||||
const font = new Font(
|
||||
"font",
|
||||
new Stream(buggy),
|
||||
makeProperties(new ToUnicodeMap([])),
|
||||
{}
|
||||
);
|
||||
const output = await ttx(font.data);
|
||||
verifyTtxOutput(output);
|
||||
const notdef =
|
||||
/<TTGlyph[^>]*name="\.notdef"[^>]*\/>|<TTGlyph[^>]*name="\.notdef"[^>]*>([\s\S]*?)<\/TTGlyph>/.exec(
|
||||
output
|
||||
);
|
||||
expect(notdef).not.toBeNull();
|
||||
expect(notdef[1] || "").not.toMatch(
|
||||
/<component\b[^>]+glyphName="\.notdef"/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("OS/2 table length validation", function () {
|
||||
it("rewrites the OS/2 table when its length doesn't match the declared version", async function () {
|
||||
const buggy = clone(baseFont);
|
||||
const tables = getTables(buggy);
|
||||
const os2 = tables["OS/2"].offset;
|
||||
buggy[os2 + 62] = 0x00;
|
||||
buggy[os2 + 63] = 0x40;
|
||||
buggy[os2 + 1] = 0x03;
|
||||
|
||||
const font = new Font(
|
||||
"font",
|
||||
new Stream(buggy),
|
||||
makeProperties(new ToUnicodeMap([])),
|
||||
{}
|
||||
);
|
||||
const output = await ttx(font.data);
|
||||
verifyTtxOutput(output);
|
||||
expect(
|
||||
/<OS_2>\s*(?:<!--[\s\S]*?-->\s*)?<version value="3"\/>/.test(output)
|
||||
).toEqual(true);
|
||||
expect(/<sCapHeight\b/.test(output)).toEqual(true);
|
||||
expect(/<usMaxContext\b/.test(output)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
71
test/font/font_os2_spec.js
Normal file
71
test/font/font_os2_spec.js
Normal file
File diff suppressed because one or more lines are too long
93
test/font/font_post_spec.js
Normal file
93
test/font/font_post_spec.js
Normal file
File diff suppressed because one or more lines are too long
24
test/font/font_test.html
Normal file
24
test/font/font_test.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>PDF.js font tests</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../../node_modules/jasmine-core/lib/jasmine-core/jasmine.css" />
|
||||
|
||||
<script src="../../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
|
||||
<script src="../../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"pdfjs/": "../../src/",
|
||||
"pdfjs-lib": "../../src/pdf.js",
|
||||
"pdfjs-web/": "../../web/",
|
||||
"pdfjs-test/": "../"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="jasmine-boot.js" type="module"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
35
test/font/fontutils.js
Normal file
35
test/font/fontutils.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
async function ttx(data) {
|
||||
const response = await fetch("/ttx", {
|
||||
method: "POST",
|
||||
body: data.toBase64(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
}
|
||||
|
||||
function verifyTtxOutput(output) {
|
||||
const m = /^<error>(.*?)<\/error>/.exec(output);
|
||||
if (m) {
|
||||
throw m[1];
|
||||
}
|
||||
}
|
||||
|
||||
export { ttx, verifyTtxOutput };
|
||||
108
test/font/jasmine-boot.js
Normal file
108
test/font/jasmine-boot.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/* Copyright 2016 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2008-2016 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/* globals jasmineRequire */
|
||||
|
||||
// Modified jasmine's boot.js file to load PDF.js libraries async.
|
||||
|
||||
"use strict";
|
||||
|
||||
import { TestReporter } from "../reporter.js";
|
||||
|
||||
async function initializePDFJS(callback) {
|
||||
await Promise.all(
|
||||
[
|
||||
"pdfjs-test/font/font_core_spec.js",
|
||||
"pdfjs-test/font/font_glyf_spec.js",
|
||||
"pdfjs-test/font/font_os2_spec.js",
|
||||
"pdfjs-test/font/font_post_spec.js",
|
||||
"pdfjs-test/font/font_fpgm_spec.js",
|
||||
].map(moduleName => import(moduleName)) // eslint-disable-line no-unsanitized/method
|
||||
);
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
(function () {
|
||||
window.jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
jasmineRequire.html(jasmine);
|
||||
|
||||
const env = jasmine.getEnv();
|
||||
|
||||
const jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
extend(window, jasmineInterface);
|
||||
|
||||
// Runner Parameters
|
||||
const urls = new jasmine.HtmlReporterV2Urls();
|
||||
|
||||
env.configure(urls.configFromCurrentUrl());
|
||||
|
||||
// Reporters
|
||||
const htmlReporter = new jasmine.HtmlReporterV2({ env, urls });
|
||||
|
||||
env.addReporter(htmlReporter);
|
||||
|
||||
if (urls.queryString.getParam("browser")) {
|
||||
const testReporter = new TestReporter(urls.queryString.getParam("browser"));
|
||||
env.addReporter(testReporter);
|
||||
}
|
||||
|
||||
// Sets longer timeout.
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
||||
|
||||
function extend(destination, source) {
|
||||
for (const property in source) {
|
||||
destination[property] = source[property];
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
function fontTestInit() {
|
||||
initializePDFJS(function () {
|
||||
env.execute();
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
document.readyState === "interactive" ||
|
||||
document.readyState === "complete"
|
||||
) {
|
||||
fontTestInit();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", fontTestInit, true);
|
||||
}
|
||||
})();
|
||||
70
test/font/ttxdriver.mjs
Normal file
70
test/font/ttxdriver.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { spawn } from "child_process";
|
||||
|
||||
let ttxTaskId = Date.now();
|
||||
|
||||
function runTtx(fontPath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ttx = spawn("ttx", [fontPath], { stdio: "ignore" });
|
||||
ttx.on("error", () => {
|
||||
reject(
|
||||
new Error(
|
||||
"Unable to execute `ttx`; make sure the `fonttools` dependency is installed"
|
||||
)
|
||||
);
|
||||
});
|
||||
ttx.on("close", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function translateFont(content) {
|
||||
const buffer = Buffer.from(content, "base64");
|
||||
const taskId = (ttxTaskId++).toString();
|
||||
const fontPath = path.join(os.tmpdir(), `pdfjs-font-test-${taskId}.otf`);
|
||||
const resultPath = path.join(os.tmpdir(), `pdfjs-font-test-${taskId}.ttx`);
|
||||
|
||||
// Write the font data to a temporary file on disk (because TTX only accepts
|
||||
// files as input).
|
||||
fs.writeFileSync(fontPath, buffer);
|
||||
|
||||
// Run TTX on the temporary font file.
|
||||
let ttxError;
|
||||
try {
|
||||
await runTtx(fontPath);
|
||||
} catch (error) {
|
||||
ttxError = error;
|
||||
}
|
||||
|
||||
// Remove the temporary font/result files and report on the outcome.
|
||||
fs.unlinkSync(fontPath);
|
||||
if (ttxError) {
|
||||
throw ttxError;
|
||||
}
|
||||
if (!fs.existsSync(resultPath)) {
|
||||
throw new Error("TTX did not generate output");
|
||||
}
|
||||
const xml = fs.readFileSync(resultPath);
|
||||
fs.unlinkSync(resultPath);
|
||||
return xml;
|
||||
}
|
||||
|
||||
export { translateFont };
|
||||
Reference in New Issue
Block a user