mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-08-04 05:17:24 +02:00
Fix the regex used to normalize css fonts in XFA
The regex was quadratic in the number of consecutive spaces, which caused performance issues when normalizing fonts with a large number of spaces.
This commit is contained in:
parent
7fc7072f9c
commit
491792f0e2
@ -574,6 +574,18 @@ function validateFontName(fontFamily, mustWarn = false) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strip the spaces preceding a digit, since e.g. "Wingdings 3" is not a valid
|
||||||
|
// font name in the css specs.
|
||||||
|
// The optional trailing digit is matched as part of the space run, so that a
|
||||||
|
// failing match cannot backtrack over the spaces; otherwise the replacement
|
||||||
|
// would be quadratic in the number of consecutive spaces.
|
||||||
|
function normalizeCSSFontFamily(fontFamily) {
|
||||||
|
return fontFamily.replaceAll(
|
||||||
|
/( +)(\d)?/g,
|
||||||
|
(_, spaces, digit) => digit ?? " "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function validateCSSFont(cssFontInfo) {
|
function validateCSSFont(cssFontInfo) {
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/font-style.
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/font-style.
|
||||||
const DEFAULT_CSS_FONT_OBLIQUE = "14";
|
const DEFAULT_CSS_FONT_OBLIQUE = "14";
|
||||||
@ -750,6 +762,7 @@ export {
|
|||||||
lookupRect,
|
lookupRect,
|
||||||
MAX_INT_32,
|
MAX_INT_32,
|
||||||
MissingDataException,
|
MissingDataException,
|
||||||
|
normalizeCSSFontFamily,
|
||||||
numberToString,
|
numberToString,
|
||||||
ParserEOFException,
|
ParserEOFException,
|
||||||
parseXFAPath,
|
parseXFAPath,
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import {
|
|||||||
isWhiteSpace,
|
isWhiteSpace,
|
||||||
lookupNormalRect,
|
lookupNormalRect,
|
||||||
MissingDataException,
|
MissingDataException,
|
||||||
|
normalizeCSSFontFamily,
|
||||||
PDF_VERSION_REGEXP,
|
PDF_VERSION_REGEXP,
|
||||||
RESOURCES_KEYS_OPERATOR_LIST,
|
RESOURCES_KEYS_OPERATOR_LIST,
|
||||||
RESOURCES_KEYS_TEXT_CONTENT,
|
RESOURCES_KEYS_TEXT_CONTENT,
|
||||||
@ -1396,9 +1397,7 @@ class PDFDocument {
|
|||||||
if (!(descriptor instanceof Dict)) {
|
if (!(descriptor instanceof Dict)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let fontFamily = descriptor.get("FontFamily");
|
const fontFamily = normalizeCSSFontFamily(descriptor.get("FontFamily"));
|
||||||
// For example, "Wingdings 3" is not a valid font name in the css specs.
|
|
||||||
fontFamily = fontFamily.replaceAll(/ +(\d)/g, "$1");
|
|
||||||
const fontWeight = descriptor.get("FontWeight");
|
const fontWeight = descriptor.get("FontWeight");
|
||||||
|
|
||||||
// Angle is expressed in degrees counterclockwise in PDF
|
// Angle is expressed in degrees counterclockwise in PDF
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import {
|
|||||||
getRotationMatrix,
|
getRotationMatrix,
|
||||||
getSizeInBytes,
|
getSizeInBytes,
|
||||||
isWhiteSpace,
|
isWhiteSpace,
|
||||||
|
normalizeCSSFontFamily,
|
||||||
numberToString,
|
numberToString,
|
||||||
parseXFAPath,
|
parseXFAPath,
|
||||||
recoverJsURL,
|
recoverJsURL,
|
||||||
@ -325,6 +326,41 @@ describe("core_utils", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("normalizeCSSFontFamily", function () {
|
||||||
|
it("should strip the spaces preceding a digit", function () {
|
||||||
|
expect(normalizeCSSFontFamily("Wingdings 3")).toEqual("Wingdings3");
|
||||||
|
expect(normalizeCSSFontFamily("Wingdings 3")).toEqual("Wingdings3");
|
||||||
|
expect(normalizeCSSFontFamily(" 1 2 3")).toEqual("123");
|
||||||
|
expect(normalizeCSSFontFamily("MS Gothic 2 Bold 7")).toEqual(
|
||||||
|
"MS Gothic2 Bold7"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should keep the spaces which don't precede a digit", function () {
|
||||||
|
expect(normalizeCSSFontFamily("")).toEqual("");
|
||||||
|
expect(normalizeCSSFontFamily("Times New Roman")).toEqual(
|
||||||
|
"Times New Roman"
|
||||||
|
);
|
||||||
|
// The runs of spaces must be preserved as-is.
|
||||||
|
expect(normalizeCSSFontFamily(" Times New Roman ")).toEqual(
|
||||||
|
" Times New Roman "
|
||||||
|
);
|
||||||
|
// A digit which isn't preceded by a space is left alone.
|
||||||
|
expect(normalizeCSSFontFamily("Wingdings3")).toEqual("Wingdings3");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle long runs of spaces efficiently", function () {
|
||||||
|
// Guard against a regular expression that backtracks over the spaces,
|
||||||
|
// which makes the replacement quadratic: that needs several seconds
|
||||||
|
// here, whereas a linear one needs well under a millisecond.
|
||||||
|
const fontFamily = `Wingdings${" ".repeat(100000)}`;
|
||||||
|
|
||||||
|
const startTime = performance.now();
|
||||||
|
expect(normalizeCSSFontFamily(fontFamily)).toEqual("Wingdings ");
|
||||||
|
expect(performance.now() - startTime).toBeLessThan(1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("validateCSSFont", function () {
|
describe("validateCSSFont", function () {
|
||||||
it("Check font family", function () {
|
it("Check font family", function () {
|
||||||
const cssFontInfo = {
|
const cssFontInfo = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user