Skip to content

Commit

Permalink
fix: inline eachTokenForScreenRows + get scopes in getTokenColor
Browse files Browse the repository at this point in the history
- This prevents the creation of callback closure (no heap function needed)
- Prevents the creation of temporary token object
- Everything is inlined so the compiler can optimize it
  • Loading branch information
aminya committed Jan 3, 2021
1 parent 02e3bf8 commit 8ce807d
Showing 1 changed file with 39 additions and 54 deletions.
93 changes: 39 additions & 54 deletions lib/mixins/canvas-drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,15 @@ export default class CanvasDrawer extends Mixin {
const editorElement = this.minimap.getTextEditorElement()

// TODO avoid closure: https://stackoverflow.com/a/46256398/7910299
const getTokenColor = this.displayCodeHighlights ? (t) => this.getTokenColor(t, editorElement) : () => this.getDefaultColor(editorElement)
const getTokenColor = this.displayCodeHighlights ? (scopes) => this.getTokenColor(scopes, editorElement) : () => this.getDefaultColor(editorElement)

updateTokensLayer(this.tokensLayer, firstRow, lastRow, this.offscreenFirstRow, this.offscreenLastRow, this.pendingChanges, lineHeight, charHeight, charWidth, canvasWidth, editor, editor.getScreenLineCount(), getInvisibleRegExp(editor), getTokenColor, this.ignoreWhitespacesInTokens, this.maxTokensInOneLine)

if (SPEC_MODE) {
// call the spy for drawLines which is used inside updateTokensLayer
this.drawLines(firstRow, lastRow)
}

const decorations = this.minimap.decorationsByTypeThenRows(firstRow, lastRow)

const renderData = {
Expand Down Expand Up @@ -309,17 +314,16 @@ export default class CanvasDrawer extends Mixin {
}

/**
* Returns the text color for the passed-in `token` object.
* Returns the text color for the passed-in scopes
*
* The color value is read from the DOM by creating a node structure that
* match the token `scope` property.
*
* @param {Object} token a `TextEditor` token
* @param {Array<string>} scopes an array of scopes for a `TextEditor` token (token.scopeDescriptor || token.scopes)
* @param {TextEditorElement} editorElement
* @return {string} the CSS color for the provided token
*/
getTokenColor (token, editorElement) {
const scopes = token.scopeDescriptor || token.scopes
getTokenColor (scopes, editorElement) {
const color = this.DOMStylesReader.retrieveStyleFromDom(scopes, 'color', editorElement, true)

return transparentize(color, this.textOpacity)
Expand Down Expand Up @@ -574,11 +578,6 @@ function updateTokensLayer (tokensLayer, firstRow, lastRow, offscreenFirstRow, o

tokensLayer.clearCanvas()

if (SPEC_MODE) {
// call the spy
this.drawLines(firstRow, lastRow)
}

if (intactRanges.length === 0) {
drawLines(firstRow, lastRow, 0, lineHeight, charHeight, charWidth, canvasWidth, context, editor, editorScreenLineCount, invisibleRegExp, getTokenColor, ignoreWhitespacesInTokens, maxTokensInOneLine)
} else {
Expand Down Expand Up @@ -655,35 +654,6 @@ function drawToken (context, text, color, x, y, charWidth, charHeight, ignoreWhi
}
}

/**
* Returns an array of tokens by line.
*
* @param {number} startRow The start row
* @param {number} endRow The end row
* @param {TextEditor} editor
* @param {number} editorScreenLineCount
* @param {RegExp} invisibleRegExp
* @param {number} maxTokensInOneLine the maximum number of tokens to render in one line
* @return {Array<Array>} An array of tokens by line
* @access private
*/
function eachTokenForScreenRows (startRow, endRow, editor, editorScreenLineCount, invisibleRegExp, maxTokensInOneLine, callback) {
endRow = Math.min(endRow, editorScreenLineCount)

for (let row = startRow; row < endRow; row++) {
const editorTokensForScreenRow = editor.tokensForScreenRow(row)
const numToken = editorTokensForScreenRow.length
const numTokenToRender = Math.min(numToken, maxTokensInOneLine)
for (let iToken = 0; iToken < numTokenToRender; iToken++) {
const token = editorTokensForScreenRow[iToken]
callback(row, {
text: token.text.replace(invisibleRegExp, ' '),
scopes: token.scopes
})
}
}
}

/**
* Draws lines on the corresponding layer.
*
Expand Down Expand Up @@ -714,23 +684,38 @@ function drawLines (firstRow, lastRow, offsetRow, lineHeight, charHeight, charWi

let lastLine, x
let y = (offsetRow * lineHeight) - lineHeight
eachTokenForScreenRows(firstRow, lastRow, editor, editorScreenLineCount, invisibleRegExp, maxTokensInOneLine, (line, token) => {
if (lastLine !== line) {
x = 0
y += lineHeight
lastLine = line
context.clearRect(x, y, canvasWidth, lineHeight)
}
if (x > canvasWidth) { return }

if (emptyLineRegexp.test(token.text)) {
x += token.text.length * charWidth
} else {
x = drawToken(
context, token.text, getTokenColor(token), x, y, charWidth, charHeight, ignoreWhitespacesInTokens
)
// eachTokenForScreenRows inlined
lastRow = Math.min(lastRow, editorScreenLineCount)

for (let line = firstRow; line < lastRow; line++) {
const editorTokensForScreenRow = editor.tokensForScreenRow(line)
const numToken = editorTokensForScreenRow.length
const numTokenToRender = Math.min(numToken, maxTokensInOneLine)
for (let iToken = 0; iToken < numTokenToRender; iToken++) {
const token = editorTokensForScreenRow[iToken]
const tokenText = token.text.replace(invisibleRegExp, ' ')
const tokenScopes = token.scopeDescriptor || token.scopes

// callback inlined
if (lastLine !== line) {
x = 0
y += lineHeight
lastLine = line
context.clearRect(x, y, canvasWidth, lineHeight)
}
if (x > canvasWidth) { continue }

if (emptyLineRegexp.test(tokenText)) {
x += tokenText.length * charWidth
} else {
x = drawToken(
context, tokenText, getTokenColor(tokenScopes), x, y, charWidth, charHeight, ignoreWhitespacesInTokens
)
}
}
})
}

context.fill()
}

Expand Down

0 comments on commit 8ce807d

Please sign in to comment.