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