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" | |
30 #include "core/editing/EditingUtilities.h" | 28 #include "core/editing/EditingUtilities.h" |
31 #include "core/editing/Editor.h" | 29 #include "core/editing/Editor.h" |
32 #include "core/editing/SelectionAdjuster.h" | 30 #include "core/editing/SelectionAdjuster.h" |
33 #include "core/frame/LocalFrame.h" | 31 #include "core/frame/LocalFrame.h" |
34 | 32 |
35 namespace blink { | 33 namespace blink { |
36 | 34 |
37 SelectionEditor::SelectionEditor(LocalFrame& frame) : m_frame(frame) { | 35 SelectionEditor::SelectionEditor(LocalFrame& frame) |
| 36 : m_frame(frame), m_observingVisibleSelection(false) { |
38 clearVisibleSelection(); | 37 clearVisibleSelection(); |
39 } | 38 } |
40 | 39 |
41 SelectionEditor::~SelectionEditor() {} | 40 SelectionEditor::~SelectionEditor() {} |
42 | 41 |
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 | |
53 void SelectionEditor::clearVisibleSelection() { | 42 void SelectionEditor::clearVisibleSelection() { |
54 m_selection = SelectionInDOMTree(); | 43 m_selection = VisibleSelection(); |
55 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); | 44 m_selectionInFlatTree = VisibleSelectionInFlatTree(); |
56 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); | |
57 m_cacheIsDirty = false; | |
58 if (!shouldAlwaysUseDirectionalSelection()) | 45 if (!shouldAlwaysUseDirectionalSelection()) |
59 return; | 46 return; |
60 m_selection.m_isDirectional = true; | 47 m_selection.setIsDirectional(true); |
| 48 m_selectionInFlatTree.setIsDirectional(true); |
61 } | 49 } |
62 | 50 |
63 void SelectionEditor::dispose() { | 51 void SelectionEditor::dispose() { |
64 resetLogicalRange(); | 52 resetLogicalRange(); |
65 clearDocumentCachedRange(); | 53 clearDocumentCachedRange(); |
66 clearVisibleSelection(); | 54 clearVisibleSelection(); |
67 } | 55 } |
68 | 56 |
69 Document& SelectionEditor::document() const { | 57 const Document& SelectionEditor::document() const { |
70 DCHECK(lifecycleContext()); | 58 DCHECK(m_document); |
71 return *lifecycleContext(); | 59 return *m_document; |
72 } | 60 } |
73 | 61 |
74 template <> | 62 template <> |
75 const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>() | 63 const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>() |
76 const { | 64 const { |
77 return computeVisibleSelectionInDOMTree(); | 65 DCHECK_EQ(frame()->document(), document()); |
| 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; |
78 } | 71 } |
79 | 72 |
80 template <> | 73 template <> |
81 const VisibleSelectionInFlatTree& | 74 const VisibleSelectionInFlatTree& |
82 SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const { | 75 SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const { |
83 return computeVisibleSelectionInFlatTree(); | 76 DCHECK_EQ(frame()->document(), document()); |
| 77 DCHECK_EQ(frame(), document().frame()); |
| 78 if (m_selectionInFlatTree.isNone()) |
| 79 return m_selectionInFlatTree; |
| 80 DCHECK_EQ(m_selectionInFlatTree.base().document(), document()); |
| 81 return m_selectionInFlatTree; |
84 } | 82 } |
85 | 83 |
86 const VisibleSelection& SelectionEditor::computeVisibleSelectionInDOMTree() | 84 void SelectionEditor::setVisibleSelection( |
87 const { | 85 const VisibleSelection& newSelection, |
88 DCHECK_EQ(frame()->document(), document()); | 86 FrameSelection::SetSelectionOptions options) { |
89 DCHECK_EQ(frame(), document().frame()); | 87 DCHECK(newSelection.isValidFor(document())) << newSelection; |
90 updateCachedVisibleSelectionIfNeeded(); | 88 resetLogicalRange(); |
91 if (m_cachedVisibleSelectionInDOMTree.isNone()) | 89 clearDocumentCachedRange(); |
92 return m_cachedVisibleSelectionInDOMTree; | 90 |
93 DCHECK_EQ(m_cachedVisibleSelectionInDOMTree.base().document(), document()); | 91 m_selection = newSelection; |
94 return m_cachedVisibleSelectionInDOMTree; | 92 if (options & FrameSelection::DoNotAdjustInFlatTree) { |
| 93 m_selectionInFlatTree.setWithoutValidation( |
| 94 toPositionInFlatTree(m_selection.base()), |
| 95 toPositionInFlatTree(m_selection.extent())); |
| 96 return; |
| 97 } |
| 98 |
| 99 SelectionAdjuster::adjustSelectionInFlatTree(&m_selectionInFlatTree, |
| 100 m_selection); |
95 } | 101 } |
96 | 102 |
97 const VisibleSelectionInFlatTree& | 103 void SelectionEditor::setVisibleSelection( |
98 SelectionEditor::computeVisibleSelectionInFlatTree() const { | 104 const VisibleSelectionInFlatTree& newSelection, |
99 DCHECK_EQ(frame()->document(), document()); | 105 FrameSelection::SetSelectionOptions options) { |
100 DCHECK_EQ(frame(), document().frame()); | 106 DCHECK(newSelection.isValidFor(document())) << newSelection; |
101 updateCachedVisibleSelectionIfNeeded(); | 107 DCHECK(!(options & FrameSelection::DoNotAdjustInFlatTree)); |
102 if (m_cachedVisibleSelectionInFlatTree.isNone()) | 108 resetLogicalRange(); |
103 return m_cachedVisibleSelectionInFlatTree; | 109 clearDocumentCachedRange(); |
104 DCHECK_EQ(m_cachedVisibleSelectionInFlatTree.base().document(), document()); | 110 |
105 return m_cachedVisibleSelectionInFlatTree; | 111 m_selectionInFlatTree = newSelection; |
| 112 SelectionAdjuster::adjustSelectionInDOMTree(&m_selection, |
| 113 m_selectionInFlatTree); |
106 } | 114 } |
107 | 115 |
108 const SelectionInDOMTree& SelectionEditor::selectionInDOMTree() const { | 116 void SelectionEditor::setWithoutValidation(const Position& base, |
109 assertSelectionValid(); | 117 const Position& extent) { |
110 return m_selection; | 118 resetLogicalRange(); |
111 } | 119 if (base.isNotNull()) |
| 120 DCHECK_EQ(base.document(), document()); |
| 121 if (extent.isNotNull()) |
| 122 DCHECK_EQ(extent.document(), document()); |
| 123 clearDocumentCachedRange(); |
112 | 124 |
113 bool SelectionEditor::hasEditableStyle() const { | 125 m_selection.setWithoutValidation(base, extent); |
114 return computeVisibleSelectionInDOMTree().hasEditableStyle(); | 126 m_selectionInFlatTree.setWithoutValidation(toPositionInFlatTree(base), |
115 } | 127 toPositionInFlatTree(extent)); |
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; | |
135 resetLogicalRange(); | |
136 clearDocumentCachedRange(); | |
137 markCacheDirty(); | |
138 m_selection = newSelection; | |
139 } | |
140 | |
141 void SelectionEditor::didChangeChildren(const ContainerNode&) { | |
142 markCacheDirty(); | |
143 didFinishDOMMutation(); | |
144 } | |
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(); | |
150 return; | |
151 } | |
152 m_selection.m_base = newBase; | |
153 m_selection.m_extent = newExtent; | |
154 markCacheDirty(); | |
155 didFinishDOMMutation(); | |
156 } | |
157 | |
158 void SelectionEditor::didFinishDOMMutation() { | |
159 assertSelectionValid(); | |
160 } | 128 } |
161 | 129 |
162 void SelectionEditor::documentAttached(Document* document) { | 130 void SelectionEditor::documentAttached(Document* document) { |
163 DCHECK(document); | 131 DCHECK(document); |
164 DCHECK(!lifecycleContext()) << lifecycleContext(); | 132 DCHECK(!m_document) << m_document; |
165 m_styleVersion = static_cast<uint64_t>(-1); | 133 m_document = document; |
166 clearVisibleSelection(); | |
167 setContext(document); | |
168 } | 134 } |
169 | 135 |
170 void SelectionEditor::contextDestroyed(Document*) { | 136 void SelectionEditor::documentDetached(const Document& document) { |
| 137 DCHECK_EQ(m_document, &document); |
171 dispose(); | 138 dispose(); |
172 m_styleVersion = static_cast<uint64_t>(-1); | 139 m_document = nullptr; |
173 m_selection = SelectionInDOMTree(); | |
174 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); | |
175 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); | |
176 m_cacheIsDirty = false; | |
177 } | 140 } |
178 | 141 |
179 void SelectionEditor::resetLogicalRange() { | 142 void SelectionEditor::resetLogicalRange() { |
180 // Non-collapsed ranges are not allowed to start at the end of a line that | 143 // Non-collapsed ranges are not allowed to start at the end of a line that |
181 // is wrapped, they start at the beginning of the next line instead | 144 // is wrapped, they start at the beginning of the next line instead |
182 if (!m_logicalRange) | 145 if (!m_logicalRange) |
183 return; | 146 return; |
184 m_logicalRange->dispose(); | 147 m_logicalRange->dispose(); |
185 m_logicalRange = nullptr; | 148 m_logicalRange = nullptr; |
186 } | 149 } |
187 | 150 |
188 void SelectionEditor::setLogicalRange(Range* range) { | 151 void SelectionEditor::setLogicalRange(Range* range) { |
189 DCHECK_EQ(range->ownerDocument(), document()); | 152 DCHECK_EQ(range->ownerDocument(), document()); |
190 DCHECK(!m_logicalRange) << "A logical range should be one."; | 153 DCHECK(!m_logicalRange) << "A logical range should be one."; |
191 m_logicalRange = range; | 154 m_logicalRange = range; |
192 } | 155 } |
193 | 156 |
194 Range* SelectionEditor::firstRange() const { | 157 Range* SelectionEditor::firstRange() const { |
195 if (m_logicalRange) | 158 if (m_logicalRange) |
196 return m_logicalRange->cloneRange(); | 159 return m_logicalRange->cloneRange(); |
197 return firstRangeOf(computeVisibleSelectionInDOMTree()); | 160 return firstRangeOf(m_selection); |
198 } | 161 } |
199 | 162 |
200 bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const { | 163 bool SelectionEditor::shouldAlwaysUseDirectionalSelection() const { |
201 return frame()->editor().behavior().shouldConsiderSelectionAsDirectional(); | 164 return frame()->editor().behavior().shouldConsiderSelectionAsDirectional(); |
202 } | 165 } |
203 | 166 |
204 void SelectionEditor::updateIfNeeded() { | 167 void SelectionEditor::updateIfNeeded() { |
205 // TODO(yosin): We should unify |SelectionEditor::updateIfNeeded()| and | 168 DCHECK(m_selection.isValidFor(document())) << m_selection; |
206 // |updateCachedVisibleSelectionIfNeeded()| | 169 DCHECK(m_selectionInFlatTree.isValidFor(document())) << m_selection; |
207 updateCachedVisibleSelectionIfNeeded(); | 170 m_selection.updateIfNeeded(); |
208 } | 171 m_selectionInFlatTree.updateIfNeeded(); |
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; | |
236 } | 172 } |
237 | 173 |
238 void SelectionEditor::cacheRangeOfDocument(Range* range) { | 174 void SelectionEditor::cacheRangeOfDocument(Range* range) { |
239 m_cachedRange = range; | 175 m_cachedRange = range; |
240 } | 176 } |
241 | 177 |
242 Range* SelectionEditor::documentCachedRange() const { | 178 Range* SelectionEditor::documentCachedRange() const { |
243 return m_cachedRange; | 179 return m_cachedRange; |
244 } | 180 } |
245 | 181 |
246 void SelectionEditor::clearDocumentCachedRange() { | 182 void SelectionEditor::clearDocumentCachedRange() { |
247 m_cachedRange = nullptr; | 183 m_cachedRange = nullptr; |
248 } | 184 } |
249 | 185 |
250 DEFINE_TRACE(SelectionEditor) { | 186 DEFINE_TRACE(SelectionEditor) { |
| 187 visitor->trace(m_document); |
251 visitor->trace(m_frame); | 188 visitor->trace(m_frame); |
252 visitor->trace(m_selection); | 189 visitor->trace(m_selection); |
253 visitor->trace(m_cachedVisibleSelectionInDOMTree); | 190 visitor->trace(m_selectionInFlatTree); |
254 visitor->trace(m_cachedVisibleSelectionInFlatTree); | |
255 visitor->trace(m_logicalRange); | 191 visitor->trace(m_logicalRange); |
256 visitor->trace(m_cachedRange); | 192 visitor->trace(m_cachedRange); |
257 SynchronousMutationObserver::trace(visitor); | |
258 } | 193 } |
259 | 194 |
260 } // namespace blink | 195 } // namespace blink |
OLD | NEW |