From 70bb672dcd3465034e7b5494690caf1e75b3f1b7 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Mon, 28 Jun 2021 19:03:47 +0200 Subject: [PATCH] XFA - Support non-embedded fonts without a Widths entry - some pdf use some fonts which are not embedded or they don't have any width array or don't have any css info (e.g. for standard fonts or Arial). - so add widths arrays for Liberation fonts in order to compute the ones for other fonts in using scale factors array. --- src/core/document.js | 60 +++++++++++- src/core/liberationsans_bold_italic_widths.js | 66 +++++++++++++ src/core/liberationsans_bold_widths.js | 66 +++++++++++++ src/core/liberationsans_italic_widths.js | 66 +++++++++++++ src/core/liberationsans_regular_widths.js | 66 +++++++++++++ src/core/xfa/factory.js | 19 ++++ src/core/xfa/fonts.js | 96 ++++++++++--------- src/core/xfa/parser.js | 4 +- src/core/xfa/template.js | 5 + src/core/xfa/xhtml.js | 21 +++- src/core/xfa_fonts.js | 54 +++++++++-- 11 files changed, 464 insertions(+), 59 deletions(-) create mode 100644 src/core/liberationsans_bold_italic_widths.js create mode 100644 src/core/liberationsans_bold_widths.js create mode 100644 src/core/liberationsans_italic_widths.js create mode 100644 src/core/liberationsans_regular_widths.js diff --git a/src/core/document.js b/src/core/document.js index bc9bfb555..b66bb7e14 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -57,6 +57,7 @@ import { AnnotationFactory } from "./annotation.js"; import { BaseStream } from "./base_stream.js"; import { calculateMD5 } from "./crypto.js"; import { Catalog } from "./catalog.js"; +import { getXfaFontWidths } from "./xfa_fonts.js"; import { Linearization } from "./parser.js"; import { ObjectLoader } from "./object_loader.js"; import { OperatorList } from "./operator_list.js"; @@ -960,7 +961,64 @@ class PDFDocument { } await Promise.all(promises); - this.xfaFactory.setFonts(pdfFonts); + const missingFonts = this.xfaFactory.setFonts(pdfFonts); + + if (!missingFonts) { + return; + } + + options.ignoreErrors = true; + promises.length = 0; + pdfFonts.length = 0; + + for (const missing of missingFonts) { + for (const fontInfo of [ + { name: "Regular", fontWeight: 400, italicAngle: 0 }, + { name: "Bold", fontWeight: 700, italicAngle: 0 }, + { name: "Italic", fontWeight: 400, italicAngle: 12 }, + { name: "BoldItalic", fontWeight: 700, italicAngle: 12 }, + ]) { + const name = `${missing}-${fontInfo.name}`; + const widths = getXfaFontWidths(name); + if (!widths) { + continue; + } + + const dict = new Dict(null); + dict.set("BaseFont", Name.get(name)); + dict.set("Type", Name.get("Font")); + dict.set("Subtype", Name.get("TrueType")); + dict.set("Encoding", Name.get("WinAnsiEncoding")); + const descriptor = new Dict(null); + descriptor.set("Widths", widths); + dict.set("FontDescriptor", descriptor); + + promises.push( + partialEvaluator + .handleSetFont( + resources, + [Name.get(name), 1], + /* fontRef = */ null, + operatorList, + task, + initialState, + /* fallbackFontDict = */ dict, + /* cssFontInfo = */ { + fontFamily: missing, + fontWeight: fontInfo.fontWeight, + italicAngle: fontInfo.italicAngle, + } + ) + .catch(function (reason) { + warn(`loadXfaFonts: "${reason}".`); + return null; + }) + ); + } + } + + await Promise.all(promises); + this.xfaFactory.appendFonts(pdfFonts); } async serializeXfaData(annotationStorage) { diff --git a/src/core/liberationsans_bold_italic_widths.js b/src/core/liberationsans_bold_italic_widths.js new file mode 100644 index 000000000..f8f53cb48 --- /dev/null +++ b/src/core/liberationsans_bold_italic_widths.js @@ -0,0 +1,66 @@ +/* Copyright 2021 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. + */ + +// Widths of glyphes in LiberationSans-BoldItalic.ttf. +const LiberationSansBoldItalicWidths = [ + 365, 0, 722, 1000, 1000, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 667, 722, 722, 722, 671, + 667, 667, 667, 667, 667, 667, 667, 667, 667, 723, 667, 667, 854, 722, 906, + 722, 556, 611, 778, 610, 778, 778, 778, 778, 722, 604, 354, 354, 604, 722, + 722, 278, 782, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 473, 278, + 556, 556, 722, 722, 722, 611, 611, 667, 611, 611, 611, 611, 833, 833, 722, + 722, 722, 722, 722, 722, 778, 1000, 778, 778, 778, 778, 778, 778, 778, 781, + 847, 778, 844, 778, 778, 778, 667, 822, 718, 829, 778, 722, 722, 722, 722, + 667, 667, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 625, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 667, 667, 667, + 667, 667, 590, 611, 611, 611, 611, 611, 778, 667, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 667, 667, 930, 722, 722, 667, 944, 944, 944, 944, 944, + 667, 657, 667, 667, 667, 667, 667, 611, 611, 611, 611, 611, 556, 556, 556, + 556, 333, 333, 556, 889, 889, 1000, 722, 708, 722, 614, 722, 667, 667, 927, + 643, 719, 719, 615, 687, 833, 722, 778, 719, 667, 722, 611, 677, 781, 667, + 729, 708, 979, 989, 854, 1000, 708, 719, 1042, 729, 575, 886, 614, 719, 667, + 278, 278, 556, 1094, 1042, 854, 622, 677, 556, 619, 604, 534, 618, 556, 556, + 736, 510, 611, 611, 507, 622, 740, 604, 611, 611, 611, 556, 889, 556, 885, + 556, 646, 583, 889, 935, 707, 854, 594, 552, 865, 589, 467, 611, 469, 563, + 556, 278, 278, 278, 969, 906, 611, 507, 556, 719, 778, 611, 611, 885, 516, + 1146, 556, 620, 620, 556, 722, 333, 556, 549, 556, 556, 1000, 500, 999, 1000, + 500, 500, 500, 584, 584, 389, 975, 556, 611, 278, 280, 621, 708, 389, 389, + 333, 333, 333, 333, 280, 350, 556, 556, 333, 333, 222, 556, 556, 556, 556, + 333, 556, 578, 604, 333, 333, 656, 333, 278, 333, 222, 737, 556, 333, 611, + 556, 556, 740, 611, 400, 610, 510, 333, 333, 333, 549, 729, 708, 556, 333, + 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 1000, 556, 1000, 556, + 611, 556, 479, 479, 584, 583, 600, 611, 611, 611, 333, 604, 333, 333, 750, + 604, 1000, 556, 834, 333, 556, 556, 333, 556, 611, 556, 611, 611, 611, 611, + 611, 333, 333, 584, 549, 556, 556, 333, 333, 611, 611, 611, 594, 604, 333, + 333, 278, 278, 278, 278, 278, 278, 556, 278, 713, 274, 604, 604, 722, 604, + 604, 1052, 278, 278, 278, 278, 278, 278, 278, 278, 556, 566, 556, 556, 278, + 278, 556, 396, 278, 479, 584, 549, 708, 556, 584, 278, 494, 278, 708, 889, + 552, 750, 333, 584, 240, 603, 584, 500, 750, 611, 611, 708, 611, 611, 556, + 333, 549, 611, 556, 556, 611, 611, 611, 611, 611, 944, 333, 611, 611, 611, + 834, 834, 611, 611, 556, 834, 834, 834, 354, 370, 365, 979, 611, 611, 611, + 611, 556, 333, 333, 494, 889, 278, 1000, 1104, 704, 712, 584, 549, 823, 773, + 611, 611, 611, 474, 500, 500, 500, 278, 278, 278, 278, 238, 389, 389, 549, + 389, 389, 737, 584, 605, 333, 708, 556, 556, 556, 556, 556, 556, 479, 556, + 556, 834, 333, 708, 664, 532, 556, 278, 1021, 531, 556, 713, 917, 333, 409, + 333, 479, 333, 558, 611, 556, 834, 834, 333, 333, 333, 1000, 990, 990, 990, + 990, 556, 611, 611, 611, 611, 611, 611, 611, 611, 556, 552, 278, 333, 333, + 333, 576, 333, 611, 333, 333, 333, 667, 719, 556, 619, 333, 333, 333, 396, + 768, 612, 167, 278, 750, 333, 611, 611, 611, 708, 591, 591, 591, 591, 611, + 611, 556, 778, 778, 778, 778, 778, 556, 450, 556, 556, 556, 556, 556, 556, + 500, 500, 500, 500, 556, 492, +]; + +export { LiberationSansBoldItalicWidths }; diff --git a/src/core/liberationsans_bold_widths.js b/src/core/liberationsans_bold_widths.js new file mode 100644 index 000000000..bd1a3d64f --- /dev/null +++ b/src/core/liberationsans_bold_widths.js @@ -0,0 +1,66 @@ +/* Copyright 2021 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. + */ + +// Widths of glyphes in LiberationSans-Bold.ttf. +const LiberationSansBoldWidths = [ + 365, 0, 722, 1000, 1000, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 667, 722, 722, 722, 719, + 667, 667, 667, 667, 667, 667, 667, 667, 667, 723, 667, 667, 853, 722, 906, + 722, 556, 611, 778, 601, 778, 778, 778, 778, 722, 604, 354, 354, 604, 722, + 722, 278, 785, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 474, 278, + 556, 556, 722, 722, 722, 611, 611, 667, 611, 611, 611, 611, 833, 833, 722, + 722, 722, 722, 722, 722, 778, 1000, 778, 778, 778, 778, 778, 778, 778, 802, + 838, 778, 825, 778, 778, 778, 667, 821, 722, 809, 778, 722, 722, 722, 722, + 667, 667, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 625, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 667, 667, 667, + 667, 667, 600, 611, 611, 611, 611, 611, 778, 667, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 667, 667, 927, 722, 722, 667, 944, 944, 944, 944, 944, + 667, 644, 667, 667, 667, 667, 667, 611, 611, 611, 611, 611, 556, 556, 556, + 556, 333, 333, 556, 889, 889, 1000, 722, 719, 722, 567, 712, 667, 669, 904, + 626, 719, 719, 610, 702, 833, 722, 778, 719, 667, 722, 611, 622, 854, 667, + 730, 703, 1005, 1019, 870, 979, 719, 711, 1031, 719, 487, 885, 567, 711, 667, + 278, 276, 556, 1094, 1062, 875, 610, 622, 556, 618, 615, 417, 635, 556, 556, + 709, 497, 615, 615, 500, 635, 740, 604, 611, 604, 611, 556, 490, 556, 875, + 556, 615, 581, 833, 844, 729, 854, 615, 552, 854, 583, 447, 611, 417, 552, + 556, 278, 281, 278, 969, 906, 611, 500, 556, 719, 778, 604, 611, 885, 489, + 1115, 556, 615, 615, 556, 722, 333, 556, 549, 556, 556, 1000, 500, 1000, 1000, + 500, 500, 500, 584, 584, 389, 975, 556, 611, 278, 280, 610, 708, 389, 389, + 333, 333, 333, 333, 280, 350, 556, 556, 333, 333, 222, 556, 556, 556, 556, + 333, 556, 576, 604, 333, 333, 656, 333, 278, 333, 222, 737, 556, 333, 611, + 556, 556, 719, 611, 400, 606, 510, 333, 333, 465, 549, 729, 708, 556, 333, + 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 1000, 556, 1000, 556, + 611, 556, 475, 451, 584, 583, 600, 611, 611, 611, 333, 604, 333, 333, 750, + 604, 1000, 556, 834, 333, 556, 556, 333, 556, 611, 556, 611, 611, 611, 611, + 611, 333, 333, 584, 549, 556, 556, 333, 333, 611, 611, 611, 594, 604, 333, + 333, 278, 278, 278, 278, 278, 278, 556, 278, 713, 274, 604, 604, 722, 604, + 604, 1052, 278, 278, 278, 278, 278, 278, 278, 278, 556, 558, 556, 556, 278, + 278, 556, 385, 278, 479, 584, 549, 708, 556, 584, 278, 494, 278, 708, 889, + 552, 750, 333, 584, 240, 612, 584, 500, 750, 611, 611, 708, 611, 611, 556, + 333, 549, 611, 556, 556, 611, 611, 611, 611, 611, 944, 333, 611, 611, 611, + 845, 845, 611, 611, 556, 834, 834, 834, 354, 370, 365, 979, 611, 611, 611, + 611, 556, 333, 333, 494, 889, 278, 1000, 1094, 715, 766, 584, 549, 823, 753, + 611, 611, 611, 474, 500, 500, 500, 278, 278, 278, 278, 238, 389, 389, 549, + 389, 389, 737, 584, 619, 333, 708, 556, 556, 556, 556, 556, 556, 479, 556, + 556, 834, 333, 708, 684, 520, 556, 278, 1021, 531, 556, 713, 917, 333, 446, + 333, 479, 333, 541, 611, 556, 834, 834, 333, 333, 333, 1000, 990, 990, 990, + 990, 556, 611, 611, 611, 611, 611, 611, 611, 611, 556, 552, 278, 333, 333, + 333, 576, 333, 611, 333, 333, 333, 667, 722, 556, 615, 333, 333, 333, 396, + 768, 612, 167, 278, 750, 333, 611, 611, 611, 708, 582, 582, 582, 582, 611, + 611, 556, 778, 778, 778, 778, 778, 556, 445, 556, 556, 556, 556, 556, 556, + 500, 500, 500, 500, 556, 460, +]; + +export { LiberationSansBoldWidths }; diff --git a/src/core/liberationsans_italic_widths.js b/src/core/liberationsans_italic_widths.js new file mode 100644 index 000000000..5d0fdbc53 --- /dev/null +++ b/src/core/liberationsans_italic_widths.js @@ -0,0 +1,66 @@ +/* Copyright 2021 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. + */ + +// Widths of glyphes in LiberationSans-Italic.ttf. +const LiberationSansItalicWidths = [ + 365, 0, 667, 1000, 1000, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, + 667, 667, 667, 667, 722, 722, 722, 722, 722, 722, 667, 722, 722, 722, 671, + 667, 667, 667, 667, 667, 667, 667, 667, 667, 723, 667, 667, 789, 722, 846, + 722, 556, 611, 778, 570, 778, 778, 778, 778, 722, 604, 354, 354, 604, 722, + 722, 278, 733, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 389, 278, + 500, 500, 667, 667, 667, 556, 556, 667, 556, 556, 556, 556, 833, 833, 722, + 722, 722, 722, 722, 722, 778, 1000, 778, 778, 778, 778, 778, 778, 778, 761, + 775, 778, 794, 778, 778, 778, 667, 837, 725, 831, 778, 722, 722, 722, 722, + 667, 667, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 625, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 667, 667, 667, + 667, 667, 600, 611, 611, 611, 611, 611, 778, 667, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 667, 667, 865, 722, 722, 667, 944, 944, 944, 944, 944, + 667, 648, 667, 667, 667, 667, 667, 611, 611, 611, 611, 611, 556, 556, 556, + 556, 333, 294, 556, 889, 889, 1000, 667, 651, 667, 544, 704, 667, 667, 917, + 614, 715, 715, 589, 686, 833, 722, 778, 725, 667, 722, 611, 639, 795, 667, + 727, 673, 920, 923, 805, 886, 651, 694, 1022, 682, 492, 843, 544, 708, 667, + 278, 278, 500, 1066, 982, 844, 589, 639, 556, 562, 522, 493, 553, 556, 556, + 688, 465, 556, 556, 472, 564, 686, 550, 556, 556, 556, 500, 833, 500, 835, + 500, 572, 518, 830, 851, 621, 736, 526, 492, 752, 534, 339, 556, 378, 496, + 500, 222, 222, 222, 910, 828, 556, 472, 500, 724, 778, 556, 556, 885, 323, + 1083, 556, 570, 570, 556, 667, 278, 556, 549, 556, 556, 1000, 500, 1000, 998, + 500, 500, 500, 469, 584, 389, 1015, 556, 556, 278, 260, 571, 708, 334, 334, + 278, 278, 333, 285, 260, 350, 500, 500, 333, 324, 222, 500, 500, 500, 500, + 333, 556, 546, 604, 333, 324, 656, 278, 278, 333, 222, 737, 556, 333, 556, + 556, 556, 625, 556, 400, 556, 510, 333, 316, 333, 549, 729, 708, 556, 333, + 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 1000, 556, 1000, 556, + 556, 556, 439, 439, 584, 584, 600, 555, 555, 556, 278, 500, 333, 278, 750, + 604, 1000, 556, 834, 333, 556, 556, 333, 556, 556, 500, 556, 556, 556, 556, + 611, 333, 294, 584, 549, 556, 556, 333, 333, 556, 556, 556, 594, 604, 333, + 398, 222, 278, 278, 278, 278, 278, 444, 278, 713, 274, 604, 604, 719, 604, + 604, 1052, 222, 222, 222, 222, 222, 278, 222, 222, 500, 500, 500, 500, 222, + 222, 492, 281, 222, 400, 584, 549, 708, 556, 584, 222, 494, 222, 708, 833, + 552, 750, 333, 584, 188, 548, 584, 500, 750, 556, 556, 615, 556, 556, 556, + 333, 549, 556, 500, 556, 556, 556, 556, 556, 556, 944, 333, 556, 556, 556, + 779, 779, 556, 556, 556, 834, 834, 834, 354, 370, 365, 979, 611, 611, 556, + 556, 537, 333, 333, 494, 889, 278, 1000, 1094, 652, 670, 584, 549, 823, 728, + 556, 556, 611, 355, 333, 333, 333, 222, 222, 222, 222, 191, 333, 333, 549, + 333, 333, 737, 584, 573, 333, 708, 500, 500, 500, 500, 500, 500, 354, 556, + 556, 834, 333, 708, 603, 486, 556, 278, 1021, 531, 556, 713, 917, 278, 374, + 278, 354, 278, 542, 556, 556, 834, 834, 333, 328, 333, 1000, 990, 990, 990, + 990, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 552, 278, 333, 333, + 333, 576, 333, 611, 278, 333, 278, 667, 715, 556, 565, 333, 333, 333, 365, + 768, 612, 167, 278, 750, 333, 500, 500, 556, 708, 550, 550, 550, 550, 556, + 556, 500, 722, 722, 722, 722, 722, 500, 447, 500, 500, 500, 500, 556, 500, + 500, 500, 500, 500, 556, 463, +]; + +export { LiberationSansItalicWidths }; diff --git a/src/core/liberationsans_regular_widths.js b/src/core/liberationsans_regular_widths.js new file mode 100644 index 000000000..fe9658213 --- /dev/null +++ b/src/core/liberationsans_regular_widths.js @@ -0,0 +1,66 @@ +/* Copyright 2021 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. + */ + +// Widths of glyphes in LiberationSans-Regular.ttf. +const LiberationSansRegularWidths = [ + 365, 0, 667, 1000, 1000, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, + 667, 667, 667, 667, 722, 722, 722, 722, 722, 722, 667, 722, 722, 722, 668, + 667, 667, 667, 667, 667, 667, 667, 667, 667, 723, 667, 667, 784, 722, 838, + 722, 556, 611, 778, 551, 778, 778, 778, 778, 722, 604, 354, 354, 604, 722, + 722, 278, 735, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 384, 278, + 500, 500, 667, 667, 667, 556, 556, 668, 556, 556, 556, 556, 833, 833, 722, + 722, 722, 722, 722, 722, 778, 1000, 778, 778, 778, 778, 778, 778, 778, 748, + 752, 778, 774, 778, 778, 778, 667, 798, 722, 835, 778, 722, 722, 722, 722, + 667, 667, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 625, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, + 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 667, 667, 667, + 667, 667, 618, 611, 611, 611, 611, 611, 778, 667, 722, 722, 722, 722, 722, + 722, 722, 722, 722, 667, 667, 855, 722, 722, 667, 944, 944, 944, 944, 944, + 667, 650, 667, 667, 667, 667, 667, 611, 611, 611, 611, 611, 556, 556, 556, + 556, 333, 556, 889, 889, 1000, 667, 656, 667, 542, 677, 667, 667, 923, 604, + 719, 719, 583, 656, 833, 722, 778, 719, 667, 722, 611, 635, 760, 667, 740, + 667, 917, 938, 792, 885, 656, 719, 1010, 722, 489, 865, 542, 719, 667, 278, + 278, 500, 1057, 1010, 854, 583, 635, 556, 573, 531, 365, 583, 556, 556, 669, + 458, 559, 559, 438, 583, 688, 552, 556, 542, 556, 500, 458, 500, 823, 500, + 573, 521, 802, 823, 625, 719, 521, 510, 750, 542, 411, 556, 365, 510, 500, + 222, 278, 222, 906, 812, 556, 438, 500, 719, 778, 552, 556, 885, 323, 1073, + 556, 578, 578, 556, 667, 278, 556, 549, 556, 556, 1000, 500, 1000, 1000, 500, + 500, 500, 469, 584, 389, 1015, 556, 556, 278, 260, 575, 708, 334, 334, 278, + 278, 333, 260, 350, 500, 500, 333, 500, 500, 500, 500, 333, 556, 525, 604, + 333, 656, 278, 278, 737, 556, 556, 556, 556, 615, 556, 400, 557, 510, 333, + 333, 549, 729, 708, 556, 333, 278, 556, 556, 556, 556, 556, 556, 556, 556, + 556, 1000, 556, 1000, 556, 556, 556, 446, 446, 584, 583, 600, 556, 556, 556, + 278, 500, 333, 278, 750, 604, 1000, 556, 834, 556, 556, 556, 556, 500, 556, + 556, 556, 556, 611, 333, 222, 222, 294, 294, 324, 324, 316, 328, 398, 285, + 333, 584, 549, 556, 556, 333, 333, 556, 556, 556, 594, 604, 333, 222, 278, + 278, 278, 278, 278, 444, 278, 713, 274, 604, 604, 719, 604, 604, 1052, 222, + 222, 222, 222, 222, 278, 222, 222, 500, 500, 500, 500, 222, 222, 500, 292, + 222, 334, 584, 549, 708, 556, 584, 222, 494, 222, 708, 833, 552, 750, 333, + 584, 188, 576, 584, 500, 750, 556, 556, 604, 556, 556, 556, 333, 549, 556, + 500, 556, 556, 556, 556, 556, 556, 944, 333, 556, 556, 556, 781, 781, 556, + 556, 556, 834, 834, 834, 354, 370, 365, 979, 611, 611, 556, 556, 537, 333, + 333, 494, 889, 278, 1000, 1094, 648, 690, 584, 549, 823, 713, 556, 556, 611, + 355, 333, 333, 333, 222, 222, 222, 222, 191, 333, 333, 549, 333, 333, 737, + 584, 569, 333, 708, 500, 500, 500, 500, 500, 500, 354, 556, 556, 834, 708, + 617, 482, 556, 278, 1021, 531, 556, 713, 917, 278, 395, 278, 375, 278, 556, + 556, 556, 834, 834, 333, 333, 1000, 990, 990, 990, 990, 556, 556, 556, 556, + 556, 556, 556, 556, 556, 556, 552, 278, 333, 333, 333, 576, 333, 611, 278, + 333, 278, 667, 722, 556, 559, 333, 333, 333, 333, 333, 333, 333, 365, 768, + 612, 167, 278, 750, 333, 333, 500, 500, 556, 708, 547, 547, 547, 547, 556, + 556, 500, 722, 722, 722, 722, 722, 500, 448, 500, 500, 500, 500, 556, 500, + 500, 500, 500, 500, 556, 441, +]; + +export { LiberationSansRegularWidths }; diff --git a/src/core/xfa/factory.js b/src/core/xfa/factory.js index 11f305a3e..d1eb6652f 100644 --- a/src/core/xfa/factory.js +++ b/src/core/xfa/factory.js @@ -17,6 +17,7 @@ import { $globalData, $toHTML } from "./xfa_object.js"; import { Binder } from "./bind.js"; import { DataHandler } from "./data.js"; import { FontFinder } from "./fonts.js"; +import { stripQuotes } from "./utils.js"; import { warn } from "../../shared/util.js"; import { XFAParser } from "./parser.js"; @@ -62,6 +63,24 @@ class XFAFactory { setFonts(fonts) { this.form[$globalData].fontFinder = new FontFinder(fonts); + const missingFonts = []; + for (let typeface of this.form[$globalData].usedTypefaces) { + typeface = stripQuotes(typeface); + const font = this.form[$globalData].fontFinder.find(typeface); + if (!font) { + missingFonts.push(typeface); + } + } + + if (missingFonts.length > 0) { + return missingFonts; + } + + return null; + } + + appendFonts(fonts) { + this.form[$globalData].fontFinder.add(fonts); } getPages() { diff --git a/src/core/xfa/fonts.js b/src/core/xfa/fonts.js index 479e6b2cc..b51313d85 100644 --- a/src/core/xfa/fonts.js +++ b/src/core/xfa/fonts.js @@ -21,53 +21,13 @@ class FontFinder { this.cache = new Map(); this.warned = new Set(); this.defaultFont = null; + this.add(pdfFonts); + } + + add(pdfFonts) { for (const pdfFont of pdfFonts) { - const cssFontInfo = pdfFont.cssFontInfo; - const name = cssFontInfo.fontFamily; - let font = this.fonts.get(name); - if (!font) { - font = Object.create(null); - this.fonts.set(name, font); - if (!this.defaultFont) { - this.defaultFont = font; - } - } - let property = ""; - if (cssFontInfo.italicAngle !== "0") { - if (parseFloat(cssFontInfo.fontWeight) >= 700) { - property = "bolditalic"; - } else { - property = "italic"; - } - } else if (parseFloat(cssFontInfo.fontWeight) >= 700) { - property = "bold"; - } - - if (!property) { - if ( - pdfFont.name.includes("Bold") || - (pdfFont.psName && pdfFont.psName.includes("Bold")) - ) { - property = "bold"; - } - if ( - pdfFont.name.includes("Italic") || - pdfFont.name.endsWith("It") || - (pdfFont.psName && - (pdfFont.psName.includes("Italic") || - pdfFont.psName.endsWith("It"))) - ) { - property += "italic"; - } - } - - if (!property) { - property = "regular"; - } - - font[property] = pdfFont; + this.addPdfFont(pdfFont); } - for (const pdfFont of this.fonts.values()) { if (!pdfFont.regular) { pdfFont.regular = pdfFont.italic || pdfFont.bold || pdfFont.bolditalic; @@ -75,6 +35,52 @@ class FontFinder { } } + addPdfFont(pdfFont) { + const cssFontInfo = pdfFont.cssFontInfo; + const name = cssFontInfo.fontFamily; + let font = this.fonts.get(name); + if (!font) { + font = Object.create(null); + this.fonts.set(name, font); + if (!this.defaultFont) { + this.defaultFont = font; + } + } + let property = ""; + if (cssFontInfo.italicAngle !== "0") { + if (parseFloat(cssFontInfo.fontWeight) >= 700) { + property = "bolditalic"; + } else { + property = "italic"; + } + } else if (parseFloat(cssFontInfo.fontWeight) >= 700) { + property = "bold"; + } + + if (!property) { + if ( + pdfFont.name.includes("Bold") || + (pdfFont.psName && pdfFont.psName.includes("Bold")) + ) { + property = "bold"; + } + if ( + pdfFont.name.includes("Italic") || + pdfFont.name.endsWith("It") || + (pdfFont.psName && + (pdfFont.psName.includes("Italic") || pdfFont.psName.endsWith("It"))) + ) { + property += "italic"; + } + } + + if (!property) { + property = "regular"; + } + + font[property] = pdfFont; + } + getDefault() { return this.defaultFont; } diff --git a/src/core/xfa/parser.js b/src/core/xfa/parser.js index f2459e66e..d29cce501 100644 --- a/src/core/xfa/parser.js +++ b/src/core/xfa/parser.js @@ -34,7 +34,9 @@ class XFAParser extends XMLParserBase { super(); this._builder = new Builder(); this._stack = []; - this._globalData = Object.create(null); + this._globalData = { + usedTypefaces: new Set(), + }; this._ids = new Map(); this._current = this._builder.buildRoot(this._ids); this._errorCode = XMLParserErrorCode.NoError; diff --git a/src/core/xfa/template.js b/src/core/xfa/template.js index 830495d7d..db95e17ef 100644 --- a/src/core/xfa/template.js +++ b/src/core/xfa/template.js @@ -2665,6 +2665,11 @@ class Font extends XFAObject { this.fill = null; } + [$clean](builder) { + super[$clean](builder); + this[$globalData].usedTypefaces.add(this.typeface); + } + [$toStyle]() { const style = toStyle(this, "fill"); const color = style.color; diff --git a/src/core/xfa/xhtml.js b/src/core/xfa/xhtml.js index 753fa11da..b4532c312 100644 --- a/src/core/xfa/xhtml.js +++ b/src/core/xfa/xhtml.js @@ -16,6 +16,7 @@ import { $acceptWhitespace, $childrenToHTML, + $clean, $content, $extra, $getChildren, @@ -144,18 +145,23 @@ function mapStyle(styleStr, fontFinder) { return style; } -function checkStyle(style) { - if (!style) { +function checkStyle(node) { + if (!node.style) { return ""; } // Remove any non-allowed keys. - return style + return node.style .trim() .split(/\s*;\s*/) .filter(s => !!s) .map(s => s.split(/\s*:\s*/, 2)) - .filter(([key]) => VALID_STYLES.has(key)) + .filter(([key, value]) => { + if (key === "font-family") { + node[$globalData].usedTypefaces.add(value); + } + return VALID_STYLES.has(key); + }) .map(kv => kv.join(":")) .join(";"); } @@ -165,7 +171,12 @@ const NoWhites = new Set(["body", "html"]); class XhtmlObject extends XmlObject { constructor(attributes, name) { super(XHTML_NS_ID, name); - this.style = checkStyle(attributes.style); + this.style = attributes.style || ""; + } + + [$clean](builder) { + super[$clean](builder); + this.style = checkStyle(this); } [$acceptWhitespace]() { diff --git a/src/core/xfa_fonts.js b/src/core/xfa_fonts.js index ec18545ae..5acf25b5c 100644 --- a/src/core/xfa_fonts.js +++ b/src/core/xfa_fonts.js @@ -22,6 +22,10 @@ import { HelveticaBoldFactors } from "./helvetica_bold.js"; import { HelveticaBoldItalicFactors } from "./helvetica_bold_italic.js"; import { HelveticaItalicFactors } from "./helvetica_italic.js"; import { HelveticaRegularFactors } from "./helvetica_regular.js"; +import { LiberationSansBoldItalicWidths } from "./liberationsans_bold_italic_widths.js"; +import { LiberationSansBoldWidths } from "./liberationsans_bold_widths.js"; +import { LiberationSansItalicWidths } from "./liberationsans_italic_widths.js"; +import { LiberationSansRegularWidths } from "./liberationsans_regular_widths.js"; import { MyriadProBoldFactors } from "./myriadpro_bold.js"; import { MyriadProBoldItalicFactors } from "./myriadpro_bold_italic.js"; import { MyriadProItalicFactors } from "./myriadpro_italic.js"; @@ -36,78 +40,101 @@ const getXFAFontMap = getLookupTableFactory(function (t) { t["MyriadPro-Regular"] = { name: "LiberationSans-Regular", factors: MyriadProRegularFactors, + baseWidths: LiberationSansRegularWidths, }; t["MyriadPro-Bold"] = { name: "LiberationSans-Bold", factors: MyriadProBoldFactors, + baseWidths: LiberationSansBoldWidths, }; t["MyriadPro-It"] = { name: "LiberationSans-Italic", factors: MyriadProItalicFactors, + baseWidths: LiberationSansItalicWidths, }; t["MyriadPro-BoldIt"] = { name: "LiberationSans-BoldItalic", factors: MyriadProBoldItalicFactors, + baseWidths: LiberationSansBoldItalicWidths, }; - t.ArialMT = { - name: "LiberationSans-Regular", - }; - t["Arial-BoldMT"] = { + t.ArialMT = + t.Arial = + t["Arial-Regular"] = + { + name: "LiberationSans-Regular", + baseWidths: LiberationSansRegularWidths, + }; + t["Arial-BoldMT"] = t["Arial-Bold"] = { name: "LiberationSans-Bold", + baseWidths: LiberationSansBoldWidths, }; - t["Arial-ItalicMT"] = { + t["Arial-ItalicMT"] = t["Arial-Italic"] = { name: "LiberationSans-Italic", + baseWidths: LiberationSansItalicWidths, }; - t["Arial-BoldItalicMT"] = { + t["Arial-BoldItalicMT"] = t["Arial-BoldItalic"] = { name: "LiberationSans-BoldItalic", + baseWidths: LiberationSansBoldItalicWidths, }; t["Calibri-Regular"] = { name: "LiberationSans-Regular", factors: CalibriRegularFactors, + baseWidths: LiberationSansRegularWidths, }; t["Calibri-Bold"] = { name: "LiberationSans-Bold", factors: CalibriBoldFactors, + baseWidths: LiberationSansBoldWidths, }; t["Calibri-Italic"] = { name: "LiberationSans-Italic", factors: CalibriItalicFactors, + baseWidths: LiberationSansItalicWidths, }; t["Calibri-BoldItalic"] = { name: "LiberationSans-BoldItalic", factors: CalibriBoldItalicFactors, + baseWidths: LiberationSansBoldItalicWidths, }; t["Segoeui-Regular"] = { name: "LiberationSans-Regular", factors: SegoeuiRegularFactors, + baseWidths: LiberationSansRegularWidths, }; t["Segoeui-Bold"] = { name: "LiberationSans-Bold", factors: SegoeuiBoldFactors, + baseWidths: LiberationSansBoldWidths, }; t["Segoeui-Italic"] = { name: "LiberationSans-Italic", factors: SegoeuiItalicFactors, + baseWidths: LiberationSansItalicWidths, }; t["Segoeui-BoldItalic"] = { name: "LiberationSans-BoldItalic", factors: SegoeuiBoldItalicFactors, + baseWidths: LiberationSansBoldItalicWidths, }; t["Helvetica-Regular"] = { name: "LiberationSans-Regular", factors: HelveticaRegularFactors, + baseWidths: LiberationSansRegularWidths, }; t["Helvetica-Bold"] = { name: "LiberationSans-Bold", factors: HelveticaBoldFactors, + baseWidths: LiberationSansBoldWidths, }; t["Helvetica-Italic"] = { name: "LiberationSans-Italic", factors: HelveticaItalicFactors, + baseWidths: LiberationSansItalicWidths, }; t["Helvetica-BoldItalic"] = { name: "LiberationSans-BoldItalic", factors: HelveticaBoldItalicFactors, + baseWidths: LiberationSansBoldItalicWidths, }; }); @@ -117,4 +144,17 @@ function getXfaFontName(name) { return fontMap[fontName]; } -export { getXfaFontName }; +function getXfaFontWidths(name) { + const info = getXfaFontName(name); + if (!info) { + return null; + } + + const { baseWidths, factors } = info; + if (!factors) { + return baseWidths; + } + return baseWidths.map((w, i) => w * factors[i]); +} + +export { getXfaFontName, getXfaFontWidths };