| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2008, 2009 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 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 splitTextAtEnd(start, end); | 344 splitTextAtEnd(start, end); |
| 345 start = startPosition(); | 345 start = startPosition(); |
| 346 end = endPosition(); | 346 end = endPosition(); |
| 347 } | 347 } |
| 348 | 348 |
| 349 // Calculate loop end point. | 349 // Calculate loop end point. |
| 350 // If the end node is before the start node (can only happen if the end node
is | 350 // If the end node is before the start node (can only happen if the end node
is |
| 351 // an ancestor of the start node), we gather nodes up to the next sibling of
the end node | 351 // an ancestor of the start node), we gather nodes up to the next sibling of
the end node |
| 352 Node *beyondEnd; | 352 Node *beyondEnd; |
| 353 if (start.deprecatedNode()->isDescendantOf(end.deprecatedNode())) | 353 if (start.deprecatedNode()->isDescendantOf(end.deprecatedNode())) |
| 354 beyondEnd = NodeTraversal::nextSkippingChildren(end.deprecatedNode()); | 354 beyondEnd = NodeTraversal::nextSkippingChildren(*end.deprecatedNode()); |
| 355 else | 355 else |
| 356 beyondEnd = NodeTraversal::next(*end.deprecatedNode()); | 356 beyondEnd = NodeTraversal::next(*end.deprecatedNode()); |
| 357 | 357 |
| 358 start = start.upstream(); // Move upstream to ensure we do not add redundant
spans. | 358 start = start.upstream(); // Move upstream to ensure we do not add redundant
spans. |
| 359 Node* startNode = start.deprecatedNode(); | 359 Node* startNode = start.deprecatedNode(); |
| 360 ASSERT(startNode); | 360 ASSERT(startNode); |
| 361 if (startNode->isTextNode() && start.deprecatedEditingOffset() >= caretMaxOf
fset(startNode)) // Move out of text node if range does not include its characte
rs. | 361 if (startNode->isTextNode() && start.deprecatedEditingOffset() >= caretMaxOf
fset(startNode)) // Move out of text node if range does not include its characte
rs. |
| 362 startNode = NodeTraversal::next(*startNode); | 362 startNode = NodeTraversal::next(*startNode); |
| 363 | 363 |
| 364 // Store away font size before making any changes to the document. | 364 // Store away font size before making any changes to the document. |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 ASSERT(startNode); | 676 ASSERT(startNode); |
| 677 | 677 |
| 678 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode()
)) { | 678 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode()
)) { |
| 679 startNode = NodeTraversal::next(*startNode); | 679 startNode = NodeTraversal::next(*startNode); |
| 680 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) | 680 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) |
| 681 return; | 681 return; |
| 682 } | 682 } |
| 683 | 683 |
| 684 Node* pastEndNode = end.deprecatedNode(); | 684 Node* pastEndNode = end.deprecatedNode(); |
| 685 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode())) | 685 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode())) |
| 686 pastEndNode = NodeTraversal::nextSkippingChildren(end.deprecatedNode()); | 686 pastEndNode = NodeTraversal::nextSkippingChildren(*end.deprecatedNode())
; |
| 687 | 687 |
| 688 // FIXME: Callers should perform this operation on a Range that includes the
br | 688 // FIXME: Callers should perform this operation on a Range that includes the
br |
| 689 // if they want style applied to the empty line. | 689 // if they want style applied to the empty line. |
| 690 if (start == end && start.deprecatedNode()->hasTagName(brTag)) | 690 if (start == end && start.deprecatedNode()->hasTagName(brTag)) |
| 691 pastEndNode = NodeTraversal::next(*start.deprecatedNode()); | 691 pastEndNode = NodeTraversal::next(*start.deprecatedNode()); |
| 692 | 692 |
| 693 // Start from the highest fully selected ancestor so that we can modify the
fully selected node. | 693 // Start from the highest fully selected ancestor so that we can modify the
fully selected node. |
| 694 // e.g. When applying font-size: large on <font color="blue">hello</font>, w
e need to include the font element in our run | 694 // e.g. When applying font-size: large on <font color="blue">hello</font>, w
e need to include the font element in our run |
| 695 // to generate <font color="blue" size="4">hello</font> instead of <font col
or="blue"><font size="4">hello</font></font> | 695 // to generate <font color="blue" size="4">hello</font> instead of <font col
or="blue"><font size="4">hello</font></font> |
| 696 RefPtr<Range> range = Range::create(startNode->document(), start, end); | 696 RefPtr<Range> range = Range::create(startNode->document(), start, end); |
| 697 Element* editableRoot = startNode->rootEditableElement(); | 697 Element* editableRoot = startNode->rootEditableElement(); |
| 698 if (startNode != editableRoot) { | 698 if (startNode != editableRoot) { |
| 699 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(startNode->parentNode(), range.get())) | 699 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(startNode->parentNode(), range.get())) |
| 700 startNode = startNode->parentNode(); | 700 startNode = startNode->parentNode(); |
| 701 } | 701 } |
| 702 | 702 |
| 703 applyInlineStyleToNodeRange(style, startNode, pastEndNode); | 703 applyInlineStyleToNodeRange(style, startNode, pastEndNode); |
| 704 } | 704 } |
| 705 | 705 |
| 706 static bool containsNonEditableRegion(Node* node) | 706 static bool containsNonEditableRegion(Node& node) |
| 707 { | 707 { |
| 708 if (!node->rendererIsEditable()) | 708 if (!node.rendererIsEditable()) |
| 709 return true; | 709 return true; |
| 710 | 710 |
| 711 Node* sibling = NodeTraversal::nextSkippingChildren(node); | 711 Node* sibling = NodeTraversal::nextSkippingChildren(node); |
| 712 for (Node* descendent = node->firstChild(); descendent && descendent != sibl
ing; descendent = NodeTraversal::next(*descendent)) { | 712 for (Node* descendent = node.firstChild(); descendent && descendent != sibli
ng; descendent = NodeTraversal::next(*descendent)) { |
| 713 if (!descendent->rendererIsEditable()) | 713 if (!descendent->rendererIsEditable()) |
| 714 return true; | 714 return true; |
| 715 } | 715 } |
| 716 | 716 |
| 717 return false; | 717 return false; |
| 718 } | 718 } |
| 719 | 719 |
| 720 struct InlineRunToApplyStyle { | 720 struct InlineRunToApplyStyle { |
| 721 InlineRunToApplyStyle(Node* start, Node* end, Node* pastEndNode) | 721 InlineRunToApplyStyle(Node* start, Node* end, Node* pastEndNode) |
| 722 : start(start) | 722 : start(start) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 continue; | 755 continue; |
| 756 | 756 |
| 757 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { | 757 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { |
| 758 // This is a plaintext-only region. Only proceed if it's fully selec
ted. | 758 // This is a plaintext-only region. Only proceed if it's fully selec
ted. |
| 759 // pastEndNode is the node after the last fully selected node, so if
it's inside node then | 759 // pastEndNode is the node after the last fully selected node, so if
it's inside node then |
| 760 // node isn't fully selected. | 760 // node isn't fully selected. |
| 761 if (pastEndNode && pastEndNode->isDescendantOf(node.get())) | 761 if (pastEndNode && pastEndNode->isDescendantOf(node.get())) |
| 762 break; | 762 break; |
| 763 // Add to this element's inline style and skip over its contents. | 763 // Add to this element's inline style and skip over its contents. |
| 764 HTMLElement* element = toHTMLElement(node); | 764 HTMLElement* element = toHTMLElement(node); |
| 765 next = NodeTraversal::nextSkippingChildren(node.get()); | 765 next = NodeTraversal::nextSkippingChildren(*node); |
| 766 if (!style->style()) | 766 if (!style->style()) |
| 767 continue; | 767 continue; |
| 768 RefPtr<MutableStylePropertySet> inlineStyle = copyStyleOrCreateEmpty
(element->inlineStyle()); | 768 RefPtr<MutableStylePropertySet> inlineStyle = copyStyleOrCreateEmpty
(element->inlineStyle()); |
| 769 inlineStyle->mergeAndOverrideOnConflict(style->style()); | 769 inlineStyle->mergeAndOverrideOnConflict(style->style()); |
| 770 setNodeAttribute(element, styleAttr, inlineStyle->asText()); | 770 setNodeAttribute(element, styleAttr, inlineStyle->asText()); |
| 771 continue; | 771 continue; |
| 772 } | 772 } |
| 773 | 773 |
| 774 if (isBlock(node.get())) | 774 if (isBlock(node.get())) |
| 775 continue; | 775 continue; |
| 776 | 776 |
| 777 if (node->childNodeCount()) { | 777 if (node->childNodeCount()) { |
| 778 if (node->contains(pastEndNode.get()) || containsNonEditableRegion(n
ode.get()) || !node->parentNode()->rendererIsEditable()) | 778 if (node->contains(pastEndNode.get()) || containsNonEditableRegion(*
node) || !node->parentNode()->rendererIsEditable()) |
| 779 continue; | 779 continue; |
| 780 if (editingIgnoresContent(node.get())) { | 780 if (editingIgnoresContent(node.get())) { |
| 781 next = NodeTraversal::nextSkippingChildren(node.get()); | 781 next = NodeTraversal::nextSkippingChildren(*node); |
| 782 continue; | 782 continue; |
| 783 } | 783 } |
| 784 } | 784 } |
| 785 | 785 |
| 786 Node* runStart = node.get(); | 786 Node* runStart = node.get(); |
| 787 Node* runEnd = node.get(); | 787 Node* runEnd = node.get(); |
| 788 Node* sibling = node->nextSibling(); | 788 Node* sibling = node->nextSibling(); |
| 789 while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNo
de.get()) | 789 while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNo
de.get()) |
| 790 && (!isBlock(sibling) || sibling->hasTagName(brTag)) | 790 && (!isBlock(sibling) || sibling->hasTagName(brTag)) |
| 791 && !containsNonEditableRegion(sibling)) { | 791 && !containsNonEditableRegion(*sibling)) { |
| 792 runEnd = sibling; | 792 runEnd = sibling; |
| 793 sibling = runEnd->nextSibling(); | 793 sibling = runEnd->nextSibling(); |
| 794 } | 794 } |
| 795 next = NodeTraversal::nextSkippingChildren(runEnd); | 795 ASSERT(runEnd); |
| 796 next = NodeTraversal::nextSkippingChildren(*runEnd); |
| 796 | 797 |
| 797 Node* pastEndNode = NodeTraversal::nextSkippingChildren(runEnd); | 798 Node* pastEndNode = NodeTraversal::nextSkippingChildren(*runEnd); |
| 798 if (!shouldApplyInlineStyleToRun(style, runStart, pastEndNode)) | 799 if (!shouldApplyInlineStyleToRun(style, runStart, pastEndNode)) |
| 799 continue; | 800 continue; |
| 800 | 801 |
| 801 runs.append(InlineRunToApplyStyle(runStart, runEnd, pastEndNode)); | 802 runs.append(InlineRunToApplyStyle(runStart, runEnd, pastEndNode)); |
| 802 } | 803 } |
| 803 | 804 |
| 804 for (size_t i = 0; i < runs.size(); i++) { | 805 for (size_t i = 0; i < runs.size(); i++) { |
| 805 removeConflictingInlineStyleFromRun(style, runs[i].start, runs[i].end, r
uns[i].pastEndNode); | 806 removeConflictingInlineStyleFromRun(style, runs[i].start, runs[i].end, r
uns[i].pastEndNode); |
| 806 runs[i].positionForStyleComputation = positionToComputeInlineStyleChange
(runs[i].start, runs[i].dummyElement); | 807 runs[i].positionForStyleComputation = positionToComputeInlineStyleChange
(runs[i].start, runs[i].dummyElement); |
| 807 } | 808 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 return false; | 843 return false; |
| 843 } | 844 } |
| 844 | 845 |
| 845 void ApplyStyleCommand::removeConflictingInlineStyleFromRun(EditingStyle* style,
RefPtr<Node>& runStart, RefPtr<Node>& runEnd, PassRefPtr<Node> pastEndNode) | 846 void ApplyStyleCommand::removeConflictingInlineStyleFromRun(EditingStyle* style,
RefPtr<Node>& runStart, RefPtr<Node>& runEnd, PassRefPtr<Node> pastEndNode) |
| 846 { | 847 { |
| 847 ASSERT(runStart && runEnd); | 848 ASSERT(runStart && runEnd); |
| 848 RefPtr<Node> next = runStart; | 849 RefPtr<Node> next = runStart; |
| 849 for (RefPtr<Node> node = next; node && node->inDocument() && node != pastEnd
Node; node = next) { | 850 for (RefPtr<Node> node = next; node && node->inDocument() && node != pastEnd
Node; node = next) { |
| 850 if (editingIgnoresContent(node.get())) { | 851 if (editingIgnoresContent(node.get())) { |
| 851 ASSERT(!node->contains(pastEndNode.get())); | 852 ASSERT(!node->contains(pastEndNode.get())); |
| 852 next = NodeTraversal::nextSkippingChildren(node.get()); | 853 next = NodeTraversal::nextSkippingChildren(*node); |
| 853 } else { | 854 } else { |
| 854 next = NodeTraversal::next(*node); | 855 next = NodeTraversal::next(*node); |
| 855 } | 856 } |
| 856 if (!node->isHTMLElement()) | 857 if (!node->isHTMLElement()) |
| 857 continue; | 858 continue; |
| 858 | 859 |
| 859 RefPtr<Node> previousSibling = node->previousSibling(); | 860 RefPtr<Node> previousSibling = node->previousSibling(); |
| 860 RefPtr<Node> nextSibling = node->nextSibling(); | 861 RefPtr<Node> nextSibling = node->nextSibling(); |
| 861 RefPtr<ContainerNode> parent = node->parentNode(); | 862 RefPtr<ContainerNode> parent = node->parentNode(); |
| 862 removeInlineStyleFromElement(style, toHTMLElement(node), RemoveAlways); | 863 removeInlineStyleFromElement(style, toHTMLElement(node), RemoveAlways); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1102 // If pushDownInlineStyleAroundNode has pruned start.deprecatedNode() or end
.deprecatedNode(), | 1103 // If pushDownInlineStyleAroundNode has pruned start.deprecatedNode() or end
.deprecatedNode(), |
| 1103 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround
Node won't prune. | 1104 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround
Node won't prune. |
| 1104 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; | 1105 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; |
| 1105 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; | 1106 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; |
| 1106 | 1107 |
| 1107 RefPtr<Node> node = start.deprecatedNode(); | 1108 RefPtr<Node> node = start.deprecatedNode(); |
| 1108 while (node) { | 1109 while (node) { |
| 1109 RefPtr<Node> next; | 1110 RefPtr<Node> next; |
| 1110 if (editingIgnoresContent(node.get())) { | 1111 if (editingIgnoresContent(node.get())) { |
| 1111 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); | 1112 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); |
| 1112 next = NodeTraversal::nextSkippingChildren(node.get()); | 1113 next = NodeTraversal::nextSkippingChildren(*node); |
| 1113 } else { | 1114 } else { |
| 1114 next = NodeTraversal::next(*node); | 1115 next = NodeTraversal::next(*node); |
| 1115 } | 1116 } |
| 1116 if (node->isHTMLElement() && nodeFullySelected(node.get(), start, end))
{ | 1117 if (node->isHTMLElement() && nodeFullySelected(node.get(), start, end))
{ |
| 1117 RefPtr<HTMLElement> elem = toHTMLElement(node); | 1118 RefPtr<HTMLElement> elem = toHTMLElement(node); |
| 1118 RefPtr<Node> prev = NodeTraversal::previousPostOrder(*elem); | 1119 RefPtr<Node> prev = NodeTraversal::previousPostOrder(*elem); |
| 1119 RefPtr<Node> next = NodeTraversal::next(*elem); | 1120 RefPtr<Node> next = NodeTraversal::next(*elem); |
| 1120 RefPtr<EditingStyle> styleToPushDown; | 1121 RefPtr<EditingStyle> styleToPushDown; |
| 1121 RefPtr<Node> childNode; | 1122 RefPtr<Node> childNode; |
| 1122 if (isStyledInlineElementToRemove(elem.get())) { | 1123 if (isStyledInlineElementToRemove(elem.get())) { |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1546 String textToMove = nextText->data(); | 1547 String textToMove = nextText->data(); |
| 1547 insertTextIntoNode(childText, childText->length(), textToMove); | 1548 insertTextIntoNode(childText, childText->length(), textToMove); |
| 1548 removeNode(next); | 1549 removeNode(next); |
| 1549 // don't move child node pointer. it may want to merge with more text no
des. | 1550 // don't move child node pointer. it may want to merge with more text no
des. |
| 1550 } | 1551 } |
| 1551 | 1552 |
| 1552 updateStartEnd(newStart, newEnd); | 1553 updateStartEnd(newStart, newEnd); |
| 1553 } | 1554 } |
| 1554 | 1555 |
| 1555 } | 1556 } |
| OLD | NEW |