From 2a2d0b60f719f55668fab12239a843689b022477 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 24 Jul 2014 16:41:25 -0700 Subject: [PATCH 1/4] :lipstick: --- spec/editor-component-spec.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 113a05620..112ffec88 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -374,12 +374,6 @@ describe "EditorComponent", -> expect(line2LeafNodes[2].textContent).toBe ' ' expect(line2LeafNodes[2].classList.contains('indent-guide')).toBe false - getLeafNodes = (node) -> - if node.children.length > 0 - flatten(toArray(node.children).map(getLeafNodes)) - else - [node] - describe "when the buffer contains null bytes", -> it "excludes the null byte from character measurement", -> editor.setText("a\0b") @@ -401,6 +395,12 @@ describe "EditorComponent", -> foldedLineNode = component.lineNodeForScreenRow(4) expect(foldedLineNode.querySelector('.fold-marker')).toBeFalsy() + getLeafNodes = (node) -> + if node.children.length > 0 + flatten(toArray(node.children).map(getLeafNodes)) + else + [node] + describe "gutter rendering", -> [gutter] = [] From c6116468e40949a67924fab709e66a693663d087 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 24 Jul 2014 16:54:01 -0700 Subject: [PATCH 2/4] Apply background color of root editor node to lines as an inline style This ensures lines have an opaque background that matches whatever the editor is styled as, but avoids the need to apply the .editor-colors class to the .lines div. That approach fell down when people were setting the background color via means other than .editor-colors, such as styling mini editors via the .editor.mini selector in the settings view. --- spec/editor-component-spec.coffee | 10 ++++++++++ src/editor-component.coffee | 12 +++++++++++- src/lines-component.coffee | 5 +++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 112ffec88..7f9626111 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -199,6 +199,16 @@ describe "EditorComponent", -> atom.config.set("editor.showInvisibles", false) expect(component.lineNodeForScreenRow(10).textContent).toBe nbsp + it "gives the lines div the same background color as the editor to improve GPU performance", -> + linesNode = componentNode.querySelector('.lines') + backgroundColor = getComputedStyle(wrapperNode).backgroundColor + expect(linesNode.style.backgroundColor).toBe backgroundColor + + wrapperNode.style.backgroundColor = 'rgb(255, 0, 0)' + advanceClock(component.domPollingInterval) + runSetImmediateCallbacks() + expect(linesNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' + describe "when showInvisibles is enabled", -> invisibles = null diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 543212e81..f9e015ad7 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -24,6 +24,7 @@ EditorComponent = React.createClass visible: false autoHeight: false + backgroundColor: null pendingScrollTop: null pendingScrollLeft: null selectOnMouseMove: false @@ -118,7 +119,7 @@ EditorComponent = React.createClass showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft, @scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles, @visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration, - placeholderText, @performedInitialMeasurement + placeholderText, @performedInitialMeasurement, @backgroundColor } ScrollbarComponent @@ -221,6 +222,7 @@ EditorComponent = React.createClass @updatesPaused = true @measureLineHeightAndDefaultCharWidth() @measureHeightAndWidth() + @sampleBackgroundColor() @measureScrollbars() @props.editor.setVisible(true) @updatesPaused = false @@ -772,6 +774,7 @@ EditorComponent = React.createClass if @visible = @isVisible() if wasVisible @measureHeightAndWidth() + @sampleBackgroundColor() else @performInitialMeasurement() @forceUpdate() @@ -813,6 +816,13 @@ EditorComponent = React.createClass clientWidth -= paddingLeft editor.setWidth(clientWidth) if clientWidth > 0 + sampleBackgroundColor: (suppressUpdate) -> + {parentView} = @props + {backgroundColor} = getComputedStyle(parentView.element) + if backgroundColor isnt @backgroundColor + @backgroundColor = backgroundColor + @requestUpdate() unless suppressUpdate + measureLineHeightAndDefaultCharWidthIfNeeded: (prevState) -> if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily') if @visible diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 14135089a..c4c2980ff 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -19,12 +19,13 @@ LinesComponent = React.createClass {performedInitialMeasurement} = @props if performedInitialMeasurement - {editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText} = @props + {editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props style = height: Math.max(scrollHeight, scrollViewHeight) width: scrollWidth WebkitTransform: @getTransform() + backgroundColor: backgroundColor div {className: 'lines', style}, div className: 'placeholder-text', placeholderText if placeholderText? @@ -50,7 +51,7 @@ LinesComponent = React.createClass 'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible', 'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration', - 'placeholderText', 'performedInitialMeasurement' + 'placeholderText', 'performedInitialMeasurement', 'backgroundColor' ) {renderedRowRange, pendingChanges} = newProps From 7738eeeaccbc7e08c6b47d2499d8f7c3d958be0d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 24 Jul 2014 17:23:04 -0700 Subject: [PATCH 3/4] Give the line-numbers div an opaque background for better GPU perf We sample both the background color of the editor and the gutter. If the gutter has an actual background color, we use it. Otherwise we fall back to the same background as the editor. --- spec/editor-component-spec.coffee | 12 ++++++++++++ src/editor-component.coffee | 22 +++++++++++++++++----- src/gutter-component.coffee | 8 ++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 7f9626111..850e2e9b8 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -504,6 +504,18 @@ describe "EditorComponent", -> runSetImmediateCallbacks() expect(componentNode.querySelector('.line-numbers').offsetHeight).toBe componentNode.offsetHeight + it "applies the background color of the gutter or the editor to the line numbers to improve GPU performance", -> + gutterNode = componentNode.querySelector('.gutter') + lineNumbersNode = gutterNode.querySelector('.line-numbers') + {backgroundColor} = getComputedStyle(wrapperNode) + expect(lineNumbersNode.style.backgroundColor).toBe backgroundColor + + # favor gutter color if it's assigned + gutterNode.style.backgroundColor = 'rgb(255, 0, 0)' + advanceClock(component.domPollingInterval) + runSetImmediateCallbacks() + expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' + describe "when the editor.showLineNumbers config is false", -> it "doesn't render any line numbers", -> expect(component.refs.gutter).toBeDefined() diff --git a/src/editor-component.coffee b/src/editor-component.coffee index f9e015ad7..1f285f35c 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -25,6 +25,7 @@ EditorComponent = React.createClass visible: false autoHeight: false backgroundColor: null + gutterBackgroundColor: null pendingScrollTop: null pendingScrollLeft: null selectOnMouseMove: false @@ -92,12 +93,12 @@ EditorComponent = React.createClass className += ' has-selection' if hasSelection div {className, style, tabIndex: -1}, - if not mini and showLineNumbers + if @shouldRenderGutter() GutterComponent { ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, - @useHardwareAcceleration, @performedInitialMeasurement + @useHardwareAcceleration, @performedInitialMeasurement, @backgroundColor, @gutterBackgroundColor } div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown, @@ -158,6 +159,9 @@ EditorComponent = React.createClass {editor} = @props Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels())) + shouldRenderGutter: -> + not @props.mini and @state.showLineNumbers + getInitialState: -> {} getDefaultProps: -> @@ -222,7 +226,7 @@ EditorComponent = React.createClass @updatesPaused = true @measureLineHeightAndDefaultCharWidth() @measureHeightAndWidth() - @sampleBackgroundColor() + @sampleBackgroundColors() @measureScrollbars() @props.editor.setVisible(true) @updatesPaused = false @@ -774,7 +778,7 @@ EditorComponent = React.createClass if @visible = @isVisible() if wasVisible @measureHeightAndWidth() - @sampleBackgroundColor() + @sampleBackgroundColors() else @performInitialMeasurement() @forceUpdate() @@ -816,13 +820,21 @@ EditorComponent = React.createClass clientWidth -= paddingLeft editor.setWidth(clientWidth) if clientWidth > 0 - sampleBackgroundColor: (suppressUpdate) -> + sampleBackgroundColors: (suppressUpdate) -> {parentView} = @props + {showLineNumbers} = @state {backgroundColor} = getComputedStyle(parentView.element) + if backgroundColor isnt @backgroundColor @backgroundColor = backgroundColor @requestUpdate() unless suppressUpdate + if @shouldRenderGutter() + gutterBackgroundColor = getComputedStyle(@refs.gutter.getDOMNode()).backgroundColor + if gutterBackgroundColor isnt @gutterBackgroundColor + @gutterBackgroundColor = gutterBackgroundColor + @requestUpdate() unless suppressUpdate + measureLineHeightAndDefaultCharWidthIfNeeded: (prevState) -> if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily') if @visible diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index ede951657..e9eeddaf9 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -16,12 +16,16 @@ GutterComponent = React.createClass measuredWidth: null render: -> - {scrollHeight, scrollViewHeight, onMouseDown} = @props + {scrollHeight, scrollViewHeight, onMouseDown, backgroundColor, gutterBackgroundColor} = @props + + if gutterBackgroundColor isnt 'rbga(0, 0, 0, 0)' + backgroundColor = gutterBackgroundColor div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown, div className: 'line-numbers', ref: 'lineNumbers', style: height: Math.max(scrollHeight, scrollViewHeight) WebkitTransform: @getTransform() + backgroundColor: backgroundColor getTransform: -> {scrollTop, useHardwareAcceleration} = @props @@ -47,7 +51,7 @@ GutterComponent = React.createClass shouldComponentUpdate: (newProps) -> return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations', - 'scrollViewHeight', 'useHardwareAcceleration' + 'scrollViewHeight', 'useHardwareAcceleration', 'backgroundColor', 'gutterBackgroundColor' ) {renderedRowRange, pendingChanges, lineDecorations} = newProps From 85363f8eaa8a85ea3b61f40b7cbd79cffbe0a462 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 24 Jul 2014 17:25:04 -0700 Subject: [PATCH 4/4] Resample background colors whenever stylesheets change This prevents a flicker that occurred on theme changes when we just detected this via polling. I'm going to leave the polling as a catch-all in case the editor is styled inline in some way. --- src/editor-component.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 1f285f35c..51a5d21f4 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -679,6 +679,7 @@ EditorComponent = React.createClass onStylesheetsChanged: (stylesheet) -> @refreshScrollbars() if @containsScrollbarSelector(stylesheet) + @sampleBackgroundColors() @remeasureCharacterWidthsIfVisibleAfterNextUpdate = true @requestUpdate() if @visible