Skip to content
Merged
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
6 changes: 6 additions & 0 deletions src.csharp/AlphaTab/Core/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ public static string SubstringIndex(this string s, double startIndex, double end
return s.Substring((int) startIndex, (int) (endIndex - startIndex));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ReplaceAll(this string s, string before, string after)
{
return s.Replace(before, after);
}

public static string TypeOf(object? actual)
{
switch (actual)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ internal fun String.substring(startIndex: Double): String {
return this.substring(startIndex.toInt())
}

internal fun String.replaceAll(before:String, after:String): String {
return this.replace(before, after)
}

internal fun IAlphaTabEnum.toDouble(): Double {
return this.value.toDouble()
}
Expand Down
9 changes: 7 additions & 2 deletions src/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class Environment {
/**
* @target web
*/
public static bravuraFontChecker: FontLoadingChecker = new FontLoadingChecker('alphaTab');
public static bravuraFontChecker: FontLoadingChecker = new FontLoadingChecker(['alphaTab']);

/**
* @target web
Expand Down Expand Up @@ -549,14 +549,19 @@ export class Environment {
(Environment.globalThis as any).IntersectionObserver = IntersectionObserverPolyfill;
}

if(!('replaceChildren' in Element.prototype)) {
if (!('replaceChildren' in Element.prototype)) {
Element.prototype.replaceChildren = function (...nodes: (Node | string)[]) {
this.innerHTML = '';
this.append(...nodes);
};
Document.prototype.replaceChildren = Element.prototype.replaceChildren;
DocumentFragment.prototype.replaceChildren = Element.prototype.replaceChildren;
}
if (!('replaceAll' in String.prototype)) {
(String.prototype as any).replaceAll = function (str: string, newStr: string) {
return this.replace(new RegExp(str, 'g'), newStr);
};
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/RenderingResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { Font, FontStyle, FontWeight } from '@src/model/Font';
* @json
*/
export class RenderingResources {
private static sansFont: string = 'Arial';
private static serifFont: string = 'Georgia';
private static sansFont: string = 'Arial, sans-serif';
private static serifFont: string = 'Georgia, serif';

/**
* Gets or sets the font to use for displaying the songs copyright information in the header of the music sheet.
Expand Down
96 changes: 72 additions & 24 deletions src/model/Font.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class FontParser {
public lineHeight: string = 'normal';
public size: string = '1rem';
public families: string[] = [];
public parseOnlyFamilies: boolean = false;

private _tokens: FontParserToken[];
private _currentTokenIndex: number = -1;
Expand Down Expand Up @@ -70,14 +71,27 @@ class FontParser {
}
}

this.fontStyleVariantWeight();
this.fontSizeLineHeight();
if (!this.parseOnlyFamilies) {
this.fontStyleVariantWeight();
this.fontSizeLineHeight();
}
this.fontFamily();
}

public static parseFamilies(value: string): string[] {
const parser = new FontParser(value);
parser.parseOnlyFamilies = true;
parser.parse();
return parser.families;
}

private fontFamily() {
if (!this._currentToken) {
throw new Error(`Missing font list`);
if(this.parseOnlyFamilies) {
return;
} else {
throw new Error(`Missing font list`);
}
}

const familyListInput = this._input.substr(this._currentToken.startPos).trim();
Expand Down Expand Up @@ -263,6 +277,15 @@ class FontParser {
this._currentTokenIndex = -1;
this.nextToken();
}

public static quoteFont(f: string): string {
if(f.indexOf(' ') === -1) {
return f;
}

const escapedQuotes = f.replaceAll('"', '\\"');
return `"${escapedQuotes}"`;
}
}

/**
Expand Down Expand Up @@ -299,7 +322,7 @@ export enum FontWeight {
export class Font {
private _css: string;
private _cssScale: number = 0.0;
private _family: string;
private _families: string[];
private _style: FontStyle;
private _weight: FontWeight;
private _size: number;
Expand All @@ -310,17 +333,33 @@ export class Font {
}

/**
* Gets the font family name.
* Gets the first font family name.
* @deprecated Consider using {@link families} for multi font family support.
*/
public get family(): string {
return this._family;
return this._families[0];
}

/**
* Sets the font family name.
* Sets the font family list.
* @deprecated Consider using {@link families} for multi font family support.
*/
public set family(value: string) {
this._family = value;
this.families = FontParser.parseFamilies(value);
}

/**
* Gets the font family name.
*/
public get families(): string[] {
return this._families;
}

/**
* Sets the font family name.
*/
public set families(value: string[]) {
this._families = value;
this.reset();
}

Expand Down Expand Up @@ -389,13 +428,31 @@ export class Font {
style: FontStyle = FontStyle.Plain,
weight: FontWeight = FontWeight.Regular
) {
this._family = family;
this._families = FontParser.parseFamilies(family);
this._size = size;
this._style = style;
this._weight = weight;
this._css = this.toCssString();
}

/**
* Initializes a new instance of the {@link Font} class.
* @param families The families.
* @param size The size.
* @param style The style.
* @param weight The weight.
*/
public static withFamilyList(
families: string[],
size: number,
style: FontStyle = FontStyle.Plain,
weight: FontWeight = FontWeight.Regular
) {
const f = new Font("", size, style, weight);
f.families = families;
return f;
}

public toCssString(scale: number = 1): string {
if (!this._css || !(Math.abs(scale - this._cssScale) < 0.01)) {
let buf: string = '';
Expand All @@ -407,9 +464,7 @@ export class Font {
}
buf += this.size * scale;
buf += 'px ';
buf += "'";
buf += this.family;
buf += "'";
buf += this.families.map(f => FontParser.quoteFont(f)).join(', ');
this._css = buf;
this._cssScale = scale;
}
Expand All @@ -422,25 +477,18 @@ export class Font {
return null;
case 'object': {
const m = v as Map<string, unknown>;
let family = m.get('family') as string;
let families = m.get('families') as string[];
// tslint:disable-next-line: no-unnecessary-type-assertion
let size = m.get('size')! as number;
let style = JsonHelper.parseEnum<FontStyle>(m.get('style'), FontStyle)!;
let weight = JsonHelper.parseEnum<FontWeight>(m.get('weight'), FontWeight)!;
return new Font(family, size, style, weight);
return Font.withFamilyList(families, size, style, weight);
}
case 'string': {
const parser = new FontParser(v as string);
parser.parse();

let family: string = parser.families[0];
if (
(family.startsWith("'") && family.endsWith("'")) ||
(family.startsWith('"') && family.endsWith('"'))
) {
family = family.substr(1, family.length - 2);
}

let families: string[] = parser.families;
let fontSizeString: string = parser.size.toLowerCase();
let fontSize: number = 0;
// as per https://websemantics.uk/articles/font-size-conversion/
Expand Down Expand Up @@ -502,7 +550,7 @@ export class Font {
break;
}

return new Font(family, fontSize, fontStyle, fontWeight);
return Font.withFamilyList(families, fontSize, fontStyle, fontWeight);
}
default:
return null;
Expand All @@ -511,7 +559,7 @@ export class Font {

public static toJson(font: Font): Map<string, unknown> {
const o = new Map<string, unknown>();
o.set('family', font.family);
o.set('families', font.families);
o.set('size', font.size);
o.set('style', font.style as number);
o.set('weight', font.weight as number);
Expand Down
6 changes: 3 additions & 3 deletions src/platform/javascript/BrowserUiFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ export class BrowserUiFacade implements IUiFacade<unknown> {
}

private registerFontChecker(font: Font): void {
if (!this._fontCheckers.has(font.family)) {
let checker: FontLoadingChecker = new FontLoadingChecker(font.family);
this._fontCheckers.set(font.family, checker);
if (!this._fontCheckers.has(font.families.join(', '))) {
let checker: FontLoadingChecker = new FontLoadingChecker(font.families);
this._fontCheckers.set(font.families.join(', '), checker);
checker.fontLoaded.on(this.onFontLoaded.bind(this));
checker.checkForFontAvailability();
}
Expand Down
12 changes: 11 additions & 1 deletion src/platform/svg/FontSizes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,19 @@ export class FontSizes {
}
}

public static measureString(s: string, family: string, size: number, style: FontStyle, weight:FontWeight): number {
public static measureString(s: string, families: string[], size: number, style: FontStyle, weight:FontWeight): number {
let data: Uint8Array;
let dataSize: number = 11;
let family = families[0]; // default to first font

// find a font which is maybe registered already
for(let i = 0; i < families.length; i++) {
if(FontSizes.FontSizeLookupTables.has(families[i])) {
family = families[i];
break;
}
}

if (!FontSizes.FontSizeLookupTables.has(family)) {
FontSizes.generateFontLookup(family);
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/svg/SvgCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export abstract class SvgCanvas implements ICanvas {
if (!text) {
return 0;
}
return FontSizes.measureString(text, this.font.family, this.font.size, this.font.style, this.font.weight);
return FontSizes.measureString(text, this.font.families, this.font.size, this.font.style, this.font.weight);
}

public abstract fillMusicFontSymbol(
Expand Down
2 changes: 1 addition & 1 deletion src/rendering/glyphs/TripletFeelGlyph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class TripletFeelGlyph extends EffectGlyph {
private renderTriplet(cx: number, cy: number, canvas: ICanvas): void {
cy += 2 * this.scale;
let font: Font = this.renderer.resources.effectFont;
canvas.font = new Font(font.family, font.size * 0.8, font.style);
canvas.font = Font.withFamilyList(font.families, font.size * 0.8, font.style);
let rightX: number = cx + TripletFeelGlyph.NoteSeparation * this.scale + 3 * this.scale;
canvas.beginPath();
canvas.moveTo(cx, cy + 3 * this.scale);
Expand Down
2 changes: 1 addition & 1 deletion src/rendering/layout/ScoreLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export abstract class ScoreLayout {
let height: number = Math.floor(size * 2);

const e = new RenderFinishedEventArgs();
const font = new Font(resources.copyrightFont.family, size, FontStyle.Plain, FontWeight.Bold);
const font = Font.withFamilyList(resources.copyrightFont.families, size, FontStyle.Plain, FontWeight.Bold);

this.renderer.canvas!.font = font;

Expand Down
Loading