3707381b2fa764d343ddf30484d701b9c1f4bd87
[WebKit-https.git] / WebCore / khtml / editing / htmlediting.cpp
1 /*
2  * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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. 
24  */
25
26 #include "htmlediting.h"
27
28 #include "css_computedstyle.h"
29 #include "css_value.h"
30 #include "css_valueimpl.h"
31 #include "cssparser.h"
32 #include "cssproperties.h"
33 #include "dom_doc.h"
34 #include "dom_docimpl.h"
35 #include "dom_elementimpl.h"
36 #include "dom_nodeimpl.h"
37 #include "dom_position.h"
38 #include "dom_stringimpl.h"
39 #include "dom_textimpl.h"
40 #include "dom2_range.h"
41 #include "dom2_rangeimpl.h"
42 #include "html_elementimpl.h"
43 #include "html_imageimpl.h"
44 #include "html_interchange.h"
45 #include "htmlattrs.h"
46 #include "htmltags.h"
47 #include "khtml_part.h"
48 #include "khtml_part.h"
49 #include "khtmlview.h"
50 #include "qcolor.h"
51 #include "qptrlist.h"
52 #include "render_object.h"
53 #include "render_style.h"
54 #include "render_text.h"
55 #include "visible_position.h"
56 #include "visible_text.h"
57 #include "visible_units.h"
58
59 using DOM::AttrImpl;
60 using DOM::CSSComputedStyleDeclarationImpl;
61 using DOM::CSSMutableStyleDeclarationImpl;
62 using DOM::CSSParser;
63 using DOM::CSSPrimitiveValue;
64 using DOM::CSSPrimitiveValueImpl;
65 using DOM::CSSProperty;
66 using DOM::CSSStyleDeclarationImpl;
67 using DOM::CSSValue;
68 using DOM::CSSValueImpl;
69 using DOM::DocumentFragmentImpl;
70 using DOM::DocumentImpl;
71 using DOM::DOMString;
72 using DOM::DOMStringImpl;
73 using DOM::DoNotUpdateLayout;
74 using DOM::EditingTextImpl;
75 using DOM::ElementImpl;
76 using DOM::HTMLElementImpl;
77 using DOM::HTMLImageElementImpl;
78 using DOM::NamedAttrMapImpl;
79 using DOM::NodeImpl;
80 using DOM::NodeListImpl;
81 using DOM::Position;
82 using DOM::Range;
83 using DOM::RangeImpl;
84 using DOM::TextImpl;
85 using DOM::TreeWalkerImpl;
86
87 #if APPLE_CHANGES
88 #include "KWQAssertions.h"
89 #include "KWQLogging.h"
90 #include "KWQKHTMLPart.h"
91 #else
92 #define ASSERT(assertion) ((void)0)
93 #define ASSERT_WITH_MESSAGE(assertion, formatAndArgs...) ((void)0)
94 #define ASSERT_NOT_REACHED() ((void)0)
95 #define LOG(channel, formatAndArgs...) ((void)0)
96 #define ERROR(formatAndArgs...) ((void)0)
97 #define ASSERT(assertion) assert(assertion)
98 #if LOG_DISABLED
99 #define debugPosition(a,b) ((void)0)
100 #define debugNode(a,b) ((void)0)
101 #endif
102 #endif
103
104 namespace khtml {
105
106 static inline bool isNBSP(const QChar &c)
107 {
108     return c.unicode() == 0xa0;
109 }
110
111 // FIXME: Can't really determine this without taking white-space mode into account.
112 static inline bool nextCharacterIsCollapsibleWhitespace(const Position &pos)
113 {
114     if (!pos.node())
115         return false;
116     if (!pos.node()->isTextNode())
117         return false;
118     return isCollapsibleWhitespace(static_cast<TextImpl *>(pos.node())->data()[pos.offset()]);
119 }
120
121 static const int spacesPerTab = 4;
122
123 bool isTableStructureNode(const NodeImpl *node)
124 {
125     RenderObject *r = node->renderer();
126     return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
127 }
128
129 static bool isListStructureNode(const NodeImpl *node)
130 {
131     // FIXME: Irritating that we can get away with just going at the render tree for isTableStructureNode,
132     // but here we also have to peek at the type of DOM node?
133     RenderObject *r = node->renderer();
134     NodeImpl::Id nodeID = node->id();
135     return (r && r->isListItem())
136         || (nodeID == ID_OL || nodeID == ID_UL || nodeID == ID_DD || nodeID == ID_DT || nodeID == ID_DIR || nodeID == ID_MENU);
137 }
138
139 static DOMString &nonBreakingSpaceString()
140 {
141     static DOMString nonBreakingSpaceString = QString(QChar(0xa0));
142     return nonBreakingSpaceString;
143 }
144
145 static DOMString &matchNearestBlockquoteColorString()
146 {
147     static DOMString matchNearestBlockquoteColorString = "match";
148     return matchNearestBlockquoteColorString;
149 }
150
151 static void derefNodesInList(QPtrList<NodeImpl> &list)
152 {
153     for (QPtrListIterator<NodeImpl> it(list); it.current(); ++it)
154         it.current()->deref();
155 }
156
157 static int maxRangeOffset(NodeImpl *n)
158 {
159     if (DOM::offsetInCharacters(n->nodeType()))
160         return n->maxOffset();
161
162     if (n->isElementNode())
163         return n->childNodeCount();
164
165     return 1;
166 }
167
168 static int maxDeepOffset(NodeImpl *n)
169 {
170     if (n->isAtomicNode())
171         return n->caretMaxOffset();
172
173     if (n->isElementNode())
174         return n->childNodeCount();
175
176     return 1;
177 }
178
179 static void debugPosition(const char *prefix, const Position &pos)
180 {
181     if (!prefix)
182         prefix = "";
183     if (pos.isNull())
184         LOG(Editing, "%s <null>", prefix);
185     else
186         LOG(Editing, "%s%s %p : %d", prefix, pos.node()->nodeName().string().latin1(), pos.node(), pos.offset());
187 }
188
189 static void debugNode(const char *prefix, const NodeImpl *node)
190 {
191     if (!prefix)
192         prefix = "";
193     if (!node)
194         LOG(Editing, "%s <null>", prefix);
195     else
196         LOG(Editing, "%s%s %p", prefix, node->nodeName().string().latin1(), node);
197 }
198
199 static bool isSpecialElement(NodeImpl *n)
200 {
201     if (!n->isHTMLElement())
202         return false;
203
204     if (n->id() == ID_A && n->isLink())
205         return true;
206
207     if (n->id() == ID_UL || n->id() == ID_OL || n->id() == ID_DL)
208         return true;
209
210     RenderObject *renderer = n->renderer();
211
212     if (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE))
213         return true;
214
215     if (renderer && renderer->style()->isFloating())
216         return true;
217
218     if (renderer && renderer->style()->position() != STATIC)
219         return true;
220
221     return false;
222 }
223
224 // This version of the function is meant to be called on positions in a document fragment,
225 // so it does not check for a root editable element, it is assumed these nodes will be put
226 // somewhere editable in the future
227 static bool isFirstVisiblePositionInSpecialElementInFragment(const Position& pos)
228 {
229     VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
230
231     for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
232         if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
233             return false;
234         if (isSpecialElement(n))
235             return true;
236     }
237
238     return false;
239 }
240
241 static bool isFirstVisiblePositionInSpecialElement(const Position& pos)
242 {
243     VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
244
245     for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
246         if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
247             return false;
248         if (n->rootEditableElement() == NULL)
249             return false;
250         if (isSpecialElement(n))
251             return true;
252     }
253
254     return false;
255 }
256
257 static Position positionBeforeNode(NodeImpl *node)
258 {
259     return Position(node->parentNode(), node->nodeIndex());
260 }
261
262 static Position positionBeforeContainingSpecialElement(const Position& pos)
263 {
264     ASSERT(isFirstVisiblePositionInSpecialElement(pos));
265
266     VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
267     
268     NodeImpl *outermostSpecialElement = NULL;
269
270     for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
271         if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
272             break;
273         if (n->rootEditableElement() == NULL)
274             break;
275         if (isSpecialElement(n))
276             outermostSpecialElement = n;
277     }
278     
279     ASSERT(outermostSpecialElement);
280
281     Position result = positionBeforeNode(outermostSpecialElement);
282     if (result.isNull() || !result.node()->rootEditableElement())
283         return pos;
284     
285     return result;
286 }
287
288 static bool isLastVisiblePositionInSpecialElement(const Position& pos)
289 {
290     // make sure to get a range-compliant version of the position
291     Position rangePos = VisiblePosition(pos, DOWNSTREAM).position();
292
293     VisiblePosition vPos = VisiblePosition(rangePos, DOWNSTREAM);
294
295     for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) {
296         if (VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM) != vPos)
297             return false;
298         if (n->rootEditableElement() == NULL)
299             return false;
300         if (isSpecialElement(n))
301             return true;
302     }
303
304     return false;
305 }
306
307 static Position positionAfterNode(NodeImpl *node)
308 {
309     return Position(node->parentNode(), node->nodeIndex() + 1);
310 }
311
312 static Position positionAfterContainingSpecialElement(const Position& pos)
313 {
314     ASSERT(isLastVisiblePositionInSpecialElement(pos));
315
316     // make sure to get a range-compliant version of the position
317     Position rangePos = VisiblePosition(pos, DOWNSTREAM).position();
318
319     VisiblePosition vPos = VisiblePosition(rangePos, DOWNSTREAM);
320
321     NodeImpl *outermostSpecialElement = NULL;
322
323     for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) {
324         if (VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM) != vPos)
325             break;
326         if (n->rootEditableElement() == NULL)
327             break;
328         if (isSpecialElement(n))
329             outermostSpecialElement = n;
330     }
331     
332     ASSERT(outermostSpecialElement);
333
334     Position result = positionAfterNode(outermostSpecialElement);
335     if (result.isNull() || !result.node()->rootEditableElement())
336         return pos;
337     
338     return result;
339 }
340
341 static Position positionOutsideContainingSpecialElement(const Position &pos)
342 {
343     if (isFirstVisiblePositionInSpecialElement(pos)) {
344         return positionBeforeContainingSpecialElement(pos);
345     } else if (isLastVisiblePositionInSpecialElement(pos)) {
346         return positionAfterContainingSpecialElement(pos);
347     }
348
349     return pos;
350 }
351
352 static Position positionBeforePossibleContainingSpecialElement(const Position &pos)
353 {
354     if (isFirstVisiblePositionInSpecialElement(pos)) {
355         return positionBeforeContainingSpecialElement(pos);
356     } 
357
358     return pos;
359 }
360
361 static Position positionAfterPossibleContainingSpecialElement(const Position &pos)
362 {
363     if (isLastVisiblePositionInSpecialElement(pos)) {
364         return positionAfterContainingSpecialElement(pos);
365     }
366
367     return pos;
368 }
369
370 //------------------------------------------------------------------------------------------
371 // DeleteFromTextNodeCommand
372
373 DeleteFromTextNodeCommand::DeleteFromTextNodeCommand(DocumentImpl *document, TextImpl *node, long offset, long count)
374     : EditCommand(document), m_node(node), m_offset(offset), m_count(count)
375 {
376     ASSERT(m_node);
377     ASSERT(m_offset >= 0);
378     ASSERT(m_offset < (long)m_node->length());
379     ASSERT(m_count >= 0);
380     
381     m_node->ref();
382 }
383
384 DeleteFromTextNodeCommand::~DeleteFromTextNodeCommand()
385 {
386     ASSERT(m_node);
387     m_node->deref();
388 }
389
390 void DeleteFromTextNodeCommand::doApply()
391 {
392     ASSERT(m_node);
393
394     int exceptionCode = 0;
395     m_text = m_node->substringData(m_offset, m_count, exceptionCode);
396     ASSERT(exceptionCode == 0);
397     
398     m_node->deleteData(m_offset, m_count, exceptionCode);
399     ASSERT(exceptionCode == 0);
400 }
401
402 void DeleteFromTextNodeCommand::doUnapply()
403 {
404     ASSERT(m_node);
405     ASSERT(!m_text.isEmpty());
406
407     int exceptionCode = 0;
408     m_node->insertData(m_offset, m_text, exceptionCode);
409     ASSERT(exceptionCode == 0);
410 }
411
412 //------------------------------------------------------------------------------------------
413 // DeleteSelectionCommand
414
415 DeleteSelectionCommand::DeleteSelectionCommand(DocumentImpl *document, bool smartDelete, bool mergeBlocksAfterDelete)
416     : CompositeEditCommand(document), 
417       m_hasSelectionToDelete(false), 
418       m_smartDelete(smartDelete), 
419       m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
420       m_startBlock(0),
421       m_endBlock(0),
422       m_startNode(0),
423       m_typingStyle(0)
424 {
425 }
426
427 DeleteSelectionCommand::DeleteSelectionCommand(DocumentImpl *document, const Selection &selection, bool smartDelete, bool mergeBlocksAfterDelete)
428     : CompositeEditCommand(document), 
429       m_hasSelectionToDelete(true), 
430       m_smartDelete(smartDelete), 
431       m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
432       m_selectionToDelete(selection),
433       m_startBlock(0),
434       m_endBlock(0),
435       m_startNode(0),
436       m_typingStyle(0)
437 {
438 }
439
440 void DeleteSelectionCommand::initializePositionData()
441 {
442     //
443     // Handle setting some basic positions
444     //
445     Position start = m_selectionToDelete.start();
446     start = positionOutsideContainingSpecialElement(start);
447     Position end = m_selectionToDelete.end();
448     end = positionOutsideContainingSpecialElement(end);
449
450     m_upstreamStart = positionBeforePossibleContainingSpecialElement(start.upstream());
451     m_downstreamStart = positionBeforePossibleContainingSpecialElement(start.downstream());
452     m_upstreamEnd = positionAfterPossibleContainingSpecialElement(end.upstream());
453     m_downstreamEnd = positionAfterPossibleContainingSpecialElement(end.downstream());
454
455     //
456     // Handle leading and trailing whitespace, as well as smart delete adjustments to the selection
457     //
458     m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.startAffinity());
459     m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
460
461     if (m_smartDelete) {
462     
463         // skip smart delete if the selection to delete already starts or ends with whitespace
464         Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.startAffinity()).deepEquivalent();
465         bool skipSmartDelete = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
466         if (!skipSmartDelete)
467             skipSmartDelete = m_downstreamEnd.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
468
469         // extend selection upstream if there is whitespace there
470         bool hasLeadingWhitespaceBeforeAdjustment = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.startAffinity(), true).isNotNull();
471         if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) {
472             VisiblePosition visiblePos = VisiblePosition(start, m_selectionToDelete.startAffinity()).previous();
473             pos = visiblePos.deepEquivalent();
474             // Expand out one character upstream for smart delete and recalculate
475             // positions based on this change.
476             m_upstreamStart = pos.upstream();
477             m_downstreamStart = pos.downstream();
478             m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(visiblePos.affinity());
479         }
480         
481         // trailing whitespace is only considered for smart delete if there is no leading
482         // whitespace, as in the case where you double-click the first word of a paragraph.
483         if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull()) {
484             // Expand out one character downstream for smart delete and recalculate
485             // positions based on this change.
486             pos = VisiblePosition(end, m_selectionToDelete.endAffinity()).next().deepEquivalent();
487             m_upstreamEnd = pos.upstream();
488             m_downstreamEnd = pos.downstream();
489             m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
490         }
491     }
492     
493     m_trailingWhitespaceValid = true;
494     
495     //
496     // Handle setting start and end blocks and the start node.
497     //
498     m_startBlock = m_downstreamStart.node()->enclosingBlockFlowElement();
499     m_startBlock->ref();
500     m_endBlock = m_upstreamEnd.node()->enclosingBlockFlowElement();
501     m_endBlock->ref();
502     m_startNode = m_upstreamStart.node();
503     m_startNode->ref();
504
505     //
506     // Handle detecting if the line containing the selection end is itself fully selected.
507     // This is one of the tests that determines if block merging of content needs to be done.
508     //
509     VisiblePosition visibleEnd(end, m_selectionToDelete.endAffinity());
510     if (isStartOfParagraph(visibleEnd) || isEndOfParagraph(visibleEnd)) {
511         Position previousLineStart = previousLinePosition(visibleEnd, 0).deepEquivalent();
512         if (previousLineStart.isNull() || RangeImpl::compareBoundaryPoints(previousLineStart, m_downstreamStart) >= 0)
513             m_mergeBlocksAfterDelete = false;
514     }
515
516     debugPosition("m_upstreamStart      ", m_upstreamStart);
517     debugPosition("m_downstreamStart    ", m_downstreamStart);
518     debugPosition("m_upstreamEnd        ", m_upstreamEnd);
519     debugPosition("m_downstreamEnd      ", m_downstreamEnd);
520     debugPosition("m_leadingWhitespace  ", m_leadingWhitespace);
521     debugPosition("m_trailingWhitespace ", m_trailingWhitespace);
522     debugNode(    "m_startBlock         ", m_startBlock);
523     debugNode(    "m_endBlock           ", m_endBlock);    
524     debugNode(    "m_startNode          ", m_startNode);    
525 }
526
527 void DeleteSelectionCommand::insertPlaceholderForAncestorBlockContent()
528 {
529     // This code makes sure a line does not disappear when deleting in this case:
530     // <p>foo</p>bar<p>baz</p>
531     // Select "bar" and hit delete. If nothing is done, the line containing bar will disappear.
532     // It needs to be held open by inserting a placeholder.
533     // Also see:
534     // <rdar://problem/3928305> selecting an entire line and typing over causes new inserted text at top of document
535     //
536     // The checks below detect the case where the selection contains content in an ancestor block 
537     // surrounded by child blocks.
538     //
539     VisiblePosition visibleStart(m_upstreamStart, VP_DEFAULT_AFFINITY);
540     VisiblePosition beforeStart = visibleStart.previous();
541     NodeImpl *startBlock = enclosingBlockFlowElement(visibleStart);
542     NodeImpl *beforeStartBlock = enclosingBlockFlowElement(beforeStart);
543     
544     if (!beforeStart.isNull() &&
545         !inSameBlock(visibleStart, beforeStart) &&
546         beforeStartBlock->isAncestor(startBlock) &&
547         startBlock != m_upstreamStart.node()) {
548
549         VisiblePosition visibleEnd(m_downstreamEnd, VP_DEFAULT_AFFINITY);
550         VisiblePosition afterEnd = visibleEnd.next();
551         
552         if ((!afterEnd.isNull() && !inSameBlock(afterEnd, visibleEnd) && !inSameBlock(afterEnd, visibleStart)) ||
553             (m_downstreamEnd == m_selectionToDelete.end() && isEndOfParagraph(visibleEnd))) {
554             NodeImpl *block = createDefaultParagraphElement(document());
555             insertNodeBefore(block, m_upstreamStart.node());
556             addBlockPlaceholderIfNeeded(block);
557             m_endingPosition = Position(block, 0);
558         }
559     }
560 }
561
562 void DeleteSelectionCommand::saveTypingStyleState()
563 {
564     // Figure out the typing style in effect before the delete is done.
565     // FIXME: Improve typing style.
566     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
567     CSSComputedStyleDeclarationImpl *computedStyle = m_selectionToDelete.start().computedStyle();
568     computedStyle->ref();
569     m_typingStyle = computedStyle->copyInheritableProperties();
570     m_typingStyle->ref();
571     computedStyle->deref();
572 }
573
574 bool DeleteSelectionCommand::handleSpecialCaseBRDelete()
575 {
576     // Check for special-case where the selection contains only a BR on a line by itself after another BR.
577     bool upstreamStartIsBR = m_startNode->id() == ID_BR;
578     bool downstreamStartIsBR = m_downstreamStart.node()->id() == ID_BR;
579     bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.node() == m_upstreamEnd.node();
580     if (isBROnLineByItself) {
581         removeNode(m_downstreamStart.node());
582         m_endingPosition = m_upstreamStart;
583         m_mergeBlocksAfterDelete = false;
584         return true;
585     }
586
587     // Not a special-case delete per se, but we can detect that the merging of content between blocks
588     // should not be done.
589     if (upstreamStartIsBR && downstreamStartIsBR)
590         m_mergeBlocksAfterDelete = false;
591
592     return false;
593 }
594
595 void DeleteSelectionCommand::setStartNode(NodeImpl *node)
596 {
597     NodeImpl *old = m_startNode;
598     m_startNode = node;
599     if (m_startNode)
600         m_startNode->ref();
601     if (old)
602         old->deref();
603 }
604
605 void DeleteSelectionCommand::handleGeneralDelete()
606 {
607     int startOffset = m_upstreamStart.offset();
608     VisiblePosition visibleEnd = VisiblePosition(m_downstreamEnd, m_selectionToDelete.endAffinity());
609     bool endAtEndOfBlock = isEndOfBlock(visibleEnd);
610
611     // Handle some special cases where the selection begins and ends on specific visible units.
612     // Sometimes a node that is actually selected needs to be retained in order to maintain
613     // user expectations for the delete operation. Here is an example:
614     //     1. Open a new Blot or Mail document
615     //     2. hit Return ten times or so
616     //     3. Type a letter (do not hit Return after it)
617     //     4. Type shift-up-arrow to select the line containing the letter and the previous blank line
618     //     5. Hit Delete
619     // You expect the insertion point to wind up at the start of the line where your selection began.
620     // Because of the nature of HTML, the editing code needs to perform a special check to get
621     // this behavior. So:
622     // If the entire start block is selected, and the selection does not extend to the end of the 
623     // end of a block other than the block containing the selection start, then do not delete the 
624     // start block, otherwise delete the start block.
625     // A similar case is provided to cover selections starting in BR elements.
626     if (startOffset == 1 && m_startNode && m_startNode->id() == ID_BR) {
627         setStartNode(m_startNode->traverseNextNode());
628         startOffset = 0;
629     }
630     if (m_startBlock != m_endBlock && startOffset == 0 && m_startNode && m_startNode->id() == ID_BR && endAtEndOfBlock) {
631         // Don't delete the BR element
632         setStartNode(m_startNode->traverseNextNode());
633     }
634     else if (m_startBlock != m_endBlock && isStartOfBlock(VisiblePosition(m_upstreamStart, m_selectionToDelete.startAffinity()))) {
635         if (!m_startBlock->isAncestor(m_endBlock) && !isStartOfBlock(visibleEnd) && endAtEndOfBlock) {
636             // Delete all the children of the block, but not the block itself.
637             setStartNode(m_startBlock->firstChild());
638             startOffset = 0;
639         }
640     }
641     else if (startOffset >= m_startNode->caretMaxOffset() &&
642              (m_startNode->isAtomicNode() || startOffset == 0)) {
643         // Move the start node to the next node in the tree since the startOffset is equal to
644         // or beyond the start node's caretMaxOffset This means there is nothing visible to delete. 
645         // But don't do this if the node is not atomic - we don't want to move into the first child.
646
647         // Also, before moving on, delete any insignificant text that may be present in a text node.
648         if (m_startNode->isTextNode()) {
649             // Delete any insignificant text from this node.
650             TextImpl *text = static_cast<TextImpl *>(m_startNode);
651             if (text->length() > (unsigned)m_startNode->caretMaxOffset())
652                 deleteTextFromNode(text, m_startNode->caretMaxOffset(), text->length() - m_startNode->caretMaxOffset());
653         }
654         
655         // shift the start node to the next
656         setStartNode(m_startNode->traverseNextNode());
657         startOffset = 0;
658     }
659
660     // Done adjusting the start.  See if we're all done.
661     if (!m_startNode)
662         return;
663
664     if (m_startNode == m_downstreamEnd.node()) {
665         // The selection to delete is all in one node.
666         if (!m_startNode->renderer() || 
667             (startOffset == 0 && m_downstreamEnd.offset() >= maxDeepOffset(m_startNode))) {
668             // just delete
669             removeFullySelectedNode(m_startNode);
670         } else if (m_downstreamEnd.offset() - startOffset > 0) {
671             if (m_startNode->isTextNode()) {
672                 // in a text node that needs to be trimmed
673                 TextImpl *text = static_cast<TextImpl *>(m_startNode);
674                 deleteTextFromNode(text, startOffset, m_downstreamEnd.offset() - startOffset);
675                 m_trailingWhitespaceValid = false;
676             } else {
677                 removeChildrenInRange(m_startNode, startOffset, m_downstreamEnd.offset());
678                 m_endingPosition = m_upstreamStart;
679             }
680         }
681     }
682     else {
683         // The selection to delete spans more than one node.
684         NodeImpl *node = m_startNode;
685         
686         if (startOffset > 0) {
687             if (m_startNode->isTextNode()) {
688                 // in a text node that needs to be trimmed
689                 TextImpl *text = static_cast<TextImpl *>(node);
690                 deleteTextFromNode(text, startOffset, text->length() - startOffset);
691                 node = node->traverseNextNode();
692             } else {
693                 node = m_startNode->childNode(startOffset);
694             }
695         }
696         
697         // handle deleting all nodes that are completely selected
698         while (node && node != m_downstreamEnd.node()) {
699             if (RangeImpl::compareBoundaryPoints(Position(node, 0), m_downstreamEnd) >= 0) {
700                 // traverseNextSibling just blew past the end position, so stop deleting
701                 node = 0;
702             } else if (!m_downstreamEnd.node()->isAncestor(node)) {
703                 NodeImpl *nextNode = node->traverseNextSibling();
704                 // if we just removed a node from the end container, update end position so the
705                 // check above will work
706                 if (node->parentNode() == m_downstreamEnd.node()) {
707                     ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.offset());
708                     m_downstreamEnd = Position(m_downstreamEnd.node(), m_downstreamEnd.offset() - 1);
709                 }
710                 removeFullySelectedNode(node);
711                 node = nextNode;
712             } else {
713                 NodeImpl *n = node->lastChild();
714                 while (n && n->lastChild())
715                     n = n->lastChild();
716                 if (n == m_downstreamEnd.node() && m_downstreamEnd.offset() >= m_downstreamEnd.node()->caretMaxOffset()) {
717                     removeFullySelectedNode(node);
718                     m_trailingWhitespaceValid = false;
719                     node = 0;
720                 } 
721                 else {
722                     node = node->traverseNextNode();
723                 }
724             }
725         }
726
727         
728         if (m_downstreamEnd.node() != m_startNode && !m_upstreamStart.node()->isAncestor(m_downstreamEnd.node()) && m_downstreamEnd.node()->inDocument() && m_downstreamEnd.offset() >= m_downstreamEnd.node()->caretMinOffset()) {
729             if (m_downstreamEnd.offset() >= maxDeepOffset(m_downstreamEnd.node())) {
730                 // need to delete whole node
731                 // we can get here if this is the last node in the block
732                 // remove an ancestor of m_downstreamEnd.node(), and thus m_downstreamEnd.node() itself
733                 if (!m_upstreamStart.node()->inDocument() ||
734                     m_upstreamStart.node() == m_downstreamEnd.node() ||
735                     m_upstreamStart.node()->isAncestor(m_downstreamEnd.node())) {
736                     m_upstreamStart = Position(m_downstreamEnd.node()->parentNode(), m_downstreamEnd.node()->nodeIndex());
737                 }
738                 
739                 removeFullySelectedNode(m_downstreamEnd.node());
740                 m_trailingWhitespaceValid = false;
741             } else {
742                 if (m_downstreamEnd.node()->isTextNode()) {
743                     // in a text node that needs to be trimmed
744                     TextImpl *text = static_cast<TextImpl *>(m_downstreamEnd.node());
745                     if (m_downstreamEnd.offset() > 0) {
746                         deleteTextFromNode(text, 0, m_downstreamEnd.offset());
747                         m_downstreamEnd = Position(text, 0);
748                         m_trailingWhitespaceValid = false;
749                     }
750                 } else {
751                     int offset = 0;
752                     if (m_upstreamStart.node()->isAncestor(m_downstreamEnd.node())) {
753                         NodeImpl *n = m_upstreamStart.node();
754                         while (n && n->parentNode() != m_downstreamEnd.node())
755                             n = n->parentNode();
756                         if (n)
757                             offset = n->nodeIndex() + 1;
758                     }
759                     removeChildrenInRange(m_downstreamEnd.node(), offset, m_downstreamEnd.offset());
760                     m_downstreamEnd = Position(m_downstreamEnd.node(), offset);
761                 }
762             }
763         }
764     }
765 }
766
767 void DeleteSelectionCommand::fixupWhitespace()
768 {
769     document()->updateLayout();
770     if (m_leadingWhitespace.isNotNull() && (m_trailingWhitespace.isNotNull() || !m_leadingWhitespace.isRenderedCharacter())) {
771         LOG(Editing, "replace leading");
772         TextImpl *textNode = static_cast<TextImpl *>(m_leadingWhitespace.node());
773         replaceTextInNode(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
774     }
775     else if (m_trailingWhitespace.isNotNull()) {
776         if (m_trailingWhitespaceValid) {
777             if (!m_trailingWhitespace.isRenderedCharacter()) {
778                 LOG(Editing, "replace trailing [valid]");
779                 TextImpl *textNode = static_cast<TextImpl *>(m_trailingWhitespace.node());
780                 replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
781             }
782         }
783         else {
784             Position pos = m_endingPosition.downstream();
785             pos = Position(pos.node(), pos.offset() - 1);
786             if (nextCharacterIsCollapsibleWhitespace(pos) && !pos.isRenderedCharacter()) {
787                 LOG(Editing, "replace trailing [invalid]");
788                 TextImpl *textNode = static_cast<TextImpl *>(pos.node());
789                 replaceTextInNode(textNode, pos.offset(), 1, nonBreakingSpaceString());
790                 // need to adjust ending position since the trailing position is not valid.
791                 m_endingPosition = pos;
792             }
793         }
794     }
795 }
796
797 // This function moves nodes in the block containing startNode to dstBlock, starting
798 // from startNode and proceeding to the end of the paragraph. Nodes in the block containing
799 // startNode that appear in document order before startNode are not moved.
800 // This function is an important helper for deleting selections that cross paragraph
801 // boundaries.
802 void DeleteSelectionCommand::moveNodesAfterNode()
803 {
804     if (!m_mergeBlocksAfterDelete)
805         return;
806
807     if (m_endBlock == m_startBlock)
808         return;
809
810     NodeImpl *startNode = m_downstreamEnd.node();
811     NodeImpl *dstNode = m_upstreamStart.node();
812
813     if (!startNode->inDocument() || !dstNode->inDocument())
814         return;
815
816     NodeImpl *startBlock = startNode->enclosingBlockFlowElement();
817     if (isTableStructureNode(startBlock) || isListStructureNode(startBlock))
818         // Do not move content between parts of a table or list.
819         return;
820
821     // Now that we are about to add content, check to see if a placeholder element
822     // can be removed.
823     removeBlockPlaceholder(startBlock);
824
825     // Move the subtree containing node
826     NodeImpl *node = startNode->enclosingInlineElement();
827
828     // Insert after the subtree containing destNode
829     NodeImpl *refNode = dstNode->enclosingInlineElement();
830
831     // Nothing to do if start is already at the beginning of dstBlock
832     NodeImpl *dstBlock = refNode->enclosingBlockFlowElement();
833     if (startBlock == dstBlock->firstChild())
834         return;
835
836     // Do the move.
837     NodeImpl *rootNode = refNode->rootEditableElement();
838     while (node && node->isAncestor(startBlock)) {
839         NodeImpl *moveNode = node;
840         node = node->nextSibling();
841         removeNode(moveNode);
842         if (moveNode->id() == ID_BR && !moveNode->renderer()) {
843             // Just remove this node, and don't put it back.
844             // If the BR was not rendered (since it was at the end of a block, for instance), 
845             // putting it back in the document might make it appear, and that is not desirable.
846             break;
847         }
848         if (refNode == rootNode)
849             insertNodeAt(moveNode, refNode, 0);
850         else
851             insertNodeAfter(moveNode, refNode);
852         refNode = moveNode;
853         if (moveNode->id() == ID_BR)
854             break;
855     }
856
857     // If the startBlock no longer has any kids, we may need to deal with adding a BR
858     // to make the layout come out right. Consider this document:
859     //
860     // One
861     // <div>Two</div>
862     // Three
863     // 
864     // Placing the insertion before before the 'T' of 'Two' and hitting delete will
865     // move the contents of the div to the block containing 'One' and delete the div.
866     // This will have the side effect of moving 'Three' on to the same line as 'One'
867     // and 'Two'. This is undesirable. We fix this up by adding a BR before the 'Three'.
868     // This may not be ideal, but it is better than nothing.
869     document()->updateLayout();
870     if (!startBlock->renderer() || !startBlock->renderer()->firstChild()) {
871         removeNode(startBlock);
872         document()->updateLayout();
873         if (refNode->renderer() && refNode->renderer()->inlineBox() && refNode->renderer()->inlineBox()->nextOnLineExists()) {
874             insertNodeAfter(createBreakElement(document()), refNode);
875         }
876     }
877 }
878
879 void DeleteSelectionCommand::calculateEndingPosition()
880 {
881     if (m_endingPosition.isNotNull() && m_endingPosition.node()->inDocument())
882         return;
883
884     m_endingPosition = m_upstreamStart;
885     if (m_endingPosition.node()->inDocument())
886         return;
887     
888     m_endingPosition = m_downstreamEnd;
889     if (m_endingPosition.node()->inDocument())
890         return;
891
892     m_endingPosition = Position(m_startBlock, 0);
893     if (m_endingPosition.node()->inDocument())
894         return;
895
896     m_endingPosition = Position(m_endBlock, 0);
897     if (m_endingPosition.node()->inDocument())
898         return;
899
900     m_endingPosition = Position(document()->documentElement(), 0);
901 }
902
903 void DeleteSelectionCommand::calculateTypingStyleAfterDelete(NodeImpl *insertedPlaceholder)
904 {
905     // Compute the difference between the style before the delete and the style now
906     // after the delete has been done. Set this style on the part, so other editing
907     // commands being composed with this one will work, and also cache it on the command,
908     // so the KHTMLPart::appliedEditing can set it after the whole composite command 
909     // has completed.
910     // FIXME: Improve typing style.
911     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
912     CSSComputedStyleDeclarationImpl endingStyle(m_endingPosition.node());
913     endingStyle.diff(m_typingStyle);
914     if (!m_typingStyle->length()) {
915         m_typingStyle->deref();
916         m_typingStyle = 0;
917     }
918     if (insertedPlaceholder && m_typingStyle) {
919         // Apply style to the placeholder. This makes sure that the single line in the
920         // paragraph has the right height, and that the paragraph takes on the style
921         // of the preceding line and retains it even if you click away, click back, and
922         // then start typing. In this case, the typing style is applied right now, and
923         // is not retained until the next typing action.
924
925         // FIXME: is this even right? I don't think post-deletion typing style is supposed 
926         // to be saved across clicking away and clicking back, it certainly isn't in TextEdit
927
928         Position pastPlaceholder(insertedPlaceholder, 1);
929
930         setEndingSelection(Selection(m_endingPosition, m_selectionToDelete.endAffinity(), pastPlaceholder, DOWNSTREAM));
931
932         applyStyle(m_typingStyle, EditActionUnspecified);
933
934         m_typingStyle->deref();
935         m_typingStyle = 0;
936     }
937     // Set m_typingStyle as the typing style.
938     // It's perfectly OK for m_typingStyle to be null.
939     document()->part()->setTypingStyle(m_typingStyle);
940     setTypingStyle(m_typingStyle);
941 }
942
943 void DeleteSelectionCommand::clearTransientState()
944 {
945     m_selectionToDelete.clear();
946     m_upstreamStart.clear();
947     m_downstreamStart.clear();
948     m_upstreamEnd.clear();
949     m_downstreamEnd.clear();
950     m_endingPosition.clear();
951     m_leadingWhitespace.clear();
952     m_trailingWhitespace.clear();
953
954     if (m_startBlock) {
955         m_startBlock->deref();
956         m_startBlock = 0;
957     }
958     if (m_endBlock) {
959         m_endBlock->deref();
960         m_endBlock = 0;
961     }
962     if (m_startNode) {
963         m_startNode->deref();
964         m_startNode = 0;
965     }
966     if (m_typingStyle) {
967         m_typingStyle->deref();
968         m_typingStyle = 0;
969     }
970 }
971
972 void DeleteSelectionCommand::doApply()
973 {
974     // If selection has not been set to a custom selection when the command was created,
975     // use the current ending selection.
976     if (!m_hasSelectionToDelete)
977         m_selectionToDelete = endingSelection();
978         
979     if (!m_selectionToDelete.isRange())
980         return;
981
982     // save this to later make the selection with
983     EAffinity affinity = m_selectionToDelete.startAffinity();
984     
985     // set up our state
986     initializePositionData();
987
988     if (!m_startBlock || !m_endBlock) {
989         // Can't figure out what blocks we're in. This can happen if
990         // the document structure is not what we are expecting, like if
991         // the document has no body element, or if the editable block
992         // has been changed to display: inline. Some day it might
993         // be nice to be able to deal with this, but for now, bail.
994         clearTransientState();
995         return;
996     }
997     
998     // if all we are deleting is complete paragraph(s), we need to make
999     // sure a blank paragraph remains when we are done
1000     bool forceBlankParagraph = isStartOfParagraph(VisiblePosition(m_upstreamStart, VP_DEFAULT_AFFINITY)) &&
1001                                isEndOfParagraph(VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY));
1002
1003     // Delete any text that may hinder our ability to fixup whitespace after the detele
1004     deleteInsignificantTextDownstream(m_trailingWhitespace);    
1005
1006     saveTypingStyleState();
1007     insertPlaceholderForAncestorBlockContent();
1008     
1009     if (!handleSpecialCaseBRDelete())
1010         handleGeneralDelete();
1011     
1012     // Do block merge if start and end of selection are in different blocks.
1013     moveNodesAfterNode();
1014     
1015     calculateEndingPosition();
1016     fixupWhitespace();
1017
1018     // if the m_endingPosition is already a blank paragraph, there is
1019     // no need to force a new one
1020     if (forceBlankParagraph &&
1021         isStartOfParagraph(VisiblePosition(m_endingPosition, VP_DEFAULT_AFFINITY)) &&
1022         isEndOfParagraph(VisiblePosition(m_endingPosition, VP_DEFAULT_AFFINITY))) {
1023         forceBlankParagraph = false;
1024     }
1025     
1026     NodeImpl *addedPlaceholder = forceBlankParagraph ? insertBlockPlaceholder(m_endingPosition) :
1027         addBlockPlaceholderIfNeeded(m_endingPosition.node());
1028
1029     calculateTypingStyleAfterDelete(addedPlaceholder);
1030     debugPosition("endingPosition   ", m_endingPosition);
1031     setEndingSelection(Selection(m_endingPosition, affinity));
1032     clearTransientState();
1033     rebalanceWhitespace();
1034 }
1035
1036 EditAction DeleteSelectionCommand::editingAction() const
1037 {
1038     // Note that DeleteSelectionCommand is also used when the user presses the Delete key,
1039     // but in that case there's a TypingCommand that supplies the editingAction(), so
1040     // the Undo menu correctly shows "Undo Typing"
1041     return EditActionCut;
1042 }
1043
1044 bool DeleteSelectionCommand::preservesTypingStyle() const
1045 {
1046     return true;
1047 }
1048
1049 //------------------------------------------------------------------------------------------
1050 // InsertIntoTextNode
1051
1052 InsertIntoTextNode::InsertIntoTextNode(DocumentImpl *document, TextImpl *node, long offset, const DOMString &text)
1053     : EditCommand(document), m_node(node), m_offset(offset)
1054 {
1055     ASSERT(m_node);
1056     ASSERT(m_offset >= 0);
1057     ASSERT(!text.isEmpty());
1058     
1059     m_node->ref();
1060     m_text = text.copy(); // make a copy to ensure that the string never changes
1061 }
1062
1063 InsertIntoTextNode::~InsertIntoTextNode()
1064 {
1065     if (m_node)
1066         m_node->deref();
1067 }
1068
1069 void InsertIntoTextNode::doApply()
1070 {
1071     ASSERT(m_node);
1072     ASSERT(m_offset >= 0);
1073     ASSERT(!m_text.isEmpty());
1074
1075     int exceptionCode = 0;
1076     m_node->insertData(m_offset, m_text, exceptionCode);
1077     ASSERT(exceptionCode == 0);
1078 }
1079
1080 void InsertIntoTextNode::doUnapply()
1081 {
1082     ASSERT(m_node);
1083     ASSERT(m_offset >= 0);
1084     ASSERT(!m_text.isEmpty());
1085
1086     int exceptionCode = 0;
1087     m_node->deleteData(m_offset, m_text.length(), exceptionCode);
1088     ASSERT(exceptionCode == 0);
1089 }
1090
1091 //------------------------------------------------------------------------------------------
1092 // InsertLineBreakCommand
1093
1094 InsertLineBreakCommand::InsertLineBreakCommand(DocumentImpl *document) 
1095     : CompositeEditCommand(document)
1096 {
1097 }
1098
1099 bool InsertLineBreakCommand::preservesTypingStyle() const
1100 {
1101     return true;
1102 }
1103
1104 void InsertLineBreakCommand::insertNodeAfterPosition(NodeImpl *node, const Position &pos)
1105 {
1106     // Insert the BR after the caret position. In the case the
1107     // position is a block, do an append. We don't want to insert
1108     // the BR *after* the block.
1109     Position upstream(pos.upstream());
1110     NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1111     if (cb == pos.node())
1112         appendNode(node, cb);
1113     else
1114         insertNodeAfter(node, pos.node());
1115 }
1116
1117 void InsertLineBreakCommand::insertNodeBeforePosition(NodeImpl *node, const Position &pos)
1118 {
1119     // Insert the BR after the caret position. In the case the
1120     // position is a block, do an append. We don't want to insert
1121     // the BR *before* the block.
1122     Position upstream(pos.upstream());
1123     NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1124     if (cb == pos.node())
1125         appendNode(node, cb);
1126     else
1127         insertNodeBefore(node, pos.node());
1128 }
1129
1130 void InsertLineBreakCommand::doApply()
1131 {
1132     deleteSelection();
1133     Selection selection = endingSelection();
1134
1135     ElementImpl *breakNode = createBreakElement(document());
1136     NodeImpl *nodeToInsert = breakNode;
1137     
1138     Position pos(selection.start().upstream());
1139
1140     pos = positionOutsideContainingSpecialElement(pos);
1141
1142     bool atStart = pos.offset() <= pos.node()->caretMinOffset();
1143     bool atEnd = pos.offset() >= pos.node()->caretMaxOffset();
1144     bool atEndOfBlock = isEndOfBlock(VisiblePosition(pos, selection.startAffinity()));
1145     
1146     if (atEndOfBlock) {
1147         LOG(Editing, "input newline case 1");
1148         // Check for a trailing BR. If there isn't one, we'll need to insert an "extra" one.
1149         // This makes the "real" BR we want to insert appear in the rendering without any 
1150         // significant side effects (and no real worries either since you can't arrow past 
1151         // this extra one.
1152         if (pos.node()->id() == ID_BR && pos.offset() == 0) {
1153             // Already placed in a trailing BR. Insert "real" BR before it and leave the selection alone.
1154             insertNodeBefore(nodeToInsert, pos.node());
1155         }
1156         else {
1157             NodeImpl *next = pos.node()->traverseNextNode();
1158             bool hasTrailingBR = next && next->id() == ID_BR && pos.node()->enclosingBlockFlowElement() == next->enclosingBlockFlowElement();
1159             insertNodeAfterPosition(nodeToInsert, pos);
1160             if (hasTrailingBR) {
1161                 setEndingSelection(Selection(Position(next, 0), DOWNSTREAM));
1162             }
1163             else if (!document()->inStrictMode()) {
1164                 // Insert an "extra" BR at the end of the block. 
1165                 ElementImpl *extraBreakNode = createBreakElement(document());
1166                 insertNodeAfter(extraBreakNode, nodeToInsert);
1167                 setEndingSelection(Position(extraBreakNode, 0), DOWNSTREAM);
1168             }
1169         }
1170     }
1171     else if (atStart) {
1172         LOG(Editing, "input newline case 2");
1173         // Insert node before downstream position, and place caret there as well. 
1174         Position endingPosition = pos.downstream();
1175         insertNodeBeforePosition(nodeToInsert, endingPosition);
1176         setEndingSelection(endingPosition, DOWNSTREAM);
1177     }
1178     else if (atEnd) {
1179         LOG(Editing, "input newline case 3");
1180         // Insert BR after this node. Place caret in the position that is downstream
1181         // of the current position, reckoned before inserting the BR in between.
1182         Position endingPosition = pos.downstream();
1183         insertNodeAfterPosition(nodeToInsert, pos);
1184         setEndingSelection(endingPosition, DOWNSTREAM);
1185     }
1186     else {
1187         // Split a text node
1188         LOG(Editing, "input newline case 4");
1189         ASSERT(pos.node()->isTextNode());
1190         
1191         // Do the split
1192         int exceptionCode = 0;
1193         TextImpl *textNode = static_cast<TextImpl *>(pos.node());
1194         TextImpl *textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
1195         deleteTextFromNode(textNode, 0, pos.offset());
1196         insertNodeBefore(textBeforeNode, textNode);
1197         insertNodeBefore(nodeToInsert, textNode);
1198         Position endingPosition = Position(textNode, 0);
1199         
1200         // Handle whitespace that occurs after the split
1201         document()->updateLayout();
1202         if (!endingPosition.isRenderedCharacter()) {
1203             // Clear out all whitespace and insert one non-breaking space
1204             deleteInsignificantTextDownstream(endingPosition);
1205             insertTextIntoNode(textNode, 0, nonBreakingSpaceString());
1206         }
1207         
1208         setEndingSelection(endingPosition, DOWNSTREAM);
1209     }
1210
1211     // Handle the case where there is a typing style.
1212     // FIXME: Improve typing style.
1213     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
1214     
1215     CSSMutableStyleDeclarationImpl *typingStyle = document()->part()->typingStyle();
1216     
1217     if (typingStyle && typingStyle->length() > 0) {
1218         Selection selectionBeforeStyle = endingSelection();
1219
1220         DOM::RangeImpl *rangeAroundNode = document()->createRange();
1221         int exception;
1222         rangeAroundNode->selectNode(nodeToInsert, exception);
1223
1224         // affinity is not really important since this is a temp selection
1225         // just for calling applyStyle
1226         setEndingSelection(Selection(rangeAroundNode, khtml::SEL_DEFAULT_AFFINITY, khtml::SEL_DEFAULT_AFFINITY));
1227         applyStyle(typingStyle);
1228
1229         setEndingSelection(selectionBeforeStyle);
1230     }
1231
1232     rebalanceWhitespace();
1233 }
1234
1235 //------------------------------------------------------------------------------------------
1236 // InsertNodeBeforeCommand
1237
1238 InsertNodeBeforeCommand::InsertNodeBeforeCommand(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
1239     : EditCommand(document), m_insertChild(insertChild), m_refChild(refChild)
1240 {
1241     ASSERT(m_insertChild);
1242     m_insertChild->ref();
1243
1244     ASSERT(m_refChild);
1245     m_refChild->ref();
1246 }
1247
1248 InsertNodeBeforeCommand::~InsertNodeBeforeCommand()
1249 {
1250     ASSERT(m_insertChild);
1251     m_insertChild->deref();
1252
1253     ASSERT(m_refChild);
1254     m_refChild->deref();
1255 }
1256
1257 void InsertNodeBeforeCommand::doApply()
1258 {
1259     ASSERT(m_insertChild);
1260     ASSERT(m_refChild);
1261     ASSERT(m_refChild->parentNode());
1262
1263     int exceptionCode = 0;
1264     m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
1265     ASSERT(exceptionCode == 0);
1266 }
1267
1268 void InsertNodeBeforeCommand::doUnapply()
1269 {
1270     ASSERT(m_insertChild);
1271     ASSERT(m_refChild);
1272     ASSERT(m_refChild->parentNode());
1273
1274     int exceptionCode = 0;
1275     m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
1276     ASSERT(exceptionCode == 0);
1277 }
1278
1279 //------------------------------------------------------------------------------------------
1280 // InsertParagraphSeparatorCommand
1281
1282 InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand(DocumentImpl *document) 
1283     : CompositeEditCommand(document), m_style(0)
1284 {
1285 }
1286
1287 InsertParagraphSeparatorCommand::~InsertParagraphSeparatorCommand() 
1288 {
1289     derefNodesInList(clonedNodes);
1290     if (m_style)
1291         m_style->deref();
1292 }
1293
1294 bool InsertParagraphSeparatorCommand::preservesTypingStyle() const
1295 {
1296     return true;
1297 }
1298
1299 ElementImpl *InsertParagraphSeparatorCommand::createParagraphElement()
1300 {
1301     ElementImpl *element = createDefaultParagraphElement(document());
1302     element->ref();
1303     clonedNodes.append(element);
1304     return element;
1305 }
1306
1307 void InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion(const Position &pos)
1308 {
1309     // It is only important to set a style to apply later if we're at the boundaries of
1310     // a paragraph. Otherwise, content that is moved as part of the work of the command
1311     // will lend their styles to the new paragraph without any extra work needed.
1312     VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
1313     if (!isStartOfParagraph(visiblePos) && !isEndOfParagraph(visiblePos))
1314         return;
1315     
1316     if (m_style)
1317         m_style->deref();
1318     m_style = styleAtPosition(pos);
1319     m_style->ref();
1320 }
1321
1322 void InsertParagraphSeparatorCommand::applyStyleAfterInsertion()
1323 {
1324     // FIXME: Improve typing style.
1325     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
1326     if (!m_style)
1327         return;
1328
1329     CSSComputedStyleDeclarationImpl endingStyle(endingSelection().start().node());
1330     endingStyle.diff(m_style);
1331     if (m_style->length() > 0) {
1332         applyStyle(m_style);
1333     }
1334 }
1335
1336 void InsertParagraphSeparatorCommand::doApply()
1337 {
1338     bool splitText = false;
1339     Selection selection = endingSelection();
1340     if (selection.isNone())
1341         return;
1342     
1343     Position pos = selection.start();
1344     EAffinity affinity = selection.startAffinity();
1345         
1346     // Delete the current selection.
1347     if (selection.isRange()) {
1348         calculateStyleBeforeInsertion(pos);
1349         deleteSelection(false, false);
1350         pos = endingSelection().start();
1351         affinity = endingSelection().startAffinity();
1352     }
1353
1354     pos = positionOutsideContainingSpecialElement(pos);
1355
1356     calculateStyleBeforeInsertion(pos);
1357
1358     // Find the start block.
1359     NodeImpl *startNode = pos.node();
1360     NodeImpl *startBlock = startNode->enclosingBlockFlowElement();
1361     if (!startBlock || !startBlock->parentNode())
1362         return;
1363
1364     VisiblePosition visiblePos(pos, affinity);
1365     bool isFirstInBlock = isStartOfBlock(visiblePos);
1366     bool isLastInBlock = isEndOfBlock(visiblePos);
1367     bool startBlockIsRoot = startBlock == startBlock->rootEditableElement();
1368
1369     // This is the block that is going to be inserted.
1370     NodeImpl *blockToInsert = startBlockIsRoot ? createParagraphElement() : startBlock->cloneNode(false);
1371
1372     //---------------------------------------------------------------------
1373     // Handle empty block case.
1374     if (isFirstInBlock && isLastInBlock) {
1375         LOG(Editing, "insert paragraph separator: empty block case");
1376         if (startBlockIsRoot) {
1377             NodeImpl *extraBlock = createParagraphElement();
1378             appendNode(extraBlock, startBlock);
1379             appendBlockPlaceholder(extraBlock);
1380             appendNode(blockToInsert, startBlock);
1381         }
1382         else {
1383             insertNodeAfter(blockToInsert, startBlock);
1384         }
1385         appendBlockPlaceholder(blockToInsert);
1386         setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
1387         applyStyleAfterInsertion();
1388         return;
1389     }
1390
1391     //---------------------------------------------------------------------
1392     // Handle case when position is in the last visible position in its block. 
1393     if (isLastInBlock) {
1394         LOG(Editing, "insert paragraph separator: last in block case");
1395         if (startBlockIsRoot)
1396             appendNode(blockToInsert, startBlock);
1397         else
1398             insertNodeAfter(blockToInsert, startBlock);
1399         appendBlockPlaceholder(blockToInsert);
1400         setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
1401         applyStyleAfterInsertion();
1402         return;
1403     }
1404
1405     //---------------------------------------------------------------------
1406     // Handle case when position is in the first visible position in its block.
1407     // and similar case where upstream position is in another block.
1408     bool prevInDifferentBlock = !inSameBlock(visiblePos, visiblePos.previous());
1409
1410     if (prevInDifferentBlock || isFirstInBlock) {
1411         LOG(Editing, "insert paragraph separator: first in block case");
1412         pos = pos.downstream();
1413         pos = positionOutsideContainingSpecialElement(pos);
1414         Position refPos;
1415         NodeImpl *refNode;
1416         if (isFirstInBlock && !startBlockIsRoot) {
1417             refNode = startBlock;
1418         } else if (pos.node() == startBlock && startBlockIsRoot) {
1419             ASSERT(startBlock->childNode(pos.offset())); // must be true or we'd be in the end of block case
1420             refNode = startBlock->childNode(pos.offset());
1421         } else {
1422             refNode = pos.node();
1423         }
1424
1425         insertNodeBefore(blockToInsert, refNode);
1426         appendBlockPlaceholder(blockToInsert);
1427         setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
1428         applyStyleAfterInsertion();
1429         setEndingSelection(pos, DOWNSTREAM);
1430         return;
1431     }
1432
1433     //---------------------------------------------------------------------
1434     // Handle the (more complicated) general case,
1435
1436     LOG(Editing, "insert paragraph separator: general case");
1437
1438     // Check if pos.node() is a <br>. If it is, and the document is in quirks mode, 
1439     // then this <br> will collapse away when we add a block after it. Add an extra <br>.
1440     if (!document()->inStrictMode()) {
1441         Position upstreamPos = pos.upstream();
1442         if (upstreamPos.node()->id() == ID_BR)
1443             insertNodeAfter(createBreakElement(document()), upstreamPos.node());
1444     }
1445     
1446     // Move downstream. Typing style code will take care of carrying along the 
1447     // style of the upstream position.
1448     pos = pos.downstream();
1449     startNode = pos.node();
1450
1451     // Build up list of ancestors in between the start node and the start block.
1452     if (startNode != startBlock) {
1453         for (NodeImpl *n = startNode->parentNode(); n && n != startBlock; n = n->parentNode())
1454             ancestors.prepend(n);
1455     }
1456
1457     // Make sure we do not cause a rendered space to become unrendered.
1458     // FIXME: We need the affinity for pos, but pos.downstream() does not give it
1459     Position leadingWhitespace = pos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY);
1460     if (leadingWhitespace.isNotNull()) {
1461         TextImpl *textNode = static_cast<TextImpl *>(leadingWhitespace.node());
1462         replaceTextInNode(textNode, leadingWhitespace.offset(), 1, nonBreakingSpaceString());
1463     }
1464     
1465     // Split at pos if in the middle of a text node.
1466     if (startNode->isTextNode()) {
1467         TextImpl *textNode = static_cast<TextImpl *>(startNode);
1468         bool atEnd = (unsigned long)pos.offset() >= textNode->length();
1469         if (pos.offset() > 0 && !atEnd) {
1470             splitTextNode(textNode, pos.offset());
1471             pos = Position(startNode, 0);
1472             splitText = true;
1473         }
1474     }
1475
1476     // Put the added block in the tree.
1477     if (startBlockIsRoot) {
1478         appendNode(blockToInsert, startBlock);
1479     } else {
1480         insertNodeAfter(blockToInsert, startBlock);
1481     }
1482
1483     // Make clones of ancestors in between the start node and the start block.
1484     NodeImpl *parent = blockToInsert;
1485     for (QPtrListIterator<NodeImpl> it(ancestors); it.current(); ++it) {
1486         NodeImpl *child = it.current()->cloneNode(false); // shallow clone
1487         child->ref();
1488         clonedNodes.append(child);
1489         appendNode(child, parent);
1490         parent = child;
1491     }
1492
1493     // Insert a block placeholder if the next visible position is in a different paragraph,
1494     // because we know that there will be no content on the first line of the new block 
1495     // before the first block child. So, we need the placeholder to "hold the first line open".
1496     VisiblePosition next = visiblePos.next();
1497     if (!next.isNull() && !inSameBlock(visiblePos, next))
1498         appendBlockPlaceholder(blockToInsert);
1499
1500     // Move the start node and the siblings of the start node.
1501     if (startNode != startBlock) {
1502         NodeImpl *n = startNode;
1503         if (pos.offset() >= startNode->caretMaxOffset()) {
1504             n = startNode->nextSibling();
1505         }
1506         while (n && n != blockToInsert) {
1507             NodeImpl *next = n->nextSibling();
1508             removeNode(n);
1509             appendNode(n, parent);
1510             n = next;
1511         }
1512     }            
1513
1514     // Move everything after the start node.
1515     NodeImpl *leftParent = ancestors.last();
1516     while (leftParent && leftParent != startBlock) {
1517         parent = parent->parentNode();
1518         NodeImpl *n = leftParent->nextSibling();
1519         while (n && n != blockToInsert) {
1520             NodeImpl *next = n->nextSibling();
1521             removeNode(n);
1522             appendNode(n, parent);
1523             n = next;
1524         }
1525         leftParent = leftParent->parentNode();
1526     }
1527
1528     // Handle whitespace that occurs after the split
1529     if (splitText) {
1530         document()->updateLayout();
1531         pos = Position(startNode, 0);
1532         if (!pos.isRenderedCharacter()) {
1533             // Clear out all whitespace and insert one non-breaking space
1534             ASSERT(startNode && startNode->isTextNode());
1535             deleteInsignificantTextDownstream(pos);
1536             insertTextIntoNode(static_cast<TextImpl *>(startNode), 0, nonBreakingSpaceString());
1537         }
1538     }
1539
1540     setEndingSelection(Position(blockToInsert, 0), DOWNSTREAM);
1541     rebalanceWhitespace();
1542     applyStyleAfterInsertion();
1543 }
1544
1545 //------------------------------------------------------------------------------------------
1546 // InsertParagraphSeparatorInQuotedContentCommand
1547
1548 InsertParagraphSeparatorInQuotedContentCommand::InsertParagraphSeparatorInQuotedContentCommand(DocumentImpl *document)
1549     : CompositeEditCommand(document), m_breakNode(0)
1550 {
1551 }
1552
1553 InsertParagraphSeparatorInQuotedContentCommand::~InsertParagraphSeparatorInQuotedContentCommand()
1554 {
1555     derefNodesInList(clonedNodes);
1556     if (m_breakNode)
1557         m_breakNode->deref();
1558 }
1559
1560 void InsertParagraphSeparatorInQuotedContentCommand::doApply()
1561 {
1562     Selection selection = endingSelection();
1563     if (selection.isNone())
1564         return;
1565     
1566     // Delete the current selection.
1567     Position pos = selection.start();
1568     EAffinity affinity = selection.startAffinity();
1569     if (selection.isRange()) {
1570         deleteSelection(false, false);
1571         pos = endingSelection().start().upstream();
1572         affinity = endingSelection().startAffinity();
1573     }
1574     
1575     // Find the top-most blockquote from the start.
1576     NodeImpl *startNode = pos.node();
1577     NodeImpl *topBlockquote = 0;
1578     for (NodeImpl *n = startNode->parentNode(); n; n = n->parentNode()) {
1579         if (isMailBlockquote(n))
1580             topBlockquote = n;
1581     }
1582     if (!topBlockquote || !topBlockquote->parentNode())
1583         return;
1584     
1585     // Insert a break after the top blockquote.
1586     m_breakNode = createBreakElement(document());
1587     m_breakNode->ref();
1588     insertNodeAfter(m_breakNode, topBlockquote);
1589     
1590     if (!isLastVisiblePositionInNode(VisiblePosition(pos, affinity), topBlockquote)) {
1591         
1592         NodeImpl *newStartNode = 0;
1593         // Split at pos if in the middle of a text node.
1594         if (startNode->isTextNode()) {
1595             TextImpl *textNode = static_cast<TextImpl *>(startNode);
1596             bool atEnd = (unsigned long)pos.offset() >= textNode->length();
1597             if (pos.offset() > 0 && !atEnd) {
1598                 splitTextNode(textNode, pos.offset());
1599                 pos = Position(startNode, 0);
1600             }
1601             else if (atEnd) {
1602                 newStartNode = startNode->traverseNextNode();
1603                 ASSERT(newStartNode);
1604             }
1605         }
1606         else if (pos.offset() > 0) {
1607             newStartNode = startNode->traverseNextNode();
1608             ASSERT(newStartNode);
1609         }
1610         
1611         // If a new start node was determined, find a new top block quote.
1612         if (newStartNode) {
1613             startNode = newStartNode;
1614             for (NodeImpl *n = startNode->parentNode(); n; n = n->parentNode()) {
1615                 if (isMailBlockquote(n))
1616                     topBlockquote = n;
1617             }
1618             if (!topBlockquote || !topBlockquote->parentNode())
1619                 return;
1620         }
1621         
1622         // Build up list of ancestors in between the start node and the top blockquote.
1623         if (startNode != topBlockquote) {
1624             for (NodeImpl *n = startNode->parentNode(); n && n != topBlockquote; n = n->parentNode())
1625                 ancestors.prepend(n);
1626         }                    
1627         
1628         // Insert a clone of the top blockquote after the break.
1629         NodeImpl *clonedBlockquote = topBlockquote->cloneNode(false);
1630         clonedBlockquote->ref();
1631         clonedNodes.append(clonedBlockquote);
1632         insertNodeAfter(clonedBlockquote, m_breakNode);
1633         
1634         // Make clones of ancestors in between the start node and the top blockquote.
1635         NodeImpl *parent = clonedBlockquote;
1636         for (QPtrListIterator<NodeImpl> it(ancestors); it.current(); ++it) {
1637             NodeImpl *child = it.current()->cloneNode(false); // shallow clone
1638             child->ref();
1639             clonedNodes.append(child);
1640             appendNode(child, parent);
1641             parent = child;
1642         }
1643         
1644         // Move the start node and the siblings of the start node.
1645         bool startIsBR = false;
1646         if (startNode != topBlockquote) {
1647             NodeImpl *n = startNode;
1648             startIsBR = n->id() == ID_BR;
1649             if (startIsBR)
1650                 n = n->nextSibling();
1651             while (n) {
1652                 NodeImpl *next = n->nextSibling();
1653                 removeNode(n);
1654                 appendNode(n, parent);
1655                 n = next;
1656             }
1657         }
1658         
1659         // Move everything after the start node.
1660         NodeImpl *leftParent = ancestors.last();
1661         
1662         // Insert an extra new line when the start is at the beginning of a line.
1663         if (!newStartNode && !startIsBR) {
1664             if (!leftParent)
1665                 leftParent = topBlockquote;
1666             ElementImpl *b = createBreakElement(document());
1667             b->ref();
1668             clonedNodes.append(b);
1669             appendNode(b, leftParent);
1670         }        
1671         
1672         leftParent = ancestors.last();
1673         while (leftParent && leftParent != topBlockquote) {
1674             parent = parent->parentNode();
1675             NodeImpl *n = leftParent->nextSibling();
1676             while (n) {
1677                 NodeImpl *next = n->nextSibling();
1678                 removeNode(n);
1679                 appendNode(n, parent);
1680                 n = next;
1681             }
1682             leftParent = leftParent->parentNode();
1683         }
1684         
1685         // Make sure the cloned block quote renders.
1686         addBlockPlaceholderIfNeeded(clonedBlockquote);
1687     }
1688     
1689     // Put the selection right before the break.
1690     setEndingSelection(Position(m_breakNode, 0), DOWNSTREAM);
1691     rebalanceWhitespace();
1692 }
1693
1694 //------------------------------------------------------------------------------------------
1695 // InsertTextCommand
1696
1697 InsertTextCommand::InsertTextCommand(DocumentImpl *document) 
1698     : CompositeEditCommand(document), m_charactersAdded(0)
1699 {
1700 }
1701
1702 void InsertTextCommand::doApply()
1703 {
1704 }
1705
1706 Position InsertTextCommand::prepareForTextInsertion(bool adjustDownstream)
1707 {
1708     // Prepare for text input by looking at the current position.
1709     // It may be necessary to insert a text node to receive characters.
1710     Selection selection = endingSelection();
1711     ASSERT(selection.isCaret());
1712     
1713     Position pos = selection.start();
1714     if (adjustDownstream)
1715         pos = pos.downstream();
1716     else
1717         pos = pos.upstream();
1718     
1719     Selection typingStyleRange;
1720
1721     pos = positionOutsideContainingSpecialElement(pos);
1722
1723     if (!pos.node()->isTextNode()) {
1724         NodeImpl *textNode = document()->createEditingTextNode("");
1725         NodeImpl *nodeToInsert = textNode;
1726
1727         // Now insert the node in the right place
1728         if (pos.node()->rootEditableElement() != NULL) {
1729             LOG(Editing, "prepareForTextInsertion case 1");
1730             insertNodeAt(nodeToInsert, pos.node(), pos.offset());
1731         }
1732         else if (pos.node()->caretMinOffset() == pos.offset()) {
1733             LOG(Editing, "prepareForTextInsertion case 2");
1734             insertNodeBefore(nodeToInsert, pos.node());
1735         }
1736         else if (pos.node()->caretMaxOffset() == pos.offset()) {
1737             LOG(Editing, "prepareForTextInsertion case 3");
1738             insertNodeAfter(nodeToInsert, pos.node());
1739         }
1740         else
1741             ASSERT_NOT_REACHED();
1742         
1743         pos = Position(textNode, 0);
1744     }
1745
1746     return pos;
1747 }
1748
1749 void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
1750 {
1751     assert(text.find('\n') == -1);
1752
1753     Selection selection = endingSelection();
1754     bool adjustDownstream = isStartOfLine(VisiblePosition(selection.start().downstream(), DOWNSTREAM));
1755
1756     // Delete the current selection, or collapse whitespace, as needed
1757     if (selection.isRange())
1758         deleteSelection();
1759     
1760     // Delete any insignificant text that could get in the way of whitespace turning
1761     // out correctly after the insertion.
1762     selection = endingSelection();
1763     deleteInsignificantTextDownstream(selection.end().trailingWhitespacePosition(selection.endAffinity()));
1764     
1765     // Make sure the document is set up to receive text
1766     Position startPosition = prepareForTextInsertion(adjustDownstream);
1767     
1768     Position endPosition;
1769
1770     TextImpl *textNode = static_cast<TextImpl *>(startPosition.node());
1771     long offset = startPosition.offset();
1772
1773     // Now that we are about to add content, check to see if a placeholder element
1774     // can be removed.
1775     removeBlockPlaceholder(textNode->enclosingBlockFlowElement());
1776     
1777     // These are temporary implementations for inserting adjoining spaces
1778     // into a document. We are working on a CSS-related whitespace solution
1779     // that will replace this some day. We hope.
1780     if (text == "\t") {
1781         // Treat a tab like a number of spaces. This seems to be the HTML editing convention,
1782         // although the number of spaces varies (we choose four spaces). 
1783         // Note that there is no attempt to make this work like a real tab stop, it is merely 
1784         // a set number of spaces. This also seems to be the HTML editing convention.
1785         for (int i = 0; i < spacesPerTab; i++) {
1786             insertSpace(textNode, offset);
1787             rebalanceWhitespace();
1788             document()->updateLayout();
1789         }
1790         
1791         endPosition = Position(textNode, offset + spacesPerTab);
1792
1793         m_charactersAdded += spacesPerTab;
1794     }
1795     else if (text == " ") {
1796         insertSpace(textNode, offset);
1797         endPosition = Position(textNode, offset + 1);
1798
1799         m_charactersAdded++;
1800         rebalanceWhitespace();
1801     }
1802     else {
1803         const DOMString &existingText = textNode->data();
1804         if (textNode->length() >= 2 && offset >= 2 && isNBSP(existingText[offset - 1]) && !isCollapsibleWhitespace(existingText[offset - 2])) {
1805             // DOM looks like this:
1806             // character nbsp caret
1807             // As we are about to insert a non-whitespace character at the caret
1808             // convert the nbsp to a regular space.
1809             // EDIT FIXME: This needs to be improved some day to convert back only
1810             // those nbsp's added by the editor to make rendering come out right.
1811             replaceTextInNode(textNode, offset - 1, 1, " ");
1812         }
1813         insertTextIntoNode(textNode, offset, text);
1814         endPosition = Position(textNode, offset + text.length());
1815
1816         m_charactersAdded += text.length();
1817     }
1818
1819     setEndingSelection(Selection(startPosition, DOWNSTREAM, endPosition, SEL_DEFAULT_AFFINITY));
1820
1821     // Handle the case where there is a typing style.
1822     // FIXME: Improve typing style.
1823     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
1824     CSSMutableStyleDeclarationImpl *typingStyle = document()->part()->typingStyle();
1825     if (typingStyle && typingStyle->length() > 0)
1826         applyStyle(typingStyle);
1827
1828     if (!selectInsertedText)
1829         setEndingSelection(endingSelection().end(), endingSelection().endAffinity());
1830 }
1831
1832 void InsertTextCommand::insertSpace(TextImpl *textNode, unsigned long offset)
1833 {
1834     ASSERT(textNode);
1835
1836     DOMString text(textNode->data());
1837
1838     // count up all spaces and newlines in front of the caret
1839     // delete all collapsed ones
1840     // this will work out OK since the offset we have been passed has been upstream-ized 
1841     int count = 0;
1842     for (unsigned int i = offset; i < text.length(); i++) {
1843         if (isCollapsibleWhitespace(text[i]))
1844             count++;
1845         else 
1846             break;
1847     }
1848     if (count > 0) {
1849         // By checking the character at the downstream position, we can
1850         // check if there is a rendered WS at the caret
1851         Position pos(textNode, offset);
1852         Position downstream = pos.downstream();
1853         if (downstream.offset() < (long)text.length() && isCollapsibleWhitespace(text[downstream.offset()]))
1854             count--; // leave this WS in
1855         if (count > 0)
1856             deleteTextFromNode(textNode, offset, count);
1857     }
1858
1859     if (offset > 0 && offset <= text.length() - 1 && !isCollapsibleWhitespace(text[offset]) && !isCollapsibleWhitespace(text[offset - 1])) {
1860         // insert a "regular" space
1861         insertTextIntoNode(textNode, offset, " ");
1862         return;
1863     }
1864
1865     if (text.length() >= 2 && offset >= 2 && isNBSP(text[offset - 2]) && isNBSP(text[offset - 1])) {
1866         // DOM looks like this:
1867         // nbsp nbsp caret
1868         // insert a space between the two nbsps
1869         insertTextIntoNode(textNode, offset - 1, " ");
1870         return;
1871     }
1872
1873     // insert an nbsp
1874     insertTextIntoNode(textNode, offset, nonBreakingSpaceString());
1875 }
1876
1877 bool InsertTextCommand::isInsertTextCommand() const
1878 {
1879     return true;
1880 }
1881
1882 //------------------------------------------------------------------------------------------
1883 // JoinTextNodesCommand
1884
1885 JoinTextNodesCommand::JoinTextNodesCommand(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
1886     : EditCommand(document), m_text1(text1), m_text2(text2)
1887 {
1888     ASSERT(m_text1);
1889     ASSERT(m_text2);
1890     ASSERT(m_text1->nextSibling() == m_text2);
1891     ASSERT(m_text1->length() > 0);
1892     ASSERT(m_text2->length() > 0);
1893
1894     m_text1->ref();
1895     m_text2->ref();
1896 }
1897
1898 JoinTextNodesCommand::~JoinTextNodesCommand()
1899 {
1900     ASSERT(m_text1);
1901     m_text1->deref();
1902     ASSERT(m_text2);
1903     m_text2->deref();
1904 }
1905
1906 void JoinTextNodesCommand::doApply()
1907 {
1908     ASSERT(m_text1);
1909     ASSERT(m_text2);
1910     ASSERT(m_text1->nextSibling() == m_text2);
1911
1912     int exceptionCode = 0;
1913     m_text2->insertData(0, m_text1->data(), exceptionCode);
1914     ASSERT(exceptionCode == 0);
1915
1916     m_text2->parentNode()->removeChild(m_text1, exceptionCode);
1917     ASSERT(exceptionCode == 0);
1918
1919     m_offset = m_text1->length();
1920 }
1921
1922 void JoinTextNodesCommand::doUnapply()
1923 {
1924     ASSERT(m_text2);
1925     ASSERT(m_offset > 0);
1926
1927     int exceptionCode = 0;
1928
1929     m_text2->deleteData(0, m_offset, exceptionCode);
1930     ASSERT(exceptionCode == 0);
1931
1932     m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
1933     ASSERT(exceptionCode == 0);
1934         
1935     ASSERT(m_text2->previousSibling()->isTextNode());
1936     ASSERT(m_text2->previousSibling() == m_text1);
1937 }
1938
1939 //------------------------------------------------------------------------------------------
1940 // MoveSelectionCommand
1941
1942 MoveSelectionCommand::MoveSelectionCommand(DocumentImpl *document, DocumentFragmentImpl *fragment, Position &position, bool smartMove) 
1943     : CompositeEditCommand(document), m_fragment(fragment), m_position(position), m_smartMove(smartMove)
1944 {
1945     ASSERT(m_fragment);
1946     m_fragment->ref();
1947 }
1948
1949 MoveSelectionCommand::~MoveSelectionCommand()
1950 {
1951     ASSERT(m_fragment);
1952     m_fragment->deref();
1953 }
1954
1955 void MoveSelectionCommand::doApply()
1956 {
1957     Selection selection = endingSelection();
1958     ASSERT(selection.isRange());
1959
1960     Position pos = m_position;
1961     if (pos.isNull())
1962         return;
1963         
1964     // Update the position otherwise it may become invalid after the selection is deleted.
1965     NodeImpl *positionNode = m_position.node();
1966     long positionOffset = m_position.offset();
1967     Position selectionEnd = selection.end();
1968     long selectionEndOffset = selectionEnd.offset();    
1969     if (selectionEnd.node() == positionNode && selectionEndOffset < positionOffset) {
1970         positionOffset -= selectionEndOffset;
1971         Position selectionStart = selection.start();
1972         if (selectionStart.node() == positionNode) {
1973             positionOffset += selectionStart.offset();
1974         }
1975         pos = Position(positionNode, positionOffset);
1976     }
1977
1978     deleteSelection(m_smartMove);
1979
1980     // If the node for the destination has been removed as a result of the deletion,
1981     // set the destination to the ending point after the deletion.
1982     // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSelectionCommand; 
1983     //        selection is empty, leading to null deref
1984     if (!pos.node()->inDocument())
1985         pos = endingSelection().start();
1986
1987     setEndingSelection(pos, endingSelection().startAffinity());
1988     EditCommandPtr cmd(new ReplaceSelectionCommand(document(), m_fragment, true, m_smartMove));
1989     applyCommandToComposite(cmd);
1990 }
1991
1992 EditAction MoveSelectionCommand::editingAction() const
1993 {
1994     return EditActionDrag;
1995 }
1996
1997 //------------------------------------------------------------------------------------------
1998 // RebalanceWhitespaceCommand
1999
2000 RebalanceWhitespaceCommand::RebalanceWhitespaceCommand(DocumentImpl *document, const Position &pos)
2001     : EditCommand(document), m_position(pos), m_upstreamOffset(InvalidOffset), m_downstreamOffset(InvalidOffset)
2002 {
2003 }
2004
2005 RebalanceWhitespaceCommand::~RebalanceWhitespaceCommand()
2006 {
2007 }
2008
2009 void RebalanceWhitespaceCommand::doApply()
2010 {
2011     static DOMString space(" ");
2012
2013     if (m_position.isNull() || !m_position.node()->isTextNode())
2014         return;
2015         
2016     TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
2017     DOMString text = textNode->data();
2018     if (text.length() == 0)
2019         return;
2020     
2021     // find upstream offset
2022     long upstream = m_position.offset();
2023     while (upstream > 0 && isCollapsibleWhitespace(text[upstream - 1]) || isNBSP(text[upstream - 1])) {
2024         upstream--;
2025         m_upstreamOffset = upstream;
2026     }
2027
2028     // find downstream offset
2029     long downstream = m_position.offset();
2030     while ((unsigned)downstream < text.length() && isCollapsibleWhitespace(text[downstream]) || isNBSP(text[downstream])) {
2031         downstream++;
2032         m_downstreamOffset = downstream;
2033     }
2034
2035     if (m_upstreamOffset == InvalidOffset && m_downstreamOffset == InvalidOffset)
2036         return;
2037         
2038     m_upstreamOffset = upstream;
2039     m_downstreamOffset = downstream;
2040     long length = m_downstreamOffset - m_upstreamOffset;
2041     
2042     m_beforeString = text.substring(m_upstreamOffset, length);
2043     
2044     // The following loop figures out a "rebalanced" whitespace string for any length
2045     // string, and takes into account the special cases that need to handled for the
2046     // start and end of strings (i.e. first and last character must be an nbsp.
2047     long i = m_upstreamOffset;
2048     while (i < m_downstreamOffset) {
2049         long add = (m_downstreamOffset - i) % 3;
2050         switch (add) {
2051             case 0:
2052                 m_afterString += nonBreakingSpaceString();
2053                 m_afterString += space;
2054                 m_afterString += nonBreakingSpaceString();
2055                 add = 3;
2056                 break;
2057             case 1:
2058                 if (i == 0 || (unsigned)i + 1 == text.length()) // at start or end of string
2059                     m_afterString += nonBreakingSpaceString();
2060                 else
2061                     m_afterString += space;
2062                 break;
2063             case 2:
2064                 if ((unsigned)i + 2 == text.length()) {
2065                      // at end of string
2066                     m_afterString += nonBreakingSpaceString();
2067                     m_afterString += nonBreakingSpaceString();
2068                 }
2069                 else {
2070                     m_afterString += nonBreakingSpaceString();
2071                     m_afterString += space;
2072                 }
2073                 break;
2074         }
2075         i += add;
2076     }
2077     
2078     text.remove(m_upstreamOffset, length);
2079     text.insert(m_afterString, m_upstreamOffset);
2080 }
2081
2082 void RebalanceWhitespaceCommand::doUnapply()
2083 {
2084     if (m_upstreamOffset == InvalidOffset && m_downstreamOffset == InvalidOffset)
2085         return;
2086     
2087     ASSERT(m_position.node()->isTextNode());
2088     TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
2089     DOMString text = textNode->data();
2090     text.remove(m_upstreamOffset, m_afterString.length());
2091     text.insert(m_beforeString, m_upstreamOffset);
2092 }
2093
2094 bool RebalanceWhitespaceCommand::preservesTypingStyle() const
2095 {
2096     return true;
2097 }
2098
2099 //------------------------------------------------------------------------------------------
2100 // RemoveCSSPropertyCommand
2101
2102 RemoveCSSPropertyCommand::RemoveCSSPropertyCommand(DocumentImpl *document, CSSStyleDeclarationImpl *decl, int property)
2103     : EditCommand(document), m_decl(decl->makeMutable()), m_property(property), m_important(false)
2104 {
2105     ASSERT(m_decl);
2106     m_decl->ref();
2107 }
2108
2109 RemoveCSSPropertyCommand::~RemoveCSSPropertyCommand()
2110 {
2111     ASSERT(m_decl);
2112     m_decl->deref();
2113 }
2114
2115 void RemoveCSSPropertyCommand::doApply()
2116 {
2117     ASSERT(m_decl);
2118
2119     m_oldValue = m_decl->getPropertyValue(m_property);
2120     ASSERT(!m_oldValue.isNull());
2121
2122     m_important = m_decl->getPropertyPriority(m_property);
2123     m_decl->removeProperty(m_property);
2124 }
2125
2126 void RemoveCSSPropertyCommand::doUnapply()
2127 {
2128     ASSERT(m_decl);
2129     ASSERT(!m_oldValue.isNull());
2130
2131     m_decl->setProperty(m_property, m_oldValue, m_important);
2132 }
2133
2134 //------------------------------------------------------------------------------------------
2135 // RemoveNodeAttributeCommand
2136
2137 RemoveNodeAttributeCommand::RemoveNodeAttributeCommand(DocumentImpl *document, ElementImpl *element, NodeImpl::Id attribute)
2138     : EditCommand(document), m_element(element), m_attribute(attribute)
2139 {
2140     ASSERT(m_element);
2141     m_element->ref();
2142 }
2143
2144 RemoveNodeAttributeCommand::~RemoveNodeAttributeCommand()
2145 {
2146     ASSERT(m_element);
2147     m_element->deref();
2148 }
2149
2150 void RemoveNodeAttributeCommand::doApply()
2151 {
2152     ASSERT(m_element);
2153
2154     m_oldValue = m_element->getAttribute(m_attribute);
2155     ASSERT(!m_oldValue.isNull());
2156
2157     int exceptionCode = 0;
2158     m_element->removeAttribute(m_attribute, exceptionCode);
2159     ASSERT(exceptionCode == 0);
2160 }
2161
2162 void RemoveNodeAttributeCommand::doUnapply()
2163 {
2164     ASSERT(m_element);
2165     ASSERT(!m_oldValue.isNull());
2166
2167     int exceptionCode = 0;
2168     m_element->setAttribute(m_attribute, m_oldValue.implementation(), exceptionCode);
2169     ASSERT(exceptionCode == 0);
2170 }
2171
2172 //------------------------------------------------------------------------------------------
2173 // RemoveNodeCommand
2174
2175 RemoveNodeCommand::RemoveNodeCommand(DocumentImpl *document, NodeImpl *removeChild)
2176     : EditCommand(document), m_parent(0), m_removeChild(removeChild), m_refChild(0)
2177 {
2178     ASSERT(m_removeChild);
2179     m_removeChild->ref();
2180
2181     m_parent = m_removeChild->parentNode();
2182     ASSERT(m_parent);
2183     m_parent->ref();
2184     
2185     m_refChild = m_removeChild->nextSibling();
2186     if (m_refChild)
2187         m_refChild->ref();
2188 }
2189
2190 RemoveNodeCommand::~RemoveNodeCommand()
2191 {
2192     ASSERT(m_parent);
2193     m_parent->deref();
2194
2195     ASSERT(m_removeChild);
2196     m_removeChild->deref();
2197
2198     if (m_refChild)
2199         m_refChild->deref();
2200 }
2201
2202 void RemoveNodeCommand::doApply()
2203 {
2204     ASSERT(m_parent);
2205     ASSERT(m_removeChild);
2206
2207     int exceptionCode = 0;
2208     m_parent->removeChild(m_removeChild, exceptionCode);
2209     ASSERT(exceptionCode == 0);
2210 }
2211
2212 void RemoveNodeCommand::doUnapply()
2213 {
2214     ASSERT(m_parent);
2215     ASSERT(m_removeChild);
2216
2217     int exceptionCode = 0;
2218     m_parent->insertBefore(m_removeChild, m_refChild, exceptionCode);
2219     ASSERT(exceptionCode == 0);
2220 }
2221
2222 //------------------------------------------------------------------------------------------
2223 // RemoveNodePreservingChildrenCommand
2224
2225 RemoveNodePreservingChildrenCommand::RemoveNodePreservingChildrenCommand(DocumentImpl *document, NodeImpl *node)
2226     : CompositeEditCommand(document), m_node(node)
2227 {
2228     ASSERT(m_node);
2229     m_node->ref();
2230 }
2231
2232 RemoveNodePreservingChildrenCommand::~RemoveNodePreservingChildrenCommand()
2233 {
2234     ASSERT(m_node);
2235     m_node->deref();
2236 }
2237
2238 void RemoveNodePreservingChildrenCommand::doApply()
2239 {
2240     while (NodeImpl* curr = node()->firstChild()) {
2241         removeNode(curr);
2242         insertNodeBefore(curr, node());
2243     }
2244     removeNode(node());
2245 }
2246
2247 //------------------------------------------------------------------------------------------
2248 // ReplaceSelectionCommand
2249
2250 ReplacementFragment::ReplacementFragment(DocumentImpl *document, DocumentFragmentImpl *fragment, bool matchStyle)
2251     : m_document(document), 
2252       m_fragment(fragment), 
2253       m_matchStyle(matchStyle), 
2254       m_hasInterchangeNewlineAtStart(false), 
2255       m_hasInterchangeNewlineAtEnd(false), 
2256       m_hasMoreThanOneBlock(false)
2257 {
2258     if (!m_document)
2259         return;
2260
2261     if (!m_fragment) {
2262         m_type = EmptyFragment;
2263         return;
2264     }
2265
2266     m_document->ref();
2267     m_fragment->ref();
2268
2269     NodeImpl *firstChild = m_fragment->firstChild();
2270     NodeImpl *lastChild = m_fragment->lastChild();
2271
2272     if (!firstChild) {
2273         m_type = EmptyFragment;
2274         return;
2275     }
2276
2277     if (firstChild == lastChild && firstChild->isTextNode()) {
2278         m_type = SingleTextNodeFragment;
2279         return;
2280     }
2281     
2282     m_type = TreeFragment;
2283
2284     NodeImpl *node = m_fragment->firstChild();
2285     NodeImpl *newlineAtStartNode = 0;
2286     NodeImpl *newlineAtEndNode = 0;
2287     while (node) {
2288         NodeImpl *next = node->traverseNextNode();
2289         if (isInterchangeNewlineNode(node)) {
2290             if (next || node == m_fragment->firstChild()) {
2291                 m_hasInterchangeNewlineAtStart = true;
2292                 newlineAtStartNode = node;
2293             }
2294             else {
2295                 m_hasInterchangeNewlineAtEnd = true;
2296                 newlineAtEndNode = node;
2297             }
2298         }
2299         else if (isInterchangeConvertedSpaceSpan(node)) {
2300             NodeImpl *n = 0;
2301             while ((n = node->firstChild())) {
2302                 n->ref();
2303                 removeNode(n);
2304                 insertNodeBefore(n, node);
2305                 n->deref();
2306             }
2307             removeNode(node);
2308             if (n)
2309                 next = n->traverseNextNode();
2310         }
2311         node = next;
2312     }
2313
2314     if (newlineAtStartNode)
2315         removeNode(newlineAtStartNode);
2316     if (newlineAtEndNode)
2317         removeNode(newlineAtEndNode);
2318     
2319     NodeImpl *holder = insertFragmentForTestRendering();
2320     if (holder)
2321         holder->ref();
2322     if (!m_matchStyle) {
2323         computeStylesUsingTestRendering(holder);
2324     }
2325     removeUnrenderedNodesUsingTestRendering(holder);
2326     m_hasMoreThanOneBlock = countRenderedBlocks(holder) > 1;
2327     restoreTestRenderingNodesToFragment(holder);
2328     removeNode(holder);
2329     holder->deref();
2330     removeStyleNodes();
2331 }
2332
2333 ReplacementFragment::~ReplacementFragment()
2334 {
2335     if (m_document)
2336         m_document->deref();
2337     if (m_fragment)
2338         m_fragment->deref();
2339 }
2340
2341 NodeImpl *ReplacementFragment::firstChild() const 
2342
2343     return m_fragment->firstChild(); 
2344 }
2345
2346 NodeImpl *ReplacementFragment::lastChild() const 
2347
2348     return  m_fragment->lastChild(); 
2349 }
2350
2351 NodeImpl *ReplacementFragment::mergeStartNode() const
2352 {
2353     NodeImpl *node = m_fragment->firstChild();
2354     while (node && isProbablyBlock(node) && !isMailPasteAsQuotationNode(node))
2355         node = node->traverseNextNode();
2356     return node;
2357 }
2358
2359 void ReplacementFragment::pruneEmptyNodes()
2360 {
2361     bool run = true;
2362     while (run) {
2363         run = false;
2364         NodeImpl *node = m_fragment->firstChild();
2365         while (node) {
2366             if ((node->isTextNode() && static_cast<TextImpl *>(node)->length() == 0) ||
2367                 (isProbablyBlock(node) && !isProbablyTableStructureNode(node) && node->childNodeCount() == 0)) {
2368                 NodeImpl *next = node->traverseNextSibling();
2369                 removeNode(node);
2370                 node = next;
2371                 run = true;
2372             }
2373             else {
2374                 node = node->traverseNextNode();
2375             }
2376          }
2377     }
2378 }
2379
2380 bool ReplacementFragment::isInterchangeNewlineNode(const NodeImpl *node)
2381 {
2382     static DOMString interchangeNewlineClassString(AppleInterchangeNewline);
2383     return node && node->id() == ID_BR && static_cast<const ElementImpl *>(node)->getAttribute(ATTR_CLASS) == interchangeNewlineClassString;
2384 }
2385
2386 bool ReplacementFragment::isInterchangeConvertedSpaceSpan(const NodeImpl *node)
2387 {
2388     static DOMString convertedSpaceSpanClassString(AppleConvertedSpace);
2389     return node->isHTMLElement() && static_cast<const HTMLElementImpl *>(node)->getAttribute(ATTR_CLASS) == convertedSpaceSpanClassString;
2390 }
2391
2392 NodeImpl *ReplacementFragment::enclosingBlock(NodeImpl *node) const
2393 {
2394     while (node && !isProbablyBlock(node))
2395         node = node->parentNode();    
2396     return node ? node : m_fragment;
2397 }
2398
2399 void ReplacementFragment::removeNodePreservingChildren(NodeImpl *node)
2400 {
2401     if (!node)
2402         return;
2403
2404     while (NodeImpl *n = node->firstChild()) {
2405         n->ref();
2406         removeNode(n);
2407         insertNodeBefore(n, node);
2408         n->deref();
2409     }
2410     removeNode(node);
2411 }
2412
2413 void ReplacementFragment::removeNode(NodeImpl *node)
2414 {
2415     if (!node)
2416         return;
2417         
2418     NodeImpl *parent = node->parentNode();
2419     if (!parent)
2420         return;
2421         
2422     int exceptionCode = 0;
2423     parent->removeChild(node, exceptionCode);
2424     ASSERT(exceptionCode == 0);
2425 }
2426
2427 void ReplacementFragment::insertNodeBefore(NodeImpl *node, NodeImpl *refNode)
2428 {
2429     if (!node || !refNode)
2430         return;
2431         
2432     NodeImpl *parent = refNode->parentNode();
2433     if (!parent)
2434         return;
2435         
2436     int exceptionCode = 0;
2437     parent->insertBefore(node, refNode, exceptionCode);
2438     ASSERT(exceptionCode == 0);
2439 }
2440
2441 NodeImpl *ReplacementFragment::insertFragmentForTestRendering()
2442 {
2443     NodeImpl *body = m_document->body();
2444     if (!body)
2445         return 0;
2446
2447     ElementImpl *holder = createDefaultParagraphElement(m_document);
2448     holder->ref();
2449     
2450     int exceptionCode = 0;
2451     holder->appendChild(m_fragment, exceptionCode);
2452     ASSERT(exceptionCode == 0);
2453     
2454     body->appendChild(holder, exceptionCode);
2455     ASSERT(exceptionCode == 0);
2456     holder->deref();
2457     
2458     m_document->updateLayout();
2459     
2460     return holder;
2461 }
2462
2463 void ReplacementFragment::restoreTestRenderingNodesToFragment(NodeImpl *holder)
2464 {
2465     if (!holder)
2466         return;
2467
2468     int exceptionCode = 0;
2469     while (NodeImpl *node = holder->firstChild()) {
2470         node->ref();
2471         holder->removeChild(node, exceptionCode);
2472         ASSERT(exceptionCode == 0);
2473         m_fragment->appendChild(node, exceptionCode);
2474         ASSERT(exceptionCode == 0);
2475         node->deref();
2476     }
2477 }
2478
2479 void ReplacementFragment::computeStylesUsingTestRendering(NodeImpl *holder)
2480 {
2481     if (!holder)
2482         return;
2483
2484     m_document->updateLayout();
2485
2486     for (NodeImpl *node = holder->firstChild(); node; node = node->traverseNextNode(holder))
2487         computeAndStoreNodeDesiredStyle(node, m_styles);
2488 }
2489
2490 void ReplacementFragment::removeUnrenderedNodesUsingTestRendering(NodeImpl *holder)
2491 {
2492     if (!holder)
2493         return;
2494
2495     QPtrList<NodeImpl> unrendered;
2496
2497     for (NodeImpl *node = holder->firstChild(); node; node = node->traverseNextNode(holder)) {
2498         if (!isNodeRendered(node) && !isTableStructureNode(node))
2499             unrendered.append(node);
2500     }
2501
2502     for (QPtrListIterator<NodeImpl> it(unrendered); it.current(); ++it)
2503         removeNode(it.current());
2504 }
2505
2506 int ReplacementFragment::countRenderedBlocks(NodeImpl *holder)
2507 {
2508     if (!holder)
2509         return 0;
2510     
2511     int count = 0;
2512     NodeImpl *prev = 0;
2513     for (NodeImpl *node = holder->firstChild(); node; node = node->traverseNextNode(holder)) {
2514         if (node->isBlockFlow()) {
2515             if (!prev) {
2516                 count++;
2517                 prev = node;
2518             }
2519         }
2520         else {
2521             NodeImpl *block = node->enclosingBlockFlowElement();
2522             if (block != prev) {
2523                 count++;
2524                 prev = block;
2525             }
2526         }
2527     }
2528     
2529     return count;
2530 }
2531
2532 void ReplacementFragment::removeStyleNodes()
2533 {
2534     // Since style information has been computed and cached away in
2535     // computeStylesForNodes(), these style nodes can be removed, since
2536     // the correct styles will be added back in fixupNodeStyles().
2537     NodeImpl *node = m_fragment->firstChild();
2538     while (node) {
2539         NodeImpl *next = node->traverseNextNode();
2540         // This list of tags change the appearance of content
2541         // in ways we can add back on later with CSS, if necessary.
2542         if (node->id() == ID_B || 
2543             node->id() == ID_BIG || 
2544             node->id() == ID_CENTER || 
2545             node->id() == ID_FONT || 
2546             node->id() == ID_I || 
2547             node->id() == ID_S || 
2548             node->id() == ID_SMALL || 
2549             node->id() == ID_STRIKE || 
2550             node->id() == ID_SUB || 
2551             node->id() == ID_SUP || 
2552             node->id() == ID_TT || 
2553             node->id() == ID_U || 
2554             isStyleSpan(node)) {
2555             removeNodePreservingChildren(node);
2556         }
2557         else if (node->isHTMLElement()) {
2558             HTMLElementImpl *elem = static_cast<HTMLElementImpl *>(node);
2559             CSSMutableStyleDeclarationImpl *inlineStyleDecl = elem->inlineStyleDecl();
2560             if (inlineStyleDecl) {
2561                 inlineStyleDecl->removeBlockProperties();
2562                 inlineStyleDecl->removeInheritableProperties();
2563             }
2564         }
2565         node = next;
2566     }
2567 }
2568
2569 NodeDesiredStyle::NodeDesiredStyle(NodeImpl *node, CSSMutableStyleDeclarationImpl *style) 
2570     : m_node(node), m_style(style)
2571 {
2572     if (m_node)
2573         m_node->ref();
2574     if (m_style)
2575         m_style->ref();
2576 }
2577
2578 NodeDesiredStyle::NodeDesiredStyle(const NodeDesiredStyle &other)
2579     : m_node(other.node()), m_style(other.style())
2580 {
2581     if (m_node)
2582         m_node->ref();
2583     if (m_style)
2584         m_style->ref();
2585 }
2586
2587 NodeDesiredStyle::~NodeDesiredStyle()
2588 {
2589     if (m_node)
2590         m_node->deref();
2591     if (m_style)
2592         m_style->deref();
2593 }
2594
2595 NodeDesiredStyle &NodeDesiredStyle::operator=(const NodeDesiredStyle &other)
2596 {
2597     NodeImpl *oldNode = m_node;
2598     CSSMutableStyleDeclarationImpl *oldStyle = m_style;
2599
2600     m_node = other.node();
2601     m_style = other.style();
2602     
2603     if (m_node)
2604         m_node->ref();
2605     if (m_style)
2606         m_style->ref();
2607     
2608     if (oldNode)
2609         oldNode->deref();
2610     if (oldStyle)
2611         oldStyle->deref();
2612         
2613     return *this;
2614 }
2615
2616 ReplaceSelectionCommand::ReplaceSelectionCommand(DocumentImpl *document, DocumentFragmentImpl *fragment, bool selectReplacement, bool smartReplace, bool matchStyle) 
2617     : CompositeEditCommand(document), 
2618       m_fragment(document, fragment, matchStyle),
2619       m_firstNodeInserted(0),
2620       m_lastNodeInserted(0),
2621       m_lastTopNodeInserted(0),
2622       m_insertionStyle(0),
2623       m_selectReplacement(selectReplacement), 
2624       m_smartReplace(smartReplace),
2625       m_matchStyle(matchStyle)
2626 {
2627 }
2628
2629 ReplaceSelectionCommand::~ReplaceSelectionCommand()
2630 {
2631     if (m_firstNodeInserted)
2632         m_firstNodeInserted->deref();
2633     if (m_lastNodeInserted)
2634         m_lastNodeInserted->deref();
2635     if (m_lastTopNodeInserted)
2636         m_lastTopNodeInserted->deref();
2637     if (m_insertionStyle)
2638         m_insertionStyle->deref();
2639 }
2640
2641 void ReplaceSelectionCommand::doApply()
2642 {
2643     // collect information about the current selection, prior to deleting the selection
2644     Selection selection = endingSelection();
2645     ASSERT(selection.isCaretOrRange());
2646
2647     VisiblePosition visibleStart(selection.start(), selection.startAffinity());
2648     VisiblePosition visibleEnd(selection.end(), selection.endAffinity());
2649     bool startAtStartOfBlock = isStartOfBlock(visibleStart);
2650     bool startAtEndOfBlock = isEndOfBlock(visibleStart);
2651     bool startAtBlockBoundary = startAtStartOfBlock || startAtEndOfBlock;
2652     NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
2653     NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
2654
2655     // decide whether to later merge content into the startBlock
2656     bool mergeStart = false;
2657     if (startBlock == startBlock->rootEditableElement() && startAtStartOfBlock && startAtEndOfBlock) {
2658         // empty editable subtree, need to mergeStart so that fragment ends up
2659         // inside the editable subtree rather than just before it
2660         mergeStart = false;
2661     } else {
2662         // merge if current selection starts inside a paragraph, or there is only one block and no interchange newline to add
2663         mergeStart = !m_fragment.hasInterchangeNewlineAtStart() && 
2664             (!isStartOfParagraph(visibleStart) || (!m_fragment.hasInterchangeNewlineAtEnd() && !m_fragment.hasMoreThanOneBlock())) &&
2665             !isLastVisiblePositionInSpecialElement(selection.start());
2666         
2667         // This is a workaround for this bug:
2668         // <rdar://problem/4013642> REGRESSION (Mail): Copied quoted word does not paste as a quote if pasted at the start of a line
2669         // We need more powerful logic in this whole mergeStart code for this case to come out right without
2670         // breaking other cases.
2671         if (isStartOfParagraph(visibleStart) && isMailBlockquote(m_fragment.firstChild()))
2672             mergeStart = false;
2673     }
2674     
2675     // decide whether to later append nodes to the end
2676     NodeImpl *beyondEndNode = 0;
2677     if (!isEndOfParagraph(visibleEnd) && !m_fragment.hasInterchangeNewlineAtEnd()) {
2678         Position beyondEndPos = selection.end().downstream();
2679         if (!isFirstVisiblePositionInSpecialElement(beyondEndPos))
2680             beyondEndNode = beyondEndPos.node();
2681     }
2682     bool moveNodesAfterEnd = beyondEndNode && (startBlock != endBlock || m_fragment.hasMoreThanOneBlock());
2683
2684     Position startPos = selection.start();
2685     
2686     // delete the current range selection, or insert paragraph for caret selection, as needed
2687     if (selection.isRange()) {
2688         deleteSelection(false, !(m_fragment.hasInterchangeNewlineAtStart() || m_fragment.hasInterchangeNewlineAtEnd() || m_fragment.hasMoreThanOneBlock()));
2689         document()->updateLayout();
2690         visibleStart = VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY);
2691         if (m_fragment.hasInterchangeNewlineAtStart()) {
2692             if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
2693                 if (!isEndOfDocument(visibleStart))
2694                     setEndingSelection(visibleStart.next());
2695             }
2696             else {
2697                 insertParagraphSeparator();
2698                 setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY));
2699             }
2700         }
2701         startPos = endingSelection().start();
2702     } 
2703     else {
2704         ASSERT(selection.isCaret());
2705         if (m_fragment.hasInterchangeNewlineAtStart()) {
2706             if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
2707                 if (!isEndOfDocument(visibleStart))
2708                     setEndingSelection(visibleStart.next());
2709             }
2710             else {
2711                 insertParagraphSeparator();
2712                 setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY));
2713             }
2714         }
2715         if (!m_fragment.hasInterchangeNewlineAtEnd() && m_fragment.hasMoreThanOneBlock() && 
2716             !startAtBlockBoundary && !isEndOfParagraph(visibleEnd)) {
2717             // The start and the end need to wind up in separate blocks.
2718             // Insert a paragraph separator to make that happen.
2719             insertParagraphSeparator();
2720             setEndingSelection(VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY).previous());
2721         }
2722         startPos = endingSelection().start();
2723     }
2724
2725     if (startAtStartOfBlock && startBlock->inDocument())
2726         startPos = Position(startBlock, 0);
2727
2728     startPos = positionOutsideContainingSpecialElement(startPos);
2729
2730     KHTMLPart *part = document()->part();
2731     if (m_matchStyle) {
2732         m_insertionStyle = styleAtPosition(startPos);
2733         m_insertionStyle->ref();
2734     }
2735     
2736     // FIXME: Improve typing style.
2737     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
2738     part->clearTypingStyle();
2739     setTypingStyle(0);    
2740     
2741     // done if there is nothing to add
2742     if (!m_fragment.firstChild())
2743         return;
2744     
2745     // check for a line placeholder, and store it away for possible removal later.
2746     NodeImpl *block = startPos.node()->enclosingBlockFlowElement();
2747     NodeImpl *linePlaceholder = findBlockPlaceholder(block);
2748     if (!linePlaceholder) {
2749         Position downstream = startPos.downstream();
2750         downstream = positionOutsideContainingSpecialElement(downstream);
2751         if (downstream.node()->id() == ID_BR && downstream.offset() == 0 && 
2752             m_fragment.hasInterchangeNewlineAtEnd() &&
2753             isStartOfLine(VisiblePosition(downstream, VP_DEFAULT_AFFINITY)))
2754             linePlaceholder = downstream.node();
2755     }
2756     
2757     // check whether to "smart replace" needs to add leading and/or trailing space
2758     bool addLeadingSpace = false;
2759     bool addTrailingSpace = false;
2760     // FIXME: We need the affinity for startPos and endPos, but Position::downstream
2761     // and Position::upstream do not give it
2762     if (m_smartReplace) {
2763         VisiblePosition visiblePos = VisiblePosition(startPos, VP_DEFAULT_AFFINITY);
2764         assert(visiblePos.isNotNull());
2765         addLeadingSpace = startPos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isStartOfLine(visiblePos);
2766         if (addLeadingSpace) {
2767             QChar previousChar = visiblePos.previous().character();
2768             if (!previousChar.isNull()) {
2769                 addLeadingSpace = !part->isCharacterSmartReplaceExempt(previousChar, true);
2770             }
2771         }
2772         addTrailingSpace = startPos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull() && !isEndOfLine(visiblePos);
2773         if (addTrailingSpace) {
2774             QChar thisChar = visiblePos.character();
2775             if (!thisChar.isNull()) {
2776                 addTrailingSpace = !part->isCharacterSmartReplaceExempt(thisChar, false);
2777             }
2778         }
2779     }
2780     
2781     // There are five steps to adding the content: merge blocks at start, add remaining blocks,
2782     // add "smart replace" space, handle trailing newline, clean up.
2783     
2784     // initially, we say the insertion point is the start of selection
2785     document()->updateLayout();
2786     Position insertionPos = startPos;
2787
2788     // step 1: merge content into the start block, if that is needed
2789     if (mergeStart && !isFirstVisiblePositionInSpecialElementInFragment(Position(m_fragment.mergeStartNode(), 0))) {
2790         NodeImpl *refNode = m_fragment.mergeStartNode();
2791         if (refNode) {
2792             NodeImpl *node = refNode ? refNode->nextSibling() : 0;
2793             insertNodeAtAndUpdateNodesInserted(refNode, startPos.node(), startPos.offset());
2794             while (node && !isProbablyBlock(node)) {
2795                 NodeImpl *next = node->nextSibling();
2796                 insertNodeAfterAndUpdateNodesInserted(node, refNode);
2797                 refNode = node;
2798                 node = next;
2799             }
2800         }
2801         
2802         // update insertion point to be at the end of the last block inserted
2803         if (m_lastNodeInserted) {
2804             document()->updateLayout();
2805             insertionPos = Position(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
2806         }
2807     }
2808
2809     // prune empty nodes from fragment
2810     // NOTE: why was this not done earlier, before the mergeStart?
2811     m_fragment.pruneEmptyNodes();
2812     
2813     // step 2 : merge everything remaining in the fragment
2814     if (m_fragment.firstChild()) {
2815         NodeImpl *refNode = m_fragment.firstChild();
2816         NodeImpl *node = refNode ? refNode->nextSibling() : 0;
2817         NodeImpl *insertionBlock = insertionPos.node()->enclosingBlockFlowElement();
2818         bool insertionBlockIsRoot = insertionBlock == insertionBlock->rootEditableElement();
2819         VisiblePosition visiblePos(insertionPos, DOWNSTREAM);
2820         if (!insertionBlockIsRoot && isProbablyBlock(refNode) && isStartOfBlock(visiblePos))
2821             insertNodeBeforeAndUpdateNodesInserted(refNode, insertionBlock);
2822         else if (!insertionBlockIsRoot && isProbablyBlock(refNode) && isEndOfBlock(visiblePos)) {
2823             insertNodeAfterAndUpdateNodesInserted(refNode, insertionBlock);
2824         } else if (mergeStart && !isProbablyBlock(refNode)) {
2825             Position pos = visiblePos.next().deepEquivalent().downstream();
2826             insertNodeAtAndUpdateNodesInserted(refNode, pos.node(), pos.offset());
2827         } else {
2828             insertNodeAtAndUpdateNodesInserted(refNode, insertionPos.node(), insertionPos.offset());
2829         }
2830         
2831         while (node) {
2832             NodeImpl *next = node->nextSibling();
2833             insertNodeAfterAndUpdateNodesInserted(node, refNode);
2834             refNode = node;
2835             node = next;
2836         }
2837         document()->updateLayout();
2838         insertionPos = Position(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
2839     }
2840
2841     // step 3 : handle "smart replace" whitespace
2842     if (addTrailingSpace && m_lastNodeInserted) {
2843         document()->updateLayout();
2844         Position pos(m_lastNodeInserted, m_lastNodeInserted->caretMaxOffset());
2845         bool needsTrailingSpace = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull();
2846         if (needsTrailingSpace) {
2847             if (m_lastNodeInserted->isTextNode()) {
2848                 TextImpl *text = static_cast<TextImpl *>(m_lastNodeInserted);
2849                 insertTextIntoNode(text, text->length(), nonBreakingSpaceString());
2850                 insertionPos = Position(text, text->length());
2851             }
2852             else {
2853                 NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
2854                 insertNodeAfterAndUpdateNodesInserted(node, m_lastNodeInserted);
2855                 insertionPos = Position(node, 1);
2856             }
2857         }
2858     }
2859
2860     if (addLeadingSpace && m_firstNodeInserted) {
2861         document()->updateLayout();
2862         Position pos(m_firstNodeInserted, 0);
2863         bool needsLeadingSpace = pos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNull();
2864         if (needsLeadingSpace) {
2865             if (m_firstNodeInserted->isTextNode()) {
2866                 TextImpl *text = static_cast<TextImpl *>(m_firstNodeInserted);
2867                 insertTextIntoNode(text, 0, nonBreakingSpaceString());
2868             } else {
2869                 NodeImpl *node = document()->createEditingTextNode(nonBreakingSpaceString());
2870                 insertNodeBeforeAndUpdateNodesInserted(node, m_firstNodeInserted);
2871             }
2872         }
2873     }
2874     
2875     Position lastPositionToSelect;
2876
2877     // step 4 : handle trailing newline
2878     if (m_fragment.hasInterchangeNewlineAtEnd()) {
2879         removeLinePlaceholderIfNeeded(linePlaceholder);
2880
2881         if (!m_lastNodeInserted) {
2882             lastPositionToSelect = endingSelection().end().downstream();
2883         }
2884         else {
2885             bool insertParagraph = false;
2886             VisiblePosition pos(insertionPos, VP_DEFAULT_AFFINITY);
2887
2888             if (startBlock == endBlock && !isProbablyBlock(m_lastTopNodeInserted)) {
2889                 insertParagraph = true;
2890             } else {
2891                 // Handle end-of-document case.
2892                 document()->updateLayout();
2893                 if (isEndOfDocument(pos))
2894                     insertParagraph = true;
2895             }
2896             if (insertParagraph) {
2897                 setEndingSelection(insertionPos, DOWNSTREAM);
2898                 insertParagraphSeparator();
2899                 VisiblePosition next = pos.next();
2900
2901                 // Select up to the paragraph separator that was added.
2902                 lastPositionToSelect = next.deepEquivalent().downstream();
2903                 updateNodesInserted(lastPositionToSelect.node());
2904             } else {
2905                 // Select up to the preexising paragraph separator.
2906                 VisiblePosition next = pos.next();
2907                 lastPositionToSelect = next.deepEquivalent().downstream();
2908             }
2909         }
2910     } 
2911     else {
2912         if (m_lastNodeInserted && m_lastNodeInserted->id() == ID_BR && !document()->inStrictMode()) {
2913             document()->updateLayout();
2914             VisiblePosition pos(Position(m_lastNodeInserted, 1), DOWNSTREAM);
2915             if (isEndOfBlock(pos)) {
2916                 NodeImpl *next = m_lastNodeInserted->traverseNextNode();
2917                 bool hasTrailingBR = next && next->id() == ID_BR && m_lastNodeInserted->enclosingBlockFlowElement() == next->enclosingBlockFlowElement();
2918                 if (!hasTrailingBR) {
2919                     // Insert an "extra" BR at the end of the block. 
2920                     insertNodeBefore(createBreakElement(document()), m_lastNodeInserted);
2921                 }
2922             }
2923         }
2924
2925         if (moveNodesAfterEnd && !isLastVisiblePositionInSpecialElement(Position(m_lastNodeInserted, maxRangeOffset(m_lastNodeInserted)))) {
2926             document()->updateLayout();
2927             QValueList<NodeDesiredStyle> styles;
2928             QPtrList<NodeImpl> blocks;
2929             NodeImpl *node = beyondEndNode;
2930             NodeImpl *refNode = m_lastNodeInserted;
2931             while (node) {
2932                 RenderObject *renderer = node->renderer();
2933                 // Stop at the first table or block.
2934                 if (renderer && (renderer->isBlockFlow() || renderer->isTable()))
2935                     break;
2936                 NodeImpl *next = node->nextSibling();
2937                 blocks.append(node->enclosingBlockFlowElement());
2938                 computeAndStoreNodeDesiredStyle(node, styles);
2939                 removeNode(node);
2940                 // No need to update inserted node variables.
2941                 insertNodeAfter(node, refNode);
2942                 refNode = node;
2943                 // We want to move the first BR we see, so check for that here.
2944                 if (node->id() == ID_BR)
2945                     break;
2946                 node = next;
2947             }
2948             document()->updateLayout();
2949             for (QPtrListIterator<NodeImpl> it(blocks); it.current(); ++it) {
2950                 NodeImpl *blockToRemove = it.current();
2951                 if (!blockToRemove->inDocument())
2952                     continue;
2953                 if (!blockToRemove->renderer() || !blockToRemove->renderer()->firstChild()) {
2954                     if (blockToRemove->parentNode())
2955                         blocks.append(blockToRemove->parentNode()->enclosingBlockFlowElement());
2956                     removeNode(blockToRemove);
2957                     document()->updateLayout();
2958                 }
2959             }
2960
2961             fixupNodeStyles(styles);
2962         }
2963     }
2964     
2965     if (!m_matchStyle)
2966         fixupNodeStyles(m_fragment.desiredStyles());
2967     completeHTMLReplacement(lastPositionToSelect);
2968     
2969     // step 5 : mop up
2970     removeLinePlaceholderIfNeeded(linePlaceholder);
2971 }
2972
2973 void ReplaceSelectionCommand::removeLinePlaceholderIfNeeded(NodeImpl *linePlaceholder)
2974 {
2975     if (!linePlaceholder)
2976         return;
2977         
2978     document()->updateLayout();
2979     if (linePlaceholder->inDocument()) {
2980         VisiblePosition placeholderPos(linePlaceholder, linePlaceholder->renderer()->caretMinOffset(), DOWNSTREAM);
2981         if (placeholderPos.next().isNull() ||
2982             !(isStartOfLine(placeholderPos) && isEndOfLine(placeholderPos))) {
2983             NodeImpl *block = linePlaceholder->enclosingBlockFlowElement();
2984             removeNode(linePlaceholder);
2985             document()->updateLayout();
2986             if (!block->renderer() || block->renderer()->height() == 0)
2987                 removeNode(block);
2988         }
2989     }
2990 }
2991
2992 void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositionToSelect)
2993 {
2994     Position start;
2995     Position end;
2996
2997     if (m_firstNodeInserted && m_firstNodeInserted->inDocument() &&
2998         m_lastNodeInserted && m_lastNodeInserted->inDocument()) {
2999
3000         // Find the last leaf.
3001         NodeImpl *lastLeaf = m_lastNodeInserted;
3002         while (1) {
3003             NodeImpl *nextChild = lastLeaf->lastChild();
3004             if (!nextChild)
3005                 break;
3006             lastLeaf = nextChild;
3007         }
3008     
3009         // Find the first leaf.
3010         NodeImpl *firstLeaf = m_firstNodeInserted;
3011         while (1) {
3012             NodeImpl *nextChild = firstLeaf->firstChild();
3013             if (!nextChild)
3014                 break;
3015             firstLeaf = nextChild;
3016         }
3017         
3018         // Call updateLayout so caretMinOffset and caretMaxOffset return correct values.
3019         document()->updateLayout();
3020         start = Position(firstLeaf, firstLeaf->caretMinOffset());
3021         end = Position(lastLeaf, lastLeaf->caretMaxOffset());
3022
3023         if (m_matchStyle) {
3024             assert(m_insertionStyle);
3025             setEndingSelection(Selection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY));
3026             applyStyle(m_insertionStyle);
3027         }    
3028         
3029         if (lastPositionToSelect.isNotNull())
3030             end = lastPositionToSelect;
3031     }
3032     else if (lastPositionToSelect.isNotNull()) {
3033         start = end = lastPositionToSelect;
3034     }
3035     else {
3036         return;
3037     }
3038     
3039     if (m_selectReplacement)
3040         setEndingSelection(Selection(start, SEL_DEFAULT_AFFINITY, end, SEL_DEFAULT_AFFINITY));
3041     else
3042         setEndingSelection(end, SEL_DEFAULT_AFFINITY);
3043     
3044     rebalanceWhitespace();
3045 }
3046
3047 EditAction ReplaceSelectionCommand::editingAction() const
3048 {
3049     return EditActionPaste;
3050 }
3051
3052 void ReplaceSelectionCommand::insertNodeAfterAndUpdateNodesInserted(NodeImpl *insertChild, NodeImpl *refChild)
3053 {
3054     insertNodeAfter(insertChild, refChild);
3055     updateNodesInserted(insertChild);
3056 }
3057
3058 void ReplaceSelectionCommand::insertNodeAtAndUpdateNodesInserted(NodeImpl *insertChild, NodeImpl *refChild, long offset)
3059 {
3060     insertNodeAt(insertChild, refChild, offset);
3061     updateNodesInserted(insertChild);
3062 }
3063
3064 void ReplaceSelectionCommand::insertNodeBeforeAndUpdateNodesInserted(NodeImpl *insertChild, NodeImpl *refChild)
3065 {
3066     insertNodeBefore(insertChild, refChild);
3067     updateNodesInserted(insertChild);
3068 }
3069
3070 void ReplaceSelectionCommand::updateNodesInserted(NodeImpl *node)
3071 {
3072     if (!node)
3073         return;
3074
3075     // update m_lastTopNodeInserted
3076     node->ref();
3077     if (m_lastTopNodeInserted)
3078         m_lastTopNodeInserted->deref();
3079     m_lastTopNodeInserted = node;
3080     
3081     // update m_firstNodeInserted
3082     if (!m_firstNodeInserted) {
3083         m_firstNodeInserted = node;
3084         m_firstNodeInserted->ref();
3085     }
3086     
3087     if (node == m_lastNodeInserted)
3088         return;
3089     
3090     // update m_lastNodeInserted
3091     NodeImpl *old = m_lastNodeInserted;
3092     m_lastNodeInserted = node->lastDescendent();
3093     m_lastNodeInserted->ref();
3094     if (old)
3095         old->deref();
3096 }
3097
3098 void ReplaceSelectionCommand::fixupNodeStyles(const QValueList<NodeDesiredStyle> &list)
3099 {
3100     // This function uses the mapped "desired style" to apply the additional style needed, if any,
3101     // to make the node have the desired style.
3102
3103     document()->updateLayout();
3104
3105     QValueListConstIterator<NodeDesiredStyle> it;
3106     for (it = list.begin(); it != list.end(); ++it) {
3107         NodeImpl *node = (*it).node();
3108         CSSMutableStyleDeclarationImpl *desiredStyle = (*it).style();
3109         ASSERT(desiredStyle);
3110
3111         if (!node->inDocument())
3112             continue;
3113
3114         // The desiredStyle declaration tells what style this node wants to be.
3115         // Compare that to the style that it is right now in the document.
3116         Position pos(node, 0);
3117         CSSComputedStyleDeclarationImpl *currentStyle = pos.computedStyle();
3118         currentStyle->ref();
3119
3120         // Check for the special "match nearest blockquote color" property and resolve to the correct
3121         // color if necessary.
3122         DOMString matchColorCheck = desiredStyle->getPropertyValue(CSS_PROP__KHTML_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR);
3123         if (matchColorCheck == matchNearestBlockquoteColorString()) {
3124             NodeImpl *blockquote = nearestMailBlockquote(node);
3125             Position pos(blockquote ? blockquote : node->getDocument()->documentElement(), 0);
3126             CSSComputedStyleDeclarationImpl *style = pos.computedStyle();
3127             DOMString desiredColor = desiredStyle->getPropertyValue(CSS_PROP_COLOR);
3128             DOMString nearestColor = style->getPropertyValue(CSS_PROP_COLOR);
3129             if (desiredColor != nearestColor)
3130                 desiredStyle->setProperty(CSS_PROP_COLOR, nearestColor);
3131         }
3132         desiredStyle->removeProperty(CSS_PROP__KHTML_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR);
3133
3134         currentStyle->diff(desiredStyle);
3135         
3136         // Only add in block properties if the node is at the start of a 
3137         // paragraph. This matches AppKit.
3138         if (!isStartOfParagraph(VisiblePosition(pos, DOWNSTREAM)))
3139             desiredStyle->removeBlockProperties();
3140         
3141         // If the desiredStyle is non-zero length, that means the current style differs
3142         // from the desired by the styles remaining in the desiredStyle declaration.
3143         if (desiredStyle->length() > 0) {
3144             DOM::RangeImpl *rangeAroundNode = document()->createRange();
3145             rangeAroundNode->ref();
3146             int exceptionCode = 0;
3147             rangeAroundNode->selectNode(node, exceptionCode);
3148             ASSERT(exceptionCode == 0);
3149             // affinity is not really important since this is a temp selection
3150             // just for calling applyStyle
3151             setEndingSelection(Selection(rangeAroundNode, SEL_DEFAULT_AFFINITY, SEL_DEFAULT_AFFINITY));
3152             applyStyle(desiredStyle);
3153             rangeAroundNode->deref();
3154         }
3155
3156         currentStyle->deref();
3157     }
3158 }
3159
3160 void computeAndStoreNodeDesiredStyle(DOM::NodeImpl *node, QValueList<NodeDesiredStyle> &list)
3161 {
3162     if (!node || !node->inDocument())
3163         return;
3164         
3165     CSSComputedStyleDeclarationImpl *computedStyle = Position(node, 0).computedStyle();
3166     computedStyle->ref();
3167     CSSMutableStyleDeclarationImpl *style = computedStyle->copyInheritableProperties();
3168     list.append(NodeDesiredStyle(node, style));
3169     computedStyle->deref();
3170
3171     // In either of the color-matching tests below, set the color to a pseudo-color that will
3172     // make the content take on the color of the nearest-enclosing blockquote (if any) after
3173     // being pasted in.
3174     if (NodeImpl *blockquote = nearestMailBlockquote(node)) {
3175         CSSComputedStyleDeclarationImpl *blockquoteStyle = Position(blockquote, 0).computedStyle();
3176         if (blockquoteStyle->getPropertyValue(CSS_PROP_COLOR) == style->getPropertyValue(CSS_PROP_COLOR)) {
3177             style->setProperty(CSS_PROP__KHTML_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR, matchNearestBlockquoteColorString());
3178             return;
3179         }
3180     }
3181     NodeImpl *documentElement = node->getDocument() ? node->getDocument()->documentElement() : 0;
3182     if (documentElement) {
3183         CSSComputedStyleDeclarationImpl *documentStyle = Position(documentElement, 0).computedStyle();
3184         if (documentStyle->getPropertyValue(CSS_PROP_COLOR) == style->getPropertyValue(CSS_PROP_COLOR)) {
3185             style->setProperty(CSS_PROP__KHTML_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR, matchNearestBlockquoteColorString());
3186         }
3187     }
3188 }
3189
3190 //------------------------------------------------------------------------------------------
3191 // SetNodeAttributeCommand
3192
3193 SetNodeAttributeCommand::SetNodeAttributeCommand(DocumentImpl *document, ElementImpl *element, NodeImpl::Id attribute, const DOMString &value)
3194     : EditCommand(document), m_element(element), m_attribute(attribute), m_value(value)
3195 {
3196     ASSERT(m_element);
3197     m_element->ref();
3198     ASSERT(!m_value.isNull());
3199 }
3200
3201 SetNodeAttributeCommand::~SetNodeAttributeCommand()
3202 {
3203     ASSERT(m_element);
3204     m_element->deref();
3205 }
3206
3207 void SetNodeAttributeCommand::doApply()
3208 {
3209     ASSERT(m_element);
3210     ASSERT(!m_value.isNull());
3211
3212     int exceptionCode = 0;
3213     m_oldValue = m_element->getAttribute(m_attribute);
3214     m_element->setAttribute(m_attribute, m_value.implementation(), exceptionCode);
3215     ASSERT(exceptionCode == 0);
3216 }
3217
3218 void SetNodeAttributeCommand::doUnapply()
3219 {
3220     ASSERT(m_element);
3221
3222     int exceptionCode = 0;
3223     if (m_oldValue.isNull())
3224         m_element->removeAttribute(m_attribute, exceptionCode);
3225     else
3226         m_element->setAttribute(m_attribute, m_oldValue.implementation(), exceptionCode);
3227     ASSERT(exceptionCode == 0);
3228 }
3229
3230 //------------------------------------------------------------------------------------------
3231 // SplitTextNodeCommand
3232
3233 SplitTextNodeCommand::SplitTextNodeCommand(DocumentImpl *document, TextImpl *text, long offset)
3234     : EditCommand(document), m_text1(0), m_text2(text), m_offset(offset)
3235 {
3236     ASSERT(m_text2);
3237     ASSERT(m_text2->length() > 0);
3238
3239     m_text2->ref();
3240 }
3241
3242 SplitTextNodeCommand::~SplitTextNodeCommand()
3243 {
3244     if (m_text1)
3245         m_text1->deref();
3246
3247     ASSERT(m_text2);
3248     m_text2->deref();
3249 }
3250
3251 void SplitTextNodeCommand::doApply()
3252 {
3253     ASSERT(m_text2);
3254     ASSERT(m_offset > 0);
3255
3256     int exceptionCode = 0;
3257
3258     // EDIT FIXME: This should use better smarts for figuring out which portion
3259     // of the split to copy (based on their comparitive sizes). We should also
3260     // just use the DOM's splitText function.
3261     
3262     if (!m_text1) {
3263         // create only if needed.
3264         // if reapplying, this object will already exist.
3265         m_text1 = document()->createTextNode(m_text2->substringData(0, m_offset, exceptionCode));
3266         ASSERT(exceptionCode == 0);
3267         ASSERT(m_text1);
3268         m_text1->ref();
3269     }
3270
3271     m_text2->deleteData(0, m_offset, exceptionCode);
3272     ASSERT(exceptionCode == 0);
3273
3274     m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
3275     ASSERT(exceptionCode == 0);
3276         
3277     ASSERT(m_text2->previousSibling()->isTextNode());
3278     ASSERT(m_text2->previousSibling() == m_text1);
3279 }
3280
3281 void SplitTextNodeCommand::doUnapply()
3282 {
3283     ASSERT(m_text1);
3284     ASSERT(m_text2);
3285     
3286     ASSERT(m_text1->nextSibling() == m_text2);
3287
3288     int exceptionCode = 0;
3289     m_text2->insertData(0, m_text1->data(), exceptionCode);
3290     ASSERT(exceptionCode == 0);
3291
3292     m_text2->parentNode()->removeChild(m_text1, exceptionCode);
3293     ASSERT(exceptionCode == 0);
3294
3295     m_offset = m_text1->length();
3296 }
3297
3298 //------------------------------------------------------------------------------------------
3299 // SplitElementCommand
3300
3301 SplitElementCommand::SplitElementCommand(DOM::DocumentImpl *document, DOM::ElementImpl *element, DOM::NodeImpl *atChild)
3302     : EditCommand(document), m_element1(0), m_element2(element), m_atChild(atChild)
3303 {
3304     ASSERT(m_element2);
3305     ASSERT(m_atChild);
3306
3307     m_element2->ref();
3308     m_atChild->ref();
3309 }
3310
3311 SplitElementCommand::~SplitElementCommand()
3312 {
3313     if (m_element1)
3314         m_element1->deref();
3315
3316     ASSERT(m_element2);
3317     m_element2->deref();
3318     ASSERT(m_atChild);
3319     m_atChild->deref();
3320 }
3321
3322 void SplitElementCommand::doApply()
3323 {
3324     ASSERT(m_element2);
3325     ASSERT(m_atChild);
3326
3327     int exceptionCode = 0;
3328
3329     if (!m_element1) {
3330         // create only if needed.
3331         // if reapplying, this object will already exist.
3332         m_element1 = static_cast<ElementImpl *>(m_element2->cloneNode(false));
3333         ASSERT(m_element1);
3334         m_element1->ref();
3335     }
3336
3337     m_element2->parent()->insertBefore(m_element1, m_element2, exceptionCode);
3338     ASSERT(exceptionCode == 0);
3339     
3340     while (m_element2->firstChild() != m_atChild) {
3341         ASSERT(m_element2->firstChild());
3342         m_element1->appendChild(m_element2->firstChild(), exceptionCode);
3343         ASSERT(exceptionCode == 0);
3344     }
3345 }
3346
3347 void SplitElementCommand::doUnapply()
3348 {
3349     ASSERT(m_element1);
3350     ASSERT(m_element2);
3351     ASSERT(m_atChild);
3352
3353     ASSERT(m_element1->nextSibling() == m_element2);
3354     ASSERT(m_element2->firstChild() && m_element2->firstChild() == m_atChild);
3355
3356     int exceptionCode = 0;
3357
3358     while (m_element1->lastChild()) {
3359         m_element2->insertBefore(m_element1->lastChild(), m_element2->firstChild(), exceptionCode);
3360         ASSERT(exceptionCode == 0);
3361     }
3362
3363     m_element2->parentNode()->removeChild(m_element1, exceptionCode);
3364     ASSERT(exceptionCode == 0);
3365 }
3366
3367 //------------------------------------------------------------------------------------------
3368 // MergeIdenticalElementsCommand
3369
3370 MergeIdenticalElementsCommand::MergeIdenticalElementsCommand(DOM::DocumentImpl *document, DOM::ElementImpl *first, DOM::ElementImpl *second)
3371     : EditCommand(document), m_element1(first), m_element2(second), m_atChild(0)
3372 {
3373     ASSERT(m_element1);
3374     ASSERT(m_element2);
3375
3376     m_element1->ref();
3377     m_element2->ref();
3378 }
3379
3380 MergeIdenticalElementsCommand::~MergeIdenticalElementsCommand()
3381 {
3382     if (m_atChild)
3383         m_atChild->deref();
3384
3385     ASSERT(m_element1);
3386     m_element1->deref();
3387     ASSERT(m_element2);
3388     m_element2->deref();
3389 }
3390
3391 void MergeIdenticalElementsCommand::doApply()
3392 {
3393     ASSERT(m_element1);
3394     ASSERT(m_element2);
3395     ASSERT(m_element1->nextSibling() == m_element2);
3396
3397     int exceptionCode = 0;
3398
3399     if (!m_atChild) {
3400         m_atChild = m_element2->firstChild();
3401         m_atChild->ref();
3402     }
3403
3404     while (m_element1->lastChild()) {
3405         m_element2->insertBefore(m_element1->lastChild(), m_element2->firstChild(), exceptionCode);
3406         ASSERT(exceptionCode == 0);
3407     }
3408
3409     m_element2->parentNode()->removeChild(m_element1, exceptionCode);
3410     ASSERT(exceptionCode == 0);
3411 }
3412
3413 void MergeIdenticalElementsCommand::doUnapply()
3414 {
3415     ASSERT(m_element1);
3416     ASSERT(m_element2);
3417
3418     int exceptionCode = 0;
3419
3420     m_element2->parent()->insertBefore(m_element1, m_element2, exceptionCode);
3421     ASSERT(exceptionCode == 0);
3422
3423     while (m_element2->firstChild() != m_atChild) {
3424         ASSERT(m_element2->firstChild());
3425         m_element1->appendChild(m_element2->firstChild(), exceptionCode);
3426         ASSERT(exceptionCode == 0);
3427     }
3428 }
3429
3430 //------------------------------------------------------------------------------------------
3431 // WrapContentsInDummySpanCommand
3432
3433 WrapContentsInDummySpanCommand::WrapContentsInDummySpanCommand(DOM::DocumentImpl *document, DOM::ElementImpl *element)
3434     : EditCommand(document), m_element(element), m_dummySpan(0)
3435 {
3436     ASSERT(m_element);
3437
3438     m_element->ref();
3439 }
3440
3441 WrapContentsInDummySpanCommand::~WrapContentsInDummySpanCommand()
3442 {
3443     if (m_dummySpan)
3444         m_dummySpan->deref();
3445
3446     ASSERT(m_element);
3447     m_element->deref();
3448 }
3449
3450 void WrapContentsInDummySpanCommand::doApply()
3451 {
3452     ASSERT(m_element);
3453
3454     int exceptionCode = 0;
3455
3456     if (!m_dummySpan) {
3457         m_dummySpan = createStyleSpanElement(document());
3458         m_dummySpan->ref();
3459    &n