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 authored and bh213 committed Jun 3, 2022
1 parent cf6187e commit bb3d8b4
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 bb3d8b4

Please sign in to comment.