Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Remove TextFormatter - with Bravura and Petaluma as text #1466

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions src/annotation.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// [VexFlow](https://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// MIT License
import { Element } from './element';
import { FontInfo } from './font';
import { Font, FontInfo } from './font';
import { Modifier, ModifierPosition } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { Stave } from './stave';
import { Stem } from './stem';
import { StemmableNote } from './stemmablenote';
import { Tables } from './tables';
import { TextFormatter } from './textformatter';
import { Category, isStemmableNote, isTabNote } from './typeguard';
import { log } from './util';

Expand Down Expand Up @@ -84,15 +83,14 @@ export class Annotation extends Modifier {
let maxRightGlyphWidth = 0;
for (let i = 0; i < annotations.length; ++i) {
const annotation = annotations[i];
const textFormatter = TextFormatter.create(annotation.textFont);
// Text height is expressed in fractional stave spaces.
const textLines = (5 + textFormatter.maxHeight) / Tables.STAVE_LINE_DISTANCE;
const textLines = (5 + Font.convertSizeToPointValue(annotation.textFont?.size)) / Tables.STAVE_LINE_DISTANCE;
let verticalSpaceNeeded = textLines;

const note = annotation.checkAttachedNote();
const glyphWidth = note.getGlyph().getWidth();
// Get the text width from the font metrics.
const textWidth = textFormatter.getWidthForTextInPx(annotation.text);
const textWidth = Font.measureText(annotation.text, annotation.textFont!).width;
if (annotation.horizontalJustification === AnnotationHorizontalJustify.LEFT) {
maxLeftGlyphWidth = Math.max(glyphWidth, maxLeftGlyphWidth);
leftWidth = Math.max(leftWidth, textWidth) + Annotation.minAnnotationPadding;
Expand Down Expand Up @@ -230,7 +228,6 @@ export class Annotation extends Modifier {
const ctx = this.checkContext();
const note = this.checkAttachedNote();
const stemDirection = note.hasStem() ? note.getStemDirection() : Stem.UP;
const textFormatter = TextFormatter.create(this.textFont);
const start = note.getModifierStartXY(ModifierPosition.ABOVE, this.index);

this.setRendered();
Expand All @@ -245,7 +242,7 @@ export class Annotation extends Modifier {
ctx.setFont(this.textFont);

const text_width = ctx.measureText(this.text).width;
const text_height = textFormatter.maxHeight + 2;
const text_height = Font.convertSizeToPointValue(this.textFont?.size) + 2;
let x;
let y;

Expand Down
9 changes: 3 additions & 6 deletions src/bend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
// MIT License

import { Element } from './element';
import { FontInfo } from './font';
import { Font, FontInfo } from './font';
import { Modifier } from './modifier';
import { ModifierContextState } from './modifiercontext';
import { TextFormatter } from './textformatter';
import { Category, isTabNote } from './typeguard';
import { RuntimeError } from './util';

Expand Down Expand Up @@ -148,15 +147,13 @@ export class Bend extends Modifier {
return this.text;
}
getTextHeight(): number {
const textFormatter = TextFormatter.create(this.textFont);
return textFormatter.maxHeight;
return Font.convertSizeToPointValue(this.textFont?.size);
}

/** Recalculate width. */
protected updateWidth(): this {
const textFormatter = TextFormatter.create(this.textFont);
const measureText = (text: string) => {
return textFormatter.getWidthForTextInPx(text);
return Font.measureText(text, this.textFont!).width;
};

let totalWidth = 0;
Expand Down
29 changes: 10 additions & 19 deletions src/chordsymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { ModifierContextState } from './modifiercontext';
import { Note } from './note';
import { StemmableNote } from './stemmablenote';
import { Tables } from './tables';
import { TextFormatter } from './textformatter';
import { Category, isStemmableNote } from './typeguard';
import { log } from './util';

Expand Down Expand Up @@ -290,7 +289,7 @@ export class ChordSymbol extends Modifier {

// If there is a symbol-specific offset, add it but consider font
// size since font and glyphs will be interspersed.
const fontSize = symbol.textFormatter.fontSizeInPixels;
const fontSize = Font.convertSizeToPixelValue(symbol.textFont?.size);
const superSubFontSize = fontSize * superSubScale;
if (block.symbolType === SymbolTypes.GLYPH && block.glyph !== undefined) {
block.width = ChordSymbol.getWidthForGlyph(block.glyph) * superSubFontSize;
Expand Down Expand Up @@ -384,9 +383,6 @@ export class ChordSymbol extends Modifier {
protected useKerning: boolean = true;
protected reportWidth: boolean = true;

// Initialized by the constructor via this.setFont().
protected textFormatter!: TextFormatter;

constructor() {
super();
this.resetFont();
Expand Down Expand Up @@ -415,11 +411,11 @@ export class ChordSymbol extends Modifier {
* The offset is specified in `em`. Scale this value by the font size in pixels.
*/
get superscriptOffset(): number {
return ChordSymbol.superscriptOffset * this.textFormatter.fontSizeInPixels;
return ChordSymbol.superscriptOffset * Font.convertSizeToPixelValue(this.textFont?.size);
}

get subscriptOffset(): number {
return ChordSymbol.subscriptOffset * this.textFormatter.fontSizeInPixels;
return ChordSymbol.subscriptOffset * Font.convertSizeToPixelValue(this.textFont?.size);
}

setReportWidth(value: boolean): this {
Expand All @@ -442,7 +438,7 @@ export class ChordSymbol extends Modifier {
}
const bar = this.symbolBlocks[barIndex];
const xoff = bar.width / 4;
const yoff = 0.25 * this.textFormatter.fontSizeInPixels;
const yoff = 0.25 * Font.convertSizeToPixelValue(this.textFont?.size);
let symIndex = 0;
for (symIndex === 0; symIndex < barIndex; ++symIndex) {
const symbol = this.symbolBlocks[symIndex];
Expand Down Expand Up @@ -501,7 +497,7 @@ export class ChordSymbol extends Modifier {
preKernLower = ChordSymbol.lowerKerningText.some((xx) => xx === prevSymbol.text[prevSymbol.text.length - 1]);
}

const kerningOffsetPixels = ChordSymbol.kerningOffset * this.textFormatter.fontSizeInPixels;
const kerningOffsetPixels = ChordSymbol.kerningOffset * Font.convertSizeToPixelValue(this.textFont?.size);
// TODO: adjust kern for font size.
// Where should this constant live?
if (preKernUpper && currSymbol.symbolModifier === SymbolModifiers.SUPERSCRIPT) {
Expand Down Expand Up @@ -547,7 +543,7 @@ export class ChordSymbol extends Modifier {
// rv.width = rv.glyph.getMetrics().width;
// don't set yShift here, b/c we need to do it at formatting time after the font is set.
} else if (symbolType === SymbolTypes.TEXT) {
symbolBlock.width = this.textFormatter.getWidthForTextInEm(symbolBlock.text);
symbolBlock.width = Font.measureText(symbolBlock.text, this.textFont!).width / Font.scaleToPxFrom['em'];
} else if (symbolType === SymbolTypes.LINE) {
symbolBlock.width = params.width;
}
Expand Down Expand Up @@ -646,7 +642,6 @@ export class ChordSymbol extends Modifier {
*/
setFont(f?: string | FontInfo, size?: string | number, weight?: string | number, style?: string): this {
super.setFont(f, size, weight, style);
this.textFormatter = TextFormatter.create(this.textFont);
return this;
}

Expand Down Expand Up @@ -687,15 +682,11 @@ export class ChordSymbol extends Modifier {
let acc = 0;
let i = 0;
for (i = 0; i < text.length; ++i) {
const metrics = this.textFormatter.getGlyphMetrics(text[i]);
if (metrics) {
const yMax = metrics.y_max ?? 0;
acc = yMax < acc ? yMax : acc;
}
const yMax = Font.textMetrics(text[i], this.fontInfo).fontBoundingBoxDescent;
acc = yMax < acc ? yMax : acc;
}

const resolution = this.textFormatter.getResolution();
return i > 0 ? -1 * (acc / resolution) : 0;
return -acc;
}

/** Render text and glyphs above/below the note. */
Expand Down Expand Up @@ -749,7 +740,7 @@ export class ChordSymbol extends Modifier {
// HorizontalJustify.CENTER_STEM
x = note.getStemX() - this.getWidth() / 2;
}
L('Rendering ChordSymbol: ', this.textFormatter, x, y);
L('Rendering ChordSymbol: ', x, y);

this.symbolBlocks.forEach((symbol) => {
const isSuper = ChordSymbol.isSuperscript(symbol);
Expand Down
2 changes: 0 additions & 2 deletions src/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ import { TabStave } from './tabstave';
import { TabTie } from './tabtie';
import { TextBracket, TextBracketPosition } from './textbracket';
import { TextDynamics } from './textdynamics';
import { TextFormatter } from './textformatter';
import { TextJustification, TextNote } from './textnote';
import { TickContext } from './tickcontext';
import { TimeSignature } from './timesignature';
Expand Down Expand Up @@ -167,7 +166,6 @@ export class Flow {
static TabTie = TabTie;
static TextBracket = TextBracket;
static TextDynamics = TextDynamics;
static TextFormatter = TextFormatter;
static TextNote = TextNote;
static TickContext = TickContext;
static TimeSignature = TimeSignature;
Expand Down
51 changes: 51 additions & 0 deletions src/font.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TextMeasure } from './rendercontext';
import { defined } from './util';

export interface FontInfo {
Expand Down Expand Up @@ -51,6 +52,7 @@ export interface FontGlyph {
x_max: number;
y_min?: number;
y_max?: number;
unicode?: number;
ha: number;
leftSideBearing?: number;
advanceWidth?: number;
Expand Down Expand Up @@ -89,6 +91,9 @@ export class Font {
/** Default font size in `pt`. */
static SIZE: number = 10;

/** Canvas used to measure text */
protected static txtCanvas?: HTMLCanvasElement;

// CSS Font Sizes: 36pt == 48px == 3em == 300% == 0.5in
/** Given a length (for units: pt, px, em, %, in, mm, cm) what is the scale factor to convert it to px? */
static scaleToPxFrom: Record<string, number> = {
Expand Down Expand Up @@ -321,6 +326,9 @@ export class Font {
static WEB_FONT_FILES: Record<string /* fontName */, string /* fontPath */> = {
'Roboto Slab': 'robotoslab/RobotoSlab-Medium_2.001.woff',
PetalumaScript: 'petaluma/PetalumaScript_1.10_FS.woff',
//Gonville: 'gonville/Gonville-18_20200703.woff',
Bravura: 'bravura/Bravura_1.392.woff',
Petaluma: 'petaluma/Petaluma_1.065.woff',
};

/**
Expand Down Expand Up @@ -389,6 +397,49 @@ export class Font {
}
return font;
}
static textMetrics(text: string, fontInfo: FontInfo): TextMetrics {
let txtCanvas = this.txtCanvas;
if (!txtCanvas) {
// Create the SVG text element that will be used to measure text in the event
// of a cache miss.
txtCanvas = document.createElement('canvas');
this.txtCanvas = txtCanvas;
}
const context = txtCanvas.getContext('2d');
context!.font = Font.toCSSString(Font.validate(fontInfo));
return context!.measureText(text);
}

/** Return the text bounding box */
static measureText(text: string, fontInfo: FontInfo): TextMeasure {
let txtCanvas = this.txtCanvas;
if (!txtCanvas) {
// Create the SVG text element that will be used to measure text in the event
// of a cache miss.
txtCanvas = document.createElement('canvas');
this.txtCanvas = txtCanvas;
}
const context = txtCanvas.getContext('2d');
context!.font = Font.toCSSString(Font.validate(fontInfo));
const metrics = context!.measureText(text);

let y = 0;
let height = 0;
if (metrics.fontBoundingBoxAscent) {
y = -metrics.fontBoundingBoxAscent;
height = metrics.fontBoundingBoxDescent + metrics.fontBoundingBoxAscent;
} else {
y = -metrics.actualBoundingBoxAscent;
height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
}
// Return x, y, width & height in the same manner as svg getBBox
return {
x: 0,
y: y,
width: metrics.width,
height: height,
};
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// INSTANCE MEMBERS
Expand Down
Loading