mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 15:37:46 +03:00
Enable subpixel font scaling
For certain font sizes, enabling `textRendering: optimizeLegibility` caused a bunch of measurement-related issues. You can reproduce it by setting the following in your stylesheet: ``` atom-text-editor { font-size: 14px; text-rendering: optimizeLegibility; } ``` Although I wanted to defer subpixel font scaling to a later moment, it seems like Chrome needs to have it enabled in order to properly support the "legibility" path for text rendering. (I guess this is part of the reason why the Chromium team enabled it by default at some point in the past.)
This commit is contained in:
parent
b7e373fdca
commit
beb7896234
@ -70,10 +70,10 @@ describe "LinesYardstick", ->
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 0])).toEqual({left: 0, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 1])).toEqual({left: 7, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 38, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 42, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 280, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 37.8046875, top: 0})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 43.20703125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72.20703125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 288.046875, top: 28})
|
||||
|
||||
it "reuses already computed pixel positions unless it is invalidated", ->
|
||||
atom.styles.addStyleSheet """
|
||||
@ -83,9 +83,9 @@ describe "LinesYardstick", ->
|
||||
}
|
||||
"""
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 20, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 60, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 100, top: 70})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70})
|
||||
|
||||
atom.styles.addStyleSheet """
|
||||
* {
|
||||
@ -93,15 +93,15 @@ describe "LinesYardstick", ->
|
||||
}
|
||||
"""
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 20, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 60, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 100, top: 70})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70})
|
||||
|
||||
linesYardstick.invalidateCache()
|
||||
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120, top: 70})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24.00390625, top: 14})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72.01171875, top: 28})
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120.01171875, top: 70})
|
||||
|
||||
it "correctly handles RTL characters", ->
|
||||
atom.styles.addStyleSheet """
|
||||
@ -114,8 +114,8 @@ describe "LinesYardstick", ->
|
||||
editor.setText("السلام عليكم")
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 0]).left).toBe 0
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 1]).left).toBe 8
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 2]).left).toBe 17
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5]).left).toBe 34
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 2]).left).toBe 16
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 5]).left).toBe 33
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 7]).left).toBe 50
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 9]).left).toBe 67
|
||||
expect(linesYardstick.pixelPositionForScreenPosition([0, 11]).left).toBe 84
|
||||
@ -133,13 +133,13 @@ describe "LinesYardstick", ->
|
||||
"""
|
||||
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 0, left: 12.5})).toEqual([0, 2])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 14, left: 17.8})).toEqual([1, 3])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 14, left: 18.8})).toEqual([1, 3])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 28, left: 100})).toEqual([2, 14])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 32, left: 24.3})).toEqual([2, 3])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 46, left: 66.5})).toEqual([3, 9])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 99.9})).toEqual([5, 14])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 221.5})).toEqual([5, 29])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 222})).toEqual([5, 30])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 224.4365234375})).toEqual([5, 29])
|
||||
expect(linesYardstick.screenPositionForPixelPosition({top: 80, left: 225})).toEqual([5, 30])
|
||||
|
||||
it "clips pixel positions above buffer start", ->
|
||||
expect(linesYardstick.screenPositionForPixelPosition(top: -Infinity, left: -Infinity)).toEqual [0, 0]
|
||||
|
@ -958,8 +958,8 @@ describe "TextEditorComponent", ->
|
||||
cursorNodes = componentNode.querySelectorAll('.cursor')
|
||||
expect(cursorNodes.length).toBe 1
|
||||
expect(cursorNodes[0].offsetHeight).toBe lineHeightInPixels
|
||||
expect(cursorNodes[0].offsetWidth).toBe charWidth
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{5 * charWidth}px, #{0 * lineHeightInPixels}px)"
|
||||
expect(cursorNodes[0].offsetWidth).toBeCloseTo charWidth, 0
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(5 * charWidth)}px, #{0 * lineHeightInPixels}px)"
|
||||
|
||||
cursor2 = editor.addCursorAtScreenPosition([8, 11], autoscroll: false)
|
||||
cursor3 = editor.addCursorAtScreenPosition([4, 10], autoscroll: false)
|
||||
@ -968,8 +968,8 @@ describe "TextEditorComponent", ->
|
||||
cursorNodes = componentNode.querySelectorAll('.cursor')
|
||||
expect(cursorNodes.length).toBe 2
|
||||
expect(cursorNodes[0].offsetTop).toBe 0
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{5 * charWidth}px, #{0 * lineHeightInPixels}px)"
|
||||
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{10 * charWidth}px, #{4 * lineHeightInPixels}px)"
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(5 * charWidth)}px, #{0 * lineHeightInPixels}px)"
|
||||
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{Math.round(10 * charWidth)}px, #{4 * lineHeightInPixels}px)"
|
||||
|
||||
verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels
|
||||
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
|
||||
@ -980,13 +980,13 @@ describe "TextEditorComponent", ->
|
||||
|
||||
cursorNodes = componentNode.querySelectorAll('.cursor')
|
||||
expect(cursorNodes.length).toBe 2
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{10 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(10 * charWidth - horizontalScrollbarNode.scrollLeft)}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorNodes[1].style['-webkit-transform']).toBe "translate(#{Math.round(11 * charWidth - horizontalScrollbarNode.scrollLeft)}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
|
||||
editor.onDidChangeCursorPosition cursorMovedListener = jasmine.createSpy('cursorMovedListener')
|
||||
cursor3.setScreenPosition([4, 11], autoscroll: false)
|
||||
nextAnimationFrame()
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(11 * charWidth - horizontalScrollbarNode.scrollLeft)}px, #{4 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorMovedListener).toHaveBeenCalled()
|
||||
|
||||
cursor3.destroy()
|
||||
@ -994,7 +994,7 @@ describe "TextEditorComponent", ->
|
||||
cursorNodes = componentNode.querySelectorAll('.cursor')
|
||||
|
||||
expect(cursorNodes.length).toBe 1
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{11 * charWidth - horizontalScrollbarNode.scrollLeft}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(11 * charWidth - horizontalScrollbarNode.scrollLeft)}px, #{8 * lineHeightInPixels - verticalScrollbarNode.scrollTop}px)"
|
||||
|
||||
it "accounts for character widths when positioning cursors", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
@ -1010,8 +1010,8 @@ describe "TextEditorComponent", ->
|
||||
range.setEnd(cursorLocationTextNode, 1)
|
||||
rangeRect = range.getBoundingClientRect()
|
||||
|
||||
expect(cursorRect.left).toBe rangeRect.left
|
||||
expect(cursorRect.width).toBe rangeRect.width
|
||||
expect(cursorRect.left).toBeCloseTo rangeRect.left, 0
|
||||
expect(cursorRect.width).toBeCloseTo rangeRect.width, 0
|
||||
|
||||
it "accounts for the width of paired characters when positioning cursors", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
@ -1029,8 +1029,8 @@ describe "TextEditorComponent", ->
|
||||
range.setEnd(cursorLocationTextNode, 1)
|
||||
rangeRect = range.getBoundingClientRect()
|
||||
|
||||
expect(cursorRect.left).toBe rangeRect.left
|
||||
expect(cursorRect.width).toBe rangeRect.width
|
||||
expect(cursorRect.left).toBeCloseTo rangeRect.left, 0
|
||||
expect(cursorRect.width).toBeCloseTo rangeRect.width, 0
|
||||
|
||||
it "positions cursors correctly after character widths are changed via a stylesheet change", ->
|
||||
atom.config.set('editor.fontFamily', 'sans-serif')
|
||||
@ -1053,8 +1053,8 @@ describe "TextEditorComponent", ->
|
||||
range.setEnd(cursorLocationTextNode, 1)
|
||||
rangeRect = range.getBoundingClientRect()
|
||||
|
||||
expect(cursorRect.left).toBe rangeRect.left
|
||||
expect(cursorRect.width).toBe rangeRect.width
|
||||
expect(cursorRect.left).toBeCloseTo rangeRect.left, 0
|
||||
expect(cursorRect.width).toBeCloseTo rangeRect.width, 0
|
||||
|
||||
atom.themes.removeStylesheet('test')
|
||||
|
||||
@ -1062,13 +1062,13 @@ describe "TextEditorComponent", ->
|
||||
editor.setCursorScreenPosition([0, Infinity])
|
||||
nextAnimationFrame()
|
||||
cursorNode = componentNode.querySelector('.cursor')
|
||||
expect(cursorNode.offsetWidth).toBe charWidth
|
||||
expect(cursorNode.offsetWidth).toBeCloseTo charWidth, 0
|
||||
|
||||
it "gives the cursor a non-zero width even if it's inside atomic tokens", ->
|
||||
editor.setCursorScreenPosition([1, 0])
|
||||
nextAnimationFrame()
|
||||
cursorNode = componentNode.querySelector('.cursor')
|
||||
expect(cursorNode.offsetWidth).toBe charWidth
|
||||
expect(cursorNode.offsetWidth).toBeCloseTo charWidth, 0
|
||||
|
||||
it "blinks cursors when they aren't moving", ->
|
||||
cursorsNode = componentNode.querySelector('.cursors')
|
||||
@ -1102,21 +1102,21 @@ describe "TextEditorComponent", ->
|
||||
|
||||
cursorNodes = componentNode.querySelectorAll('.cursor')
|
||||
expect(cursorNodes.length).toBe 1
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{8 * charWidth}px, #{6 * lineHeightInPixels}px)"
|
||||
expect(cursorNodes[0].style['-webkit-transform']).toBe "translate(#{Math.round(8 * charWidth)}px, #{6 * lineHeightInPixels}px)"
|
||||
|
||||
it "updates cursor positions when the line height changes", ->
|
||||
editor.setCursorBufferPosition([1, 10])
|
||||
component.setLineHeight(2)
|
||||
nextAnimationFrame()
|
||||
cursorNode = componentNode.querySelector('.cursor')
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{10 * editor.getDefaultCharWidth()}px, #{editor.getLineHeightInPixels()}px)"
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{Math.round(10 * editor.getDefaultCharWidth())}px, #{editor.getLineHeightInPixels()}px)"
|
||||
|
||||
it "updates cursor positions when the font size changes", ->
|
||||
editor.setCursorBufferPosition([1, 10])
|
||||
component.setFontSize(10)
|
||||
nextAnimationFrame()
|
||||
cursorNode = componentNode.querySelector('.cursor')
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{10 * editor.getDefaultCharWidth()}px, #{editor.getLineHeightInPixels()}px)"
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{Math.round(10 * editor.getDefaultCharWidth())}px, #{editor.getLineHeightInPixels()}px)"
|
||||
|
||||
it "updates cursor positions when the font family changes", ->
|
||||
editor.setCursorBufferPosition([1, 10])
|
||||
@ -1125,7 +1125,7 @@ describe "TextEditorComponent", ->
|
||||
cursorNode = componentNode.querySelector('.cursor')
|
||||
|
||||
{left} = wrapperNode.pixelPositionForScreenPosition([1, 10])
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{left}px, #{editor.getLineHeightInPixels()}px)"
|
||||
expect(cursorNode.style['-webkit-transform']).toBe "translate(#{Math.round(left)}px, #{editor.getLineHeightInPixels()}px)"
|
||||
|
||||
describe "selection rendering", ->
|
||||
[scrollViewNode, scrollViewClientLeft] = []
|
||||
@ -1144,8 +1144,8 @@ describe "TextEditorComponent", ->
|
||||
regionRect = regions[0].getBoundingClientRect()
|
||||
expect(regionRect.top).toBe 1 * lineHeightInPixels
|
||||
expect(regionRect.height).toBe 1 * lineHeightInPixels
|
||||
expect(regionRect.left).toBe scrollViewClientLeft + 6 * charWidth
|
||||
expect(regionRect.width).toBe 4 * charWidth
|
||||
expect(regionRect.left).toBeCloseTo scrollViewClientLeft + 6 * charWidth, 0
|
||||
expect(regionRect.width).toBeCloseTo 4 * charWidth, 0
|
||||
|
||||
it "renders 2 regions for 2-line selections", ->
|
||||
editor.setSelectedScreenRange([[1, 6], [2, 10]])
|
||||
@ -1157,14 +1157,14 @@ describe "TextEditorComponent", ->
|
||||
region1Rect = regions[0].getBoundingClientRect()
|
||||
expect(region1Rect.top).toBe 1 * lineHeightInPixels
|
||||
expect(region1Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth
|
||||
expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region1Rect.left).toBeCloseTo scrollViewClientLeft + 6 * charWidth, 0
|
||||
expect(region1Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
region2Rect = regions[1].getBoundingClientRect()
|
||||
expect(region2Rect.top).toBe 2 * lineHeightInPixels
|
||||
expect(region2Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region2Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region2Rect.width).toBe 10 * charWidth
|
||||
expect(region2Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region2Rect.width).toBeCloseTo 10 * charWidth, 0
|
||||
|
||||
it "renders 3 regions per tile for selections with more than 2 lines", ->
|
||||
editor.setSelectedScreenRange([[0, 6], [5, 10]])
|
||||
@ -1178,20 +1178,20 @@ describe "TextEditorComponent", ->
|
||||
region1Rect = regions[0].getBoundingClientRect()
|
||||
expect(region1Rect.top).toBe 0
|
||||
expect(region1Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region1Rect.left).toBe scrollViewClientLeft + 6 * charWidth
|
||||
expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region1Rect.left).toBeCloseTo scrollViewClientLeft + 6 * charWidth, 0
|
||||
expect(region1Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
region2Rect = regions[1].getBoundingClientRect()
|
||||
expect(region2Rect.top).toBe 1 * lineHeightInPixels
|
||||
expect(region2Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region2Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region2Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region2Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region2Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
region3Rect = regions[2].getBoundingClientRect()
|
||||
expect(region3Rect.top).toBe 2 * lineHeightInPixels
|
||||
expect(region3Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region3Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region3Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region3Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region3Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
# Tile 3
|
||||
tileNode = component.tileNodesForLines()[1]
|
||||
@ -1201,20 +1201,20 @@ describe "TextEditorComponent", ->
|
||||
region1Rect = regions[0].getBoundingClientRect()
|
||||
expect(region1Rect.top).toBe 3 * lineHeightInPixels
|
||||
expect(region1Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region1Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region1Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region1Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region1Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
region2Rect = regions[1].getBoundingClientRect()
|
||||
expect(region2Rect.top).toBe 4 * lineHeightInPixels
|
||||
expect(region2Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region2Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region2Rect.right).toBe tileNode.getBoundingClientRect().right
|
||||
expect(region2Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region2Rect.right).toBeCloseTo tileNode.getBoundingClientRect().right, 0
|
||||
|
||||
region3Rect = regions[2].getBoundingClientRect()
|
||||
expect(region3Rect.top).toBe 5 * lineHeightInPixels
|
||||
expect(region3Rect.height).toBe 1 * lineHeightInPixels
|
||||
expect(region3Rect.left).toBe scrollViewClientLeft + 0
|
||||
expect(region3Rect.width).toBe 10 * charWidth
|
||||
expect(region3Rect.left).toBeCloseTo scrollViewClientLeft + 0, 0
|
||||
expect(region3Rect.width).toBeCloseTo 10 * charWidth, 0
|
||||
|
||||
it "does not render empty selections", ->
|
||||
editor.addSelectionForBufferRange([[2, 2], [2, 2]])
|
||||
@ -1237,7 +1237,7 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
selectionNode = componentNode.querySelector('.region')
|
||||
expect(selectionNode.offsetTop).toBe editor.getLineHeightInPixels()
|
||||
expect(selectionNode.offsetLeft).toBe 6 * editor.getDefaultCharWidth()
|
||||
expect(selectionNode.offsetLeft).toBeCloseTo 6 * editor.getDefaultCharWidth(), 0
|
||||
|
||||
it "updates selections when the font family changes", ->
|
||||
editor.setSelectedBufferRange([[1, 6], [1, 10]])
|
||||
@ -1245,7 +1245,7 @@ describe "TextEditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
selectionNode = componentNode.querySelector('.region')
|
||||
expect(selectionNode.offsetTop).toBe editor.getLineHeightInPixels()
|
||||
expect(selectionNode.offsetLeft).toBe wrapperNode.pixelPositionForScreenPosition([1, 6]).left
|
||||
expect(selectionNode.offsetLeft).toBeCloseTo wrapperNode.pixelPositionForScreenPosition([1, 6]).left, 0
|
||||
|
||||
it "will flash the selection when flash:true is passed to editor::setSelectedBufferRange", ->
|
||||
editor.setSelectedBufferRange([[1, 6], [1, 10]], flash: true)
|
||||
@ -1439,8 +1439,8 @@ describe "TextEditorComponent", ->
|
||||
regionRect = regions[0].style
|
||||
expect(regionRect.top).toBe (0 + 'px')
|
||||
expect(regionRect.height).toBe 1 * lineHeightInPixels + 'px'
|
||||
expect(regionRect.left).toBe 2 * charWidth + 'px'
|
||||
expect(regionRect.width).toBe 2 * charWidth + 'px'
|
||||
expect(regionRect.left).toBe Math.round(2 * charWidth) + 'px'
|
||||
expect(regionRect.width).toBe Math.round(2 * charWidth) + 'px'
|
||||
|
||||
it "renders highlights decoration's marker is added", ->
|
||||
regions = componentNode.querySelectorAll('.test-highlight .region')
|
||||
@ -1606,7 +1606,7 @@ describe "TextEditorComponent", ->
|
||||
position = wrapperNode.pixelPositionForBufferPosition([2, 10])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + gutterWidth + 'px'
|
||||
expect(overlay.style.left).toBe Math.round(position.left + gutterWidth) + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
describe "positioning the overlay when near the edge of the editor", ->
|
||||
@ -1614,10 +1614,10 @@ describe "TextEditorComponent", ->
|
||||
beforeEach ->
|
||||
atom.storeWindowDimensions()
|
||||
|
||||
itemWidth = 4 * editor.getDefaultCharWidth()
|
||||
itemWidth = Math.round(4 * editor.getDefaultCharWidth())
|
||||
itemHeight = 4 * editor.getLineHeightInPixels()
|
||||
|
||||
windowWidth = gutterWidth + 30 * editor.getDefaultCharWidth()
|
||||
windowWidth = Math.round(gutterWidth + 30 * editor.getDefaultCharWidth())
|
||||
windowHeight = 10 * editor.getLineHeightInPixels()
|
||||
|
||||
item.style.width = itemWidth + 'px'
|
||||
@ -1645,7 +1645,7 @@ describe "TextEditorComponent", ->
|
||||
position = wrapperNode.pixelPositionForBufferPosition([0, 26])
|
||||
|
||||
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
|
||||
expect(overlay.style.left).toBe position.left + gutterWidth + 'px'
|
||||
expect(overlay.style.left).toBe Math.round(position.left + gutterWidth) + 'px'
|
||||
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
|
||||
|
||||
editor.insertText('a')
|
||||
@ -1689,7 +1689,7 @@ describe "TextEditorComponent", ->
|
||||
wrapperNode.focus() # updates via state change
|
||||
nextAnimationFrame()
|
||||
expect(inputNode.offsetTop).toBe (5 * lineHeightInPixels) - wrapperNode.getScrollTop()
|
||||
expect(inputNode.offsetLeft).toBe (4 * charWidth) - wrapperNode.getScrollLeft()
|
||||
expect(inputNode.offsetLeft).toBeCloseTo (4 * charWidth) - wrapperNode.getScrollLeft(), 0
|
||||
|
||||
# In bounds, not focused
|
||||
inputNode.blur() # updates via state change
|
||||
@ -2482,7 +2482,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
rightOfLongestLine = component.lineNodeForScreenRow(6).querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
leftOfVerticalScrollbar = verticalScrollbarNode.getBoundingClientRect().left
|
||||
expect(Math.round(rightOfLongestLine)).toBe leftOfVerticalScrollbar - 1 # Leave 1 px so the cursor is visible on the end of the line
|
||||
expect(Math.round(rightOfLongestLine)).toBeCloseTo leftOfVerticalScrollbar - 1, 0 # Leave 1 px so the cursor is visible on the end of the line
|
||||
|
||||
it "only displays dummy scrollbars when scrollable in that direction", ->
|
||||
expect(verticalScrollbarNode.style.display).toBe 'none'
|
||||
@ -2963,7 +2963,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
cursorLeft = componentNode.querySelector('.cursor').getBoundingClientRect().left
|
||||
line0Right = componentNode.querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
expect(cursorLeft).toBe line0Right
|
||||
expect(cursorLeft).toBeCloseTo line0Right, 0
|
||||
|
||||
describe "when the fontFamily changes while the editor is hidden", ->
|
||||
it "does not attempt to measure the defaultCharWidth until the editor becomes visible again", ->
|
||||
@ -2995,7 +2995,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
cursorLeft = componentNode.querySelector('.cursor').getBoundingClientRect().left
|
||||
line0Right = componentNode.querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
expect(cursorLeft).toBe line0Right
|
||||
expect(cursorLeft).toBeCloseTo line0Right, 0
|
||||
|
||||
describe "when stylesheets change while the editor is hidden", ->
|
||||
afterEach ->
|
||||
@ -3021,7 +3021,7 @@ describe "TextEditorComponent", ->
|
||||
|
||||
cursorLeft = componentNode.querySelector('.cursor').getBoundingClientRect().left
|
||||
line0Right = componentNode.querySelector('.line > span:last-child').getBoundingClientRect().right
|
||||
expect(cursorLeft).toBe line0Right
|
||||
expect(cursorLeft).toBeCloseTo line0Right, 0
|
||||
|
||||
describe "when lines are changed while the editor is hidden", ->
|
||||
xit "does not measure new characters until the editor is shown again", ->
|
||||
@ -3350,8 +3350,9 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.setSelectedBufferRange([[5, 6], [6, 8]])
|
||||
nextAnimationFrame()
|
||||
right = wrapperNode.pixelPositionForBufferPosition([6, 8 + editor.getHorizontalScrollMargin()]).left
|
||||
expect(wrapperNode.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
editor.setSelectedBufferRange([[0, 0], [0, 0]])
|
||||
nextAnimationFrame()
|
||||
@ -3361,14 +3362,16 @@ describe "TextEditorComponent", ->
|
||||
editor.setSelectedBufferRange([[6, 6], [6, 8]])
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
describe "when adding selections for buffer ranges", ->
|
||||
it "autoscrolls to the added selection if needed", ->
|
||||
editor.addSelectionForBufferRange([[8, 10], [8, 15]])
|
||||
nextAnimationFrame()
|
||||
|
||||
right = wrapperNode.pixelPositionForBufferPosition([8, 15]).left
|
||||
expect(wrapperNode.getScrollBottom()).toBe (9 * 10) + (2 * 10)
|
||||
expect(wrapperNode.getScrollRight()).toBe (15 * 10) + (2 * 10)
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo(right + 2 * 10, 0)
|
||||
|
||||
describe "when selecting lines containing cursors", ->
|
||||
it "autoscrolls to the selection", ->
|
||||
@ -3406,9 +3409,10 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.scrollToCursorPosition()
|
||||
nextAnimationFrame()
|
||||
right = wrapperNode.pixelPositionForScreenPosition([8, 9 + editor.getHorizontalScrollMargin()]).left
|
||||
expect(wrapperNode.getScrollTop()).toBe (8.8 * 10) - 30
|
||||
expect(wrapperNode.getScrollBottom()).toBe (8.3 * 10) + 30
|
||||
expect(wrapperNode.getScrollRight()).toBe (9 + editor.getHorizontalScrollMargin()) * 10
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
wrapperNode.setScrollTop(0)
|
||||
editor.scrollToCursorPosition(center: false)
|
||||
@ -3460,11 +3464,13 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe 6 * 10
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 6]).left
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
editor.moveRight()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollRight()).toBe 7 * 10
|
||||
right = wrapperNode.pixelPositionForScreenPosition([0, 7]).left
|
||||
expect(wrapperNode.getScrollRight()).toBeCloseTo right, 0
|
||||
|
||||
it "scrolls left when the last cursor gets closer than ::horizontalScrollMargin to the left of the editor", ->
|
||||
wrapperNode.setScrollRight(wrapperNode.getScrollWidth())
|
||||
@ -3475,11 +3481,13 @@ describe "TextEditorComponent", ->
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollLeft()).toBe 59 * 10
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 59]).left
|
||||
expect(wrapperNode.getScrollLeft()).toBeCloseTo left, 0
|
||||
|
||||
editor.moveLeft()
|
||||
nextAnimationFrame()
|
||||
expect(wrapperNode.getScrollLeft()).toBe 58 * 10
|
||||
left = wrapperNode.pixelPositionForScreenPosition([6, 58]).left
|
||||
expect(wrapperNode.getScrollLeft()).toBeCloseTo left, 0
|
||||
|
||||
it "scrolls down when inserting lines makes the document longer than the editor's height", ->
|
||||
editor.setCursorScreenPosition([13, Infinity])
|
||||
|
@ -28,7 +28,7 @@ class AtomWindow
|
||||
title: 'Atom'
|
||||
'web-preferences':
|
||||
'direct-write': true
|
||||
'subpixel-font-scaling': false
|
||||
'subpixel-font-scaling': true
|
||||
# Don't set icon on Windows so the exe's ico will be used as window and
|
||||
# taskbar's icon. See https://github.com/atom/atom/issues/4811 for more.
|
||||
if process.platform is 'linux'
|
||||
|
@ -501,7 +501,7 @@ class TextEditorPresenter
|
||||
return unless cursor.isVisible() and @startRow <= screenRange.start.row < @endRow
|
||||
|
||||
pixelRect = @pixelRectForScreenRange(screenRange)
|
||||
pixelRect.width = @baseCharacterWidth if pixelRect.width is 0
|
||||
pixelRect.width = Math.round(@baseCharacterWidth) if pixelRect.width is 0
|
||||
@state.content.cursors[cursor.id] = pixelRect
|
||||
|
||||
updateOverlaysState: ->
|
||||
@ -1134,6 +1134,10 @@ class TextEditorPresenter
|
||||
@linesYardstick.pixelPositionForScreenPosition(screenPosition, clip)
|
||||
position.top -= @getScrollTop()
|
||||
position.left -= @getScrollLeft()
|
||||
|
||||
position.top = Math.round(position.top)
|
||||
position.left = Math.round(position.left)
|
||||
|
||||
position
|
||||
|
||||
hasPixelRectRequirements: ->
|
||||
@ -1146,6 +1150,12 @@ class TextEditorPresenter
|
||||
rect = @linesYardstick.pixelRectForScreenRange(screenRange)
|
||||
rect.top -= @getScrollTop()
|
||||
rect.left -= @getScrollLeft()
|
||||
|
||||
rect.top = Math.round(rect.top)
|
||||
rect.left = Math.round(rect.left)
|
||||
rect.width = Math.round(rect.width)
|
||||
rect.height = Math.round(rect.height)
|
||||
|
||||
rect
|
||||
|
||||
observeDecoration: (decoration) ->
|
||||
@ -1507,10 +1517,10 @@ class TextEditorPresenter
|
||||
@emitDidUpdateState()
|
||||
|
||||
getVerticalScrollMarginInPixels: ->
|
||||
@model.getVerticalScrollMargin() * @lineHeight
|
||||
Math.round(@model.getVerticalScrollMargin() * @lineHeight)
|
||||
|
||||
getHorizontalScrollMarginInPixels: ->
|
||||
@model.getHorizontalScrollMargin() * @baseCharacterWidth
|
||||
Math.round(@model.getHorizontalScrollMargin() * @baseCharacterWidth)
|
||||
|
||||
getVerticalScrollbarWidth: ->
|
||||
@verticalScrollbarWidth
|
||||
|
Loading…
Reference in New Issue
Block a user