From 937116a2808771b8a6b43f8017463b136bffcb2d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 3 Dec 2015 11:26:45 +0100 Subject: [PATCH] Render only visible and yet-to-be-measured block decorations --- spec/text-editor-presenter-spec.coffee | 101 ++++++++++++------------- src/block-decorations-component.coffee | 4 +- src/block-decorations-presenter.js | 15 +++- src/text-editor-component.coffee | 3 + src/text-editor-element.coffee | 3 + src/text-editor-presenter.coffee | 11 ++- 6 files changed, 78 insertions(+), 59 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index be8ce974e..52d2e2bc0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2129,62 +2129,61 @@ describe "TextEditorPresenter", -> isVisible: false } - waitsForStateToUpdate presenter, -> - editor.getBuffer().insert([0, 0], 'Hello world \n\n\n\n') + presenter.setBlockDecorationDimensions(blockDecoration1, 0, 10) + presenter.setBlockDecorationDimensions(blockDecoration4, 0, 20) - runs -> - expectValues stateForBlockDecoration(presenter, blockDecoration1), { - decoration: blockDecoration1 - screenRow: 4 - isVisible: true - } - expectValues stateForBlockDecoration(presenter, blockDecoration2), { - decoration: blockDecoration2 - screenRow: 8 - isVisible: false - } - expectValues stateForBlockDecoration(presenter, blockDecoration3), { - decoration: blockDecoration3 - screenRow: 8 - isVisible: false - } - expectValues stateForBlockDecoration(presenter, blockDecoration4), { - decoration: blockDecoration4 - screenRow: 14 - isVisible: false - } + expectValues stateForBlockDecoration(presenter, blockDecoration1), { + decoration: blockDecoration1 + screenRow: 0 + isVisible: true + } + expectValues stateForBlockDecoration(presenter, blockDecoration2), { + decoration: blockDecoration2 + screenRow: 4 + isVisible: false + } + expectValues stateForBlockDecoration(presenter, blockDecoration3), { + decoration: blockDecoration3 + screenRow: 4 + isVisible: false + } + expect(stateForBlockDecoration(presenter, blockDecoration4)).toBeUndefined() - waitsForStateToUpdate presenter, -> - blockDecoration2.destroy() - blockDecoration4.destroy() - presenter.setBlockDecorationDimensions(blockDecoration1, 0, 20) + presenter.setScrollTop(90) - runs -> - expectValues stateForBlockDecoration(presenter, blockDecoration1), { - decoration: blockDecoration1 - screenRow: 4 - isVisible: true - } - expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined() - expectValues stateForBlockDecoration(presenter, blockDecoration3), { - decoration: blockDecoration3 - screenRow: 8 - isVisible: false - } - expect(stateForBlockDecoration(presenter, blockDecoration4)).toBeUndefined() + expect(stateForBlockDecoration(presenter, blockDecoration1)).toBeUndefined() + expectValues stateForBlockDecoration(presenter, blockDecoration2), { + decoration: blockDecoration2 + screenRow: 4 + isVisible: false + } + expectValues stateForBlockDecoration(presenter, blockDecoration3), { + decoration: blockDecoration3 + screenRow: 4 + isVisible: false + } + expectValues stateForBlockDecoration(presenter, blockDecoration4), { + decoration: blockDecoration4 + screenRow: 10 + isVisible: true + } - presenter.setScrollTop(80) + presenter.invalidateBlockDecorationDimensions(blockDecoration1) + presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10) + presenter.setBlockDecorationDimensions(blockDecoration3, 0, 10) - expectValues stateForBlockDecoration(presenter, blockDecoration1), { - decoration: blockDecoration1 - screenRow: 4 - isVisible: false - } - expectValues stateForBlockDecoration(presenter, blockDecoration3), { - decoration: blockDecoration3 - screenRow: 8 - isVisible: true - } + expectValues stateForBlockDecoration(presenter, blockDecoration1), { + decoration: blockDecoration1 + screenRow: 0 + isVisible: false + } + expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined() + expect(stateForBlockDecoration(presenter, blockDecoration3)).toBeUndefined() + expectValues stateForBlockDecoration(presenter, blockDecoration4), { + decoration: blockDecoration4 + screenRow: 10 + isVisible: true + } describe ".overlays", -> [item] = [] diff --git a/src/block-decorations-component.coffee b/src/block-decorations-component.coffee index b214fd584..50ac52fc7 100644 --- a/src/block-decorations-component.coffee +++ b/src/block-decorations-component.coffee @@ -60,9 +60,9 @@ class BlockDecorationsComponent oldBlockDecorationState = @oldState.blockDecorations[id] blockDecorationNode = @blockDecorationNodesById[id] - if newBlockDecorationState.isVisible and not oldBlockDecorationState.isVisible + if newBlockDecorationState.isVisible blockDecorationNode.classList.remove("atom--invisible-block-decoration") - else if not newBlockDecorationState.isVisible and oldBlockDecorationState.isVisible + else blockDecorationNode.classList.add("atom--invisible-block-decoration") if newBlockDecorationState.screenRow isnt oldBlockDecorationState.screenRow diff --git a/src/block-decorations-presenter.js b/src/block-decorations-presenter.js index 31571f57a..a5306a7ef 100644 --- a/src/block-decorations-presenter.js +++ b/src/block-decorations-presenter.js @@ -14,6 +14,7 @@ class BlockDecorationsPresenter { this.blocksByDecoration = new Map this.decorationsByBlock = new Map this.observedDecorations = new Set + this.measuredDecorations = new Set this.observeModel() } @@ -62,6 +63,12 @@ class BlockDecorationsPresenter { this.lineTopIndex.resizeBlock(block, height) } + this.measuredDecorations.add(decoration) + this.emitter.emit("did-update-state") + } + + invalidateDimensionsForDecoration (decoration) { + this.measuredDecorations.delete(decoration) this.emitter.emit("did-update-state") } @@ -70,14 +77,16 @@ class BlockDecorationsPresenter { return blocks.map((block) => this.decorationsByBlock.get(block.id)).filter((decoration) => decoration) } - getAllDecorationsByScreenRow () { + decorationsForScreenRowRange (startRow, endRow) { let blocks = this.lineTopIndex.allBlocks() let decorationsByScreenRow = new Map for (let block of blocks) { let decoration = this.decorationsByBlock.get(block.id) - if (decoration) { + let hasntMeasuredDecoration = !this.measuredDecorations.has(decoration) + let isVisible = startRow <= block.row && block.row < endRow + if (decoration && (isVisible || hasntMeasuredDecoration)) { let decorations = decorationsByScreenRow.get(block.row) || [] - decorations.push(decoration) + decorations.push({decoration, isVisible}) decorationsByScreenRow.set(block.row, decorations) } } diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index e5e63c371..afe46c705 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -456,6 +456,9 @@ class TextEditorComponent @editor.screenPositionForBufferPosition(bufferPosition) ) + invalidateBlockDecorationDimensions: -> + @presenter.invalidateBlockDecorationDimensions(arguments...) + onMouseDown: (event) => unless event.button is 0 or (event.button is 1 and process.platform is 'linux') # Only handle mouse down events for left mouse button on all platforms diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 1a55eb002..6722f51df 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -347,4 +347,7 @@ class TextEditorElement extends HTMLElement getHeight: -> @offsetHeight + invalidateBlockDecorationDimensions: -> + @component.invalidateBlockDecorationDimensions(arguments...) + module.exports = TextEditorElement = document.registerElement 'atom-text-editor', prototype: TextEditorElement.prototype diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 72d1cec54..b2bc16ca9 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1213,9 +1213,11 @@ class TextEditorPresenter updateBlockDecorationsState: -> @state.content.blockDecorations = {} - @blockDecorationsPresenter.getAllDecorationsByScreenRow().forEach (decorations, screenRow) => - for decoration in decorations - isVisible = @getStartTileRow() <= screenRow < @getEndTileRow() + @tileSize + startRow = @getStartTileRow() + endRow = @getEndTileRow() + @tileSize + decorations = @blockDecorationsPresenter.decorationsForScreenRowRange(startRow, endRow) + decorations.forEach (decorations, screenRow) => + for {decoration, isVisible} in decorations @state.content.blockDecorations[decoration.id] = {decoration, screenRow, isVisible} updateLineDecorations: -> @@ -1414,6 +1416,9 @@ class TextEditorPresenter setBlockDecorationDimensions: -> @blockDecorationsPresenter.setDimensionsForDecoration(arguments...) + invalidateBlockDecorationDimensions: -> + @blockDecorationsPresenter.invalidateDimensionsForDecoration(arguments...) + observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => @shouldUpdateHiddenInputState = true if cursor.isLastCursor()