OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 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 |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
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/SelectionEditor.h" | 26 #include "core/editing/SelectionEditor.h" |
27 | 27 |
| 28 #include "core/dom/NodeWithIndex.h" |
| 29 #include "core/dom/Text.h" |
28 #include "core/editing/EditingUtilities.h" | 30 #include "core/editing/EditingUtilities.h" |
29 #include "core/editing/Editor.h" | 31 #include "core/editing/Editor.h" |
30 #include "core/editing/SelectionAdjuster.h" | 32 #include "core/editing/SelectionAdjuster.h" |
31 #include "core/frame/LocalFrame.h" | 33 #include "core/frame/LocalFrame.h" |
32 | 34 |
33 namespace blink { | 35 namespace blink { |
34 | 36 |
35 SelectionEditor::SelectionEditor(LocalFrame& frame) | 37 SelectionEditor::SelectionEditor(LocalFrame& frame) : m_frame(frame) { |
36 : m_frame(frame), m_observingVisibleSelection(false) { | |
37 clearVisibleSelection(); | 38 clearVisibleSelection(); |
38 } | 39 } |
39 | 40 |
40 SelectionEditor::~SelectionEditor() {} | 41 SelectionEditor::~SelectionEditor() {} |
41 | 42 |
| 43 void SelectionEditor::assertSelectionValid() const { |
| 44 #if DCHECK_IS_ON() |
| 45 // Since We don't track dom tree version during attribute changes, we can't |
| 46 // use it for validity of |m_selection|. |
| 47 const_cast<SelectionEditor*>(this)->m_selection.m_domTreeVersion = |
| 48 document().domTreeVersion(); |
| 49 #endif |
| 50 m_selection.assertValidFor(document()); |
| 51 } |
| 52 |
42 void SelectionEditor::clearVisibleSelection() { | 53 void SelectionEditor::clearVisibleSelection() { |
43 m_selection = VisibleSelection(); | 54 m_selection = SelectionInDOMTree(); |
44 m_selectionInFlatTree = VisibleSelectionInFlatTree(); | 55 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); |
| 56 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); |
| 57 m_cacheIsDirty = false; |
45 if (!shouldAlwaysUseDirectionalSelection()) | 58 if (!shouldAlwaysUseDirectionalSelection()) |
46 return; | 59 return; |
47 m_selection.setIsDirectional(true); | 60 m_selection.m_isDirectional = true; |
48 m_selectionInFlatTree.setIsDirectional(true); | |
49 } | 61 } |
50 | 62 |
51 void SelectionEditor::dispose() { | 63 void SelectionEditor::dispose() { |
52 resetLogicalRange(); | 64 resetLogicalRange(); |
53 clearDocumentCachedRange(); | 65 clearDocumentCachedRange(); |
54 clearVisibleSelection(); | 66 clearVisibleSelection(); |
55 } | 67 } |
56 | 68 |
57 const Document& SelectionEditor::document() const { | 69 Document& SelectionEditor::document() const { |
58 DCHECK(m_document); | 70 DCHECK(lifecycleContext()); |
59 return *m_document; | 71 return *lifecycleContext(); |
60 } | 72 } |
61 | 73 |
62 template <> | 74 template <> |
63 const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>() | 75 const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>() |
64 const { | 76 const { |
65 DCHECK_EQ(frame()->document(), document()); | 77 return computeVisibleSelectionInDOMTree(); |
66 DCHECK_EQ(frame(), document().frame()); | |
67 if (m_selection.isNone()) | |
68 return m_selection; | |
69 DCHECK_EQ(m_selection.base().document(), document()); | |
70 return m_selection; | |
71 } | 78 } |
72 | 79 |
73 template <> | 80 template <> |
74 const VisibleSelectionInFlatTree& | 81 const VisibleSelectionInFlatTree& |
75 SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const { | 82 SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const { |
| 83 return computeVisibleSelectionInFlatTree(); |
| 84 } |
| 85 |
| 86 const VisibleSelection& SelectionEditor::computeVisibleSelectionInDOMTree() |
| 87 const { |
76 DCHECK_EQ(frame()->document(), document()); | 88 DCHECK_EQ(frame()->document(), document()); |
77 DCHECK_EQ(frame(), document().frame()); | 89 DCHECK_EQ(frame(), document().frame()); |
78 if (m_selectionInFlatTree.isNone()) | 90 updateCachedVisibleSelectionIfNeeded(); |
79 return m_selectionInFlatTree; | 91 if (m_cachedVisibleSelectionInDOMTree.isNone()) |
80 DCHECK_EQ(m_selectionInFlatTree.base().document(), document()); | 92 return m_cachedVisibleSelectionInDOMTree; |
81 return m_selectionInFlatTree; | 93 DCHECK_EQ(m_cachedVisibleSelectionInDOMTree.base().document(), document()); |
| 94 return m_cachedVisibleSelectionInDOMTree; |
82 } | 95 } |
83 | 96 |
84 void SelectionEditor::setVisibleSelection( | 97 const VisibleSelectionInFlatTree& |
85 const VisibleSelection& newSelection, | 98 SelectionEditor::computeVisibleSelectionInFlatTree() const { |
86 FrameSelection::SetSelectionOptions options) { | 99 DCHECK_EQ(frame()->document(), document()); |
87 DCHECK(newSelection.isValidFor(document())) << newSelection; | 100 DCHECK_EQ(frame(), document().frame()); |
| 101 updateCachedVisibleSelectionIfNeeded(); |
| 102 if (m_cachedVisibleSelectionInFlatTree.isNone()) |
| 103 return m_cachedVisibleSelectionInFlatTree; |
| 104 DCHECK_EQ(m_cachedVisibleSelectionInFlatTree.base().document(), document()); |
| 105 return m_cachedVisibleSelectionInFlatTree; |
| 106 } |
| 107 |
| 108 const SelectionInDOMTree& SelectionEditor::selectionInDOMTree() const { |
| 109 assertSelectionValid(); |
| 110 return m_selection; |
| 111 } |
| 112 |
| 113 bool SelectionEditor::hasEditableStyle() const { |
| 114 return computeVisibleSelectionInDOMTree().hasEditableStyle(); |
| 115 } |
| 116 |
| 117 bool SelectionEditor::isContentEditable() const { |
| 118 return computeVisibleSelectionInDOMTree().isContentEditable(); |
| 119 } |
| 120 |
| 121 bool SelectionEditor::isContentRichlyEditable() const { |
| 122 return computeVisibleSelectionInDOMTree().isContentRichlyEditable(); |
| 123 } |
| 124 |
| 125 void SelectionEditor::markCacheDirty() { |
| 126 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); |
| 127 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); |
| 128 m_cacheIsDirty = true; |
| 129 } |
| 130 |
| 131 void SelectionEditor::setSelection(const SelectionInDOMTree& newSelection) { |
| 132 newSelection.assertValidFor(document()); |
| 133 if (m_selection == newSelection) |
| 134 return; |
88 resetLogicalRange(); | 135 resetLogicalRange(); |
89 clearDocumentCachedRange(); | 136 clearDocumentCachedRange(); |
| 137 markCacheDirty(); |
| 138 m_selection = newSelection; |
| 139 } |
90 | 140 |
91 m_selection = newSelection; | 141 void SelectionEditor::didChangeChildren(const ContainerNode&) { |
92 if (options & FrameSelection::DoNotAdjustInFlatTree) { | 142 markCacheDirty(); |
93 m_selectionInFlatTree.setWithoutValidation( | 143 didFinishDOMMutation(); |
94 toPositionInFlatTree(m_selection.base()), | 144 } |
95 toPositionInFlatTree(m_selection.extent())); | 145 |
| 146 void SelectionEditor::didFinishTextChange(const Position& newBase, |
| 147 const Position& newExtent) { |
| 148 if (newBase == m_selection.m_base && newExtent == m_selection.m_extent) { |
| 149 didFinishDOMMutation(); |
96 return; | 150 return; |
97 } | 151 } |
98 | 152 m_selection.m_base = newBase; |
99 SelectionAdjuster::adjustSelectionInFlatTree(&m_selectionInFlatTree, | 153 m_selection.m_extent = newExtent; |
100 m_selection); | 154 markCacheDirty(); |
| 155 didFinishDOMMutation(); |
101 } | 156 } |
102 | 157 |
103 void SelectionEditor::setVisibleSelection( | 158 void SelectionEditor::didFinishDOMMutation() { |
104 const VisibleSelectionInFlatTree& newSelection, | 159 assertSelectionValid(); |
105 FrameSelection::SetSelectionOptions options) { | |
106 DCHECK(newSelection.isValidFor(document())) << newSelection; | |
107 DCHECK(!(options & FrameSelection::DoNotAdjustInFlatTree)); | |
108 resetLogicalRange(); | |
109 clearDocumentCachedRange(); | |
110 | |
111 m_selectionInFlatTree = newSelection; | |
112 SelectionAdjuster::adjustSelectionInDOMTree(&m_selection, | |
113 m_selectionInFlatTree); | |
114 } | |
115 | |
116 void SelectionEditor::setWithoutValidation(const Position& base, | |
117 const Position& extent) { | |
118 resetLogicalRange(); | |
119 if (base.isNotNull()) | |
120 DCHECK_EQ(base.document(), document()); | |
121 if (extent.isNotNull()) | |
122 DCHECK_EQ(extent.document(), document()); | |
123 clearDocumentCachedRange(); | |
124 | |
125 m_selection.setWithoutValidation(base, extent); | |
126 m_selectionInFlatTree.setWithoutValidation(toPositionInFlatTree(base), | |
127 toPositionInFlatTree(extent)); | |
128 } | 160 } |
129 | 161 |
130 void SelectionEditor::documentAttached(Document* document) { | 162 void SelectionEditor::documentAttached(Document* document) { |
131 DCHECK(document); | 163 DCHECK(document); |
132 DCHECK(!m_document) << m_document; | 164 DCHECK(!lifecycleContext()) << lifecycleContext(); |
133 m_document = document; | 165 m_styleVersion = static_cast<uint64_t>(-1); |
| 166 clearVisibleSelection(); |
| 167 setContext(document); |
134 } | 168 } |
135 | 169 |
136 void SelectionEditor::documentDetached(const Document& document) { | 170 void SelectionEditor::contextDestroyed(Document*) { |
137 DCHECK_EQ(m_document, &document); | |
138 dispose(); | 171 dispose(); |
139 m_document = nullptr; | 172 m_styleVersion = static_cast<uint64_t>(-1); |
| 173 m_selection = SelectionInDOMTree(); |
| 174 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); |
| 175 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); |
| 176 m_cacheIsDirty = false; |
140 } | 177 } |
141 | 178 |
142 void SelectionEditor::resetLogicalRange() { | 179 void SelectionEditor::resetLogicalRange() { |
143 // Non-collapsed ranges are not allowed to start at the end of a line that | 180 // Non-collapsed ranges are not allowed to start at the end of a line that |
144 // is wrapped, they start at the beginning of the next line instead | 181 // is wrapped, they start at the beginning of the next line instead |
145 if (!m_logicalRange) | 182 if (!m_logicalRange) |
146 return; | 183 return; |
147 m_logicalRange->dispose(); | 184 m_logicalRange->dispose(); |
148 m_logicalRange = nullptr; | 185 m_logicalRange = nullptr; |
149 } | 186 } |
150 | 187 |
151 void SelectionEditor::setLogicalRange(Range* range) { | 188 void SelectionEditor::setLogicalRange(Range* range) { |
152 DCHECK_EQ(range->ownerDocument(), document()); | 189 DCHECK_EQ(range->ownerDocument(), document()); |
153 DCHECK(!m_logicalRange) << "A logical range should be one."; | 190 DCHECK(!m_logicalRange) << "A logical range should be one."; |
154 m_logicalRange = range; | 191 m_logicalRange = range; |
155 } | 192 } |
156 | 193 |
157 Range* SelectionEditor::firstRange() const { | 194 Range* SelectionEditor::firstRange() const { |
158 if (m_logicalRange) | 195 if (m_logicalRange) |
159 return m_logicalRange->cloneRange(); | 196 return m_logicalRange->cloneRange(); |
160 return firstRangeOf(m_selection); | 197 return firstRangeOf(computeVisibleSelectionInDOMTree()); |
161 } | 198 } |
162 | 199 |
163 bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const { | 200 bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const { |
164 return frame()->editor().behavior().shouldConsiderSelectionAsDirectional(); | 201 return frame()->editor().behavior().shouldConsiderSelectionAsDirectional(); |
165 } | 202 } |
166 | 203 |
167 void SelectionEditor::updateIfNeeded() { | 204 void SelectionEditor::updateIfNeeded() { |
168 DCHECK(m_selection.isValidFor(document())) << m_selection; | 205 // TODO(yosin): We should unify |SelectionEditor::updateIfNeeded()| and |
169 DCHECK(m_selectionInFlatTree.isValidFor(document())) << m_selection; | 206 // |updateCachedVisibleSelectionIfNeeded()| |
170 m_selection.updateIfNeeded(); | 207 updateCachedVisibleSelectionIfNeeded(); |
171 m_selectionInFlatTree.updateIfNeeded(); | 208 } |
| 209 |
| 210 bool SelectionEditor::needsUpdateVisibleSelection() const { |
| 211 return m_cacheIsDirty || m_styleVersion != document().styleVersion(); |
| 212 } |
| 213 |
| 214 void SelectionEditor::updateCachedVisibleSelectionIfNeeded() const { |
| 215 // Note: Since we |FrameCaret::updateApperance()| is called from |
| 216 // |FrameView::performPostLayoutTasks()|, we check lifecycle against |
| 217 // |AfterPerformLayout| instead of |LayoutClean|. |
| 218 DCHECK_GE(document().lifecycle().state(), |
| 219 DocumentLifecycle::AfterPerformLayout); |
| 220 assertSelectionValid(); |
| 221 if (!needsUpdateVisibleSelection()) |
| 222 return; |
| 223 |
| 224 m_cachedVisibleSelectionInDOMTree = createVisibleSelection(m_selection); |
| 225 m_cachedVisibleSelectionInFlatTree = createVisibleSelection( |
| 226 SelectionInFlatTree::Builder() |
| 227 .setBaseAndExtent(toPositionInFlatTree(m_selection.base()), |
| 228 toPositionInFlatTree(m_selection.extent())) |
| 229 .setAffinity(m_selection.affinity()) |
| 230 .setHasTrailingWhitespace(m_selection.hasTrailingWhitespace()) |
| 231 .setGranularity(m_selection.granularity()) |
| 232 .setIsDirectional(m_selection.isDirectional()) |
| 233 .build()); |
| 234 m_styleVersion = document().styleVersion(); |
| 235 m_cacheIsDirty = false; |
172 } | 236 } |
173 | 237 |
174 void SelectionEditor::cacheRangeOfDocument(Range* range) { | 238 void SelectionEditor::cacheRangeOfDocument(Range* range) { |
175 m_cachedRange = range; | 239 m_cachedRange = range; |
176 } | 240 } |
177 | 241 |
178 Range* SelectionEditor::documentCachedRange() const { | 242 Range* SelectionEditor::documentCachedRange() const { |
179 return m_cachedRange; | 243 return m_cachedRange; |
180 } | 244 } |
181 | 245 |
182 void SelectionEditor::clearDocumentCachedRange() { | 246 void SelectionEditor::clearDocumentCachedRange() { |
183 m_cachedRange = nullptr; | 247 m_cachedRange = nullptr; |
184 } | 248 } |
185 | 249 |
186 DEFINE_TRACE(SelectionEditor) { | 250 DEFINE_TRACE(SelectionEditor) { |
187 visitor->trace(m_document); | |
188 visitor->trace(m_frame); | 251 visitor->trace(m_frame); |
189 visitor->trace(m_selection); | 252 visitor->trace(m_selection); |
190 visitor->trace(m_selectionInFlatTree); | 253 visitor->trace(m_cachedVisibleSelectionInDOMTree); |
| 254 visitor->trace(m_cachedVisibleSelectionInFlatTree); |
191 visitor->trace(m_logicalRange); | 255 visitor->trace(m_logicalRange); |
192 visitor->trace(m_cachedRange); | 256 visitor->trace(m_cachedRange); |
| 257 SynchronousMutationObserver::trace(visitor); |
193 } | 258 } |
194 | 259 |
195 } // namespace blink | 260 } // namespace blink |
OLD | NEW |