| 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 |