Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp

Issue 1695153002: Editing: Make the |EditingState*| argument of CompositeEditCommand::removeNode mandatory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: ; Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 618 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest or); 629 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest or);
630 630
631 Position embeddingRemoveEnd = end; 631 Position embeddingRemoveEnd = end;
632 if (endUnsplitAncestor && elementFullySelected(*endUnsplitAncestor, remo veStart, end)) 632 if (endUnsplitAncestor && elementFullySelected(*endUnsplitAncestor, remo veStart, end))
633 embeddingRemoveEnd = mostForwardCaretPosition(positionInParentBefore Node(*endUnsplitAncestor)); 633 embeddingRemoveEnd = mostForwardCaretPosition(positionInParentBefore Node(*endUnsplitAncestor));
634 634
635 if (embeddingRemoveEnd != removeStart || embeddingRemoveEnd != end) { 635 if (embeddingRemoveEnd != removeStart || embeddingRemoveEnd != end) {
636 styleWithoutEmbedding = style->copy(); 636 styleWithoutEmbedding = style->copy();
637 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirectio n(); 637 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirectio n();
638 638
639 if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0) 639 if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0) {
640 removeInlineStyle(embeddingStyle.get(), embeddingRemoveStart, em beddingRemoveEnd); 640 removeInlineStyle(embeddingStyle.get(), embeddingRemoveStart, em beddingRemoveEnd, editingState);
641 if (editingState->isAborted())
642 return;
643 }
641 } 644 }
642 } 645 }
643 646
644 removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding.get() : styl e, removeStart, end); 647 removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding.get() : styl e, removeStart, end, editingState);
648 if (editingState->isAborted())
649 return;
645 start = startPosition(); 650 start = startPosition();
646 end = endPosition(); 651 end = endPosition();
647 if (start.isNull() || start.isOrphan() || end.isNull() || end.isOrphan()) 652 if (start.isNull() || start.isOrphan() || end.isNull() || end.isOrphan())
648 return; 653 return;
649 654
650 if (splitStart && mergeStartWithPreviousIfIdentical(start, end)) { 655 if (splitStart) {
656 bool mergeResult = mergeStartWithPreviousIfIdentical(start, end, editing State);
657 if (editingState->isAborted())
658 return;
659 if (splitStart && mergeResult) {
660 start = startPosition();
661 end = endPosition();
662 }
663 }
664
665 if (splitEnd) {
666 mergeEndWithNextIfIdentical(start, end, editingState);
667 if (editingState->isAborted())
668 return;
651 start = startPosition(); 669 start = startPosition();
652 end = endPosition(); 670 end = endPosition();
653 } 671 }
654
655 if (splitEnd) {
656 mergeEndWithNextIfIdentical(start, end);
657 start = startPosition();
658 end = endPosition();
659 }
660 672
661 // update document layout once before running the rest of the function 673 // update document layout once before running the rest of the function
662 // so that we avoid the expense of updating before each and every call 674 // so that we avoid the expense of updating before each and every call
663 // to check a computed style 675 // to check a computed style
664 document().updateLayoutIgnorePendingStylesheets(); 676 document().updateLayoutIgnorePendingStylesheets();
665 677
666 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style; 678 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style;
667 if (hasTextDirection) { 679 if (hasTextDirection) {
668 // Avoid applying the unicode-bidi and direction properties beneath ance stors that already have them. 680 // Avoid applying the unicode-bidi and direction properties beneath ance stors that already have them.
669 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(start.anch orNode(), enclosingBlock(start.anchorNode())); 681 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(start.anch orNode(), enclosingBlock(start.anchorNode()));
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 result = toHTMLElement(n); 1038 result = toHTMLElement(n);
1027 // Should stop at the editable root (cannot cross editing boundary) and 1039 // Should stop at the editable root (cannot cross editing boundary) and
1028 // also stop at the unsplittable element to be consistent with other UAs 1040 // also stop at the unsplittable element to be consistent with other UAs
1029 if (n == unsplittableElement) 1041 if (n == unsplittableElement)
1030 break; 1042 break;
1031 } 1043 }
1032 1044
1033 return result; 1045 return result;
1034 } 1046 }
1035 1047
1036 void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, EditingStyle* sty le) 1048 void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, EditingStyle* sty le, EditingState* editingState)
1037 { 1049 {
1038 ASSERT(node); 1050 ASSERT(node);
1039 1051
1040 node->document().updateLayoutTreeIfNeeded(); 1052 node->document().updateLayoutTreeIfNeeded();
1041 1053
1042 if (!style || style->isEmpty() || !node->layoutObject() || isHTMLIFrameEleme nt(*node)) 1054 if (!style || style->isEmpty() || !node->layoutObject() || isHTMLIFrameEleme nt(*node))
1043 return; 1055 return;
1044 1056
1045 RefPtrWillBeRawPtr<EditingStyle> newInlineStyle = style; 1057 RefPtrWillBeRawPtr<EditingStyle> newInlineStyle = style;
1046 if (node->isHTMLElement() && toHTMLElement(node)->inlineStyle()) { 1058 if (node->isHTMLElement() && toHTMLElement(node)->inlineStyle()) {
1047 newInlineStyle = style->copy(); 1059 newInlineStyle = style->copy();
1048 newInlineStyle->mergeInlineStyleOfElement(toHTMLElement(node), EditingSt yle::OverrideValues); 1060 newInlineStyle->mergeInlineStyleOfElement(toHTMLElement(node), EditingSt yle::OverrideValues);
1049 } 1061 }
1050 1062
1051 // Since addInlineStyleIfNeeded can't add styles to block-flow layout object s, add style attribute instead. 1063 // Since addInlineStyleIfNeeded can't add styles to block-flow layout object s, add style attribute instead.
1052 // FIXME: applyInlineStyleToRange should be used here instead. 1064 // FIXME: applyInlineStyleToRange should be used here instead.
1053 if ((node->layoutObject()->isLayoutBlockFlow() || node->hasChildren()) && no de->isHTMLElement()) { 1065 if ((node->layoutObject()->isLayoutBlockFlow() || node->hasChildren()) && no de->isHTMLElement()) {
1054 setNodeAttribute(toHTMLElement(node), styleAttr, AtomicString(newInlineS tyle->style()->asText())); 1066 setNodeAttribute(toHTMLElement(node), styleAttr, AtomicString(newInlineS tyle->style()->asText()));
1055 return; 1067 return;
1056 } 1068 }
1057 1069
1058 if (node->layoutObject()->isText() && toLayoutText(node->layoutObject())->is AllCollapsibleWhitespace()) 1070 if (node->layoutObject()->isText() && toLayoutText(node->layoutObject())->is AllCollapsibleWhitespace())
1059 return; 1071 return;
1060 1072
1061 // We can't wrap node with the styled element here because new styled elemen t will never be removed if we did. 1073 // We can't wrap node with the styled element here because new styled elemen t will never be removed if we did.
1062 // If we modified the child pointer in pushDownInlineStyleAroundNode to poin t to new style element 1074 // If we modified the child pointer in pushDownInlineStyleAroundNode to poin t to new style element
1063 // then we fall into an infinite loop where we keep removing and adding styl ed element wrapping node. 1075 // then we fall into an infinite loop where we keep removing and adding styl ed element wrapping node.
1064 addInlineStyleIfNeeded(newInlineStyle.get(), node, node, DoNotAddStyledEleme nt); 1076 addInlineStyleIfNeeded(newInlineStyle.get(), node, node, editingState, DoNot AddStyledElement);
1065 } 1077 }
1066 1078
1067 void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node* targetNode) 1079 void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node* targetNode, EditingState* editingState)
1068 { 1080 {
1069 HTMLElement* highestAncestor = highestAncestorWithConflictingInlineStyle(sty le, targetNode); 1081 HTMLElement* highestAncestor = highestAncestorWithConflictingInlineStyle(sty le, targetNode);
1070 if (!highestAncestor) 1082 if (!highestAncestor)
1071 return; 1083 return;
1072 1084
1073 // The outer loop is traversing the tree vertically from highestAncestor to targetNode 1085 // The outer loop is traversing the tree vertically from highestAncestor to targetNode
1074 RefPtrWillBeRawPtr<Node> current = highestAncestor; 1086 RefPtrWillBeRawPtr<Node> current = highestAncestor;
1075 // Along the way, styled elements that contain targetNode are removed and ac cumulated into elementsToPushDown. 1087 // Along the way, styled elements that contain targetNode are removed and ac cumulated into elementsToPushDown.
1076 // Each child of the removed element, exclusing ancestors of targetNode, is then wrapped by clones of elements in elementsToPushDown. 1088 // Each child of the removed element, exclusing ancestors of targetNode, is then wrapped by clones of elements in elementsToPushDown.
1077 WillBeHeapVector<RefPtrWillBeMember<Element>> elementsToPushDown; 1089 WillBeHeapVector<RefPtrWillBeMember<Element>> elementsToPushDown;
(...skipping 23 matching lines...) Expand all
1101 // Delete id attribute from the second element because the s ame id cannot be used for more than one element 1113 // Delete id attribute from the second element because the s ame id cannot be used for more than one element
1102 element->removeAttribute(HTMLNames::idAttr); 1114 element->removeAttribute(HTMLNames::idAttr);
1103 if (isHTMLAnchorElement(element)) 1115 if (isHTMLAnchorElement(element))
1104 element->removeAttribute(HTMLNames::nameAttr); 1116 element->removeAttribute(HTMLNames::nameAttr);
1105 surroundNodeRangeWithElement(child, child, wrapper, ASSERT_N O_EDITING_ABORT); 1117 surroundNodeRangeWithElement(child, child, wrapper, ASSERT_N O_EDITING_ABORT);
1106 } 1118 }
1107 } 1119 }
1108 1120
1109 // Apply style to all nodes containing targetNode and their siblings but NOT to targetNode 1121 // Apply style to all nodes containing targetNode and their siblings but NOT to targetNode
1110 // But if we've removed styledElement then go ahead and always apply the style. 1122 // But if we've removed styledElement then go ahead and always apply the style.
1111 if (child != targetNode || styledElement) 1123 if (child != targetNode || styledElement) {
1112 applyInlineStyleToPushDown(child, styleToPushDown.get()); 1124 applyInlineStyleToPushDown(child, styleToPushDown.get(), editing State);
1125 if (editingState->isAborted())
1126 return;
1127 }
1113 1128
1114 // We found the next node for the outer loop (contains targetNode) 1129 // We found the next node for the outer loop (contains targetNode)
1115 // When reached targetNode, stop the outer loop upon the completion of the current inner loop 1130 // When reached targetNode, stop the outer loop upon the completion of the current inner loop
1116 if (child == targetNode || child->contains(targetNode)) 1131 if (child == targetNode || child->contains(targetNode))
1117 current = child; 1132 current = child;
1118 } 1133 }
1119 } 1134 }
1120 } 1135 }
1121 1136
1122 void ApplyStyleCommand::removeInlineStyle(EditingStyle* style, const Position &s tart, const Position &end) 1137 void ApplyStyleCommand::removeInlineStyle(EditingStyle* style, const Position &s tart, const Position &end, EditingState* editingState)
1123 { 1138 {
1124 ASSERT(start.isNotNull()); 1139 ASSERT(start.isNotNull());
1125 ASSERT(end.isNotNull()); 1140 ASSERT(end.isNotNull());
1126 ASSERT(start.inDocument()); 1141 ASSERT(start.inDocument());
1127 ASSERT(end.inDocument()); 1142 ASSERT(end.inDocument());
1128 ASSERT(Position::commonAncestorTreeScope(start, end)); 1143 ASSERT(Position::commonAncestorTreeScope(start, end));
1129 ASSERT(comparePositions(start, end) <= 0); 1144 ASSERT(comparePositions(start, end) <= 0);
1130 // FIXME: We should assert that start/end are not in the middle of a text no de. 1145 // FIXME: We should assert that start/end are not in the middle of a text no de.
1131 1146
1132 Position pushDownStart = mostForwardCaretPosition(start); 1147 Position pushDownStart = mostForwardCaretPosition(start);
1133 // If the pushDownStart is at the end of a text node, then this node is not fully selected. 1148 // If the pushDownStart is at the end of a text node, then this node is not fully selected.
1134 // Move it to the next deep quivalent position to avoid removing the style f rom this node. 1149 // Move it to the next deep quivalent position to avoid removing the style f rom this node.
1135 // e.g. if pushDownStart was at Position("hello", 5) in <b>hello<div>world</ div></b>, we want Position("world", 0) instead. 1150 // e.g. if pushDownStart was at Position("hello", 5) in <b>hello<div>world</ div></b>, we want Position("world", 0) instead.
1136 Node* pushDownStartContainer = pushDownStart.computeContainerNode(); 1151 Node* pushDownStartContainer = pushDownStart.computeContainerNode();
1137 if (pushDownStartContainer && pushDownStartContainer->isTextNode() 1152 if (pushDownStartContainer && pushDownStartContainer->isTextNode()
1138 && pushDownStart.computeOffsetInContainerNode() == pushDownStartContaine r->maxCharacterOffset()) 1153 && pushDownStart.computeOffsetInContainerNode() == pushDownStartContaine r->maxCharacterOffset())
1139 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart); 1154 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart);
1140 Position pushDownEnd = mostBackwardCaretPosition(end); 1155 Position pushDownEnd = mostBackwardCaretPosition(end);
1141 // If pushDownEnd is at the start of a text node, then this node is not full y selected. 1156 // If pushDownEnd is at the start of a text node, then this node is not full y selected.
1142 // Move it to the previous deep equivalent position to avoid removing the st yle from this node. 1157 // Move it to the previous deep equivalent position to avoid removing the st yle from this node.
1143 Node* pushDownEndContainer = pushDownEnd.computeContainerNode(); 1158 Node* pushDownEndContainer = pushDownEnd.computeContainerNode();
1144 if (pushDownEndContainer && pushDownEndContainer->isTextNode() && !pushDownE nd.computeOffsetInContainerNode()) 1159 if (pushDownEndContainer && pushDownEndContainer->isTextNode() && !pushDownE nd.computeOffsetInContainerNode())
1145 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd); 1160 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd);
1146 1161
1147 pushDownInlineStyleAroundNode(style, pushDownStart.anchorNode()); 1162 pushDownInlineStyleAroundNode(style, pushDownStart.anchorNode(), editingStat e);
1148 pushDownInlineStyleAroundNode(style, pushDownEnd.anchorNode()); 1163 if (editingState->isAborted())
1164 return;
1165 pushDownInlineStyleAroundNode(style, pushDownEnd.anchorNode(), editingState) ;
1166 if (editingState->isAborted())
1167 return;
1149 1168
1150 // The s and e variables store the positions used to set the ending selectio n after style removal 1169 // The s and e variables store the positions used to set the ending selectio n after style removal
1151 // takes place. This will help callers to recognize when either the start no de or the end node 1170 // takes place. This will help callers to recognize when either the start no de or the end node
1152 // are removed from the document during the work of this function. 1171 // are removed from the document during the work of this function.
1153 // If pushDownInlineStyleAroundNode has pruned start.anchorNode() or end.anc horNode(), 1172 // If pushDownInlineStyleAroundNode has pruned start.anchorNode() or end.anc horNode(),
1154 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround Node won't prune. 1173 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround Node won't prune.
1155 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; 1174 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start;
1156 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; 1175 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end;
1157 1176
1158 // Current ending selection resetting algorithm assumes |start| and |end| 1177 // Current ending selection resetting algorithm assumes |start| and |end|
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1191 if (e.anchorNode() == elem) { 1210 if (e.anchorNode() == elem) {
1192 // Since elem must have been fully selected, and it is at th e end 1211 // Since elem must have been fully selected, and it is at th e end
1193 // of the selection, it is clear we can set the new e offset to 1212 // of the selection, it is clear we can set the new e offset to
1194 // the max range offset of prev. 1213 // the max range offset of prev.
1195 ASSERT(s.isAfterAnchor() || !offsetIsBeforeLastNodeOffset(s. offsetInContainerNode(), s.computeContainerNode())); 1214 ASSERT(s.isAfterAnchor() || !offsetIsBeforeLastNodeOffset(s. offsetInContainerNode(), s.computeContainerNode()));
1196 e = lastPositionInOrAfterNode(prev.get()); 1215 e = lastPositionInOrAfterNode(prev.get());
1197 } 1216 }
1198 } 1217 }
1199 1218
1200 if (styleToPushDown) { 1219 if (styleToPushDown) {
1201 for (; childNode; childNode = childNode->nextSibling()) 1220 for (; childNode; childNode = childNode->nextSibling()) {
1202 applyInlineStyleToPushDown(childNode.get(), styleToPushDown. get()); 1221 applyInlineStyleToPushDown(childNode.get(), styleToPushDown. get(), editingState);
1222 if (editingState->isAborted())
1223 return;
1224 }
1203 } 1225 }
1204 } 1226 }
1205 if (node == end.anchorNode()) 1227 if (node == end.anchorNode())
1206 break; 1228 break;
1207 node = next; 1229 node = next;
1208 } 1230 }
1209 1231
1210 updateStartEnd(s, e); 1232 updateStartEnd(s, e);
1211 } 1233 }
1212 1234
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1294 { 1316 {
1295 ASSERT(position.isNotNull()); 1317 ASSERT(position.isNotNull());
1296 1318
1297 Node* node = position.computeContainerNode(); 1319 Node* node = position.computeContainerNode();
1298 if (!position.isOffsetInAnchor() || !node->isTextNode()) 1320 if (!position.isOffsetInAnchor() || !node->isTextNode())
1299 return false; 1321 return false;
1300 int offsetInText = position.offsetInContainerNode(); 1322 int offsetInText = position.offsetInContainerNode();
1301 return offsetInText > caretMinOffset(node) && offsetInText < caretMaxOffset( node); 1323 return offsetInText > caretMinOffset(node) && offsetInText < caretMaxOffset( node);
1302 } 1324 }
1303 1325
1304 bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start, const Position& end) 1326 bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position& start, const Position& end, EditingState* editingState)
1305 { 1327 {
1306 Node* startNode = start.computeContainerNode(); 1328 Node* startNode = start.computeContainerNode();
1307 int startOffset = start.computeOffsetInContainerNode(); 1329 int startOffset = start.computeOffsetInContainerNode();
1308 if (startOffset) 1330 if (startOffset)
1309 return false; 1331 return false;
1310 1332
1311 if (isAtomicNode(startNode)) { 1333 if (isAtomicNode(startNode)) {
1312 // note: prior siblings could be unrendered elements. it's silly to miss the 1334 // note: prior siblings could be unrendered elements. it's silly to miss the
1313 // merge opportunity just for that. 1335 // merge opportunity just for that.
1314 if (startNode->previousSibling()) 1336 if (startNode->previousSibling())
1315 return false; 1337 return false;
1316 1338
1317 startNode = startNode->parentNode(); 1339 startNode = startNode->parentNode();
1318 } 1340 }
1319 1341
1320 if (!startNode->isElementNode()) 1342 if (!startNode->isElementNode())
1321 return false; 1343 return false;
1322 1344
1323 Node* previousSibling = startNode->previousSibling(); 1345 Node* previousSibling = startNode->previousSibling();
1324 1346
1325 if (previousSibling && areIdenticalElements(*startNode, *previousSibling)) { 1347 if (previousSibling && areIdenticalElements(*startNode, *previousSibling)) {
1326 Element* previousElement = toElement(previousSibling); 1348 Element* previousElement = toElement(previousSibling);
1327 Element* element = toElement(startNode); 1349 Element* element = toElement(startNode);
1328 Node* startChild = element->firstChild(); 1350 Node* startChild = element->firstChild();
1329 ASSERT(startChild); 1351 ASSERT(startChild);
1330 mergeIdenticalElements(previousElement, element); 1352 mergeIdenticalElements(previousElement, element, editingState);
1353 if (editingState->isAborted())
1354 return false;
1331 1355
1332 int startOffsetAdjustment = startChild->nodeIndex(); 1356 int startOffsetAdjustment = startChild->nodeIndex();
1333 int endOffsetAdjustment = startNode == end.anchorNode() ? startOffsetAdj ustment : 0; 1357 int endOffsetAdjustment = startNode == end.anchorNode() ? startOffsetAdj ustment : 0;
1334 updateStartEnd(Position(startNode, startOffsetAdjustment), 1358 updateStartEnd(Position(startNode, startOffsetAdjustment),
1335 Position(end.anchorNode(), end.computeEditingOffset() + endOffsetAdj ustment)); 1359 Position(end.anchorNode(), end.computeEditingOffset() + endOffsetAdj ustment));
1336 return true; 1360 return true;
1337 } 1361 }
1338 1362
1339 return false; 1363 return false;
1340 } 1364 }
1341 1365
1342 bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const Position& end) 1366 bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const Position& end, EditingState* editingState)
1343 { 1367 {
1344 Node* endNode = end.computeContainerNode(); 1368 Node* endNode = end.computeContainerNode();
1345 1369
1346 if (isAtomicNode(endNode)) { 1370 if (isAtomicNode(endNode)) {
1347 int endOffset = end.computeOffsetInContainerNode(); 1371 int endOffset = end.computeOffsetInContainerNode();
1348 if (offsetIsBeforeLastNodeOffset(endOffset, endNode)) 1372 if (offsetIsBeforeLastNodeOffset(endOffset, endNode))
1349 return false; 1373 return false;
1350 1374
1351 if (end.anchorNode()->nextSibling()) 1375 if (end.anchorNode()->nextSibling())
1352 return false; 1376 return false;
1353 1377
1354 endNode = end.anchorNode()->parentNode(); 1378 endNode = end.anchorNode()->parentNode();
1355 } 1379 }
1356 1380
1357 if (!endNode->isElementNode() || isHTMLBRElement(*endNode)) 1381 if (!endNode->isElementNode() || isHTMLBRElement(*endNode))
1358 return false; 1382 return false;
1359 1383
1360 Node* nextSibling = endNode->nextSibling(); 1384 Node* nextSibling = endNode->nextSibling();
1361 if (nextSibling && areIdenticalElements(*endNode, *nextSibling)) { 1385 if (nextSibling && areIdenticalElements(*endNode, *nextSibling)) {
1362 Element* nextElement = toElement(nextSibling); 1386 Element* nextElement = toElement(nextSibling);
1363 Element* element = toElement(endNode); 1387 Element* element = toElement(endNode);
1364 Node* nextChild = nextElement->firstChild(); 1388 Node* nextChild = nextElement->firstChild();
1365 1389
1366 mergeIdenticalElements(element, nextElement); 1390 mergeIdenticalElements(element, nextElement, editingState);
1391 if (editingState->isAborted())
1392 return false;
1367 1393
1368 bool shouldUpdateStart = start.computeContainerNode() == endNode; 1394 bool shouldUpdateStart = start.computeContainerNode() == endNode;
1369 int endOffset = nextChild ? nextChild->nodeIndex() : nextElement->childN odes()->length(); 1395 int endOffset = nextChild ? nextChild->nodeIndex() : nextElement->childN odes()->length();
1370 updateStartEnd(shouldUpdateStart ? Position(nextElement, start.offsetInC ontainerNode()) : start, 1396 updateStartEnd(shouldUpdateStart ? Position(nextElement, start.offsetInC ontainerNode()) : start,
1371 Position(nextElement, endOffset)); 1397 Position(nextElement, endOffset));
1372 return true; 1398 return true;
1373 } 1399 }
1374 1400
1375 return false; 1401 return false;
1376 } 1402 }
(...skipping 19 matching lines...) Expand all
1396 return; 1422 return;
1397 } 1423 }
1398 if (node == endNode) 1424 if (node == endNode)
1399 break; 1425 break;
1400 node = next; 1426 node = next;
1401 } 1427 }
1402 1428
1403 RefPtrWillBeRawPtr<Node> nextSibling = element->nextSibling(); 1429 RefPtrWillBeRawPtr<Node> nextSibling = element->nextSibling();
1404 RefPtrWillBeRawPtr<Node> previousSibling = element->previousSibling(); 1430 RefPtrWillBeRawPtr<Node> previousSibling = element->previousSibling();
1405 if (nextSibling && nextSibling->isElementNode() && nextSibling->hasEditableS tyle() 1431 if (nextSibling && nextSibling->isElementNode() && nextSibling->hasEditableS tyle()
1406 && areIdenticalElements(*element, toElement(*nextSibling))) 1432 && areIdenticalElements(*element, toElement(*nextSibling))) {
1407 mergeIdenticalElements(element.get(), toElement(nextSibling)); 1433 mergeIdenticalElements(element.get(), toElement(nextSibling), editingSta te);
1434 if (editingState->isAborted())
1435 return;
1436 }
1408 1437
1409 if (previousSibling && previousSibling->isElementNode() && previousSibling-> hasEditableStyle()) { 1438 if (previousSibling && previousSibling->isElementNode() && previousSibling-> hasEditableStyle()) {
1410 Node* mergedElement = previousSibling->nextSibling(); 1439 Node* mergedElement = previousSibling->nextSibling();
1411 if (mergedElement->isElementNode() && mergedElement->hasEditableStyle() 1440 if (mergedElement->isElementNode() && mergedElement->hasEditableStyle()
1412 && areIdenticalElements(toElement(*previousSibling), toElement(*merg edElement))) 1441 && areIdenticalElements(toElement(*previousSibling), toElement(*merg edElement))) {
1413 mergeIdenticalElements(toElement(previousSibling), toElement(mergedE lement)); 1442 mergeIdenticalElements(toElement(previousSibling), toElement(mergedE lement), editingState);
1443 if (editingState->isAborted())
1444 return;
1445 }
1414 } 1446 }
1415 1447
1416 // FIXME: We should probably call updateStartEnd if the start or end was in the node 1448 // FIXME: We should probably call updateStartEnd if the start or end was in the node
1417 // range so that the endingSelection() is canonicalized. See the comments a t the end of 1449 // range so that the endingSelection() is canonicalized. See the comments a t the end of
1418 // VisibleSelection::validate(). 1450 // VisibleSelection::validate().
1419 } 1451 }
1420 1452
1421 void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElemen t* block) 1453 void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElemen t* block)
1422 { 1454 {
1423 // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for 1455 // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for
1424 // inline content. 1456 // inline content.
1425 if (!block) 1457 if (!block)
1426 return; 1458 return;
1427 1459
1428 String cssStyle = styleChange.cssStyle(); 1460 String cssStyle = styleChange.cssStyle();
1429 StringBuilder cssText; 1461 StringBuilder cssText;
1430 cssText.append(cssStyle); 1462 cssText.append(cssStyle);
1431 if (const StylePropertySet* decl = block->inlineStyle()) { 1463 if (const StylePropertySet* decl = block->inlineStyle()) {
1432 if (!cssStyle.isEmpty()) 1464 if (!cssStyle.isEmpty())
1433 cssText.append(' '); 1465 cssText.append(' ');
1434 cssText.append(decl->asText()); 1466 cssText.append(decl->asText());
1435 } 1467 }
1436 setNodeAttribute(block, styleAttr, cssText.toAtomicString()); 1468 setNodeAttribute(block, styleAttr, cssText.toAtomicString());
1437 } 1469 }
1438 1470
1439 void ApplyStyleCommand::addInlineStyleIfNeeded(EditingStyle* style, PassRefPtrWi llBeRawPtr<Node> passedStart, PassRefPtrWillBeRawPtr<Node> passedEnd, EAddStyled Element addStyledElement) 1471 void ApplyStyleCommand::addInlineStyleIfNeeded(EditingStyle* style, PassRefPtrWi llBeRawPtr<Node> passedStart, PassRefPtrWillBeRawPtr<Node> passedEnd, EditingSta te* editingState, EAddStyledElement addStyledElement)
1440 { 1472 {
1441 if (!passedStart || !passedEnd || !passedStart->inDocument() || !passedEnd-> inDocument()) 1473 if (!passedStart || !passedEnd || !passedStart->inDocument() || !passedEnd-> inDocument())
1442 return; 1474 return;
1443 1475
1444 RefPtrWillBeRawPtr<Node> start = passedStart; 1476 RefPtrWillBeRawPtr<Node> start = passedStart;
1445 RefPtrWillBeMember<HTMLSpanElement> dummyElement = nullptr; 1477 RefPtrWillBeMember<HTMLSpanElement> dummyElement = nullptr;
1446 StyleChange styleChange(style, positionToComputeInlineStyleChange(start, dum myElement)); 1478 StyleChange styleChange(style, positionToComputeInlineStyleChange(start, dum myElement));
1447 1479
1448 if (dummyElement) 1480 if (dummyElement) {
1449 removeNode(dummyElement); 1481 removeNode(dummyElement, editingState);
1482 if (editingState->isAborted())
1483 return;
1484 }
1450 1485
1451 applyInlineStyleChange(start, passedEnd, styleChange, addStyledElement, ASSE RT_NO_EDITING_ABORT); 1486 applyInlineStyleChange(start, passedEnd, styleChange, addStyledElement, edit ingState);
1452 } 1487 }
1453 1488
1454 Position ApplyStyleCommand::positionToComputeInlineStyleChange(PassRefPtrWillBeR awPtr<Node> startNode, RefPtrWillBeMember<HTMLSpanElement>& dummyElement) 1489 Position ApplyStyleCommand::positionToComputeInlineStyleChange(PassRefPtrWillBeR awPtr<Node> startNode, RefPtrWillBeMember<HTMLSpanElement>& dummyElement)
1455 { 1490 {
1456 // It's okay to obtain the style at the startNode because we've removed all relevant styles from the current run. 1491 // It's okay to obtain the style at the startNode because we've removed all relevant styles from the current run.
1457 if (!startNode->isElementNode()) { 1492 if (!startNode->isElementNode()) {
1458 dummyElement = HTMLSpanElement::create(document()); 1493 dummyElement = HTMLSpanElement::create(document());
1459 insertNodeAt(dummyElement, positionBeforeNode(startNode.get())); 1494 insertNodeAt(dummyElement, positionBeforeNode(startNode.get()));
1460 return positionBeforeNode(dummyElement.get()); 1495 return positionBeforeNode(dummyElement.get());
1461 } 1496 }
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
1610 if (!next || !next->isTextNode()) 1645 if (!next || !next->isTextNode())
1611 continue; 1646 continue;
1612 1647
1613 Text* nextText = toText(next); 1648 Text* nextText = toText(next);
1614 if (start.isOffsetInAnchor() && next == start.computeContainerNode()) 1649 if (start.isOffsetInAnchor() && next == start.computeContainerNode())
1615 newStart = Position(childText, childText->length() + start.offsetInC ontainerNode()); 1650 newStart = Position(childText, childText->length() + start.offsetInC ontainerNode());
1616 if (end.isOffsetInAnchor() && next == end.computeContainerNode()) 1651 if (end.isOffsetInAnchor() && next == end.computeContainerNode())
1617 newEnd = Position(childText, childText->length() + end.offsetInConta inerNode()); 1652 newEnd = Position(childText, childText->length() + end.offsetInConta inerNode());
1618 String textToMove = nextText->data(); 1653 String textToMove = nextText->data();
1619 insertTextIntoNode(childText, childText->length(), textToMove); 1654 insertTextIntoNode(childText, childText->length(), textToMove);
1620 removeNode(next); 1655 // Removing a Text node doesn't dispatch synchronous events.
1656 removeNode(next, ASSERT_NO_EDITING_ABORT);
1621 // don't move child node pointer. it may want to merge with more text no des. 1657 // don't move child node pointer. it may want to merge with more text no des.
1622 } 1658 }
1623 1659
1624 updateStartEnd(newStart, newEnd); 1660 updateStartEnd(newStart, newEnd);
1625 } 1661 }
1626 1662
1627 DEFINE_TRACE(ApplyStyleCommand) 1663 DEFINE_TRACE(ApplyStyleCommand)
1628 { 1664 {
1629 visitor->trace(m_style); 1665 visitor->trace(m_style);
1630 visitor->trace(m_start); 1666 visitor->trace(m_start);
1631 visitor->trace(m_end); 1667 visitor->trace(m_end);
1632 visitor->trace(m_styledInlineElement); 1668 visitor->trace(m_styledInlineElement);
1633 CompositeEditCommand::trace(visitor); 1669 CompositeEditCommand::trace(visitor);
1634 } 1670 }
1635 1671
1636 } // namespace blink 1672 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698