| 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 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 insertNodeBefore(insertChild, refChild->nextSibling()); | 327 insertNodeBefore(insertChild, refChild->nextSibling()); |
| 328 } | 328 } |
| 329 } | 329 } |
| 330 | 330 |
| 331 void CompositeEditCommand::insertNodeAt(PassRefPtrWillBeRawPtr<Node> insertChild
, const Position& editingPosition) | 331 void CompositeEditCommand::insertNodeAt(PassRefPtrWillBeRawPtr<Node> insertChild
, const Position& editingPosition) |
| 332 { | 332 { |
| 333 ASSERT(isEditablePosition(editingPosition, ContentIsEditable, DoNotUpdateSty
le)); | 333 ASSERT(isEditablePosition(editingPosition, ContentIsEditable, DoNotUpdateSty
le)); |
| 334 // For editing positions like [table, 0], insert before the table, | 334 // For editing positions like [table, 0], insert before the table, |
| 335 // likewise for replaced elements, brs, etc. | 335 // likewise for replaced elements, brs, etc. |
| 336 Position p = editingPosition.parentAnchoredEquivalent(); | 336 Position p = editingPosition.parentAnchoredEquivalent(); |
| 337 Node* refChild = p.deprecatedNode(); | 337 Node* refChild = p.anchorNode(); |
| 338 int offset = p.deprecatedEditingOffset(); | 338 int offset = p.deprecatedEditingOffset(); |
| 339 | 339 |
| 340 if (canHaveChildrenForEditing(refChild)) { | 340 if (canHaveChildrenForEditing(refChild)) { |
| 341 Node* child = refChild->firstChild(); | 341 Node* child = refChild->firstChild(); |
| 342 for (int i = 0; child && i < offset; i++) | 342 for (int i = 0; child && i < offset; i++) |
| 343 child = child->nextSibling(); | 343 child = child->nextSibling(); |
| 344 if (child) | 344 if (child) |
| 345 insertNodeBefore(insertChild, child); | 345 insertNodeBefore(insertChild, child); |
| 346 else | 346 else |
| 347 appendNode(insertChild, toContainerNode(refChild)); | 347 appendNode(insertChild, toContainerNode(refChild)); |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 // this function doesn't get all surrounding whitespace, just the whitespace
in the current text node. | 677 // this function doesn't get all surrounding whitespace, just the whitespace
in the current text node. |
| 678 isStartOfParagraph(
visibleUpstreamPos) || upstream == 0, | 678 isStartOfParagraph(
visibleUpstreamPos) || upstream == 0, |
| 679 isEndOfParagraph(vi
sibleDownstreamPos) || (unsigned)downstream == text.length()); | 679 isEndOfParagraph(vi
sibleDownstreamPos) || (unsigned)downstream == text.length()); |
| 680 | 680 |
| 681 if (string != rebalancedString) | 681 if (string != rebalancedString) |
| 682 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length,
rebalancedString); | 682 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length,
rebalancedString); |
| 683 } | 683 } |
| 684 | 684 |
| 685 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio
n) | 685 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio
n) |
| 686 { | 686 { |
| 687 Node* node = position.deprecatedNode(); | 687 Node* node = position.anchorNode(); |
| 688 if (!node || !node->isTextNode()) | 688 if (!node || !node->isTextNode()) |
| 689 return; | 689 return; |
| 690 Text* textNode = toText(node); | 690 Text* textNode = toText(node); |
| 691 | 691 |
| 692 if (textNode->length() == 0) | 692 if (textNode->length() == 0) |
| 693 return; | 693 return; |
| 694 LayoutText* layoutText = textNode->layoutObject(); | 694 LayoutText* layoutText = textNode->layoutObject(); |
| 695 if (layoutText && !layoutText->style()->collapseWhiteSpace()) | 695 if (layoutText && !layoutText->style()->collapseWhiteSpace()) |
| 696 return; | 696 return; |
| 697 | 697 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 | 809 |
| 810 void CompositeEditCommand::deleteInsignificantText(const Position& start, const
Position& end) | 810 void CompositeEditCommand::deleteInsignificantText(const Position& start, const
Position& end) |
| 811 { | 811 { |
| 812 if (start.isNull() || end.isNull()) | 812 if (start.isNull() || end.isNull()) |
| 813 return; | 813 return; |
| 814 | 814 |
| 815 if (comparePositions(start, end) >= 0) | 815 if (comparePositions(start, end) >= 0) |
| 816 return; | 816 return; |
| 817 | 817 |
| 818 WillBeHeapVector<RefPtrWillBeMember<Text>> nodes; | 818 WillBeHeapVector<RefPtrWillBeMember<Text>> nodes; |
| 819 for (Node& node : NodeTraversal::startsAt(start.deprecatedNode())) { | 819 for (Node& node : NodeTraversal::startsAt(start.anchorNode())) { |
| 820 if (node.isTextNode()) | 820 if (node.isTextNode()) |
| 821 nodes.append(toText(&node)); | 821 nodes.append(toText(&node)); |
| 822 if (&node == end.deprecatedNode()) | 822 if (&node == end.anchorNode()) |
| 823 break; | 823 break; |
| 824 } | 824 } |
| 825 | 825 |
| 826 for (const auto& node : nodes) { | 826 for (const auto& node : nodes) { |
| 827 Text* textNode = node.get(); | 827 Text* textNode = node.get(); |
| 828 int startOffset = textNode == start.deprecatedNode() ? start.deprecatedE
ditingOffset() : 0; | 828 int startOffset = textNode == start.anchorNode() ? start.deprecatedEditi
ngOffset() : 0; |
| 829 int endOffset = textNode == end.deprecatedNode() ? end.deprecatedEditing
Offset() : static_cast<int>(textNode->length()); | 829 int endOffset = textNode == end.anchorNode() ? end.deprecatedEditingOffs
et() : static_cast<int>(textNode->length()); |
| 830 deleteInsignificantText(textNode, startOffset, endOffset); | 830 deleteInsignificantText(textNode, startOffset, endOffset); |
| 831 } | 831 } |
| 832 } | 832 } |
| 833 | 833 |
| 834 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos
) | 834 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos
) |
| 835 { | 835 { |
| 836 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); | 836 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale
nt().downstream(); |
| 837 deleteInsignificantText(pos, end); | 837 deleteInsignificantText(pos, end); |
| 838 } | 838 } |
| 839 | 839 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 851 appendNode(placeholder, container); | 851 appendNode(placeholder, container); |
| 852 return placeholder.release(); | 852 return placeholder.release(); |
| 853 } | 853 } |
| 854 | 854 |
| 855 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::insertBlockPlacehold
er(const Position& pos) | 855 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::insertBlockPlacehold
er(const Position& pos) |
| 856 { | 856 { |
| 857 if (pos.isNull()) | 857 if (pos.isNull()) |
| 858 return nullptr; | 858 return nullptr; |
| 859 | 859 |
| 860 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. | 860 // Should assert isLayoutBlockFlow || isInlineFlow when deletion improves. S
ee 4244964. |
| 861 ASSERT(pos.deprecatedNode()->layoutObject()); | 861 ASSERT(pos.anchorNode()->layoutObject()); |
| 862 | 862 |
| 863 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBlockPlaceholderElemen
t(document()); | 863 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBlockPlaceholderElemen
t(document()); |
| 864 insertNodeAt(placeholder, pos); | 864 insertNodeAt(placeholder, pos); |
| 865 return placeholder.release(); | 865 return placeholder.release(); |
| 866 } | 866 } |
| 867 | 867 |
| 868 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::addBlockPlaceholderI
fNeeded(Element* container) | 868 PassRefPtrWillBeRawPtr<HTMLBRElement> CompositeEditCommand::addBlockPlaceholderI
fNeeded(Element* container) |
| 869 { | 869 { |
| 870 if (!container) | 870 if (!container) |
| 871 return nullptr; | 871 return nullptr; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 | 923 |
| 924 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); | 924 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); |
| 925 Position upstreamEnd = visibleEnd.deepEquivalent().upstream(); | 925 Position upstreamEnd = visibleEnd.deepEquivalent().upstream(); |
| 926 | 926 |
| 927 // If there are no VisiblePositions in the same block as pos then | 927 // If there are no VisiblePositions in the same block as pos then |
| 928 // upstreamStart will be outside the paragraph | 928 // upstreamStart will be outside the paragraph |
| 929 if (comparePositions(pos, upstreamStart) < 0) | 929 if (comparePositions(pos, upstreamStart) < 0) |
| 930 return nullptr; | 930 return nullptr; |
| 931 | 931 |
| 932 // Perform some checks to see if we need to perform work in this function. | 932 // Perform some checks to see if we need to perform work in this function. |
| 933 if (isBlock(upstreamStart.deprecatedNode())) { | 933 if (isBlock(upstreamStart.anchorNode())) { |
| 934 // If the block is the root editable element, always move content to a n
ew block, | 934 // If the block is the root editable element, always move content to a n
ew block, |
| 935 // since it is illegal to modify attributes on the root editable element
for editing. | 935 // since it is illegal to modify attributes on the root editable element
for editing. |
| 936 if (upstreamStart.deprecatedNode() == editableRootForPosition(upstreamSt
art)) { | 936 if (upstreamStart.anchorNode() == editableRootForPosition(upstreamStart)
) { |
| 937 // If the block is the root editable element and it contains no visi
ble content, create a new | 937 // If the block is the root editable element and it contains no visi
ble content, create a new |
| 938 // block but don't try and move content into it, since there's nothi
ng for moveParagraphs to move. | 938 // block but don't try and move content into it, since there's nothi
ng for moveParagraphs to move. |
| 939 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstream
Start.deprecatedNode()->layoutObject())) | 939 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(upstream
Start.anchorNode()->layoutObject())) |
| 940 return insertNewDefaultParagraphElementAt(upstreamStart); | 940 return insertNewDefaultParagraphElementAt(upstreamStart); |
| 941 } else if (isBlock(upstreamEnd.deprecatedNode())) { | 941 } else if (isBlock(upstreamEnd.anchorNode())) { |
| 942 if (!upstreamEnd.deprecatedNode()->isDescendantOf(upstreamStart.depr
ecatedNode())) { | 942 if (!upstreamEnd.anchorNode()->isDescendantOf(upstreamStart.anchorNo
de())) { |
| 943 // If the paragraph end is a descendant of paragraph start, then
we need to run | 943 // If the paragraph end is a descendant of paragraph start, then
we need to run |
| 944 // the rest of this function. If not, we can bail here. | 944 // the rest of this function. If not, we can bail here. |
| 945 return nullptr; | 945 return nullptr; |
| 946 } | 946 } |
| 947 } else if (enclosingBlock(upstreamEnd.deprecatedNode()) != upstreamStart
.deprecatedNode()) { | 947 } else if (enclosingBlock(upstreamEnd.anchorNode()) != upstreamStart.anc
horNode()) { |
| 948 // It should be an ancestor of the paragraph start. | 948 // It should be an ancestor of the paragraph start. |
| 949 // We can bail as we have a full block to work with. | 949 // We can bail as we have a full block to work with. |
| 950 return nullptr; | 950 return nullptr; |
| 951 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { | 951 } else if (isEndOfEditableOrNonEditableContent(visibleEnd)) { |
| 952 // At the end of the editable region. We can bail here as well. | 952 // At the end of the editable region. We can bail here as well. |
| 953 return nullptr; | 953 return nullptr; |
| 954 } | 954 } |
| 955 } | 955 } |
| 956 | 956 |
| 957 if (visibleParagraphEnd.isNull()) | 957 if (visibleParagraphEnd.isNull()) |
| 958 return nullptr; | 958 return nullptr; |
| 959 | 959 |
| 960 RefPtrWillBeRawPtr<HTMLElement> newBlock = insertNewDefaultParagraphElementA
t(upstreamStart); | 960 RefPtrWillBeRawPtr<HTMLElement> newBlock = insertNewDefaultParagraphElementA
t(upstreamStart); |
| 961 | 961 |
| 962 bool endWasBr = isHTMLBRElement(*visibleParagraphEnd.deepEquivalent().deprec
atedNode()); | 962 bool endWasBr = isHTMLBRElement(*visibleParagraphEnd.deepEquivalent().anchor
Node()); |
| 963 | 963 |
| 964 // Inserting default paragraph element can change visible position. We | 964 // Inserting default paragraph element can change visible position. We |
| 965 // should update visible positions before use them. | 965 // should update visible positions before use them. |
| 966 visiblePos = VisiblePosition(pos, VP_DEFAULT_AFFINITY); | 966 visiblePos = VisiblePosition(pos, VP_DEFAULT_AFFINITY); |
| 967 visibleParagraphStart = VisiblePosition(startOfParagraph(visiblePos)); | 967 visibleParagraphStart = VisiblePosition(startOfParagraph(visiblePos)); |
| 968 visibleParagraphEnd = VisiblePosition(endOfParagraph(visiblePos)); | 968 visibleParagraphEnd = VisiblePosition(endOfParagraph(visiblePos)); |
| 969 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); | 969 moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(f
irstPositionInNode(newBlock.get()))); |
| 970 | 970 |
| 971 if (newBlock->lastChild() && isHTMLBRElement(*newBlock->lastChild()) && !end
WasBr) | 971 if (newBlock->lastChild() && isHTMLBRElement(*newBlock->lastChild()) && !end
WasBr) |
| 972 removeNode(newBlock->lastChild()); | 972 removeNode(newBlock->lastChild()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 lastNode = blockElement; | 1005 lastNode = blockElement; |
| 1006 } else { | 1006 } else { |
| 1007 lastNode = outerNode->cloneNode(isRenderedHTMLTableElement(outerNode.get
())); | 1007 lastNode = outerNode->cloneNode(isRenderedHTMLTableElement(outerNode.get
())); |
| 1008 appendNode(lastNode, blockElement); | 1008 appendNode(lastNode, blockElement); |
| 1009 } | 1009 } |
| 1010 | 1010 |
| 1011 if (start.anchorNode() != outerNode && lastNode->isElementNode() && start.an
chorNode()->isDescendantOf(outerNode.get())) { | 1011 if (start.anchorNode() != outerNode && lastNode->isElementNode() && start.an
chorNode()->isDescendantOf(outerNode.get())) { |
| 1012 WillBeHeapVector<RefPtrWillBeMember<Node>> ancestors; | 1012 WillBeHeapVector<RefPtrWillBeMember<Node>> ancestors; |
| 1013 | 1013 |
| 1014 // Insert each node from innerNode to outerNode (excluded) in a list. | 1014 // Insert each node from innerNode to outerNode (excluded) in a list. |
| 1015 for (Node* n = start.deprecatedNode(); n && n != outerNode; n = n->paren
tNode()) | 1015 for (Node* n = start.anchorNode(); n && n != outerNode; n = n->parentNod
e()) |
| 1016 ancestors.append(n); | 1016 ancestors.append(n); |
| 1017 | 1017 |
| 1018 // Clone every node between start.deprecatedNode() and outerBlock. | 1018 // Clone every node between start.anchorNode() and outerBlock. |
| 1019 | 1019 |
| 1020 for (size_t i = ancestors.size(); i != 0; --i) { | 1020 for (size_t i = ancestors.size(); i != 0; --i) { |
| 1021 Node* item = ancestors[i - 1].get(); | 1021 Node* item = ancestors[i - 1].get(); |
| 1022 RefPtrWillBeRawPtr<Node> child = item->cloneNode(isRenderedHTMLTable
Element(item)); | 1022 RefPtrWillBeRawPtr<Node> child = item->cloneNode(isRenderedHTMLTable
Element(item)); |
| 1023 appendNode(child, toElement(lastNode)); | 1023 appendNode(child, toElement(lastNode)); |
| 1024 lastNode = child.release(); | 1024 lastNode = child.release(); |
| 1025 } | 1025 } |
| 1026 } | 1026 } |
| 1027 | 1027 |
| 1028 // Scripts specified in javascript protocol may remove |outerNode| | 1028 // Scripts specified in javascript protocol may remove |outerNode| |
| 1029 // during insertion, e.g. <iframe src="javascript:..."> | 1029 // during insertion, e.g. <iframe src="javascript:..."> |
| 1030 if (!outerNode->inDocument()) | 1030 if (!outerNode->inDocument()) |
| 1031 return; | 1031 return; |
| 1032 | 1032 |
| 1033 // Handle the case of paragraphs with more than one node, | 1033 // Handle the case of paragraphs with more than one node, |
| 1034 // cloning all the siblings until end.deprecatedNode() is reached. | 1034 // cloning all the siblings until end.anchorNode() is reached. |
| 1035 | 1035 |
| 1036 if (start.deprecatedNode() != end.deprecatedNode() && !start.deprecatedNode(
)->isDescendantOf(end.deprecatedNode())) { | 1036 if (start.anchorNode() != end.anchorNode() && !start.anchorNode()->isDescend
antOf(end.anchorNode())) { |
| 1037 // If end is not a descendant of outerNode we need to | 1037 // If end is not a descendant of outerNode we need to |
| 1038 // find the first common ancestor to increase the scope | 1038 // find the first common ancestor to increase the scope |
| 1039 // of our nextSibling traversal. | 1039 // of our nextSibling traversal. |
| 1040 while (outerNode && !end.deprecatedNode()->isDescendantOf(outerNode.get(
))) { | 1040 while (outerNode && !end.anchorNode()->isDescendantOf(outerNode.get()))
{ |
| 1041 outerNode = outerNode->parentNode(); | 1041 outerNode = outerNode->parentNode(); |
| 1042 } | 1042 } |
| 1043 | 1043 |
| 1044 if (!outerNode) | 1044 if (!outerNode) |
| 1045 return; | 1045 return; |
| 1046 | 1046 |
| 1047 RefPtrWillBeRawPtr<Node> startNode = start.deprecatedNode(); | 1047 RefPtrWillBeRawPtr<Node> startNode = start.anchorNode(); |
| 1048 for (RefPtrWillBeRawPtr<Node> node = NodeTraversal::nextSkippingChildren
(*startNode, outerNode.get()); node; node = NodeTraversal::nextSkippingChildren(
*node, outerNode.get())) { | 1048 for (RefPtrWillBeRawPtr<Node> node = NodeTraversal::nextSkippingChildren
(*startNode, outerNode.get()); node; node = NodeTraversal::nextSkippingChildren(
*node, outerNode.get())) { |
| 1049 // Move lastNode up in the tree as much as node was moved up in the | 1049 // Move lastNode up in the tree as much as node was moved up in the |
| 1050 // tree by NodeTraversal::nextSkippingChildren, so that the relative
depth between | 1050 // tree by NodeTraversal::nextSkippingChildren, so that the relative
depth between |
| 1051 // node and the original start node is maintained in the clone. | 1051 // node and the original start node is maintained in the clone. |
| 1052 while (startNode && lastNode && startNode->parentNode() != node->par
entNode()) { | 1052 while (startNode && lastNode && startNode->parentNode() != node->par
entNode()) { |
| 1053 startNode = startNode->parentNode(); | 1053 startNode = startNode->parentNode(); |
| 1054 lastNode = lastNode->parentNode(); | 1054 lastNode = lastNode->parentNode(); |
| 1055 } | 1055 } |
| 1056 | 1056 |
| 1057 if (!lastNode || !lastNode->parentNode()) | 1057 if (!lastNode || !lastNode->parentNode()) |
| 1058 return; | 1058 return; |
| 1059 | 1059 |
| 1060 RefPtrWillBeRawPtr<Node> clonedNode = node->cloneNode(true); | 1060 RefPtrWillBeRawPtr<Node> clonedNode = node->cloneNode(true); |
| 1061 insertNodeAfter(clonedNode, lastNode); | 1061 insertNodeAfter(clonedNode, lastNode); |
| 1062 lastNode = clonedNode.release(); | 1062 lastNode = clonedNode.release(); |
| 1063 if (node == end.deprecatedNode() || end.deprecatedNode()->isDescenda
ntOf(node.get())) | 1063 if (node == end.anchorNode() || end.anchorNode()->isDescendantOf(nod
e.get())) |
| 1064 break; | 1064 break; |
| 1065 } | 1065 } |
| 1066 } | 1066 } |
| 1067 } | 1067 } |
| 1068 | 1068 |
| 1069 | 1069 |
| 1070 // There are bugs in deletion when it removes a fully selected table/list. | 1070 // There are bugs in deletion when it removes a fully selected table/list. |
| 1071 // It expands and removes the entire table/list, but will let content | 1071 // It expands and removes the entire table/list, but will let content |
| 1072 // before and after the table/list collapse onto one line. | 1072 // before and after the table/list collapse onto one line. |
| 1073 // Deleting a paragraph will leave a placeholder. Remove it (and prune | 1073 // Deleting a paragraph will leave a placeholder. Remove it (and prune |
| 1074 // empty or unrendered parents). | 1074 // empty or unrendered parents). |
| 1075 | 1075 |
| 1076 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) | 1076 void CompositeEditCommand::cleanupAfterDeletion(VisiblePosition destination) |
| 1077 { | 1077 { |
| 1078 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); | 1078 VisiblePosition caretAfterDelete = endingSelection().visibleStart(); |
| 1079 Node* destinationNode = destination.deepEquivalent().anchorNode(); | 1079 Node* destinationNode = destination.deepEquivalent().anchorNode(); |
| 1080 if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete)
&& isEndOfParagraph(caretAfterDelete)) { | 1080 if (caretAfterDelete != destination && isStartOfParagraph(caretAfterDelete)
&& isEndOfParagraph(caretAfterDelete)) { |
| 1081 // Note: We want the rightmost candidate. | 1081 // Note: We want the rightmost candidate. |
| 1082 Position position = caretAfterDelete.deepEquivalent().downstream(); | 1082 Position position = caretAfterDelete.deepEquivalent().downstream(); |
| 1083 Node* node = position.deprecatedNode(); | 1083 Node* node = position.anchorNode(); |
| 1084 | 1084 |
| 1085 // Bail if we'd remove an ancestor of our destination. | 1085 // Bail if we'd remove an ancestor of our destination. |
| 1086 if (destinationNode && destinationNode->isDescendantOf(node)) | 1086 if (destinationNode && destinationNode->isDescendantOf(node)) |
| 1087 return; | 1087 return; |
| 1088 | 1088 |
| 1089 // Normally deletion will leave a br as a placeholder. | 1089 // Normally deletion will leave a br as a placeholder. |
| 1090 if (isHTMLBRElement(*node)) { | 1090 if (isHTMLBRElement(*node)) { |
| 1091 removeNodeAndPruneAncestors(node, destinationNode); | 1091 removeNodeAndPruneAncestors(node, destinationNode); |
| 1092 | 1092 |
| 1093 // If the selection to move was empty and in an empty block that | 1093 // If the selection to move was empty and in an empty block that |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 // Add a br if pruning an empty block level element caused a collapse. For
example: | 1150 // Add a br if pruning an empty block level element caused a collapse. For
example: |
| 1151 // foo^ | 1151 // foo^ |
| 1152 // <div>bar</div> | 1152 // <div>bar</div> |
| 1153 // baz | 1153 // baz |
| 1154 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would | 1154 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. Th
at would |
| 1155 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. | 1155 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br
. |
| 1156 // Must recononicalize these two VisiblePositions after the pruning above. | 1156 // Must recononicalize these two VisiblePositions after the pruning above. |
| 1157 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); | 1157 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); |
| 1158 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); | 1158 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); |
| 1159 | 1159 |
| 1160 if (beforeParagraph.isNotNull() && !isRenderedTableElement(beforeParagraph.d
eepEquivalent().deprecatedNode()) | 1160 if (beforeParagraph.isNotNull() && !isRenderedTableElement(beforeParagraph.d
eepEquivalent().anchorNode()) |
| 1161 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { | 1161 && ((!isEndOfParagraph(beforeParagraph) && !isStartOfParagraph(beforePar
agraph)) || beforeParagraph == afterParagraph)) { |
| 1162 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. | 1162 // FIXME: Trim text between beforeParagraph and afterParagraph if they a
ren't equal. |
| 1163 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); | 1163 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival
ent()); |
| 1164 } | 1164 } |
| 1165 } | 1165 } |
| 1166 | 1166 |
| 1167 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) | 1167 void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraph
ToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& dest
ination, bool preserveSelection, bool preserveStyle, Node* constrainingAncestor) |
| 1168 { | 1168 { |
| 1169 ASSERT(isStartOfParagraph(startOfParagraphToMove)); | 1169 ASSERT(isStartOfParagraph(startOfParagraphToMove)); |
| 1170 ASSERT(isEndOfParagraph(endOfParagraphToMove)); | 1170 ASSERT(isEndOfParagraph(endOfParagraphToMove)); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1383 if (!isStartOfParagraph(atBR)) | 1383 if (!isStartOfParagraph(atBR)) |
| 1384 insertNodeBefore(createBreakElement(document()), br); | 1384 insertNodeBefore(createBreakElement(document()), br); |
| 1385 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); | 1385 setEndingSelection(VisibleSelection(atBR, endingSelection().isDirectional())
); |
| 1386 | 1386 |
| 1387 // If this is an empty paragraph there must be a line break here. | 1387 // If this is an empty paragraph there must be a line break here. |
| 1388 if (!lineBreakExistsAtVisiblePosition(caret)) | 1388 if (!lineBreakExistsAtVisiblePosition(caret)) |
| 1389 return false; | 1389 return false; |
| 1390 | 1390 |
| 1391 Position caretPos(caret.deepEquivalent().downstream()); | 1391 Position caretPos(caret.deepEquivalent().downstream()); |
| 1392 // A line break is either a br or a preserved newline. | 1392 // A line break is either a br or a preserved newline. |
| 1393 ASSERT(isHTMLBRElement(caretPos.deprecatedNode()) || (caretPos.deprecatedNod
e()->isTextNode() && caretPos.deprecatedNode()->layoutObject()->style()->preserv
eNewline())); | 1393 ASSERT(isHTMLBRElement(caretPos.anchorNode()) || (caretPos.anchorNode()->isT
extNode() && caretPos.anchorNode()->layoutObject()->style()->preserveNewline()))
; |
| 1394 | 1394 |
| 1395 if (isHTMLBRElement(*caretPos.deprecatedNode())) | 1395 if (isHTMLBRElement(*caretPos.anchorNode())) { |
| 1396 removeNodeAndPruneAncestors(caretPos.deprecatedNode()); | 1396 removeNodeAndPruneAncestors(caretPos.anchorNode()); |
| 1397 else if (caretPos.deprecatedNode()->isTextNode()) { | 1397 } else if (caretPos.anchorNode()->isTextNode()) { |
| 1398 ASSERT(caretPos.deprecatedEditingOffset() == 0); | 1398 ASSERT(caretPos.deprecatedEditingOffset() == 0); |
| 1399 Text* textNode = toText(caretPos.deprecatedNode()); | 1399 Text* textNode = toText(caretPos.anchorNode()); |
| 1400 ContainerNode* parentNode = textNode->parentNode(); | 1400 ContainerNode* parentNode = textNode->parentNode(); |
| 1401 // The preserved newline must be the first thing in the node, since othe
rwise the previous | 1401 // The preserved newline must be the first thing in the node, since othe
rwise the previous |
| 1402 // paragraph would be quoted, and we verified that it wasn't above. | 1402 // paragraph would be quoted, and we verified that it wasn't above. |
| 1403 deleteTextFromNode(textNode, 0, 1); | 1403 deleteTextFromNode(textNode, 0, 1); |
| 1404 prune(parentNode); | 1404 prune(parentNode); |
| 1405 } | 1405 } |
| 1406 | 1406 |
| 1407 return true; | 1407 return true; |
| 1408 } | 1408 } |
| 1409 | 1409 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1425 | 1425 |
| 1426 // Don't avoid block level anchors, because that would insert content into t
he wrong paragraph. | 1426 // Don't avoid block level anchors, because that would insert content into t
he wrong paragraph. |
| 1427 if (enclosingAnchor && !isBlock(enclosingAnchor)) { | 1427 if (enclosingAnchor && !isBlock(enclosingAnchor)) { |
| 1428 VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor)); | 1428 VisiblePosition firstInAnchor(firstPositionInNode(enclosingAnchor)); |
| 1429 VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor)); | 1429 VisiblePosition lastInAnchor(lastPositionInNode(enclosingAnchor)); |
| 1430 // If visually just after the anchor, insert *inside* the anchor unless
it's the last | 1430 // If visually just after the anchor, insert *inside* the anchor unless
it's the last |
| 1431 // VisiblePosition in the document, to match NSTextView. | 1431 // VisiblePosition in the document, to match NSTextView. |
| 1432 if (visiblePos == lastInAnchor) { | 1432 if (visiblePos == lastInAnchor) { |
| 1433 // Make sure anchors are pushed down before avoiding them so that we
don't | 1433 // Make sure anchors are pushed down before avoiding them so that we
don't |
| 1434 // also avoid structural elements like lists and blocks (5142012). | 1434 // also avoid structural elements like lists and blocks (5142012). |
| 1435 if (original.deprecatedNode() != enclosingAnchor && original.depreca
tedNode()->parentNode() != enclosingAnchor) { | 1435 if (original.anchorNode() != enclosingAnchor && original.anchorNode(
)->parentNode() != enclosingAnchor) { |
| 1436 pushAnchorElementDown(enclosingAnchor); | 1436 pushAnchorElementDown(enclosingAnchor); |
| 1437 enclosingAnchor = enclosingAnchorElement(original); | 1437 enclosingAnchor = enclosingAnchorElement(original); |
| 1438 if (!enclosingAnchor) | 1438 if (!enclosingAnchor) |
| 1439 return original; | 1439 return original; |
| 1440 } | 1440 } |
| 1441 // Don't insert outside an anchor if doing so would skip over a line
break. It would | 1441 // Don't insert outside an anchor if doing so would skip over a line
break. It would |
| 1442 // probably be safe to move the line break so that we could still av
oid the anchor here. | 1442 // probably be safe to move the line break so that we could still av
oid the anchor here. |
| 1443 Position downstream(visiblePos.deepEquivalent().downstream()); | 1443 Position downstream(visiblePos.deepEquivalent().downstream()); |
| 1444 if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.depre
catedNode()->isDescendantOf(enclosingAnchor)) | 1444 if (lineBreakExistsAtVisiblePosition(visiblePos) && downstream.ancho
rNode()->isDescendantOf(enclosingAnchor)) |
| 1445 return original; | 1445 return original; |
| 1446 | 1446 |
| 1447 result = positionInParentAfterNode(*enclosingAnchor); | 1447 result = positionInParentAfterNode(*enclosingAnchor); |
| 1448 } | 1448 } |
| 1449 // If visually just before an anchor, insert *outside* the anchor unless
it's the first | 1449 // If visually just before an anchor, insert *outside* the anchor unless
it's the first |
| 1450 // VisiblePosition in a paragraph, to match NSTextView. | 1450 // VisiblePosition in a paragraph, to match NSTextView. |
| 1451 if (visiblePos == firstInAnchor) { | 1451 if (visiblePos == firstInAnchor) { |
| 1452 // Make sure anchors are pushed down before avoiding them so that we
don't | 1452 // Make sure anchors are pushed down before avoiding them so that we
don't |
| 1453 // also avoid structural elements like lists and blocks (5142012). | 1453 // also avoid structural elements like lists and blocks (5142012). |
| 1454 if (original.deprecatedNode() != enclosingAnchor && original.depreca
tedNode()->parentNode() != enclosingAnchor) { | 1454 if (original.anchorNode() != enclosingAnchor && original.anchorNode(
)->parentNode() != enclosingAnchor) { |
| 1455 pushAnchorElementDown(enclosingAnchor); | 1455 pushAnchorElementDown(enclosingAnchor); |
| 1456 enclosingAnchor = enclosingAnchorElement(original); | 1456 enclosingAnchor = enclosingAnchorElement(original); |
| 1457 } | 1457 } |
| 1458 if (!enclosingAnchor) | 1458 if (!enclosingAnchor) |
| 1459 return original; | 1459 return original; |
| 1460 | 1460 |
| 1461 result = positionInParentBeforeNode(*enclosingAnchor); | 1461 result = positionInParentBeforeNode(*enclosingAnchor); |
| 1462 } | 1462 } |
| 1463 } | 1463 } |
| 1464 | 1464 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1498 } | 1498 } |
| 1499 | 1499 |
| 1500 DEFINE_TRACE(CompositeEditCommand) | 1500 DEFINE_TRACE(CompositeEditCommand) |
| 1501 { | 1501 { |
| 1502 visitor->trace(m_commands); | 1502 visitor->trace(m_commands); |
| 1503 visitor->trace(m_composition); | 1503 visitor->trace(m_composition); |
| 1504 EditCommand::trace(visitor); | 1504 EditCommand::trace(visitor); |
| 1505 } | 1505 } |
| 1506 | 1506 |
| 1507 } // namespace blink | 1507 } // namespace blink |
| OLD | NEW |