Skip to content

Commit

Permalink
Add the possibility to rescale each glyph in a font
Browse files Browse the repository at this point in the history
  - a lot of xfa files are using Myriad pro or Arial fonts without embedding them and some containers have some dimensions based on those font metrics. So not having the exact same font leads to a wrong display.
  - since it's pretty hard to find a replacement font with the exact same metrics, this patch gives the possibility to read glyf table, rescale each glyph and then write a new table.
  - so once PR mozilla#12726 is merged we could rescale for example Helvetica to replace Myriad Pro.
  • Loading branch information
calixteman committed Jun 8, 2021
1 parent d639a27 commit 3b3e54b
Show file tree
Hide file tree
Showing 2 changed files with 754 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/core/fonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js";
import { CFFFont } from "./cff_font.js";
import { FontRendererFactory } from "./font_renderer.js";
import { GlyfTable } from "./glyf.js";
import { IdentityCMap } from "./cmap.js";
import { OpenTypeFileBuilder } from "./opentype_file_builder.js";
import { readUint32 } from "./core_utils.js";
Expand Down Expand Up @@ -2323,6 +2324,51 @@ class Font {
font.pos = (font.start || 0) + tables.maxp.offset;
const version = font.getInt32();
const numGlyphs = font.getUint16();

if (
properties.scaleFactors &&
properties.scaleFactors.length === numGlyphs &&
isTrueType
) {
const { scaleFactors } = properties;
const isGlyphLocationsLong = int16(
tables.head.data[50],
tables.head.data[51]
);

const glyphs = new GlyfTable({
glyfTable: tables.glyf.data,
isGlyphLocationsLong,
locaTable: tables.loca.data,
numGlyphs,
});
glyphs.scale(scaleFactors);

const { glyf, loca, isLocationLong } = glyphs.write();
tables.glyf.data = glyf;
tables.loca.data = loca;

if (isLocationLong !== !!isGlyphLocationsLong) {
tables.head.data[50] = 0;
tables.head.data[51] = isLocationLong ? 1 : 0;
}

const metrics = tables.hmtx.data;

for (let i = 0; i < numGlyphs; i++) {
const j = 4 * i;
const advanceWidth = Math.round(
scaleFactors[i] * int16(metrics[j], metrics[j + 1])
);
metrics[j] = (advanceWidth >> 8) & 0xff;
metrics[j + 1] = advanceWidth & 0xff;
const lsb = Math.round(
scaleFactors[i] * signedInt16(metrics[j + 2], metrics[j + 3])
);
writeSignedInt16(metrics, j + 2, lsb);
}
}

// Glyph 0 is duplicated and appended.
let numGlyphsOut = numGlyphs + 1;
let dupFirstEntry = true;
Expand Down

0 comments on commit 3b3e54b

Please sign in to comment.