diff --git a/demo/client/html/text-demo.html.hbs b/demo/client/html/text-demo.html.hbs
index 073d1f39..eabb16c0 100644
--- a/demo/client/html/text-demo.html.hbs
+++ b/demo/client/html/text-demo.html.hbs
@@ -80,6 +80,12 @@
{{>partials/switch.html id="pf-stem-darkening"
title="Stem Darkening"}}
+
+
+
+
diff --git a/demo/client/src/atlas.ts b/demo/client/src/atlas.ts
index 60caf16f..94e23008 100644
--- a/demo/client/src/atlas.ts
+++ b/demo/client/src/atlas.ts
@@ -35,7 +35,7 @@ export class Atlas {
pixelsPerUnit: number,
rotationAngle: number,
hint: Hint,
- stemDarkeningAmount: glmatrix.vec2):
+ emboldenAmount: glmatrix.vec2):
void {
let nextOrigin = glmatrix.vec2.fromValues(1.0, 1.0);
let shelfBottom = 2.0;
@@ -46,7 +46,7 @@ export class Atlas {
if (metrics == null)
continue;
- const unitMetrics = new UnitMetrics(metrics, rotationAngle, stemDarkeningAmount);
+ const unitMetrics = new UnitMetrics(metrics, rotationAngle, emboldenAmount);
glyph.setPixelLowerLeft(nextOrigin, unitMetrics, pixelsPerUnit);
let pixelOrigin = glyph.calculateSubpixelOrigin(pixelsPerUnit);
diff --git a/demo/client/src/text-demo.ts b/demo/client/src/text-demo.ts
index f9b04d78..f3317323 100644
--- a/demo/client/src/text-demo.ts
+++ b/demo/client/src/text-demo.ts
@@ -122,6 +122,7 @@ class TextDemoController extends DemoAppController {
atlasGlyphs: AtlasGlyph[];
private hintingSelect: HTMLSelectElement;
+ private emboldenInput: HTMLInputElement;
private editTextModal: HTMLElement;
private editTextArea: HTMLTextAreaElement;
@@ -132,6 +133,7 @@ class TextDemoController extends DemoAppController {
private _fontSize: number;
private _rotationAngle: number;
+ private _emboldenAmount: number;
private text: string;
@@ -146,11 +148,16 @@ class TextDemoController extends DemoAppController {
this._fontSize = INITIAL_FONT_SIZE;
this._rotationAngle = 0.0;
+ this._emboldenAmount = 0.0;
this.hintingSelect = unwrapNull(document.getElementById('pf-hinting-select')) as
HTMLSelectElement;
this.hintingSelect.addEventListener('change', () => this.hintingChanged(), false);
+ this.emboldenInput = unwrapNull(document.getElementById('pf-embolden')) as
+ HTMLInputElement;
+ this.emboldenInput.addEventListener('input', () => this.emboldenAmountChanged(), false);
+
this.editTextModal = unwrapNull(document.getElementById('pf-edit-text-modal'));
this.editTextArea = unwrapNull(document.getElementById('pf-edit-text-area')) as
HTMLTextAreaElement;
@@ -167,6 +174,10 @@ class TextDemoController extends DemoAppController {
window.jQuery(this.editTextModal).modal();
}
+ get emboldenAmount(): number {
+ return this._emboldenAmount;
+ }
+
protected createView(gammaLUT: HTMLImageElement,
commonShaderSource: string,
shaderSources: ShaderMap):
@@ -183,6 +194,11 @@ class TextDemoController extends DemoAppController {
this.view.then(view => view.renderer.updateHinting());
}
+ private emboldenAmountChanged(): void {
+ this._emboldenAmount = parseFloat(this.emboldenInput.value);
+ this.view.then(view => view.renderer.updateEmboldenAmount());
+ }
+
private updateText(): void {
this.text = this.editTextArea.value;
window.jQuery(this.editTextModal).modal('hide');
@@ -246,8 +262,12 @@ class TextDemoController extends DemoAppController {
this.view.then(view => view.renderer.relayoutText());
}
+ get unitsPerEm(): number {
+ return this.font.opentypeFont.unitsPerEm;
+ }
+
get pixelsPerUnit(): number {
- return this._fontSize / this.font.opentypeFont.unitsPerEm;
+ return this._fontSize / this.unitsPerEm;
}
get useHinting(): boolean {
@@ -391,6 +411,12 @@ class TextDemoRenderer extends TextRenderer {
return this.renderContext.appController.rotationAngle;
}
+ protected get extraEmboldenAmount(): glmatrix.vec2 {
+ const appController = this.renderContext.appController;
+ const emboldenLength = appController.emboldenAmount * appController.unitsPerEm;
+ return glmatrix.vec2.clone([emboldenLength, emboldenLength]);
+ }
+
prepareToAttachText(): void {
if (this.atlasFramebuffer == null)
this.createAtlasFramebuffer();
@@ -428,6 +454,13 @@ class TextDemoRenderer extends TextRenderer {
this.renderContext.setDirty();
}
+ updateEmboldenAmount(): void {
+ // Likewise, need to relayout the text.
+ this.layoutText();
+ this.buildGlyphs();
+ this.renderContext.setDirty();
+ }
+
viewPanned(): void {
this.buildGlyphs();
this.renderContext.setDirty();
@@ -513,7 +546,7 @@ class TextDemoRenderer extends TextRenderer {
run.recalculatePixelRects(pixelsPerUnit,
rotationAngle,
hint,
- this.stemDarkeningAmount,
+ this.emboldenAmount,
SUBPIXEL_GRANULARITY,
textBounds);
@@ -638,7 +671,7 @@ class TextDemoRenderer extends TextRenderer {
const atlasGlyphUnitMetrics = new UnitMetrics(atlasGlyphMetrics,
rotationAngle,
- this.stemDarkeningAmount);
+ this.emboldenAmount);
const atlasGlyphPixelOrigin =
atlasGlyph.calculateSubpixelOrigin(pixelsPerUnit);
diff --git a/demo/client/src/text-renderer.ts b/demo/client/src/text-renderer.ts
index cbe9c57f..fb432da9 100644
--- a/demo/client/src/text-renderer.ts
+++ b/demo/client/src/text-renderer.ts
@@ -81,7 +81,9 @@ export abstract class TextRenderer extends Renderer {
}
get emboldenAmount(): glmatrix.vec2 {
- return this.stemDarkeningAmount;
+ const emboldenAmount = glmatrix.vec2.create();
+ glmatrix.vec2.add(emboldenAmount, this.extraEmboldenAmount, this.stemDarkeningAmount);
+ return emboldenAmount;
}
get bgColor(): glmatrix.vec4 {
@@ -127,6 +129,10 @@ export abstract class TextRenderer extends Renderer {
return this.meshes == null ? 0 : this.meshes.length;
}
+ protected get extraEmboldenAmount(): glmatrix.vec2 {
+ return glmatrix.vec2.create();
+ }
+
private stemDarkening: StemDarkeningMode;
private subpixelAA: SubpixelAAType;
@@ -162,9 +168,7 @@ export abstract class TextRenderer extends Renderer {
const atlasGlyphMetrics = font.metricsForGlyph(glyph.glyphKey.id);
if (atlasGlyphMetrics == null)
continue;
- const atlasUnitMetrics = new UnitMetrics(atlasGlyphMetrics,
- 0.0,
- this.stemDarkeningAmount);
+ const atlasUnitMetrics = new UnitMetrics(atlasGlyphMetrics, 0.0, this.emboldenAmount);
const pathID = glyph.pathID;
boundingRects[pathID * 4 + 0] = atlasUnitMetrics.left;
@@ -201,7 +205,8 @@ export abstract class TextRenderer extends Renderer {
protected clearForDirectRendering(): void {}
protected buildAtlasGlyphs(atlasGlyphs: AtlasGlyph[]): void {
- const font = this.renderContext.font;
+ const renderContext = this.renderContext;
+ const font = renderContext.font;
const pixelsPerUnit = this.pixelsPerUnit;
const rotationAngle = this.rotationAngle;
const hint = this.createHint();
@@ -211,13 +216,13 @@ export abstract class TextRenderer extends Renderer {
if (atlasGlyphs.length === 0)
return;
- this.renderContext.atlasGlyphs = atlasGlyphs;
- this.renderContext.atlas.layoutGlyphs(atlasGlyphs,
- font,
- pixelsPerUnit,
- rotationAngle,
- hint,
- this.stemDarkeningAmount);
+ renderContext.atlasGlyphs = atlasGlyphs;
+ renderContext.atlas.layoutGlyphs(atlasGlyphs,
+ font,
+ pixelsPerUnit,
+ rotationAngle,
+ hint,
+ this.emboldenAmount);
this.uploadPathTransforms(1);
this.uploadPathColors(1);
@@ -250,10 +255,10 @@ export abstract class TextRenderer extends Renderer {
// the ascenders and x-heights of the glyphs are pixel snapped, while they aren't on macOS.
// But we should really figure out what macOS does…
const ascender = this.renderContext.font.opentypeFont.ascender;
- const stemDarkeningAmount = this.stemDarkeningAmount;
- const stemDarkeningYScale = (ascender + stemDarkeningAmount[1]) / ascender;
+ const emboldenAmount = this.emboldenAmount;
+ const stemDarkeningYScale = (ascender + emboldenAmount[1]) / ascender;
- const stemDarkeningOffset = glmatrix.vec2.clone(stemDarkeningAmount);
+ const stemDarkeningOffset = glmatrix.vec2.clone(emboldenAmount);
glmatrix.vec2.scale(stemDarkeningOffset, stemDarkeningOffset, pixelsPerUnit);
glmatrix.vec2.scale(stemDarkeningOffset, stemDarkeningOffset, SQRT_1_2);
glmatrix.vec2.mul(stemDarkeningOffset, stemDarkeningOffset, [1, stemDarkeningYScale]);
diff --git a/demo/client/src/text.ts b/demo/client/src/text.ts
index 88564cca..66ff6a30 100644
--- a/demo/client/src/text.ts
+++ b/demo/client/src/text.ts
@@ -167,13 +167,13 @@ export class TextRun {
recalculatePixelRects(pixelsPerUnit: number,
rotationAngle: number,
hint: Hint,
- stemDarkeningAmount: glmatrix.vec2,
+ emboldenAmount: glmatrix.vec2,
subpixelGranularity: number,
textFrameBounds: glmatrix.vec4):
void {
for (let index = 0; index < this.glyphIDs.length; index++) {
const metrics = unwrapNull(this.font.metricsForGlyph(this.glyphIDs[index]));
- const unitMetrics = new UnitMetrics(metrics, rotationAngle, stemDarkeningAmount);
+ const unitMetrics = new UnitMetrics(metrics, rotationAngle, emboldenAmount);
const textGlyphOrigin = this.calculatePixelOriginForGlyphAt(index,
pixelsPerUnit,
rotationAngle,
@@ -381,11 +381,11 @@ export class UnitMetrics {
ascent: number;
descent: number;
- constructor(metrics: Metrics, rotationAngle: number, stemDarkeningAmount: glmatrix.vec2) {
+ constructor(metrics: Metrics, rotationAngle: number, emboldenAmount: glmatrix.vec2) {
const left = metrics.xMin;
const bottom = metrics.yMin;
- const right = metrics.xMax + stemDarkeningAmount[0] * 2;
- const top = metrics.yMax + stemDarkeningAmount[1] * 2;
+ const right = metrics.xMax + emboldenAmount[0] * 2;
+ const top = metrics.yMax + emboldenAmount[1] * 2;
const transform = glmatrix.mat2.create();
glmatrix.mat2.fromRotation(transform, -rotationAngle);