| 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/FrameCaret.h" | 26 #include "core/editing/FrameCaret.h" |
| 27 | 27 |
| 28 #include "core/dom/TaskRunnerHelper.h" | 28 #include "core/dom/TaskRunnerHelper.h" |
| 29 #include "core/editing/CaretBase.h" |
| 29 #include "core/editing/EditingUtilities.h" | 30 #include "core/editing/EditingUtilities.h" |
| 30 #include "core/editing/Editor.h" | 31 #include "core/editing/Editor.h" |
| 31 #include "core/editing/SelectionEditor.h" | 32 #include "core/editing/SelectionEditor.h" |
| 32 #include "core/editing/commands/CompositeEditCommand.h" | 33 #include "core/editing/commands/CompositeEditCommand.h" |
| 33 #include "core/frame/FrameView.h" | 34 #include "core/frame/FrameView.h" |
| 34 #include "core/frame/LocalFrame.h" | 35 #include "core/frame/LocalFrame.h" |
| 35 #include "core/frame/Settings.h" | 36 #include "core/frame/Settings.h" |
| 36 #include "core/html/TextControlElement.h" | 37 #include "core/html/TextControlElement.h" |
| 37 #include "core/layout/LayoutTheme.h" | 38 #include "core/layout/LayoutTheme.h" |
| 38 #include "core/layout/api/LayoutPartItem.h" | 39 #include "core/layout/api/LayoutPartItem.h" |
| 39 #include "core/page/Page.h" | 40 #include "core/page/Page.h" |
| 40 #include "core/paint/PaintLayer.h" | 41 #include "core/paint/PaintLayer.h" |
| 41 #include "public/platform/WebTraceLocation.h" | 42 #include "public/platform/WebTraceLocation.h" |
| 42 | 43 |
| 43 namespace blink { | 44 namespace blink { |
| 44 | 45 |
| 45 FrameCaret::FrameCaret(LocalFrame& frame, | 46 FrameCaret::FrameCaret(LocalFrame& frame, |
| 46 const SelectionEditor& selectionEditor) | 47 const SelectionEditor& selectionEditor) |
| 47 : m_selectionEditor(&selectionEditor), | 48 : m_selectionEditor(&selectionEditor), |
| 48 m_frame(frame), | 49 m_frame(frame), |
| 50 m_caretBase(new CaretBase()), |
| 49 m_caretVisibility(CaretVisibility::Hidden), | 51 m_caretVisibility(CaretVisibility::Hidden), |
| 50 m_previousCaretVisibility(CaretVisibility::Hidden), | 52 m_previousCaretVisibility(CaretVisibility::Hidden), |
| 51 m_caretBlinkTimer(TaskRunnerHelper::get(TaskType::UnspecedTimer, &frame), | 53 m_caretBlinkTimer(TaskRunnerHelper::get(TaskType::UnspecedTimer, &frame), |
| 52 this, | 54 this, |
| 53 &FrameCaret::caretBlinkTimerFired), | 55 &FrameCaret::caretBlinkTimerFired), |
| 54 m_caretRectDirty(true), | 56 m_caretRectDirty(true), |
| 55 m_shouldPaintCaret(true), | 57 m_shouldPaintCaret(true), |
| 56 m_isCaretBlinkingSuspended(false), | 58 m_isCaretBlinkingSuspended(false), |
| 57 m_shouldShowBlockCursor(false) {} | 59 m_shouldShowBlockCursor(false) {} |
| 58 | 60 |
| 59 FrameCaret::~FrameCaret() = default; | 61 FrameCaret::~FrameCaret() = default; |
| 60 | 62 |
| 61 DEFINE_TRACE(FrameCaret) { | 63 DEFINE_TRACE(FrameCaret) { |
| 62 visitor->trace(m_selectionEditor); | 64 visitor->trace(m_selectionEditor); |
| 63 visitor->trace(m_frame); | 65 visitor->trace(m_frame); |
| 64 visitor->trace(m_previousCaretNode); | 66 visitor->trace(m_previousCaretNode); |
| 65 visitor->trace(m_previousCaretAnchorNode); | 67 visitor->trace(m_previousCaretAnchorNode); |
| 66 CaretBase::trace(visitor); | |
| 67 } | 68 } |
| 68 | 69 |
| 69 const PositionWithAffinity FrameCaret::caretPosition() const { | 70 const PositionWithAffinity FrameCaret::caretPosition() const { |
| 70 const VisibleSelection& selection = | 71 const VisibleSelection& selection = |
| 71 m_selectionEditor->visibleSelection<EditingStrategy>(); | 72 m_selectionEditor->visibleSelection<EditingStrategy>(); |
| 72 if (!selection.isCaret()) | 73 if (!selection.isCaret()) |
| 73 return PositionWithAffinity(); | 74 return PositionWithAffinity(); |
| 74 return PositionWithAffinity(selection.start(), selection.affinity()); | 75 return PositionWithAffinity(selection.start(), selection.affinity()); |
| 75 } | 76 } |
| 76 | 77 |
| 78 const DisplayItemClient& FrameCaret::displayItemClient() const { |
| 79 return *m_caretBase; |
| 80 } |
| 81 |
| 77 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) { | 82 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) { |
| 78 return frame->editor().lastEditCommand() && | 83 return frame->editor().lastEditCommand() && |
| 79 frame->editor().lastEditCommand()->shouldStopCaretBlinking(); | 84 frame->editor().lastEditCommand()->shouldStopCaretBlinking(); |
| 80 } | 85 } |
| 81 | 86 |
| 82 void FrameCaret::updateAppearance() { | 87 void FrameCaret::updateAppearance() { |
| 83 // Paint a block cursor instead of a caret in overtype mode unless the caret | 88 // Paint a block cursor instead of a caret in overtype mode unless the caret |
| 84 // is at the end of a line (in this case the FrameSelection will paint a | 89 // is at the end of a line (in this case the FrameSelection will paint a |
| 85 // blinking caret as usual). | 90 // blinking caret as usual). |
| 86 bool paintBlockCursor = m_shouldShowBlockCursor && isActive(); | 91 bool paintBlockCursor = m_shouldShowBlockCursor && isActive(); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 // caret blink interval could be zero and thus |m_caretBlinkTimer| will | 195 // caret blink interval could be zero and thus |m_caretBlinkTimer| will |
| 191 // never be started. We provide |forceInvalidation| for use by paint | 196 // never be started. We provide |forceInvalidation| for use by paint |
| 192 // invalidation internals where we need to invalidate the caret regardless | 197 // invalidation internals where we need to invalidate the caret regardless |
| 193 // of timer state. | 198 // of timer state. |
| 194 if (!forceInvalidation && !m_caretBlinkTimer.isActive() && | 199 if (!forceInvalidation && !m_caretBlinkTimer.isActive() && |
| 195 newNode == m_previousCaretNode && newRect == m_previousCaretRect && | 200 newNode == m_previousCaretNode && newRect == m_previousCaretRect && |
| 196 m_caretVisibility == m_previousCaretVisibility) | 201 m_caretVisibility == m_previousCaretVisibility) |
| 197 return; | 202 return; |
| 198 | 203 |
| 199 if (m_previousCaretAnchorNode && | 204 if (m_previousCaretAnchorNode && |
| 200 shouldRepaintCaret(*m_previousCaretAnchorNode)) { | 205 CaretBase::shouldRepaintCaret(*m_previousCaretAnchorNode)) { |
| 201 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), | 206 m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| 202 m_previousCaretRect); | 207 m_previousCaretRect); |
| 203 } | 208 } |
| 204 if (newAnchorNode && shouldRepaintCaret(*newAnchorNode)) | 209 if (newAnchorNode && CaretBase::shouldRepaintCaret(*newAnchorNode)) |
| 205 invalidateLocalCaretRect(newAnchorNode, newRect); | 210 m_caretBase->invalidateLocalCaretRect(newAnchorNode, newRect); |
| 206 m_previousCaretNode = newNode; | 211 m_previousCaretNode = newNode; |
| 207 m_previousCaretAnchorNode = newAnchorNode; | 212 m_previousCaretAnchorNode = newAnchorNode; |
| 208 m_previousCaretRect = newRect; | 213 m_previousCaretRect = newRect; |
| 209 m_previousCaretVisibility = m_caretVisibility; | 214 m_previousCaretVisibility = m_caretVisibility; |
| 210 } | 215 } |
| 211 | 216 |
| 212 // TDOO(yosin): We should mark |FrameCaret::absoluteCaretBounds()| to |const|. | 217 // TDOO(yosin): We should mark |FrameCaret::absoluteCaretBounds()| to |const|. |
| 213 IntRect FrameCaret::absoluteCaretBounds() { | 218 IntRect FrameCaret::absoluteCaretBounds() { |
| 214 DCHECK_NE(m_frame->document()->lifecycle().state(), | 219 DCHECK_NE(m_frame->document()->lifecycle().state(), |
| 215 DocumentLifecycle::InPaintInvalidation); | 220 DocumentLifecycle::InPaintInvalidation); |
| 216 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 221 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
| 217 DocumentLifecycle::DisallowTransitionScope disallowTransition( | 222 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
| 218 m_frame->document()->lifecycle()); | 223 m_frame->document()->lifecycle()); |
| 219 | 224 |
| 220 Node* const caretNode = caretPosition().anchorNode(); | 225 Node* const caretNode = caretPosition().anchorNode(); |
| 221 if (!isActive()) | 226 if (!isActive()) |
| 222 return absoluteBoundsForLocalRect(caretNode, LayoutRect()); | 227 return CaretBase::absoluteBoundsForLocalRect(caretNode, LayoutRect()); |
| 223 // TODO(yosin): We should get rid of text control short path since layout | 228 // TODO(yosin): We should get rid of text control short path since layout |
| 224 // tree is clean. | 229 // tree is clean. |
| 225 if (enclosingTextControl(caretPosition().position()) && | 230 if (enclosingTextControl(caretPosition().position()) && |
| 226 isVisuallyEquivalentCandidate(caretPosition().position())) { | 231 isVisuallyEquivalentCandidate(caretPosition().position())) { |
| 227 return absoluteBoundsForLocalRect(caretNode, | 232 return CaretBase::absoluteBoundsForLocalRect( |
| 228 computeCaretRect(caretPosition())); | 233 caretNode, CaretBase::computeCaretRect(caretPosition())); |
| 229 } | 234 } |
| 230 return absoluteBoundsForLocalRect( | 235 return CaretBase::absoluteBoundsForLocalRect( |
| 231 caretNode, computeCaretRect(createVisiblePosition(caretPosition()))); | 236 caretNode, |
| 237 CaretBase::computeCaretRect(createVisiblePosition(caretPosition()))); |
| 232 } | 238 } |
| 233 | 239 |
| 234 void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) { | 240 void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) { |
| 235 m_shouldShowBlockCursor = shouldShowBlockCursor; | 241 m_shouldShowBlockCursor = shouldShowBlockCursor; |
| 236 | 242 |
| 237 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 243 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 238 | 244 |
| 239 updateAppearance(); | 245 updateAppearance(); |
| 240 } | 246 } |
| 241 | 247 |
| 242 void FrameCaret::paintCaret(GraphicsContext& context, | 248 void FrameCaret::paintCaret(GraphicsContext& context, |
| 243 const LayoutPoint& paintOffset) { | 249 const LayoutPoint& paintOffset) { |
| 244 if (m_caretVisibility == CaretVisibility::Hidden) | 250 if (m_caretVisibility == CaretVisibility::Hidden) |
| 245 return; | 251 return; |
| 246 | 252 |
| 247 if (!(isActive() && m_shouldPaintCaret)) | 253 if (!(isActive() && m_shouldPaintCaret)) |
| 248 return; | 254 return; |
| 249 | 255 |
| 250 const LayoutRect caretLocalRect = computeCaretRect(caretPosition()); | 256 const LayoutRect caretLocalRect = |
| 251 CaretBase::paintCaret(caretPosition().anchorNode(), context, *this, | 257 CaretBase::computeCaretRect(caretPosition()); |
| 258 CaretBase::paintCaret(caretPosition().anchorNode(), context, *m_caretBase, |
| 252 caretLocalRect, paintOffset, DisplayItem::kCaret); | 259 caretLocalRect, paintOffset, DisplayItem::kCaret); |
| 253 } | 260 } |
| 254 | 261 |
| 255 void FrameCaret::dataWillChange(const CharacterData& node) { | 262 void FrameCaret::dataWillChange(const CharacterData& node) { |
| 256 if (node == m_previousCaretNode) { | 263 if (node == m_previousCaretNode) { |
| 257 // This invalidation is eager, and intentionally uses stale state. | 264 // This invalidation is eager, and intentionally uses stale state. |
| 258 DisableCompositingQueryAsserts disabler; | 265 DisableCompositingQueryAsserts disabler; |
| 259 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), | 266 m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| 260 m_previousCaretRect); | 267 m_previousCaretRect); |
| 261 } | 268 } |
| 262 } | 269 } |
| 263 | 270 |
| 264 void FrameCaret::nodeWillBeRemoved(Node& node) { | 271 void FrameCaret::nodeWillBeRemoved(Node& node) { |
| 265 if (node != m_previousCaretNode && node != m_previousCaretAnchorNode) | 272 if (node != m_previousCaretNode && node != m_previousCaretAnchorNode) |
| 266 return; | 273 return; |
| 267 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html | 274 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html |
| 268 DisableCompositingQueryAsserts disabler; | 275 DisableCompositingQueryAsserts disabler; |
| 269 invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), | 276 m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| 270 m_previousCaretRect); | 277 m_previousCaretRect); |
| 271 m_previousCaretNode = nullptr; | 278 m_previousCaretNode = nullptr; |
| 272 m_previousCaretAnchorNode = nullptr; | 279 m_previousCaretAnchorNode = nullptr; |
| 273 m_previousCaretRect = LayoutRect(); | 280 m_previousCaretRect = LayoutRect(); |
| 274 m_previousCaretVisibility = CaretVisibility::Hidden; | 281 m_previousCaretVisibility = CaretVisibility::Hidden; |
| 275 } | 282 } |
| 276 | 283 |
| 277 void FrameCaret::documentDetached() { | 284 void FrameCaret::documentDetached() { |
| 278 m_caretBlinkTimer.stop(); | 285 m_caretBlinkTimer.stop(); |
| 279 m_previousCaretNode.clear(); | 286 m_previousCaretNode.clear(); |
| 280 m_previousCaretAnchorNode.clear(); | 287 m_previousCaretAnchorNode.clear(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 298 | 305 |
| 299 void FrameCaret::caretBlinkTimerFired(TimerBase*) { | 306 void FrameCaret::caretBlinkTimerFired(TimerBase*) { |
| 300 DCHECK_EQ(m_caretVisibility, CaretVisibility::Visible); | 307 DCHECK_EQ(m_caretVisibility, CaretVisibility::Visible); |
| 301 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) | 308 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) |
| 302 return; | 309 return; |
| 303 m_shouldPaintCaret = !m_shouldPaintCaret; | 310 m_shouldPaintCaret = !m_shouldPaintCaret; |
| 304 setCaretRectNeedsUpdate(); | 311 setCaretRectNeedsUpdate(); |
| 305 } | 312 } |
| 306 | 313 |
| 307 } // namespace blink | 314 } // namespace blink |
| OLD | NEW |