OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 12 matching lines...) Expand all Loading... |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "core/editing/VisibleSelection.h" | 26 #include "core/editing/VisibleSelection.h" |
27 | 27 |
28 #include "bindings/core/v8/ExceptionState.h" | 28 #include "bindings/core/v8/ExceptionState.h" |
29 #include "core/dom/Document.h" | 29 #include "core/dom/Document.h" |
30 #include "core/dom/Element.h" | 30 #include "core/dom/Element.h" |
31 #include "core/dom/Range.h" | 31 #include "core/dom/Range.h" |
32 #include "core/editing/EditingUtilities.h" | 32 #include "core/editing/EditingUtilities.h" |
33 #include "core/editing/SelectionAdjuster.h" | |
34 #include "core/editing/iterators/CharacterIterator.h" | 33 #include "core/editing/iterators/CharacterIterator.h" |
35 #include "platform/geometry/LayoutPoint.h" | 34 #include "platform/geometry/LayoutPoint.h" |
36 #include "wtf/Assertions.h" | 35 #include "wtf/Assertions.h" |
37 #include "wtf/text/CString.h" | 36 #include "wtf/text/CString.h" |
38 #include "wtf/text/CharacterNames.h" | 37 #include "wtf/text/CharacterNames.h" |
39 #include "wtf/text/StringBuilder.h" | 38 #include "wtf/text/StringBuilder.h" |
40 | 39 |
41 namespace blink { | 40 namespace blink { |
42 | 41 |
| 42 namespace { |
| 43 |
| 44 enum class AdjustDirection { kAdjustNone, kAdjustStart, kAdjustEnd }; |
| 45 |
| 46 Node* enclosingShadowHost(Node* node) { |
| 47 for (Node* runner = node; runner; |
| 48 runner = FlatTreeTraversal::parent(*runner)) { |
| 49 if (isShadowHost(runner)) |
| 50 return runner; |
| 51 } |
| 52 return nullptr; |
| 53 } |
| 54 |
| 55 bool isEnclosedBy(const PositionInFlatTree& position, const Node& node) { |
| 56 DCHECK(position.isNotNull()); |
| 57 Node* anchorNode = position.anchorNode(); |
| 58 if (anchorNode == node) |
| 59 return !position.isAfterAnchor() && !position.isBeforeAnchor(); |
| 60 |
| 61 return FlatTreeTraversal::isDescendantOf(*anchorNode, node); |
| 62 } |
| 63 |
| 64 bool isSelectionBoundary(const Node& node) { |
| 65 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || |
| 66 isHTMLSelectElement(node); |
| 67 } |
| 68 |
| 69 Node* enclosingShadowHostForStart(const PositionInFlatTree& position) { |
| 70 Node* node = position.nodeAsRangeFirstNode(); |
| 71 if (!node) |
| 72 return nullptr; |
| 73 Node* shadowHost = enclosingShadowHost(node); |
| 74 if (!shadowHost) |
| 75 return nullptr; |
| 76 if (!isEnclosedBy(position, *shadowHost)) |
| 77 return nullptr; |
| 78 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
| 79 } |
| 80 |
| 81 Node* enclosingShadowHostForEnd(const PositionInFlatTree& position) { |
| 82 Node* node = position.nodeAsRangeLastNode(); |
| 83 if (!node) |
| 84 return nullptr; |
| 85 Node* shadowHost = enclosingShadowHost(node); |
| 86 if (!shadowHost) |
| 87 return nullptr; |
| 88 if (!isEnclosedBy(position, *shadowHost)) |
| 89 return nullptr; |
| 90 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
| 91 } |
| 92 |
| 93 PositionInFlatTree adjustPositionInFlatTreeForStart( |
| 94 const PositionInFlatTree& position, |
| 95 Node* shadowHost) { |
| 96 if (isEnclosedBy(position, *shadowHost)) { |
| 97 if (position.isBeforeChildren()) |
| 98 return PositionInFlatTree::beforeNode(shadowHost); |
| 99 return PositionInFlatTree::afterNode(shadowHost); |
| 100 } |
| 101 |
| 102 // We use |firstChild|'s after instead of beforeAllChildren for backward |
| 103 // compatibility. The positions are same but the anchors would be different, |
| 104 // and selection painting uses anchor nodes. |
| 105 if (Node* firstChild = FlatTreeTraversal::firstChild(*shadowHost)) |
| 106 return PositionInFlatTree::beforeNode(firstChild); |
| 107 return PositionInFlatTree(); |
| 108 } |
| 109 |
| 110 Position adjustPositionForEnd(const Position& currentPosition, |
| 111 Node* startContainerNode) { |
| 112 TreeScope& treeScope = startContainerNode->treeScope(); |
| 113 |
| 114 DCHECK(currentPosition.computeContainerNode()->treeScope() != treeScope); |
| 115 |
| 116 if (Node* ancestor = treeScope.ancestorInThisScope( |
| 117 currentPosition.computeContainerNode())) { |
| 118 if (ancestor->contains(startContainerNode)) |
| 119 return Position::afterNode(ancestor); |
| 120 return Position::beforeNode(ancestor); |
| 121 } |
| 122 |
| 123 if (Node* lastChild = treeScope.rootNode().lastChild()) |
| 124 return Position::afterNode(lastChild); |
| 125 |
| 126 return Position(); |
| 127 } |
| 128 |
| 129 PositionInFlatTree adjustPositionInFlatTreeForEnd( |
| 130 const PositionInFlatTree& position, |
| 131 Node* shadowHost) { |
| 132 if (isEnclosedBy(position, *shadowHost)) { |
| 133 if (position.isAfterChildren()) |
| 134 return PositionInFlatTree::afterNode(shadowHost); |
| 135 return PositionInFlatTree::beforeNode(shadowHost); |
| 136 } |
| 137 |
| 138 // We use |lastChild|'s after instead of afterAllChildren for backward |
| 139 // compatibility. The positions are same but the anchors would be different, |
| 140 // and selection painting uses anchor nodes. |
| 141 if (Node* lastChild = FlatTreeTraversal::lastChild(*shadowHost)) |
| 142 return PositionInFlatTree::afterNode(lastChild); |
| 143 return PositionInFlatTree(); |
| 144 } |
| 145 |
| 146 Position adjustPositionForStart(const Position& currentPosition, |
| 147 Node* endContainerNode) { |
| 148 TreeScope& treeScope = endContainerNode->treeScope(); |
| 149 |
| 150 DCHECK(currentPosition.computeContainerNode()->treeScope() != treeScope); |
| 151 |
| 152 if (Node* ancestor = treeScope.ancestorInThisScope( |
| 153 currentPosition.computeContainerNode())) { |
| 154 if (ancestor->contains(endContainerNode)) |
| 155 return Position::beforeNode(ancestor); |
| 156 return Position::afterNode(ancestor); |
| 157 } |
| 158 |
| 159 if (Node* firstChild = treeScope.rootNode().firstChild()) |
| 160 return Position::beforeNode(firstChild); |
| 161 |
| 162 return Position(); |
| 163 } |
| 164 |
| 165 std::pair<AdjustDirection, Position> adjustmentToAvoidCrossingShadowBoundaries( |
| 166 const VisibleSelection& selection) { |
| 167 // Note: |m_selectionType| isn't computed yet. |
| 168 DCHECK(selection.base().isNotNull()); |
| 169 DCHECK(selection.extent().isNotNull()); |
| 170 DCHECK(selection.start().isNotNull()); |
| 171 DCHECK(selection.end().isNotNull()); |
| 172 |
| 173 // TODO(hajimehoshi): Checking treeScope is wrong when a node is |
| 174 // distributed, but we leave it as it is for backward compatibility. |
| 175 if (selection.start().anchorNode()->treeScope() == |
| 176 selection.end().anchorNode()->treeScope()) |
| 177 return std::make_pair(AdjustDirection::kAdjustNone, Position()); |
| 178 |
| 179 if (selection.isBaseFirst()) { |
| 180 const Position& newEnd = adjustPositionForEnd( |
| 181 selection.end(), selection.start().computeContainerNode()); |
| 182 return std::make_pair(AdjustDirection::kAdjustEnd, newEnd); |
| 183 } |
| 184 |
| 185 const Position& newStart = adjustPositionForStart( |
| 186 selection.start(), selection.end().computeContainerNode()); |
| 187 return std::make_pair(AdjustDirection::kAdjustStart, newStart); |
| 188 } |
| 189 |
| 190 // This function is called twice. The first is called when |m_start| and |m_end| |
| 191 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed |
| 192 // after downstream/upstream. |
| 193 std::pair<AdjustDirection, PositionInFlatTree> |
| 194 adjustmentToAvoidCrossingShadowBoundaries( |
| 195 const VisibleSelectionInFlatTree& selection) { |
| 196 Node* const shadowHostStart = enclosingShadowHostForStart(selection.start()); |
| 197 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection.end()); |
| 198 if (shadowHostStart == shadowHostEnd) |
| 199 return std::make_pair(AdjustDirection::kAdjustNone, PositionInFlatTree()); |
| 200 |
| 201 if (selection.isBaseFirst()) { |
| 202 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostEnd; |
| 203 const PositionInFlatTree& newEnd = |
| 204 adjustPositionInFlatTreeForEnd(selection.end(), shadowHost); |
| 205 return std::make_pair(AdjustDirection::kAdjustEnd, newEnd); |
| 206 } |
| 207 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart; |
| 208 const PositionInFlatTree& newStart = |
| 209 adjustPositionInFlatTreeForStart(selection.start(), shadowHost); |
| 210 return std::make_pair(AdjustDirection::kAdjustStart, newStart); |
| 211 } |
| 212 |
| 213 } // namespace |
| 214 |
43 template <typename Strategy> | 215 template <typename Strategy> |
44 VisibleSelectionTemplate<Strategy>::VisibleSelectionTemplate() | 216 VisibleSelectionTemplate<Strategy>::VisibleSelectionTemplate() |
45 : m_affinity(TextAffinity::Downstream), | 217 : m_affinity(TextAffinity::Downstream), |
46 m_selectionType(NoSelection), | 218 m_selectionType(NoSelection), |
47 m_baseIsFirst(true), | 219 m_baseIsFirst(true), |
48 m_isDirectional(false), | 220 m_isDirectional(false), |
49 m_granularity(CharacterGranularity), | 221 m_granularity(CharacterGranularity), |
50 m_hasTrailingWhitespace(false) {} | 222 m_hasTrailingWhitespace(false) {} |
51 | 223 |
52 template <typename Strategy> | 224 template <typename Strategy> |
(...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
808 | 980 |
809 void showTree(const blink::VisibleSelectionInFlatTree& sel) { | 981 void showTree(const blink::VisibleSelectionInFlatTree& sel) { |
810 sel.showTreeForThis(); | 982 sel.showTreeForThis(); |
811 } | 983 } |
812 | 984 |
813 void showTree(const blink::VisibleSelectionInFlatTree* sel) { | 985 void showTree(const blink::VisibleSelectionInFlatTree* sel) { |
814 if (sel) | 986 if (sel) |
815 sel->showTreeForThis(); | 987 sel->showTreeForThis(); |
816 } | 988 } |
817 #endif | 989 #endif |
OLD | NEW |