OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 #include "core/editing/SplitElementCommand.h" | 56 #include "core/editing/SplitElementCommand.h" |
57 #include "core/editing/SplitTextNodeCommand.h" | 57 #include "core/editing/SplitTextNodeCommand.h" |
58 #include "core/editing/SplitTextNodeContainingElementCommand.h" | 58 #include "core/editing/SplitTextNodeContainingElementCommand.h" |
59 #include "core/editing/TextIterator.h" | 59 #include "core/editing/TextIterator.h" |
60 #include "core/editing/VisibleUnits.h" | 60 #include "core/editing/VisibleUnits.h" |
61 #include "core/editing/WrapContentsInDummySpanCommand.h" | 61 #include "core/editing/WrapContentsInDummySpanCommand.h" |
62 #include "core/editing/htmlediting.h" | 62 #include "core/editing/htmlediting.h" |
63 #include "core/editing/markup.h" | 63 #include "core/editing/markup.h" |
64 #include "core/events/ScopedEventQueue.h" | 64 #include "core/events/ScopedEventQueue.h" |
65 #include "core/frame/LocalFrame.h" | 65 #include "core/frame/LocalFrame.h" |
| 66 #include "core/html/HTMLBRElement.h" |
66 #include "core/html/HTMLElement.h" | 67 #include "core/html/HTMLElement.h" |
67 #include "core/html/HTMLSpanElement.h" | 68 #include "core/html/HTMLSpanElement.h" |
68 #include "core/rendering/InlineTextBox.h" | 69 #include "core/rendering/InlineTextBox.h" |
69 #include "core/rendering/RenderBlock.h" | 70 #include "core/rendering/RenderBlock.h" |
70 #include "core/rendering/RenderListItem.h" | 71 #include "core/rendering/RenderListItem.h" |
71 #include "core/rendering/RenderText.h" | 72 #include "core/rendering/RenderText.h" |
72 | 73 |
73 namespace blink { | 74 namespace blink { |
74 | 75 |
75 using namespace HTMLNames; | 76 using namespace HTMLNames; |
(...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 deleteInsignificantText(textNode, startOffset, endOffset); | 821 deleteInsignificantText(textNode, startOffset, endOffset); |
821 } | 822 } |
822 } | 823 } |
823 | 824 |
824 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos
) | 825 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos
) |
825 { | 826 { |
826 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); | 827 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); |
827 deleteInsignificantText(pos, end); | 828 deleteInsignificantText(pos, end); |
828 } | 829 } |
829 | 830 |
830 PassRefPtrWillBeRawPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRe
fPtrWillBeRawPtr<Element> container) | 831 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::appendBlockPlacehold
er(PassRefPtrWillBeRawPtr<Element> container) |
831 { | 832 { |
832 if (!container) | 833 if (!container) |
833 return nullptr; | 834 return nullptr; |
834 | 835 |
835 document().updateLayoutIgnorePendingStylesheets(); | 836 document().updateLayoutIgnorePendingStylesheets(); |
836 | 837 |
837 // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. | 838 // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. |
838 ASSERT(container->renderer()); | 839 ASSERT(container->renderer()); |
839 | 840 |
840 RefPtrWillBeRawPtr<Node> placeholder = createBlockPlaceholderElement(documen
t()); | 841 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBlockPlaceholderElemen
t(document()); |
841 appendNode(placeholder, container); | 842 appendNode(placeholder, container); |
842 return placeholder.release(); | 843 return placeholder.release(); |
843 } | 844 } |
844 | 845 |
845 PassRefPtrWillBeRawPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const
Position& pos) | 846 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::insertBlockPlacehold
er(const Position& pos) |
846 { | 847 { |
847 if (pos.isNull()) | 848 if (pos.isNull()) |
848 return nullptr; | 849 return nullptr; |
849 | 850 |
850 // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. | 851 // Should assert isRenderBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. |
851 ASSERT(pos.deprecatedNode()->renderer()); | 852 ASSERT(pos.deprecatedNode()->renderer()); |
852 | 853 |
853 RefPtrWillBeRawPtr<Node> placeholder = createBlockPlaceholderElement(documen
t()); | 854 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBlockPlaceholderElemen
t(document()); |
854 insertNodeAt(placeholder, pos); | 855 insertNodeAt(placeholder, pos); |
855 return placeholder.release(); | 856 return placeholder.release(); |
856 } | 857 } |
857 | 858 |
858 PassRefPtrWillBeRawPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(E
lement* container) | 859 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::addBlockPlaceholderI
fNeeded(Element* container) |
859 { | 860 { |
860 if (!container) | 861 if (!container) |
861 return nullptr; | 862 return nullptr; |
862 | 863 |
863 document().updateLayoutIgnorePendingStylesheets(); | 864 document().updateLayoutIgnorePendingStylesheets(); |
864 | 865 |
865 RenderObject* renderer = container->renderer(); | 866 RenderObject* renderer = container->renderer(); |
866 if (!renderer || !renderer->isRenderBlockFlow()) | 867 if (!renderer || !renderer->isRenderBlockFlow()) |
867 return nullptr; | 868 return nullptr; |
868 | 869 |
869 // append the placeholder to make sure it follows | 870 // append the placeholder to make sure it follows |
870 // any unrendered blocks | 871 // any unrendered blocks |
871 RenderBlock* block = toRenderBlock(renderer); | 872 RenderBlockFlow* block = toRenderBlockFlow(renderer); |
872 if (block->height() == 0 || (block->isListItem() && toRenderListItem(block)-
>isEmpty())) | 873 if (block->height() == 0 || (block->isListItem() && toRenderListItem(block)-
>isEmpty())) |
873 return appendBlockPlaceholder(container); | 874 return appendBlockPlaceholder(container); |
874 | 875 |
875 return nullptr; | 876 return nullptr; |
876 } | 877 } |
877 | 878 |
878 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. | 879 // Assumes that the position is at a placeholder and does the removal without mu
ch checking. |
879 void CompositeEditCommand::removePlaceholderAt(const Position& p) | 880 void CompositeEditCommand::removePlaceholderAt(const Position& p) |
880 { | 881 { |
881 ASSERT(lineBreakExistsAtPosition(p)); | 882 ASSERT(lineBreakExistsAtPosition(p)); |
882 | 883 |
883 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. | 884 // We are certain that the position is at a line break, but it may be a br o
r a preserved newline. |
884 if (isHTMLBRElement(*p.anchorNode())) { | 885 if (isHTMLBRElement(*p.anchorNode())) { |
885 removeNode(p.anchorNode()); | 886 removeNode(p.anchorNode()); |
886 return; | 887 return; |
887 } | 888 } |
888 | 889 |
889 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); | 890 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); |
890 } | 891 } |
891 | 892 |
892 PassRefPtrWillBeRawPtr<Element> CompositeEditCommand::insertNewDefaultParagraphE
lementAt(const Position& position) | 893 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::insertNewDefaultParagr
aphElementAt(const Position& position) |
893 { | 894 { |
894 RefPtrWillBeRawPtr<Element> paragraphElement = createDefaultParagraphElement
(document()); | 895 RefPtrWillBeRawPtr<HTMLElement> paragraphElement = createDefaultParagraphEle
ment(document()); |
895 paragraphElement->appendChild(createBreakElement(document())); | 896 paragraphElement->appendChild(createBreakElement(document())); |
896 insertNodeAt(paragraphElement, position); | 897 insertNodeAt(paragraphElement, position); |
897 return paragraphElement.release(); | 898 return paragraphElement.release(); |
898 } | 899 } |
899 | 900 |
900 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into | 901 // If the paragraph is not entirely within it's own block, create one and move t
he paragraph into |
901 // it, and return that block. Otherwise return 0. | 902 // it, and return that block. Otherwise return 0. |
902 PassRefPtrWillBeRawPtr<Element> CompositeEditCommand::moveParagraphContentsToNew
BlockIfNecessary(const Position& pos) | 903 PassRefPtrWillBeRawPtr<HTMLElement> CompositeEditCommand::moveParagraphContentsT
oNewBlockIfNecessary(const Position& pos) |
903 { | 904 { |
904 ASSERT(isEditablePosition(pos, ContentIsEditable, DoNotUpdateStyle)); | 905 ASSERT(isEditablePosition(pos, ContentIsEditable, DoNotUpdateStyle)); |
905 | 906 |
906 // It's strange that this function is responsible for verifying that pos has
not been invalidated | 907 // It's strange that this function is responsible for verifying that pos has
not been invalidated |
907 // by an earlier call to this function. The caller, applyBlockStyle, should
do this. | 908 // by an earlier call to this function. The caller, applyBlockStyle, should
do this. |
908 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); | 909 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); |
909 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); | 910 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); |
910 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); | 911 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); |
911 VisiblePosition next = visibleParagraphEnd.next(); | 912 VisiblePosition next = visibleParagraphEnd.next(); |
912 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; | 913 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; |
(...skipping 27 matching lines...) Expand all Loading... |
940 return nullptr; | 941 return nullptr; |
941 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { | 942 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { |
942 // At the end of the editable region. We can bail here as well. | 943 // At the end of the editable region. We can bail here as well. |
943 return nullptr; | 944 return nullptr; |
944 } | 945 } |
945 } | 946 } |
946 | 947 |
947 if (visibleParagraphEnd.isNull()) | 948 if (visibleParagraphEnd.isNull()) |
948 return nullptr; | 949 return nullptr; |
949 | 950 |
950 RefPtrWillBeRawPtr<Element> newBlock = insertNewDefaultParagraphElementAt(up
streamStart); | 951 RefPtrWillBeRawPtr<HTMLElement> newBlock = insertNewDefaultParagraphElementA
t(upstreamStart); |
951 | 952 |
952 bool endWasBr = isHTMLBRElement(*visibleParagraphEnd.deepEquivalent().deprec
atedNode()); | 953 bool endWasBr = isHTMLBRElement(*visibleParagraphEnd.deepEquivalent().deprec
atedNode()); |
953 | 954 |
954 // Inserting default paragraph element can change visible position. We | 955 // Inserting default paragraph element can change visible position. We |
955 // should update visible positions before use them. | 956 // should update visible positions before use them. |
956 visiblePos = VisiblePosition(pos, VP_DEFAULT_AFFINITY); | 957 visiblePos = VisiblePosition(pos, VP_DEFAULT_AFFINITY); |
957 visibleParagraphStart = VisiblePosition(startOfParagraph(visiblePos)); | 958 visibleParagraphStart = VisiblePosition(startOfParagraph(visiblePos)); |
958 visibleParagraphEnd = VisiblePosition(endOfParagraph(visiblePos)); | 959 visibleParagraphEnd = VisiblePosition(endOfParagraph(visiblePos)); |
959 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); | 960 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); |
960 | 961 |
961 if (newBlock->lastChild() && isHTMLBRElement(*newBlock->lastChild()) && !end
WasBr) | 962 if (newBlock->lastChild() && isHTMLBRElement(*newBlock->lastChild()) && !end
WasBr) |
962 removeNode(newBlock->lastChild()); | 963 removeNode(newBlock->lastChild()); |
963 | 964 |
964 return newBlock.release(); | 965 return newBlock.release(); |
965 } | 966 } |
966 | 967 |
967 void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode) | 968 void CompositeEditCommand::pushAnchorElementDown(Element* anchorNode) |
968 { | 969 { |
969 if (!anchorNode) | 970 if (!anchorNode) |
970 return; | 971 return; |
971 | 972 |
972 ASSERT(anchorNode->isLink()); | 973 ASSERT(anchorNode->isLink()); |
973 | 974 |
974 setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode)
); | 975 setEndingSelection(VisibleSelection::selectionFromContentsOfNode(anchorNode)
); |
975 applyStyledElement(toElement(anchorNode)); | 976 applyStyledElement(anchorNode); |
976 // Clones of anchorNode have been pushed down, now remove it. | 977 // Clones of anchorNode have been pushed down, now remove it. |
977 if (anchorNode->inDocument()) | 978 if (anchorNode->inDocument()) |
978 removeNodePreservingChildren(anchorNode); | 979 removeNodePreservingChildren(anchorNode); |
979 } | 980 } |
980 | 981 |
981 // Clone the paragraph between start and end under blockElement, | 982 // Clone the paragraph between start and end under blockElement, |
982 // preserving the hierarchy up to outerNode. | 983 // preserving the hierarchy up to outerNode. |
983 | 984 |
984 void CompositeEditCommand::cloneParagraphUnderNewElement(const Position& start,
const Position& end, Node* passedOuterNode, Element* blockElement) | 985 void CompositeEditCommand::cloneParagraphUnderNewElement(const Position& start,
const Position& end, Node* passedOuterNode, Element* blockElement) |
985 { | 986 { |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1362 return false; | 1363 return false; |
1363 | 1364 |
1364 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) | 1365 if (!isStartOfParagraph(caret) || !isEndOfParagraph(caret)) |
1365 return false; | 1366 return false; |
1366 | 1367 |
1367 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); | 1368 VisiblePosition previous(caret.previous(CannotCrossEditingBoundary)); |
1368 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. | 1369 // Only move forward if there's nothing before the caret, or if there's unqu
oted content before it. |
1369 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) | 1370 if (enclosingNodeOfType(previous.deepEquivalent(), &isMailBlockquote)) |
1370 return false; | 1371 return false; |
1371 | 1372 |
1372 RefPtrWillBeRawPtr<Node> br = createBreakElement(document()); | 1373 RefPtrWillBeRawPtr<HTMLBRElement> br = createBreakElement(document()); |
1373 // We want to replace this quoted paragraph with an unquoted one, so insert
a br | 1374 // We want to replace this quoted paragraph with an unquoted one, so insert
a br |
1374 // to hold the caret before the highest blockquote. | 1375 // to hold the caret before the highest blockquote. |
1375 insertNodeBefore(br, highestBlockquote); | 1376 insertNodeBefore(br, highestBlockquote); |
1376 VisiblePosition atBR(positionBeforeNode(br.get())); | 1377 VisiblePosition atBR(positionBeforeNode(br.get())); |
1377 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert | 1378 // If the br we inserted collapsed, for example foo<br><blockquote>...</bloc
kquote>, insert |
1378 // a second one. | 1379 // a second one. |
1379 if (!isStartOfParagraph(atBR)) | 1380 if (!isStartOfParagraph(atBR)) |
1380 insertNodeBefore(createBreakElement(document()), br); | 1381 insertNodeBefore(createBreakElement(document()), br); |
1381 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1382 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
1382 | 1383 |
(...skipping 23 matching lines...) Expand all Loading... |
1406 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of | 1407 // Operations use this function to avoid inserting content into an anchor when a
t the start or the end of |
1407 // that anchor, as in NSTextView. | 1408 // that anchor, as in NSTextView. |
1408 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how | 1409 // FIXME: This is only an approximation of NSTextViews insertion behavior, which
varies depending on how |
1409 // the caret was made. | 1410 // the caret was made. |
1410 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original) | 1411 Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Posi
tion& original) |
1411 { | 1412 { |
1412 if (original.isNull()) | 1413 if (original.isNull()) |
1413 return original; | 1414 return original; |
1414 | 1415 |
1415 VisiblePosition visiblePos(original); | 1416 VisiblePosition visiblePos(original); |
1416 Node* enclosingAnchor = enclosingAnchorElement(original); | 1417 Element* enclosingAnchor = enclosingAnchorElement(original); |
1417 Position result = original; | 1418 Position result = original; |
1418 | 1419 |
1419 if (!enclosingAnchor) | 1420 if (!enclosingAnchor) |
1420 return result; | 1421 return result; |
1421 | 1422 |
1422 // Don't avoid block level anchors, because that would insert content into t
he wrong paragraph. | 1423 // Don't avoid block level anchors, because that would insert content into t
he wrong paragraph. |
1423 if (enclosingAnchor && !isBlock(enclosingAnchor)) { | 1424 if (enclosingAnchor && !isBlock(enclosingAnchor)) { |
1424 VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor)); | 1425 VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor)); |
1425 VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor)); | 1426 VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor)); |
1426 // If visually just after the anchor, insert *inside* the anchor unless
it's the last | 1427 // If visually just after the anchor, insert *inside* the anchor unless
it's the last |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1473 ASSERT(start != end); | 1474 ASSERT(start != end); |
1474 | 1475 |
1475 if (shouldSplitAncestor && end->parentNode()) | 1476 if (shouldSplitAncestor && end->parentNode()) |
1476 end = end->parentNode(); | 1477 end = end->parentNode(); |
1477 if (!start->isDescendantOf(end)) | 1478 if (!start->isDescendantOf(end)) |
1478 return end; | 1479 return end; |
1479 | 1480 |
1480 RefPtrWillBeRawPtr<Node> endNode = end; | 1481 RefPtrWillBeRawPtr<Node> endNode = end; |
1481 RefPtrWillBeRawPtr<Node> node = nullptr; | 1482 RefPtrWillBeRawPtr<Node> node = nullptr; |
1482 for (node = start; node->parentNode() != endNode; node = node->parentNode())
{ | 1483 for (node = start; node->parentNode() != endNode; node = node->parentNode())
{ |
1483 if (!node->parentNode()->isElementNode()) | 1484 Element* parentElement = node->parentElement(); |
| 1485 if (!parentElement) |
1484 break; | 1486 break; |
1485 // Do not split a node when doing so introduces an empty node. | 1487 // Do not split a node when doing so introduces an empty node. |
1486 VisiblePosition positionInParent(firstPositionInNode(node->parentNode())
); | 1488 VisiblePosition positionInParent(firstPositionInNode(parentElement)); |
1487 VisiblePosition positionInNode(firstPositionInOrBeforeNode(node.get())); | 1489 VisiblePosition positionInNode(firstPositionInOrBeforeNode(node.get())); |
1488 if (positionInParent != positionInNode) | 1490 if (positionInParent != positionInNode) |
1489 splitElement(toElement(node->parentNode()), node); | 1491 splitElement(parentElement, node); |
1490 } | 1492 } |
1491 | 1493 |
1492 return node.release(); | 1494 return node.release(); |
1493 } | 1495 } |
1494 | 1496 |
1495 PassRefPtrWillBeRawPtr<Element> createBlockPlaceholderElement(Document& document
) | |
1496 { | |
1497 return document.createElement(brTag, false); | |
1498 } | |
1499 | |
1500 void CompositeEditCommand::trace(Visitor* visitor) | 1497 void CompositeEditCommand::trace(Visitor* visitor) |
1501 { | 1498 { |
1502 visitor->trace(m_commands); | 1499 visitor->trace(m_commands); |
1503 visitor->trace(m_composition); | 1500 visitor->trace(m_composition); |
1504 EditCommand::trace(visitor); | 1501 EditCommand::trace(visitor); |
1505 } | 1502 } |
1506 | 1503 |
1507 } // namespace blink | 1504 } // namespace blink |
OLD | NEW |