Commit 46779daf authored by yutak@chromium.org's avatar yutak@chromium.org

Implement Range-based selection expansion.

This patch simplifies Selection.addRange()'s implementation by expanding
the selection based on DOM Ranges instead of VisiblePositions.

There is a slight behavior change caused by this shift of data structures
we use: ranges which are discrete in the DOM tree but visually adjacent will
be rejected after this patch is landed. However, I don't think this will be
a huge problem, since (1) API behavior relying on visual positions can be
tricky to users because they are Blink-internal only information; and
(2) users wishing to connect the regions can (and probably should) specify
a range which overlaps with the current selection.

BUG=346613

Review URL: https://codereview.chromium.org/205903003

git-svn-id: svn://svn.chromium.org/blink/trunk@170640 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 4db7bf3a
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
......
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
Selection.addRange() should properly merge intersecting (and don't merge discrete) ranges.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Running: testExpandLeftToRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandLeftToRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandLeftToRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandLeftToRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandLeftToRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandLeftToRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandLeftToRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandLeftToRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandLeftToRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testExpandLeftToRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testExpandRightToLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandRightToLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandRightToLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandRightToLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandRightToLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandRightToLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandRightToLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandRightToLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandRightToLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testExpandRightToLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 2), end = ([Text: 12345], 4)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 2), end = ([Text: 12345], 4)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 2), end = ([<DIV>: #container], 4)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 2), end = ([<DIV>: #container], 4)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #e], 0)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #e], 0)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #a], 0), end = ([<SPAN>: #c], 0)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #a], 0), end = ([<SPAN>: #c], 0)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 1), end = ([<DIV>: #container], 1)
Running: testExpandLeftToRightAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 1), end = ([<DIV>: #container], 1)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 3)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 3)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 3)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 3)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #d], 0)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #d], 0)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #b], 0)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #b], 0)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #a], 1)
Running: testExpandRightToLeftAdjacent (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #a], 1)
Running: testExpandBothEnds (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandBothEnds (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testExpandBothEnds (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandBothEnds (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testExpandBothEnds (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandBothEnds (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testExpandBothEnds (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandBothEnds (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testExpandBothEnds (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testExpandBothEnds (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testDontExpand (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testDontExpand (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 4)
Running: testDontExpand (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testDontExpand (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 4)
Running: testDontExpand (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testDontExpand (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #e], 0)
Running: testDontExpand (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testDontExpand (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #c], 0)
Running: testDontExpand (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testDontExpand (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<DIV>: #container], 1)
Running: testAddSameRange (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 2), end = ([Text: 12345], 3)
Running: testAddSameRange (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 2), end = ([Text: 12345], 3)
Running: testAddSameRange (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 2), end = ([<DIV>: #container], 3)
Running: testAddSameRange (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 2), end = ([<DIV>: #container], 3)
Running: testAddSameRange (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #d], 0)
Running: testAddSameRange (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #d], 0)
Running: testAddSameRange (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #a], 0), end = ([<SPAN>: #b], 0)
Running: testAddSameRange (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #a], 0), end = ([<SPAN>: #b], 0)
Running: testAddSameRange (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 1), end = ([<SPAN>: #a], 1)
Running: testAddSameRange (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 1), end = ([<SPAN>: #a], 1)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 2)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 2)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 2)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 2)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #a], 0)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #a], 0)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #b], 1)
Running: testRejectDistantRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #b], 1)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 3), end = ([Text: 12345], 4)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 3), end = ([Text: 12345], 4)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 3), end = ([<DIV>: #container], 4)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 3), end = ([<DIV>: #container], 4)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #d], 0), end = ([<SPAN>: #e], 0)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #d], 0), end = ([<SPAN>: #e], 0)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #a], 1), end = ([<DIV>: #container], 1)
Running: testRejectDistantRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #a], 1), end = ([<DIV>: #container], 1)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 2)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 1), end = ([Text: 12345], 2)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 2)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 1), end = ([<DIV>: #container], 2)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #a], 0)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 0), end = ([<SPAN>: #a], 0)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #b], 1)
Running: testRejectDistantCollapsedRangeAtRight (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #c], 0), end = ([<SPAN>: #b], 1)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = false)
PASS Selection was: start = ([Text: 12345], 3), end = ([Text: 12345], 4)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeTextPositions, containerIsEditable = true)
PASS Selection was: start = ([Text: 12345], 3), end = ([Text: 12345], 4)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<DIV>: #container], 3), end = ([<DIV>: #container], 4)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeOuterElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<DIV>: #container], 3), end = ([<DIV>: #container], 4)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #d], 0), end = ([<SPAN>: #e], 0)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeInnerElementPositions, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #d], 0), end = ([<SPAN>: #e], 0)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsBeforeNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #b], 0), end = ([<SPAN>: #c], 0)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = false)
PASS Selection was: start = ([<SPAN>: #a], 1), end = ([<DIV>: #container], 1)
Running: testRejectDistantCollapsedRangeAtLeft (initializePositionsFunction = initializeVisiblyEquivalentPositionsAfterNodes, containerIsEditable = true)
PASS Selection was: start = ([<SPAN>: #a], 1), end = ([<DIV>: #container], 1)
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<title>Range merging with Selection.addRange()</title>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<script>
description('Selection.addRange() should properly merge intersecting (and don\'t merge discrete) ranges.');
var selection = window.getSelection();
// Utility functions:
function createPosition(container, offset)
{
return {'container': container, 'offset': offset};
}
function createRange(startPosition, endPosition)
{
var range = new Range();
range.setStart(startPosition.container, startPosition.offset);
range.setEnd(endPosition.container, endPosition.offset);
return range;
}
function nodeToString(node)
{
switch (node.nodeType) {
case Node.ELEMENT_NODE:
return '[<' + node.tagName + '>: #' + node.id + ']';
case Node.TEXT_NODE:
return '[Text: ' + node.data + ']';
default:
return node.toString();
}
}
function positionToString(position)
{
return '(' + nodeToString(position.container) + ', ' + position.offset + ')';
}
function selectionShouldBe(expectedStartPosition, expectedEndPosition)
{
var range = selection.getRangeAt(0);
var actualStartPosition = createPosition(range.startContainer, range.startOffset);
var actualEndPosition = createPosition(range.endContainer, range.endOffset);
if (actualStartPosition.container === expectedStartPosition.container
&& actualStartPosition.offset === expectedStartPosition.offset
&& actualEndPosition.container === expectedEndPosition.container
&& actualEndPosition.offset === expectedEndPosition.offset) {
testPassed('Selection was: start = ' + positionToString(expectedStartPosition) + ', end = ' + positionToString(expectedEndPosition));
} else {
testFailed('Selection should be: start = ' + positionToString(expectedStartPosition) + ', end = ' + positionToString(expectedEndPosition) + '\nbut was: start = ' + positionToString(actualStartPosition) + ', end = ' + positionToString(actualEndPosition));
}
}
function runSingleTest(testFunction, initializePositionsFunction, containerIsEditable)
{
selection.removeAllRanges();
var container = document.createElement('div');
container.id = 'container';
if (containerIsEditable)
container.contentEditable = true;
document.body.appendChild(container);
var positions = initializePositionsFunction(container);
debug('Running: ' + testFunction.name + ' (initializePositionsFunction = ' + initializePositionsFunction.name + ', containerIsEditable = ' + containerIsEditable + ')');
testFunction(positions);
document.body.removeChild(container);
}
// Actual tests:
// To have better coverage over the possible code paths, each test is parametarized over four document positions;
// these positions are guaranteed to be ordered in the document order, but each position may vary in each test run.
//
// You can assume the selection is cleared before each test run.
function testExpandLeftToRight(positions)
{
selection.addRange(createRange(positions[0], positions[2]));
selection.addRange(createRange(positions[1], positions[3]));
selectionShouldBe(positions[0], positions[3]);
}
function testExpandRightToLeft(positions)
{
selection.addRange(createRange(positions[1], positions[3]));
selection.addRange(createRange(positions[0], positions[2]));
selectionShouldBe(positions[0], positions[3]);
}
function testExpandLeftToRightAdjacent(positions)
{
selection.addRange(createRange(positions[1], positions[2]));
selection.addRange(createRange(positions[2], positions[3]));
selectionShouldBe(positions[1], positions[3]);
}
function testExpandRightToLeftAdjacent(positions)
{
selection.addRange(createRange(positions[1], positions[2]));
selection.addRange(createRange(positions[0], positions[1]));
selectionShouldBe(positions[0], positions[2]);
}
function testExpandBothEnds(positions)
{
selection.addRange(createRange(positions[1], positions[2]));
selection.addRange(createRange(positions[0], positions[3]));
selectionShouldBe(positions[0], positions[3]);
}
function testDontExpand(positions)
{
selection.addRange(createRange(positions[0], positions[3]));
selection.addRange(createRange(positions[1], positions[2]));
selectionShouldBe(positions[0], positions[3]);
}
function testAddSameRange(positions)
{
selection.addRange(createRange(positions[1], positions[2]));
selection.addRange(createRange(positions[1], positions[2]));
selectionShouldBe(positions[1], positions[2]);
}
function testRejectDistantRangeAtRight(positions)
{
selection.addRange(createRange(positions[0], positions[1]));
selection.addRange(createRange(positions[2], positions[3]));
selectionShouldBe(positions[0], positions[1]);
}
function testRejectDistantRangeAtLeft(positions)
{
selection.addRange(createRange(positions[2], positions[3]));
selection.addRange(createRange(positions[0], positions[1]));
selectionShouldBe(positions[2], positions[3]);
}
function testRejectDistantCollapsedRangeAtRight(positions)
{
selection.addRange(createRange(positions[0], positions[1]));
selection.addRange(createRange(positions[2], positions[2]));
selectionShouldBe(positions[0], positions[1]);
}
function testRejectDistantCollapsedRangeAtLeft(positions)
{
selection.addRange(createRange(positions[2], positions[3]));
selection.addRange(createRange(positions[1], positions[1]));
selectionShouldBe(positions[2], positions[3]);
}
// Position initializers:
// Each initializer function takes an argument |container| which denotes the root element which can be filled with
// arbitrary contents. This element is created and added to the document before each test run, and removed from
// the document after each test run.
function initializeTextPositions(container)
{
container.innerHTML = '12345';
var text = container.firstChild;
return [createPosition(text, 1), createPosition(text, 2), createPosition(text, 3), createPosition(text, 4)];
}
function initializeOuterElementPositions(container)
{
container.innerHTML = '<span id="a">1</span><span id="b">2</span><span id="c">3</span><span id="d">4</span><span id="e">5</span>';
return [createPosition(container, 1), createPosition(container, 2), createPosition(container, 3), createPosition(container, 4)];
}
function initializeInnerElementPositions(container)
{
container.innerHTML = '<span id="a">1</span><span id="b">2</span><span id="c">3</span><span id="d">4</span><span id="e">5</span>';
return [createPosition(container.childNodes[1], 0), createPosition(container.childNodes[2], 0), createPosition(container.childNodes[3], 0), createPosition(container.childNodes[4], 0)];
}
function initializeVisiblyEquivalentPositionsBeforeNodes(container)
{
container.innerHTML = '<span id="a"><span id="b"><span id="c"></span></span></span>';
return [createPosition(container, 0), createPosition(container.firstChild, 0), createPosition(container.firstChild.firstChild, 0), createPosition(container.firstChild.firstChild.firstChild, 0)];
}
function initializeVisiblyEquivalentPositionsAfterNodes(container)
{
container.innerHTML = '<span id="a"><span id="b"><span id="c"></span></span></span>';
return [createPosition(container.firstChild.firstChild.firstChild, 0), createPosition(container.firstChild.firstChild, 1), createPosition(container.firstChild, 1), createPosition(container, 1)];
}
var tests = [
testExpandLeftToRight,
testExpandRightToLeft,
testExpandLeftToRightAdjacent,
testExpandRightToLeftAdjacent,
testExpandBothEnds,
testDontExpand,
testAddSameRange,
testRejectDistantRangeAtRight,
testRejectDistantRangeAtLeft,
testRejectDistantCollapsedRangeAtRight,
testRejectDistantCollapsedRangeAtLeft
];
var positionInitializers = [
initializeTextPositions,
initializeOuterElementPositions,
initializeInnerElementPositions,
initializeVisiblyEquivalentPositionsBeforeNodes,
initializeVisiblyEquivalentPositionsAfterNodes
];
tests.forEach(function (testFunction) {
positionInitializers.forEach(function (initializePositionsFunction) {
[false, true].forEach(function (containerIsEditable) {
runSingleTest(testFunction, initializePositionsFunction, containerIsEditable);
});
});
});
</script>
</body>
</html>
CONSOLE ERROR: Discontiguous selection is not supported.
The _before_selection_ word is before the selection, so we shouldn't be able to find it if span_to_select is selected.
The _in_selection_ word is in the selection and we should always be able to find it.
The _after_selection_ word is after the selection and we should always be able to find that too.
......
CONSOLE ERROR: Discontiguous selection is not supported.
CONSOLE ERROR: Discontiguous selection is not supported.
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
......
......@@ -402,7 +402,7 @@ void DOMSelection::addRange(Range* newRange)
return;
}
RefPtr<Range> originalRange = selection.selection().toNormalizedRange();
RefPtr<Range> originalRange = selection.firstRange();
if (originalRange->startContainer()->document() != newRange->startContainer()->document()) {
addConsoleError("The given range does not belong to the current selection's document.");
......@@ -413,30 +413,22 @@ void DOMSelection::addRange(Range* newRange)
return;
}
// FIXME: Emit a console error if the combined ranges would form a discontiguous selection.
if (newRange->compareBoundaryPoints(Range::START_TO_START, originalRange.get(), ASSERT_NO_EXCEPTION) == -1) {
// We don't support discontiguous selection. We don't do anything if newRange and originalRange don't intersect.
if (newRange->compareBoundaryPoints(Range::START_TO_END, originalRange.get(), ASSERT_NO_EXCEPTION) > -1) {
if (newRange->compareBoundaryPoints(Range::END_TO_END, originalRange.get(), ASSERT_NO_EXCEPTION) == -1) {
// The original originalRange and newRange intersect.
selection.setSelection(VisibleSelection(newRange->startPosition(), originalRange->endPosition(), DOWNSTREAM));
} else {
// newRange contains the original originalRange.
selection.setSelection(VisibleSelection(newRange));
}
}
} else {
// We don't support discontiguous selection. We don't do anything if newRange and originalRange don't intersect.
if (newRange->compareBoundaryPoints(Range::END_TO_START, originalRange.get(), ASSERT_NO_EXCEPTION) < 1) {
if (newRange->compareBoundaryPoints(Range::END_TO_END, originalRange.get(), ASSERT_NO_EXCEPTION) == -1) {
// The original range contains newRange.
selection.setSelection(VisibleSelection(originalRange.get()));
} else {
// The original range and r intersect.
selection.setSelection(VisibleSelection(originalRange->startPosition(), newRange->endPosition(), DOWNSTREAM));
}
}
if (originalRange->compareBoundaryPoints(Range::START_TO_END, newRange, ASSERT_NO_EXCEPTION) < 0
|| newRange->compareBoundaryPoints(Range::START_TO_END, originalRange.get(), ASSERT_NO_EXCEPTION) < 0) {
addConsoleError("Discontiguous selection is not supported.");
return;
}
// FIXME: "Merge the ranges if they intersect" is Blink-specific behavior; other browsers supporting discontiguous
// selection (obviously) keep each Range added and return it in getRangeAt(). But it's unclear if we can really
// do the same, since we don't support discontiguous selection. Further discussions at
// <https://code.google.com/p/chromium/issues/detail?id=353069>.
Range* start = originalRange->compareBoundaryPoints(Range::START_TO_START, newRange, ASSERT_NO_EXCEPTION) < 0 ? originalRange.get() : newRange;
Range* end = originalRange->compareBoundaryPoints(Range::END_TO_END, newRange, ASSERT_NO_EXCEPTION) < 0 ? newRange : originalRange.get();
RefPtr<Range> merged = Range::create(originalRange->startContainer()->document(), start->startContainer(), start->startOffset(), end->endContainer(), end->endOffset());
EAffinity affinity = selection.selection().affinity();
selection.setSelectedRange(merged.get(), affinity);
}
void DOMSelection::deleteFromDocument()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment