diff --git a/html_orig/jssrc/term_screen.js b/html_orig/jssrc/term_screen.js index 153ce31..c37bf68 100644 --- a/html_orig/jssrc/term_screen.js +++ b/html_orig/jssrc/term_screen.js @@ -480,20 +480,18 @@ class TermScreen { Math.ceil(cellWidth), Math.ceil(cellHeight)); ctx.globalCompositeOperation = 'source-over'; - let fontModifiers = {}; + if (!text) return; + let underline = false; let blink = false; let strike = false; - if (attrs & 1) fontModifiers.weight = 'bold'; if (attrs & 1 << 1) ctx.globalAlpha = 0.5; - if (attrs & 1 << 2) fontModifiers.style = 'italic'; if (attrs & 1 << 3) underline = true; if (attrs & 1 << 4) blink = true; if (attrs & 1 << 5) text = TermScreen.alphaToFraktur(text); if (attrs & 1 << 6) strike = true; if (!blink || this.window.blinkStyleOn) { - ctx.font = this.getFont(fontModifiers); ctx.fillStyle = inSelection ? SELECTION_FG : this.colors[fg]; ctx.fillText(text, (x + 0.5) * cellWidth, (y + 0.5) * cellHeight); @@ -545,51 +543,73 @@ class TermScreen { ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; - for (let cell = 0; cell < screenLength; cell++) { - let x = cell % width; - let y = Math.floor(cell / width); - let isCursor = this.cursor.x === x && this.cursor.y === y; - if (this.cursor.hanging) isCursor = false; - let invertForCursor = isCursor && this.cursor.blinkOn && - this.cursor.style === 'block'; - - let text = this.screen[cell]; - let fg = invertForCursor ? this.screenBG[cell] : this.screenFG[cell]; - let bg = invertForCursor ? this.screenFG[cell] : this.screenBG[cell]; - let attrs = this.screenAttrs[cell]; + // bits in the attr value that affect the font + const FONT_MASK = 0b101; - // HACK: ensure cursor is visible - if (invertForCursor && fg === bg) bg = fg === 0 ? 7 : 0; + // Map of (attrs & FONT_MASK) -> Array of cell indices + const fontGroups = new Map(); - this.drawCell({ - x, y, charSize, cellWidth, cellHeight, text, fg, bg, attrs - }); + for (let cell = 0; cell < screenLength; cell++) { + let attrs = this.screenAttrs[cell]; + let font = attrs & FONT_MASK; + if (!fontGroups.has(font)) fontGroups.set(font, []); + fontGroups.get(font).push(cell); + } - if (isCursor && this.cursor.blinkOn && this.cursor.style !== 'block') { - ctx.save(); - ctx.beginPath(); - if (this.cursor.style === 'bar') { - // vertical bar - let barWidth = 2; - ctx.rect(x * cellWidth, y * cellHeight, barWidth, cellHeight) - } else if (this.cursor.style === 'line') { - // underline - let lineHeight = 2; - ctx.rect(x * cellWidth, y * cellHeight + charSize.height, - cellWidth, lineHeight) - } - ctx.clip(); + for (let font of fontGroups.keys()) { + // set font once because in Firefox, this is a really slow action for some + // reason + let modifiers = {} + if (font & 1) modifiers.weight = 'bold' + if (font & 1 << 2) modifiers.style = 'italic' + ctx.font = this.getFont(modifiers) + + for (let cell of fontGroups.get(font)) { + let x = cell % width; + let y = Math.floor(cell / width); + let isCursor = this.cursor.x === x && this.cursor.y === y; + if (this.cursor.hanging) isCursor = false; + let invertForCursor = isCursor && this.cursor.blinkOn && + this.cursor.style === 'block'; + + let text = this.screen[cell]; + let fg = invertForCursor ? this.screenBG[cell] : this.screenFG[cell]; + let bg = invertForCursor ? this.screenFG[cell] : this.screenBG[cell]; + let attrs = this.screenAttrs[cell]; - // swap foreground/background - fg = this.screenBG[cell]; - bg = this.screenFG[cell]; // HACK: ensure cursor is visible - if (fg === bg) bg = fg === 0 ? 7 : 0; + if (invertForCursor && fg === bg) bg = fg === 0 ? 7 : 0; this.drawCell({ x, y, charSize, cellWidth, cellHeight, text, fg, bg, attrs - }, true); - ctx.restore() + }); + + if (isCursor && this.cursor.blinkOn && this.cursor.style !== 'block') { + ctx.save(); + ctx.beginPath(); + if (this.cursor.style === 'bar') { + // vertical bar + let barWidth = 2; + ctx.rect(x * cellWidth, y * cellHeight, barWidth, cellHeight) + } else if (this.cursor.style === 'line') { + // underline + let lineHeight = 2; + ctx.rect(x * cellWidth, y * cellHeight + charSize.height, + cellWidth, lineHeight) + } + ctx.clip(); + + // swap foreground/background + fg = this.screenBG[cell]; + bg = this.screenFG[cell]; + // HACK: ensure cursor is visible + if (fg === bg) bg = fg === 0 ? 7 : 0; + + this.drawCell({ + x, y, charSize, cellWidth, cellHeight, text, fg, bg, attrs + }, true); + ctx.restore() + } } } }