| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 #include "core/editing/SelectionAdjuster.h" | 26 #include "core/editing/SelectionAdjuster.h" |
| 27 | 27 |
| 28 #include "core/editing/EditingUtilities.h" | 28 #include "core/editing/EditingUtilities.h" |
| 29 | 29 |
| 30 namespace blink { | 30 namespace blink { |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 Node* enclosingShadowHost(Node* node) | 34 Node* enclosingShadowHost(Node* node) |
| 35 { | 35 { |
| 36 for (Node* runner = node; runner; runner = ComposedTreeTraversal::parent(*ru
nner)) { | 36 for (Node* runner = node; runner; runner = FlatTreeTraversal::parent(*runner
)) { |
| 37 if (isShadowHost(runner)) | 37 if (isShadowHost(runner)) |
| 38 return runner; | 38 return runner; |
| 39 } | 39 } |
| 40 return nullptr; | 40 return nullptr; |
| 41 } | 41 } |
| 42 | 42 |
| 43 bool isEnclosedBy(const PositionInComposedTree& position, const Node& node) | 43 bool isEnclosedBy(const PositionInFlatTree& position, const Node& node) |
| 44 { | 44 { |
| 45 ASSERT(position.isNotNull()); | 45 ASSERT(position.isNotNull()); |
| 46 Node* anchorNode = position.anchorNode(); | 46 Node* anchorNode = position.anchorNode(); |
| 47 if (anchorNode == node) | 47 if (anchorNode == node) |
| 48 return !position.isAfterAnchor() && !position.isBeforeAnchor(); | 48 return !position.isAfterAnchor() && !position.isBeforeAnchor(); |
| 49 | 49 |
| 50 return ComposedTreeTraversal::isDescendantOf(*anchorNode, node); | 50 return FlatTreeTraversal::isDescendantOf(*anchorNode, node); |
| 51 } | 51 } |
| 52 | 52 |
| 53 bool isSelectionBoundary(const Node& node) | 53 bool isSelectionBoundary(const Node& node) |
| 54 { | 54 { |
| 55 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele
ctElement(node); | 55 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele
ctElement(node); |
| 56 } | 56 } |
| 57 | 57 |
| 58 Node* enclosingShadowHostForStart(const PositionInComposedTree& position) | 58 Node* enclosingShadowHostForStart(const PositionInFlatTree& position) |
| 59 { | 59 { |
| 60 Node* node = position.nodeAsRangeFirstNode(); | 60 Node* node = position.nodeAsRangeFirstNode(); |
| 61 if (!node) | 61 if (!node) |
| 62 return nullptr; | 62 return nullptr; |
| 63 Node* shadowHost = enclosingShadowHost(node); | 63 Node* shadowHost = enclosingShadowHost(node); |
| 64 if (!shadowHost) | 64 if (!shadowHost) |
| 65 return nullptr; | 65 return nullptr; |
| 66 if (!isEnclosedBy(position, *shadowHost)) | 66 if (!isEnclosedBy(position, *shadowHost)) |
| 67 return nullptr; | 67 return nullptr; |
| 68 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; | 68 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
| 69 } | 69 } |
| 70 | 70 |
| 71 Node* enclosingShadowHostForEnd(const PositionInComposedTree& position) | 71 Node* enclosingShadowHostForEnd(const PositionInFlatTree& position) |
| 72 { | 72 { |
| 73 Node* node = position.nodeAsRangeLastNode(); | 73 Node* node = position.nodeAsRangeLastNode(); |
| 74 if (!node) | 74 if (!node) |
| 75 return nullptr; | 75 return nullptr; |
| 76 Node* shadowHost = enclosingShadowHost(node); | 76 Node* shadowHost = enclosingShadowHost(node); |
| 77 if (!shadowHost) | 77 if (!shadowHost) |
| 78 return nullptr; | 78 return nullptr; |
| 79 if (!isEnclosedBy(position, *shadowHost)) | 79 if (!isEnclosedBy(position, *shadowHost)) |
| 80 return nullptr; | 80 return nullptr; |
| 81 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; | 81 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
| 82 } | 82 } |
| 83 | 83 |
| 84 PositionInComposedTree adjustPositionInComposedTreeForStart(const PositionInComp
osedTree& position, Node* shadowHost) | 84 PositionInFlatTree adjustPositionInFlatTreeForStart(const PositionInFlatTree& po
sition, Node* shadowHost) |
| 85 { | 85 { |
| 86 if (isEnclosedBy(position, *shadowHost)) { | 86 if (isEnclosedBy(position, *shadowHost)) { |
| 87 if (position.isBeforeChildren()) | 87 if (position.isBeforeChildren()) |
| 88 return PositionInComposedTree::beforeNode(shadowHost); | 88 return PositionInFlatTree::beforeNode(shadowHost); |
| 89 return PositionInComposedTree::afterNode(shadowHost); | 89 return PositionInFlatTree::afterNode(shadowHost); |
| 90 } | 90 } |
| 91 | 91 |
| 92 // We use |firstChild|'s after instead of beforeAllChildren for backward | 92 // We use |firstChild|'s after instead of beforeAllChildren for backward |
| 93 // compatibility. The positions are same but the anchors would be different, | 93 // compatibility. The positions are same but the anchors would be different, |
| 94 // and selection painting uses anchor nodes. | 94 // and selection painting uses anchor nodes. |
| 95 if (Node* firstChild = ComposedTreeTraversal::firstChild(*shadowHost)) | 95 if (Node* firstChild = FlatTreeTraversal::firstChild(*shadowHost)) |
| 96 return PositionInComposedTree::beforeNode(firstChild); | 96 return PositionInFlatTree::beforeNode(firstChild); |
| 97 return PositionInComposedTree(); | 97 return PositionInFlatTree(); |
| 98 } | 98 } |
| 99 | 99 |
| 100 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai
nerNode) | 100 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai
nerNode) |
| 101 { | 101 { |
| 102 TreeScope& treeScope = startContainerNode->treeScope(); | 102 TreeScope& treeScope = startContainerNode->treeScope(); |
| 103 | 103 |
| 104 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); | 104 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); |
| 105 | 105 |
| 106 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { | 106 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { |
| 107 if (ancestor->contains(startContainerNode)) | 107 if (ancestor->contains(startContainerNode)) |
| 108 return positionAfterNode(ancestor); | 108 return positionAfterNode(ancestor); |
| 109 return positionBeforeNode(ancestor); | 109 return positionBeforeNode(ancestor); |
| 110 } | 110 } |
| 111 | 111 |
| 112 if (Node* lastChild = treeScope.rootNode().lastChild()) | 112 if (Node* lastChild = treeScope.rootNode().lastChild()) |
| 113 return positionAfterNode(lastChild); | 113 return positionAfterNode(lastChild); |
| 114 | 114 |
| 115 return Position(); | 115 return Position(); |
| 116 } | 116 } |
| 117 | 117 |
| 118 PositionInComposedTree adjustPositionInComposedTreeForEnd(const PositionInCompos
edTree& position, Node* shadowHost) | 118 PositionInFlatTree adjustPositionInFlatTreeForEnd(const PositionInFlatTree& posi
tion, Node* shadowHost) |
| 119 { | 119 { |
| 120 if (isEnclosedBy(position, *shadowHost)) { | 120 if (isEnclosedBy(position, *shadowHost)) { |
| 121 if (position.isAfterChildren()) | 121 if (position.isAfterChildren()) |
| 122 return PositionInComposedTree::afterNode(shadowHost); | 122 return PositionInFlatTree::afterNode(shadowHost); |
| 123 return PositionInComposedTree::beforeNode(shadowHost); | 123 return PositionInFlatTree::beforeNode(shadowHost); |
| 124 } | 124 } |
| 125 | 125 |
| 126 // We use |lastChild|'s after instead of afterAllChildren for backward | 126 // We use |lastChild|'s after instead of afterAllChildren for backward |
| 127 // compatibility. The positions are same but the anchors would be different, | 127 // compatibility. The positions are same but the anchors would be different, |
| 128 // and selection painting uses anchor nodes. | 128 // and selection painting uses anchor nodes. |
| 129 if (Node* lastChild = ComposedTreeTraversal::lastChild(*shadowHost)) | 129 if (Node* lastChild = FlatTreeTraversal::lastChild(*shadowHost)) |
| 130 return PositionInComposedTree::afterNode(lastChild); | 130 return PositionInFlatTree::afterNode(lastChild); |
| 131 return PositionInComposedTree(); | 131 return PositionInFlatTree(); |
| 132 } | 132 } |
| 133 | 133 |
| 134 Position adjustPositionForStart(const Position& currentPosition, Node* endContai
nerNode) | 134 Position adjustPositionForStart(const Position& currentPosition, Node* endContai
nerNode) |
| 135 { | 135 { |
| 136 TreeScope& treeScope = endContainerNode->treeScope(); | 136 TreeScope& treeScope = endContainerNode->treeScope(); |
| 137 | 137 |
| 138 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); | 138 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); |
| 139 | 139 |
| 140 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { | 140 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { |
| 141 if (ancestor->contains(endContainerNode)) | 141 if (ancestor->contains(endContainerNode)) |
| 142 return positionBeforeNode(ancestor); | 142 return positionBeforeNode(ancestor); |
| 143 return positionAfterNode(ancestor); | 143 return positionAfterNode(ancestor); |
| 144 } | 144 } |
| 145 | 145 |
| 146 if (Node* firstChild = treeScope.rootNode().firstChild()) | 146 if (Node* firstChild = treeScope.rootNode().firstChild()) |
| 147 return positionBeforeNode(firstChild); | 147 return positionBeforeNode(firstChild); |
| 148 | 148 |
| 149 return Position(); | 149 return Position(); |
| 150 } | 150 } |
| 151 | 151 |
| 152 } // namespace | 152 } // namespace |
| 153 | 153 |
| 154 // Updates |selectionInComposedTree| to match with |selection|. | 154 // Updates |selectionInFlatTree| to match with |selection|. |
| 155 void SelectionAdjuster::adjustSelectionInComposedTree(VisibleSelectionInComposed
Tree* selectionInComposedTree, const VisibleSelection& selection) | 155 void SelectionAdjuster::adjustSelectionInFlatTree(VisibleSelectionInFlatTree* se
lectionInFlatTree, const VisibleSelection& selection) |
| 156 { | 156 { |
| 157 if (selection.isNone()) { | 157 if (selection.isNone()) { |
| 158 *selectionInComposedTree = VisibleSelectionInComposedTree(); | 158 *selectionInFlatTree = VisibleSelectionInFlatTree(); |
| 159 return; | 159 return; |
| 160 } | 160 } |
| 161 | 161 |
| 162 const PositionInComposedTree& base = toPositionInComposedTree(selection.base
()); | 162 const PositionInFlatTree& base = toPositionInFlatTree(selection.base()); |
| 163 const PositionInComposedTree& extent = toPositionInComposedTree(selection.ex
tent()); | 163 const PositionInFlatTree& extent = toPositionInFlatTree(selection.extent()); |
| 164 const PositionInComposedTree& position1 = toPositionInComposedTree(selection
.start()); | 164 const PositionInFlatTree& position1 = toPositionInFlatTree(selection.start()
); |
| 165 const PositionInComposedTree& position2 = toPositionInComposedTree(selection
.end()); | 165 const PositionInFlatTree& position2 = toPositionInFlatTree(selection.end()); |
| 166 position1.anchorNode()->updateDistribution(); | 166 position1.anchorNode()->updateDistribution(); |
| 167 position2.anchorNode()->updateDistribution(); | 167 position2.anchorNode()->updateDistribution(); |
| 168 selectionInComposedTree->m_base = base; | 168 selectionInFlatTree->m_base = base; |
| 169 selectionInComposedTree->m_extent = extent; | 169 selectionInFlatTree->m_extent = extent; |
| 170 selectionInComposedTree->m_affinity = selection.m_affinity; | 170 selectionInFlatTree->m_affinity = selection.m_affinity; |
| 171 selectionInComposedTree->m_isDirectional = selection.m_isDirectional; | 171 selectionInFlatTree->m_isDirectional = selection.m_isDirectional; |
| 172 selectionInComposedTree->m_granularity = selection.m_granularity; | 172 selectionInFlatTree->m_granularity = selection.m_granularity; |
| 173 selectionInComposedTree->m_hasTrailingWhitespace = selection.m_hasTrailingWh
itespace; | 173 selectionInFlatTree->m_hasTrailingWhitespace = selection.m_hasTrailingWhites
pace; |
| 174 selectionInComposedTree->m_baseIsFirst = base.isNull() || base.compareTo(ext
ent) <= 0; | 174 selectionInFlatTree->m_baseIsFirst = base.isNull() || base.compareTo(extent)
<= 0; |
| 175 if (position1.compareTo(position2) <= 0) { | 175 if (position1.compareTo(position2) <= 0) { |
| 176 selectionInComposedTree->m_start = position1; | 176 selectionInFlatTree->m_start = position1; |
| 177 selectionInComposedTree->m_end = position2; | 177 selectionInFlatTree->m_end = position2; |
| 178 } else { | 178 } else { |
| 179 selectionInComposedTree->m_start = position2; | 179 selectionInFlatTree->m_start = position2; |
| 180 selectionInComposedTree->m_end = position1; | 180 selectionInFlatTree->m_end = position1; |
| 181 } | 181 } |
| 182 selectionInComposedTree->updateSelectionType(); | 182 selectionInFlatTree->updateSelectionType(); |
| 183 selectionInComposedTree->didChange(); | 183 selectionInFlatTree->didChange(); |
| 184 } | 184 } |
| 185 | 185 |
| 186 static bool isCrossingShadowBoundaries(const VisibleSelectionInComposedTree& sel
ection) | 186 static bool isCrossingShadowBoundaries(const VisibleSelectionInFlatTree& selecti
on) |
| 187 { | 187 { |
| 188 if (!selection.isRange()) | 188 if (!selection.isRange()) |
| 189 return false; | 189 return false; |
| 190 TreeScope& treeScope = selection.base().anchorNode()->treeScope(); | 190 TreeScope& treeScope = selection.base().anchorNode()->treeScope(); |
| 191 return selection.extent().anchorNode()->treeScope() != treeScope | 191 return selection.extent().anchorNode()->treeScope() != treeScope |
| 192 || selection.start().anchorNode()->treeScope() != treeScope | 192 || selection.start().anchorNode()->treeScope() != treeScope |
| 193 || selection.end().anchorNode()->treeScope() != treeScope; | 193 || selection.end().anchorNode()->treeScope() != treeScope; |
| 194 } | 194 } |
| 195 | 195 |
| 196 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co
nst VisibleSelectionInComposedTree& selectionInComposedTree) | 196 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co
nst VisibleSelectionInFlatTree& selectionInFlatTree) |
| 197 { | 197 { |
| 198 if (selectionInComposedTree.isNone()) { | 198 if (selectionInFlatTree.isNone()) { |
| 199 *selection = VisibleSelection(); | 199 *selection = VisibleSelection(); |
| 200 return; | 200 return; |
| 201 } | 201 } |
| 202 | 202 |
| 203 const Position& base = toPositionInDOMTree(selectionInComposedTree.base()); | 203 const Position& base = toPositionInDOMTree(selectionInFlatTree.base()); |
| 204 const Position& extent = toPositionInDOMTree(selectionInComposedTree.extent(
)); | 204 const Position& extent = toPositionInDOMTree(selectionInFlatTree.extent()); |
| 205 | 205 |
| 206 if (isCrossingShadowBoundaries(selectionInComposedTree)) { | 206 if (isCrossingShadowBoundaries(selectionInFlatTree)) { |
| 207 *selection = VisibleSelection(base, extent); | 207 *selection = VisibleSelection(base, extent); |
| 208 return; | 208 return; |
| 209 } | 209 } |
| 210 | 210 |
| 211 const Position& position1 = toPositionInDOMTree(selectionInComposedTree.star
t()); | 211 const Position& position1 = toPositionInDOMTree(selectionInFlatTree.start())
; |
| 212 const Position& position2 = toPositionInDOMTree(selectionInComposedTree.end(
)); | 212 const Position& position2 = toPositionInDOMTree(selectionInFlatTree.end()); |
| 213 selection->m_base = base; | 213 selection->m_base = base; |
| 214 selection->m_extent = extent; | 214 selection->m_extent = extent; |
| 215 selection->m_affinity = selectionInComposedTree.m_affinity; | 215 selection->m_affinity = selectionInFlatTree.m_affinity; |
| 216 selection->m_isDirectional = selectionInComposedTree.m_isDirectional; | 216 selection->m_isDirectional = selectionInFlatTree.m_isDirectional; |
| 217 selection->m_granularity = selectionInComposedTree.m_granularity; | 217 selection->m_granularity = selectionInFlatTree.m_granularity; |
| 218 selection->m_hasTrailingWhitespace = selectionInComposedTree.m_hasTrailingWh
itespace; | 218 selection->m_hasTrailingWhitespace = selectionInFlatTree.m_hasTrailingWhites
pace; |
| 219 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0; | 219 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0; |
| 220 if (position1.compareTo(position2) <= 0) { | 220 if (position1.compareTo(position2) <= 0) { |
| 221 selection->m_start = position1; | 221 selection->m_start = position1; |
| 222 selection->m_end = position2; | 222 selection->m_end = position2; |
| 223 } else { | 223 } else { |
| 224 selection->m_start = position2; | 224 selection->m_start = position2; |
| 225 selection->m_end = position1; | 225 selection->m_end = position1; |
| 226 } | 226 } |
| 227 selection->updateSelectionType(); | 227 selection->updateSelectionType(); |
| 228 selection->didChange(); | 228 selection->didChange(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 249 } | 249 } |
| 250 | 250 |
| 251 const Position& newStart = adjustPositionForStart(selection->start(), select
ion->end().computeContainerNode()); | 251 const Position& newStart = adjustPositionForStart(selection->start(), select
ion->end().computeContainerNode()); |
| 252 selection->m_extent = newStart; | 252 selection->m_extent = newStart; |
| 253 selection->m_start = newStart; | 253 selection->m_start = newStart; |
| 254 } | 254 } |
| 255 | 255 |
| 256 // This function is called twice. The first is called when |m_start| and |m_end| | 256 // This function is called twice. The first is called when |m_start| and |m_end| |
| 257 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed | 257 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed |
| 258 // after downstream/upstream. | 258 // after downstream/upstream. |
| 259 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe
lectionInComposedTree* selection) | 259 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe
lectionInFlatTree* selection) |
| 260 { | 260 { |
| 261 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start()
); | 261 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start()
); |
| 262 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end()); | 262 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end()); |
| 263 if (shadowHostStart == shadowHostEnd) | 263 if (shadowHostStart == shadowHostEnd) |
| 264 return; | 264 return; |
| 265 | 265 |
| 266 if (selection->isBaseFirst()) { | 266 if (selection->isBaseFirst()) { |
| 267 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE
nd; | 267 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE
nd; |
| 268 const PositionInComposedTree& newEnd = adjustPositionInComposedTreeForEn
d(selection->end(), shadowHost); | 268 const PositionInFlatTree& newEnd = adjustPositionInFlatTreeForEnd(select
ion->end(), shadowHost); |
| 269 selection->m_extent = newEnd; | 269 selection->m_extent = newEnd; |
| 270 selection->m_end = newEnd; | 270 selection->m_end = newEnd; |
| 271 return; | 271 return; |
| 272 } | 272 } |
| 273 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart; | 273 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart; |
| 274 const PositionInComposedTree& newStart = adjustPositionInComposedTreeForStar
t(selection->start(), shadowHost); | 274 const PositionInFlatTree& newStart = adjustPositionInFlatTreeForStart(select
ion->start(), shadowHost); |
| 275 selection->m_extent = newStart; | 275 selection->m_extent = newStart; |
| 276 selection->m_start = newStart; | 276 selection->m_start = newStart; |
| 277 } | 277 } |
| 278 | 278 |
| 279 } // namespace blink | 279 } // namespace blink |
| OLD | NEW |