From fc2db7dddfd057c6edce60464cc0f6dffd839923 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 10 Jan 2021 17:59:32 +0100 Subject: [PATCH 1/2] Updates and cleanups --- src.compiler/BuilderHelpers.ts | 1 - src.compiler/TranspilerBase.ts | 4 +- src.compiler/csharp/CSharpAstPrinter.ts | 4 +- src.compiler/typescript/SerializerEmitter.ts | 84 +++++++------ src/Environment.ts | 124 +------------------ src/alphatab.ts | 76 ------------ src/exporter/GpifWriter.ts | 11 +- src/generated/NotationSettingsSerializer.ts | 4 +- src/generated/model/MasterBarSerializer.ts | 4 +- src/generated/model/StaffSerializer.ts | 4 +- src/importer/AlphaTexImporter.ts | 4 +- src/importer/BinaryStylesheet.ts | 4 +- src/importer/CapellaParser.ts | 4 +- src/importer/GpifParser.ts | 14 +-- src/importer/MusicXmlImporter.ts | 8 +- src/importer/ScoreLoader.ts | 27 ---- src/io/IOHelper.ts | 103 ++------------- src/model/JsonConverter.ts | 2 +- src/model/Note.ts | 2 +- src/platform/javascript/BrowserUiFacade.ts | 4 +- src/platform/svg/SvgCanvas.ts | 7 +- src/rendering/BarRendererBase.ts | 26 ++-- src/rendering/EffectBand.ts | 4 +- src/rendering/TabBarRenderer.ts | 4 +- src/rendering/glyphs/ChordDiagramGlyph.ts | 4 +- src/rendering/glyphs/ScoreNoteChordGlyph.ts | 16 +-- src/rendering/glyphs/TabNoteChordGlyph.ts | 8 +- src/rendering/layout/PageViewLayout.ts | 4 +- src/rendering/layout/ScoreLayout.ts | 4 +- src/rendering/staves/BarLayoutingInfo.ts | 16 +-- src/rendering/utils/BarCollisionHelper.ts | 4 +- src/rendering/utils/BeamingHelper.ts | 4 +- src/util/FontLoadingChecker.ts | 120 ++++-------------- src/xml/XmlWriter.ts | 12 +- 34 files changed, 176 insertions(+), 545 deletions(-) diff --git a/src.compiler/BuilderHelpers.ts b/src.compiler/BuilderHelpers.ts index bda0c358d..ead0b0e9f 100644 --- a/src.compiler/BuilderHelpers.ts +++ b/src.compiler/BuilderHelpers.ts @@ -1,4 +1,3 @@ -import { indexOf } from 'lodash'; import * as ts from 'typescript'; export function addNewLines(stmts: ts.Statement[]) { diff --git a/src.compiler/TranspilerBase.ts b/src.compiler/TranspilerBase.ts index 453b52709..d5b625399 100644 --- a/src.compiler/TranspilerBase.ts +++ b/src.compiler/TranspilerBase.ts @@ -72,13 +72,13 @@ export default function (emitters: Emitter[], handleErrors: boolean = false) { let diagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); let errorCount = 0; let warningCount = 0; - diagnostics.forEach(d => { + for(const d of diagnostics) { switch (d.category) { case ts.DiagnosticCategory.Error: errorCount++; break; case ts.DiagnosticCategory.Warning: warningCount++; break; } reportDiagnostic(d); - }); + } if (pretty) { reportDiagnostic({ diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index a81f47182..454f4745d 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -94,9 +94,9 @@ export default class CSharpAstPrinter { if (!this._isStartOfLine) { this.writeLine(); } - lines.forEach(line => { + for(const line of lines) { this.writeLine(`/// ${this.escapeXmlDoc(line)}`); - }); + } } else if (lines.length === 1) { if (this._isStartOfLine) { this.writeLine(`/// ${this.escapeXmlDoc(lines[0])}`); diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index b80081dbc..36deb070a 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -290,12 +290,12 @@ function generateToJsonBody( ts.factory.createStringLiteral(jsonName), ts.factory.createAsExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - type.isNullable - ? ts.factory.createUnionTypeNode([ - ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), - ts.factory.createLiteralTypeNode(ts.factory.createNull()) - ]) - : ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) + type.isNullable + ? ts.factory.createUnionTypeNode([ + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]) + : ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) ) ] ))); @@ -344,7 +344,7 @@ function generateToJsonBody( let writeValue: ts.Expression; if (isPrimitiveToJson(mapType.typeArguments![1], typeChecker)) { writeValue = ts.factory.createIdentifier('v'); - } else if(isEnumType(mapType.typeArguments![1])) { + } else if (isEnumType(mapType.typeArguments![1])) { writeValue = ts.factory.createAsExpression( ts.factory.createIdentifier('v'), ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) @@ -358,7 +358,7 @@ function generateToJsonBody( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), undefined, [ - ts.factory.createIdentifier('v') + ts.factory.createIdentifier('v'), ] ); } @@ -387,42 +387,46 @@ function generateToJsonBody( ] )), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - 'forEach' - ), - undefined, - [ - ts.factory.createArrowFunction( - undefined, + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration( + ts.factory.createArrayBindingPattern([ + ts.factory.createBindingElement( + undefined, + undefined, + 'k' + ), + ts.factory.createBindingElement( + undefined, + undefined, + 'v' + ), + ]) + )], + ts.NodeFlags.Const + ), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createBlock([ + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('m'), 'set'), undefined, [ - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') - ], - undefined, - ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('m'), 'set'), - undefined, - [ - // todo: key to string - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('k'), - 'toString' - ), - undefined, - [] + // todo: key to string + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('k'), + 'toString' ), - writeValue - ] - ) + undefined, + [] + ), + writeValue + ] ) - ] - ) + ) + ]) ) ])); } else if (isImmutable(type.type)) { diff --git a/src/Environment.ts b/src/Environment.ts index 752f1d5f8..d9c43eb7f 100644 --- a/src/Environment.ts +++ b/src/Environment.ts @@ -40,7 +40,6 @@ import { TripletFeelEffectInfo } from '@src/rendering/effects/TripletFeelEffectI import { WhammyBarEffectInfo } from '@src/rendering/effects/WhammyBarEffectInfo'; import { WideBeatVibratoEffectInfo } from '@src/rendering/effects/WideBeatVibratoEffectInfo'; import { WideNoteVibratoEffectInfo } from '@src/rendering/effects/WideNoteVibratoEffectInfo'; -import { MusicFontSymbol } from '@src/model/MusicFontSymbol'; import { EffectBarRendererInfo } from '@src/rendering/EffectBarRendererInfo'; import { IScoreRenderer } from '@src/rendering/IScoreRenderer'; import { HorizontalScreenLayout } from '@src/rendering/layout/HorizontalScreenLayout'; @@ -184,8 +183,7 @@ export class Environment { * @target web */ public static bravuraFontChecker: FontLoadingChecker = new FontLoadingChecker( - 'alphaTab', - `&#${MusicFontSymbol.GClef};` + 'alphaTab' ); /** @@ -195,20 +193,6 @@ export class Environment { return 'WorkerGlobalScope' in Environment.globalThis; } - /** - * @target web - */ - public static get supportsFontsApi(): boolean { - return 'fonts' in document && 'load' in (document as any).fonts; - } - - /** - * @target web - */ - public static get supportsTextDecoder(): boolean { - return 'TextDecoder' in Environment.globalThis; - } - /** * @target web */ @@ -227,47 +211,7 @@ export class Environment { if (Environment.isRunningInWorker) { return null; } - // try to build the find the alphaTab script url in case we are not in the webworker already - let scriptElement: HTMLScriptElement = document.currentScript as HTMLScriptElement; - let scriptFile: string | null = null; - - if (!scriptElement) { - // try to get javascript from exception stack - try { - let error: Error = new Error(); - let stack = error.stack; - if (!stack) { - throw error; - } - scriptFile = Environment.scriptFileFromStack(stack); - } catch (e) { - if (e instanceof Error) { - let stack = e.stack; - if (!stack) { - scriptElement = document.querySelector('script[data-alphatab]') as HTMLScriptElement; - } else { - scriptFile = Environment.scriptFileFromStack(stack); - } - } else { - throw e; - } - } - } - - // failed to automatically resolve - if (!scriptFile) { - if (!scriptElement) { - Logger.warning( - 'Environment', - 'Could not automatically find alphaTab script file for worker, please add the data-alphatab attribute to the script tag that includes alphaTab or provide it when initializing alphaTab', - null - ); - } else { - scriptFile = scriptElement.src; - } - } - - return scriptFile; + return (document.currentScript as HTMLScriptElement).src; } /** @@ -295,30 +239,6 @@ export class Environment { } } - /** - * based on https://github.com/JamesMGreene/currentExecutingScript - * @target web - */ - private static scriptFileFromStack(stack: string): string | null { - let matches = stack.match( - '(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?' - ); - if (!matches) { - matches = stack.match( - '^(?:|[^:@]*@|.+\\)@(?=data:text\\/javascript|blob|http[s]?|file)|.+?\\s+(?: at |@)(?:[^:\\(]+ )*[\\(]?)(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?' - ); - if (!matches) { - matches = stack.match( - '\\)@(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?' - ); - if (!matches) { - return null; - } - } - } - return matches[1]; - } - public static renderEngines: Map = Environment.createDefaultRenderEngines(); public static layoutEngines: Map = Environment.createDefaultLayoutEngines(); public static staveProfiles: Map = Environment.createDefaultStaveProfiles(); @@ -528,46 +448,8 @@ export class Environment { */ public static platformInit(): void { Environment.registerJQueryPlugin(); - // polyfills - Math.log2 = Math.log2 - ? Math.log2 - : function (x) { - return Math.log(x) * Math.LOG2E; - }; - if (!Environment.isRunningInWorker) { Environment.HighDpiFactor = window.devicePixelRatio; - - let vbAjaxLoader: string = ''; - vbAjaxLoader += 'Function VbAjaxLoader(method, fileName)' + '\r\n'; - vbAjaxLoader += ' Dim xhr' + '\r\n'; - vbAjaxLoader += ' Set xhr = CreateObject("Microsoft.XMLHTTP")' + '\r\n'; - vbAjaxLoader += ' xhr.Open method, fileName, False' + '\r\n'; - vbAjaxLoader += ' xhr.setRequestHeader "Accept-Charset", "x-user-defined"' + '\r\n'; - vbAjaxLoader += ' xhr.send' + '\r\n'; - vbAjaxLoader += ' Dim byteArray()' + '\r\n'; - vbAjaxLoader += ' if xhr.Status = 200 Then' + '\r\n'; - vbAjaxLoader += ' Dim byteString' + '\r\n'; - vbAjaxLoader += ' Dim i' + '\r\n'; - vbAjaxLoader += ' byteString=xhr.responseBody' + '\r\n'; - vbAjaxLoader += ' ReDim byteArray(LenB(byteString))' + '\r\n'; - vbAjaxLoader += ' For i = 1 To LenB(byteString)' + '\r\n'; - vbAjaxLoader += ' byteArray(i-1) = AscB(MidB(byteString, i, 1))' + '\r\n'; - vbAjaxLoader += ' Next' + '\r\n'; - vbAjaxLoader += ' End If' + '\r\n'; - vbAjaxLoader += ' VbAjaxLoader=byteArray' + '\r\n'; - vbAjaxLoader += 'End Function' + '\r\n'; - let vbAjaxLoaderScript: HTMLScriptElement = document.createElement('script') as HTMLScriptElement; - vbAjaxLoaderScript.setAttribute('type', 'text/vbscript'); - let inlineScript: Node = document.createTextNode(vbAjaxLoader); - vbAjaxLoaderScript.appendChild(inlineScript); - document.addEventListener( - 'DOMContentLoaded', - () => { - document.body.appendChild(vbAjaxLoaderScript); - }, - false - ); } else { AlphaTabWebWorker.init(); AlphaSynthWebWorker.init(); @@ -575,4 +457,4 @@ export class Environment { } } -Environment.platformInit(); +Environment.platformInit(); \ No newline at end of file diff --git a/src/alphatab.ts b/src/alphatab.ts index a43e0d856..fa5f13efc 100644 --- a/src/alphatab.ts +++ b/src/alphatab.ts @@ -1,79 +1,3 @@ -if (!('WorkerGlobalScope' in self)) { - if (!Element.prototype.matches) { - Element.prototype.matches = - (Element.prototype as any).msMatchesSelector || Element.prototype.webkitMatchesSelector; - } - - if (!Element.prototype.closest) { - Element.prototype.closest = function (s: string) { - let el: any = this; - do { - if (Element.prototype.matches.call(el, s)) return el; - el = el.parentElement || el.parentNode; - } while (el !== null && el.nodeType === 1); - return null; - }; - } - - if (window.NodeList && !NodeList.prototype.forEach) { - (NodeList.prototype as any).forEach = Array.prototype.forEach; - } -} - -if (!String.prototype.startsWith) { - String.prototype.startsWith = function (searchString, position) { - position = position || 0; - return this.indexOf(searchString, position) === position; - }; -} - -// https://tc39.github.io/ecma262/#sec-array.prototype.find -if (!Array.prototype.find) { - Object.defineProperty(Array.prototype, 'find', { - value: function (predicate: any) { - // 1. Let O be ? ToObject(this value). - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - let o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - let len = o.length >>> 0; - - // 3. If IsCallable(predicate) is false, throw a TypeError exception. - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - - // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. - let thisArg = arguments[1]; - - // 5. Let k be 0. - let k = 0; - - // 6. Repeat, while k < len - while (k < len) { - // a. Let Pk be ! ToString(k). - // b. Let kValue be ? Get(O, Pk). - // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). - // d. If testResult is true, return kValue. - let kValue = o[k]; - if (predicate.call(thisArg, kValue, k, o)) { - return kValue; - } - // e. Increase k by 1. - k++; - } - - // 7. Return undefined. - return undefined; - }, - configurable: true, - writable: true - }); -} - import { CoreSettings } from '@src/CoreSettings'; import { DisplaySettings, LayoutMode, StaveProfile } from '@src/DisplaySettings'; import { ImporterSettings } from '@src/ImporterSettings'; diff --git a/src/exporter/GpifWriter.ts b/src/exporter/GpifWriter.ts index 83bc3eb91..9637606a9 100644 --- a/src/exporter/GpifWriter.ts +++ b/src/exporter/GpifWriter.ts @@ -1184,8 +1184,7 @@ export class GpifWriter { diagramCollectionProperty.attributes.set('name', name); const diagramCollectionItems = diagramCollectionProperty.addElement('Items'); - staff.chords.forEach((chord, id) => { - + for (const [id, chord] of staff.chords) { const diagramCollectionItem = diagramCollectionItems.addElement('Item'); diagramCollectionItem.attributes.set('id', id); diagramCollectionItem.attributes.set('name', chord.name); @@ -1289,7 +1288,7 @@ export class GpifWriter { degree2Node.attributes.set('interval', 'Fifth'); degree2Node.attributes.set('alteration', 'Perfect'); degree2Node.attributes.set('omitted', 'false'); - }); + } } private writeSimplePropertyNode(parent: XmlNode, propertyName: string, propertyValueTagName: string, propertyValue: string | null) { @@ -1363,7 +1362,7 @@ export class GpifWriter { private writeInstrumentSetNode(trackNode: XmlNode, track: Track) { const instrumentSet = trackNode.addElement('InstrumentSet'); - const firstStaff:Staff = track.staves[0]; + const firstStaff: Staff = track.staves[0]; instrumentSet.addElement('LineCount').innerText = firstStaff.standardNotationLineCount.toString(); @@ -1538,9 +1537,9 @@ export class GpifWriter { if (masterBar.fermata.size > 0) { const fermatas = parent.addElement('Fermatas'); - masterBar.fermata.forEach((fermata, offset) => { + for (const [offset, fermata] of masterBar.fermata) { this.writeFermata(fermatas, offset, fermata); - }); + } } } diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 9cb1cba31..f1e2b17ee 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -26,7 +26,9 @@ export class NotationSettingsSerializer { { const m = new Map(); o.set("elements", m); - obj.elements.forEach((v, k) => m.set(k.toString(), v)); + for (const [k, v] of obj.elements) { + m.set(k.toString(), v); + } } o.set("rhythmMode", (obj.rhythmMode as number)); o.set("rhythmHeight", obj.rhythmHeight); diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index 96e28b47a..4710c0a5b 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -41,7 +41,9 @@ export class MasterBarSerializer { { const m = new Map(); o.set("fermata", m); - obj.fermata.forEach((v, k) => m.set(k.toString(), FermataSerializer.toJson(v))); + for (const [k, v] of obj.fermata) { + m.set(k.toString(), FermataSerializer.toJson(v)); + } } o.set("start", obj.start); o.set("isAnacrusis", obj.isAnacrusis); diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 706f892c7..6770de024 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -26,7 +26,9 @@ export class StaffSerializer { { const m = new Map(); o.set("chords", m); - obj.chords.forEach((v, k) => m.set(k.toString(), ChordSerializer.toJson(v))); + for (const [k, v] of obj.chords) { + m.set(k.toString(), ChordSerializer.toJson(v)); + } } o.set("capo", obj.capo); o.set("transpositionPitch", obj.transpositionPitch); diff --git a/src/importer/AlphaTexImporter.ts b/src/importer/AlphaTexImporter.ts index 9e1e3149e..b737d4be4 100644 --- a/src/importer/AlphaTexImporter.ts +++ b/src/importer/AlphaTexImporter.ts @@ -148,9 +148,9 @@ export class AlphaTexImporter extends ScoreImporter { this.consolidate(); this._score.finish(this.settings); this._score.rebuildRepeatGroups(); - this._lyrics.forEach((lyrics, track) => { + for(const [track, lyrics] of this._lyrics) { this._score.tracks[track].applyLyrics(lyrics); - }); + } return this._score; } catch (e) { if (e instanceof AlphaTexError) { diff --git a/src/importer/BinaryStylesheet.ts b/src/importer/BinaryStylesheet.ts index 05a09058d..5d3da3257 100644 --- a/src/importer/BinaryStylesheet.ts +++ b/src/importer/BinaryStylesheet.ts @@ -111,13 +111,13 @@ export class BinaryStylesheet { } public apply(score: Score): void { - this.raw.forEach((value, key) => { + for(const [key, value] of this.raw) { switch (key) { case 'StandardNotation/hideDynamics': score.stylesheet.hideDynamics = value as boolean; break; } - }); + } } public addValue(key: string, value: unknown): void { diff --git a/src/importer/CapellaParser.ts b/src/importer/CapellaParser.ts index e2ba111eb..9bf7ecc72 100644 --- a/src/importer/CapellaParser.ts +++ b/src/importer/CapellaParser.ts @@ -186,7 +186,7 @@ export class CapellaParser { effects: Map, applyEffect: (effect: T, beat: Beat) => void ) { - effects.forEach((effect, startBeat) => { + for(const [startBeat, effect] of effects) { const noteRange = effect.noteRange; let endBeat = startBeat; for (let i = 0; i < noteRange; i++) { @@ -201,7 +201,7 @@ export class CapellaParser { break; } } - }); + } } private parseDom(dom: XmlDocument): void { diff --git a/src/importer/GpifParser.ts b/src/importer/GpifParser.ts index 1168df898..672862bfb 100644 --- a/src/importer/GpifParser.ts +++ b/src/importer/GpifParser.ts @@ -143,10 +143,10 @@ export class GpifParser { this.buildModel(); this.score.finish(settings); if (!this._skipApplyLyrics && this._lyricsByTrack.size > 0) { - this._lyricsByTrack.forEach((lyrics, t) => { + for (const [t, lyrics] of this._lyricsByTrack) { let track: Track = this._tracksById.get(t)!; track.applyLyrics(lyrics); - }); + } } } @@ -1898,7 +1898,7 @@ export class GpifParser { case 'Octave': note.octave = parseInt(c.findChildElement('Number')!.innerText); // when exporting GP6 from GP7 the tone might be missing - if(note.tone === -1) { + if (note.tone === -1) { note.tone = 0; } break; @@ -2244,7 +2244,7 @@ export class GpifParser { if (this._automationsPerTrackIdAndBarIndex.has(trackId)) { const trackAutomations = this._automationsPerTrackIdAndBarIndex.get(trackId)!; - trackAutomations.forEach((automations, barNumber) => { + for (const [barNumber, automations] of trackAutomations) { if (track.staves.length > 0 && barNumber < track.staves[0].bars.length) { const bar = track.staves[0].bars[barNumber]; if (bar.voices.length > 0 && bar.voices[0].beats.length > 0) { @@ -2254,12 +2254,12 @@ export class GpifParser { } } } - }); + } } } // build masterbar automations - this._masterTrackAutomations.forEach((automations, barNumber) => { + for (const [barNumber, automations] of this._masterTrackAutomations) { let masterBar: MasterBar = this.score.masterBars[barNumber]; for (let i: number = 0, j: number = automations.length; i < j; i++) { let automation: Automation = automations[i]; @@ -2273,6 +2273,6 @@ export class GpifParser { masterBar.tempoAutomation = automation; } } - }); + } } } diff --git a/src/importer/MusicXmlImporter.ts b/src/importer/MusicXmlImporter.ts index 5009d3360..07749e529 100644 --- a/src/importer/MusicXmlImporter.ts +++ b/src/importer/MusicXmlImporter.ts @@ -76,12 +76,12 @@ export class MusicXmlImporter extends ScoreImporter { private mergePartGroups(): void { let anyMerged: boolean = false; - this._partGroups.forEach((tracks) =>{ + for(const tracks of this._partGroups.values()) { if (tracks.length > 1) { this.mergeGroup(tracks); anyMerged = true; } - }); + } // if any groups were merged, we need to rebuild the indexes if (anyMerged) { for (let i: number = 0; i < this._score.tracks.length; i++) { @@ -161,11 +161,11 @@ export class MusicXmlImporter extends ScoreImporter { let id: string = element.getAttribute('id'); if (!this._trackById.has(id)) { if (this._trackById.size === 1) { - this._trackById.forEach((t, x)=> { + for(const [x,t] of this._trackById) { if (t.staves.length === 0 || t.staves[0].bars.length === 0) { id = x; } - }); + } if (!this._trackById.has(id)) { return; } diff --git a/src/importer/ScoreLoader.ts b/src/importer/ScoreLoader.ts index 5190e5893..38a3b13ab 100644 --- a/src/importer/ScoreLoader.ts +++ b/src/importer/ScoreLoader.ts @@ -10,8 +10,6 @@ import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; -declare var VbAjaxLoader: any; - /** * The ScoreLoader enables you easy loading of Scores using all * available importers @@ -25,7 +23,6 @@ export class ScoreLoader { * @param settings settings for the score import * @target web */ - // TODO: use promises public static loadScoreAsync( path: string, success: (score: Score) => void, @@ -62,33 +59,9 @@ export class ScoreLoader { } } }; - // IE fallback - if (xhr.responseType !== 'arraybuffer') { - // use VB Loader to load binary array - let vbArr: any = VbAjaxLoader('GET', path); - let fileContents: any = vbArr.toArray(); - // decode byte array to string - let data: string = ''; - let i: number = 0; - while (i < fileContents.length - 1) { - data += (fileContents[i] as number).toString(); - i++; - } - let reader: Uint8Array = ScoreLoader.getBytesFromString(data); - let score: Score = ScoreLoader.loadScoreFromBytes(reader, settings); - success(score); - } xhr.send(); } - private static getBytesFromString(s: string): Uint8Array { - let b: Uint8Array = new Uint8Array(s.length); - for (let i: number = 0; i < s.length; i++) { - b[i] = s.charCodeAt(i); - } - return b; - } - /** * Loads the score from the given binary data. * @param data The binary data containing a score in any known file format. diff --git a/src/io/IOHelper.ts b/src/io/IOHelper.ts index 06833a434..7a4083ca4 100644 --- a/src/io/IOHelper.ts +++ b/src/io/IOHelper.ts @@ -1,6 +1,5 @@ import { IReadable } from '@src/io/IReadable'; import { TypeConversions } from '@src/io/TypeConversions'; -import { Environment } from '@src/Environment'; import { IWriteable } from './IWriteable'; export class IOHelper { @@ -117,43 +116,15 @@ export class IOHelper { } public static toString(data: Uint8Array, encoding: string): string { - if (Environment.supportsTextDecoder) { - let detectedEncoding: string | null = IOHelper.detectEncoding(data); - if (detectedEncoding) { - encoding = detectedEncoding; - } - if (!encoding) { - encoding = 'utf-8'; - } - let decoder: TextDecoder = new TextDecoder(encoding); - return decoder.decode(data.buffer); - } else { - // manual UTF8 decoding for older browsers - let s: string = ''; - let i: number = 0; - while (i < data.length) { - let c: number = data[i++]; - if (c < 0x80) { - if (c === 0) { - break; - } - s += String.fromCharCode(c); - } else if (c < 0xe0) { - s += String.fromCharCode(((c & 0x3f) << 6) | (data[i++] & 0x7f)); - } else if (c < 0xf0) { - s += String.fromCharCode(((c & 0x1f) << 12) | ((data[i++] & 0x7f) << 6) | (data[i++] & 0x7f)); - } else { - let u: number = - ((c & 0x0f) << 18) | - ((data[i++] & 0x7f) << 12) | - ((data[i++] & 0x7f) << 6) | - (data[i++] & 0x7f); - s += String.fromCharCode((u >> 18) + 0xd7c0); - s += String.fromCharCode((u & 0x3ff) | 0xdc00); - } - } - return s; + let detectedEncoding: string | null = IOHelper.detectEncoding(data); + if (detectedEncoding) { + encoding = detectedEncoding; + } + if (!encoding) { + encoding = 'utf-8'; } + let decoder: TextDecoder = new TextDecoder(encoding); + return decoder.decode(data.buffer); } private static detectEncoding(data: Uint8Array): string | null { @@ -173,58 +144,8 @@ export class IOHelper { } public static stringToBytes(str: string): Uint8Array { - if (Environment.supportsTextDecoder) { - let decoder: TextEncoder = new TextEncoder(); - return decoder.encode(str); - } else { - // manual UTF8 decoding for older browsers - // https://developer.mozilla.org/de/docs/Web/API/TextEncoder - const Len = str.length; - let resPos = -1; - const resArr = new Uint8Array(Len * 3); - - for (let point = 0, nextcode = 0, i = 0; i !== Len; ) { - point = str.charCodeAt(i); - i += 1; - if (point >= 0xd800 && point <= 0xdbff) { - if (i === Len) { - resArr[(resPos += 1)] = 0xef /*0b11101111*/; - resArr[(resPos += 1)] = 0xbf /*0b10111111*/; - resArr[(resPos += 1)] = 0xbd /*0b10111101*/; - break; - } - // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - nextcode = str.charCodeAt(i); - if (nextcode >= 0xdc00 && nextcode <= 0xdfff) { - point = (point - 0xd800) * 0x400 + nextcode - 0xdc00 + 0x10000; - i += 1; - if (point > 0xffff) { - resArr[(resPos += 1)] = (0x1e /*0b11110*/ << 3) | (point >>> 18); - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | ((point >>> 12) & 0x3f) /*0b00111111*/; - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | ((point >>> 6) & 0x3f) /*0b00111111*/; - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | (point & 0x3f) /*0b00111111*/; - continue; - } - } else { - resArr[(resPos += 1)] = 0xef /*0b11101111*/; - resArr[(resPos += 1)] = 0xbf /*0b10111111*/; - resArr[(resPos += 1)] = 0xbd /*0b10111101*/; - continue; - } - } - if (point <= 0x007f) { - resArr[(resPos += 1)] = (0x0 /*0b0*/ << 7) | point; - } else if (point <= 0x07ff) { - resArr[(resPos += 1)] = (0x6 /*0b110*/ << 5) | (point >>> 6); - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | (point & 0x3f) /*0b00111111*/; - } else { - resArr[(resPos += 1)] = (0xe /*0b1110*/ << 4) | (point >>> 12); - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | ((point >>> 6) & 0x3f) /*0b00111111*/; - resArr[(resPos += 1)] = (0x2 /*0b10*/ << 6) | (point & 0x3f) /*0b00111111*/; - } - } - return resArr.subarray(0, resPos + 1); - } + let decoder: TextEncoder = new TextEncoder(); + return decoder.encode(str); } public static writeInt32BE(o: IWriteable, v: number) { @@ -235,14 +156,14 @@ export class IOHelper { } public static writeInt32LE(o: IWriteable, v: number) { - o.writeByte((v >> 0) & 0xFF); + o.writeByte((v >> 0) & 0xFF); o.writeByte((v >> 8) & 0xFF); o.writeByte((v >> 16) & 0xFF); o.writeByte((v >> 24) & 0xFF); } public static writeUInt16LE(o: IWriteable, v: number) { - o.writeByte((v >> 0) & 0xFF); + o.writeByte((v >> 0) & 0xFF); o.writeByte((v >> 8) & 0xFF); } diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 86cc07567..1d29d0a6a 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -23,7 +23,7 @@ export class JsonConverter { return (Object as any).fromEntries(v); } else { const o: any = {}; - v.forEach((v, k) => o[k] = v); + for (const [k, mv] of v) { o[k] = mv; } return o; } } diff --git a/src/model/Note.ts b/src/model/Note.ts index 810cf9006..0aed2efb2 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -131,7 +131,7 @@ export class Note { /** * Gets or sets the variation of this note. - * * @deprecated + * @deprecated */ public get variation(): number { return this.isPercussion ? PercussionMapper.getElementAndVariation(this)[1] : -1; diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index e3a64dd0f..089a4c681 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -61,11 +61,11 @@ export class BrowserUiFacade implements IUiFacade { } let isAnyNotLoaded = false; - this._fontCheckers.forEach(checker => { + for(const checker of this._fontCheckers.values()) { if (!checker.isFontLoaded) { isAnyNotLoaded = true; } - }); + } if (isAnyNotLoaded) { return false; diff --git a/src/platform/svg/SvgCanvas.ts b/src/platform/svg/SvgCanvas.ts index d032d2591..1b16edb4b 100644 --- a/src/platform/svg/SvgCanvas.ts +++ b/src/platform/svg/SvgCanvas.ts @@ -23,7 +23,7 @@ export abstract class SvgCanvas implements ICanvas { public beginRender(width: number, height: number): void { this.buffer = `\n`; + }px" class="at-surface-svg" style="dominant-baseline: central;">\n`; this._currentPath = ''; this._currentPathIsEmpty = true; this.textBaseline = TextBaseline.Top; @@ -166,11 +166,10 @@ export abstract class SvgCanvas implements ICanvas { switch (this.textBaseline) { case TextBaseline.Top: return `dominant-baseline="hanging"`; - case TextBaseline.Middle: - return `dominant-baseline="central"`; case TextBaseline.Bottom: return `dominant-baseline="bottom"`; - default: + case TextBaseline.Middle: + // middle is set as default on the SVG tag via css return ''; } } diff --git a/src/rendering/BarRendererBase.ts b/src/rendering/BarRendererBase.ts index 95a1b28e3..907e5b9ff 100644 --- a/src/rendering/BarRendererBase.ts +++ b/src/rendering/BarRendererBase.ts @@ -150,9 +150,9 @@ export class BarRendererBase { public scaleToWidth(width: number): void { // preBeat and postBeat glyphs do not get resized let containerWidth: number = width - this._preBeatGlyphs.width - this._postBeatGlyphs.width; - this._voiceContainers.forEach(container => { + for (const container of this._voiceContainers.values()) { container.scaleToWidth(containerWidth); - }); + } this._postBeatGlyphs.x = this._preBeatGlyphs.x + this._preBeatGlyphs.width + containerWidth; this.width = width; } @@ -185,9 +185,9 @@ export class BarRendererBase { if (info.preBeatSize < preSize) { info.preBeatSize = preSize; } - this._voiceContainers.forEach(container => { + for (const container of this._voiceContainers.values()) { container.registerLayoutingInfo(info); - }); + } let postSize: number = this._postBeatGlyphs.width; if (info.postBeatSize < postSize) { info.postBeatSize = postSize; @@ -206,14 +206,14 @@ export class BarRendererBase { this._preBeatGlyphs.width = this.layoutingInfo.preBeatSize; // on beat glyphs we apply the glyph spacing let voiceEnd: number = this._preBeatGlyphs.x + this._preBeatGlyphs.width; - this._voiceContainers.forEach(c => { + for (const c of this._voiceContainers.values()) { c.x = this._preBeatGlyphs.x + this._preBeatGlyphs.width; c.applyLayoutingInfo(this.layoutingInfo); let newEnd: number = c.x + c.width; if (voiceEnd < newEnd) { voiceEnd = newEnd; } - }); + } // on the post glyphs we add the spacing before all other glyphs this._postBeatGlyphs.x = Math.floor(voiceEnd); this._postBeatGlyphs.width = this.layoutingInfo.postBeatSize; @@ -284,14 +284,14 @@ export class BarRendererBase { let voiceContainers: Map = this._voiceContainers; let beatGlyphsStart: number = this.beatGlyphsStart; let postBeatStart: number = beatGlyphsStart; - voiceContainers.forEach(c => { + for (const c of voiceContainers.values()) { c.x = beatGlyphsStart; c.doLayout(); let x: number = c.x + c.width; if (postBeatStart < x) { postBeatStart = x; } - }); + } this._postBeatGlyphs.x = Math.floor(postBeatStart); this.width = Math.ceil(this._postBeatGlyphs.x + this._postBeatGlyphs.width); this.height += this.layoutingInfo.height * this.scale; @@ -330,10 +330,10 @@ export class BarRendererBase { this.paintBackground(cx, cy, canvas); canvas.color = this.resources.mainGlyphColor; this._preBeatGlyphs.paint(cx + this.x, cy + this.y, canvas); - this._voiceContainers.forEach(c => { + for (const c of this._voiceContainers.values()) { canvas.color = c.voice.index === 0 ? this.resources.mainGlyphColor : this.resources.secondaryGlyphColor; c.paint(cx + this.x, cy + this.y, canvas); - }); + } canvas.color = this.resources.mainGlyphColor; this._postBeatGlyphs.paint(cx + this.x, cy + this.y, canvas); } @@ -364,7 +364,7 @@ export class BarRendererBase { barBounds.realBounds.h = this.height; masterBarBounds.addBar(barBounds); - this._voiceContainers.forEach((c, index) => { + for (const [index, c] of this._voiceContainers) { let isEmptyBar: boolean = this.bar.isEmpty && index === 0; if (!c.voice.isEmpty || isEmptyBar) { for (let i: number = 0, j: number = c.beatGlyphs.length; i < j; i++) { @@ -372,7 +372,7 @@ export class BarRendererBase { bc.buildBoundingsLookup(barBounds, cx + this.x + c.x, cy + this.y + c.y, isEmptyBar); } } - }); + } } protected addPostBeatGlyph(g: Glyph): void { @@ -487,7 +487,7 @@ export class BarRendererBase { break; } } - + public completeBeamingHelper(helper: BeamingHelper) { // nothing by default } diff --git a/src/rendering/EffectBand.ts b/src/rendering/EffectBand.ts index 254c792c1..d0a6f9401 100644 --- a/src/rendering/EffectBand.ts +++ b/src/rendering/EffectBand.ts @@ -155,9 +155,9 @@ export class EffectBand extends Glyph { public alignGlyphs(): void { for (let v: number = 0; v < this._effectGlyphs.length; v++) { - this._effectGlyphs[v].forEach((g, beatIndex)=> { + for (const beatIndex of this._effectGlyphs[v].keys()) { this.alignGlyph(this.info.sizingMode, this.renderer.bar.voices[v].beats[beatIndex]); - }); + } } } diff --git a/src/rendering/TabBarRenderer.ts b/src/rendering/TabBarRenderer.ts index 4daa791b5..34b1a9f62 100644 --- a/src/rendering/TabBarRenderer.ts +++ b/src/rendering/TabBarRenderer.ts @@ -206,7 +206,7 @@ export class TabBarRenderer extends BarRendererBase { let notes: TabBeatGlyph = bg.onNotes as TabBeatGlyph; let noteNumbers: TabNoteChordGlyph | null = notes.noteNumbers; if (noteNumbers) { - noteNumbers.notesPerString.forEach((noteNumber, str) => { + for(const [str, noteNumber] of noteNumbers.notesPerString) { if (!noteNumber.isEmpty) { tabNotes[this.bar.staff.tuning.length - str].push( new Float32Array([ @@ -215,7 +215,7 @@ export class TabBarRenderer extends BarRendererBase { ]) ); } - }); + } } } } diff --git a/src/rendering/glyphs/ChordDiagramGlyph.ts b/src/rendering/glyphs/ChordDiagramGlyph.ts index 688c7b54e..7ea5dc2f7 100644 --- a/src/rendering/glyphs/ChordDiagramGlyph.ts +++ b/src/rendering/glyphs/ChordDiagramGlyph.ts @@ -120,12 +120,12 @@ export class ChordDiagramGlyph extends EffectGlyph { } } - barreLookup.forEach((strings, fret) => { + for(const [fret, strings] of barreLookup) { let y: number = cy + fret * fretSpacing + fretSpacing / 2 + this.scale; let xLeft: number = cx + (this._chord.strings.length - strings[1] - 1) * stringSpacing; let xRight: number = cx + (this._chord.strings.length - strings[0] - 1) * stringSpacing; canvas.fillRect(xLeft, y - circleRadius, xRight - xLeft, circleRadius * 2); - }); + } canvas.textAlign = align; canvas.textBaseline = baseline; diff --git a/src/rendering/glyphs/ScoreNoteChordGlyph.ts b/src/rendering/glyphs/ScoreNoteChordGlyph.ts index d9a6db691..442aaee40 100644 --- a/src/rendering/glyphs/ScoreNoteChordGlyph.ts +++ b/src/rendering/glyphs/ScoreNoteChordGlyph.ts @@ -100,14 +100,14 @@ export class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase { public doLayout(): void { super.doLayout(); let direction: BeamDirection = this.direction; - this.aboveBeatEffects.forEach(effect => { + for (const effect of this.aboveBeatEffects.values()) { effect.renderer = this.renderer; effect.doLayout(); - }); - this.belowBeatEffects.forEach(effect => { + } + for (const effect of this.belowBeatEffects.values()) { effect.renderer = this.renderer; effect.doLayout(); - }); + } if (this.beat.isTremolo) { let offset: number = 0; let baseNote: ScoreNoteGlyphInfo = direction === BeamDirection.Up ? this.minNote! : this.maxNote!; @@ -171,15 +171,15 @@ export class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase { belowEffectSpacing *= -1; } - this.aboveBeatEffects.forEach(g => { + for (const g of this.aboveBeatEffects.values()) { aboveBeatEffectsY += aboveEffectSpacing * g.height; g.paint(cx + this.x + 2 * this.scale, cy + this.y + aboveBeatEffectsY, canvas); - }); + } - this.belowBeatEffects.forEach(g => { + for (const g of this.belowBeatEffects.values()) { belowBeatEffectsY += belowEffectSpacing * g.height; g.paint(cx + this.x + 2 * this.scale, cy + this.y + belowBeatEffectsY, canvas); - }); + } super.paint(cx, cy, canvas); if (this._tremoloPicking) { this._tremoloPicking.paint(cx, cy, canvas); diff --git a/src/rendering/glyphs/TabNoteChordGlyph.ts b/src/rendering/glyphs/TabNoteChordGlyph.ts index df9bce8ad..e17a8b8bc 100644 --- a/src/rendering/glyphs/TabNoteChordGlyph.ts +++ b/src/rendering/glyphs/TabNoteChordGlyph.ts @@ -92,13 +92,13 @@ export class TabNoteChordGlyph extends Glyph { let effectY: number = this.getNoteY(this.minStringNote!, NoteYPosition.Center) + tabHeight / 2; // TODO: take care of actual glyph height let effectSpacing: number = 7 * this.scale; - this.beatEffects.forEach(g => { + for (const g of this.beatEffects.values()) { g.y += effectY; g.x += this.width / 2; g.renderer = this.renderer; effectY += effectSpacing; g.doLayout(); - }); + } this.width = w; } @@ -126,9 +126,9 @@ export class TabNoteChordGlyph extends Glyph { g.paint(cx, cy, canvas); } canvas.textBaseline = oldBaseLine; - this.beatEffects.forEach(g => { + for(const g of this.beatEffects.values()) { g.paint(cx, cy, canvas); - }); + } } public updateBeamingHelper(cx: number): void { diff --git a/src/rendering/layout/PageViewLayout.ts b/src/rendering/layout/PageViewLayout.ts index 344392a0c..d5844e6dc 100644 --- a/src/rendering/layout/PageViewLayout.ts +++ b/src/rendering/layout/PageViewLayout.ts @@ -198,9 +198,9 @@ export class PageViewLayout extends ScoreLayout { canvas.beginRender(this.width, y); canvas.color = res.scoreInfoColor; canvas.textAlign = TextAlign.Center; - this.scoreInfoGlyphs.forEach(g => { + for(const g of this.scoreInfoGlyphs.values()) { g.paint(0, 0, canvas); - }); + } let result: unknown = canvas.endRender(); let e = new RenderFinishedEventArgs(); diff --git a/src/rendering/layout/ScoreLayout.ts b/src/rendering/layout/ScoreLayout.ts index f681b2fa4..bf35fde89 100644 --- a/src/rendering/layout/ScoreLayout.ts +++ b/src/rendering/layout/ScoreLayout.ts @@ -151,14 +151,14 @@ export abstract class ScoreLayout { let chords: Map = new Map(); for (let track of this.renderer.tracks!) { for (let staff of track.staves) { - staff.chords.forEach((chord, chordId) => { + for (const [chordId, chord] of staff.chords) { if (!chords.has(chordId)) { if (chord.showDiagram) { chords.set(chordId, chord); this.chordDiagrams!.addChord(chord); } } - }); + } } } } diff --git a/src/rendering/staves/BarLayoutingInfo.ts b/src/rendering/staves/BarLayoutingInfo.ts index afc9c645b..0abfeccbb 100644 --- a/src/rendering/staves/BarLayoutingInfo.ts +++ b/src/rendering/staves/BarLayoutingInfo.ts @@ -107,12 +107,12 @@ export class BarLayoutingInfo { if (this._timeSortedSprings.length > 0) { let smallestDuration: number = duration; let previousSpring: Spring = this._timeSortedSprings[this._timeSortedSprings.length - 1]; - previousSpring.allDurations.forEach(prevDuration => { + for(const prevDuration of previousSpring.allDurations) { let end: number = previousSpring.timePosition + prevDuration; if (end >= start && prevDuration < smallestDuration) { smallestDuration = prevDuration; } - }); + } } spring.longestDuration = duration; spring.postSpringWidth = postSpringSize; @@ -197,7 +197,7 @@ export class BarLayoutingInfo { } public finish(): void { - this.allGraceRods.forEach((s, k) => { + for(const [k,s] of this.allGraceRods) { let offset = 0; if (this.incompleteGraceRods.has(k)) { for (const sp of s) { @@ -214,13 +214,13 @@ export class BarLayoutingInfo { offset -= (s[i].preBeatWidth + s[i].postSpringWidth); } } - }); + } this._incompleteGraceRodsWidth = 0; - this.incompleteGraceRods.forEach(s => { + for(const s of this.incompleteGraceRods.values()) { for (const sp of s) { this._incompleteGraceRodsWidth += sp.preBeatWidth + sp.postSpringWidth; } - }); + } this.calculateSpringConstants(); this.version++; @@ -229,11 +229,11 @@ export class BarLayoutingInfo { private calculateSpringConstants(): void { this._xMin = 0; let springs: Map = this.springs; - springs.forEach(spring => { + for(const spring of springs.values()){ if (spring.springWidth < this._xMin) { this._xMin = spring.springWidth; } - }); + } let totalSpringConstant: number = 0; let sortedSprings: Spring[] = this._timeSortedSprings; if (sortedSprings.length === 0) { diff --git a/src/rendering/utils/BarCollisionHelper.ts b/src/rendering/utils/BarCollisionHelper.ts index d865f6d49..bf301ea19 100644 --- a/src/rendering/utils/BarCollisionHelper.ts +++ b/src/rendering/utils/BarCollisionHelper.ts @@ -45,7 +45,7 @@ export class BarCollisionHelper { public getBeatMinMaxY(): number[] { let minY = -1000; let maxY = -1000; - this.reservedLayoutAreasByDisplayTime.forEach((v, k) => { + for(const v of this.reservedLayoutAreasByDisplayTime.values()) { if (minY === -1000) { minY = v.topY; maxY = v.bottomY; @@ -57,7 +57,7 @@ export class BarCollisionHelper { maxY = v.bottomY; } } - }); + } if (minY === -1000) { return [0, 0]; diff --git a/src/rendering/utils/BeamingHelper.ts b/src/rendering/utils/BeamingHelper.ts index 5d1e9ab99..8b2c23679 100644 --- a/src/rendering/utils/BeamingHelper.ts +++ b/src/rendering/utils/BeamingHelper.ts @@ -130,13 +130,13 @@ export class BeamingHelper { positions.staffId = staffId; positions.up = up; positions.down = down; - this.drawingInfos.forEach((v, _) => { + for(const v of this.drawingInfos.values()) { if (v.startBeat == beat) { v.startX = this.getBeatLineX(beat); } else if (v.endBeat == beat) { v.endX = this.getBeatLineX(beat); } - }); + } } private getOrCreateBeatPositions(beat: Beat): BeatLinePositions { diff --git a/src/util/FontLoadingChecker.ts b/src/util/FontLoadingChecker.ts index ff670d6c9..7c68e3dc3 100644 --- a/src/util/FontLoadingChecker.ts +++ b/src/util/FontLoadingChecker.ts @@ -8,15 +8,13 @@ import { Environment } from '@src/Environment'; */ export class FontLoadingChecker { private _family: string; - private _fallbackText: string; private _isStarted: boolean = false; public isFontLoaded: boolean = false; public fontLoaded: IEventEmitterOfT = new EventEmitterOfT(); - public constructor(family: string, fallbackText: string = 'BESbwy') { + public constructor(family: string) { this._family = family; - this._fallbackText = fallbackText; } public checkForFontAvailability(): void { @@ -43,104 +41,30 @@ export class FontLoadingChecker { Logger.debug('Font', `Start checking for font availablility: ${this._family}`); - if (Environment.supportsFontsApi) { - Logger.debug('Font', `[${this._family}] Font API available`); + Logger.debug('Font', `[${this._family}] Font API available`); - let checkFont = () => { - (document as any).fonts.load(`1em ${this._family}`).then(() => { - Logger.debug('Font', `[${this._family}] Font API signaled loaded`); + let checkFont = () => { + (document as any).fonts.load(`1em ${this._family}`).then(() => { + Logger.debug('Font', `[${this._family}] Font API signaled loaded`); - if ((document as any).fonts.check('1em ' + this._family)) { - Logger.debug('Rendering', `[${this._family}] Font API signaled available`); - this.isFontLoaded = true; - window.clearInterval(failCounterId); - (this.fontLoaded as EventEmitterOfT).trigger(this._family); - } else { - Logger.debug( - 'Font', - `[${this._family}] Font API loaded reported, but font not available, checking later again`, - null - ); - window.setTimeout(() => { - checkFont(); - }, 250); - } - return true; - }); - }; - checkFont(); - } else { - Logger.debug('Font', `[${this._family}] Font API not available, using resize trick`, null); - // based on the idea of https://www.bramstein.com/writing/detecting-system-fonts-without-flash.html - // simply create 3 elements with the 3 default font families and measure them - // then change to the desired font and expect a change on the width - let sans: HTMLElement; - let serif: HTMLElement; - let monospace: HTMLElement; - let initialSansWidth: number = -1; - let initialSerifWidth: number = -1; - let initialMonospaceWidth: number = -1; - let checkFont = () => { - if (!sans) { - sans = this.createCheckerElement('sans-serif'); - serif = this.createCheckerElement('serif'); - monospace = this.createCheckerElement('monospace'); - document.body.appendChild(sans); - document.body.appendChild(serif); - document.body.appendChild(monospace); - initialSansWidth = sans.offsetWidth; - initialSerifWidth = serif.offsetWidth; - initialMonospaceWidth = monospace.offsetWidth; - sans.style.fontFamily = `'${this._family}',sans-serif`; - serif.style.fontFamily = `'${this._family}',serif`; - monospace.style.fontFamily = `'${this._family}',monospace`; - } - let sansWidth: number = sans.offsetWidth; - let serifWidth: number = serif.offsetWidth; - let monospaceWidth: number = monospace.offsetWidth; - if ( - (sansWidth !== initialSansWidth && serifWidth !== initialSerifWidth) || - (sansWidth !== initialSansWidth && monospaceWidth !== initialMonospaceWidth) || - (serifWidth !== initialSerifWidth && monospaceWidth !== initialMonospaceWidth) - ) { - if (sansWidth === serifWidth || sansWidth === monospaceWidth || serifWidth === monospaceWidth) { - document.body.removeChild(sans); - document.body.removeChild(serif); - document.body.removeChild(monospace); - this.isFontLoaded = true; - window.clearInterval(failCounterId); - (this.fontLoaded as EventEmitterOfT).trigger(this._family); - } else { - window.setTimeout(checkFont, 250); - } + if ((document as any).fonts.check('1em ' + this._family)) { + Logger.debug('Rendering', `[${this._family}] Font API signaled available`); + this.isFontLoaded = true; + window.clearInterval(failCounterId); + (this.fontLoaded as EventEmitterOfT).trigger(this._family); } else { - window.setTimeout(checkFont, 250); + Logger.debug( + 'Font', + `[${this._family}] Font API loaded reported, but font not available, checking later again`, + null + ); + window.setTimeout(() => { + checkFont(); + }, 250); } - }; - - let readyState:string = document.readyState; - if (readyState === "complete" - || readyState === "loaded" - || readyState === "interactive") { - checkFont(); - } else { - document.addEventListener('DOMContentLoaded', () => { - checkFont(); - }); - } - } - } - - private createCheckerElement(family: string): HTMLElement { - let checkerElement: HTMLElement = document.createElement('span'); - checkerElement.style.display = 'inline-block'; - checkerElement.style.position = 'absolute'; - checkerElement.style.overflow = 'hidden'; - checkerElement.style.top = '-1000px'; - checkerElement.style.fontSize = '100px'; - checkerElement.style.fontFamily = family; - checkerElement.innerHTML = this._fallbackText; - document.body.appendChild(checkerElement); - return checkerElement; + return true; + }); + }; + checkFont(); } } diff --git a/src/xml/XmlWriter.ts b/src/xml/XmlWriter.ts index 653a49d4d..29a035894 100644 --- a/src/xml/XmlWriter.ts +++ b/src/xml/XmlWriter.ts @@ -32,11 +32,11 @@ export class XmlWriter { this.writeLine(); } this.write(`<${xml.localName}`); - xml.attributes.forEach((value, name) => { + for (const [name, value] of xml.attributes) { this.write(` ${name}="`); this.writeAttributeValue(value); this.write('"'); - }); + } if (xml.childNodes.length === 0) { this.write('/>'); @@ -97,16 +97,16 @@ export class XmlWriter { const c = value.charAt(i); switch (c) { case '<': - this._result.push( '<'); + this._result.push('<'); break; case '>': - this._result.push( '>'); + this._result.push('>'); break; case '&': - this._result.push( '&'); + this._result.push('&'); break; case "'": - this._result.push( '''); + this._result.push('''); break; case '"': this._result.push('"'); From 6bb2747b355134bd44b8368c48e215c97ddf83b0 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 10 Jan 2021 18:17:29 +0100 Subject: [PATCH 2/2] Add support for array bindings on C# compilation --- src.compiler/csharp/CSharpAst.ts | 9 ++- src.compiler/csharp/CSharpAstPrinter.ts | 19 +++++- src.compiler/csharp/CSharpAstTransformer.ts | 64 +++++++++++++------ .../AlphaTab/Core/EcmaScript/MapEntry.cs | 6 ++ src.csharp/AlphaTab/Core/EcmaScript/Set.cs | 13 +++- src/platform/svg/SvgCanvas.ts | 1 + 6 files changed, 89 insertions(+), 23 deletions(-) diff --git a/src.compiler/csharp/CSharpAst.ts b/src.compiler/csharp/CSharpAst.ts index e3719d2e4..268f4869d 100644 --- a/src.compiler/csharp/CSharpAst.ts +++ b/src.compiler/csharp/CSharpAst.ts @@ -42,6 +42,7 @@ export enum SyntaxKind { VariableDeclarationList, VariableDeclaration, + DeconstructDeclaration, CaseClause, DefaultClause, CatchClause, @@ -264,7 +265,8 @@ export enum PrimitiveType { Int, Void, Object, - Dynamic + Dynamic, + Var } export interface PrimitiveTypeNode extends TypeNode { @@ -436,9 +438,14 @@ export interface VariableDeclarationList extends Node { export interface VariableDeclaration extends Node { type: TypeNode; name: string; + deconstructNames?: string[]; initializer?: Expression; } +export interface DeconstructDeclaration extends Node { + names: string[]; +} + export interface ForStatement extends Statement { initializer?: VariableDeclarationList | Expression; condition?: Expression; diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index 454f4745d..27920ba5a 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -94,7 +94,7 @@ export default class CSharpAstPrinter { if (!this._isStartOfLine) { this.writeLine(); } - for(const line of lines) { + for (const line of lines) { this.writeLine(`/// ${this.escapeXmlDoc(line)}`); } } else if (lines.length === 1) { @@ -598,6 +598,9 @@ export default class CSharpAstPrinter { case cs.PrimitiveType.Void: this.write('void'); break; + case cs.PrimitiveType.Var: + this.write('var'); + break; } } @@ -1257,7 +1260,19 @@ export default class CSharpAstPrinter { this.write(', '); } - this.write(d.name); + if (d.deconstructNames) { + this.write('('); + d.deconstructNames.forEach((v, i) => { + if (i > 0) { + this.write(', '); + } + this.write(v); + }) + this.write(')'); + } else { + this.write(d.name); + } + if (d.initializer) { this.write(' = '); this.writeExpression(d.initializer); diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index 0f75ab0ec..bae6f50bb 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -460,6 +460,19 @@ export default class CSharpAstTransformer { return unresolved; } + private createVarTypeNode( + parent: cs.Node | null, + tsNode: ts.Node, + ): cs.PrimitiveTypeNode { + const varNode = { + nodeType: cs.SyntaxKind.PrimitiveTypeNode, + tsNode: tsNode, + parent: parent, + type: cs.PrimitiveType.Var + } as cs.PrimitiveTypeNode; + return varNode; + } + public visitTestClass(d: ts.CallExpression): void { const csClass: cs.ClassDeclaration = { visibility: cs.Visibility.Public, @@ -1366,34 +1379,47 @@ export default class CSharpAstTransformer { return variableStatement; } private visitVariableDeclaration(parent: cs.Node, s: ts.VariableDeclaration): cs.VariableDeclaration { - const symbol = this._context.typeChecker.getSymbolAtLocation(s.name); - const type = this._context.typeChecker.getTypeOfSymbolAtLocation(symbol!, s); - const variableStatement = { nodeType: cs.SyntaxKind.VariableDeclaration, parent: parent, tsNode: s, - name: (s.name as ts.Identifier).text, + name: '', type: {} as cs.TypeNode } as cs.VariableDeclaration; - if (parent.nodeType === cs.SyntaxKind.CatchClause) { - variableStatement.type = { - nodeType: cs.SyntaxKind.TypeReference, - parent: variableStatement, - tsNode: s, - reference: 'AlphaTab.Core.EcmaScript.Error' - } as cs.TypeReference; - } else { - variableStatement.type = this.createUnresolvedTypeNode(variableStatement, s.type ?? s, type); - } + if (ts.isIdentifier(s.name)) { + const symbol = this._context.typeChecker.getSymbolAtLocation(s.name); + const type = this._context.typeChecker.getTypeOfSymbolAtLocation(symbol!, s); + + variableStatement.name = s.name.text; + if (parent.nodeType === cs.SyntaxKind.CatchClause) { + variableStatement.type = { + nodeType: cs.SyntaxKind.TypeReference, + parent: variableStatement, + tsNode: s, + reference: 'AlphaTab.Core.EcmaScript.Error' + } as cs.TypeReference; + } else { + variableStatement.type = this.createUnresolvedTypeNode(variableStatement, s.type ?? s, type); + } - variableStatement.type.parent = variableStatement; + variableStatement.type.parent = variableStatement; - if (s.initializer) { - this._declarationOrAssignmentTypeStack.push(type); - variableStatement.initializer = this.visitExpression(variableStatement, s.initializer) ?? undefined; - this._declarationOrAssignmentTypeStack.pop(); + if (s.initializer) { + this._declarationOrAssignmentTypeStack.push(type); + variableStatement.initializer = this.visitExpression(variableStatement, s.initializer) ?? undefined; + this._declarationOrAssignmentTypeStack.pop(); + } + } else if (ts.isArrayBindingPattern(s.name)) { + variableStatement.type = this.createVarTypeNode(variableStatement, s.type ?? s); + variableStatement.deconstructNames = []; + for (const el of s.name.elements) { + if (ts.isOmittedExpression(el)) { + variableStatement.deconstructNames.push('_'); + } else if (ts.isBindingElement(el)) { + variableStatement.deconstructNames.push((el.name as ts.Identifier).text); + } + } } return variableStatement; diff --git a/src.csharp/AlphaTab/Core/EcmaScript/MapEntry.cs b/src.csharp/AlphaTab/Core/EcmaScript/MapEntry.cs index 039f6af3c..b8fdb0719 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/MapEntry.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/MapEntry.cs @@ -10,5 +10,11 @@ public MapEntry(TKey key, TValue value) Key = key; Value = value; } + + public void Deconstruct(out TKey key, out TValue value) + { + key = Key; + value = Value; + } } } diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Set.cs b/src.csharp/AlphaTab/Core/EcmaScript/Set.cs index 0a8a0f324..1a2aeb18d 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Set.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Set.cs @@ -1,10 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace AlphaTab.Core.EcmaScript { - public class Set + public class Set : IEnumerable { private readonly HashSet _data = new HashSet(); @@ -28,5 +29,15 @@ public void ForEach(Action action) action(i); } } + + public IEnumerator GetEnumerator() + { + return _data.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } } } diff --git a/src/platform/svg/SvgCanvas.ts b/src/platform/svg/SvgCanvas.ts index 1b16edb4b..938dda354 100644 --- a/src/platform/svg/SvgCanvas.ts +++ b/src/platform/svg/SvgCanvas.ts @@ -169,6 +169,7 @@ export abstract class SvgCanvas implements ICanvas { case TextBaseline.Bottom: return `dominant-baseline="bottom"`; case TextBaseline.Middle: + default: // middle is set as default on the SVG tag via css return ''; }