mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-10-04 06:18:00 +02:00
Compare commits
8
Commits
735ea6285c
...
c33c32aed4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c33c32aed4 | ||
|
|
d9080794fa | ||
|
|
f786355550 | ||
|
|
e3e606de23 | ||
|
|
62de7c55e1 | ||
|
|
29a06285dc | ||
|
|
a02decd96c | ||
|
|
40cc2082df |
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
+10
-10
File diff suppressed because one or more lines are too long
@@ -3004,10 +3004,7 @@ class PartialEvaluator {
|
|||||||
}
|
}
|
||||||
let charSpacing = baseCharSpacing + (i + 1 === ii ? extraSpacing : 0);
|
let charSpacing = baseCharSpacing + (i + 1 === ii ? extraSpacing : 0);
|
||||||
|
|
||||||
let glyphWidth = glyph.width;
|
const glyphWidth = font.vertical ? glyph.vmetric[0] : glyph.width;
|
||||||
if (font.vertical) {
|
|
||||||
glyphWidth = glyph.vmetric ? glyph.vmetric[0] : -glyphWidth;
|
|
||||||
}
|
|
||||||
let scaledDim = glyphWidth * scale;
|
let scaledDim = glyphWidth * scale;
|
||||||
|
|
||||||
if (originalCharCode === 0x20) {
|
if (originalCharCode === 0x20) {
|
||||||
|
|||||||
+7
-2
@@ -87,7 +87,6 @@ const EXPORT_DATA_PROPERTIES = [
|
|||||||
// "charProcOperatorList" is handled separately, since it's not compiled.
|
// "charProcOperatorList" is handled separately, since it's not compiled.
|
||||||
"cssFontInfo",
|
"cssFontInfo",
|
||||||
"data",
|
"data",
|
||||||
"defaultVMetrics",
|
|
||||||
"descent",
|
"descent",
|
||||||
"disableFontFace",
|
"disableFontFace",
|
||||||
"fallbackName",
|
"fallbackName",
|
||||||
@@ -108,6 +107,7 @@ const EXPORT_DATA_PROPERTIES = [
|
|||||||
const EXPORT_DATA_EXTRA_PROPERTIES = [
|
const EXPORT_DATA_EXTRA_PROPERTIES = [
|
||||||
"composite",
|
"composite",
|
||||||
"defaultEncoding",
|
"defaultEncoding",
|
||||||
|
"defaultVMetrics",
|
||||||
"defaultWidth",
|
"defaultWidth",
|
||||||
"differences",
|
"differences",
|
||||||
"isMonospace",
|
"isMonospace",
|
||||||
@@ -3561,7 +3561,12 @@ class Font {
|
|||||||
if (typeof width !== "number") {
|
if (typeof width !== "number") {
|
||||||
width = this.defaultWidth;
|
width = this.defaultWidth;
|
||||||
}
|
}
|
||||||
const vmetric = this.vmetrics?.[widthCode] || this.defaultVMetrics;
|
let vmetric = this.vmetrics?.[widthCode];
|
||||||
|
if (!vmetric && this.defaultVMetrics) {
|
||||||
|
// Without a W2 entry, vx is half the glyph width (PDF 32000-1, 9.7.4.3).
|
||||||
|
const [w1y, , vy] = this.defaultVMetrics;
|
||||||
|
vmetric = [w1y, width * 0.5, vy];
|
||||||
|
}
|
||||||
|
|
||||||
let unicode = this.toUnicode.get(charcode) || charcode;
|
let unicode = this.toUnicode.get(charcode) || charcode;
|
||||||
if (typeof unicode === "number") {
|
if (typeof unicode === "number") {
|
||||||
|
|||||||
@@ -193,20 +193,9 @@ function compileFontInfo(font) {
|
|||||||
/* writerName = */ "setFloat64",
|
/* writerName = */ "setFloat64",
|
||||||
/* increment = */ 8
|
/* increment = */ 8
|
||||||
);
|
);
|
||||||
assert(
|
|
||||||
offset === FONT_INFO.OFFSET_DEFAULT_VMETRICS,
|
|
||||||
"compileFontInfo: FontMatrix properties offset mismatch"
|
|
||||||
);
|
|
||||||
|
|
||||||
writeArray(
|
|
||||||
/* arr = */ font.defaultVMetrics,
|
|
||||||
/* arrLen = */ 3,
|
|
||||||
/* writerName = */ "setInt16",
|
|
||||||
/* increment = */ 2
|
|
||||||
);
|
|
||||||
assert(
|
assert(
|
||||||
offset === FONT_INFO.OFFSET_STRINGS,
|
offset === FONT_INFO.OFFSET_STRINGS,
|
||||||
"compileFontInfo: DefaultVMetrics properties offset mismatch"
|
"compileFontInfo: FontMatrix properties offset mismatch"
|
||||||
);
|
);
|
||||||
|
|
||||||
view.setUint32(offset, stringsLength);
|
view.setUint32(offset, stringsLength);
|
||||||
|
|||||||
@@ -2772,7 +2772,6 @@ class CanvasGraphics {
|
|||||||
const glyphsLength = glyphs.length;
|
const glyphsLength = glyphs.length;
|
||||||
const vertical = font.vertical;
|
const vertical = font.vertical;
|
||||||
const spacingDir = vertical ? 1 : -1;
|
const spacingDir = vertical ? 1 : -1;
|
||||||
const defaultVMetrics = font.defaultVMetrics;
|
|
||||||
const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
||||||
|
|
||||||
const simpleFillText =
|
const simpleFillText =
|
||||||
@@ -2896,12 +2895,11 @@ class CanvasGraphics {
|
|||||||
let scaledX, scaledY;
|
let scaledX, scaledY;
|
||||||
let width = glyph.width;
|
let width = glyph.width;
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
const vmetric = glyph.vmetric || defaultVMetrics;
|
const vmetric = glyph.vmetric;
|
||||||
const vx =
|
const vx = -vmetric[1] * widthAdvanceScale;
|
||||||
-(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
|
|
||||||
const vy = vmetric[2] * widthAdvanceScale;
|
const vy = vmetric[2] * widthAdvanceScale;
|
||||||
|
|
||||||
width = vmetric ? -vmetric[0] : width;
|
width = -vmetric[0];
|
||||||
scaledX = vx / fontSizeScale;
|
scaledX = vx / fontSizeScale;
|
||||||
scaledY = (x + vy) / fontSizeScale;
|
scaledY = (x + vy) / fontSizeScale;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -589,10 +589,6 @@ class FontFaceObject {
|
|||||||
get systemFontInfo() {
|
get systemFontInfo() {
|
||||||
return this.#fontData.systemFontInfo;
|
return this.#fontData.systemFontInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultVMetrics() {
|
|
||||||
return this.#fontData.defaultVMetrics;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { FontFaceObject, FontLoader };
|
export { FontFaceObject, FontLoader };
|
||||||
|
|||||||
@@ -206,15 +206,6 @@ class FontInfo {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultVMetrics() {
|
|
||||||
return this.#readArray(
|
|
||||||
/* offset = */ FONT_INFO.OFFSET_DEFAULT_VMETRICS,
|
|
||||||
/* arrLen = */ 3,
|
|
||||||
/* lookup = */ "getInt16",
|
|
||||||
/* increment = */ 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#readString(index) {
|
#readString(index) {
|
||||||
assert(index < FONT_INFO.strings.length, "Invalid string index");
|
assert(index < FONT_INFO.strings.length, "Invalid string index");
|
||||||
return readString(
|
return readString(
|
||||||
|
|||||||
@@ -1236,7 +1236,7 @@ class Doc extends PDFObject {
|
|||||||
let mustCalculate = false;
|
let mustCalculate = false;
|
||||||
let fieldsToReset;
|
let fieldsToReset;
|
||||||
if (aFields) {
|
if (aFields) {
|
||||||
fieldsToReset = [];
|
fieldsToReset = new Set();
|
||||||
for (const fieldName of aFields) {
|
for (const fieldName of aFields) {
|
||||||
if (!fieldName) {
|
if (!fieldName) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1250,12 +1250,23 @@ class Doc extends PDFObject {
|
|||||||
if (!field) {
|
if (!field) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fieldsToReset.push(field);
|
fieldsToReset.add(field);
|
||||||
mustCalculate = true;
|
mustCalculate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fieldsToReset) {
|
if (fieldsToReset) {
|
||||||
|
// A non-terminal field stands for all its descendants, hence add the
|
||||||
|
// kids (the Set iterator also visits the newly added fields).
|
||||||
|
for (const { obj } of fieldsToReset) {
|
||||||
|
for (const id of obj._kidIds || []) {
|
||||||
|
const kid = obj._appObjects[id];
|
||||||
|
if (kid) {
|
||||||
|
fieldsToReset.add(kid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
fieldsToReset = this._fields.values();
|
fieldsToReset = this._fields.values();
|
||||||
mustCalculate = this._fields.size !== 0;
|
mustCalculate = this._fields.size !== 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,9 +47,7 @@ class FONT_INFO {
|
|||||||
|
|
||||||
static OFFSET_FONT_MATRIX = this.OFFSET_BBOX + 1 + 2 * 4;
|
static OFFSET_FONT_MATRIX = this.OFFSET_BBOX + 1 + 2 * 4;
|
||||||
|
|
||||||
static OFFSET_DEFAULT_VMETRICS = this.OFFSET_FONT_MATRIX + 1 + 8 * 6;
|
static OFFSET_STRINGS = this.OFFSET_FONT_MATRIX + 1 + 8 * 6;
|
||||||
|
|
||||||
static OFFSET_STRINGS = this.OFFSET_DEFAULT_VMETRICS + 1 + 2 * 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PATTERN_INFO {
|
class PATTERN_INFO {
|
||||||
|
|||||||
@@ -14,9 +14,58 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Font } from "../../src/core/fonts.js";
|
import { Font } from "../../src/core/fonts.js";
|
||||||
|
import { IdentityCMap } from "../../src/core/cmap.js";
|
||||||
import { IdentityToUnicodeMap } from "../../src/core/to_unicode_map.js";
|
import { IdentityToUnicodeMap } from "../../src/core/to_unicode_map.js";
|
||||||
|
|
||||||
describe("Font", () => {
|
describe("Font", () => {
|
||||||
|
describe("charsToGlyphs", () => {
|
||||||
|
// Match the sparse metric arrays from PartialEvaluator.extractWidths.
|
||||||
|
function createFont(vertical) {
|
||||||
|
return new Font(
|
||||||
|
"TestFont",
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
type: "CIDFontType2",
|
||||||
|
composite: true,
|
||||||
|
vertical,
|
||||||
|
cMap: new IdentityCMap(vertical, 2),
|
||||||
|
cidEncoding: vertical ? "Identity-V" : "Identity-H",
|
||||||
|
toUnicode: new IdentityToUnicodeMap(65, 68),
|
||||||
|
differences: new Map(),
|
||||||
|
defaultEncoding: [],
|
||||||
|
widths: Object.assign([], { 65: 600, 66: 0, 68: 800 }),
|
||||||
|
defaultWidth: 1000,
|
||||||
|
vmetrics: vertical ? Object.assign([], { 68: [-800, 175, 700] }) : [],
|
||||||
|
defaultVMetrics: vertical ? [-1200, 500, 900] : undefined,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should use half the glyph width for the default vertical origin", () => {
|
||||||
|
const font = createFont(/* vertical = */ true);
|
||||||
|
const glyphs = font.charsToGlyphs("\x00A\x00B\x00C\x00D");
|
||||||
|
|
||||||
|
// Cover per-glyph widths, zero width, DW fallback, and explicit W2.
|
||||||
|
expect(glyphs.map(glyph => glyph.vmetric)).toEqual([
|
||||||
|
[-1200, 300, 900],
|
||||||
|
[-1200, 0, 900],
|
||||||
|
[-1200, 500, 900],
|
||||||
|
[-800, 175, 700],
|
||||||
|
]);
|
||||||
|
expect(font.defaultVMetrics).toEqual([-1200, 500, 900]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not set a vertical metric for horizontal fonts", () => {
|
||||||
|
const font = createFont(/* vertical = */ false);
|
||||||
|
const glyphs = font.charsToGlyphs("\x00A\x00B\x00C\x00D");
|
||||||
|
|
||||||
|
for (const glyph of glyphs) {
|
||||||
|
expect(glyph.vmetric).toBeUndefined();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("encodeString", () => {
|
describe("encodeString", () => {
|
||||||
// `encodeString` only reads `this.toUnicode` and `this.cMap`, so a
|
// `encodeString` only reads `this.toUnicode` and `this.cMap`, so a
|
||||||
// full `Font` (which needs a complete properties/font-file setup) isn't
|
// full `Font` (which needs a complete properties/font-file setup) isn't
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ describe("obj_bin_transform", function () {
|
|||||||
descent: -1,
|
descent: -1,
|
||||||
bbox: [1, 1, 1, 1],
|
bbox: [1, 1, 1, 1],
|
||||||
fontMatrix: [1, 1, 1, 1, 1, 1],
|
fontMatrix: [1, 1, 1, 1, 1, 1],
|
||||||
defaultVMetrics: [1, 1, 1],
|
|
||||||
fallbackName: "string",
|
fallbackName: "string",
|
||||||
loadedName: "string",
|
loadedName: "string",
|
||||||
mimetype: "string",
|
mimetype: "string",
|
||||||
@@ -125,7 +124,7 @@ describe("obj_bin_transform", function () {
|
|||||||
|
|
||||||
describe("FontInfo", function () {
|
describe("FontInfo", function () {
|
||||||
it("must roundtrip correctly for FontInfo", function () {
|
it("must roundtrip correctly for FontInfo", function () {
|
||||||
let sizeEstimate = 84; // fixed offset until the strings
|
let sizeEstimate = 77; // fixed offset until the strings
|
||||||
const { encoder } = InfoUtils;
|
const { encoder } = InfoUtils;
|
||||||
sizeEstimate += 4 + 4 * (4 + encoder.encode("string").length);
|
sizeEstimate += 4 + 4 * (4 + encoder.encode("string").length);
|
||||||
sizeEstimate += 4 + 4; // cssFontInfo and systemFontInfo
|
sizeEstimate += 4 + 4; // cssFontInfo and systemFontInfo
|
||||||
@@ -147,7 +146,6 @@ describe("obj_bin_transform", function () {
|
|||||||
expect(deserialized.descent).toEqual(-1);
|
expect(deserialized.descent).toEqual(-1);
|
||||||
expect(deserialized.bbox).toEqual([1, 1, 1, 1]);
|
expect(deserialized.bbox).toEqual([1, 1, 1, 1]);
|
||||||
expect(deserialized.fontMatrix).toEqual([1, 1, 1, 1, 1, 1]);
|
expect(deserialized.fontMatrix).toEqual([1, 1, 1, 1, 1, 1]);
|
||||||
expect(deserialized.defaultVMetrics).toEqual([1, 1, 1]);
|
|
||||||
expect(deserialized.fallbackName).toEqual("string");
|
expect(deserialized.fallbackName).toEqual("string");
|
||||||
expect(deserialized.loadedName).toEqual("string");
|
expect(deserialized.loadedName).toEqual("string");
|
||||||
expect(deserialized.mimetype).toEqual("string");
|
expect(deserialized.mimetype).toEqual("string");
|
||||||
|
|||||||
@@ -197,6 +197,55 @@ describe("Scripting", function () {
|
|||||||
);
|
);
|
||||||
expect(value).toEqual([4, 5, 6, 7]);
|
expect(value).toEqual([4, 5, 6, 7]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should reset the descendants of a non-terminal field", async () => {
|
||||||
|
const refIds = [0, 1, 2, 3, 4].map(_ => getId());
|
||||||
|
const text = id => ({
|
||||||
|
id,
|
||||||
|
value: "",
|
||||||
|
defaultValue: "",
|
||||||
|
actions: {},
|
||||||
|
type: "text",
|
||||||
|
});
|
||||||
|
const data = {
|
||||||
|
objects: {
|
||||||
|
A: [{ id: refIds[0], type: "", kidIds: [refIds[1], refIds[2]] }],
|
||||||
|
"A.B": [text(refIds[1])],
|
||||||
|
"A.C": [{ id: refIds[2], type: "", kidIds: [refIds[3]] }],
|
||||||
|
"A.C.D": [text(refIds[3])],
|
||||||
|
E: [text(refIds[4])],
|
||||||
|
},
|
||||||
|
appInfo: { language: "en-US", platform: "Linux x86_64" },
|
||||||
|
calculationOrder: [],
|
||||||
|
dispatchEventName: "_dispatchMe",
|
||||||
|
};
|
||||||
|
sandbox.createSandbox(data);
|
||||||
|
|
||||||
|
await myeval(
|
||||||
|
`(["A.B", "A.C.D", "E"].forEach(n => this.getField(n).value = "hello"), 0)`
|
||||||
|
);
|
||||||
|
for (const id of [refIds[1], refIds[3], refIds[4]]) {
|
||||||
|
send_queue.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await myeval(`(this.resetForm(["A"]), 0)`);
|
||||||
|
|
||||||
|
for (const id of [refIds[1], refIds[3]]) {
|
||||||
|
expect(send_queue.get(id)).toEqual({
|
||||||
|
id,
|
||||||
|
siblings: null,
|
||||||
|
value: "",
|
||||||
|
formattedValue: null,
|
||||||
|
selRange: [0, 0],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect(send_queue.has(refIds[4])).toBeFalse();
|
||||||
|
|
||||||
|
const values = await myeval(
|
||||||
|
`["A.B", "A.C.D", "E"].map(n => this.getField(n).value)`
|
||||||
|
);
|
||||||
|
expect(values).toEqual(["", "", "hello"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Util", function () {
|
describe("Util", function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user