OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. |
3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. | 3 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 // We also stop when changing block flow elements because even though the vi
sual position is the | 115 // We also stop when changing block flow elements because even though the vi
sual position is the |
116 // same. E.g., | 116 // same. E.g., |
117 // <div>foo^</div>^ | 117 // <div>foo^</div>^ |
118 // The two positions above are the same visual position, but we want to stay
in the same block. | 118 // The two positions above are the same visual position, but we want to stay
in the same block. |
119 Node* enclosingBlockNode = enclosingBlock(pos.containerNode()); | 119 Node* enclosingBlockNode = enclosingBlock(pos.containerNode()); |
120 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB
lockNode; pos = nextPosition) { | 120 for (Position nextPosition = pos; nextPosition.containerNode() != enclosingB
lockNode; pos = nextPosition) { |
121 if (lineBreakExistsAtPosition(pos)) | 121 if (lineBreakExistsAtPosition(pos)) |
122 break; | 122 break; |
123 | 123 |
124 if (pos.containerNode()->nonShadowBoundaryParentNode()) | 124 if (pos.containerNode()->nonShadowBoundaryParentNode()) |
125 nextPosition = positionInParentAfterNode(pos.containerNode()); | 125 nextPosition = positionInParentAfterNode(*pos.containerNode()); |
126 | 126 |
127 if (nextPosition == pos | 127 if (nextPosition == pos |
128 || enclosingBlock(nextPosition.containerNode()) != enclosingBlockNod
e | 128 || enclosingBlock(nextPosition.containerNode()) != enclosingBlockNod
e |
129 || VisiblePosition(pos) != VisiblePosition(nextPosition)) | 129 || VisiblePosition(pos) != VisiblePosition(nextPosition)) |
130 break; | 130 break; |
131 } | 131 } |
132 return pos; | 132 return pos; |
133 } | 133 } |
134 | 134 |
135 ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
ragment, const VisibleSelection& selection) | 135 ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
ragment, const VisibleSelection& selection) |
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 { | 613 { |
614 RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); | 614 RefPtr<Node> pastEndNode = insertedNodes.pastLastLeaf(); |
615 RefPtr<Node> next; | 615 RefPtr<Node> next; |
616 for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node !=
pastEndNode; node = next) { | 616 for (RefPtr<Node> node = insertedNodes.firstNodeInserted(); node && node !=
pastEndNode; node = next) { |
617 next = NodeTraversal::next(*node); | 617 next = NodeTraversal::next(*node); |
618 | 618 |
619 if (!node->isHTMLElement()) | 619 if (!node->isHTMLElement()) |
620 continue; | 620 continue; |
621 | 621 |
622 if (isProhibitedParagraphChild(toHTMLElement(node)->localName())) { | 622 if (isProhibitedParagraphChild(toHTMLElement(node)->localName())) { |
623 if (HTMLElement* paragraphElement = toHTMLElement(enclosingNodeWithT
ag(positionInParentBeforeNode(node.get()), pTag))) | 623 if (HTMLElement* paragraphElement = toHTMLElement(enclosingNodeWithT
ag(positionInParentBeforeNode(*node), pTag))) |
624 moveNodeOutOfAncestor(node, paragraphElement); | 624 moveNodeOutOfAncestor(node, paragraphElement); |
625 } | 625 } |
626 | 626 |
627 if (isHeaderElement(node.get())) { | 627 if (isHeaderElement(node.get())) { |
628 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO
fType(positionInParentBeforeNode(node.get()), isHeaderElement))) | 628 if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeO
fType(positionInParentBeforeNode(*node), isHeaderElement))) |
629 moveNodeOutOfAncestor(node, headerElement); | 629 moveNodeOutOfAncestor(node, headerElement); |
630 } | 630 } |
631 } | 631 } |
632 } | 632 } |
633 | 633 |
634 void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtr<Node> prpNode, Pa
ssRefPtr<Node> prpAncestor) | 634 void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtr<Node> prpNode, Pa
ssRefPtr<Node> prpAncestor) |
635 { | 635 { |
636 RefPtr<Node> node = prpNode; | 636 RefPtr<Node> node = prpNode; |
637 RefPtr<Node> ancestor = prpAncestor; | 637 RefPtr<Node> ancestor = prpAncestor; |
638 | 638 |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
966 | 966 |
967 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break | 967 // We don't want any of the pasted content to end up nested in a Mail blockq
uote, so first break |
968 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case | 968 // out of any surrounding Mail blockquotes. Unless we're inserting in a tabl
e, in which case |
969 // breaking the blockquote will prevent the content from actually being inse
rted in the table. | 969 // breaking the blockquote will prevent the content from actually being inse
rted in the table. |
970 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType
(insertionPos, &isTableStructureNode))) { | 970 if (startIsInsideMailBlockquote && m_preventNesting && !(enclosingNodeOfType
(insertionPos, &isTableStructureNode))) { |
971 applyCommandToComposite(BreakBlockquoteCommand::create(document())); | 971 applyCommandToComposite(BreakBlockquoteCommand::create(document())); |
972 // This will leave a br between the split. | 972 // This will leave a br between the split. |
973 Node* br = endingSelection().start().deprecatedNode(); | 973 Node* br = endingSelection().start().deprecatedNode(); |
974 ASSERT(br->hasTagName(brTag)); | 974 ASSERT(br->hasTagName(brTag)); |
975 // Insert content between the two blockquotes, but remove the br (since
it was just a placeholder). | 975 // Insert content between the two blockquotes, but remove the br (since
it was just a placeholder). |
976 insertionPos = positionInParentBeforeNode(br); | 976 insertionPos = positionInParentBeforeNode(*br); |
977 removeNode(br); | 977 removeNode(br); |
978 } | 978 } |
979 | 979 |
980 // Inserting content could cause whitespace to collapse, e.g. inserting <div
>foo</div> into hello^ world. | 980 // Inserting content could cause whitespace to collapse, e.g. inserting <div
>foo</div> into hello^ world. |
981 prepareWhitespaceAtPositionForSplit(insertionPos); | 981 prepareWhitespaceAtPositionForSplit(insertionPos); |
982 | 982 |
983 // If the downstream node has been removed there's no point in continuing. | 983 // If the downstream node has been removed there's no point in continuing. |
984 if (!insertionPos.downstream().deprecatedNode()) | 984 if (!insertionPos.downstream().deprecatedNode()) |
985 return; | 985 return; |
986 | 986 |
987 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after | 987 // NOTE: This would be an incorrect usage of downstream() if downstream() we
re changed to mean the last position after |
988 // p that maps to the same visible position as p (since in the case where a
br is at the end of a block and collapsed | 988 // p that maps to the same visible position as p (since in the case where a
br is at the end of a block and collapsed |
989 // away, there are positions after the br which map to the same visible posi
tion as [br, 0]). | 989 // away, there are positions after the br which map to the same visible posi
tion as [br, 0]). |
990 Node* endBR = insertionPos.downstream().deprecatedNode()->hasTagName(brTag)
? insertionPos.downstream().deprecatedNode() : 0; | 990 Node* endBR = insertionPos.downstream().deprecatedNode()->hasTagName(brTag)
? insertionPos.downstream().deprecatedNode() : 0; |
991 VisiblePosition originalVisPosBeforeEndBR; | 991 VisiblePosition originalVisPosBeforeEndBR; |
992 if (endBR) | 992 if (endBR) |
993 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D
OWNSTREAM).previous(); | 993 originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), D
OWNSTREAM).previous(); |
994 | 994 |
995 RefPtr<Node> insertionBlock = enclosingBlock(insertionPos.deprecatedNode()); | 995 RefPtr<Node> insertionBlock = enclosingBlock(insertionPos.deprecatedNode()); |
996 | 996 |
997 // Adjust insertionPos to prevent nesting. | 997 // Adjust insertionPos to prevent nesting. |
998 // If the start was in a Mail blockquote, we will have already handled adjus
ting insertionPos above. | 998 // If the start was in a Mail blockquote, we will have already handled adjus
ting insertionPos above. |
999 if (m_preventNesting && insertionBlock && !isTableCell(insertionBlock.get())
&& !startIsInsideMailBlockquote) { | 999 if (m_preventNesting && insertionBlock && !isTableCell(insertionBlock.get())
&& !startIsInsideMailBlockquote) { |
1000 ASSERT(insertionBlock != currentRoot); | 1000 ASSERT(insertionBlock != currentRoot); |
1001 VisiblePosition visibleInsertionPos(insertionPos); | 1001 VisiblePosition visibleInsertionPos(insertionPos); |
1002 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti
onPos) && fragment.hasInterchangeNewlineAtEnd())) | 1002 if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInserti
onPos) && fragment.hasInterchangeNewlineAtEnd())) |
1003 insertionPos = positionInParentAfterNode(insertionBlock.get()); | 1003 insertionPos = positionInParentAfterNode(*insertionBlock); |
1004 else if (isStartOfBlock(visibleInsertionPos)) | 1004 else if (isStartOfBlock(visibleInsertionPos)) |
1005 insertionPos = positionInParentBeforeNode(insertionBlock.get()); | 1005 insertionPos = positionInParentBeforeNode(*insertionBlock); |
1006 } | 1006 } |
1007 | 1007 |
1008 // Paste at start or end of link goes outside of link. | 1008 // Paste at start or end of link goes outside of link. |
1009 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos); | 1009 insertionPos = positionAvoidingSpecialElementBoundary(insertionPos); |
1010 | 1010 |
1011 // FIXME: Can this wait until after the operation has been performed? There
doesn't seem to be | 1011 // FIXME: Can this wait until after the operation has been performed? There
doesn't seem to be |
1012 // any work performed after this that queries or uses the typing style. | 1012 // any work performed after this that queries or uses the typing style. |
1013 if (LocalFrame* frame = document().frame()) | 1013 if (LocalFrame* frame = document().frame()) |
1014 frame->selection().clearTypingStyle(); | 1014 frame->selection().clearTypingStyle(); |
1015 | 1015 |
(...skipping 24 matching lines...) Expand all Loading... |
1040 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon
tainerNode()); | 1040 splitTextNode(insertionPos.containerText(), insertionPos.offsetInCon
tainerNode()); |
1041 insertionPos = firstPositionInNode(insertionPos.containerNode()); | 1041 insertionPos = firstPositionInNode(insertionPos.containerNode()); |
1042 } | 1042 } |
1043 | 1043 |
1044 if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNode
sWithStyle(insertionPos)) { | 1044 if (RefPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNode
sWithStyle(insertionPos)) { |
1045 if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) { | 1045 if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) { |
1046 Node* splitStart = insertionPos.computeNodeAfterPosition(); | 1046 Node* splitStart = insertionPos.computeNodeAfterPosition(); |
1047 if (!splitStart) | 1047 if (!splitStart) |
1048 splitStart = insertionPos.containerNode(); | 1048 splitStart = insertionPos.containerNode(); |
1049 nodeToSplitTo = splitTreeToNode(splitStart, nodeToSplitTo->paren
tNode()).get(); | 1049 nodeToSplitTo = splitTreeToNode(splitStart, nodeToSplitTo->paren
tNode()).get(); |
1050 insertionPos = positionInParentBeforeNode(nodeToSplitTo.get()); | 1050 insertionPos = positionInParentBeforeNode(*nodeToSplitTo); |
1051 } | 1051 } |
1052 } | 1052 } |
1053 } | 1053 } |
1054 | 1054 |
1055 // FIXME: When pasting rich content we're often prevented from heading down
the fast path by style spans. Try | 1055 // FIXME: When pasting rich content we're often prevented from heading down
the fast path by style spans. Try |
1056 // again here if they've been removed. | 1056 // again here if they've been removed. |
1057 | 1057 |
1058 // 1) Insert the content. | 1058 // 1) Insert the content. |
1059 // 2) Remove redundant styles and style tags, this inner <b> for example: <b
>foo <b>bar</b> baz</b>. | 1059 // 2) Remove redundant styles and style tags, this inner <b> for example: <b
>foo <b>bar</b> baz</b>. |
1060 // 3) Merge the start of the added content with the content before the posit
ion being pasted into. | 1060 // 3) Merge the start of the added content with the content before the posit
ion being pasted into. |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1370 if (!text) | 1370 if (!text) |
1371 return; | 1371 return; |
1372 | 1372 |
1373 if (text->previousSibling() && text->previousSibling()->isTextNode()) { | 1373 if (text->previousSibling() && text->previousSibling()->isTextNode()) { |
1374 RefPtr<Text> previous = toText(text->previousSibling()); | 1374 RefPtr<Text> previous = toText(text->previousSibling()); |
1375 insertTextIntoNode(text, 0, previous->data()); | 1375 insertTextIntoNode(text, 0, previous->data()); |
1376 | 1376 |
1377 if (positionIsOffsetInAnchor) | 1377 if (positionIsOffsetInAnchor) |
1378 position.moveToOffset(previous->length() + position.offsetInContaine
rNode()); | 1378 position.moveToOffset(previous->length() + position.offsetInContaine
rNode()); |
1379 else | 1379 else |
1380 updatePositionForNodeRemoval(position, previous.get()); | 1380 updatePositionForNodeRemoval(position, *previous); |
1381 | 1381 |
1382 if (positionOnlyToBeUpdatedIsOffsetInAnchor) { | 1382 if (positionOnlyToBeUpdatedIsOffsetInAnchor) { |
1383 if (positionOnlyToBeUpdated.containerNode() == text) | 1383 if (positionOnlyToBeUpdated.containerNode() == text) |
1384 positionOnlyToBeUpdated.moveToOffset(previous->length() + positi
onOnlyToBeUpdated.offsetInContainerNode()); | 1384 positionOnlyToBeUpdated.moveToOffset(previous->length() + positi
onOnlyToBeUpdated.offsetInContainerNode()); |
1385 else if (positionOnlyToBeUpdated.containerNode() == previous) | 1385 else if (positionOnlyToBeUpdated.containerNode() == previous) |
1386 positionOnlyToBeUpdated.moveToPosition(text, positionOnlyToBeUpd
ated.offsetInContainerNode()); | 1386 positionOnlyToBeUpdated.moveToPosition(text, positionOnlyToBeUpd
ated.offsetInContainerNode()); |
1387 } else | 1387 } else { |
1388 updatePositionForNodeRemoval(positionOnlyToBeUpdated, previous.get()
); | 1388 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *previous); |
| 1389 } |
1389 | 1390 |
1390 removeNode(previous); | 1391 removeNode(previous); |
1391 } | 1392 } |
1392 if (text->nextSibling() && text->nextSibling()->isTextNode()) { | 1393 if (text->nextSibling() && text->nextSibling()->isTextNode()) { |
1393 RefPtr<Text> next = toText(text->nextSibling()); | 1394 RefPtr<Text> next = toText(text->nextSibling()); |
1394 unsigned originalLength = text->length(); | 1395 unsigned originalLength = text->length(); |
1395 insertTextIntoNode(text, originalLength, next->data()); | 1396 insertTextIntoNode(text, originalLength, next->data()); |
1396 | 1397 |
1397 if (!positionIsOffsetInAnchor) | 1398 if (!positionIsOffsetInAnchor) |
1398 updatePositionForNodeRemoval(position, next.get()); | 1399 updatePositionForNodeRemoval(position, *next); |
1399 | 1400 |
1400 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c
ontainerNode() == next) | 1401 if (positionOnlyToBeUpdatedIsOffsetInAnchor && positionOnlyToBeUpdated.c
ontainerNode() == next) |
1401 positionOnlyToBeUpdated.moveToPosition(text, originalLength + positi
onOnlyToBeUpdated.offsetInContainerNode()); | 1402 positionOnlyToBeUpdated.moveToPosition(text, originalLength + positi
onOnlyToBeUpdated.offsetInContainerNode()); |
1402 else | 1403 else |
1403 updatePositionForNodeRemoval(positionOnlyToBeUpdated, next.get()); | 1404 updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next); |
1404 | 1405 |
1405 removeNode(next); | 1406 removeNode(next); |
1406 } | 1407 } |
1407 } | 1408 } |
1408 | 1409 |
1409 EditAction ReplaceSelectionCommand::editingAction() const | 1410 EditAction ReplaceSelectionCommand::editingAction() const |
1410 { | 1411 { |
1411 return m_editAction; | 1412 return m_editAction; |
1412 } | 1413 } |
1413 | 1414 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1493 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); | 1494 removeNodeAndPruneAncestors(nodeAfterInsertionPos.get()); |
1494 | 1495 |
1495 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); | 1496 VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, en
d); |
1496 | 1497 |
1497 setEndingSelection(selectionAfterReplace); | 1498 setEndingSelection(selectionAfterReplace); |
1498 | 1499 |
1499 return true; | 1500 return true; |
1500 } | 1501 } |
1501 | 1502 |
1502 } // namespace WebCore | 1503 } // namespace WebCore |
OLD | NEW |