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

Side by Side Diff: Source/WebCore/editing/CompositeEditCommand.cpp

Issue 9565017: Revert 109368 - Merge 107761 (Closed) Base URL: http://svn.webkit.org/repository/webkit/branches/chromium/963/
Patch Set: Created 8 years, 9 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
« no previous file with comments | « LayoutTests/editing/inserting/delete-insignificant-text-crash-expected.txt ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2005, 2006, 2007, 2008 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 10 matching lines...) Expand all
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "config.h" 26 #include "config.h"
27 #include "CompositeEditCommand.h" 27 #include "CompositeEditCommand.h"
28 28
29 #include "AppendNodeCommand.h" 29 #include "AppendNodeCommand.h"
30 #include "ApplyStyleCommand.h" 30 #include "ApplyStyleCommand.h"
31 #include "DeleteButtonController.h"
32 #include "DeleteFromTextNodeCommand.h" 31 #include "DeleteFromTextNodeCommand.h"
33 #include "DeleteSelectionCommand.h" 32 #include "DeleteSelectionCommand.h"
34 #include "Document.h" 33 #include "Document.h"
35 #include "DocumentFragment.h" 34 #include "DocumentFragment.h"
36 #include "DocumentMarkerController.h" 35 #include "DocumentMarkerController.h"
37 #include "EditorInsertAction.h" 36 #include "EditorInsertAction.h"
38 #include "Frame.h" 37 #include "Frame.h"
39 #include "HTMLElement.h" 38 #include "HTMLElement.h"
40 #include "HTMLNames.h" 39 #include "HTMLNames.h"
41 #include "InlineTextBox.h" 40 #include "InlineTextBox.h"
42 #include "InsertIntoTextNodeCommand.h" 41 #include "InsertIntoTextNodeCommand.h"
43 #include "InsertLineBreakCommand.h" 42 #include "InsertLineBreakCommand.h"
44 #include "InsertNodeBeforeCommand.h" 43 #include "InsertNodeBeforeCommand.h"
45 #include "InsertParagraphSeparatorCommand.h" 44 #include "InsertParagraphSeparatorCommand.h"
46 #include "InsertTextCommand.h" 45 #include "InsertTextCommand.h"
47 #include "MergeIdenticalElementsCommand.h" 46 #include "MergeIdenticalElementsCommand.h"
48 #include "Range.h" 47 #include "Range.h"
49 #include "RemoveCSSPropertyCommand.h" 48 #include "RemoveCSSPropertyCommand.h"
50 #include "RemoveNodeCommand.h" 49 #include "RemoveNodeCommand.h"
51 #include "RemoveNodePreservingChildrenCommand.h" 50 #include "RemoveNodePreservingChildrenCommand.h"
52 #include "ReplaceNodeWithSpanCommand.h" 51 #include "ReplaceNodeWithSpanCommand.h"
53 #include "ReplaceSelectionCommand.h" 52 #include "ReplaceSelectionCommand.h"
54 #include "RenderBlock.h" 53 #include "RenderBlock.h"
55 #include "RenderText.h" 54 #include "RenderText.h"
56 #include "ScopedEventQueue.h"
57 #include "SetNodeAttributeCommand.h" 55 #include "SetNodeAttributeCommand.h"
58 #include "SplitElementCommand.h" 56 #include "SplitElementCommand.h"
59 #include "SplitTextNodeCommand.h" 57 #include "SplitTextNodeCommand.h"
60 #include "SplitTextNodeContainingElementCommand.h" 58 #include "SplitTextNodeContainingElementCommand.h"
61 #include "Text.h" 59 #include "Text.h"
62 #include "TextIterator.h" 60 #include "TextIterator.h"
63 #include "WrapContentsInDummySpanCommand.h" 61 #include "WrapContentsInDummySpanCommand.h"
64 #include "htmlediting.h" 62 #include "htmlediting.h"
65 #include "markup.h" 63 #include "markup.h"
66 #include "visible_units.h" 64 #include "visible_units.h"
67 #include <wtf/unicode/CharacterNames.h> 65 #include <wtf/unicode/CharacterNames.h>
68 66
69 using namespace std; 67 using namespace std;
70 68
71 namespace WebCore { 69 namespace WebCore {
72 70
73 using namespace HTMLNames; 71 using namespace HTMLNames;
74 72
75 PassRefPtr<EditCommandComposition> EditCommandComposition::create(Document* docu ment,
76 const VisibleSelection& startingSelection, const VisibleSelection& endingSel ection, EditAction editAction)
77 {
78 return adoptRef(new EditCommandComposition(document, startingSelection, endi ngSelection, editAction));
79 }
80
81 EditCommandComposition::EditCommandComposition(Document* document, const Visible Selection& startingSelection, const VisibleSelection& endingSelection, EditActio n editAction)
82 : m_document(document)
83 , m_startingSelection(startingSelection)
84 , m_endingSelection(endingSelection)
85 , m_startingRootEditableElement(startingSelection.rootEditableElement())
86 , m_endingRootEditableElement(endingSelection.rootEditableElement())
87 , m_editAction(editAction)
88 {
89 }
90
91 void EditCommandComposition::unapply()
92 {
93 ASSERT(m_document);
94 Frame* frame = m_document->frame();
95 ASSERT(frame);
96
97 // Changes to the document may have been made since the last editing operati on that require a layout, as in <rdar://problem/5658603>.
98 // Low level operations, like RemoveNodeCommand, don't require a layout beca use the high level operations that use them perform one
99 // if one is necessary (like for the creation of VisiblePositions).
100 m_document->updateLayoutIgnorePendingStylesheets();
101
102 DeleteButtonController* deleteButtonController = frame->editor()->deleteButt onController();
103 deleteButtonController->disable();
104 size_t size = m_commands.size();
105 for (size_t i = size; i != 0; --i)
106 m_commands[i - 1]->doUnapply();
107 deleteButtonController->enable();
108
109 frame->editor()->unappliedEditing(this);
110 }
111
112 void EditCommandComposition::reapply()
113 {
114 ASSERT(m_document);
115 Frame* frame = m_document->frame();
116 ASSERT(frame);
117
118 // Changes to the document may have been made since the last editing operati on that require a layout, as in <rdar://problem/5658603>.
119 // Low level operations, like RemoveNodeCommand, don't require a layout beca use the high level operations that use them perform one
120 // if one is necessary (like for the creation of VisiblePositions).
121 m_document->updateLayoutIgnorePendingStylesheets();
122
123 DeleteButtonController* deleteButtonController = frame->editor()->deleteButt onController();
124 deleteButtonController->disable();
125 size_t size = m_commands.size();
126 for (size_t i = 0; i != size; ++i)
127 m_commands[i]->doReapply();
128 deleteButtonController->enable();
129
130 frame->editor()->reappliedEditing(this);
131 }
132
133 void EditCommandComposition::append(SimpleEditCommand* command)
134 {
135 m_commands.append(command);
136 }
137
138 void EditCommandComposition::setStartingSelection(const VisibleSelection& select ion)
139 {
140 m_startingSelection = selection;
141 m_startingRootEditableElement = selection.rootEditableElement();
142 }
143
144 void EditCommandComposition::setEndingSelection(const VisibleSelection& selectio n)
145 {
146 m_endingSelection = selection;
147 m_endingRootEditableElement = selection.rootEditableElement();
148 }
149
150 #ifndef NDEBUG
151 void EditCommandComposition::getNodesInCommand(HashSet<Node*>& nodes)
152 {
153 size_t size = m_commands.size();
154 for (size_t i = 0; i < size; ++i)
155 m_commands[i]->getNodesInCommand(nodes);
156 }
157 #endif
158
159 void applyCommand(PassRefPtr<CompositeEditCommand> command)
160 {
161 command->apply();
162 }
163
164 CompositeEditCommand::CompositeEditCommand(Document *document) 73 CompositeEditCommand::CompositeEditCommand(Document *document)
165 : EditCommand(document) 74 : EditCommand(document)
166 { 75 {
167 } 76 }
168 77
169 CompositeEditCommand::~CompositeEditCommand() 78 CompositeEditCommand::~CompositeEditCommand()
170 { 79 {
171 ASSERT(isTopLevelCommand() || !m_composition);
172 } 80 }
173 81
174 void CompositeEditCommand::apply() 82 void CompositeEditCommand::doUnapply()
175 { 83 {
176 if (!endingSelection().isContentRichlyEditable()) { 84 size_t size = m_commands.size();
177 switch (editingAction()) { 85 for (size_t i = size; i != 0; --i)
178 case EditActionTyping: 86 m_commands[i - 1]->unapply();
179 case EditActionPaste:
180 case EditActionDrag:
181 case EditActionSetWritingDirection:
182 case EditActionCut:
183 case EditActionUnspecified:
184 break;
185 default:
186 ASSERT_NOT_REACHED();
187 return;
188 }
189 }
190 ensureComposition();
191
192 // Changes to the document may have been made since the last editing operati on that require a layout, as in <rdar://problem/5658603>.
193 // Low level operations, like RemoveNodeCommand, don't require a layout beca use the high level operations that use them perform one
194 // if one is necessary (like for the creation of VisiblePositions).
195 ASSERT(document());
196 document()->updateLayoutIgnorePendingStylesheets();
197
198 Frame* frame = document()->frame();
199 ASSERT(frame);
200 {
201 EventQueueScope scope;
202 DeleteButtonController* deleteButtonController = frame->editor()->delete ButtonController();
203 deleteButtonController->disable();
204 doApply();
205 deleteButtonController->enable();
206 }
207
208 // Only need to call appliedEditing for top-level commands,
209 // and TypingCommands do it on their own (see TypingCommand::typingAddedToOp enCommand).
210 if (!isTypingCommand())
211 frame->editor()->appliedEditing(this);
212 setShouldRetainAutocorrectionIndicator(false);
213 } 87 }
214 88
215 EditCommandComposition* CompositeEditCommand::ensureComposition() 89 void CompositeEditCommand::doReapply()
216 { 90 {
217 CompositeEditCommand* command = this; 91 size_t size = m_commands.size();
218 while (command && command->parent()) 92 for (size_t i = 0; i != size; ++i)
219 command = command->parent(); 93 m_commands[i]->reapply();
220 if (!command->m_composition)
221 command->m_composition = EditCommandComposition::create(document(), star tingSelection(), endingSelection(), editingAction());
222 return command->m_composition.get();
223 }
224
225 bool CompositeEditCommand::isCreateLinkCommand() const
226 {
227 return false;
228 }
229
230 bool CompositeEditCommand::preservesTypingStyle() const
231 {
232 return false;
233 }
234
235 bool CompositeEditCommand::isTypingCommand() const
236 {
237 return false;
238 }
239
240 bool CompositeEditCommand::shouldRetainAutocorrectionIndicator() const
241 {
242 return false;
243 }
244
245 void CompositeEditCommand::setShouldRetainAutocorrectionIndicator(bool)
246 {
247 } 94 }
248 95
249 // 96 //
250 // sugary-sweet convenience functions to help create and apply edit commands in composite commands 97 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
251 // 98 //
252 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> prpCo mmand) 99 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> cmd)
253 { 100 {
254 RefPtr<EditCommand> command = prpCommand; 101 cmd->setParent(this);
255 command->setParent(this); 102 cmd->apply();
256 command->doApply(); 103 m_commands.append(cmd);
257 if (command->isSimpleEditCommand()) {
258 command->setParent(0);
259 ensureComposition()->append(toSimpleEditCommand(command.get()));
260 }
261 m_commands.append(command.release());
262 } 104 }
263 105
264 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<CompositeEditComma nd> command, const VisibleSelection& selection) 106 void CompositeEditCommand::applyCommandToComposite(PassRefPtr<CompositeEditComma nd> command, const VisibleSelection& selection)
265 { 107 {
266 command->setParent(this); 108 command->setParent(this);
267 if (selection != command->endingSelection()) { 109 if (selection != command->endingSelection()) {
268 command->setStartingSelection(selection); 110 command->setStartingSelection(selection);
269 command->setEndingSelection(selection); 111 command->setEndingSelection(selection);
270 } 112 }
271 command->doApply(); 113 command->apply();
272 m_commands.append(command); 114 m_commands.append(command);
273 } 115 }
274 116
275 void CompositeEditCommand::applyStyle(const EditingStyle* style, EditAction edit ingAction) 117 void CompositeEditCommand::applyStyle(const EditingStyle* style, EditAction edit ingAction)
276 { 118 {
277 applyCommandToComposite(ApplyStyleCommand::create(document(), style, editing Action)); 119 applyCommandToComposite(ApplyStyleCommand::create(document(), style, editing Action));
278 } 120 }
279 121
280 void CompositeEditCommand::applyStyle(const EditingStyle* style, const Position& start, const Position& end, EditAction editingAction) 122 void CompositeEditCommand::applyStyle(const EditingStyle* style, const Position& start, const Position& end, EditAction editingAction)
281 { 123 {
(...skipping 13 matching lines...) Expand all
295 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElem ent) 137 void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElem ent)
296 { 138 {
297 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement)); 139 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement));
298 } 140 }
299 141
300 void CompositeEditCommand::insertLineBreak() 142 void CompositeEditCommand::insertLineBreak()
301 { 143 {
302 applyCommandToComposite(InsertLineBreakCommand::create(document())); 144 applyCommandToComposite(InsertLineBreakCommand::create(document()));
303 } 145 }
304 146
305 bool CompositeEditCommand::isRemovableBlock(const Node* node)
306 {
307 Node* parentNode = node->parentNode();
308 if ((parentNode && parentNode->firstChild() != parentNode->lastChild()) || ! node->hasTagName(divTag))
309 return false;
310
311 if (!node->isElementNode() || !toElement(node)->hasAttributes())
312 return true;
313
314 return false;
315 }
316
317 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRe fPtr<Node> refChild) 147 void CompositeEditCommand::insertNodeBefore(PassRefPtr<Node> insertChild, PassRe fPtr<Node> refChild)
318 { 148 {
319 ASSERT(!refChild->hasTagName(bodyTag)); 149 ASSERT(!refChild->hasTagName(bodyTag));
320 applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChil d)); 150 applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChil d));
321 } 151 }
322 152
323 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRef Ptr<Node> refChild) 153 void CompositeEditCommand::insertNodeAfter(PassRefPtr<Node> insertChild, PassRef Ptr<Node> refChild)
324 { 154 {
325 ASSERT(insertChild); 155 ASSERT(insertChild);
326 ASSERT(refChild); 156 ASSERT(refChild);
(...skipping 22 matching lines...) Expand all
349 Node* child = refChild->firstChild(); 179 Node* child = refChild->firstChild();
350 for (int i = 0; child && i < offset; i++) 180 for (int i = 0; child && i < offset; i++)
351 child = child->nextSibling(); 181 child = child->nextSibling();
352 if (child) 182 if (child)
353 insertNodeBefore(insertChild, child); 183 insertNodeBefore(insertChild, child);
354 else 184 else
355 appendNode(insertChild, static_cast<Element*>(refChild)); 185 appendNode(insertChild, static_cast<Element*>(refChild));
356 } else if (caretMinOffset(refChild) >= offset) 186 } else if (caretMinOffset(refChild) >= offset)
357 insertNodeBefore(insertChild, refChild); 187 insertNodeBefore(insertChild, refChild);
358 else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) { 188 else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) {
359 splitTextNode(toText(refChild), offset); 189 splitTextNode(static_cast<Text *>(refChild), offset);
360 190
361 // Mutation events (bug 22634) from the text node insertion may have rem oved the refChild 191 // Mutation events (bug 22634) from the text node insertion may have rem oved the refChild
362 if (!refChild->inDocument()) 192 if (!refChild->inDocument())
363 return; 193 return;
364 insertNodeBefore(insertChild, refChild); 194 insertNodeBefore(insertChild, refChild);
365 } else 195 } else
366 insertNodeAfter(insertChild, refChild); 196 insertNodeAfter(insertChild, refChild);
367 } 197 }
368 198
369 void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<Containe rNode> parent) 199 void CompositeEditCommand::appendNode(PassRefPtr<Node> node, PassRefPtr<Containe rNode> parent)
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 } 355 }
526 356
527 Node* tabSpan = tabSpanNode(pos.containerNode()); 357 Node* tabSpan = tabSpanNode(pos.containerNode());
528 358
529 if (pos.offsetInContainerNode() <= caretMinOffset(pos.containerNode())) 359 if (pos.offsetInContainerNode() <= caretMinOffset(pos.containerNode()))
530 return positionInParentBeforeNode(tabSpan); 360 return positionInParentBeforeNode(tabSpan);
531 361
532 if (pos.offsetInContainerNode() >= caretMaxOffset(pos.containerNode())) 362 if (pos.offsetInContainerNode() >= caretMaxOffset(pos.containerNode()))
533 return positionInParentAfterNode(tabSpan); 363 return positionInParentAfterNode(tabSpan);
534 364
535 splitTextNodeContainingElement(toText(pos.containerNode()), pos.offsetInCont ainerNode()); 365 splitTextNodeContainingElement(static_cast<Text *>(pos.containerNode()), pos .offsetInContainerNode());
536 return positionInParentBeforeNode(tabSpan); 366 return positionInParentBeforeNode(tabSpan);
537 } 367 }
538 368
539 void CompositeEditCommand::insertNodeAtTabSpanPosition(PassRefPtr<Node> node, co nst Position& pos) 369 void CompositeEditCommand::insertNodeAtTabSpanPosition(PassRefPtr<Node> node, co nst Position& pos)
540 { 370 {
541 // insert node before, after, or at split of tab span 371 // insert node before, after, or at split of tab span
542 insertNodeAt(node, positionOutsideTabSpan(pos)); 372 insertNodeAt(node, positionOutsideTabSpan(pos));
543 } 373 }
544 374
545 void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAft erDelete, bool replace, bool expandForSpecialElements) 375 void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAft erDelete, bool replace, bool expandForSpecialElements)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 { 413 {
584 return containsOnlyWhitespace(text); 414 return containsOnlyWhitespace(text);
585 } 415 }
586 416
587 bool CompositeEditCommand::canRebalance(const Position& position) const 417 bool CompositeEditCommand::canRebalance(const Position& position) const
588 { 418 {
589 Node* node = position.containerNode(); 419 Node* node = position.containerNode();
590 if (position.anchorType() != Position::PositionIsOffsetInAnchor || !node || !node->isTextNode()) 420 if (position.anchorType() != Position::PositionIsOffsetInAnchor || !node || !node->isTextNode())
591 return false; 421 return false;
592 422
593 Text* textNode = toText(node); 423 Text* textNode = static_cast<Text*>(node);
594 if (textNode->length() == 0) 424 if (textNode->length() == 0)
595 return false; 425 return false;
596 426
597 RenderObject* renderer = textNode->renderer(); 427 RenderObject* renderer = textNode->renderer();
598 if (renderer && !renderer->style()->collapseWhiteSpace()) 428 if (renderer && !renderer->style()->collapseWhiteSpace())
599 return false; 429 return false;
600 430
601 return true; 431 return true;
602 } 432 }
603 433
604 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, co usins, etc). 434 // FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, co usins, etc).
605 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position) 435 void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
606 { 436 {
607 Node* node = position.containerNode(); 437 Node* node = position.containerNode();
608 if (!canRebalance(position)) 438 if (!canRebalance(position))
609 return; 439 return;
610 440
611 // If the rebalance is for the single offset, and neither text[offset] nor t ext[offset - 1] are some form of whitespace, do nothing. 441 // If the rebalance is for the single offset, and neither text[offset] nor t ext[offset - 1] are some form of whitespace, do nothing.
612 int offset = position.deprecatedEditingOffset(); 442 int offset = position.deprecatedEditingOffset();
613 String text = toText(node)->data(); 443 String text = static_cast<Text*>(node)->data();
614 if (!isWhitespace(text[offset])) { 444 if (!isWhitespace(text[offset])) {
615 offset--; 445 offset--;
616 if (offset < 0 || !isWhitespace(text[offset])) 446 if (offset < 0 || !isWhitespace(text[offset]))
617 return; 447 return;
618 } 448 }
619 449
620 rebalanceWhitespaceOnTextSubstring(toText(node), position.offsetInContainerN ode(), position.offsetInContainerNode()); 450 rebalanceWhitespaceOnTextSubstring(static_cast<Text*>(node), position.offset InContainerNode(), position.offsetInContainerNode());
621 } 451 }
622 452
623 void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(PassRefPtr<Text> p rpTextNode, int startOffset, int endOffset) 453 void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(PassRefPtr<Text> p rpTextNode, int startOffset, int endOffset)
624 { 454 {
625 RefPtr<Text> textNode = prpTextNode; 455 RefPtr<Text> textNode = prpTextNode;
626 456
627 String text = textNode->data(); 457 String text = textNode->data();
628 ASSERT(!text.isEmpty()); 458 ASSERT(!text.isEmpty());
629 459
630 // Set upstream and downstream to define the extent of the whitespace surrou nding text[offset]. 460 // Set upstream and downstream to define the extent of the whitespace surrou nding text[offset].
(...skipping 21 matching lines...) Expand all
652 482
653 if (string != rebalancedString) 483 if (string != rebalancedString)
654 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length, rebalancedString); 484 replaceTextInNodePreservingMarkers(textNode.release(), upstream, length, rebalancedString);
655 } 485 }
656 486
657 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio n) 487 void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& positio n)
658 { 488 {
659 Node* node = position.deprecatedNode(); 489 Node* node = position.deprecatedNode();
660 if (!node || !node->isTextNode()) 490 if (!node || !node->isTextNode())
661 return; 491 return;
662 Text* textNode = toText(node); 492 Text* textNode = static_cast<Text*>(node);
663 493
664 if (textNode->length() == 0) 494 if (textNode->length() == 0)
665 return; 495 return;
666 RenderObject* renderer = textNode->renderer(); 496 RenderObject* renderer = textNode->renderer();
667 if (renderer && !renderer->style()->collapseWhiteSpace()) 497 if (renderer && !renderer->style()->collapseWhiteSpace())
668 return; 498 return;
669 499
670 // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it . 500 // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it .
671 Position upstreamPos = position.upstream(); 501 Position upstreamPos = position.upstream();
672 deleteInsignificantText(position.upstream(), position.downstream()); 502 deleteInsignificantText(position.upstream(), position.downstream());
673 position = upstreamPos.downstream(); 503 position = upstreamPos.downstream();
674 504
675 VisiblePosition visiblePos(position); 505 VisiblePosition visiblePos(position);
676 VisiblePosition previousVisiblePos(visiblePos.previous()); 506 VisiblePosition previousVisiblePos(visiblePos.previous());
677 Position previous(previousVisiblePos.deepEquivalent()); 507 Position previous(previousVisiblePos.deepEquivalent());
678 508
679 if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous .deprecatedNode()->isTextNode() && !previous.deprecatedNode()->hasTagName(brTag) ) 509 if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous .deprecatedNode()->isTextNode() && !previous.deprecatedNode()->hasTagName(brTag) )
680 replaceTextInNodePreservingMarkers(toText(previous.deprecatedNode()), pr evious.deprecatedEditingOffset(), 1, nonBreakingSpaceString()); 510 replaceTextInNodePreservingMarkers(static_cast<Text*>(previous.deprecate dNode()), previous.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
681 if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.depreca tedNode()->isTextNode() && !position.deprecatedNode()->hasTagName(brTag)) 511 if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.depreca tedNode()->isTextNode() && !position.deprecatedNode()->hasTagName(brTag))
682 replaceTextInNodePreservingMarkers(toText(position.deprecatedNode()), po sition.deprecatedEditingOffset(), 1, nonBreakingSpaceString()); 512 replaceTextInNodePreservingMarkers(static_cast<Text*>(position.deprecate dNode()), position.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
683 } 513 }
684 514
685 void CompositeEditCommand::rebalanceWhitespace() 515 void CompositeEditCommand::rebalanceWhitespace()
686 { 516 {
687 VisibleSelection selection = endingSelection(); 517 VisibleSelection selection = endingSelection();
688 if (selection.isNone()) 518 if (selection.isNone())
689 return; 519 return;
690 520
691 rebalanceWhitespaceAt(selection.start()); 521 rebalanceWhitespaceAt(selection.start());
692 if (selection.isRange()) 522 if (selection.isRange())
693 rebalanceWhitespaceAt(selection.end()); 523 rebalanceWhitespaceAt(selection.end());
694 } 524 }
695 525
696 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, un signed start, unsigned end) 526 void CompositeEditCommand::deleteInsignificantText(PassRefPtr<Text> textNode, un signed start, unsigned end)
697 { 527 {
698 if (!textNode || start >= end) 528 if (!textNode || start >= end)
699 return; 529 return;
700 530
701 document()->updateLayout();
702
703 RenderText* textRenderer = toRenderText(textNode->renderer()); 531 RenderText* textRenderer = toRenderText(textNode->renderer());
704 if (!textRenderer) 532 if (!textRenderer)
705 return; 533 return;
706 534
707 Vector<InlineTextBox*> sortedTextBoxes; 535 Vector<InlineTextBox*> sortedTextBoxes;
708 size_t sortedTextBoxesPosition = 0; 536 size_t sortedTextBoxesPosition = 0;
709 537
710 for (InlineTextBox* textBox = textRenderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) 538 for (InlineTextBox* textBox = textRenderer->firstTextBox(); textBox; textBox = textBox->nextTextBox())
711 sortedTextBoxes.append(textBox); 539 sortedTextBoxes.append(textBox);
712 540
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 } 603 }
776 604
777 void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end) 605 void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end)
778 { 606 {
779 if (start.isNull() || end.isNull()) 607 if (start.isNull() || end.isNull())
780 return; 608 return;
781 609
782 if (comparePositions(start, end) >= 0) 610 if (comparePositions(start, end) >= 0)
783 return; 611 return;
784 612
785 Vector<RefPtr<Text> > nodes; 613 Node* next;
786 for (Node* node = start.deprecatedNode(); node; node = node->traverseNextNod e()) { 614 for (Node* node = start.deprecatedNode(); node; node = next) {
787 if (node->isTextNode()) 615 next = node->traverseNextNode();
788 nodes.append(toText(node)); 616 if (node->isTextNode()) {
617 Text* textNode = static_cast<Text*>(node);
618 int startOffset = node == start.deprecatedNode() ? start.deprecatedE ditingOffset() : 0;
619 int endOffset = node == end.deprecatedNode() ? end.deprecatedEditing Offset() : static_cast<int>(textNode->length());
620 deleteInsignificantText(textNode, startOffset, endOffset);
621 }
789 if (node == end.deprecatedNode()) 622 if (node == end.deprecatedNode())
790 break; 623 break;
791 } 624 }
792
793 for (size_t i = 0; i < nodes.size(); ++i) {
794 Text* textNode = nodes[i].get();
795 int startOffset = textNode == start.deprecatedNode() ? start.deprecatedE ditingOffset() : 0;
796 int endOffset = textNode == end.deprecatedNode() ? end.deprecatedEditing Offset() : static_cast<int>(textNode->length());
797 deleteInsignificantText(textNode, startOffset, endOffset);
798 }
799 } 625 }
800 626
801 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos ) 627 void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos )
802 { 628 {
803 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale nt().downstream(); 629 Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivale nt().downstream();
804 deleteInsignificantText(pos, end); 630 deleteInsignificantText(pos, end);
805 } 631 }
806 632
807 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element > container) 633 PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(PassRefPtr<Element > container)
808 { 634 {
(...skipping 19 matching lines...) Expand all
828 RefPtr<Node> placeholder = createBlockPlaceholderElement(document()); 654 RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
829 insertNodeAt(placeholder, pos); 655 insertNodeAt(placeholder, pos);
830 return placeholder.release(); 656 return placeholder.release();
831 } 657 }
832 658
833 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont ainer) 659 PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Element* cont ainer)
834 { 660 {
835 if (!container) 661 if (!container)
836 return 0; 662 return 0;
837 663
838 document()->updateLayoutIgnorePendingStylesheets(); 664 updateLayout();
839 665
840 RenderObject* renderer = container->renderer(); 666 RenderObject* renderer = container->renderer();
841 if (!renderer || !renderer->isBlockFlow()) 667 if (!renderer || !renderer->isBlockFlow())
842 return 0; 668 return 0;
843 669
844 // append the placeholder to make sure it follows 670 // append the placeholder to make sure it follows
845 // any unrendered blocks 671 // any unrendered blocks
846 RenderBlock* block = toRenderBlock(renderer); 672 RenderBlock* block = toRenderBlock(renderer);
847 if (block->height() == 0 || (block->isListItem() && block->isEmpty())) 673 if (block->height() == 0 || (block->isListItem() && block->isEmpty()))
848 return appendBlockPlaceholder(container); 674 return appendBlockPlaceholder(container);
849 675
850 return 0; 676 return 0;
851 } 677 }
852 678
853 // Assumes that the position is at a placeholder and does the removal without mu ch checking. 679 // Assumes that the position is at a placeholder and does the removal without mu ch checking.
854 void CompositeEditCommand::removePlaceholderAt(const Position& p) 680 void CompositeEditCommand::removePlaceholderAt(const Position& p)
855 { 681 {
856 ASSERT(lineBreakExistsAtPosition(p)); 682 ASSERT(lineBreakExistsAtPosition(p));
857 683
858 // We are certain that the position is at a line break, but it may be a br o r a preserved newline. 684 // We are certain that the position is at a line break, but it may be a br o r a preserved newline.
859 if (p.anchorNode()->hasTagName(brTag)) { 685 if (p.anchorNode()->hasTagName(brTag)) {
860 removeNode(p.anchorNode()); 686 removeNode(p.anchorNode());
861 return; 687 return;
862 } 688 }
863 689
864 deleteTextFromNode(toText(p.anchorNode()), p.offsetInContainerNode(), 1); 690 deleteTextFromNode(static_cast<Text*>(p.anchorNode()), p.offsetInContainerNo de(), 1);
865 } 691 }
866 692
867 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const Position& position) 693 PassRefPtr<Node> CompositeEditCommand::insertNewDefaultParagraphElementAt(const Position& position)
868 { 694 {
869 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document()) ; 695 RefPtr<Element> paragraphElement = createDefaultParagraphElement(document()) ;
870 ExceptionCode ec; 696 ExceptionCode ec;
871 paragraphElement->appendChild(createBreakElement(document()), ec); 697 paragraphElement->appendChild(createBreakElement(document()), ec);
872 insertNodeAt(paragraphElement, position); 698 insertNodeAt(paragraphElement, position);
873 return paragraphElement.release(); 699 return paragraphElement.release();
874 } 700 }
875 701
876 // If the paragraph is not entirely within it's own block, create one and move t he paragraph into 702 // If the paragraph is not entirely within it's own block, create one and move t he paragraph into
877 // it, and return that block. Otherwise return 0. 703 // it, and return that block. Otherwise return 0.
878 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar y(const Position& pos) 704 PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessar y(const Position& pos)
879 { 705 {
880 if (pos.isNull()) 706 if (pos.isNull())
881 return 0; 707 return 0;
882 708
883 document()->updateLayoutIgnorePendingStylesheets(); 709 updateLayout();
884 710
885 // It's strange that this function is responsible for verifying that pos has not been invalidated 711 // It's strange that this function is responsible for verifying that pos has not been invalidated
886 // by an earlier call to this function. The caller, applyBlockStyle, should do this. 712 // by an earlier call to this function. The caller, applyBlockStyle, should do this.
887 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY); 713 VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
888 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos)); 714 VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
889 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos); 715 VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);
890 VisiblePosition next = visibleParagraphEnd.next(); 716 VisiblePosition next = visibleParagraphEnd.next();
891 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd; 717 VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
892 718
893 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream(); 719 Position upstreamStart = visibleParagraphStart.deepEquivalent().upstream();
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1030 removeNodeAndPruneAncestors(node); 856 removeNodeAndPruneAncestors(node);
1031 // If the selection to move was empty and in an empty block that 857 // If the selection to move was empty and in an empty block that
1032 // doesn't require a placeholder to prop itself open (like a bordered 858 // doesn't require a placeholder to prop itself open (like a bordered
1033 // div or an li), remove it during the move (the list removal code 859 // div or an li), remove it during the move (the list removal code
1034 // expects this behavior). 860 // expects this behavior).
1035 else if (isBlock(node)) 861 else if (isBlock(node))
1036 removeNodeAndPruneAncestors(node); 862 removeNodeAndPruneAncestors(node);
1037 else if (lineBreakExistsAtPosition(position)) { 863 else if (lineBreakExistsAtPosition(position)) {
1038 // There is a preserved '\n' at caretAfterDelete. 864 // There is a preserved '\n' at caretAfterDelete.
1039 // We can safely assume this is a text node. 865 // We can safely assume this is a text node.
1040 Text* textNode = toText(node); 866 Text* textNode = static_cast<Text*>(node);
1041 if (textNode->length() == 1) 867 if (textNode->length() == 1)
1042 removeNodeAndPruneAncestors(node); 868 removeNodeAndPruneAncestors(node);
1043 else 869 else
1044 deleteTextFromNode(textNode, position.deprecatedEditingOffset(), 1); 870 deleteTextFromNode(textNode, position.deprecatedEditingOffset(), 1);
1045 } 871 }
1046 } 872 }
1047 } 873 }
1048 874
1049 // This is a version of moveParagraph that preserves style by keeping the origin al markup 875 // This is a version of moveParagraph that preserves style by keeping the origin al markup
1050 // It is currently used only by IndentOutdentCommand but it is meant to be used in the 876 // It is currently used only by IndentOutdentCommand but it is meant to be used in the
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1183 // baz 1009 // baz
1184 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would 1010 // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
1185 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br . 1011 // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br .
1186 // Must recononicalize these two VisiblePositions after the pruning above. 1012 // Must recononicalize these two VisiblePositions after the pruning above.
1187 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent()); 1013 beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
1188 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent()); 1014 afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
1189 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be foreParagraph == afterParagraph)) { 1015 if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || be foreParagraph == afterParagraph)) {
1190 // FIXME: Trim text between beforeParagraph and afterParagraph if they a ren't equal. 1016 // FIXME: Trim text between beforeParagraph and afterParagraph if they a ren't equal.
1191 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival ent()); 1017 insertNodeAt(createBreakElement(document()), beforeParagraph.deepEquival ent());
1192 // Need an updateLayout here in case inserting the br has split a text n ode. 1018 // Need an updateLayout here in case inserting the br has split a text n ode.
1193 document()->updateLayoutIgnorePendingStylesheets(); 1019 updateLayout();
1194 } 1020 }
1195 1021
1196 RefPtr<Range> startToDestinationRange(Range::create(document(), firstPositio nInNode(document()->documentElement()), destination.deepEquivalent().parentAncho redEquivalent())); 1022 RefPtr<Range> startToDestinationRange(Range::create(document(), firstPositio nInNode(document()->documentElement()), destination.deepEquivalent().parentAncho redEquivalent()));
1197 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true); 1023 destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
1198 1024
1199 setEndingSelection(VisibleSelection(destination, originalIsDirectional)); 1025 setEndingSelection(VisibleSelection(destination, originalIsDirectional));
1200 ASSERT(endingSelection().isCaretOrRange()); 1026 ASSERT(endingSelection().isCaretOrRange());
1201 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S electReplacement | ReplaceSelectionCommand::MovingParagraph; 1027 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S electReplacement | ReplaceSelectionCommand::MovingParagraph;
1202 if (!preserveStyle) 1028 if (!preserveStyle)
1203 options |= ReplaceSelectionCommand::MatchStyle; 1029 options |= ReplaceSelectionCommand::MatchStyle;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1323 return false; 1149 return false;
1324 1150
1325 Position caretPos(caret.deepEquivalent().downstream()); 1151 Position caretPos(caret.deepEquivalent().downstream());
1326 // A line break is either a br or a preserved newline. 1152 // A line break is either a br or a preserved newline.
1327 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN ewline())); 1153 ASSERT(caretPos.deprecatedNode()->hasTagName(brTag) || (caretPos.deprecatedN ode()->isTextNode() && caretPos.deprecatedNode()->renderer()->style()->preserveN ewline()));
1328 1154
1329 if (caretPos.deprecatedNode()->hasTagName(brTag)) 1155 if (caretPos.deprecatedNode()->hasTagName(brTag))
1330 removeNodeAndPruneAncestors(caretPos.deprecatedNode()); 1156 removeNodeAndPruneAncestors(caretPos.deprecatedNode());
1331 else if (caretPos.deprecatedNode()->isTextNode()) { 1157 else if (caretPos.deprecatedNode()->isTextNode()) {
1332 ASSERT(caretPos.deprecatedEditingOffset() == 0); 1158 ASSERT(caretPos.deprecatedEditingOffset() == 0);
1333 Text* textNode = toText(caretPos.deprecatedNode()); 1159 Text* textNode = static_cast<Text*>(caretPos.deprecatedNode());
1334 ContainerNode* parentNode = textNode->parentNode(); 1160 ContainerNode* parentNode = textNode->parentNode();
1335 // The preserved newline must be the first thing in the node, since othe rwise the previous 1161 // The preserved newline must be the first thing in the node, since othe rwise the previous
1336 // paragraph would be quoted, and we verified that it wasn't above. 1162 // paragraph would be quoted, and we verified that it wasn't above.
1337 deleteTextFromNode(textNode, 0, 1); 1163 deleteTextFromNode(textNode, 0, 1);
1338 prune(parentNode); 1164 prune(parentNode);
1339 } 1165 }
1340 1166
1341 return true; 1167 return true;
1342 } 1168 }
1343 1169
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 return node.release(); 1254 return node.release();
1429 } 1255 }
1430 1256
1431 PassRefPtr<Element> createBlockPlaceholderElement(Document* document) 1257 PassRefPtr<Element> createBlockPlaceholderElement(Document* document)
1432 { 1258 {
1433 RefPtr<Element> breakNode = document->createElement(brTag, false); 1259 RefPtr<Element> breakNode = document->createElement(brTag, false);
1434 return breakNode.release(); 1260 return breakNode.release();
1435 } 1261 }
1436 1262
1437 } // namespace WebCore 1263 } // namespace WebCore
OLDNEW
« no previous file with comments | « LayoutTests/editing/inserting/delete-insignificant-text-crash-expected.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698