diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index f576685c3..832ca993d 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -2558,7 +2558,7 @@ describe "TextEditorComponent", -> expect(wrapperNode.classList.contains('mini')).toBe true it "does not have an opaque background on lines", -> - expect(component.refs.lines.getDOMNode().getAttribute('style')).not.toContain 'background-color' + expect(component.linesComponent.domNode.getAttribute('style')).not.toContain 'background-color' it "does not render invisible characters", -> atom.config.set('editor.invisibles', eol: 'E') diff --git a/src/config-schema.coffee b/src/config-schema.coffee index f849e4909..1796bb64c 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -162,10 +162,6 @@ module.exports = default: 300 minimum: 0 description: 'Time interval in milliseconds within which operations will be grouped together in the undo history' - useHardwareAcceleration: - type: 'boolean' - default: true - description: 'Disabling will improve editor font rendering but reduce scrolling performance.' useShadowDOM: type: 'boolean' default: true diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 564c611ab..cb443cf26 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -30,13 +30,8 @@ GutterComponent = React.createClass backgroundColor: backgroundColor getTransform: -> - {useHardwareAcceleration} = @props {scrollTop} = @newState - - if useHardwareAcceleration - "translate3d(0px, #{-scrollTop}px, 0px)" - else - "translate(0px, #{-scrollTop}px)" + "translate3d(0px, #{-scrollTop}px, 0px)" componentWillMount: -> @lineNumberNodesById = {} diff --git a/src/lines-component.coffee b/src/lines-component.coffee index dba209e07..e6c0733e1 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -1,7 +1,5 @@ _ = require 'underscore-plus' -React = require 'react-atom-fork' -{div, span} = require 'reactionary-atom-fork' -{debounce, isEqual, isEqualForProperties, multiplyString, toArray} = require 'underscore-plus' +{toArray} = require 'underscore-plus' {$$} = require 'space-pen' CursorsComponent = require './cursors-component' @@ -13,76 +11,58 @@ AcceptFilter = {acceptNode: -> NodeFilter.FILTER_ACCEPT} WrapperDiv = document.createElement('div') module.exports = -LinesComponent = React.createClass - displayName: 'LinesComponent' +class LinesComponent placeholderTextDiv: null - render: -> - div {className: 'lines'} - - getTransform: (scrollTop, scrollLeft) -> - {useHardwareAcceleration} = @props - - if useHardwareAcceleration - "translate3d(#{-scrollLeft}px, #{-scrollTop}px, 0px)" - else - "translate(#{-scrollLeft}px, #{-scrollTop}px)" - - componentWillMount: -> + constructor: ({@presenter, @hostElement, @useShadowDOM}) -> @measuredLines = new Set @lineNodesByLineId = {} @screenRowsByLineId = {} @lineIdsByScreenRow = {} @renderedDecorationsByLineId = {} - componentDidMount: -> - node = @getDOMNode() + @domNode = document.createElement('div') + @domNode.classList.add('lines') - @cursorsComponent = new CursorsComponent(@props.presenter) - node.appendChild(@cursorsComponent.domNode) + @cursorsComponent = new CursorsComponent(@presenter) + @domNode.appendChild(@cursorsComponent.domNode) - @highlightsComponent = new HighlightsComponent(@props.presenter) - node.appendChild(@highlightsComponent.domNode) + @highlightsComponent = new HighlightsComponent(@presenter) + @domNode.appendChild(@highlightsComponent.domNode) - if @props.useShadowDOM + if @useShadowDOM insertionPoint = document.createElement('content') insertionPoint.setAttribute('select', '.overlayer') - node.appendChild(insertionPoint) + @domNode.appendChild(insertionPoint) insertionPoint = document.createElement('content') insertionPoint.setAttribute('select', 'atom-overlay') - @overlayManager = new OverlayManager(@props.hostElement) - node.appendChild(insertionPoint) + @overlayManager = new OverlayManager(@hostElement) + @domNode.appendChild(insertionPoint) else - @overlayManager = new OverlayManager(node) + @overlayManager = new OverlayManager(@domNode) @updateSync() - componentDidUpdate: -> - @updateSync() - - updateSync: -> - {visible, presenter} = @props - @newState = presenter.state.content + updateSync: (visible) -> + @newState = @presenter.state.content @oldState ?= {lines: {}} - node = @getDOMNode() - if @newState.scrollHeight isnt @oldState.scrollHeight - node.style.height = @newState.scrollHeight + 'px' + @domNode.style.height = @newState.scrollHeight + 'px' @oldState.scrollHeight = @newState.scrollHeight if @newState.scrollWidth isnt @oldState.scrollWidth - node.style.width = @newState.scrollWidth + 'px' + @domNode.style.width = @newState.scrollWidth + 'px' @oldState.scrollWidth = @newState.scrollWidth if @newState.scrollTop isnt @oldState.scrollTop or @newState.scrollLeft isnt @oldState.scrollLeft - node.style['-webkit-transform'] = @getTransform(@newState.scrollTop, @newState.scrollLeft) + @domNode.style['-webkit-transform'] = "translate3d(#{-@newState.scrollLeft}px, #{-@newState.scrollTop}px, 0px)" @oldState.scrollTop = @newState.scrollTop @oldState.scrollLeft = @newState.scrollLeft if @newState.backgroundColor isnt @oldState.backgroundColor - node.style.backgroundColor = @newState.backgroundColor + @domNode.style.backgroundColor = @newState.backgroundColor @oldState.backgroundColor = @newState.backgroundColor if @newState.placeholderText isnt @oldState.placeholderText @@ -91,7 +71,7 @@ LinesComponent = React.createClass @placeholderTextDiv = document.createElement('div') @placeholderTextDiv.classList.add('placeholder-text') @placeholderTextDiv.textContent = @newState.placeholderText - node.appendChild(@placeholderTextDiv) + @domNode.appendChild(@placeholderTextDiv) @removeLineNodes() unless @oldState.indentGuidesVisible is @newState.indentGuidesVisible @updateLineNodes() @@ -100,15 +80,11 @@ LinesComponent = React.createClass @cursorsComponent.updateSync() @highlightsComponent.updateSync() - @overlayManager?.render(@props) + @overlayManager?.render(@presenter) @oldState.indentGuidesVisible = @newState.indentGuidesVisible @oldState.scrollWidth = @newState.scrollWidth - clearScreenRowCaches: -> - @screenRowsByLineId = {} - @lineIdsByScreenRow = {} - removeLineNodes: -> @removeLineNode(id) for id of @oldState.lines @@ -120,8 +96,6 @@ LinesComponent = React.createClass delete @oldState.lines[id] updateLineNodes: -> - {presenter} = @props - for id of @oldState.lines unless @newState.lines.hasOwnProperty(id) @removeLineNode(id) @@ -144,15 +118,13 @@ LinesComponent = React.createClass return unless newLineIds? WrapperDiv.innerHTML = newLinesHTML - newLineNodes = toArray(WrapperDiv.children) - node = @getDOMNode() + newLineNodes = _.toArray(WrapperDiv.children) for id, i in newLineIds lineNode = newLineNodes[i] @lineNodesByLineId[id] = lineNode - node.appendChild(lineNode) + @domNode.appendChild(lineNode) buildLineHTML: (id) -> - {presenter} = @props {scrollWidth} = @newState {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id] @@ -197,7 +169,6 @@ LinesComponent = React.createClass @buildEndOfLineHTML(id) or ' ' buildLineInnerHTML: (id) -> - {editor} = @props {indentGuidesVisible} = @newState {tokens, text, isOnlyWhitespace} = @newState.lines[id] innerHTML = "" @@ -275,26 +246,22 @@ LinesComponent = React.createClass @lineNodesByLineId[@lineIdsByScreenRow[screenRow]] measureLineHeightAndDefaultCharWidth: -> - node = @getDOMNode() - node.appendChild(DummyLineNode) + @domNode.appendChild(DummyLineNode) lineHeightInPixels = DummyLineNode.getBoundingClientRect().height charWidth = DummyLineNode.firstChild.getBoundingClientRect().width - node.removeChild(DummyLineNode) + @domNode.removeChild(DummyLineNode) - {editor, presenter} = @props - presenter.setLineHeight(lineHeightInPixels) - presenter.setBaseCharacterWidth(charWidth) + @presenter.setLineHeight(lineHeightInPixels) + @presenter.setBaseCharacterWidth(charWidth) remeasureCharacterWidths: -> - return unless @props.presenter.baseCharacterWidth + return unless @presenter.baseCharacterWidth @clearScopedCharWidths() @measureCharactersInNewLines() measureCharactersInNewLines: -> - {presenter} = @props - - presenter.batchCharacterMeasurement => + @presenter.batchCharacterMeasurement => for id, lineState of @oldState.lines unless @measuredLines.has(id) lineNode = @lineNodesByLineId[id] @@ -302,13 +269,12 @@ LinesComponent = React.createClass return measureCharactersInLine: (tokenizedLine, lineNode) -> - {editor} = @props rangeForMeasurement = null iterator = null charIndex = 0 for {value, scopes, hasPairedCharacter} in tokenizedLine.tokens - charWidths = editor.getScopedCharWidths(scopes) + charWidths = @presenter.getScopedCharacterWidths(scopes) valueIndex = 0 while valueIndex < value.length @@ -340,7 +306,7 @@ LinesComponent = React.createClass rangeForMeasurement.setStart(textNode, i) rangeForMeasurement.setEnd(textNode, i + charLength) charWidth = rangeForMeasurement.getBoundingClientRect().width - @props.presenter.setScopedCharacterWidth(scopes, char, charWidth) + @presenter.setScopedCharacterWidth(scopes, char, charWidth) charIndex += charLength @@ -348,5 +314,4 @@ LinesComponent = React.createClass clearScopedCharWidths: -> @measuredLines.clear() - @props.editor.clearScopedCharWidths() - @props.presenter.clearScopedCharacterWidths() + @presenter.clearScopedCharacterWidths() diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 82387fcf7..ecfbc8667 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -3,9 +3,7 @@ class OverlayManager constructor: (@container) -> @overlayNodesById = {} - render: (props) -> - {presenter} = props - + render: (presenter) -> for decorationId, {pixelPosition, item} of presenter.state.content.overlays @renderOverlay(presenter, decorationId, item, pixelPosition) diff --git a/src/scrollbar-component.coffee b/src/scrollbar-component.coffee index eaf64b8bc..4447acc8d 100644 --- a/src/scrollbar-component.coffee +++ b/src/scrollbar-component.coffee @@ -7,7 +7,7 @@ ScrollbarComponent = React.createClass displayName: 'ScrollbarComponent' render: -> - {presenter, orientation, className, useHardwareAcceleration} = @props + {presenter, orientation, className} = @props switch orientation when 'vertical' @@ -18,7 +18,7 @@ ScrollbarComponent = React.createClass style = {} style.display = 'none' unless @newState.visible - style.transform = 'translateZ(0)' if useHardwareAcceleration # See atom/atom#3559 + style.transform = 'translateZ(0)' # See atom/atom#3559 switch orientation when 'vertical' style.width = @newState.width diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 0f4695ca0..833491c30 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -50,10 +50,8 @@ TextEditorComponent = React.createClass @performedInitialMeasurement = false if editor.isDestroyed() if @performedInitialMeasurement - visible = @isVisible() - hiddenInputStyle = @getHiddenInputPosition() - hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration + hiddenInputStyle.WebkitTransform = 'translateZ(0)' style.height = @presenter.state.height if @presenter.state.height? if useShadowDOM @@ -67,7 +65,7 @@ TextEditorComponent = React.createClass if @gutterVisible GutterComponent { ref: 'gutter', onMouseDown: @onGutterMouseDown, - @presenter, editor, @useHardwareAcceleration + @presenter, editor } div ref: 'scrollView', className: 'scroll-view', @@ -76,17 +74,12 @@ TextEditorComponent = React.createClass className: 'hidden-input' style: hiddenInputStyle - LinesComponent { - ref: 'lines', @presenter, editor, hostElement, @useHardwareAcceleration, useShadowDOM, visible - } - ScrollbarComponent ref: 'horizontalScrollbar' className: 'horizontal-scrollbar' orientation: 'horizontal' presenter: @presenter onScroll: @onHorizontalScroll - useHardwareAcceleration: @useHardwareAcceleration ScrollbarComponent ref: 'verticalScrollbar' @@ -94,7 +87,6 @@ TextEditorComponent = React.createClass orientation: 'vertical' presenter: @presenter onScroll: @onVerticalScroll - useHardwareAcceleration: @useHardwareAcceleration # Also used to measure the height/width of scrollbars after the initial render ScrollbarCornerComponent @@ -126,9 +118,14 @@ TextEditorComponent = React.createClass stoppedScrollingDelay: 200 @presenter.onDidUpdateState(@requestUpdate) - componentDidMount: -> - {editor, stylesElement} = @props + {editor, stylesElement, hostElement, useShadowDOM} = @props + + @linesComponent = new LinesComponent({@presenter, hostElement, useShadowDOM}) + scrollViewNode = @refs.scrollView.getDOMNode() + horizontalScrollbarNode = @refs.horizontalScrollbar.getDOMNode() + scrollViewNode.insertBefore(@linesComponent.domNode, horizontalScrollbarNode) + @linesComponent.updateSync(@isVisible()) @observeEditor() @listenForDOMEvents() @@ -161,6 +158,8 @@ TextEditorComponent = React.createClass @cursorMoved = false @selectionChanged = false + @linesComponent.updateSync(@isVisible()) + if @props.editor.isAlive() @updateParentViewFocusedClassIfNeeded(prevState) @updateParentViewMiniClass() @@ -289,7 +288,6 @@ TextEditorComponent = React.createClass timeoutId = setTimeout(writeSelectedTextToSelectionClipboard) observeConfig: -> - @subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration @subscribe atom.config.onDidChange 'editor.fontSize', @sampleFontStyling @subscribe atom.config.onDidChange 'editor.fontFamily', @sampleFontStyling @subscribe atom.config.onDidChange 'editor.lineHeight', @sampleFontStyling @@ -689,14 +687,14 @@ TextEditorComponent = React.createClass measureLineHeightAndDefaultCharWidth: -> if @isVisible() @measureLineHeightAndDefaultCharWidthWhenShown = false - @refs.lines.measureLineHeightAndDefaultCharWidth() + @linesComponent.measureLineHeightAndDefaultCharWidth() else @measureLineHeightAndDefaultCharWidthWhenShown = true remeasureCharacterWidths: -> if @isVisible() @remeasureCharacterWidthsWhenShown = false - @refs.lines.remeasureCharacterWidths() + @linesComponent.remeasureCharacterWidths() else @remeasureCharacterWidthsWhenShown = true @@ -761,7 +759,7 @@ TextEditorComponent = React.createClass consolidateSelections: (e) -> e.abortKeyBinding() unless @props.editor.consolidateSelections() - lineNodeForScreenRow: (screenRow) -> @refs.lines.lineNodeForScreenRow(screenRow) + lineNodeForScreenRow: (screenRow) -> @linesComponent.lineNodeForScreenRow(screenRow) lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow) @@ -816,11 +814,6 @@ TextEditorComponent = React.createClass if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 - setUseHardwareAcceleration: (useHardwareAcceleration=true) -> - unless @useHardwareAcceleration is useHardwareAcceleration - @useHardwareAcceleration = useHardwareAcceleration - @requestUpdate() - screenPositionForMouseEvent: (event) -> pixelPosition = @pixelPositionForMouseEvent(event) @props.editor.screenPositionForPixelPosition(pixelPosition) @@ -829,7 +822,7 @@ TextEditorComponent = React.createClass {editor} = @props {clientX, clientY} = event - linesClientRect = @refs.lines.getDOMNode().getBoundingClientRect() + linesClientRect = @linesComponent.domNode.getBoundingClientRect() top = clientY - linesClientRect.top left = clientX - linesClientRect.left {top, left} diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 56a2fad98..6e8417e49 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -631,6 +631,7 @@ class TextEditorPresenter clearScopedCharacterWidths: -> @characterWidthsByScope = {} + @model.clearScopedCharWidths() hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth?