Skip to content

Commit f634110

Browse files
authored
Merge pull request #1486 from rvilarl/refactor/metrics
Refactor FontMetrics
2 parents 678fc83 + 710c701 commit f634110

14 files changed

+1158
-897
lines changed

src/annotation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export class Annotation extends Modifier {
7373
// words don't run into each other.
7474
static get minAnnotationPadding(): number {
7575
const musicFont = Tables.currentMusicFont();
76-
return musicFont.lookupMetric('glyphs.noteHead.minPadding');
76+
return musicFont.lookupMetric('noteHead.minPadding');
7777
}
7878
/** Arrange annotations within a `ModifierContext` */
7979
static format(annotations: Annotation[], state: ModifierContextState): boolean {

src/chordsymbol.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { StemmableNote } from './stemmablenote';
1818
import { Tables } from './tables';
1919
import { TextFormatter } from './textformatter';
2020
import { Category, isStemmableNote } from './typeguard';
21-
import { log } from './util';
21+
import { log, RuntimeError } from './util';
2222

2323
// To enable logging for this class. Set `Vex.Flow.ChordSymbol.DEBUG` to `true`.
2424
// eslint-disable-next-line
@@ -37,6 +37,25 @@ export interface ChordSymbolBlock {
3737
glyph?: Glyph;
3838
}
3939

40+
export interface ChordSymbolGlyphMetrics {
41+
leftSideBearing: number;
42+
advanceWidth: number;
43+
yOffset: number;
44+
}
45+
46+
export interface ChordSymbolMetrics {
47+
global: {
48+
superscriptOffset: number;
49+
subscriptOffset: number;
50+
kerningOffset: number;
51+
lowerKerningText: string[];
52+
upperKerningText: string[];
53+
spacing: number;
54+
superSubRatio: number;
55+
};
56+
glyphs: Record<string, ChordSymbolGlyphMetrics>;
57+
}
58+
4059
export enum ChordSymbolHorizontalJustify {
4160
LEFT = 1,
4261
CENTER = 2,
@@ -104,10 +123,9 @@ export class ChordSymbol extends Modifier {
104123
return ChordSymbol.noFormat;
105124
}
106125

107-
// eslint-disable-next-line
108-
static getMetricForGlyph(glyphCode: string): any {
109-
if (ChordSymbol.metrics[glyphCode]) {
110-
return ChordSymbol.metrics[glyphCode];
126+
static getMetricForGlyph(glyphCode: string): ChordSymbolGlyphMetrics | undefined {
127+
if (ChordSymbol.metrics.glyphs[glyphCode]) {
128+
return ChordSymbol.metrics.glyphs[glyphCode];
111129
}
112130
return undefined;
113131
}
@@ -224,9 +242,11 @@ export class ChordSymbol extends Modifier {
224242

225243
static readonly symbolModifiers = SymbolModifiers;
226244

227-
// eslint-disable-next-line
228-
static get metrics(): any {
229-
return Tables.currentMusicFont().getMetrics().glyphs.chordSymbol;
245+
static get metrics(): ChordSymbolMetrics {
246+
const chordSymbol = Tables.currentMusicFont().getMetrics().chordSymbol;
247+
248+
if (!chordSymbol) throw new RuntimeError('BadMetrics', `chordSymbol missing`);
249+
return chordSymbol;
230250
}
231251

232252
static get lowerKerningText(): string[] {
@@ -250,7 +270,7 @@ export class ChordSymbol extends Modifier {
250270

251271
static get minPadding(): number {
252272
const musicFont = Tables.currentMusicFont();
253-
return musicFont.lookupMetric('glyphs.noteHead.minPadding');
273+
return musicFont.lookupMetric('noteHead.minPadding');
254274
}
255275
/**
256276
* Estimate the width of the whole chord symbol, based on the sum of the widths of the individual blocks.

src/clef.ts

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,23 @@ import { defined, log } from './util';
1212
export interface ClefType {
1313
point: number;
1414
code: string;
15-
line?: number;
15+
line: number;
16+
}
17+
18+
export interface ClefAnnotatiomType extends ClefType {
19+
x_shift: number;
20+
code: string;
21+
line: number;
22+
}
23+
24+
export interface ClefMetrics {
25+
width: number;
26+
annotations: {
27+
[key: string]: {
28+
point: number;
29+
[type: string]: { line?: number; shiftX?: number } | number;
30+
};
31+
};
1632
}
1733

1834
// eslint-disable-next-line
@@ -33,20 +49,14 @@ export class Clef extends StaveModifier {
3349
return Category.Clef;
3450
}
3551

36-
annotation?: {
37-
code: string;
38-
line: number;
39-
x_shift: number;
40-
point: number;
41-
};
52+
annotation?: ClefAnnotatiomType;
4253

4354
/**
4455
* The attribute `clef` must be a key from
4556
* `Clef.types`
4657
*/
4758
clef: ClefType = Clef.types['treble'];
4859

49-
protected glyph?: Glyph;
5060
protected attachment?: Glyph;
5161
protected size?: string;
5262
protected type?: string;
@@ -114,18 +124,26 @@ export class Clef extends StaveModifier {
114124
},
115125
tab: {
116126
code: '6stringTabClef',
127+
line: 3,
117128
point: 0,
118129
},
119130
};
120131
}
121132

133+
static get annotationSmufl(): Record<string, string> {
134+
return {
135+
'8va': 'timeSig8',
136+
'8vb': 'timeSig8',
137+
};
138+
}
139+
122140
/** Create a new clef. */
123141
constructor(type: string, size?: string, annotation?: string) {
124142
super();
125143

126144
this.setPosition(StaveModifierPosition.BEGIN);
127145
this.setType(type, size, annotation);
128-
this.setWidth(Tables.currentMusicFont().lookupMetric(`clef.${this.size}.width`));
146+
this.setWidth(Tables.currentMusicFont().lookupMetric(`clef_${this.size}.width`));
129147
L('Creating clef:', type);
130148
}
131149

@@ -141,17 +159,12 @@ export class Clef extends StaveModifier {
141159

142160
const musicFont = Tables.currentMusicFont();
143161

144-
this.clef.point = musicFont.lookupMetric(`clef.${this.size}.point`, 0);
145-
this.glyph = new Glyph(this.clef.code, this.clef.point, {
146-
category: `clef.${this.clef.code}.${this.size}`,
147-
});
148-
149162
// If an annotation, such as 8va, is specified, add it to the Clef object.
150163
if (annotation !== undefined) {
151-
const code = musicFont.lookupMetric(`clef.annotations.${annotation}.smuflCode`);
152-
const point = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.point`);
153-
const line = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.${this.type}.line`);
154-
const x_shift = musicFont.lookupMetric(`clef.annotations.${annotation}.${this.size}.${this.type}.shiftX`);
164+
const code = Clef.annotationSmufl[annotation];
165+
const point = musicFont.lookupMetric(`clef_${this.size}.annotations.${annotation}.point`);
166+
const line = musicFont.lookupMetric(`clef_${this.size}.annotations.${annotation}.${this.type}.line`);
167+
const x_shift = musicFont.lookupMetric(`clef_${this.size}.annotations.${annotation}.${this.type}.shiftX`);
155168

156169
this.annotation = { code, point, line, x_shift };
157170

@@ -176,35 +189,20 @@ export class Clef extends StaveModifier {
176189
/** Set associated stave. */
177190
setStave(stave: Stave): this {
178191
this.stave = stave;
179-
if (this.type === 'tab') {
180-
const glyph = defined(this.glyph, 'ClefError', "Can't set stave without glyph.");
181-
182-
const numLines = this.stave.getNumLines();
183-
const musicFont = Tables.currentMusicFont();
184-
const point = musicFont.lookupMetric(`clef.lineCount.${numLines}.point`);
185-
const shiftY = musicFont.lookupMetric(`clef.lineCount.${numLines}.shiftY`);
186-
glyph.setPoint(point);
187-
glyph.setYShift(shiftY);
188-
}
189192
return this;
190193
}
191194

192195
/** Render clef. */
193196
draw(): void {
194-
const glyph = defined(this.glyph, 'ClefError', "Can't draw clef without glyph.");
195197
const stave = this.checkStave();
196198
const ctx = stave.checkContext();
197199
this.setRendered();
198200

199201
this.applyStyle(ctx);
200202
ctx.openGroup('clef', this.getAttribute('id'));
201-
glyph.setStave(stave);
202-
glyph.setContext(ctx);
203-
if (this.clef.line !== undefined) {
204-
this.placeGlyphOnLine(glyph, stave, this.clef.line);
205-
}
206-
glyph.renderToStave(this.x);
207-
203+
Glyph.renderGlyph(ctx, this.x, stave.getYForLine(this.clef.line), this.clef.point, this.clef.code, {
204+
category: `clef_${this.size}`,
205+
});
208206
if (this.annotation !== undefined && this.attachment !== undefined) {
209207
this.placeGlyphOnLine(this.attachment, stave, this.annotation.line);
210208
this.attachment.setStave(stave);

src/clefnote.ts

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
// Author Taehoon Moon 2014
33
// MIT License
44

5-
import { Clef, ClefType } from './clef';
5+
import { Clef, ClefAnnotatiomType, ClefType } from './clef';
66
import { Glyph } from './glyph';
77
import { Note } from './note';
8-
import { RenderContext } from './rendercontext';
98
import { Category } from './typeguard';
109

1110
/** ClefNote implements clef annotations in measures. */
@@ -14,16 +13,19 @@ export class ClefNote extends Note {
1413
return Category.ClefNote;
1514
}
1615

17-
protected glyph: Glyph;
18-
protected clef: Clef;
16+
protected clef: ClefType;
17+
protected annotation?: ClefAnnotatiomType;
1918
protected type: string;
19+
protected size: string;
2020

2121
constructor(type: string, size?: string, annotation?: string) {
2222
super({ duration: 'b' });
2323
this.type = type;
24-
this.clef = new Clef(type, size, annotation);
25-
this.glyph = new Glyph(this.clef.clef.code, this.clef.clef.point);
26-
this.setWidth(this.glyph.getMetrics().width);
24+
const clef = new Clef(type, size, annotation);
25+
this.clef = clef.clef;
26+
this.annotation = clef.annotation;
27+
this.size = size === undefined ? 'default' : size;
28+
this.setWidth(Glyph.getWidth(this.clef.code, this.clef.point, `clefNote_${this.size}`));
2729

2830
// Note properties
2931
this.ignore_ticks = true;
@@ -32,22 +34,17 @@ export class ClefNote extends Note {
3234
/** Set clef type, size and annotation. */
3335
setType(type: string, size: string, annotation: string): this {
3436
this.type = type;
35-
this.clef = new Clef(type, size, annotation);
36-
this.glyph = new Glyph(this.clef.clef.code, this.clef.clef.point);
37-
this.setWidth(this.glyph.getMetrics().width);
37+
this.size = size;
38+
const clef = new Clef(type, size, annotation);
39+
this.clef = clef.clef;
40+
this.annotation = clef.annotation;
41+
this.setWidth(Glyph.getWidth(this.clef.code, this.clef.point, `clefNote_${this.size}`));
3842
return this;
3943
}
4044

4145
/** Get associated clef. */
4246
getClef(): ClefType {
43-
return this.clef.clef;
44-
}
45-
46-
/** Set associated context. */
47-
setContext(context: RenderContext): this {
48-
super.setContext(context);
49-
this.glyph.setContext(this.getContext());
50-
return this;
47+
return this.clef;
5148
}
5249

5350
preFormat(): this {
@@ -58,26 +55,22 @@ export class ClefNote extends Note {
5855
/** Render clef note. */
5956
draw(): void {
6057
const stave = this.checkStave();
61-
if (!this.glyph.getContext()) {
62-
this.glyph.setContext(this.getContext());
63-
}
58+
const ctx = this.checkContext();
6459

6560
this.setRendered();
6661
const abs_x = this.getAbsoluteX();
6762

68-
this.glyph.setStave(stave);
69-
this.glyph.setYShift(stave.getYForLine(this.clef.clef.line ?? 0) - stave.getYForGlyphs());
70-
this.glyph.renderToStave(abs_x);
63+
Glyph.renderGlyph(ctx, abs_x, stave.getYForLine(this.clef.line), this.clef.point, this.clef.code, {
64+
category: `clefNote_${this.size}`,
65+
});
7166

7267
// If the Vex.Flow.Clef has an annotation, such as 8va, draw it.
73-
if (this.clef.annotation !== undefined) {
74-
const attachment = new Glyph(this.clef.annotation.code, this.clef.annotation.point);
75-
if (!attachment.getContext()) {
76-
attachment.setContext(this.getContext());
77-
}
68+
if (this.annotation !== undefined) {
69+
const attachment = new Glyph(this.annotation.code, this.annotation.point);
70+
attachment.setContext(ctx);
7871
attachment.setStave(stave);
79-
attachment.setYShift(stave.getYForLine(this.clef.annotation.line) - stave.getYForGlyphs());
80-
attachment.setXShift(this.clef.annotation.x_shift);
72+
attachment.setYShift(stave.getYForLine(this.annotation.line) - stave.getYForGlyphs());
73+
attachment.setXShift(this.annotation.x_shift);
8174
attachment.renderToStave(abs_x);
8275
}
8376
}

src/font.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import { ChordSymbolMetrics } from './chordsymbol';
2+
import { ClefMetrics } from './clef';
3+
import { NoteHeadMetrics } from './notehead';
4+
import { OrnamentMetrics } from './ornament';
15
import { StringNumberMetrics } from './stringnumber';
6+
import { TupletMetrics } from './tuplet';
27
import { defined } from './util';
38

49
export interface FontInfo {
@@ -34,18 +39,27 @@ export interface FontMetrics extends Record<string, any> {
3439
smufl: boolean;
3540
stave?: Record<string, number>;
3641
accidental?: Record<string, number>;
37-
// eslint-disable-next-line
38-
clef?: Record<string, any>;
42+
clef_default?: ClefMetrics;
43+
clef_small?: ClefMetrics;
3944
pedalMarking?: Record<string, Record<string, number>>;
4045
digits?: Record<string, number>;
41-
// Not specified in gonville_metrics.ts.
4246
articulation?: Record<string, Record<string, number>>;
4347
tremolo?: Record<string, Record<string, number>>;
44-
// Not specified in bravura_metrics.ts or gonville_metrics.ts.
45-
noteHead?: Record<string, Record<string, number>>;
48+
chordSymbol?: ChordSymbolMetrics;
49+
ornament?: Record<string, OrnamentMetrics>;
50+
noteHead?: NoteHeadMetrics;
4651
stringNumber?: StringNumberMetrics;
47-
// eslint-disable-next-line
48-
glyphs: Record<string, Record<string, any>>;
52+
tuplet?: TupletMetrics;
53+
glyphs: Record<
54+
string,
55+
{
56+
point?: number;
57+
shiftX?: number;
58+
shiftY?: number;
59+
scale?: number;
60+
[key: string]: { point?: number; shiftX?: number; shiftY?: number; scale?: number } | number | undefined;
61+
}
62+
>;
4963
}
5064

5165
export interface FontGlyph {

0 commit comments

Comments
 (0)