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 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 m_shouldShowBlockCursor(false) { | 53 m_shouldShowBlockCursor(false) { |
54 DCHECK(frame); | 54 DCHECK(frame); |
55 } | 55 } |
56 | 56 |
57 FrameCaret::~FrameCaret() = default; | 57 FrameCaret::~FrameCaret() = default; |
58 | 58 |
59 DEFINE_TRACE(FrameCaret) { | 59 DEFINE_TRACE(FrameCaret) { |
60 visitor->trace(m_selectionEditor); | 60 visitor->trace(m_selectionEditor); |
61 visitor->trace(m_frame); | 61 visitor->trace(m_frame); |
62 visitor->trace(m_previousCaretNode); | 62 visitor->trace(m_previousCaretNode); |
63 visitor->trace(m_previousCaretAnchorNode); | |
63 CaretBase::trace(visitor); | 64 CaretBase::trace(visitor); |
64 } | 65 } |
65 | 66 |
66 const PositionWithAffinity FrameCaret::caretPosition() const { | 67 const PositionWithAffinity FrameCaret::caretPosition() const { |
67 const VisibleSelection& selection = | 68 const VisibleSelection& selection = |
68 m_selectionEditor->visibleSelection<EditingStrategy>(); | 69 m_selectionEditor->visibleSelection<EditingStrategy>(); |
69 if (!selection.isCaret()) | 70 if (!selection.isCaret()) |
70 return PositionWithAffinity(); | 71 return PositionWithAffinity(); |
71 return PositionWithAffinity(selection.start(), selection.affinity()); | 72 return PositionWithAffinity(selection.start(), selection.affinity()); |
72 } | 73 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 } | 146 } |
146 | 147 |
147 void FrameCaret::invalidateCaretRect(bool forceInvalidation) { | 148 void FrameCaret::invalidateCaretRect(bool forceInvalidation) { |
148 if (!m_caretRectDirty) | 149 if (!m_caretRectDirty) |
149 return; | 150 return; |
150 m_caretRectDirty = false; | 151 m_caretRectDirty = false; |
151 | 152 |
152 DCHECK(caretPositionIsValidForDocument(*m_frame->document())); | 153 DCHECK(caretPositionIsValidForDocument(*m_frame->document())); |
153 LayoutObject* layoutObject = nullptr; | 154 LayoutObject* layoutObject = nullptr; |
154 LayoutRect newRect; | 155 LayoutRect newRect; |
156 PositionWithAffinity currentCaretPosition = caretPosition(); | |
155 if (isActive()) | 157 if (isActive()) |
156 newRect = localCaretRectOfPosition(caretPosition(), layoutObject); | 158 newRect = localCaretRectOfPosition(currentCaretPosition, layoutObject); |
157 Node* newNode = layoutObject ? layoutObject->node() : nullptr; | 159 Node* newNode = layoutObject ? layoutObject->node() : nullptr; |
158 | 160 // The current selected node |newNode| could be a child multiple levels below |
161 // its associated "anchor node" ancestor, so we reference and keep around the | |
162 // anchor node for checking editability. | |
163 // TODO(wkorman): Consider storing previous Position, rather than Node, and | |
164 // making use of EditingUtilies::isEditablePosition() directly. | |
165 Node* newAnchorNode = | |
yosin_UTC9
2016/10/13 03:58:47
I think we should use layout object associated Dis
| |
166 currentCaretPosition.position().parentAnchoredEquivalent().anchorNode(); | |
167 if (newNode && newAnchorNode && newNode != newAnchorNode && | |
168 newAnchorNode->layoutObject() && newAnchorNode->layoutObject()->isBox()) { | |
169 newNode->layoutObject()->mapToVisualRectInAncestorSpace( | |
170 toLayoutBoxModelObject(newAnchorNode->layoutObject()), newRect); | |
171 } | |
159 // It's possible for the timer to be inactive even though we want to | 172 // It's possible for the timer to be inactive even though we want to |
160 // invalidate the caret. For example, when running as a layout test the | 173 // invalidate the caret. For example, when running as a layout test the |
161 // caret blink interval could be zero and thus |m_caretBlinkTimer| will | 174 // caret blink interval could be zero and thus |m_caretBlinkTimer| will |
162 // never be started. We provide |forceInvalidation| for use by paint | 175 // never be started. We provide |forceInvalidation| for use by paint |
163 // invalidation internals where we need to invalidate the caret regardless | 176 // invalidation internals where we need to invalidate the caret regardless |
164 // of timer state. | 177 // of timer state. |
165 if (!forceInvalidation && !m_caretBlinkTimer.isActive() && | 178 if (!forceInvalidation && !m_caretBlinkTimer.isActive() && |
166 newNode == m_previousCaretNode && newRect == m_previousCaretRect && | 179 newNode == m_previousCaretNode && newRect == m_previousCaretRect && |
167 m_caretVisibility == m_previousCaretVisibility) | 180 m_caretVisibility == m_previousCaretVisibility) |
168 return; | 181 return; |
169 | 182 |
170 if (m_previousCaretNode && shouldRepaintCaret(*m_previousCaretNode)) | 183 if (m_previousCaretNode && shouldRepaintCaret(*m_previousCaretAnchorNode)) { |
171 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect); | 184 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
172 if (newNode && shouldRepaintCaret(*newNode)) | 185 m_previousCaretRect); |
173 invalidateLocalCaretRect(newNode, newRect); | 186 } |
187 if (newNode && shouldRepaintCaret(*newAnchorNode)) | |
188 invalidateLocalCaretRect(newAnchorNode, newRect); | |
174 m_previousCaretNode = newNode; | 189 m_previousCaretNode = newNode; |
190 m_previousCaretAnchorNode = newAnchorNode; | |
175 m_previousCaretRect = newRect; | 191 m_previousCaretRect = newRect; |
176 m_previousCaretVisibility = m_caretVisibility; | 192 m_previousCaretVisibility = m_caretVisibility; |
177 } | 193 } |
178 | 194 |
179 IntRect FrameCaret::absoluteCaretBounds() { | 195 IntRect FrameCaret::absoluteCaretBounds() { |
180 DCHECK_NE(m_frame->document()->lifecycle().state(), | 196 DCHECK_NE(m_frame->document()->lifecycle().state(), |
181 DocumentLifecycle::InPaintInvalidation); | 197 DocumentLifecycle::InPaintInvalidation); |
182 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 198 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
183 DocumentLifecycle::DisallowTransitionScope disallowTransition( | 199 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
184 m_frame->document()->lifecycle()); | 200 m_frame->document()->lifecycle()); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 | 233 |
218 updateCaretRect(caretPosition()); | 234 updateCaretRect(caretPosition()); |
219 CaretBase::paintCaret(caretPosition().position().anchorNode(), context, | 235 CaretBase::paintCaret(caretPosition().position().anchorNode(), context, |
220 paintOffset, DisplayItem::kCaret); | 236 paintOffset, DisplayItem::kCaret); |
221 } | 237 } |
222 | 238 |
223 void FrameCaret::dataWillChange(const CharacterData& node) { | 239 void FrameCaret::dataWillChange(const CharacterData& node) { |
224 if (node == m_previousCaretNode) { | 240 if (node == m_previousCaretNode) { |
225 // This invalidation is eager, and intentionally uses stale state. | 241 // This invalidation is eager, and intentionally uses stale state. |
226 DisableCompositingQueryAsserts disabler; | 242 DisableCompositingQueryAsserts disabler; |
227 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect); | 243 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
244 m_previousCaretRect); | |
228 } | 245 } |
229 } | 246 } |
230 | 247 |
231 void FrameCaret::nodeWillBeRemoved(Node& node) { | 248 void FrameCaret::nodeWillBeRemoved(Node& node) { |
232 if (node != m_previousCaretNode) | 249 if (node != m_previousCaretNode && node != m_previousCaretAnchorNode) |
233 return; | 250 return; |
234 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html | 251 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html |
235 DisableCompositingQueryAsserts disabler; | 252 DisableCompositingQueryAsserts disabler; |
236 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect); | 253 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
254 m_previousCaretRect); | |
237 m_previousCaretNode = nullptr; | 255 m_previousCaretNode = nullptr; |
256 m_previousCaretAnchorNode = nullptr; | |
238 m_previousCaretRect = LayoutRect(); | 257 m_previousCaretRect = LayoutRect(); |
239 m_previousCaretVisibility = CaretVisibility::Hidden; | 258 m_previousCaretVisibility = CaretVisibility::Hidden; |
240 } | 259 } |
241 | 260 |
242 void FrameCaret::documentDetached() { | 261 void FrameCaret::documentDetached() { |
243 m_caretBlinkTimer.stop(); | 262 m_caretBlinkTimer.stop(); |
244 m_previousCaretNode.clear(); | 263 m_previousCaretNode.clear(); |
264 m_previousCaretAnchorNode.clear(); | |
245 } | 265 } |
246 | 266 |
247 bool FrameCaret::shouldBlinkCaret() const { | 267 bool FrameCaret::shouldBlinkCaret() const { |
248 if (m_caretVisibility != CaretVisibility::Visible || !isActive()) | 268 if (m_caretVisibility != CaretVisibility::Visible || !isActive()) |
249 return false; | 269 return false; |
250 | 270 |
251 Element* root = rootEditableElementOf(caretPosition().position()); | 271 Element* root = rootEditableElementOf(caretPosition().position()); |
252 if (!root) | 272 if (!root) |
253 return false; | 273 return false; |
254 | 274 |
255 Element* focusedElement = root->document().focusedElement(); | 275 Element* focusedElement = root->document().focusedElement(); |
256 if (!focusedElement) | 276 if (!focusedElement) |
257 return false; | 277 return false; |
258 | 278 |
259 return focusedElement->isShadowIncludingInclusiveAncestorOf( | 279 return focusedElement->isShadowIncludingInclusiveAncestorOf( |
260 caretPosition().position().anchorNode()); | 280 caretPosition().position().anchorNode()); |
261 } | 281 } |
262 | 282 |
263 void FrameCaret::caretBlinkTimerFired(TimerBase*) { | 283 void FrameCaret::caretBlinkTimerFired(TimerBase*) { |
264 DCHECK_EQ(m_caretVisibility, CaretVisibility::Visible); | 284 DCHECK_EQ(m_caretVisibility, CaretVisibility::Visible); |
265 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) | 285 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) |
266 return; | 286 return; |
267 m_shouldPaintCaret = !m_shouldPaintCaret; | 287 m_shouldPaintCaret = !m_shouldPaintCaret; |
268 setCaretRectNeedsUpdate(); | 288 setCaretRectNeedsUpdate(); |
269 } | 289 } |
270 | 290 |
271 } // nemaspace blink | 291 } // namespace blink |
OLD | NEW |