pdf.js/src/core/xfa_fonts.js
Calixte Denizet 4a4591bd2c XFA - Fix font scale factors (bug 1720888)
- All the scale factors in for the substitution font were wrong because of different glyph positions between Liberation and the other ones:
    - regenerate all the factors
  - Text may have polish chars for example and in this case the glyph widths were wrong:
    - treat substitution font as a composite one
    - add a map glyphIndex to unicode for Liberation in order to generate width array for cid font
2021-07-28 19:10:42 +02:00

303 lines
9.1 KiB
JavaScript

/* 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.
*/
import {
CalibriBoldFactors,
CalibriBoldItalicFactors,
CalibriBoldItalicMetrics,
CalibriBoldMetrics,
CalibriItalicFactors,
CalibriItalicMetrics,
CalibriRegularFactors,
CalibriRegularMetrics,
} from "./calibri_factors.js";
import { Dict, Name } from "./primitives.js";
import {
HelveticaBoldFactors,
HelveticaBoldItalicFactors,
HelveticaBoldItalicMetrics,
HelveticaBoldMetrics,
HelveticaItalicFactors,
HelveticaItalicMetrics,
HelveticaRegularFactors,
HelveticaRegularMetrics,
} from "./helvetica_factors.js";
import {
LiberationSansBoldItalicMapping,
LiberationSansBoldItalicWidths,
LiberationSansBoldMapping,
LiberationSansBoldWidths,
LiberationSansItalicMapping,
LiberationSansItalicWidths,
LiberationSansRegularMapping,
LiberationSansRegularWidths,
} from "./liberationsans_widths.js";
import {
MyriadProBoldFactors,
MyriadProBoldItalicFactors,
MyriadProBoldItalicMetrics,
MyriadProBoldMetrics,
MyriadProItalicFactors,
MyriadProItalicMetrics,
MyriadProRegularFactors,
MyriadProRegularMetrics,
} from "./myriadpro_factors.js";
import {
SegoeuiBoldFactors,
SegoeuiBoldItalicFactors,
SegoeuiBoldItalicMetrics,
SegoeuiBoldMetrics,
SegoeuiItalicFactors,
SegoeuiItalicMetrics,
SegoeuiRegularFactors,
SegoeuiRegularMetrics,
} from "./segoeui_factors.js";
import { getLookupTableFactory } from "./core_utils.js";
import { normalizeFontName } from "./fonts_utils.js";
const getXFAFontMap = getLookupTableFactory(function (t) {
t["MyriadPro-Regular"] = t["PdfJS-Fallback-Regular"] = {
name: "LiberationSans-Regular",
factors: MyriadProRegularFactors,
baseWidths: LiberationSansRegularWidths,
baseMapping: LiberationSansRegularMapping,
metrics: MyriadProRegularMetrics,
};
t["MyriadPro-Bold"] = t["PdfJS-Fallback-Bold"] = {
name: "LiberationSans-Bold",
factors: MyriadProBoldFactors,
baseWidths: LiberationSansBoldWidths,
baseMapping: LiberationSansBoldMapping,
metrics: MyriadProBoldMetrics,
};
t["MyriadPro-It"] =
t["MyriadPro-Italic"] =
t["PdfJS-Fallback-Italic"] =
{
name: "LiberationSans-Italic",
factors: MyriadProItalicFactors,
baseWidths: LiberationSansItalicWidths,
baseMapping: LiberationSansItalicMapping,
metrics: MyriadProItalicMetrics,
};
t["MyriadPro-BoldIt"] =
t["MyriadPro-BoldItalic"] =
t["PdfJS-Fallback-BoldItalic"] =
{
name: "LiberationSans-BoldItalic",
factors: MyriadProBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths,
baseMapping: LiberationSansBoldItalicMapping,
metrics: MyriadProBoldItalicMetrics,
};
t.ArialMT =
t.Arial =
t["Arial-Regular"] =
{
name: "LiberationSans-Regular",
baseWidths: LiberationSansRegularWidths,
baseMapping: LiberationSansRegularMapping,
};
t["Arial-BoldMT"] = t["Arial-Bold"] = {
name: "LiberationSans-Bold",
baseWidths: LiberationSansBoldWidths,
baseMapping: LiberationSansBoldMapping,
};
t["Arial-ItalicMT"] = t["Arial-Italic"] = {
name: "LiberationSans-Italic",
baseWidths: LiberationSansItalicWidths,
baseMapping: LiberationSansItalicMapping,
};
t["Arial-BoldItalicMT"] = t["Arial-BoldItalic"] = {
name: "LiberationSans-BoldItalic",
baseWidths: LiberationSansBoldItalicWidths,
baseMapping: LiberationSansBoldItalicMapping,
};
t["Calibri-Regular"] = {
name: "LiberationSans-Regular",
factors: CalibriRegularFactors,
baseWidths: LiberationSansRegularWidths,
baseMapping: LiberationSansRegularMapping,
metrics: CalibriRegularMetrics,
};
t["Calibri-Bold"] = {
name: "LiberationSans-Bold",
factors: CalibriBoldFactors,
baseWidths: LiberationSansBoldWidths,
baseMapping: LiberationSansBoldMapping,
metrics: CalibriBoldMetrics,
};
t["Calibri-Italic"] = {
name: "LiberationSans-Italic",
factors: CalibriItalicFactors,
baseWidths: LiberationSansItalicWidths,
baseMapping: LiberationSansItalicMapping,
metrics: CalibriItalicMetrics,
};
t["Calibri-BoldItalic"] = {
name: "LiberationSans-BoldItalic",
factors: CalibriBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths,
baseMapping: LiberationSansBoldItalicMapping,
metrics: CalibriBoldItalicMetrics,
};
t["Segoeui-Regular"] = {
name: "LiberationSans-Regular",
factors: SegoeuiRegularFactors,
baseWidths: LiberationSansRegularWidths,
baseMapping: LiberationSansRegularMapping,
metrics: SegoeuiRegularMetrics,
};
t["Segoeui-Bold"] = {
name: "LiberationSans-Bold",
factors: SegoeuiBoldFactors,
baseWidths: LiberationSansBoldWidths,
baseMapping: LiberationSansBoldMapping,
metrics: SegoeuiBoldMetrics,
};
t["Segoeui-Italic"] = {
name: "LiberationSans-Italic",
factors: SegoeuiItalicFactors,
baseWidths: LiberationSansItalicWidths,
baseMapping: LiberationSansItalicMapping,
metrics: SegoeuiItalicMetrics,
};
t["Segoeui-BoldItalic"] = {
name: "LiberationSans-BoldItalic",
factors: SegoeuiBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths,
baseMapping: LiberationSansBoldItalicMapping,
metrics: SegoeuiBoldItalicMetrics,
};
t["Helvetica-Regular"] = t.Helvetica = {
name: "LiberationSans-Regular",
factors: HelveticaRegularFactors,
baseWidths: LiberationSansRegularWidths,
baseMapping: LiberationSansRegularMapping,
metrics: HelveticaRegularMetrics,
};
t["Helvetica-Bold"] = {
name: "LiberationSans-Bold",
factors: HelveticaBoldFactors,
baseWidths: LiberationSansBoldWidths,
baseMapping: LiberationSansBoldMapping,
metrics: HelveticaBoldMetrics,
};
t["Helvetica-Italic"] = {
name: "LiberationSans-Italic",
factors: HelveticaItalicFactors,
baseWidths: LiberationSansItalicWidths,
baseMapping: LiberationSansItalicMapping,
metrics: HelveticaItalicMetrics,
};
t["Helvetica-BoldItalic"] = {
name: "LiberationSans-BoldItalic",
factors: HelveticaBoldItalicFactors,
baseWidths: LiberationSansBoldItalicWidths,
baseMapping: LiberationSansBoldItalicMapping,
metrics: HelveticaBoldItalicMetrics,
};
});
function getXfaFontName(name) {
const fontName = normalizeFontName(name);
const fontMap = getXFAFontMap();
return fontMap[fontName];
}
function getXfaFontWidths(name) {
const info = getXfaFontName(name);
if (!info) {
return null;
}
const { baseWidths, baseMapping, factors } = info;
let rescaledBaseWidths;
if (!factors) {
rescaledBaseWidths = baseWidths;
} else {
rescaledBaseWidths = baseWidths.map((w, i) => w * factors[i]);
}
let currentCode = -2;
let currentArray;
// Widths array for composite font is:
// CharCode1 [10, 20, 30] ...
// which means:
// - CharCode1 has a width equal to 10
// - CharCode1+1 has a width equal to 20
// - CharCode1+2 has a width equal to 30
//
// The baseMapping array contains a map for glyph index to unicode.
// So from baseMapping we'll get sorted unicodes and their positions
// (i.e. glyph indices) and then we put widths in an array for the
// the consecutive unicodes.
const newWidths = [];
for (const [unicode, glyphIndex] of baseMapping
.map(
(charUnicode, index) => [
charUnicode,
index,
] /* collect unicode and glyph index */
)
.sort(
([unicode1], [unicode2]) =>
unicode1 - unicode2 /* order by unicode only */
)) {
if (unicode === -1) {
continue;
}
if (unicode === currentCode + 1) {
currentArray.push(rescaledBaseWidths[glyphIndex]);
currentCode += 1;
} else {
currentCode = unicode;
currentArray = [rescaledBaseWidths[glyphIndex]];
newWidths.push(unicode, currentArray);
}
}
return newWidths;
}
function getXfaFontDict(name) {
const widths = getXfaFontWidths(name);
const dict = new Dict(null);
dict.set("BaseFont", Name.get(name));
dict.set("Type", Name.get("Font"));
dict.set("Subtype", Name.get("CIDFontType2"));
dict.set("Encoding", Name.get("Identity-H"));
dict.set("CIDToGIDMap", Name.get("Identity"));
dict.set("W", widths);
dict.set("FirstChar", widths[0]);
dict.set(
"LastChar",
widths[widths.length - 2] + widths[widths.length - 1].length - 1
);
const descriptor = new Dict(null);
dict.set("FontDescriptor", descriptor);
const systemInfo = new Dict(null);
systemInfo.set("Ordering", "Identity");
systemInfo.set("Registry", "Adobe");
systemInfo.set("Supplement", 0);
dict.set("CIDSystemInfo", systemInfo);
return dict;
}
export { getXfaFontDict, getXfaFontName };