| 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 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 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. |
| 361 startNode = NodeTraversal::next(startNode); | 362 startNode = NodeTraversal::next(*startNode); |
| 362 | 363 |
| 363 // Store away font size before making any changes to the document. | 364 // Store away font size before making any changes to the document. |
| 364 // This ensures that changes to one node won't effect another. | 365 // This ensures that changes to one node won't effect another. |
| 365 HashMap<Node*, float> startingFontSizes; | 366 HashMap<Node*, float> startingFontSizes; |
| 366 for (Node *node = startNode; node != beyondEnd; node = NodeTraversal::next(n
ode)) | 367 for (Node* node = startNode; node != beyondEnd; node = NodeTraversal::next(*
node)) |
| 367 startingFontSizes.set(node, computedFontSize(node)); | 368 startingFontSizes.set(node, computedFontSize(node)); |
| 368 | 369 |
| 369 // These spans were added by us. If empty after font size changes, they can
be removed. | 370 // These spans were added by us. If empty after font size changes, they can
be removed. |
| 370 Vector<RefPtr<HTMLElement> > unstyledSpans; | 371 Vector<RefPtr<HTMLElement> > unstyledSpans; |
| 371 | 372 |
| 372 Node* lastStyledNode = 0; | 373 Node* lastStyledNode = 0; |
| 373 for (Node* node = startNode; node != beyondEnd; node = NodeTraversal::next(n
ode)) { | 374 for (Node* node = startNode; node != beyondEnd; node = NodeTraversal::next(*
node)) { |
| 374 RefPtr<HTMLElement> element; | 375 RefPtr<HTMLElement> element; |
| 375 if (node->isHTMLElement()) { | 376 if (node->isHTMLElement()) { |
| 376 // Only work on fully selected nodes. | 377 // Only work on fully selected nodes. |
| 377 if (!nodeFullySelected(node, start, end)) | 378 if (!nodeFullySelected(node, start, end)) |
| 378 continue; | 379 continue; |
| 379 element = toHTMLElement(node); | 380 element = toHTMLElement(node); |
| 380 } else if (node->isTextNode() && node->renderer() && node->parentNode()
!= lastStyledNode) { | 381 } else if (node->isTextNode() && node->renderer() && node->parentNode()
!= lastStyledNode) { |
| 381 // Last styled node was not parent node of this text node, but we wi
sh to style this | 382 // Last styled node was not parent node of this text node, but we wi
sh to style this |
| 382 // text node. To make this possible, add a style span to surround th
is text node. | 383 // text node. To make this possible, add a style span to surround th
is text node. |
| 383 RefPtr<HTMLElement> span = createStyleSpanElement(document()); | 384 RefPtr<HTMLElement> span = createStyleSpanElement(document()); |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 | 666 |
| 666 // Remove dummy style spans created by splitting text elements. | 667 // Remove dummy style spans created by splitting text elements. |
| 667 cleanupUnstyledAppleStyleSpans(startDummySpanAncestor.get()); | 668 cleanupUnstyledAppleStyleSpans(startDummySpanAncestor.get()); |
| 668 if (endDummySpanAncestor != startDummySpanAncestor) | 669 if (endDummySpanAncestor != startDummySpanAncestor) |
| 669 cleanupUnstyledAppleStyleSpans(endDummySpanAncestor.get()); | 670 cleanupUnstyledAppleStyleSpans(endDummySpanAncestor.get()); |
| 670 } | 671 } |
| 671 | 672 |
| 672 void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const P
osition& start, const Position& end) | 673 void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const P
osition& start, const Position& end) |
| 673 { | 674 { |
| 674 Node* startNode = start.deprecatedNode(); | 675 Node* startNode = start.deprecatedNode(); |
| 676 ASSERT(startNode); |
| 675 | 677 |
| 676 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode()
)) { | 678 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode()
)) { |
| 677 startNode = NodeTraversal::next(startNode); | 679 startNode = NodeTraversal::next(*startNode); |
| 678 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) | 680 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) |
| 679 return; | 681 return; |
| 680 } | 682 } |
| 681 | 683 |
| 682 Node* pastEndNode = end.deprecatedNode(); | 684 Node* pastEndNode = end.deprecatedNode(); |
| 683 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode())) | 685 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode())) |
| 684 pastEndNode = NodeTraversal::nextSkippingChildren(end.deprecatedNode()); | 686 pastEndNode = NodeTraversal::nextSkippingChildren(end.deprecatedNode()); |
| 685 | 687 |
| 686 // 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 |
| 687 // if they want style applied to the empty line. | 689 // if they want style applied to the empty line. |
| 688 if (start == end && start.deprecatedNode()->hasTagName(brTag)) | 690 if (start == end && start.deprecatedNode()->hasTagName(brTag)) |
| 689 pastEndNode = NodeTraversal::next(start.deprecatedNode()); | 691 pastEndNode = NodeTraversal::next(*start.deprecatedNode()); |
| 690 | 692 |
| 691 // 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. |
| 692 // 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 |
| 693 // 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> |
| 694 RefPtr<Range> range = Range::create(startNode->document(), start, end); | 696 RefPtr<Range> range = Range::create(startNode->document(), start, end); |
| 695 Element* editableRoot = startNode->rootEditableElement(); | 697 Element* editableRoot = startNode->rootEditableElement(); |
| 696 if (startNode != editableRoot) { | 698 if (startNode != editableRoot) { |
| 697 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(startNode->parentNode(), range.get())) | 699 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(startNode->parentNode(), range.get())) |
| 698 startNode = startNode->parentNode(); | 700 startNode = startNode->parentNode(); |
| 699 } | 701 } |
| 700 | 702 |
| 701 applyInlineStyleToNodeRange(style, startNode, pastEndNode); | 703 applyInlineStyleToNodeRange(style, startNode, pastEndNode); |
| 702 } | 704 } |
| 703 | 705 |
| 704 static bool containsNonEditableRegion(Node* node) | 706 static bool containsNonEditableRegion(Node* node) |
| 705 { | 707 { |
| 706 if (!node->rendererIsEditable()) | 708 if (!node->rendererIsEditable()) |
| 707 return true; | 709 return true; |
| 708 | 710 |
| 709 Node* sibling = NodeTraversal::nextSkippingChildren(node); | 711 Node* sibling = NodeTraversal::nextSkippingChildren(node); |
| 710 for (Node* descendent = node->firstChild(); descendent && descendent != sibl
ing; descendent = NodeTraversal::next(descendent)) { | 712 for (Node* descendent = node->firstChild(); descendent && descendent != sibl
ing; descendent = NodeTraversal::next(*descendent)) { |
| 711 if (!descendent->rendererIsEditable()) | 713 if (!descendent->rendererIsEditable()) |
| 712 return true; | 714 return true; |
| 713 } | 715 } |
| 714 | 716 |
| 715 return false; | 717 return false; |
| 716 } | 718 } |
| 717 | 719 |
| 718 struct InlineRunToApplyStyle { | 720 struct InlineRunToApplyStyle { |
| 719 InlineRunToApplyStyle(Node* start, Node* end, Node* pastEndNode) | 721 InlineRunToApplyStyle(Node* start, Node* end, Node* pastEndNode) |
| 720 : start(start) | 722 : start(start) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 740 void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, PassRef
Ptr<Node> startNode, PassRefPtr<Node> pastEndNode) | 742 void ApplyStyleCommand::applyInlineStyleToNodeRange(EditingStyle* style, PassRef
Ptr<Node> startNode, PassRefPtr<Node> pastEndNode) |
| 741 { | 743 { |
| 742 if (m_removeOnly) | 744 if (m_removeOnly) |
| 743 return; | 745 return; |
| 744 | 746 |
| 745 document().updateLayoutIgnorePendingStylesheets(); | 747 document().updateLayoutIgnorePendingStylesheets(); |
| 746 | 748 |
| 747 Vector<InlineRunToApplyStyle> runs; | 749 Vector<InlineRunToApplyStyle> runs; |
| 748 RefPtr<Node> node = startNode; | 750 RefPtr<Node> node = startNode; |
| 749 for (RefPtr<Node> next; node && node != pastEndNode; node = next) { | 751 for (RefPtr<Node> next; node && node != pastEndNode; node = next) { |
| 750 next = NodeTraversal::next(node.get()); | 752 next = NodeTraversal::next(*node); |
| 751 | 753 |
| 752 if (!node->renderer() || !node->rendererIsEditable()) | 754 if (!node->renderer() || !node->rendererIsEditable()) |
| 753 continue; | 755 continue; |
| 754 | 756 |
| 755 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { | 757 if (!node->rendererIsRichlyEditable() && node->isHTMLElement()) { |
| 756 // 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. |
| 757 // 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 |
| 758 // node isn't fully selected. | 760 // node isn't fully selected. |
| 759 if (pastEndNode && pastEndNode->isDescendantOf(node.get())) | 761 if (pastEndNode && pastEndNode->isDescendantOf(node.get())) |
| 760 break; | 762 break; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 bool ApplyStyleCommand::isStyledInlineElementToRemove(Element* element) const | 823 bool ApplyStyleCommand::isStyledInlineElementToRemove(Element* element) const |
| 822 { | 824 { |
| 823 return (m_styledInlineElement && element->hasTagName(m_styledInlineElement->
tagQName())) | 825 return (m_styledInlineElement && element->hasTagName(m_styledInlineElement->
tagQName())) |
| 824 || (m_isInlineElementToRemoveFunction && m_isInlineElementToRemoveFuncti
on(element)); | 826 || (m_isInlineElementToRemoveFunction && m_isInlineElementToRemoveFuncti
on(element)); |
| 825 } | 827 } |
| 826 | 828 |
| 827 bool ApplyStyleCommand::shouldApplyInlineStyleToRun(EditingStyle* style, Node* r
unStart, Node* pastEndNode) | 829 bool ApplyStyleCommand::shouldApplyInlineStyleToRun(EditingStyle* style, Node* r
unStart, Node* pastEndNode) |
| 828 { | 830 { |
| 829 ASSERT(style && runStart); | 831 ASSERT(style && runStart); |
| 830 | 832 |
| 831 for (Node* node = runStart; node && node != pastEndNode; node = NodeTraversa
l::next(node)) { | 833 for (Node* node = runStart; node && node != pastEndNode; node = NodeTraversa
l::next(*node)) { |
| 832 if (node->childNodeCount()) | 834 if (node->childNodeCount()) |
| 833 continue; | 835 continue; |
| 834 // We don't consider m_isInlineElementToRemoveFunction here because we n
ever apply style when m_isInlineElementToRemoveFunction is specified | 836 // We don't consider m_isInlineElementToRemoveFunction here because we n
ever apply style when m_isInlineElementToRemoveFunction is specified |
| 835 if (!style->styleIsPresentInComputedStyleOfNode(node)) | 837 if (!style->styleIsPresentInComputedStyleOfNode(node)) |
| 836 return true; | 838 return true; |
| 837 if (m_styledInlineElement && !enclosingNodeWithTag(positionBeforeNode(no
de), m_styledInlineElement->tagQName())) | 839 if (m_styledInlineElement && !enclosingNodeWithTag(positionBeforeNode(no
de), m_styledInlineElement->tagQName())) |
| 838 return true; | 840 return true; |
| 839 } | 841 } |
| 840 return false; | 842 return false; |
| 841 } | 843 } |
| 842 | 844 |
| 843 void ApplyStyleCommand::removeConflictingInlineStyleFromRun(EditingStyle* style,
RefPtr<Node>& runStart, RefPtr<Node>& runEnd, PassRefPtr<Node> pastEndNode) | 845 void ApplyStyleCommand::removeConflictingInlineStyleFromRun(EditingStyle* style,
RefPtr<Node>& runStart, RefPtr<Node>& runEnd, PassRefPtr<Node> pastEndNode) |
| 844 { | 846 { |
| 845 ASSERT(runStart && runEnd); | 847 ASSERT(runStart && runEnd); |
| 846 RefPtr<Node> next = runStart; | 848 RefPtr<Node> next = runStart; |
| 847 for (RefPtr<Node> node = next; node && node->inDocument() && node != pastEnd
Node; node = next) { | 849 for (RefPtr<Node> node = next; node && node->inDocument() && node != pastEnd
Node; node = next) { |
| 848 if (editingIgnoresContent(node.get())) { | 850 if (editingIgnoresContent(node.get())) { |
| 849 ASSERT(!node->contains(pastEndNode.get())); | 851 ASSERT(!node->contains(pastEndNode.get())); |
| 850 next = NodeTraversal::nextSkippingChildren(node.get()); | 852 next = NodeTraversal::nextSkippingChildren(node.get()); |
| 851 } else | 853 } else { |
| 852 next = NodeTraversal::next(node.get()); | 854 next = NodeTraversal::next(*node); |
| 855 } |
| 853 if (!node->isHTMLElement()) | 856 if (!node->isHTMLElement()) |
| 854 continue; | 857 continue; |
| 855 | 858 |
| 856 RefPtr<Node> previousSibling = node->previousSibling(); | 859 RefPtr<Node> previousSibling = node->previousSibling(); |
| 857 RefPtr<Node> nextSibling = node->nextSibling(); | 860 RefPtr<Node> nextSibling = node->nextSibling(); |
| 858 RefPtr<ContainerNode> parent = node->parentNode(); | 861 RefPtr<ContainerNode> parent = node->parentNode(); |
| 859 removeInlineStyleFromElement(style, toHTMLElement(node), RemoveAlways); | 862 removeInlineStyleFromElement(style, toHTMLElement(node), RemoveAlways); |
| 860 if (!node->inDocument()) { | 863 if (!node->inDocument()) { |
| 861 // FIXME: We might need to update the start and the end of current s
election here but need a test. | 864 // FIXME: We might need to update the start and the end of current s
election here but need a test. |
| 862 if (runStart == node) | 865 if (runStart == node) |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; | 1104 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; |
| 1102 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; | 1105 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; |
| 1103 | 1106 |
| 1104 RefPtr<Node> node = start.deprecatedNode(); | 1107 RefPtr<Node> node = start.deprecatedNode(); |
| 1105 while (node) { | 1108 while (node) { |
| 1106 RefPtr<Node> next; | 1109 RefPtr<Node> next; |
| 1107 if (editingIgnoresContent(node.get())) { | 1110 if (editingIgnoresContent(node.get())) { |
| 1108 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); | 1111 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); |
| 1109 next = NodeTraversal::nextSkippingChildren(node.get()); | 1112 next = NodeTraversal::nextSkippingChildren(node.get()); |
| 1110 } else { | 1113 } else { |
| 1111 next = NodeTraversal::next(node.get()); | 1114 next = NodeTraversal::next(*node); |
| 1112 } | 1115 } |
| 1113 if (node->isHTMLElement() && nodeFullySelected(node.get(), start, end))
{ | 1116 if (node->isHTMLElement() && nodeFullySelected(node.get(), start, end))
{ |
| 1114 RefPtr<HTMLElement> elem = toHTMLElement(node); | 1117 RefPtr<HTMLElement> elem = toHTMLElement(node); |
| 1115 RefPtr<Node> prev = NodeTraversal::previousPostOrder(elem.get()); | 1118 RefPtr<Node> prev = NodeTraversal::previousPostOrder(elem.get()); |
| 1116 RefPtr<Node> next = NodeTraversal::next(elem.get()); | 1119 RefPtr<Node> next = NodeTraversal::next(*elem); |
| 1117 RefPtr<EditingStyle> styleToPushDown; | 1120 RefPtr<EditingStyle> styleToPushDown; |
| 1118 RefPtr<Node> childNode; | 1121 RefPtr<Node> childNode; |
| 1119 if (isStyledInlineElementToRemove(elem.get())) { | 1122 if (isStyledInlineElementToRemove(elem.get())) { |
| 1120 styleToPushDown = EditingStyle::create(); | 1123 styleToPushDown = EditingStyle::create(); |
| 1121 childNode = elem->firstChild(); | 1124 childNode = elem->firstChild(); |
| 1122 } | 1125 } |
| 1123 | 1126 |
| 1124 removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styl
eToPushDown.get()); | 1127 removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styl
eToPushDown.get()); |
| 1125 if (!elem->inDocument()) { | 1128 if (!elem->inDocument()) { |
| 1126 if (s.deprecatedNode() == elem) { | 1129 if (s.deprecatedNode() == elem) { |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1543 String textToMove = nextText->data(); | 1546 String textToMove = nextText->data(); |
| 1544 insertTextIntoNode(childText, childText->length(), textToMove); | 1547 insertTextIntoNode(childText, childText->length(), textToMove); |
| 1545 removeNode(next); | 1548 removeNode(next); |
| 1546 // don't move child node pointer. it may want to merge with more text no
des. | 1549 // don't move child node pointer. it may want to merge with more text no
des. |
| 1547 } | 1550 } |
| 1548 | 1551 |
| 1549 updateStartEnd(newStart, newEnd); | 1552 updateStartEnd(newStart, newEnd); |
| 1550 } | 1553 } |
| 1551 | 1554 |
| 1552 } | 1555 } |
| OLD | NEW |