From be691b6a54b2179fe8bfcb749d731649b7a679e1 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 21:50:59 -0700 Subject: [PATCH 01/11] Precompute contentHeight and height --- spec/text-editor-presenter-spec.coffee | 36 +++++++++++------------ src/text-editor-presenter.coffee | 40 +++++++++++++++----------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d86c47337..e75644de1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -260,13 +260,13 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.computeContentHeight() + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> @@ -302,14 +302,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeContentHeight() - (presenter.lineHeight * 3) + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() describe ".content", -> describe ".scrollingVertically", -> @@ -352,13 +352,13 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.content.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.content.scrollHeight).toBe presenter.computeContentHeight() + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.content.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight describe ".scrollWidth", -> it "is initialized as the max of the computed clientWidth and the width of the longest line", -> @@ -449,14 +449,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.content.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.content.scrollTop).toBe presenter.computeContentHeight() - (presenter.lineHeight * 3) + expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.content.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() describe ".scrollLeft", -> it "tracks the value of ::scrollLeft", -> @@ -1524,13 +1524,13 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.gutter.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.gutter.scrollHeight).toBe presenter.computeContentHeight() + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.gutter.scrollHeight).toBe presenter.computeContentHeight() + expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> @@ -1566,14 +1566,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeContentHeight() - (presenter.lineHeight * 3) + expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeContentHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() describe ".backgroundColor", -> it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c48c66b03..7f0a72835 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -43,6 +43,8 @@ class TextEditorPresenter observeModel: -> @disposables.add @model.onDidChange => + @updateContentHeight() + @updateHeightState() @updateVerticalScrollState() @updateHorizontalScrollState() @@ -87,6 +89,9 @@ class TextEditorPresenter @updateState() updateState: -> + @updateContentHeight() + @updateHeight() + @updateHeightState() @updateVerticalScrollState() @updateHorizontalScrollState() @@ -101,7 +106,7 @@ class TextEditorPresenter updateHeightState: -> if @autoHeight - @state.height = @computeContentHeight() + @state.height = @contentHeight else @state.height = null @@ -339,7 +344,7 @@ class TextEditorPresenter computeEndRow: -> startRow = Math.floor(@computeScrollTop() / @lineHeight) - visibleLinesCount = Math.ceil(@computeHeight() / @lineHeight) + 1 + visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 endRow = startRow + visibleLinesCount + @lineOverdrawMargin Math.min(@model.getScreenLineCount(), endRow) @@ -347,22 +352,23 @@ class TextEditorPresenter Math.max(@computeContentWidth(), @computeClientWidth()) computeScrollHeight: -> - contentHeight = @computeContentHeight() + contentHeight = @contentHeight if atom.config.get('editor.scrollPastEnd') extraScrollHeight = @computeClientHeight() - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 - Math.max(contentHeight, @computeHeight()) + Math.max(contentHeight, @height) computeContentWidth: -> contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width contentWidth - computeContentHeight: -> - @lineHeight * @model.getScreenLineCount() + updateContentHeight: -> + @contentHeight = @lineHeight * @model.getScreenLineCount() + @updateHeight() computeClientHeight: -> - @computeHeight() - @computeHorizontalScrollbarHeight() + @height - @computeHorizontalScrollbarHeight() computeClientWidth: -> @contentFrameWidth - @computeVerticalScrollbarWidth() @@ -387,15 +393,14 @@ class TextEditorPresenter computeHorizontalScrollbarHeight: -> contentWidth = @computeContentWidth() - contentHeight = @computeContentHeight() clientWidthWithoutVerticalScrollbar = @contentFrameWidth clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth - clientHeightWithoutHorizontalScrollbar = @computeHeight() + clientHeightWithoutHorizontalScrollbar = @height clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @horizontalScrollbarHeight horizontalScrollbarVisible = contentWidth > clientWidthWithoutVerticalScrollbar or - contentWidth > clientWidthWithVerticalScrollbar and contentHeight > clientHeightWithoutHorizontalScrollbar + contentWidth > clientWidthWithVerticalScrollbar and @contentHeight > clientHeightWithoutHorizontalScrollbar if horizontalScrollbarVisible @horizontalScrollbarHeight @@ -404,15 +409,14 @@ class TextEditorPresenter computeVerticalScrollbarWidth: -> contentWidth = @computeContentWidth() - contentHeight = @computeContentHeight() clientWidthWithoutVerticalScrollbar = @contentFrameWidth clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth - clientHeightWithoutHorizontalScrollbar = @computeHeight() + clientHeightWithoutHorizontalScrollbar = @height clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @horizontalScrollbarHeight verticalScrollbarVisible = - contentHeight > clientHeightWithoutHorizontalScrollbar or - contentHeight > clientHeightWithHorizontalScrollbar and contentWidth > clientWidthWithoutVerticalScrollbar + @contentHeight > clientHeightWithoutHorizontalScrollbar or + @contentHeight > clientHeightWithHorizontalScrollbar and contentWidth > clientWidthWithoutVerticalScrollbar if verticalScrollbarVisible @verticalScrollbarWidth @@ -516,6 +520,7 @@ class TextEditorPresenter unless @explicitHeight is explicitHeight @explicitHeight = explicitHeight @model.setHeight(explicitHeight) + @updateHeight() @updateVerticalScrollState() @updateScrollbarsState() @updateDecorations() @@ -523,8 +528,8 @@ class TextEditorPresenter @updateCursorsState() @updateLineNumbersState() - computeHeight: -> - @explicitHeight ? @computeContentHeight() + updateHeight: -> + @height = @explicitHeight ? @contentHeight setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth @@ -554,6 +559,9 @@ class TextEditorPresenter unless @lineHeight is lineHeight @lineHeight = lineHeight @model.setLineHeightInPixels(lineHeight) + + @updateContentHeight() + @updateHeightState() @updateVerticalScrollState() @updateDecorations() From b6908b18b47e4aac887f8fee559b3713480faedd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 22:06:11 -0700 Subject: [PATCH 02/11] Precompute contentWidth --- src/text-editor-presenter.coffee | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7f0a72835..8750165f2 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -44,6 +44,7 @@ class TextEditorPresenter observeModel: -> @disposables.add @model.onDidChange => @updateContentHeight() + @updateContentWidth() @updateHeightState() @updateVerticalScrollState() @@ -91,6 +92,7 @@ class TextEditorPresenter updateState: -> @updateContentHeight() @updateHeight() + @updateContentWidth() @updateHeightState() @updateVerticalScrollState() @@ -349,7 +351,7 @@ class TextEditorPresenter Math.min(@model.getScreenLineCount(), endRow) computeScrollWidth: -> - Math.max(@computeContentWidth(), @computeClientWidth()) + Math.max(@contentWidth, @computeClientWidth()) computeScrollHeight: -> contentHeight = @contentHeight @@ -358,10 +360,9 @@ class TextEditorPresenter contentHeight += extraScrollHeight if extraScrollHeight > 0 Math.max(contentHeight, @height) - computeContentWidth: -> - contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left - contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width - contentWidth + updateContentWidth: -> + @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left + @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width updateContentHeight: -> @contentHeight = @lineHeight * @model.getScreenLineCount() @@ -392,15 +393,14 @@ class TextEditorPresenter Math.max(0, scrollLeft) if scrollLeft? computeHorizontalScrollbarHeight: -> - contentWidth = @computeContentWidth() clientWidthWithoutVerticalScrollbar = @contentFrameWidth clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth clientHeightWithoutHorizontalScrollbar = @height clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @horizontalScrollbarHeight horizontalScrollbarVisible = - contentWidth > clientWidthWithoutVerticalScrollbar or - contentWidth > clientWidthWithVerticalScrollbar and @contentHeight > clientHeightWithoutHorizontalScrollbar + @contentWidth > clientWidthWithoutVerticalScrollbar or + @contentWidth > clientWidthWithVerticalScrollbar and @contentHeight > clientHeightWithoutHorizontalScrollbar if horizontalScrollbarVisible @horizontalScrollbarHeight @@ -408,7 +408,6 @@ class TextEditorPresenter 0 computeVerticalScrollbarWidth: -> - contentWidth = @computeContentWidth() clientWidthWithoutVerticalScrollbar = @contentFrameWidth clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth clientHeightWithoutHorizontalScrollbar = @height @@ -416,7 +415,7 @@ class TextEditorPresenter verticalScrollbarVisible = @contentHeight > clientHeightWithoutHorizontalScrollbar or - @contentHeight > clientHeightWithHorizontalScrollbar and contentWidth > clientWidthWithoutVerticalScrollbar + @contentHeight > clientHeightWithHorizontalScrollbar and @contentWidth > clientWidthWithoutVerticalScrollbar if verticalScrollbarVisible @verticalScrollbarWidth @@ -606,6 +605,8 @@ class TextEditorPresenter @characterWidthsChanged() unless @batchingCharacterMeasurement characterWidthsChanged: -> + @updateContentWidth() + @updateHorizontalScrollState() @updateContentState() @updateDecorations() From a3f902104c38f4e9a6d2294a7f57f88b409b0206 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 22:25:10 -0700 Subject: [PATCH 03/11] Precompute ::horizontalScrollbarHeight and ::verticalScrollbarWidth --- src/text-editor-presenter.coffee | 82 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 8750165f2..c426631a9 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -12,9 +12,11 @@ class TextEditorPresenter constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft} = params - {@horizontalScrollbarHeight, @verticalScrollbarWidth} = params + {horizontalScrollbarHeight, verticalScrollbarWidth} = params {@lineHeight, @baseCharacterWidth, @lineOverdrawMargin, @backgroundColor, @gutterBackgroundColor} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay} = params + @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight + @measuredVerticalScrollbarWidth = verticalScrollbarWidth @disposables = new CompositeDisposable @emitter = new Emitter @@ -38,8 +40,8 @@ class TextEditorPresenter @model.setDefaultCharWidth(@baseCharacterWidth) if @baseCharacterWidth? @model.setScrollTop(@scrollTop) if @scrollTop? @model.setScrollLeft(@scrollLeft) if @scrollLeft? - @model.setVerticalScrollbarWidth(@verticalScrollbarWidth) if @verticalScrollbarWidth? - @model.setHorizontalScrollbarHeight(@horizontalScrollbarHeight) if @horizontalScrollbarHeight? + @model.setVerticalScrollbarWidth(@measuredVerticalScrollbarWidth) if @measuredVerticalScrollbarWidth? + @model.setHorizontalScrollbarHeight(@measuredHorizontalScrollbarHeight) if @measuredHorizontalScrollbarHeight? observeModel: -> @disposables.add @model.onDidChange => @@ -93,6 +95,7 @@ class TextEditorPresenter @updateContentHeight() @updateHeight() @updateContentWidth() + @updateScrollbarDimensions() @updateHeightState() @updateVerticalScrollState() @@ -139,16 +142,13 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateScrollbarsState: -> - horizontalScrollbarHeight = @computeHorizontalScrollbarHeight() - verticalScrollbarWidth = @computeVerticalScrollbarWidth() + @state.horizontalScrollbar.visible = @horizontalScrollbarHeight > 0 + @state.horizontalScrollbar.height = @measuredHorizontalScrollbarHeight + @state.horizontalScrollbar.right = @verticalScrollbarWidth - @state.horizontalScrollbar.visible = horizontalScrollbarHeight > 0 - @state.horizontalScrollbar.height = @horizontalScrollbarHeight - @state.horizontalScrollbar.right = verticalScrollbarWidth - - @state.verticalScrollbar.visible = verticalScrollbarWidth > 0 - @state.verticalScrollbar.width = @verticalScrollbarWidth - @state.verticalScrollbar.bottom = horizontalScrollbarHeight + @state.verticalScrollbar.visible = @verticalScrollbarWidth > 0 + @state.verticalScrollbar.width = @measuredVerticalScrollbarWidth + @state.verticalScrollbar.bottom = @horizontalScrollbarHeight @emitter.emit 'did-update-state' @@ -363,16 +363,18 @@ class TextEditorPresenter updateContentWidth: -> @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width + @updateScrollbarDimensions() updateContentHeight: -> @contentHeight = @lineHeight * @model.getScreenLineCount() @updateHeight() + @updateScrollbarDimensions() computeClientHeight: -> - @height - @computeHorizontalScrollbarHeight() + @height - @horizontalScrollbarHeight computeClientWidth: -> - @contentFrameWidth - @computeVerticalScrollbarWidth() + @contentFrameWidth - @verticalScrollbarWidth computeScrollTop: -> @scrollTop = @constrainScrollTop(@scrollTop) @@ -392,35 +394,31 @@ class TextEditorPresenter else Math.max(0, scrollLeft) if scrollLeft? - computeHorizontalScrollbarHeight: -> + updateScrollbarDimensions: -> clientWidthWithoutVerticalScrollbar = @contentFrameWidth - clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth + clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @measuredVerticalScrollbarWidth clientHeightWithoutHorizontalScrollbar = @height - clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @horizontalScrollbarHeight + clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @measuredHorizontalScrollbarHeight horizontalScrollbarVisible = @contentWidth > clientWidthWithoutVerticalScrollbar or @contentWidth > clientWidthWithVerticalScrollbar and @contentHeight > clientHeightWithoutHorizontalScrollbar - if horizontalScrollbarVisible - @horizontalScrollbarHeight - else - 0 - - computeVerticalScrollbarWidth: -> - clientWidthWithoutVerticalScrollbar = @contentFrameWidth - clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @verticalScrollbarWidth - clientHeightWithoutHorizontalScrollbar = @height - clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @horizontalScrollbarHeight - verticalScrollbarVisible = @contentHeight > clientHeightWithoutHorizontalScrollbar or @contentHeight > clientHeightWithHorizontalScrollbar and @contentWidth > clientWidthWithoutVerticalScrollbar - if verticalScrollbarVisible - @verticalScrollbarWidth - else - 0 + @horizontalScrollbarHeight = + if horizontalScrollbarVisible + @measuredHorizontalScrollbarHeight + else + 0 + + @verticalScrollbarWidth = + if verticalScrollbarVisible + @measuredVerticalScrollbarWidth + else + 0 lineDecorationClassesForRow: (row) -> return null if @model.isMini() @@ -450,8 +448,8 @@ class TextEditorPresenter @scrollTop? and @contentFrameWidth? and @scrollLeft? and - @verticalScrollbarWidth? and - @horizontalScrollbarHeight? + @measuredVerticalScrollbarWidth? and + @measuredHorizontalScrollbarHeight? setScrollTop: (scrollTop) -> scrollTop = @constrainScrollTop(scrollTop) @@ -493,19 +491,21 @@ class TextEditorPresenter @updateCursorsState() unless oldScrollLeft? setHorizontalScrollbarHeight: (horizontalScrollbarHeight) -> - unless @horizontalScrollbarHeight is horizontalScrollbarHeight - oldHorizontalScrollbarHeight = @horizontalScrollbarHeight - @horizontalScrollbarHeight = horizontalScrollbarHeight + unless @measuredHorizontalScrollbarHeight is horizontalScrollbarHeight + oldHorizontalScrollbarHeight = @measuredHorizontalScrollbarHeight + @measuredHorizontalScrollbarHeight = horizontalScrollbarHeight @model.setHorizontalScrollbarHeight(horizontalScrollbarHeight) + @updateScrollbarDimensions() @updateScrollbarsState() @updateVerticalScrollState() @updateCursorsState() unless oldHorizontalScrollbarHeight? setVerticalScrollbarWidth: (verticalScrollbarWidth) -> - unless @verticalScrollbarWidth is verticalScrollbarWidth - oldVerticalScrollbarWidth = @verticalScrollbarWidth - @verticalScrollbarWidth = verticalScrollbarWidth + unless @measuredVerticalScrollbarWidth is verticalScrollbarWidth + oldVerticalScrollbarWidth = @measuredVerticalScrollbarWidth + @measuredVerticalScrollbarWidth = verticalScrollbarWidth @model.setVerticalScrollbarWidth(verticalScrollbarWidth) + @updateScrollbarDimensions() @updateScrollbarsState() @updateHorizontalScrollState() @updateCursorsState() unless oldVerticalScrollbarWidth? @@ -529,12 +529,14 @@ class TextEditorPresenter updateHeight: -> @height = @explicitHeight ? @contentHeight + @updateScrollbarDimensions() setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth oldContentFrameWidth = @contentFrameWidth @contentFrameWidth = contentFrameWidth @model.setWidth(contentFrameWidth) + @updateScrollbarDimensions() @updateVerticalScrollState() @updateHorizontalScrollState() @updateScrollbarsState() From cf958ffeac6ac01345a8ab6855688aacfb62b2ec Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 22:34:42 -0700 Subject: [PATCH 04/11] =?UTF-8?q?Don=E2=80=99t=20cascade=20computed=20valu?= =?UTF-8?q?es=20unless=20upstream=20values=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/text-editor-presenter.coffee | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c426631a9..c96668445 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -361,14 +361,18 @@ class TextEditorPresenter Math.max(contentHeight, @height) updateContentWidth: -> - @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left - @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width - @updateScrollbarDimensions() + contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left + contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width + unless @contentWidth is contentWidth + @contentWidth = contentWidth + @updateScrollbarDimensions() updateContentHeight: -> - @contentHeight = @lineHeight * @model.getScreenLineCount() - @updateHeight() - @updateScrollbarDimensions() + contentHeight = @lineHeight * @model.getScreenLineCount() + unless @contentHeight is contentHeight + @contentHeight = contentHeight + @updateHeight() + @updateScrollbarDimensions() computeClientHeight: -> @height - @horizontalScrollbarHeight @@ -528,8 +532,10 @@ class TextEditorPresenter @updateLineNumbersState() updateHeight: -> - @height = @explicitHeight ? @contentHeight - @updateScrollbarDimensions() + height = @explicitHeight ? @contentHeight + unless @height is height + @height = height + @updateScrollbarDimensions() setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth From fc603aaa0d5d273a2389ea6ad8b2b5e7ee6e273a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 22:42:32 -0700 Subject: [PATCH 05/11] Precompute ::clientHeight and ::clientWidth --- spec/text-editor-presenter-spec.coffee | 62 +++++++++++++------------- src/text-editor-presenter.coffee | 30 ++++++++----- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index e75644de1..7a942548d 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -140,7 +140,7 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.state.horizontalScrollbar.scrollWidth).toBe presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 @@ -164,16 +164,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, explicitHeight: 100, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger scrollLeftBefore = presenter.state.horizontalScrollbar.scrollLeft @@ -263,7 +263,7 @@ describe "TextEditorPresenter", -> expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) expect(presenter.state.verticalScrollbar.scrollHeight).toBe presenter.contentHeight @@ -278,16 +278,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop @@ -302,14 +302,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".content", -> describe ".scrollingVertically", -> @@ -355,7 +355,7 @@ describe "TextEditorPresenter", -> expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) expect(presenter.state.content.scrollHeight).toBe presenter.contentHeight @@ -401,7 +401,7 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.state.horizontalScrollbar.scrollWidth).toBe presenter.computeClientWidth() + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 @@ -425,16 +425,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scroll height minus the computed client height", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop @@ -449,14 +449,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".scrollLeft", -> it "tracks the value of ::scrollLeft", -> @@ -468,16 +468,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.computeClientWidth() + expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger scrollLeftBefore = presenter.state.content.scrollLeft @@ -1527,7 +1527,7 @@ describe "TextEditorPresenter", -> expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight + presenter.computeClientHeight() - (presenter.lineHeight * 3) + expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) expect(presenter.state.gutter.scrollHeight).toBe presenter.contentHeight @@ -1542,16 +1542,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop @@ -1566,14 +1566,14 @@ describe "TextEditorPresenter", -> it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.computeClientHeight() + expect(presenter.state.gutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".backgroundColor", -> it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index c96668445..10de005ec 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -351,12 +351,12 @@ class TextEditorPresenter Math.min(@model.getScreenLineCount(), endRow) computeScrollWidth: -> - Math.max(@contentWidth, @computeClientWidth()) + Math.max(@contentWidth, @clientWidth) computeScrollHeight: -> contentHeight = @contentHeight if atom.config.get('editor.scrollPastEnd') - extraScrollHeight = @computeClientHeight() - (@lineHeight * 3) + extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 Math.max(contentHeight, @height) @@ -374,18 +374,18 @@ class TextEditorPresenter @updateHeight() @updateScrollbarDimensions() - computeClientHeight: -> - @height - @horizontalScrollbarHeight + updateClientHeight: -> + @clientHeight = @height - @horizontalScrollbarHeight - computeClientWidth: -> - @contentFrameWidth - @verticalScrollbarWidth + updateClientWidth: -> + @clientWidth = @contentFrameWidth - @verticalScrollbarWidth computeScrollTop: -> @scrollTop = @constrainScrollTop(@scrollTop) constrainScrollTop: (scrollTop) -> if @hasRequiredMeasurements() - Math.max(0, Math.min(scrollTop, @computeScrollHeight() - @computeClientHeight())) + Math.max(0, Math.min(scrollTop, @computeScrollHeight() - @clientHeight)) else Math.max(0, scrollTop) if scrollTop? @@ -394,7 +394,7 @@ class TextEditorPresenter constrainScrollLeft: (scrollLeft) -> if @hasRequiredMeasurements() - Math.max(0, Math.min(scrollLeft, @computeScrollWidth() - @computeClientWidth())) + Math.max(0, Math.min(scrollLeft, @computeScrollWidth() - @clientWidth)) else Math.max(0, scrollLeft) if scrollLeft? @@ -412,18 +412,26 @@ class TextEditorPresenter @contentHeight > clientHeightWithoutHorizontalScrollbar or @contentHeight > clientHeightWithHorizontalScrollbar and @contentWidth > clientWidthWithoutVerticalScrollbar - @horizontalScrollbarHeight = + horizontalScrollbarHeight = if horizontalScrollbarVisible @measuredHorizontalScrollbarHeight else 0 - @verticalScrollbarWidth = + verticalScrollbarWidth = if verticalScrollbarVisible @measuredVerticalScrollbarWidth else 0 + unless @horizontalScrollbarHeight is horizontalScrollbarHeight + @horizontalScrollbarHeight = horizontalScrollbarHeight + @updateClientHeight() + + unless @verticalScrollbarWidth is verticalScrollbarWidth + @verticalScrollbarWidth = verticalScrollbarWidth + @updateClientWidth() + lineDecorationClassesForRow: (row) -> return null if @model.isMini() @@ -536,6 +544,7 @@ class TextEditorPresenter unless @height is height @height = height @updateScrollbarDimensions() + @updateClientHeight() setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth @@ -543,6 +552,7 @@ class TextEditorPresenter @contentFrameWidth = contentFrameWidth @model.setWidth(contentFrameWidth) @updateScrollbarDimensions() + @updateClientWidth() @updateVerticalScrollState() @updateHorizontalScrollState() @updateScrollbarsState() From 05554d03e4f8c99af1e470d5b7ca2c557688197a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 22:53:38 -0700 Subject: [PATCH 06/11] Precompute ::scrollWidth --- spec/text-editor-presenter-spec.coffee | 20 ++++++++++---------- src/text-editor-presenter.coffee | 21 ++++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 7a942548d..d93e0d13e 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -164,16 +164,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, explicitHeight: 100, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger scrollLeftBefore = presenter.state.horizontalScrollbar.scrollLeft @@ -468,16 +468,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.state.content.scrollLeft).toBe presenter.computeScrollWidth() - presenter.clientWidth + expect(presenter.state.content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger scrollLeftBefore = presenter.state.content.scrollLeft @@ -1995,7 +1995,7 @@ describe "TextEditorPresenter", -> presenter.setScrollTop(newScrollTop) changeScrollLeft = (log) -> - scrollWidth = presenter.computeScrollWidth() + scrollWidth = presenter.scrollWidth newScrollLeft = Math.max(0, _.random(0, scrollWidth - presenterParams.contentFrameWidth)) log """ presenterParams.scrollLeft = #{newScrollLeft} @@ -2015,7 +2015,7 @@ describe "TextEditorPresenter", -> presenter.setExplicitHeight(newExplicitHeight) changeContentFrameWidth = (log) -> - scrollWidth = presenter.computeScrollWidth() + scrollWidth = presenter.scrollWidth newContentFrameWidth = _.random(100, scrollWidth * 1.5) log """ presenterParams.contentFrameWidth = #{newContentFrameWidth} diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 10de005ec..3088fcaca 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -131,9 +131,8 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateHorizontalScrollState: -> - scrollWidth = @computeScrollWidth() - @state.content.scrollWidth = scrollWidth - @state.horizontalScrollbar.scrollWidth = scrollWidth + @state.content.scrollWidth = @scrollWidth + @state.horizontalScrollbar.scrollWidth = @scrollWidth scrollLeft = @computeScrollLeft() @state.content.scrollLeft = scrollLeft @@ -153,7 +152,7 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateContentState: -> - @state.content.scrollWidth = @computeScrollWidth() + @state.content.scrollWidth = @scrollWidth @state.content.scrollLeft = @scrollLeft @state.content.indentGuidesVisible = not @model.isMini() and atom.config.get('editor.showIndentGuide', scope: @model.getRootScopeDescriptor()) @state.content.backgroundColor = if @model.isMini() then null else @backgroundColor @@ -350,8 +349,8 @@ class TextEditorPresenter endRow = startRow + visibleLinesCount + @lineOverdrawMargin Math.min(@model.getScreenLineCount(), endRow) - computeScrollWidth: -> - Math.max(@contentWidth, @clientWidth) + updateScrollWidth: -> + @scrollWidth = Math.max(@contentWidth, @clientWidth) computeScrollHeight: -> contentHeight = @contentHeight @@ -366,6 +365,7 @@ class TextEditorPresenter unless @contentWidth is contentWidth @contentWidth = contentWidth @updateScrollbarDimensions() + @updateScrollWidth() updateContentHeight: -> contentHeight = @lineHeight * @model.getScreenLineCount() @@ -378,7 +378,10 @@ class TextEditorPresenter @clientHeight = @height - @horizontalScrollbarHeight updateClientWidth: -> - @clientWidth = @contentFrameWidth - @verticalScrollbarWidth + clientWidth = @contentFrameWidth - @verticalScrollbarWidth + unless @clientWidth is clientWidth + @clientWidth = clientWidth + @updateScrollWidth() computeScrollTop: -> @scrollTop = @constrainScrollTop(@scrollTop) @@ -394,7 +397,7 @@ class TextEditorPresenter constrainScrollLeft: (scrollLeft) -> if @hasRequiredMeasurements() - Math.max(0, Math.min(scrollLeft, @computeScrollWidth() - @clientWidth)) + Math.max(0, Math.min(scrollLeft, @scrollWidth - @clientWidth)) else Math.max(0, scrollLeft) if scrollLeft? @@ -671,7 +674,7 @@ class TextEditorPresenter top = @pixelPositionForScreenPosition(screenRange.start).top left = 0 height = (screenRange.end.row - screenRange.start.row + 1) * @lineHeight - width = @computeScrollWidth() + width = @scrollWidth else {top, left} = @pixelPositionForScreenPosition(screenRange.start, false) height = @lineHeight From 54fcaa613203c74c8faea04812f5cd00550e548d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 23:01:08 -0700 Subject: [PATCH 07/11] Precompute ::scrollHeight and cache ::scrollPastEnd config value --- spec/text-editor-presenter-spec.coffee | 24 ++++++++++---------- src/text-editor-presenter.coffee | 31 ++++++++++++++++---------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d93e0d13e..7cb081f5b 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -278,16 +278,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop @@ -425,16 +425,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scroll height minus the computed client height", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.content.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop @@ -1542,16 +1542,16 @@ describe "TextEditorPresenter", -> it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.state.gutter.scrollTop).toBe presenter.computeScrollHeight() - presenter.clientHeight + expect(presenter.state.gutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger scrollTopBefore = presenter.state.verticalScrollbar.scrollTop diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 3088fcaca..55d0928f9 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -72,8 +72,12 @@ class TextEditorPresenter @observeCursor(cursor) for cursor in @model.getCursors() observeConfig: -> + @scrollPastEnd = atom.config.get('editor.scrollPastEnd') + @disposables.add atom.config.onDidChange 'editor.showIndentGuide', scope: @model.getRootScopeDescriptor(), @updateContentState.bind(this) - @disposables.add atom.config.onDidChange 'editor.scrollPastEnd', scope: @model.getRootScopeDescriptor(), => + @disposables.add atom.config.onDidChange 'editor.scrollPastEnd', scope: @model.getRootScopeDescriptor(), ({newValue}) => + @scrollPastEnd = newValue + @updateScrollHeight() @updateVerticalScrollState() @updateScrollbarsState() @@ -118,10 +122,9 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateVerticalScrollState: -> - scrollHeight = @computeScrollHeight() - @state.content.scrollHeight = scrollHeight - @state.gutter.scrollHeight = scrollHeight - @state.verticalScrollbar.scrollHeight = scrollHeight + @state.content.scrollHeight = @scrollHeight + @state.gutter.scrollHeight = @scrollHeight + @state.verticalScrollbar.scrollHeight = @scrollHeight scrollTop = @computeScrollTop() @state.content.scrollTop = scrollTop @@ -352,12 +355,12 @@ class TextEditorPresenter updateScrollWidth: -> @scrollWidth = Math.max(@contentWidth, @clientWidth) - computeScrollHeight: -> + updateScrollHeight: -> contentHeight = @contentHeight - if atom.config.get('editor.scrollPastEnd') + if @scrollPastEnd extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 - Math.max(contentHeight, @height) + @scrollHeight = Math.max(contentHeight, @height) updateContentWidth: -> contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left @@ -373,9 +376,13 @@ class TextEditorPresenter @contentHeight = contentHeight @updateHeight() @updateScrollbarDimensions() + @updateScrollHeight() updateClientHeight: -> - @clientHeight = @height - @horizontalScrollbarHeight + clientHeight = @height - @horizontalScrollbarHeight + unless @clientHeight is clientHeight + @clientHeight = clientHeight + @updateScrollHeight() updateClientWidth: -> clientWidth = @contentFrameWidth - @verticalScrollbarWidth @@ -388,7 +395,7 @@ class TextEditorPresenter constrainScrollTop: (scrollTop) -> if @hasRequiredMeasurements() - Math.max(0, Math.min(scrollTop, @computeScrollHeight() - @clientHeight)) + Math.max(0, Math.min(scrollTop, @scrollHeight - @clientHeight)) else Math.max(0, scrollTop) if scrollTop? @@ -548,6 +555,7 @@ class TextEditorPresenter @height = height @updateScrollbarDimensions() @updateClientHeight() + @updateScrollHeight() setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth @@ -579,9 +587,8 @@ class TextEditorPresenter unless @lineHeight is lineHeight @lineHeight = lineHeight @model.setLineHeightInPixels(lineHeight) - @updateContentHeight() - + @updateScrollHeight() @updateHeightState() @updateVerticalScrollState() @updateDecorations() From 4f5b989cbbaec67572339d381f5c53779c729cbc Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 11 Feb 2015 23:04:49 -0700 Subject: [PATCH 08/11] Use property instead of non-existent method in OverlayManager --- src/overlay-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 2fa3cc028..82387fcf7 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -34,7 +34,7 @@ class OverlayManager left -= itemWidth top = pixelPosition.top + presenter.lineHeight - if top + itemHeight - scrollTop > presenter.computeHeight() and top - itemHeight - presenter.lineHeight >= scrollTop + if top + itemHeight - scrollTop > presenter.height and top - itemHeight - presenter.lineHeight >= scrollTop top -= itemHeight + presenter.lineHeight overlayNode.style.top = top + 'px' From cc80378b29d3c0dc981c88e4cf955aee9b5a0767 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 09:36:44 -0700 Subject: [PATCH 09/11] Precompute ::scrollTop in presenter --- spec/text-editor-presenter-spec.coffee | 2 +- src/text-editor-presenter.coffee | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 7cb081f5b..1dee7d57a 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -314,7 +314,7 @@ describe "TextEditorPresenter", -> describe ".content", -> describe ".scrollingVertically", -> it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", -> - presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200) + presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200, explicitHeight: 100) expect(presenter.state.content.scrollingVertically).toBe false expectStateUpdate presenter, -> presenter.setScrollTop(0) expect(presenter.state.content.scrollingVertically).toBe true diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 55d0928f9..b246a4d17 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -126,10 +126,9 @@ class TextEditorPresenter @state.gutter.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight - scrollTop = @computeScrollTop() - @state.content.scrollTop = scrollTop - @state.gutter.scrollTop = scrollTop - @state.verticalScrollbar.scrollTop = scrollTop + @state.content.scrollTop = @scrollTop + @state.gutter.scrollTop = @scrollTop + @state.verticalScrollbar.scrollTop = @scrollTop @emitter.emit 'did-update-state' @@ -343,11 +342,11 @@ class TextEditorPresenter regions computeStartRow: -> - startRow = Math.floor(@computeScrollTop() / @lineHeight) - @lineOverdrawMargin + startRow = Math.floor(@scrollTop / @lineHeight) - @lineOverdrawMargin Math.max(0, startRow) computeEndRow: -> - startRow = Math.floor(@computeScrollTop() / @lineHeight) + startRow = Math.floor(@scrollTop / @lineHeight) visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 endRow = startRow + visibleLinesCount + @lineOverdrawMargin Math.min(@model.getScreenLineCount(), endRow) @@ -360,7 +359,11 @@ class TextEditorPresenter if @scrollPastEnd extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 - @scrollHeight = Math.max(contentHeight, @height) + scrollHeight = Math.max(contentHeight, @height) + + unless @scrollHeight is scrollHeight + @scrollHeight = scrollHeight + @updateScrollTop() updateContentWidth: -> contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left @@ -383,6 +386,7 @@ class TextEditorPresenter unless @clientHeight is clientHeight @clientHeight = clientHeight @updateScrollHeight() + @updateScrollTop() updateClientWidth: -> clientWidth = @contentFrameWidth - @verticalScrollbarWidth @@ -390,7 +394,7 @@ class TextEditorPresenter @clientWidth = clientWidth @updateScrollWidth() - computeScrollTop: -> + updateScrollTop: -> @scrollTop = @constrainScrollTop(@scrollTop) constrainScrollTop: (scrollTop) -> From 205d1df7b435867ab224139e85c2b8e9225fa670 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 11:06:30 -0700 Subject: [PATCH 10/11] Precompute ::startRow and ::endRow in presenter --- spec/text-editor-component-spec.coffee | 2 +- src/text-editor-presenter.coffee | 121 +++++++++++++------------ 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 10d91941d..d4a64c300 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1119,7 +1119,7 @@ describe "TextEditorComponent", -> nextAnimationFrame() # Should not be rendering range containing the marker - expect(component.presenter.computeEndRow()).toBeLessThan 9 + expect(component.presenter.endRow).toBeLessThan 9 regions = componentNode.querySelectorAll('.some-highlight .region') diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index b246a4d17..2be807105 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -45,9 +45,8 @@ class TextEditorPresenter observeModel: -> @disposables.add @model.onDidChange => - @updateContentHeight() - @updateContentWidth() - + @updateContentDimensions() + @updateEndRow() @updateHeightState() @updateVerticalScrollState() @updateHorizontalScrollState() @@ -96,10 +95,10 @@ class TextEditorPresenter @updateState() updateState: -> - @updateContentHeight() - @updateHeight() - @updateContentWidth() + @updateContentDimensions() @updateScrollbarDimensions() + @updateStartRow() + @updateEndRow() @updateHeightState() @updateVerticalScrollState() @@ -136,9 +135,8 @@ class TextEditorPresenter @state.content.scrollWidth = @scrollWidth @state.horizontalScrollbar.scrollWidth = @scrollWidth - scrollLeft = @computeScrollLeft() - @state.content.scrollLeft = scrollLeft - @state.horizontalScrollbar.scrollLeft = scrollLeft + @state.content.scrollLeft = @scrollLeft + @state.horizontalScrollbar.scrollLeft = @scrollLeft @emitter.emit 'did-update-state' @@ -165,10 +163,8 @@ class TextEditorPresenter return unless @hasRequiredMeasurements() visibleLineIds = {} - startRow = @computeStartRow() - endRow = @computeEndRow() - row = startRow - while row < endRow + row = @startRow + while row < @endRow line = @model.tokenizedLineForScreenRow(row) visibleLineIds[line.id] = true if @state.content.lines.hasOwnProperty(line.id) @@ -210,11 +206,8 @@ class TextEditorPresenter @state.content.cursors = {} return unless @hasRequiredMeasurements() - startRow = @computeStartRow() - endRow = @computeEndRow() - for cursor in @model.getCursors() - if cursor.isVisible() and startRow <= cursor.getScreenRow() < endRow + if cursor.isVisible() and @startRow <= cursor.getScreenRow() < @endRow pixelRect = @pixelRectForScreenRange(cursor.getScreenRange()) pixelRect.width = @baseCharacterWidth if pixelRect.width is 0 @state.content.cursors[cursor.id] = pixelRect @@ -253,20 +246,18 @@ class TextEditorPresenter @emitter.emit "did-update-state" updateLineNumbersState: -> - startRow = @computeStartRow() - endRow = @computeEndRow() visibleLineNumberIds = {} - if startRow > 0 - rowBeforeStartRow = startRow - 1 + if @startRow > 0 + rowBeforeStartRow = @startRow - 1 lastBufferRow = @model.bufferRowForScreenRow(rowBeforeStartRow) wrapCount = rowBeforeStartRow - @model.screenRowForBufferRow(lastBufferRow) else lastBufferRow = null wrapCount = 0 - if endRow > startRow - for bufferRow, i in @model.bufferRowsForScreenRows(startRow, endRow - 1) + if @endRow > @startRow + for bufferRow, i in @model.bufferRowsForScreenRows(@startRow, @endRow - 1) if bufferRow is lastBufferRow wrapCount++ id = bufferRow + '-' + wrapCount @@ -277,7 +268,7 @@ class TextEditorPresenter lastBufferRow = bufferRow softWrapped = false - screenRow = startRow + i + screenRow = @startRow + i top = screenRow * @lineHeight decorationClasses = @lineNumberDecorationClassesForRow(screenRow) foldable = @model.isFoldableAtScreenRow(screenRow) @@ -341,18 +332,21 @@ class TextEditorPresenter regions - computeStartRow: -> + updateStartRow: -> startRow = Math.floor(@scrollTop / @lineHeight) - @lineOverdrawMargin - Math.max(0, startRow) + @startRow = Math.max(0, startRow) - computeEndRow: -> - startRow = Math.floor(@scrollTop / @lineHeight) + updateEndRow: -> + startRow = Math.max(0, Math.floor(@scrollTop / @lineHeight)) visibleLinesCount = Math.ceil(@height / @lineHeight) + 1 endRow = startRow + visibleLinesCount + @lineOverdrawMargin - Math.min(@model.getScreenLineCount(), endRow) + @endRow = Math.min(@model.getScreenLineCount(), endRow) updateScrollWidth: -> - @scrollWidth = Math.max(@contentWidth, @clientWidth) + scrollWidth = Math.max(@contentWidth, @clientWidth) + unless @scrollWidth is scrollWidth + @scrollWidth = scrollWidth + @updateScrollLeft() updateScrollHeight: -> contentHeight = @contentHeight @@ -365,22 +359,25 @@ class TextEditorPresenter @scrollHeight = scrollHeight @updateScrollTop() - updateContentWidth: -> - contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left - contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width - unless @contentWidth is contentWidth - @contentWidth = contentWidth - @updateScrollbarDimensions() - @updateScrollWidth() + updateContentDimensions: (updateHeight=true, updateWidth=true) -> + if updateHeight + oldContentHeight = @contentHeight + @contentHeight = @lineHeight * @model.getScreenLineCount() - updateContentHeight: -> - contentHeight = @lineHeight * @model.getScreenLineCount() - unless @contentHeight is contentHeight - @contentHeight = contentHeight + if updateWidth + oldContentWidth = @contentWidth + @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left + @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width + + if updateHeight and @contentHeight isnt oldContentHeight @updateHeight() @updateScrollbarDimensions() @updateScrollHeight() + if updateWidth and @contentWidth isnt oldContentWidth + @updateScrollbarDimensions() + @updateScrollWidth() + updateClientHeight: -> clientHeight = @height - @horizontalScrollbarHeight unless @clientHeight is clientHeight @@ -393,9 +390,14 @@ class TextEditorPresenter unless @clientWidth is clientWidth @clientWidth = clientWidth @updateScrollWidth() + @updateScrollLeft() updateScrollTop: -> - @scrollTop = @constrainScrollTop(@scrollTop) + scrollTop = @constrainScrollTop(@scrollTop) + unless @scrollTop is scrollTop + @scrollTop = scrollTop + @updateStartRow() + @updateEndRow() constrainScrollTop: (scrollTop) -> if @hasRequiredMeasurements() @@ -403,7 +405,7 @@ class TextEditorPresenter else Math.max(0, scrollTop) if scrollTop? - computeScrollLeft: -> + updateScrollLeft: -> @scrollLeft = @constrainScrollLeft(@scrollLeft) constrainScrollLeft: (scrollLeft) -> @@ -483,6 +485,8 @@ class TextEditorPresenter unless @scrollTop is scrollTop @scrollTop = scrollTop @model.setScrollTop(scrollTop) + @updateStartRow() + @updateEndRow() @didStartScrolling() @updateVerticalScrollState() @updateDecorations() @@ -560,6 +564,7 @@ class TextEditorPresenter @updateScrollbarDimensions() @updateClientHeight() @updateScrollHeight() + @updateEndRow() setContentFrameWidth: (contentFrameWidth) -> unless @contentFrameWidth is contentFrameWidth @@ -591,9 +596,11 @@ class TextEditorPresenter unless @lineHeight is lineHeight @lineHeight = lineHeight @model.setLineHeightInPixels(lineHeight) - @updateContentHeight() + @updateContentDimensions(true, false) @updateScrollHeight() @updateHeightState() + @updateStartRow() + @updateEndRow() @updateVerticalScrollState() @updateDecorations() @updateLinesState() @@ -637,7 +644,7 @@ class TextEditorPresenter @characterWidthsChanged() unless @batchingCharacterMeasurement characterWidthsChanged: -> - @updateContentWidth() + @updateContentDimensions(false, true) @updateHorizontalScrollState() @updateContentState() @@ -710,16 +717,14 @@ class TextEditorPresenter return if change.textChanged intersectsVisibleRowRange = false - startRow = @computeStartRow() - endRow = @computeEndRow() oldRange = new Range(change.oldTailScreenPosition, change.oldHeadScreenPosition) newRange = new Range(change.newTailScreenPosition, change.newHeadScreenPosition) - if oldRange.intersectsRowRange(startRow, endRow - 1) + if oldRange.intersectsRowRange(@startRow, @endRow - 1) @removeFromLineDecorationCaches(decoration, oldRange) intersectsVisibleRowRange = true - if newRange.intersectsRowRange(startRow, endRow - 1) + if newRange.intersectsRowRange(@startRow, @endRow - 1) @addToLineDecorationCaches(decoration, newRange) intersectsVisibleRowRange = true @@ -771,11 +776,9 @@ class TextEditorPresenter @highlightDecorationsById = {} visibleHighlights = {} - startRow = @computeStartRow() - endRow = @computeEndRow() - return unless 0 <= startRow <= endRow <= Infinity + return unless 0 <= @startRow <= @endRow <= Infinity - for markerId, decorations of @model.decorationsForScreenRowRange(startRow, endRow - 1) + for markerId, decorations of @model.decorationsForScreenRowRange(@startRow, @endRow - 1) range = @model.getMarker(markerId).getScreenRange() for decoration in decorations if decoration.isType('line') or decoration.isType('line-number') @@ -821,22 +824,20 @@ class TextEditorPresenter updateHighlightState: (decoration) -> return unless @hasRequiredMeasurements() - startRow = @computeStartRow() - endRow = @computeEndRow() properties = decoration.getProperties() marker = decoration.getMarker() range = marker.getScreenRange() - if decoration.isDestroyed() or not marker.isValid() or range.isEmpty() or not range.intersectsRowRange(startRow, endRow - 1) + if decoration.isDestroyed() or not marker.isValid() or range.isEmpty() or not range.intersectsRowRange(@startRow, @endRow - 1) delete @state.content.highlights[decoration.id] @emitter.emit 'did-update-state' return - if range.start.row < startRow - range.start.row = startRow + if range.start.row < @startRow + range.start.row = @startRow range.start.column = 0 - if range.end.row >= endRow - range.end.row = endRow + if range.end.row >= @endRow + range.end.row = @endRow range.end.column = 0 if range.isEmpty() From b3d03d032a91ee6745cb93c09d1004a5384800cb Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 12 Feb 2015 11:16:11 -0700 Subject: [PATCH 11/11] :racehorse: Read TextEditor::cursors directly to avoid allocation --- src/text-editor-presenter.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 2be807105..31475e317 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -206,7 +206,7 @@ class TextEditorPresenter @state.content.cursors = {} return unless @hasRequiredMeasurements() - for cursor in @model.getCursors() + for cursor in @model.cursors # using property directly to avoid allocation if cursor.isVisible() and @startRow <= cursor.getScreenRow() < @endRow pixelRect = @pixelRectForScreenRange(cursor.getScreenRange()) pixelRect.width = @baseCharacterWidth if pixelRect.width is 0