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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/font-style.
|
||||
const DEFAULT_CSS_FONT_OBLIQUE = "14";
|
||||
@ -750,6 +762,7 @@ export {
|
||||
lookupRect,
|
||||
MAX_INT_32,
|
||||
MissingDataException,
|
||||
normalizeCSSFontFamily,
|
||||
numberToString,
|
||||
ParserEOFException,
|
||||
parseXFAPath,
|
||||
|
||||
@ -42,6 +42,7 @@ import {
|
||||
isWhiteSpace,
|
||||
lookupNormalRect,
|
||||
MissingDataException,
|
||||
normalizeCSSFontFamily,
|
||||
PDF_VERSION_REGEXP,
|
||||
RESOURCES_KEYS_OPERATOR_LIST,
|
||||
RESOURCES_KEYS_TEXT_CONTENT,
|
||||
@ -1396,9 +1397,7 @@ class PDFDocument {
|
||||
if (!(descriptor instanceof Dict)) {
|
||||
continue;
|
||||
}
|
||||
let fontFamily = descriptor.get("FontFamily");
|
||||
// For example, "Wingdings 3" is not a valid font name in the css specs.
|
||||
fontFamily = fontFamily.replaceAll(/ +(\d)/g, "$1");
|
||||
const fontFamily = normalizeCSSFontFamily(descriptor.get("FontFamily"));
|
||||
const fontWeight = descriptor.get("FontWeight");
|
||||
|
||||
// Angle is expressed in degrees counterclockwise in PDF
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
getRotationMatrix,
|
||||
getSizeInBytes,
|
||||
isWhiteSpace,
|
||||
normalizeCSSFontFamily,
|
||||
numberToString,
|
||||
parseXFAPath,
|
||||
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 () {
|
||||
it("Check font family", function () {
|
||||
const cssFontInfo = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user