| 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/editing/EditingUtilities.h" | 28 #include "core/editing/EditingUtilities.h" |
| 29 #include "core/editing/Editor.h" | 29 #include "core/editing/Editor.h" |
| 30 #include "core/editing/SelectionEditor.h" |
| 30 #include "core/editing/commands/CompositeEditCommand.h" | 31 #include "core/editing/commands/CompositeEditCommand.h" |
| 31 #include "core/frame/LocalFrame.h" | 32 #include "core/frame/LocalFrame.h" |
| 32 #include "core/frame/Settings.h" | 33 #include "core/frame/Settings.h" |
| 33 #include "core/html/HTMLTextFormControlElement.h" | 34 #include "core/html/HTMLTextFormControlElement.h" |
| 34 #include "core/layout/LayoutTheme.h" | 35 #include "core/layout/LayoutTheme.h" |
| 35 #include "core/layout/api/LayoutViewItem.h" | 36 #include "core/layout/api/LayoutViewItem.h" |
| 36 #include "core/page/Page.h" | 37 #include "core/page/Page.h" |
| 37 #include "core/paint/PaintLayer.h" | 38 #include "core/paint/PaintLayer.h" |
| 38 #include "public/platform/WebTraceLocation.h" | 39 #include "public/platform/WebTraceLocation.h" |
| 39 | 40 |
| 40 namespace blink { | 41 namespace blink { |
| 41 | 42 |
| 42 FrameCaret::FrameCaret(LocalFrame* frame) | 43 FrameCaret::FrameCaret(LocalFrame* frame, const SelectionEditor& selectionEditor
) |
| 43 : m_frame(frame) | 44 : m_selectionEditor(&selectionEditor) |
| 45 , m_frame(frame) |
| 44 , m_previousCaretVisibility(CaretVisibility::Hidden) | 46 , m_previousCaretVisibility(CaretVisibility::Hidden) |
| 45 , m_caretBlinkTimer(this, &FrameCaret::caretBlinkTimerFired) | 47 , m_caretBlinkTimer(this, &FrameCaret::caretBlinkTimerFired) |
| 46 , m_caretRectDirty(true) | 48 , m_caretRectDirty(true) |
| 47 , m_shouldPaintCaret(true) | 49 , m_shouldPaintCaret(true) |
| 48 , m_isCaretBlinkingSuspended(false) | 50 , m_isCaretBlinkingSuspended(false) |
| 49 , m_shouldShowBlockCursor(false) | 51 , m_shouldShowBlockCursor(false) |
| 50 { | 52 { |
| 51 DCHECK(frame); | 53 DCHECK(frame); |
| 52 } | 54 } |
| 53 | 55 |
| 54 FrameCaret::~FrameCaret() = default; | 56 FrameCaret::~FrameCaret() = default; |
| 55 | 57 |
| 56 DEFINE_TRACE(FrameCaret) | 58 DEFINE_TRACE(FrameCaret) |
| 57 { | 59 { |
| 60 visitor->trace(m_selectionEditor); |
| 58 visitor->trace(m_frame); | 61 visitor->trace(m_frame); |
| 59 visitor->trace(m_previousCaretNode); | 62 visitor->trace(m_previousCaretNode); |
| 60 visitor->trace(m_caretPosition); | |
| 61 CaretBase::trace(visitor); | 63 CaretBase::trace(visitor); |
| 62 } | 64 } |
| 63 | 65 |
| 64 void FrameCaret::setCaretPosition(const PositionWithAffinity& position) | 66 const PositionWithAffinity FrameCaret::caretPosition() const |
| 65 { | 67 { |
| 66 m_caretPosition = position; | 68 const VisibleSelection& selection = m_selectionEditor->visibleSelection<Edit
ingStrategy>(); |
| 67 setCaretRectNeedsUpdate(); | 69 if (!selection.isCaret()) |
| 68 } | 70 return PositionWithAffinity(); |
| 69 | 71 return PositionWithAffinity(selection.start(), selection.affinity()); |
| 70 void FrameCaret::clear() | |
| 71 { | |
| 72 m_caretPosition = PositionWithAffinity(); | |
| 73 setCaretRectNeedsUpdate(); | |
| 74 } | 72 } |
| 75 | 73 |
| 76 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) | 74 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) |
| 77 { | 75 { |
| 78 return frame->editor().lastEditCommand() && frame->editor().lastEditCommand(
)->shouldStopCaretBlinking(); | 76 return frame->editor().lastEditCommand() && frame->editor().lastEditCommand(
)->shouldStopCaretBlinking(); |
| 79 } | 77 } |
| 80 | 78 |
| 81 void FrameCaret::updateAppearance() | 79 void FrameCaret::updateAppearance() |
| 82 { | 80 { |
| 83 // Paint a block cursor instead of a caret in overtype mode unless the caret
is at the end of a line (in this case | 81 // Paint a block cursor instead of a caret in overtype mode unless the caret
is at the end of a line (in this case |
| 84 // the FrameSelection will paint a blinking caret as usual). | 82 // the FrameSelection will paint a blinking caret as usual). |
| 85 bool paintBlockCursor = m_shouldShowBlockCursor && isActive() && !isLogicalE
ndOfLine(createVisiblePosition(m_caretPosition)); | 83 bool paintBlockCursor = m_shouldShowBlockCursor && isActive() && !isLogicalE
ndOfLine(createVisiblePosition(caretPosition())); |
| 86 | 84 |
| 87 bool shouldBlink = !paintBlockCursor && shouldBlinkCaret(); | 85 bool shouldBlink = !paintBlockCursor && shouldBlinkCaret(); |
| 88 | 86 |
| 89 // If the caret moved, stop the blink timer so we can restart with a | 87 // If the caret moved, stop the blink timer so we can restart with a |
| 90 // black caret in the new location. | 88 // black caret in the new location. |
| 91 if (!shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame)) | 89 if (!shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame)) |
| 92 stopCaretBlinkTimer(); | 90 stopCaretBlinkTimer(); |
| 93 | 91 |
| 94 // Start blinking with a black caret. Be sure not to restart if we're | 92 // Start blinking with a black caret. Be sure not to restart if we're |
| 95 // already blinking in the right location. | 93 // already blinking in the right location. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 | 136 |
| 139 if (Page* page = m_frame->page()) | 137 if (Page* page = m_frame->page()) |
| 140 page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); | 138 page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); |
| 141 } | 139 } |
| 142 | 140 |
| 143 bool FrameCaret::caretPositionIsValidForDocument(const Document& document) const | 141 bool FrameCaret::caretPositionIsValidForDocument(const Document& document) const |
| 144 { | 142 { |
| 145 if (!isActive()) | 143 if (!isActive()) |
| 146 return true; | 144 return true; |
| 147 | 145 |
| 148 return m_caretPosition.position().document() == document | 146 return caretPosition().position().document() == document |
| 149 && !m_caretPosition.position().isOrphan(); | 147 && !caretPosition().position().isOrphan(); |
| 150 } | 148 } |
| 151 | 149 |
| 152 void FrameCaret::invalidateCaretRect() | 150 void FrameCaret::invalidateCaretRect() |
| 153 { | 151 { |
| 154 if (!m_caretRectDirty) | 152 if (!m_caretRectDirty) |
| 155 return; | 153 return; |
| 156 m_caretRectDirty = false; | 154 m_caretRectDirty = false; |
| 157 | 155 |
| 158 DCHECK(caretPositionIsValidForDocument(*m_frame->document())); | 156 DCHECK(caretPositionIsValidForDocument(*m_frame->document())); |
| 159 LayoutObject* layoutObject = nullptr; | 157 LayoutObject* layoutObject = nullptr; |
| 160 LayoutRect newRect; | 158 LayoutRect newRect; |
| 161 if (isActive()) | 159 if (isActive()) |
| 162 newRect = localCaretRectOfPosition(m_caretPosition, layoutObject); | 160 newRect = localCaretRectOfPosition(caretPosition(), layoutObject); |
| 163 Node* newNode = layoutObject ? layoutObject->node() : nullptr; | 161 Node* newNode = layoutObject ? layoutObject->node() : nullptr; |
| 164 | 162 |
| 165 if (!m_caretBlinkTimer.isActive() | 163 if (!m_caretBlinkTimer.isActive() |
| 166 && newNode == m_previousCaretNode | 164 && newNode == m_previousCaretNode |
| 167 && newRect == m_previousCaretRect | 165 && newRect == m_previousCaretRect |
| 168 && getCaretVisibility() == m_previousCaretVisibility) | 166 && getCaretVisibility() == m_previousCaretVisibility) |
| 169 return; | 167 return; |
| 170 | 168 |
| 171 LayoutViewItem view = m_frame->document()->layoutViewItem(); | 169 LayoutViewItem view = m_frame->document()->layoutViewItem(); |
| 172 if (m_previousCaretNode && (shouldRepaintCaret(*m_previousCaretNode) || shou
ldRepaintCaret(view))) | 170 if (m_previousCaretNode && (shouldRepaintCaret(*m_previousCaretNode) || shou
ldRepaintCaret(view))) |
| 173 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect)
; | 171 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect)
; |
| 174 if (newNode && (shouldRepaintCaret(*newNode) || shouldRepaintCaret(view))) | 172 if (newNode && (shouldRepaintCaret(*newNode) || shouldRepaintCaret(view))) |
| 175 invalidateLocalCaretRect(newNode, newRect); | 173 invalidateLocalCaretRect(newNode, newRect); |
| 176 m_previousCaretNode = newNode; | 174 m_previousCaretNode = newNode; |
| 177 m_previousCaretRect = newRect; | 175 m_previousCaretRect = newRect; |
| 178 m_previousCaretVisibility = getCaretVisibility(); | 176 m_previousCaretVisibility = getCaretVisibility(); |
| 179 } | 177 } |
| 180 | 178 |
| 181 IntRect FrameCaret::absoluteCaretBounds() | 179 IntRect FrameCaret::absoluteCaretBounds() |
| 182 { | 180 { |
| 183 DCHECK_NE(m_frame->document()->lifecycle().state(), DocumentLifecycle::InPai
ntInvalidation); | 181 DCHECK_NE(m_frame->document()->lifecycle().state(), DocumentLifecycle::InPai
ntInvalidation); |
| 184 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 182 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 185 if (!isActive()) { | 183 if (!isActive()) { |
| 186 clearCaretRect(); | 184 clearCaretRect(); |
| 187 } else { | 185 } else { |
| 188 if (enclosingTextFormControl(m_caretPosition.position())) | 186 if (enclosingTextFormControl(caretPosition().position())) { |
| 189 updateCaretRect(PositionWithAffinity(isVisuallyEquivalentCandidate(m
_caretPosition.position()) ? m_caretPosition.position() : Position(), m_caretPos
ition.affinity())); | 187 if (isVisuallyEquivalentCandidate(caretPosition().position())) |
| 190 else | 188 updateCaretRect(caretPosition()); |
| 191 updateCaretRect(createVisiblePosition(m_caretPosition)); | 189 else |
| 190 updateCaretRect(createVisiblePosition(caretPosition())); |
| 191 } else { |
| 192 updateCaretRect(createVisiblePosition(caretPosition())); |
| 193 } |
| 192 } | 194 } |
| 193 return absoluteBoundsForLocalRect(m_caretPosition.position().anchorNode(), l
ocalCaretRectWithoutUpdate()); | 195 return absoluteBoundsForLocalRect(caretPosition().position().anchorNode(), l
ocalCaretRectWithoutUpdate()); |
| 194 } | 196 } |
| 195 | 197 |
| 196 void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) | 198 void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) |
| 197 { | 199 { |
| 198 m_shouldShowBlockCursor = shouldShowBlockCursor; | 200 m_shouldShowBlockCursor = shouldShowBlockCursor; |
| 199 | 201 |
| 200 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 202 m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 201 | 203 |
| 202 updateAppearance(); | 204 updateAppearance(); |
| 203 } | 205 } |
| 204 | 206 |
| 205 void FrameCaret::paintCaret(GraphicsContext& context, const LayoutPoint& paintOf
fset) | 207 void FrameCaret::paintCaret(GraphicsContext& context, const LayoutPoint& paintOf
fset) |
| 206 { | 208 { |
| 207 if (!(isActive() && m_shouldPaintCaret)) | 209 if (!(isActive() && m_shouldPaintCaret)) |
| 208 return; | 210 return; |
| 209 | 211 |
| 210 updateCaretRect(m_caretPosition); | 212 updateCaretRect(caretPosition()); |
| 211 CaretBase::paintCaret(m_caretPosition.position().anchorNode(), context, pain
tOffset); | 213 CaretBase::paintCaret(caretPosition().position().anchorNode(), context, pain
tOffset); |
| 212 } | 214 } |
| 213 | 215 |
| 214 void FrameCaret::dataWillChange(const CharacterData& node) | 216 void FrameCaret::dataWillChange(const CharacterData& node) |
| 215 { | 217 { |
| 216 if (node == m_previousCaretNode) { | 218 if (node == m_previousCaretNode) { |
| 217 // This invalidation is eager, and intentionally uses stale state. | 219 // This invalidation is eager, and intentionally uses stale state. |
| 218 DisableCompositingQueryAsserts disabler; | 220 DisableCompositingQueryAsserts disabler; |
| 219 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect)
; | 221 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect)
; |
| 220 } | 222 } |
| 221 } | 223 } |
| 222 | 224 |
| 223 void FrameCaret::nodeWillBeRemoved(Node& node) | 225 void FrameCaret::nodeWillBeRemoved(Node& node) |
| 224 { | 226 { |
| 225 if (node != m_previousCaretNode) | 227 if (node != m_previousCaretNode) |
| 226 return; | 228 return; |
| 227 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html | 229 // Hits in ManualTests/caret-paint-after-last-text-is-removed.html |
| 228 DisableCompositingQueryAsserts disabler; | 230 DisableCompositingQueryAsserts disabler; |
| 229 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect); | 231 invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect); |
| 230 m_previousCaretNode = nullptr; | 232 m_previousCaretNode = nullptr; |
| 231 m_previousCaretRect = LayoutRect(); | 233 m_previousCaretRect = LayoutRect(); |
| 232 m_previousCaretVisibility = CaretVisibility::Hidden; | 234 m_previousCaretVisibility = CaretVisibility::Hidden; |
| 233 } | 235 } |
| 234 | 236 |
| 235 void FrameCaret::documentDetached() | 237 void FrameCaret::documentDetached() |
| 236 { | 238 { |
| 237 m_caretPosition = PositionWithAffinity(); | |
| 238 m_caretBlinkTimer.stop(); | 239 m_caretBlinkTimer.stop(); |
| 239 m_previousCaretNode.clear(); | 240 m_previousCaretNode.clear(); |
| 240 } | 241 } |
| 241 | 242 |
| 242 bool FrameCaret::shouldBlinkCaret() const | 243 bool FrameCaret::shouldBlinkCaret() const |
| 243 { | 244 { |
| 244 if (!caretIsVisible() || !isActive()) | 245 if (!caretIsVisible() || !isActive()) |
| 245 return false; | 246 return false; |
| 246 | 247 |
| 247 if (m_frame->settings() && m_frame->settings()->caretBrowsingEnabled()) | 248 if (m_frame->settings() && m_frame->settings()->caretBrowsingEnabled()) |
| 248 return false; | 249 return false; |
| 249 | 250 |
| 250 Element* root = rootEditableElementOf(m_caretPosition.position()); | 251 Element* root = rootEditableElementOf(caretPosition().position()); |
| 251 if (!root) | 252 if (!root) |
| 252 return false; | 253 return false; |
| 253 | 254 |
| 254 Element* focusedElement = root->document().focusedElement(); | 255 Element* focusedElement = root->document().focusedElement(); |
| 255 if (!focusedElement) | 256 if (!focusedElement) |
| 256 return false; | 257 return false; |
| 257 | 258 |
| 258 return focusedElement->isShadowIncludingInclusiveAncestorOf(m_caretPosition.
position().anchorNode()); | 259 return focusedElement->isShadowIncludingInclusiveAncestorOf(caretPosition().
position().anchorNode()); |
| 259 } | 260 } |
| 260 | 261 |
| 261 void FrameCaret::caretBlinkTimerFired(Timer<FrameCaret>*) | 262 void FrameCaret::caretBlinkTimerFired(Timer<FrameCaret>*) |
| 262 { | 263 { |
| 263 DCHECK(caretIsVisible()); | 264 DCHECK(caretIsVisible()); |
| 264 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) | 265 if (isCaretBlinkingSuspended() && m_shouldPaintCaret) |
| 265 return; | 266 return; |
| 266 m_shouldPaintCaret = !m_shouldPaintCaret; | 267 m_shouldPaintCaret = !m_shouldPaintCaret; |
| 267 setCaretRectNeedsUpdate(); | 268 setCaretRectNeedsUpdate(); |
| 268 } | 269 } |
| 269 | 270 |
| 270 } // nemaspace blink | 271 } // nemaspace blink |
| OLD | NEW |