From 512d4da5875b3093fafac76a932926cfbb0cd41f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Jul 2014 11:56:05 -0600 Subject: [PATCH 1/4] Add editor.gpuDisabled option to prevent React editor from using layers When gpuDisabled is true, we use `translate` instead of `translate3d` to position various elements, preventing the creation of GPU layers. --- src/cursor-component.coffee | 19 ++++++++++++++----- src/cursors-component.coffee | 4 ++-- src/editor-component.coffee | 14 ++++++++++---- src/editor-view.coffee | 1 + src/gutter-component.coffee | 14 +++++++++++--- src/lines-component.coffee | 14 +++++++++++--- 6 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/cursor-component.coffee b/src/cursor-component.coffee index 2bd7880a9..b0aed6dd0 100644 --- a/src/cursor-component.coffee +++ b/src/cursor-component.coffee @@ -7,14 +7,23 @@ CursorComponent = React.createClass displayName: 'CursorComponent' render: -> - {pixelRect, scrollTop, scrollLeft, defaultCharWidth} = @props - {top, left, height, width} = pixelRect - top -= scrollTop - left -= scrollLeft + {pixelRect, defaultCharWidth} = @props + {height, width} = pixelRect width = defaultCharWidth if width is 0 - WebkitTransform = "translate3d(#{left}px, #{top}px, 0px)" + WebkitTransform = @getTransform() div className: 'cursor', style: {height, width, WebkitTransform} + getTransform: -> + {pixelRect, scrollTop, scrollLeft, gpuDisabled} = @props + {top, left} = pixelRect + top -= scrollTop + left -= scrollLeft + + if gpuDisabled + "translate(#{left}px, #{top}px)" + else + "translate3d(#{left}px, #{top}px, 0px)" + shouldComponentUpdate: (newProps) -> not isEqualForProperties(newProps, @props, 'pixelRect', 'scrollTop', 'scrollLeft', 'defaultCharWidth') diff --git a/src/cursors-component.coffee b/src/cursors-component.coffee index a1e541bfb..6fd179cd9 100644 --- a/src/cursors-component.coffee +++ b/src/cursors-component.coffee @@ -12,7 +12,7 @@ CursorsComponent = React.createClass cursorBlinkIntervalHandle: null render: -> - {cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth} = @props + {cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, gpuDisabled} = @props {blinkOff} = @state className = 'cursors' @@ -34,7 +34,7 @@ CursorsComponent = React.createClass shouldComponentUpdate: (newProps, newState) -> not newState.blinkOff is @state.blinkOff or - not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth') + not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'gpuDisabled') componentWillUpdate: (newProps) -> cursorsMoved = @props.cursorPixelRects? and diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 8e1efdd3e..b146795b2 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -74,7 +74,7 @@ EditorComponent = React.createClass verticallyScrollable = editor.verticallyScrollable() horizontallyScrollable = editor.horizontallyScrollable() hiddenInputStyle = @getHiddenInputPosition() - hiddenInputStyle.WebkitTransform = 'translateZ(0)' + hiddenInputStyle.WebkitTransform = 'translateZ(0)' unless @gpuDisabled if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow) mouseWheelScreenRow = @mouseWheelScreenRow @@ -87,7 +87,7 @@ EditorComponent = React.createClass GutterComponent { ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged, lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, - scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow + scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @gpuDisabled } div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown, @@ -100,14 +100,14 @@ EditorComponent = React.createClass CursorsComponent { scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay, - lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount + lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @gpuDisabled } LinesComponent { ref: 'lines', editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations, showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft, @scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles, - visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth + visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @gpuDisabled } ScrollbarComponent @@ -481,6 +481,7 @@ EditorComponent = React.createClass @subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles @subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers @subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity + @subscribe atom.config.observe 'editor.gpuDisabled', @setGPUDisabled onFocus: -> @refs.input.focus() @@ -873,6 +874,11 @@ EditorComponent = React.createClass if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 + setGPUDisabled: (gpuDisabled) -> + unless @gpuDisabled is gpuDisabled + @gpuDisabled = gpuDisabled + @requestUpdate() + screenPositionForMouseEvent: (event) -> pixelPosition = @pixelPositionForMouseEvent(event) @props.editor.screenPositionForPixelPosition(pixelPosition) diff --git a/src/editor-view.coffee b/src/editor-view.coffee index a7b200a7b..0c4ded5c6 100644 --- a/src/editor-view.coffee +++ b/src/editor-view.coffee @@ -57,6 +57,7 @@ class EditorView extends View softTabs: true softWrapAtPreferredLineLength: false scrollSensitivity: 40 + gpuDisabled: false @nextEditorId: 1 diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 2555c7ebd..8ad08877e 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -15,14 +15,22 @@ GutterComponent = React.createClass measuredWidth: null render: -> - {scrollHeight, scrollViewHeight, scrollTop, onMouseDown} = @props + {scrollHeight, scrollViewHeight, onMouseDown} = @props div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown, # The line-numbers div must have the 'editor-colors' class so it has an # opaque background to avoid sub-pixel anti-aliasing problems on the GPU div className: 'gutter line-numbers editor-colors', ref: 'lineNumbers', style: height: Math.max(scrollHeight, scrollViewHeight) - WebkitTransform: "translate3d(0px, #{-scrollTop}px, 0px)" + WebkitTransform: @getTransform() + + getTransform: -> + {scrollTop, gpuDisabled} = @props + + if gpuDisabled + "translate(0px, #{-scrollTop}px)" + else + "translate3d(0px, #{-scrollTop}px, 0px)" componentWillMount: -> @lineNumberNodesById = {} @@ -39,7 +47,7 @@ GutterComponent = React.createClass shouldComponentUpdate: (newProps) -> return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations', - 'scrollViewHeight' + 'scrollViewHeight', 'gpuDisabled' ) {renderedRowRange, pendingChanges, lineDecorations} = newProps diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 63809691b..592f289b1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -16,18 +16,26 @@ LinesComponent = React.createClass render: -> if @isMounted() - {editor, highlightDecorations, scrollTop, scrollLeft, scrollHeight, scrollWidth} = @props + {editor, highlightDecorations, scrollHeight, scrollWidth} = @props {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props style = height: Math.max(scrollHeight, scrollViewHeight) width: scrollWidth - WebkitTransform: "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)" + WebkitTransform: @getTransform() # The lines div must have the 'editor-colors' class so it has an opaque # background to avoid sub-pixel anti-aliasing problems on the GPU div {className: 'lines editor-colors', style}, HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount}) + getTransform: -> + {scrollTop, scrollLeft, gpuDisabled} = @props + + if gpuDisabled + "translate(#{-scrollLeft}px, #{-scrollTop}px)" + else + "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)" + componentWillMount: -> @measuredLines = new WeakSet @lineNodesByLineId = {} @@ -39,7 +47,7 @@ LinesComponent = React.createClass return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible', - 'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth' + 'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'gpuDisabled' ) {renderedRowRange, pendingChanges} = newProps From 0edfbaebebe069d43f854bc9a41e2d438d66d74f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Jul 2014 12:06:52 -0600 Subject: [PATCH 2/4] Rename editor option to useHardwareAcceleration --- src/cursor-component.coffee | 8 ++++---- src/cursors-component.coffee | 4 ++-- src/editor-component.coffee | 16 ++++++++-------- src/editor-view.coffee | 2 +- src/gutter-component.coffee | 10 +++++----- src/lines-component.coffee | 10 +++++----- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/cursor-component.coffee b/src/cursor-component.coffee index b0aed6dd0..a2a752999 100644 --- a/src/cursor-component.coffee +++ b/src/cursor-component.coffee @@ -15,15 +15,15 @@ CursorComponent = React.createClass div className: 'cursor', style: {height, width, WebkitTransform} getTransform: -> - {pixelRect, scrollTop, scrollLeft, gpuDisabled} = @props + {pixelRect, scrollTop, scrollLeft, useHardwareAcceleration} = @props {top, left} = pixelRect top -= scrollTop left -= scrollLeft - if gpuDisabled - "translate(#{left}px, #{top}px)" - else + if useHardwareAcceleration "translate3d(#{left}px, #{top}px, 0px)" + else + "translate(#{left}px, #{top}px)" shouldComponentUpdate: (newProps) -> not isEqualForProperties(newProps, @props, 'pixelRect', 'scrollTop', 'scrollLeft', 'defaultCharWidth') diff --git a/src/cursors-component.coffee b/src/cursors-component.coffee index 6fd179cd9..a87f59830 100644 --- a/src/cursors-component.coffee +++ b/src/cursors-component.coffee @@ -12,7 +12,7 @@ CursorsComponent = React.createClass cursorBlinkIntervalHandle: null render: -> - {cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, gpuDisabled} = @props + {cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props {blinkOff} = @state className = 'cursors' @@ -34,7 +34,7 @@ CursorsComponent = React.createClass shouldComponentUpdate: (newProps, newState) -> not newState.blinkOff is @state.blinkOff or - not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'gpuDisabled') + not isEqualForProperties(newProps, @props, 'cursorPixelRects', 'scrollTop', 'scrollLeft', 'defaultCharWidth', 'useHardwareAcceleration') componentWillUpdate: (newProps) -> cursorsMoved = @props.cursorPixelRects? and diff --git a/src/editor-component.coffee b/src/editor-component.coffee index b146795b2..a4b5772b0 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -74,7 +74,7 @@ EditorComponent = React.createClass verticallyScrollable = editor.verticallyScrollable() horizontallyScrollable = editor.horizontallyScrollable() hiddenInputStyle = @getHiddenInputPosition() - hiddenInputStyle.WebkitTransform = 'translateZ(0)' unless @gpuDisabled + hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow) mouseWheelScreenRow = @mouseWheelScreenRow @@ -87,7 +87,7 @@ EditorComponent = React.createClass GutterComponent { ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged, lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, - scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @gpuDisabled + scrollTop, scrollHeight, lineHeightInPixels, @pendingChanges, mouseWheelScreenRow, @useHardwareAcceleration } div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown, @@ -100,14 +100,14 @@ EditorComponent = React.createClass CursorsComponent { scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay, - lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @gpuDisabled + lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration } LinesComponent { ref: 'lines', editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations, showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft, @scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles, - visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @gpuDisabled + visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration } ScrollbarComponent @@ -481,7 +481,7 @@ EditorComponent = React.createClass @subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles @subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers @subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity - @subscribe atom.config.observe 'editor.gpuDisabled', @setGPUDisabled + @subscribe atom.config.observe 'editor.useHardwareAcceleration', @setuseHardwareAcceleration onFocus: -> @refs.input.focus() @@ -874,9 +874,9 @@ EditorComponent = React.createClass if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 - setGPUDisabled: (gpuDisabled) -> - unless @gpuDisabled is gpuDisabled - @gpuDisabled = gpuDisabled + setuseHardwareAcceleration: (useHardwareAcceleration) -> + unless @useHardwareAcceleration is useHardwareAcceleration + @useHardwareAcceleration = useHardwareAcceleration @requestUpdate() screenPositionForMouseEvent: (event) -> diff --git a/src/editor-view.coffee b/src/editor-view.coffee index 0c4ded5c6..848097404 100644 --- a/src/editor-view.coffee +++ b/src/editor-view.coffee @@ -57,7 +57,7 @@ class EditorView extends View softTabs: true softWrapAtPreferredLineLength: false scrollSensitivity: 40 - gpuDisabled: false + useHardwareAcceleration: true @nextEditorId: 1 diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 8ad08877e..ba6c07988 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -25,12 +25,12 @@ GutterComponent = React.createClass WebkitTransform: @getTransform() getTransform: -> - {scrollTop, gpuDisabled} = @props + {scrollTop, useHardwareAcceleration} = @props - if gpuDisabled - "translate(0px, #{-scrollTop}px)" - else + if useHardwareAcceleration "translate3d(0px, #{-scrollTop}px, 0px)" + else + "translate(0px, #{-scrollTop}px)" componentWillMount: -> @lineNumberNodesById = {} @@ -47,7 +47,7 @@ GutterComponent = React.createClass shouldComponentUpdate: (newProps) -> return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeightInPixels', 'mouseWheelScreenRow', 'lineDecorations', - 'scrollViewHeight', 'gpuDisabled' + 'scrollViewHeight', 'useHardwareAcceleration' ) {renderedRowRange, pendingChanges, lineDecorations} = newProps diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 592f289b1..2458b06f8 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -29,12 +29,12 @@ LinesComponent = React.createClass HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount}) getTransform: -> - {scrollTop, scrollLeft, gpuDisabled} = @props + {scrollTop, scrollLeft, useHardwareAcceleration} = @props - if gpuDisabled - "translate(#{-scrollLeft}px, #{-scrollTop}px)" - else + if useHardwareAcceleration "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)" + else + "translate(#{-scrollLeft}px, #{-scrollTop}px)" componentWillMount: -> @measuredLines = new WeakSet @@ -47,7 +47,7 @@ LinesComponent = React.createClass return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible', - 'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'gpuDisabled' + 'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration' ) {renderedRowRange, pendingChanges} = newProps From 18d17b55b56a0755e5dc5df8f21fef7b41ccda4a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Jul 2014 12:33:45 -0600 Subject: [PATCH 3/4] Pass useHardwareAcceleration property down to CursorComponent instances --- src/cursors-component.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cursors-component.coffee b/src/cursors-component.coffee index a87f59830..b33e231e5 100644 --- a/src/cursors-component.coffee +++ b/src/cursors-component.coffee @@ -21,7 +21,7 @@ CursorsComponent = React.createClass div {className}, if @isMounted() for key, pixelRect of cursorPixelRects - CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth}) + CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration}) getInitialState: -> blinkOff: false From 4efabd2b5edf19c721e7135cbfd8dd06956bc003 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Jul 2014 12:34:00 -0600 Subject: [PATCH 4/4] :lipstick: method name --- src/editor-component.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editor-component.coffee b/src/editor-component.coffee index a4b5772b0..d7e9e643a 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -481,7 +481,7 @@ EditorComponent = React.createClass @subscribe atom.config.observe 'editor.showInvisibles', @setShowInvisibles @subscribe atom.config.observe 'editor.showLineNumbers', @setShowLineNumbers @subscribe atom.config.observe 'editor.scrollSensitivity', @setScrollSensitivity - @subscribe atom.config.observe 'editor.useHardwareAcceleration', @setuseHardwareAcceleration + @subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration onFocus: -> @refs.input.focus() @@ -874,7 +874,7 @@ EditorComponent = React.createClass if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 - setuseHardwareAcceleration: (useHardwareAcceleration) -> + setUseHardwareAcceleration: (useHardwareAcceleration=true) -> unless @useHardwareAcceleration is useHardwareAcceleration @useHardwareAcceleration = useHardwareAcceleration @requestUpdate()