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 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 | 265 |
266 VisibleSelection oldSelection = m_selection; | 266 VisibleSelection oldSelection = m_selection; |
267 | 267 |
268 m_selection = s; | 268 m_selection = s; |
269 setCaretRectNeedsUpdate(); | 269 setCaretRectNeedsUpdate(); |
270 | 270 |
271 if (!s.isNone() && !(options & DoNotSetFocus)) | 271 if (!s.isNone() && !(options & DoNotSetFocus)) |
272 setFocusedNodeIfNeeded(); | 272 setFocusedNodeIfNeeded(); |
273 | 273 |
274 if (!(options & DoNotUpdateAppearance)) { | 274 if (!(options & DoNotUpdateAppearance)) { |
275 m_frame->document()->updateLayoutIgnorePendingStylesheets(); | |
276 | |
277 // Hits in compositing/overflow/do-not-paint-outline-into-composited-scr
olling-contents.html | 275 // Hits in compositing/overflow/do-not-paint-outline-into-composited-scr
olling-contents.html |
278 DisableCompositingQueryAsserts disabler; | 276 DisableCompositingQueryAsserts disabler; |
279 updateAppearance(); | 277 updateAppearance(ResetCaretBlink); |
280 } | 278 } |
281 | 279 |
282 // Always clear the x position used for vertical arrow navigation. | 280 // Always clear the x position used for vertical arrow navigation. |
283 // It will be restored by the vertical arrow navigation code if necessary. | 281 // It will be restored by the vertical arrow navigation code if necessary. |
284 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); | 282 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); |
285 selectFrameElementInParentIfFullySelected(); | 283 selectFrameElementInParentIfFullySelected(); |
286 notifyRendererOfSelectionChange(userTriggered); | 284 notifyRendererOfSelectionChange(userTriggered); |
287 m_frame->editor().respondToChangedSelection(oldSelection, options); | 285 m_frame->editor().respondToChangedSelection(oldSelection, options); |
288 if (userTriggered == UserTriggered) { | 286 if (userTriggered == UserTriggered) { |
289 ScrollAlignment alignment; | 287 ScrollAlignment alignment; |
(...skipping 936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1226 } | 1224 } |
1227 | 1225 |
1228 static bool isTextFormControl(const VisibleSelection& selection) | 1226 static bool isTextFormControl(const VisibleSelection& selection) |
1229 { | 1227 { |
1230 return enclosingTextFormControl(selection.start()); | 1228 return enclosingTextFormControl(selection.start()); |
1231 } | 1229 } |
1232 | 1230 |
1233 LayoutRect FrameSelection::localCaretRect() | 1231 LayoutRect FrameSelection::localCaretRect() |
1234 { | 1232 { |
1235 if (shouldUpdateCaretRect()) { | 1233 if (shouldUpdateCaretRect()) { |
1236 if (!isNonOrphanedCaret(m_selection)) | 1234 if (!isNonOrphanedCaret(m_selection)) { |
1237 clearCaretRect(); | 1235 clearCaretRect(); |
1238 else if (isTextFormControl(m_selection)) | 1236 } else { |
1239 m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), Positi
onWithAffinity(m_selection.start().isCandidate() ? m_selection.start() : Positio
n(), m_selection.affinity())); | 1237 m_frame->document()->updateLayoutIgnorePendingStylesheets(); |
1240 else | 1238 if (isTextFormControl(m_selection)) |
1241 m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), Visibl
ePosition(m_selection.start(), m_selection.affinity())); | 1239 m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), Po
sitionWithAffinity(m_selection.start().isCandidate() ? m_selection.start() : Pos
ition(), m_selection.affinity())); |
| 1240 else |
| 1241 m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), Vi
siblePosition(m_selection.start(), m_selection.affinity())); |
| 1242 } |
1242 } | 1243 } |
1243 | |
1244 return localCaretRectWithoutUpdate(); | 1244 return localCaretRectWithoutUpdate(); |
1245 } | 1245 } |
1246 | 1246 |
1247 IntRect FrameSelection::absoluteCaretBounds() | 1247 IntRect FrameSelection::absoluteCaretBounds() |
1248 { | 1248 { |
1249 recomputeCaretRect(); | 1249 recomputeCaretRect(); |
1250 return m_absCaretBounds; | 1250 return m_absCaretBounds; |
1251 } | 1251 } |
1252 | 1252 |
1253 bool FrameSelection::recomputeCaretRect() | 1253 bool FrameSelection::recomputeCaretRect() |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1533 bool FrameSelection::isFocusedAndActive() const | 1533 bool FrameSelection::isFocusedAndActive() const |
1534 { | 1534 { |
1535 return m_focused && m_frame->page() && m_frame->page()->focusController().is
Active(); | 1535 return m_focused && m_frame->page() && m_frame->page()->focusController().is
Active(); |
1536 } | 1536 } |
1537 | 1537 |
1538 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) | 1538 inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame) |
1539 { | 1539 { |
1540 return frame->editor().lastEditCommand() && frame->editor().lastEditCommand(
)->shouldStopCaretBlinking(); | 1540 return frame->editor().lastEditCommand() && frame->editor().lastEditCommand(
)->shouldStopCaretBlinking(); |
1541 } | 1541 } |
1542 | 1542 |
1543 void FrameSelection::updateAppearance() | 1543 void FrameSelection::updateAppearance(UpdateAppearanceOption option) |
1544 { | 1544 { |
1545 // Paint a block cursor instead of a caret in overtype mode unless the caret
is at the end of a line (in this case | 1545 // Paint a block cursor instead of a caret in overtype mode unless the caret
is at the end of a line (in this case |
1546 // the FrameSelection will paint a blinking caret as usual). | 1546 // the FrameSelection will paint a blinking caret as usual). |
1547 bool paintBlockCursor = m_shouldShowBlockCursor && m_selection.isCaret() &&
!isLogicalEndOfLine(m_selection.visibleEnd()); | 1547 bool paintBlockCursor = m_shouldShowBlockCursor && m_selection.isCaret() &&
!isLogicalEndOfLine(m_selection.visibleEnd()); |
1548 | 1548 |
1549 bool caretRectChangedOrCleared = recomputeCaretRect(); | |
1550 bool shouldBlink = !paintBlockCursor && shouldBlinkCaret(); | 1549 bool shouldBlink = !paintBlockCursor && shouldBlinkCaret(); |
1551 | 1550 |
1552 // If the caret moved, stop the blink timer so we can restart with a | 1551 // If the caret moved, stop the blink timer so we can restart with a |
1553 // black caret in the new location. | 1552 // black caret in the new location. |
1554 if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypi
ngCommand(m_frame)) { | 1553 if (option == ResetCaretBlink || !shouldBlink || shouldStopBlinkingDueToTypi
ngCommand(m_frame)) { |
1555 m_caretBlinkTimer.stop(); | 1554 m_caretBlinkTimer.stop(); |
1556 if (!shouldBlink && m_caretPaint) { | 1555 if (!shouldBlink && m_caretPaint) { |
1557 m_caretPaint = false; | 1556 m_caretPaint = false; |
1558 invalidateCaretRect(); | 1557 setCaretRectNeedsUpdate(); |
1559 } | 1558 } |
1560 } | 1559 } |
1561 | 1560 |
1562 // Start blinking with a black caret. Be sure not to restart if we're | 1561 // Start blinking with a black caret. Be sure not to restart if we're |
1563 // already blinking in the right location. | 1562 // already blinking in the right location. |
1564 if (shouldBlink && !m_caretBlinkTimer.isActive()) { | 1563 if (shouldBlink && !m_caretBlinkTimer.isActive()) { |
1565 if (double blinkInterval = RenderTheme::theme().caretBlinkInterval()) | 1564 if (double blinkInterval = RenderTheme::theme().caretBlinkInterval()) |
1566 m_caretBlinkTimer.startRepeating(blinkInterval, FROM_HERE); | 1565 m_caretBlinkTimer.startRepeating(blinkInterval, FROM_HERE); |
1567 | 1566 |
1568 if (!m_caretPaint) { | 1567 if (!m_caretPaint) { |
1569 m_caretPaint = true; | 1568 m_caretPaint = true; |
1570 invalidateCaretRect(); | 1569 setCaretRectNeedsUpdate(); |
1571 } | 1570 } |
1572 } | 1571 } |
1573 | 1572 |
| 1573 if (shouldUpdateCaretRect() && m_frame->page()) |
| 1574 m_frame->page()->animator().scheduleVisualUpdate(); |
| 1575 |
1574 RenderView* view = m_frame->contentRenderer(); | 1576 RenderView* view = m_frame->contentRenderer(); |
1575 if (!view) | 1577 if (!view) |
1576 return; | 1578 return; |
1577 | 1579 |
1578 // Construct a new VisibleSolution, since m_selection is not necessarily val
id, and the following steps | 1580 // Construct a new VisibleSolution, since m_selection is not necessarily val
id, and the following steps |
1579 // assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69
563> and <rdar://problem/10232866>. | 1581 // assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69
563> and <rdar://problem/10232866>. |
1580 VisiblePosition endVisiblePosition = paintBlockCursor ? modifyExtendingForwa
rd(CharacterGranularity) : m_selection.visibleEnd(); | 1582 |
1581 VisibleSelection selection(m_selection.visibleStart(), endVisiblePosition); | 1583 VisibleSelection selection; |
| 1584 if (isTextFormControl(m_selection)) { |
| 1585 Position endPosition = paintBlockCursor ? m_selection.extent().next() :
m_selection.end(); |
| 1586 selection.setWithoutValidation(m_selection.start(), endPosition); |
| 1587 } else { |
| 1588 VisiblePosition endVisiblePosition = paintBlockCursor ? modifyExtendingF
orward(CharacterGranularity) : m_selection.visibleEnd(); |
| 1589 selection = VisibleSelection(m_selection.visibleStart(), endVisiblePosit
ion); |
| 1590 } |
1582 | 1591 |
1583 if (!selection.isRange()) { | 1592 if (!selection.isRange()) { |
1584 view->clearSelection(); | 1593 view->clearSelection(); |
1585 return; | 1594 return; |
1586 } | 1595 } |
1587 | 1596 |
1588 // Use the rightmost candidate for the start of the selection, and the leftm
ost candidate for the end of the selection. | 1597 // Use the rightmost candidate for the start of the selection, and the leftm
ost candidate for the end of the selection. |
1589 // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', an
d that 'bar' is selected. If we pass [foo, 3] | 1598 // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', an
d that 'bar' is selected. If we pass [foo, 3] |
1590 // as the start of the selection, the selection painting code will think tha
t content on the line containing 'foo' is selected | 1599 // as the start of the selection, the selection painting code will think tha
t content on the line containing 'foo' is selected |
1591 // and will fill the gap before 'bar'. | 1600 // and will fill the gap before 'bar'. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1642 return focusedElement->containsIncludingShadowDOM(m_selection.start().anchor
Node()); | 1651 return focusedElement->containsIncludingShadowDOM(m_selection.start().anchor
Node()); |
1643 } | 1652 } |
1644 | 1653 |
1645 void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*) | 1654 void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*) |
1646 { | 1655 { |
1647 ASSERT(caretIsVisible()); | 1656 ASSERT(caretIsVisible()); |
1648 ASSERT(isCaret()); | 1657 ASSERT(isCaret()); |
1649 if (isCaretBlinkingSuspended() && m_caretPaint) | 1658 if (isCaretBlinkingSuspended() && m_caretPaint) |
1650 return; | 1659 return; |
1651 m_caretPaint = !m_caretPaint; | 1660 m_caretPaint = !m_caretPaint; |
1652 invalidateCaretRect(); | 1661 setCaretRectNeedsUpdate(); |
| 1662 if (Page* page = m_frame->page()) |
| 1663 page->animator().scheduleVisualUpdate(); |
1653 } | 1664 } |
1654 | 1665 |
1655 void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggere
d) | 1666 void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggere
d) |
1656 { | 1667 { |
1657 m_frame->document()->updateRenderTreeIfNeeded(); | |
1658 | |
1659 if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start
())) | 1668 if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start
())) |
1660 textControl->selectionChanged(userTriggered == UserTriggered); | 1669 textControl->selectionChanged(userTriggered == UserTriggered); |
1661 } | 1670 } |
1662 | 1671 |
1663 // Helper function that tells whether a particular node is an element that has a
n entire | 1672 // Helper function that tells whether a particular node is an element that has a
n entire |
1664 // LocalFrame and FrameView, a <frame>, <iframe>, or <object>. | 1673 // LocalFrame and FrameView, a <frame>, <iframe>, or <object>. |
1665 static bool isFrameElement(const Node* n) | 1674 static bool isFrameElement(const Node* n) |
1666 { | 1675 { |
1667 if (!n) | 1676 if (!n) |
1668 return false; | 1677 return false; |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1924 sel.showTreeForThis(); | 1933 sel.showTreeForThis(); |
1925 } | 1934 } |
1926 | 1935 |
1927 void showTree(const blink::FrameSelection* sel) | 1936 void showTree(const blink::FrameSelection* sel) |
1928 { | 1937 { |
1929 if (sel) | 1938 if (sel) |
1930 sel->showTreeForThis(); | 1939 sel->showTreeForThis(); |
1931 } | 1940 } |
1932 | 1941 |
1933 #endif | 1942 #endif |
OLD | NEW |