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 |
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 "config.h" | 26 #include "config.h" |
27 #include "core/editing/CompositeEditCommand.h" | 27 #include "core/editing/commands/CompositeEditCommand.h" |
28 | 28 |
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 29 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
30 #include "core/HTMLNames.h" | 30 #include "core/HTMLNames.h" |
31 #include "core/dom/Document.h" | 31 #include "core/dom/Document.h" |
32 #include "core/dom/DocumentFragment.h" | 32 #include "core/dom/DocumentFragment.h" |
33 #include "core/dom/ElementTraversal.h" | 33 #include "core/dom/ElementTraversal.h" |
34 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
35 #include "core/dom/Range.h" | 35 #include "core/dom/Range.h" |
36 #include "core/dom/Text.h" | 36 #include "core/dom/Text.h" |
37 #include "core/editing/AppendNodeCommand.h" | |
38 #include "core/editing/ApplyStyleCommand.h" | |
39 #include "core/editing/DeleteFromTextNodeCommand.h" | |
40 #include "core/editing/DeleteSelectionCommand.h" | |
41 #include "core/editing/EditingUtilities.h" | 37 #include "core/editing/EditingUtilities.h" |
42 #include "core/editing/Editor.h" | 38 #include "core/editing/Editor.h" |
43 #include "core/editing/InsertIntoTextNodeCommand.h" | |
44 #include "core/editing/InsertLineBreakCommand.h" | |
45 #include "core/editing/InsertNodeBeforeCommand.h" | |
46 #include "core/editing/InsertParagraphSeparatorCommand.h" | |
47 #include "core/editing/MergeIdenticalElementsCommand.h" | |
48 #include "core/editing/PlainTextRange.h" | 39 #include "core/editing/PlainTextRange.h" |
49 #include "core/editing/RemoveCSSPropertyCommand.h" | |
50 #include "core/editing/RemoveNodeCommand.h" | |
51 #include "core/editing/RemoveNodePreservingChildrenCommand.h" | |
52 #include "core/editing/ReplaceNodeWithSpanCommand.h" | |
53 #include "core/editing/ReplaceSelectionCommand.h" | |
54 #include "core/editing/SetNodeAttributeCommand.h" | |
55 #include "core/editing/SplitElementCommand.h" | |
56 #include "core/editing/SplitTextNodeCommand.h" | |
57 #include "core/editing/SplitTextNodeContainingElementCommand.h" | |
58 #include "core/editing/VisibleUnits.h" | 40 #include "core/editing/VisibleUnits.h" |
59 #include "core/editing/WrapContentsInDummySpanCommand.h" | 41 #include "core/editing/commands/AppendNodeCommand.h" |
| 42 #include "core/editing/commands/ApplyStyleCommand.h" |
| 43 #include "core/editing/commands/DeleteFromTextNodeCommand.h" |
| 44 #include "core/editing/commands/DeleteSelectionCommand.h" |
| 45 #include "core/editing/commands/InsertIntoTextNodeCommand.h" |
| 46 #include "core/editing/commands/InsertLineBreakCommand.h" |
| 47 #include "core/editing/commands/InsertNodeBeforeCommand.h" |
| 48 #include "core/editing/commands/InsertParagraphSeparatorCommand.h" |
| 49 #include "core/editing/commands/MergeIdenticalElementsCommand.h" |
| 50 #include "core/editing/commands/RemoveCSSPropertyCommand.h" |
| 51 #include "core/editing/commands/RemoveNodeCommand.h" |
| 52 #include "core/editing/commands/RemoveNodePreservingChildrenCommand.h" |
| 53 #include "core/editing/commands/ReplaceNodeWithSpanCommand.h" |
| 54 #include "core/editing/commands/ReplaceSelectionCommand.h" |
| 55 #include "core/editing/commands/SetNodeAttributeCommand.h" |
| 56 #include "core/editing/commands/SplitElementCommand.h" |
| 57 #include "core/editing/commands/SplitTextNodeCommand.h" |
| 58 #include "core/editing/commands/SplitTextNodeContainingElementCommand.h" |
| 59 #include "core/editing/commands/WrapContentsInDummySpanCommand.h" |
60 #include "core/editing/iterators/TextIterator.h" | 60 #include "core/editing/iterators/TextIterator.h" |
61 #include "core/editing/markers/DocumentMarkerController.h" | 61 #include "core/editing/markers/DocumentMarkerController.h" |
62 #include "core/editing/serializers/Serialization.h" | 62 #include "core/editing/serializers/Serialization.h" |
63 #include "core/editing/spellcheck/SpellChecker.h" | 63 #include "core/editing/spellcheck/SpellChecker.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/HTMLBRElement.h" |
67 #include "core/html/HTMLDivElement.h" | 67 #include "core/html/HTMLDivElement.h" |
68 #include "core/html/HTMLElement.h" | 68 #include "core/html/HTMLElement.h" |
69 #include "core/html/HTMLLIElement.h" | 69 #include "core/html/HTMLLIElement.h" |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 } | 313 } |
314 | 314 |
315 void CompositeEditCommand::insertNodeAfter(PassRefPtrWillBeRawPtr<Node> insertCh
ild, PassRefPtrWillBeRawPtr<Node> refChild) | 315 void CompositeEditCommand::insertNodeAfter(PassRefPtrWillBeRawPtr<Node> insertCh
ild, PassRefPtrWillBeRawPtr<Node> refChild) |
316 { | 316 { |
317 ASSERT(insertChild); | 317 ASSERT(insertChild); |
318 ASSERT(refChild); | 318 ASSERT(refChild); |
319 ASSERT(!isHTMLBodyElement(*refChild)); | 319 ASSERT(!isHTMLBodyElement(*refChild)); |
320 ContainerNode* parent = refChild->parentNode(); | 320 ContainerNode* parent = refChild->parentNode(); |
321 ASSERT(parent); | 321 ASSERT(parent); |
322 ASSERT(!parent->isShadowRoot()); | 322 ASSERT(!parent->isShadowRoot()); |
323 if (parent->lastChild() == refChild) | 323 if (parent->lastChild() == refChild) { |
324 appendNode(insertChild, parent); | 324 appendNode(insertChild, parent); |
325 else { | 325 } else { |
326 ASSERT(refChild->nextSibling()); | 326 ASSERT(refChild->nextSibling()); |
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.anchorNode(); | 337 Node* refChild = p.anchorNode(); |
338 int offset = p.offsetInContainerNode(); | 338 int offset = p.offsetInContainerNode(); |
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)); |
348 } else if (caretMinOffset(refChild) >= offset) | 348 } else if (caretMinOffset(refChild) >= offset) { |
349 insertNodeBefore(insertChild, refChild); | 349 insertNodeBefore(insertChild, refChild); |
350 else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) { | 350 } else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) { |
351 splitTextNode(toText(refChild), offset); | 351 splitTextNode(toText(refChild), offset); |
352 | 352 |
353 // Mutation events (bug 22634) from the text node insertion may have rem
oved the refChild | 353 // Mutation events (bug 22634) from the text node insertion may have rem
oved the refChild |
354 if (!refChild->inDocument()) | 354 if (!refChild->inDocument()) |
355 return; | 355 return; |
356 insertNodeBefore(insertChild, refChild); | 356 insertNodeBefore(insertChild, refChild); |
357 } else | 357 } else { |
358 insertNodeAfter(insertChild, refChild); | 358 insertNodeAfter(insertChild, refChild); |
| 359 } |
359 } | 360 } |
360 | 361 |
361 void CompositeEditCommand::appendNode(PassRefPtrWillBeRawPtr<Node> node, PassRef
PtrWillBeRawPtr<ContainerNode> parent) | 362 void CompositeEditCommand::appendNode(PassRefPtrWillBeRawPtr<Node> node, PassRef
PtrWillBeRawPtr<ContainerNode> parent) |
362 { | 363 { |
363 // When cloneParagraphUnderNewElement() clones the fallback content | 364 // When cloneParagraphUnderNewElement() clones the fallback content |
364 // of an OBJECT element, the ASSERT below may fire since the return | 365 // of an OBJECT element, the ASSERT below may fire since the return |
365 // value of canHaveChildrenForEditing is not reliable until the layout | 366 // value of canHaveChildrenForEditing is not reliable until the layout |
366 // object of the OBJECT is created. Hence we ignore this check for OBJECTs. | 367 // object of the OBJECT is created. Hence we ignore this check for OBJECTs. |
367 ASSERT(canHaveChildrenForEditing(parent.get()) | 368 ASSERT(canHaveChildrenForEditing(parent.get()) |
368 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob
jectTag)); | 369 || (parent->isElementNode() && toElement(parent.get())->tagQName() == ob
jectTag)); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 | 668 |
668 int length = downstream - upstream; | 669 int length = downstream - upstream; |
669 if (!length) | 670 if (!length) |
670 return; | 671 return; |
671 | 672 |
672 VisiblePosition visibleUpstreamPos(Position(textNode, upstream)); | 673 VisiblePosition visibleUpstreamPos(Position(textNode, upstream)); |
673 VisiblePosition visibleDownstreamPos(Position(textNode, downstream)); | 674 VisiblePosition visibleDownstreamPos(Position(textNode, downstream)); |
674 | 675 |
675 String string = text.substring(upstream, length); | 676 String string = text.substring(upstream, length); |
676 String rebalancedString = stringWithRebalancedWhitespace(string, | 677 String rebalancedString = stringWithRebalancedWhitespace(string, |
677 // FIXME: Because of the problem mentioned at the top of this function, we m
ust also use nbsps at the start/end of the string because | 678 // FIXME: Because of the problem mentioned at the top of this function, |
678 // this function doesn't get all surrounding whitespace, just the whitespace
in the current text node. | 679 // we must also use nbsps at the start/end of the string because this |
679 isStartOfParagraph(
visibleUpstreamPos) || upstream == 0, | 680 // function doesn't get all surrounding whitespace, just the whitespace |
680 isEndOfParagraph(vi
sibleDownstreamPos) || (unsigned)downstream == text.length()); | 681 // in the current text node. |
| 682 isStartOfParagraph(visibleUpstreamPos) || upstream == 0, |
| 683 isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.l
ength()); |
681 | 684 |
682 if (string != rebalancedString) | 685 if (string != rebalancedString) |
683 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length,
rebalancedString); | 686 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length,
rebalancedString); |
684 } | 687 } |
685 | 688 |
686 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio
n) | 689 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio
n) |
687 { | 690 { |
688 Node* node = position.anchorNode(); | 691 Node* node = position.anchorNode(); |
689 if (!node || !node->isTextNode()) | 692 if (!node || !node->isTextNode()) |
690 return; | 693 return; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 return; | 765 return; |
763 | 766 |
764 unsigned removed = 0; | 767 unsigned removed = 0; |
765 InlineTextBox* prevBox = nullptr; | 768 InlineTextBox* prevBox = nullptr; |
766 String str; | 769 String str; |
767 | 770 |
768 // This loop structure works to process all gaps preceding a box, | 771 // This loop structure works to process all gaps preceding a box, |
769 // and also will look at the gap after the last box. | 772 // and also will look at the gap after the last box. |
770 while (prevBox || box) { | 773 while (prevBox || box) { |
771 unsigned gapStart = prevBox ? prevBox->start() + prevBox->len() : 0; | 774 unsigned gapStart = prevBox ? prevBox->start() + prevBox->len() : 0; |
772 if (end < gapStart) | 775 if (end < gapStart) { |
773 // No more chance for any intersections | 776 // No more chance for any intersections |
774 break; | 777 break; |
| 778 } |
775 | 779 |
776 unsigned gapEnd = box ? box->start() : length; | 780 unsigned gapEnd = box ? box->start() : length; |
777 bool indicesIntersect = start <= gapEnd && end >= gapStart; | 781 bool indicesIntersect = start <= gapEnd && end >= gapStart; |
778 int gapLen = gapEnd - gapStart; | 782 int gapLen = gapEnd - gapStart; |
779 if (indicesIntersect && gapLen > 0) { | 783 if (indicesIntersect && gapLen > 0) { |
780 gapStart = std::max(gapStart, start); | 784 gapStart = std::max(gapStart, start); |
781 if (str.isNull()) | 785 if (str.isNull()) |
782 str = textNode->data().substring(start, end - start); | 786 str = textNode->data().substring(start, end - start); |
783 // remove text in the gap | 787 // remove text in the gap |
784 str.remove(gapStart - start - removed, gapLen); | 788 str.remove(gapStart - start - removed, gapLen); |
785 removed += gapLen; | 789 removed += gapLen; |
786 } | 790 } |
787 | 791 |
788 prevBox = box; | 792 prevBox = box; |
789 if (box) { | 793 if (box) { |
790 if (++sortedTextBoxesPosition < sortedTextBoxes.size()) | 794 if (++sortedTextBoxesPosition < sortedTextBoxes.size()) |
791 box = sortedTextBoxes[sortedTextBoxesPosition]; | 795 box = sortedTextBoxes[sortedTextBoxesPosition]; |
792 else | 796 else |
793 box = 0; | 797 box = 0; |
794 } | 798 } |
795 } | 799 } |
796 | 800 |
797 if (!str.isNull()) { | 801 if (!str.isNull()) { |
798 // Replace the text between start and end with our pruned version. | 802 // Replace the text between start and end with our pruned version. |
799 if (!str.isEmpty()) | 803 if (!str.isEmpty()) { |
800 replaceTextInNode(textNode, start, end - start, str); | 804 replaceTextInNode(textNode, start, end - start, str); |
801 else { | 805 } else { |
802 // Assert that we are not going to delete all of the text in the nod
e. | 806 // Assert that we are not going to delete all of the text in the nod
e. |
803 // If we were, that should have been done above with the call to | 807 // If we were, that should have been done above with the call to |
804 // removeNode and return. | 808 // removeNode and return. |
805 ASSERT(start > 0 || end - start < textNode->length()); | 809 ASSERT(start > 0 || end - start < textNode->length()); |
806 deleteTextFromNode(textNode, start, end - start); | 810 deleteTextFromNode(textNode, start, end - start); |
807 } | 811 } |
808 } | 812 } |
809 } | 813 } |
810 | 814 |
811 void CompositeEditCommand::deleteInsignificantText(const Position& start, const
Position& end) | 815 void CompositeEditCommand::deleteInsignificantText(const Position& start, const
Position& end) |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 // div or an li), remove it during the move (the list removal code | 1100 // div or an li), remove it during the move (the list removal code |
1097 // expects this behavior). | 1101 // expects this behavior). |
1098 } else if (isBlock(node)) { | 1102 } else if (isBlock(node)) { |
1099 // If caret position after deletion and destination position coincid
es, | 1103 // If caret position after deletion and destination position coincid
es, |
1100 // node should not be removed. | 1104 // node should not be removed. |
1101 if (!rendersInDifferentPosition(position, destination.deepEquivalent
())) { | 1105 if (!rendersInDifferentPosition(position, destination.deepEquivalent
())) { |
1102 prune(node, destinationNode); | 1106 prune(node, destinationNode); |
1103 return; | 1107 return; |
1104 } | 1108 } |
1105 removeNodeAndPruneAncestors(node, destinationNode); | 1109 removeNodeAndPruneAncestors(node, destinationNode); |
1106 } | 1110 } else if (lineBreakExistsAtPosition(position)) { |
1107 else if (lineBreakExistsAtPosition(position)) { | |
1108 // There is a preserved '\n' at caretAfterDelete. | 1111 // There is a preserved '\n' at caretAfterDelete. |
1109 // We can safely assume this is a text node. | 1112 // We can safely assume this is a text node. |
1110 Text* textNode = toText(node); | 1113 Text* textNode = toText(node); |
1111 if (textNode->length() == 1) | 1114 if (textNode->length() == 1) |
1112 removeNodeAndPruneAncestors(node, destinationNode); | 1115 removeNodeAndPruneAncestors(node, destinationNode); |
1113 else | 1116 else |
1114 deleteTextFromNode(textNode, position.computeOffsetInContainerNo
de(), 1); | 1117 deleteTextFromNode(textNode, position.computeOffsetInContainerNo
de(), 1); |
1115 } | 1118 } |
1116 } | 1119 } |
1117 } | 1120 } |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1499 } | 1502 } |
1500 | 1503 |
1501 DEFINE_TRACE(CompositeEditCommand) | 1504 DEFINE_TRACE(CompositeEditCommand) |
1502 { | 1505 { |
1503 visitor->trace(m_commands); | 1506 visitor->trace(m_commands); |
1504 visitor->trace(m_composition); | 1507 visitor->trace(m_composition); |
1505 EditCommand::trace(visitor); | 1508 EditCommand::trace(visitor); |
1506 } | 1509 } |
1507 | 1510 |
1508 } // namespace blink | 1511 } // namespace blink |
OLD | NEW |