29 #include "css/cssproperties.h"
30 #include "css/css_valueimpl.h"
32 #include "html/html_elementimpl.h"
33 #include "html/html_imageimpl.h"
34 #include "rendering/render_object.h"
35 #include "rendering/render_style.h"
36 #include "rendering/render_text.h"
37 #include "xml/dom_docimpl.h"
38 #include "xml/dom_elementimpl.h"
39 #include "xml/dom_position.h"
40 #include "xml/dom_positioniterator.h"
41 #include "xml/dom_nodeimpl.h"
42 #include "xml/dom_selection.h"
43 #include "xml/dom_stringimpl.h"
44 #include "xml/dom_textimpl.h"
45 #include "xml/dom2_rangeimpl.h"
46 #include "xml/dom2_viewsimpl.h"
56 using DOM::CSSPrimitiveValueImpl;
57 using DOM::CSSProperty;
58 using DOM::CSSStyleDeclarationImpl;
59 using DOM::CSSValueImpl;
60 using DOM::DocumentFragmentImpl;
61 using DOM::DocumentImpl;
63 using DOM::DOMStringImpl;
64 using DOM::EditingTextImpl;
65 using DOM::PositionIterator;
66 using DOM::ElementImpl;
67 using DOM::HTMLElementImpl;
68 using DOM::HTMLImageElementImpl;
69 using DOM::NamedAttrMapImpl;
72 using DOM::NodeListImpl;
78 using DOM::TreeWalkerImpl;
81 #define DEBUG_COMMANDS 1
86 static inline bool isNBSP(
const QChar &c)
88 return c == QChar(0xa0);
91 static inline bool isWS(
const QChar &c)
93 return c.isSpace() && c != QChar(0xa0);
96 static inline bool isWS(
const DOMString &text)
101 return isWS(text[0]);
104 static inline bool isWS(
const Position &pos)
109 if (!pos.node()->isTextNode())
112 const DOMString &
string =
static_cast<TextImpl *
>(pos.node())->data();
113 return isWS(
string[pos.offset()]);
116 static bool shouldPruneNode(NodeImpl *node)
121 RenderObject *renderer = node->renderer();
125 if (node->hasChildNodes())
128 if (node->rootEditableElement() == node)
131 if (renderer->isBR() || renderer->isReplaced())
134 if (node->isTextNode()) {
135 TextImpl *text =
static_cast<TextImpl *
>(node);
136 if (text->length() == 0)
141 if (!node->isHTMLElement())
144 if (node->id() == ID_BODY)
147 if (!node->isContentEditable())
153 static Position leadingWhitespacePosition(
const Position &pos)
157 Selection selection(pos);
158 Position prev = pos.previousCharacterPosition();
159 if (prev != pos && prev.node()->inSameContainingBlockFlowElement(pos.node()) && prev.node()->isTextNode()) {
160 DOMString string =
static_cast<TextImpl *
>(prev.node())->data();
161 if (isWS(
string[prev.offset()]))
168 static Position trailingWhitespacePosition(
const Position &pos)
172 if (pos.node()->isTextNode()) {
173 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
174 if (pos.offset() >= (long)textNode->length()) {
175 Position
next = pos.nextCharacterPosition();
176 if (next != pos && next.node()->inSameContainingBlockFlowElement(pos.node()) && next.node()->isTextNode()) {
177 DOMString string =
static_cast<TextImpl *
>(next.node())->data();
183 DOMString string =
static_cast<TextImpl *
>(pos.node())->data();
184 if (isWS(
string[pos.offset()]))
192 static bool textNodesAreJoinable(TextImpl *text1, TextImpl *text2)
197 return (text1->nextSibling() == text2);
200 static DOMString &nonBreakingSpaceString()
203 return nonBreakingSpaceString;
208 static DOMString styleSpanClassString =
"khtml-style-span";
209 return styleSpanClassString;
219 assert(m_document->part());
221 m_startingSelection = m_document->part()->caret();
222 m_endingSelection = m_startingSelection;
233 assert(m_document->part());
241 m_document->part()->editor()->appliedEditing(
this);
247 assert(m_document->part());
255 m_document->part()->editor()->unappliedEditing(
this);
261 assert(m_document->part());
269 m_document->part()->editor()->reappliedEditing(
this);
279 m_startingSelection = s;
282 cmd->m_startingSelection = s;
289 m_endingSelection = s;
292 cmd->m_endingSelection = s;
299 return m_parent.get();
321 if (
m_cmds.count() == 0) {
325 for (
int i =
m_cmds.count() - 1; i >= 0; --i)
333 if (
m_cmds.count() == 0) {
336 QMutableListIterator<RefPtr<EditCommandImpl> > it(
m_cmds);
338 it.next()->reapply();
350 cmd->setParent(
this);
363 if (refChild->parentNode()->lastChild() == refChild) {
364 appendNode(refChild->parentNode(), insertChild);
367 assert(refChild->nextSibling());
374 if (refChild->hasChildNodes() || (refChild->renderer() && refChild->renderer()->isBlockFlow())) {
375 NodeImpl *child = refChild->firstChild();
376 for (
long i = 0; child && i < offset; i++)
377 child = child->nextSibling();
383 else if (refChild->caretMinOffset() >= offset) {
386 else if (refChild->isTextNode() && refChild->caretMaxOffset() > offset) {
468 if (selection.state() == Selection::RANGE) {
506 int exceptionCode = 0;
507 ElementImpl *styleElement =
document()->createHTMLElement(
"SPAN");
510 styleElement->setAttribute(ATTR_STYLE,
document()->part()->editor()->typingStyle()->cssText().implementation());
513 styleElement->setAttribute(ATTR_CLASS, styleSpanClassString());
514 assert(exceptionCode == 0);
525 :
EditCommandImpl(document), m_parentNode(parentNode), m_appendChild(appendChild)
531 m_appendChild->ref();
537 m_parentNode->deref();
539 m_appendChild->deref();
547 int exceptionCode = 0;
548 m_parentNode->appendChild(m_appendChild, exceptionCode);
549 assert(exceptionCode == 0);
558 int exceptionCode = 0;
559 m_parentNode->removeChild(m_appendChild, exceptionCode);
560 assert(exceptionCode == 0);
579 static bool isBlockLevelStyle(
const CSSStyleDeclarationImpl* style)
581 QListIterator<CSSProperty*> it(*(style->values()));
582 while (it.hasNext()) {
583 CSSProperty *
property = it.next();
584 switch (property->id()) {
585 case CSS_PROP_TEXT_ALIGN:
609 static void applyStyleChangeOnTheNode(ElementImpl* element, CSSStyleDeclarationImpl* style)
611 CSSStyleDeclarationImpl *computedStyle = element->document()->defaultView()->getComputedStyle(element, 0);
613 #ifdef DEBUG_COMMANDS
614 kDebug() <<
"[change style]" << element << endl;
617 QListIterator<CSSProperty*> it(*(style->values()));
618 while ( it.hasNext() ) {
619 CSSProperty *
property = it.next();
620 CSSValueImpl *computedValue = computedStyle->getPropertyCSSValue(property->id());
621 DOMString newValue =
property->value()->cssText();
622 #ifdef DEBUG_COMMANDS
623 kDebug() <<
"[new value]:" <<
property->cssText() << endl;
624 kDebug() <<
"[computedValue]:" << computedValue->cssText() << endl;
626 if (
strcasecmp(computedValue->cssText(), newValue)) {
628 element->getInlineStyleDecls()->setProperty(property->id(), newValue);
639 Position start(
endingSelection().start().equivalentDownstreamPosition().equivalentRangeCompliantPosition());
641 #ifdef DEBUG_COMMANDS
642 kDebug() <<
"[APPLY STYLE]" << start << end << endl;
643 printEnclosingBlockTree(start.node()->enclosingBlockFlowElement());
646 if (isBlockLevelStyle(m_style)) {
647 #ifdef DEBUG_COMMANDS
648 kDebug() <<
"[APPLY BLOCK LEVEL STYLE]" << endl;
650 ElementImpl *startBlock = start.node()->enclosingBlockFlowElement();
651 ElementImpl *endBlock = end.node()->enclosingBlockFlowElement();
652 #ifdef DEBUG_COMMANDS
653 kDebug() << startBlock << startBlock->nodeName() << endl;
655 if (startBlock == endBlock && startBlock == start.node()->rootEditableElement()) {
656 ElementImpl* block =
document()->createHTMLElement(
"DIV");
657 #ifdef DEBUG_COMMANDS
658 kDebug() <<
"[Create DIV with Style:]" << m_style->cssText() << endl;
660 block->setAttribute(ATTR_STYLE, m_style->cssText());
661 for (NodeImpl* node = startBlock->firstChild(); node; node = startBlock->firstChild()) {
662 #ifdef DEBUG_COMMANDS
663 kDebug() <<
"[reparent node]" << node << node->nodeName() << endl;
669 }
else if (startBlock == endBlock) {
672 applyStyleChangeOnTheNode(startBlock, m_style);
679 removeStyle(start, end);
680 bool splitStart = splitTextAtStartIfNeeded(start, end);
685 splitTextAtEndIfNeeded(start, end);
689 #ifdef DEBUG_COMMANDS
690 kDebug() <<
"[start;end]" << start << end << endl;
692 if (start.node() == end.node()) {
694 applyStyleIfNeeded(start.node(), end.node());
696 NodeImpl *node = start.node();
698 if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
699 NodeImpl *runStart = node;
701 if (runStart->parentNode() != node->parentNode() || node->isHTMLElement() || node == end.node() ||
702 (node->renderer() && !node->renderer()->isInline())) {
703 applyStyleIfNeeded(runStart, node);
706 node = node->traverseNextNode();
709 if (node == end.node())
711 node = node->traverseNextNode();
719 bool ApplyStyleCommandImpl::isHTMLStyleNode(HTMLElementImpl *elem)
721 QListIterator<CSSProperty*> it(*(
style()->values()));
722 while (it.hasNext()) {
723 CSSProperty *
property = it.next();
724 switch (property->id()) {
725 case CSS_PROP_FONT_WEIGHT:
726 if (elem->id() == ID_B)
729 case CSS_PROP_FONT_STYLE:
730 if (elem->id() == ID_I)
739 void ApplyStyleCommandImpl::removeHTMLStyleNode(HTMLElementImpl *elem)
749 void ApplyStyleCommandImpl::removeCSSStyle(HTMLElementImpl *elem)
753 CSSStyleDeclarationImpl *decl = elem->inlineStyleDecls();
757 QListIterator<CSSProperty*> it(*(
style()->values()));
758 while ( it.hasNext() ) {
759 CSSProperty *
property = it.next();
760 if (decl->getPropertyCSSValue(property->id()))
764 if (elem->id() == ID_SPAN) {
768 NamedAttrMapImpl *map = elem->attributes();
769 if (map && (map->length() == 1 || (map->length() == 2 && elem->getAttribute(ATTR_STYLE).isEmpty())) &&
770 elem->getAttribute(ATTR_CLASS) == styleSpanClassString())
775 void ApplyStyleCommandImpl::removeStyle(
const Position &start,
const Position &end)
777 NodeImpl *node = start.node();
779 NodeImpl *
next = node->traverseNextNode();
780 if (node->isHTMLElement() && nodeFullySelected(node)) {
781 HTMLElementImpl *elem =
static_cast<HTMLElementImpl *
>(node);
782 if (isHTMLStyleNode(elem))
783 removeHTMLStyleNode(elem);
785 removeCSSStyle(elem);
787 if (node == end.node())
793 bool ApplyStyleCommandImpl::nodeFullySelected(
const NodeImpl *node)
const
799 if (node == end.node())
800 return end.offset() >= node->caretMaxOffset();
802 for (NodeImpl *child = node->lastChild(); child; child = child->lastChild()) {
803 if (child == end.node())
804 return end.offset() >= child->caretMaxOffset();
807 return node == end.node() || !node->isAncestor(end.node());
813 bool ApplyStyleCommandImpl::splitTextAtStartIfNeeded(
const Position &start,
const Position &end)
815 if (start.node()->isTextNode() && start.offset() > start.node()->caretMinOffset() && start.offset() < start.node()->caretMaxOffset()) {
816 #ifdef DEBUG_COMMANDS
817 kDebug() <<
"[split start]" << start.offset() << start.node()->caretMinOffset() << start.node()->caretMaxOffset() << endl;
819 long endOffsetAdjustment = start.node() == end.node() ? start.offset() : 0;
820 TextImpl *text =
static_cast<TextImpl *
>(start.node());
821 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text, start.offset());
823 setEndingSelection(Selection(Position(start.node(), 0), Position(end.node(), end.offset() - endOffsetAdjustment)));
829 NodeImpl *ApplyStyleCommandImpl::splitTextAtEndIfNeeded(
const Position &start,
const Position &end)
831 if (end.node()->isTextNode() && end.offset() > end.node()->caretMinOffset() && end.offset() < end.node()->caretMaxOffset()) {
832 #ifdef DEBUG_COMMANDS
833 kDebug() <<
"[split end]" << end.offset() << end.node()->caretMinOffset() << end.node()->caretMaxOffset() << endl;
835 TextImpl *text =
static_cast<TextImpl *
>(end.node());
836 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text, end.offset());
838 NodeImpl *startNode = start.node() == end.node() ? cmd->node()->previousSibling() : start.node();
840 setEndingSelection(Selection(Position(startNode, start.offset()), Position(cmd->node()->previousSibling(), cmd->node()->previousSibling()->caretMaxOffset())));
841 return cmd->node()->previousSibling();
846 void ApplyStyleCommandImpl::surroundNodeRangeWithElement(NodeImpl *startNode, NodeImpl *endNode, ElementImpl *element)
852 NodeImpl *node = startNode;
854 NodeImpl *next = node->traverseNextNode();
855 if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
865 static bool checkIfNewStylingNeeded(ElementImpl* element, CSSStyleDeclarationImpl *style)
867 CSSStyleDeclarationImpl *computedStyle = element->document()->defaultView()->getComputedStyle(element, 0);
869 #ifdef DEBUG_COMMANDS
870 kDebug() <<
"[check styling]" << element << endl;
873 QListIterator<CSSProperty*> it(*(style->values()));
874 while ( it.hasNext() ) {
875 CSSProperty *
property = it.next();
876 CSSValueImpl *computedValue = computedStyle->getPropertyCSSValue(property->id());
877 DOMString newValue =
property->value()->cssText();
878 #ifdef DEBUG_COMMANDS
879 kDebug() <<
"[new value]:" <<
property->cssText() << endl;
880 kDebug() <<
"[computedValue]:" << computedValue->cssText() << endl;
882 if (
strcasecmp(computedValue->cssText(), newValue))
888 void ApplyStyleCommandImpl::applyStyleIfNeeded(DOM::NodeImpl *startNode, DOM::NodeImpl *endNode)
890 ElementImpl *
parent = Position(startNode, 0).element();
891 if (!checkIfNewStylingNeeded(parent,
style()))
893 ElementImpl *styleElement = 0;
894 if (parent->id() == ID_SPAN && parent->firstChild() == startNode && parent->lastChild() == endNode) {
897 styleElement =
document()->createHTMLElement(
"SPAN");
898 styleElement->setAttribute(ATTR_CLASS, styleSpanClassString());
900 surroundNodeRangeWithElement(startNode, endNode, styleElement);
902 applyStyleChangeOnTheNode(styleElement,
style());
905 bool ApplyStyleCommandImpl::currentlyHasStyle(
const Position &pos,
const CSSProperty *property)
const
909 CSSStyleDeclarationImpl *decl =
document()->defaultView()->getComputedStyle(pos.element(), 0);
911 CSSValueImpl *value = decl->getPropertyCSSValue(property->id());
912 return strcasecmp(value->cssText(),
property->value()->cssText()) == 0;
915 ApplyStyleCommandImpl::StyleChange ApplyStyleCommandImpl::computeStyleChange(
const Position &insertionPoint, CSSStyleDeclarationImpl *style)
917 assert(insertionPoint.notEmpty());
920 StyleChange styleChange;
922 QListIterator<CSSProperty*> it(*(style->values()));
923 while ( it.hasNext() ) {
924 CSSProperty *
property = it.next();
925 #ifdef DEBUG_COMMANDS
926 kDebug() <<
"[CSS property]:" <<
property->cssText() << endl;
928 if (!currentlyHasStyle(insertionPoint, property)) {
929 #ifdef DEBUG_COMMANDS
930 kDebug() <<
"[Add to style change]" << endl;
932 switch (property->id()) {
933 case CSS_PROP_FONT_WEIGHT:
934 if (
strcasecmp(property->value()->cssText(),
"bold") == 0)
935 styleChange.applyBold =
true;
937 styleChange.cssStyle +=
property->cssText();
939 case CSS_PROP_FONT_STYLE: {
940 DOMString cssText(property->value()->cssText());
942 styleChange.applyItalic =
true;
944 styleChange.cssStyle += property->cssText();
948 styleChange.cssStyle +=
property->cssText();
956 Position ApplyStyleCommandImpl::positionInsertionPoint(Position pos)
958 if (pos.node()->isTextNode() && (pos.offset() > 0 && pos.offset() < pos.node()->maxOffset())) {
959 RefPtr<SplitTextNodeCommandImpl> split =
new SplitTextNodeCommandImpl(
document(), static_cast<TextImpl *>(pos.node()), pos.offset());
961 pos = Position(split->node(), 0);
969 if (currentlyHasStyle(pos))
973 if (pos.offset() >= pos.node()->caretMaxOffset()) {
974 NodeImpl *nextNode = pos.node()->traverseNextNode();
976 Position next = Position(nextNode, 0);
977 if (currentlyHasStyle(next))
983 if (pos.offset() <= pos.node()->caretMinOffset()) {
984 NodeImpl *prevNode = pos.node()->traversePreviousNode();
986 Position prev = Position(prevNode, prevNode->maxOffset());
987 if (currentlyHasStyle(prev))
1000 : CompositeEditCommandImpl(document), m_charactersDeleted(0), m_hasSelectionToCollapse(false)
1005 : CompositeEditCommandImpl(document), m_charactersDeleted(0), m_selectionToCollapse(selection), m_hasSelectionToCollapse(true)
1013 static bool shouldDeleteUpstreamPosition(
const Position &pos)
1015 if (!pos.node()->isTextNode())
1018 RenderObject *renderer = pos.node()->renderer();
1022 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1023 if (pos.offset() >= (long)textNode->length())
1026 if (pos.isLastRenderedPositionInEditableBlock())
1029 if (pos.isFirstRenderedPositionOnLine() || pos.isLastRenderedPositionOnLine())
1046 Position DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace(
const Position &pos)
1048 Position upstream = pos.equivalentUpstreamPosition();
1049 Position downstream = pos.equivalentDownstreamPosition();
1050 #ifdef DEBUG_COMMANDS
1051 kDebug() <<
"[pos]" << pos << endl;
1052 kDebug() <<
"[upstream:downstream]" << upstream << downstream << endl;
1053 printEnclosingBlockTree(pos.node());
1056 bool del = shouldDeleteUpstreamPosition(upstream);
1057 #ifdef DEBUG_COMMANDS
1058 kDebug() <<
"[delete upstream]" << del << endl;
1061 if (upstream == downstream)
1064 #ifdef DEBUG_COMMANDS
1065 PositionIterator iter(upstream);
1066 kDebug() <<
"[before print]" << endl;
1067 for (iter.next(); iter.current() != downstream; iter.next())
1068 kDebug() <<
"[iterate]" << iter.current() << endl;
1069 kDebug() <<
"[after print]" << endl;
1072 PositionIterator it(upstream);
1073 Position deleteStart = upstream;
1075 deleteStart = it.peekNext();
1076 if (deleteStart == downstream)
1080 Position endingPosition = upstream;
1082 while (it.current() != downstream) {
1083 Position next = it.peekNext();
1084 #ifdef DEBUG_COMMANDS
1085 kDebug() <<
"[iterate and delete]" << next << endl;
1087 if (next.node() != deleteStart.node()) {
1089 if (deleteStart.node()->isTextNode()) {
1090 TextImpl *textNode =
static_cast<TextImpl *
>(deleteStart.node());
1091 unsigned long count = it.current().offset() - deleteStart.offset();
1092 if (count == textNode->length()) {
1093 #ifdef DEBUG_COMMANDS
1094 kDebug(6200) <<
" removeNodeAndPrune 1:" << textNode;
1096 if (textNode == endingPosition.node())
1097 endingPosition = Position(next.node(), next.node()->caretMinOffset());
1100 #ifdef DEBUG_COMMANDS
1101 kDebug(6200) <<
" deleteText 1:" << textNode <<
"t len:" << textNode->length()<<
"start:" << deleteStart.offset() <<
"del len:" << (it.current().offset() - deleteStart.offset());
1103 deleteText(textNode, deleteStart.offset(), count);
1106 #ifdef DEBUG_COMMANDS
1107 kDebug() <<
"[not text node is not supported yet]" << endl;
1111 }
else if (next == downstream) {
1112 assert(deleteStart.node() == downstream.node());
1113 assert(downstream.node()->isTextNode());
1114 TextImpl *textNode =
static_cast<TextImpl *
>(deleteStart.node());
1115 unsigned long count = downstream.offset() - deleteStart.offset();
1116 assert(count <= textNode->length());
1117 if (count == textNode->length()) {
1118 #ifdef DEBUG_COMMANDS
1119 kDebug(6200) <<
" removeNodeAndPrune 2:"<<textNode;
1123 #ifdef DEBUG_COMMANDS
1124 kDebug(6200) <<
" deleteText 2:"<< textNode<<
"t len:" << textNode->length() <<
"start:" <<deleteStart.offset() <<
"del len:" << count;
1126 deleteText(textNode, deleteStart.offset(), count);
1127 m_charactersDeleted = count;
1128 endingPosition = Position(downstream.node(), downstream.offset() - m_charactersDeleted);
1132 it.setPosition(next);
1135 return endingPosition;
1142 if (!m_hasSelectionToCollapse)
1144 int state = m_selectionToCollapse.state();
1145 if (state == Selection::CARET) {
1146 Position endPosition = deleteWhitespace(m_selectionToCollapse.start());
1148 #ifdef DEBUG_COMMANDS
1149 kDebug(6200) <<
"-----------------------------------------------------";
1152 else if (state == Selection::RANGE) {
1153 Position startPosition = deleteWhitespace(m_selectionToCollapse.start());
1154 #ifdef DEBUG_COMMANDS
1155 kDebug(6200) <<
"-----------------------------------------------------";
1157 Position endPosition = m_selectionToCollapse.end();
1158 if (m_charactersDeleted > 0 && startPosition.node() == endPosition.node()) {
1159 #ifdef DEBUG_COMMANDS
1160 kDebug(6200) <<
"adjust end position by" << m_charactersDeleted;
1162 endPosition = Position(endPosition.node(), endPosition.offset() - m_charactersDeleted);
1164 endPosition = deleteWhitespace(endPosition);
1166 #ifdef DEBUG_COMMANDS
1167 kDebug(6200) <<
"=====================================================";
1181 : CompositeEditCommandImpl(document), m_selectionToDelete(selection), m_hasSelectionToDelete(true)
1189 void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
1193 if (selection.state() != Selection::CARET)
1196 Position pos(selection.start());
1198 if (!pos.node()->isTextNode())
1201 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1203 if (pos.offset() == 0) {
1204 PositionIterator it(pos);
1205 Position prev = it.previous();
1208 if (prev.node()->isTextNode()) {
1209 TextImpl *prevTextNode =
static_cast<TextImpl *
>(prev.node());
1210 if (textNodesAreJoinable(prevTextNode, textNode)) {
1213 #ifdef DEBUG_COMMANDS
1214 kDebug(6200) <<
"joinTextNodesWithSameStyle [1]";
1218 }
else if (pos.offset() == (long)textNode->length()) {
1219 PositionIterator it(pos);
1220 Position next = it.next();
1223 if (next.node()->isTextNode()) {
1224 TextImpl *nextTextNode =
static_cast<TextImpl *
>(next.node());
1225 if (textNodesAreJoinable(textNode, nextTextNode)) {
1228 #ifdef DEBUG_COMMANDS
1229 kDebug(6200) <<
"joinTextNodesWithSameStyle [2]";
1236 bool DeleteSelectionCommandImpl::containsOnlyWhitespace(
const Position &start,
const Position &end)
1240 PositionIterator it(start);
1241 while (!it.atEnd()) {
1242 if (!it.current().node()->isTextNode())
1244 const DOMString &text =
static_cast<TextImpl *
>(it.current().node())->data();
1246 if (text.
length() > INT_MAX)
1248 if (it.current().offset() < (int)text.
length() && !isWS(text[it.current().offset()]))
1251 if (it.current() == end)
1257 void DeleteSelectionCommandImpl::deleteContentInsideNode(NodeImpl *node,
int startOffset,
int endOffset)
1259 #ifdef DEBUG_COMMANDS
1260 kDebug() <<
"[Delete content inside node]" << node << startOffset << endOffset << endl;
1262 if (node->isTextNode()) {
1264 if (startOffset == endOffset)
1267 if (!startOffset && endOffset == node->maxOffset()) {
1272 deleteText(static_cast<TextImpl*>(node), startOffset, endOffset - startOffset);
1275 #ifdef DEBUG_COMMANDS
1276 kDebug() <<
"[non-text node] not supported" << endl;
1280 void DeleteSelectionCommandImpl::deleteContentBeforeOffset(NodeImpl *node,
int offset)
1282 deleteContentInsideNode(node, 0, offset);
1285 void DeleteSelectionCommandImpl::deleteContentAfterOffset(NodeImpl *node,
int offset)
1287 if (node->isTextNode())
1288 deleteContentInsideNode(node, offset, node->maxOffset());
1295 if (!m_hasSelectionToDelete)
1298 if (m_selectionToDelete.state() != Selection::RANGE)
1304 Position upstreamStart(selection.start().equivalentUpstreamPosition());
1305 Position downstreamStart(selection.start().equivalentDownstreamPosition());
1306 Position upstreamEnd(selection.end().equivalentUpstreamPosition());
1307 Position downstreamEnd(selection.end().equivalentDownstreamPosition());
1309 NodeImpl *startBlock = upstreamStart.node()->enclosingBlockFlowElement();
1310 NodeImpl *endBlock = downstreamEnd.node()->enclosingBlockFlowElement();
1312 #ifdef DEBUG_COMMANDS
1313 kDebug() <<
"[Delete:Start]" << upstreamStart << downstreamStart << endl;
1314 kDebug() <<
"[Delete:End]" << upstreamEnd << downstreamEnd << endl;
1315 printEnclosingBlockTree(upstreamStart.node());
1317 if (startBlock != endBlock)
1318 printEnclosingBlockTree(downstreamEnd.node());
1320 if (upstreamStart == downstreamEnd)
1325 if (upstreamStart.node() != downstreamEnd.node()) {
1326 NodeImpl *node, *next;
1327 for (node = upstreamStart.node()->traverseNextNode(); node && node != downstreamEnd.node(); node = next) {
1328 #ifdef DEBUG_COMMANDS
1329 kDebug() <<
"[traverse and delete]" << node << (node->renderer() && node->renderer()->isEditable()) << endl;
1331 next = node->traverseNextNode();
1332 if (node->renderer() && node->renderer()->isEditable())
1338 if (startBlock != endBlock && startBlock->parentNode() == endBlock->parentNode()) {
1339 NodeImpl *node = endBlock->firstChild();
1341 NodeImpl *moveNode = node;
1342 node = node->nextSibling();
1348 if (upstreamStart.node() == downstreamEnd.node())
1349 deleteContentInsideNode(upstreamEnd.node(), upstreamStart.offset(), downstreamEnd.offset());
1351 deleteContentAfterOffset(upstreamStart.node(), upstreamStart.offset());
1352 deleteContentBeforeOffset(downstreamEnd.node(), downstreamEnd.offset());
1357 Position endingPosition;
1358 bool adjustEndingPositionDownstream =
false;
1360 bool onlyWhitespace = containsOnlyWhitespace(upstreamStart, downstreamEnd);
1361 kDebug() <<
"[OnlyWhitespace]" << onlyWhitespace << endl;
1363 bool startCompletelySelected = !onlyWhitespace &&
1364 (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset() &&
1365 ((downstreamStart.node() != upstreamEnd.node()) ||
1366 (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset())));
1368 bool endCompletelySelected = !onlyWhitespace &&
1369 (upstreamEnd.offset() >= upstreamEnd.node()->caretMaxOffset() &&
1370 ((downstreamStart.node() != upstreamEnd.node()) ||
1371 (downstreamStart.offset() <= downstreamStart.node()->caretMinOffset())));
1373 kDebug() <<
"[{start:end}CompletelySelected]" << startCompletelySelected << endCompletelySelected << endl;
1375 unsigned long startRenderedOffset = downstreamStart.renderedOffset();
1377 bool startAtStartOfRootEditableElement = startRenderedOffset == 0 && downstreamStart.inFirstEditableInRootEditableElement();
1378 bool startAtStartOfBlock = startAtStartOfRootEditableElement ||
1379 (startRenderedOffset == 0 && downstreamStart.inFirstEditableInContainingEditableBlock());
1380 bool endAtEndOfBlock = downstreamEnd.isLastRenderedPositionInEditableBlock();
1382 kDebug() <<
"[startAtStartOfRootEditableElement]" << startAtStartOfRootEditableElement << endl;
1383 kDebug() <<
"[startAtStartOfBlock]" << startAtStartOfBlock << endl;
1384 kDebug() <<
"[endAtEndOfBlock]" << endAtEndOfBlock << endl;
1386 NodeImpl *startBlock = upstreamStart.node()->enclosingBlockFlowElement();
1387 NodeImpl *endBlock = downstreamEnd.node()->enclosingBlockFlowElement();
1388 bool startBlockEndBlockAreSiblings = startBlock->parentNode() == endBlock->parentNode();
1390 kDebug() <<
"[startBlockEndBlockAreSiblings]" << startBlockEndBlockAreSiblings << startBlock << endBlock << endl;
1392 debugPosition(
"upstreamStart: ", upstreamStart);
1393 debugPosition(
"downstreamStart: ", downstreamStart);
1394 debugPosition(
"upstreamEnd: ", upstreamEnd);
1395 debugPosition(
"downstreamEnd: ", downstreamEnd);
1396 kDebug(6200) <<
"start selected:" << (startCompletelySelected ?
"YES" :
"NO");
1397 kDebug(6200) <<
"at start block:" << (startAtStartOfBlock ?
"YES" :
"NO");
1398 kDebug(6200) <<
"at start root block:"<< (startAtStartOfRootEditableElement ?
"YES" :
"NO");
1399 kDebug(6200) <<
"at end block:"<< (endAtEndOfBlock ?
"YES" :
"NO");
1400 kDebug(6200) <<
"only whitespace:"<< (onlyWhitespace ?
"YES" :
"NO");
1403 if (startAtStartOfBlock) {
1404 kDebug(6200) <<
"ending position case 1";
1405 endingPosition = Position(startBlock, 0);
1406 adjustEndingPositionDownstream =
true;
1407 }
else if (!startCompletelySelected) {
1408 kDebug(6200) <<
"ending position case 2";
1409 endingPosition = upstreamEnd;
1410 if (upstreamStart.node()->id() == ID_BR && upstreamStart.offset() == 1)
1411 adjustEndingPositionDownstream =
true;
1412 }
else if (upstreamStart != downstreamStart) {
1413 kDebug(6200) <<
"ending position case 3";
1414 endingPosition = upstreamStart;
1415 if (upstreamStart.node()->id() == ID_BR && upstreamStart.offset() == 1)
1416 adjustEndingPositionDownstream =
true;
1422 if ((startAtStartOfBlock && !endAtEndOfBlock) || (!startCompletelySelected && adjustEndingPositionDownstream)) {
1424 Position trailing = trailingWhitespacePosition(downstreamEnd.equivalentDownstreamPosition());
1425 if (trailing.notEmpty()) {
1426 debugPosition(
"convertTrailingWhitespace: ", trailing);
1427 Position collapse = trailing.nextCharacterPosition();
1428 if (collapse != trailing)
1430 TextImpl *textNode =
static_cast<TextImpl *
>(trailing.node());
1431 replaceText(textNode, trailing.offset(), 1, nonBreakingSpaceString());
1433 }
else if (!startAtStartOfBlock && endAtEndOfBlock) {
1435 Position leading = leadingWhitespacePosition(upstreamStart.equivalentUpstreamPosition());
1436 if (leading.notEmpty()) {
1437 debugPosition(
"convertLeadingWhitespace: ", leading);
1438 TextImpl *textNode =
static_cast<TextImpl *
>(leading.node());
1439 replaceText(textNode, leading.offset(), 1, nonBreakingSpaceString());
1441 }
else if (!startAtStartOfBlock && !endAtEndOfBlock) {
1443 Position leading = leadingWhitespacePosition(upstreamStart.equivalentUpstreamPosition());
1444 Position trailing = trailingWhitespacePosition(downstreamEnd.equivalentDownstreamPosition());
1445 if (leading.notEmpty() && trailing.notEmpty()) {
1446 debugPosition(
"convertLeadingWhitespace [contiguous]: ", leading);
1447 TextImpl *textNode =
static_cast<TextImpl *
>(leading.node());
1448 replaceText(textNode, leading.offset(), 1, nonBreakingSpaceString());
1455 NodeImpl *n = downstreamStart.node()->traverseNextNode();
1456 kDebug() <<
"[n]" << n << endl;
1459 if (startCompletelySelected) {
1460 kDebug(6200) <<
"start node delete case 1";
1462 }
else if (onlyWhitespace) {
1466 kDebug(6200) <<
"start node delete case 2";
1467 assert(upstreamStart.node()->isTextNode());
1468 TextImpl *text =
static_cast<TextImpl *
>(upstreamStart.node());
1469 int offset = upstreamStart.offset();
1471 int length = text->
length();
1472 if (length == upstreamStart.offset())
1475 }
else if (downstreamStart.node()->isTextNode()) {
1476 kDebug(6200) <<
"start node delete case 3";
1477 TextImpl *text =
static_cast<TextImpl *
>(downstreamStart.node());
1478 int endOffset = text == upstreamEnd.node() ? upstreamEnd.offset() : text->
length();
1479 if (endOffset > downstreamStart.offset()) {
1480 deleteText(text, downstreamStart.offset(), endOffset - downstreamStart.offset());
1485 kDebug(6200) <<
"start node delete case 4";
1486 assert(downstreamStart.offset() == 1);
1489 if (n && !onlyWhitespace && downstreamStart.node() != upstreamEnd.node()) {
1491 while (n && n != upstreamEnd.node()) {
1493 n = n->traverseNextNode();
1494 if (d->renderer() && d->renderer()->isEditable())
1501 assert(n == upstreamEnd.node());
1502 if (endCompletelySelected) {
1505 else if (upstreamEnd.node()->isTextNode()) {
1506 if (upstreamEnd.offset() > 0) {
1507 TextImpl *text =
static_cast<TextImpl *
>(upstreamEnd.node());
1514 assert(downstreamStart.offset() == 0);
1523 if (startBlock != endBlock && startBlockEndBlockAreSiblings) {
1524 kDebug(6200) <<
"merging content to start block";
1525 NodeImpl *node = endBlock->firstChild();
1527 NodeImpl *moveNode = node;
1528 node = node->nextSibling();
1534 if (adjustEndingPositionDownstream) {
1535 kDebug(6200) <<
"adjust ending position downstream";
1536 endingPosition = endingPosition.equivalentDownstreamPosition();
1539 debugPosition(
"ending position: ", endingPosition);
1542 kDebug(6200) <<
"-----------------------------------------------------";
1550 :
EditCommandImpl(document), m_node(node), m_offset(offset), m_count(count)
1569 int exceptionCode = 0;
1570 m_text = m_node->substringData(m_offset, m_count, exceptionCode);
1571 assert(exceptionCode == 0);
1573 m_node->deleteData(m_offset, m_count, exceptionCode);
1574 assert(exceptionCode == 0);
1582 int exceptionCode = 0;
1583 m_node->insertData(m_offset, m_text, exceptionCode);
1584 assert(exceptionCode == 0);
1599 void InputNewlineCommandImpl::insertNodeAfterPosition(NodeImpl *node,
const Position &pos)
1604 Position upstream(pos.equivalentUpstreamPosition());
1605 NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1606 if (cb == pos.node())
1612 void InputNewlineCommandImpl::insertNodeBeforePosition(NodeImpl *node,
const Position &pos)
1617 Position upstream(pos.equivalentUpstreamPosition());
1618 NodeImpl *cb = pos.node()->enclosingBlockFlowElement();
1619 if (cb == pos.node())
1629 int exceptionCode = 0;
1631 NodeImpl *enclosingBlock = selection.start().node()->enclosingBlockFlowElement();
1632 kDebug() << enclosingBlock->nodeName() << endl;
1633 if (enclosingBlock->id() == ID_LI) {
1638 #ifdef DEBUG_COMMANDS
1639 kDebug() <<
"[insert new list item]" << selection << endl;
1640 printEnclosingBlockTree(selection.start().node());
1642 Position pos(selection.start().equivalentDownstreamPosition());
1643 NodeImpl *node = pos.node();
1644 bool atBlockStart = pos.atStartOfContainingEditableBlock();
1645 bool atBlockEnd = pos.isLastRenderedPositionInEditableBlock();
1647 if (node->isTextNode() && !atBlockStart && !atBlockEnd) {
1648 TextImpl *textNode =
static_cast<TextImpl*
>(node);
1649 TextImpl *textBeforeNode =
document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
1652 pos = Position(textNode, 0);
1657 #ifdef DEBUG_COMMANDS
1658 kDebug() <<
"[handle node]" << node << endl;
1659 printEnclosingBlockTree(enclosingBlock->parent());
1661 NodeImpl *parent = node->parent();
1663 RefPtr<NodeImpl> newParent = parent->cloneNode(
false);
1665 for (NodeImpl *nextSibling = 0; node; node = nextSibling) {
1666 #ifdef DEBUG_COMMANDS
1667 kDebug() <<
"[reattach sibling]" << node << endl;
1669 nextSibling = node->nextSibling();
1673 node = newParent.get();
1674 if (parent == enclosingBlock)
1677 }
else if (node->isTextNode()) {
1680 ElementImpl *listItem =
document()->createHTMLElement(
"LI");
1683 ElementImpl *listItem =
document()->createHTMLElement(
"LI");
1688 #ifdef DEBUG_COMMANDS
1689 kDebug() <<
"[result]" << endl;
1690 printEnclosingBlockTree(enclosingBlock->parent());
1696 ElementImpl *breakNode =
document()->createHTMLElement(
"BR");
1699 #ifdef DEBUG_COMMANDS
1700 kDebug() <<
"[insert break]" << selection << endl;
1701 printEnclosingBlockTree(enclosingBlock);
1704 NodeImpl *nodeToInsert = breakNode;
1706 if (
document()->part()->editor()->typingStyle()) {
1707 int exceptionCode = 0;
1709 styleElement->appendChild(breakNode, exceptionCode);
1710 assert(exceptionCode == 0);
1711 nodeToInsert = styleElement;
1714 Position pos(selection.start().equivalentDownstreamPosition());
1715 bool atStart = pos.offset() <= pos.node()->caretMinOffset();
1716 bool atEndOfBlock = pos.isLastRenderedPositionInEditableBlock();
1718 #ifdef DEBUG_COMMANDS
1719 kDebug() <<
"[pos]" << pos << atStart << atEndOfBlock << endl;
1723 #ifdef DEBUG_COMMANDS
1724 kDebug(6200) <<
"input newline case 1";
1729 insertNodeAfterPosition(nodeToInsert, pos);
1731 ElementImpl *extraBreakNode =
document()->createHTMLElement(
"BR");
1735 }
else if (atStart) {
1736 #ifdef DEBUG_COMMANDS
1737 kDebug(6200) <<
"input newline case 2";
1742 insertNodeBeforePosition(nodeToInsert, pos);
1748 #ifdef DEBUG_COMMANDS
1749 kDebug(6200) <<
"input newline case 3";
1751 assert(pos.node()->isTextNode());
1752 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1753 TextImpl *textBeforeNode =
document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
1754 deleteText(textNode, 0, selection.start().offset());
1788 if (!selection.start().node()->isTextNode())
1791 int exceptionCode = 0;
1792 int offset = selection.start().offset() - 1;
1793 if (offset >= selection.start().node()->caretMinOffset()) {
1794 TextImpl *textNode =
static_cast<TextImpl *
>(selection.start().node());
1795 textNode->deleteData(offset, 1, exceptionCode);
1796 assert(exceptionCode == 0);
1797 selection = Selection(Position(textNode, offset));
1799 m_charactersAdded--;
1803 Position InputTextCommandImpl::prepareForTextInsertion(
bool adjustDownstream)
1808 assert(selection.state() == Selection::CARET);
1810 #ifdef DEBUG_COMMANDS
1811 kDebug() <<
"[prepare selection]" << selection << endl;
1814 Position pos = selection.start();
1815 if (adjustDownstream)
1816 pos = pos.equivalentDownstreamPosition();
1818 pos = pos.equivalentUpstreamPosition();
1820 #ifdef DEBUG_COMMANDS
1821 kDebug() <<
"[prepare position]" << pos << endl;
1824 if (!pos.node()->isTextNode()) {
1825 NodeImpl *textNode =
document()->createEditingTextNode(
"");
1826 NodeImpl *nodeToInsert = textNode;
1827 if (
document()->part()->editor()->typingStyle()) {
1828 int exceptionCode = 0;
1830 styleElement->appendChild(textNode, exceptionCode);
1831 assert(exceptionCode == 0);
1832 nodeToInsert = styleElement;
1836 if (pos.node()->isEditableBlock()) {
1837 kDebug(6200) <<
"prepareForTextInsertion case 1";
1839 }
else if (pos.node()->id() == ID_BR && pos.offset() == 1) {
1840 kDebug(6200) <<
"prepareForTextInsertion case 2";
1842 }
else if (pos.node()->caretMinOffset() == pos.offset()) {
1843 kDebug(6200) <<
"prepareForTextInsertion case 3";
1845 }
else if (pos.node()->caretMaxOffset() == pos.offset()) {
1846 kDebug(6200) <<
"prepareForTextInsertion case 4";
1851 pos = Position(textNode, 0);
1854 if (
document()->part()->editor()->typingStyle()) {
1855 if (pos.node()->isTextNode() && pos.offset() > pos.node()->caretMinOffset() && pos.offset() < pos.node()->caretMaxOffset()) {
1857 TextImpl *text =
static_cast<TextImpl *
>(pos.node());
1858 RefPtr<SplitTextNodeCommandImpl> cmd =
new SplitTextNodeCommandImpl(
document(), text, pos.offset());
1863 int exceptionCode = 0;
1864 TextImpl *editingTextNode =
document()->createEditingTextNode(
"");
1867 styleElement->appendChild(editingTextNode, exceptionCode);
1868 assert(exceptionCode == 0);
1875 pos = Position(editingTextNode, 0);
1881 void InputTextCommandImpl::execute(
const DOMString &text)
1883 #ifdef DEBUG_COMMANDS
1884 kDebug() <<
"[execute command]" << text << endl;
1887 #ifdef DEBUG_COMMANDS
1888 kDebug() <<
"[ending selection]" << selection << endl;
1890 bool adjustDownstream = selection.start().isFirstRenderedPositionOnLine();
1891 #ifdef DEBUG_COMMANDS
1892 kDebug() <<
"[adjust]" << adjustDownstream << endl;
1895 #ifdef DEBUG_COMMANDS
1896 printEnclosingBlockTree(selection.start().node());
1900 if (selection.state() == Selection::RANGE)
1905 #ifdef DEBUG_COMMANDS
1906 kDebug() <<
"[after collapsible whitespace deletion]" << endl;
1907 printEnclosingBlockTree(selection.start().node());
1913 Position pos = prepareForTextInsertion(adjustDownstream);
1914 #ifdef DEBUG_COMMANDS
1915 kDebug() <<
"[after prepare]" << pos << endl;
1918 TextImpl *textNode =
static_cast<TextImpl *
>(pos.node());
1919 long offset = pos.offset();
1921 #ifdef DEBUG_COMMANDS
1922 kDebug() <<
"[insert at]" << textNode << offset << endl;
1929 insertSpace(textNode, offset);
1931 const DOMString &existingText = textNode->data();
1932 if (textNode->length() >= 2 && offset >= 2 && isNBSP(existingText[offset - 1]) && !isWS(existingText[offset - 2])) {
1944 m_charactersAdded += text.
length();
1947 void InputTextCommandImpl::insertSpace(TextImpl *textNode,
unsigned long offset)
1957 for (
unsigned int i = offset; i < text.
length(); i++) {
1966 Position pos(textNode, offset);
1967 Position downstream = pos.equivalentDownstreamPosition();
1968 if (downstream.offset() < (long)text.
length() && isWS(text[downstream.offset()]))
1974 if (offset > 0 && offset <= text.
length() - 1 && !isWS(text[offset]) && !isWS(text[offset - 1])) {
1980 if (text.
length() >= 2 && offset >= 2 && isNBSP(text[offset - 2]) && isNBSP(text[offset - 1])) {
1989 insertText(textNode, offset, nonBreakingSpaceString());
1996 :
EditCommandImpl(document), m_insertChild(insertChild), m_refChild(refChild)
1999 m_insertChild->ref();
2008 m_insertChild->deref();
2010 m_refChild->deref();
2017 assert(m_refChild->parentNode());
2019 int exceptionCode = 0;
2020 m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
2021 assert(exceptionCode == 0);
2028 assert(m_refChild->parentNode());
2030 int exceptionCode = 0;
2031 m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
2032 assert(exceptionCode == 0);
2046 m_text = text.
copy();
2060 int exceptionCode = 0;
2061 m_node->insertData(m_offset, m_text, exceptionCode);
2062 assert(exceptionCode == 0);
2070 int exceptionCode = 0;
2071 m_node->deleteData(m_offset, m_text.
length(), exceptionCode);
2072 assert(exceptionCode == 0);
2083 assert(m_text1->nextSibling() == m_text2);
2084 assert(m_text1->length() > 0);
2085 assert(m_text2->length() > 0);
2103 assert(m_text1->nextSibling() == m_text2);
2105 int exceptionCode = 0;
2106 m_text2->insertData(0, m_text1->data(), exceptionCode);
2107 assert(exceptionCode == 0);
2109 m_text2->parentNode()->removeChild(m_text1, exceptionCode);
2110 assert(exceptionCode == 0);
2112 m_offset = m_text1->length();
2120 int exceptionCode = 0;
2122 m_text2->deleteData(0, m_offset, exceptionCode);
2123 assert(exceptionCode == 0);
2125 m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
2126 assert(exceptionCode == 0);
2128 assert(m_text2->previousSibling()->isTextNode());
2129 assert(m_text2->previousSibling() == m_text1);
2146 NodeImpl *firstChild = m_fragment->firstChild();
2147 NodeImpl *lastChild = m_fragment->lastChild();
2152 if (selection.state() == Selection::RANGE)
2158 assert(!selection.isEmpty());
2163 }
else if (firstChild == lastChild && firstChild->isTextNode()) {
2165 Position base = selection.base();
2166 inputText(static_cast<TextImpl *>(firstChild)->data());
2167 if (m_selectReplacement) {
2173 NodeImpl *beforeNode = firstChild;
2174 NodeImpl *node = firstChild->nextSibling();
2176 insertNodeAt(firstChild, selection.start().node(), selection.start().offset());
2180 NodeImpl *next = node->nextSibling();
2188 NodeImpl *lastLeaf = lastChild;
2190 NodeImpl *nextChild = lastLeaf->lastChild();
2193 lastLeaf = nextChild;
2196 if (m_selectReplacement) {
2198 NodeImpl *firstLeaf = firstChild;
2200 NodeImpl *nextChild = firstLeaf->firstChild();
2203 firstLeaf = nextChild;
2206 setEndingSelection(Selection(Position(firstLeaf, firstLeaf->caretMinOffset()), Position(lastLeaf, lastLeaf->caretMaxOffset())));
2229 assert(selection.state() == Selection::RANGE);
2232 NodeImpl *positionNode = m_position.node();
2233 long positionOffset = m_position.offset();
2234 Position selectionEnd = selection.end();
2235 long selectionEndOffset = selectionEnd.offset();
2236 if (selectionEnd.node() == positionNode && selectionEndOffset < positionOffset) {
2237 positionOffset -= selectionEndOffset;
2238 Position selectionStart = selection.start();
2239 if (selectionStart.node() == positionNode) {
2240 positionOffset += selectionStart.offset();
2255 :
EditCommandImpl(document), m_decl(decl), m_property(property), m_important(false)
2271 m_oldValue = m_decl->getPropertyValue(m_property);
2274 m_important = m_decl->getPropertyPriority(m_property);
2275 m_decl->removeProperty(m_property);
2283 m_decl->setProperty(m_property, m_oldValue, m_important);
2290 :
EditCommandImpl(document), m_element(element), m_attribute(attribute)
2306 m_oldValue = m_element->getAttribute(m_attribute);
2309 int exceptionCode = 0;
2310 m_element->removeAttribute(m_attribute, exceptionCode);
2311 assert(exceptionCode == 0);
2320 m_element->setAttribute(m_attribute, m_oldValue.
implementation());
2328 :
EditCommandImpl(document), m_parent(0), m_removeChild(removeChild), m_refChild(0)
2331 m_removeChild->ref();
2333 m_parent = m_removeChild->parentNode();
2337 NodeListImpl *children = m_parent->childNodes();
2338 for (
int i = children->length(); i >= 0; i--) {
2339 NodeImpl *node = children->item(i);
2340 if (node == m_removeChild)
2354 m_removeChild->deref();
2356 m_refChild->deref();
2364 int exceptionCode = 0;
2365 m_parent->removeChild(m_removeChild, exceptionCode);
2366 assert(exceptionCode == 0);
2374 int exceptionCode = 0;
2376 m_parent->insertBefore(m_removeChild, m_refChild, exceptionCode);
2378 m_parent->appendChild(m_removeChild, exceptionCode);
2379 assert(exceptionCode == 0);
2396 m_pruneNode->deref();
2398 m_stopNode->deref();
2403 NodeImpl *editableBlock = m_pruneNode->enclosingBlockFlowElement();
2405 NodeImpl *node = pruneNode->traversePreviousNode();
2408 if (node == m_stopNode || editableBlock != node->enclosingBlockFlowElement() || !shouldPruneNode(node))
2411 node = node->traversePreviousNode();
2434 NodeListImpl *children =
node()->childNodes();
2435 int length = children->length();
2436 for (
int i = 0; i < length; i++) {
2437 NodeImpl *child = children->item(0);
2448 :
EditCommandImpl(document), m_element(element), m_attribute(attribute), m_value(value)
2467 m_oldValue = m_element->getAttribute(m_attribute);
2478 m_element->setAttribute(m_attribute, m_oldValue.
implementation());
2486 :
EditCommandImpl(document), m_text1(0), m_text2(text), m_offset(offset)
2489 assert(m_text2->length() > 0);
2507 int exceptionCode = 0;
2516 m_text1 =
document()->createTextNode(m_text2->substringData(0, m_offset, exceptionCode));
2517 assert(exceptionCode == 0);
2522 m_text2->deleteData(0, m_offset, exceptionCode);
2523 assert(exceptionCode == 0);
2525 m_text2->parentNode()->insertBefore(m_text1, m_text2, exceptionCode);
2526 assert(exceptionCode == 0);
2528 assert(m_text2->previousSibling()->isTextNode());
2529 assert(m_text2->previousSibling() == m_text1);
2537 assert(m_text1->nextSibling() == m_text2);
2539 int exceptionCode = 0;
2540 m_text2->insertData(0, m_text1->data(), exceptionCode);
2541 assert(exceptionCode == 0);
2543 m_text2->parentNode()->removeChild(m_text1, exceptionCode);
2544 assert(exceptionCode == 0);
2546 m_offset = m_text1->length();
2565 void TypingCommandImpl::typingAddedToOpenCommand()
2569 document()->part()->editor()->appliedEditing(
this);
2574 if (
document()->part()->editor()->typingStyle() ||
m_cmds.count() == 0) {
2588 typingAddedToOpenCommand();
2595 typingAddedToOpenCommand();
2598 void TypingCommandImpl::issueCommandForDeleteKey()
2601 assert(selectionToDelete.state() != Selection::NONE);
2603 #ifdef DEBUG_COMMANDS
2604 kDebug() <<
"[selection]" << selectionToDelete << endl;
2606 if (selectionToDelete.state() == Selection::CARET) {
2607 #ifdef DEBUG_COMMANDS
2608 kDebug() <<
"[caret selection]" << endl;
2610 Position pos(selectionToDelete.start());
2611 if (pos.inFirstEditableInRootEditableElement() && pos.offset() <= pos.node()->caretMinOffset()) {
2615 selectionToDelete = Selection(pos.previousCharacterPosition(), pos);
2616 #ifdef DEBUG_COMMANDS
2617 kDebug() <<
"[modified selection]" << selectionToDelete << endl;
2621 typingAddedToOpenCommand();
2634 issueCommandForDeleteKey();
2636 if (
m_cmds.count() == 0) {
2637 issueCommandForDeleteKey();
2640 EditCommand lastCommand =
m_cmds.last();
2641 if (lastCommand.commandID() == InputTextCommandID) {
2642 InputTextCommand cmd =
static_cast<InputTextCommand &
>(lastCommand);
2643 cmd.deleteCharacter();
2644 if (cmd.charactersAdded() == 0) {
2648 else if (lastCommand.commandID() == InputNewlineCommandID) {
2649 lastCommand.unapply();
2650 removeCommand(lastCommand);
2653 issueCommandForDeleteKey();
2659 void TypingCommandImpl::removeCommand(
const PassRefPtr<EditCommandImpl> cmd)
2673 static bool isOpenForMoreTypingCommand(
const EditCommandImpl *command)
2675 return command && command->isTypingCommand() &&
2676 static_cast<const TypingCommandImpl*
>(command)->openForMoreTyping();
2688 command->deleteKeyPressed();
2695 Editor *ed = document->part()->editor();
2698 if (isOpenForMoreTypingCommand(lastEditCommand)) {
2703 command->insertNewline();
2709 #ifdef DEBUG_COMMANDS
2710 kDebug() <<
"[insert text]" << text << endl;
2713 Editor *ed = document->part()->editor();
2716 if (isOpenForMoreTypingCommand(lastEditCommand)) {
2721 command->insertText(text);
2740 #ifdef DEBUG_COMMANDS
2745 ElementImpl *startBlock = start.node()->enclosingBlockFlowElement();
2746 ElementImpl *endBlock = end.node()->enclosingBlockFlowElement();
2747 #ifdef DEBUG_COMMANDS
2748 kDebug() <<
"[start:end blocks]" << startBlock << endBlock << endl;
2749 printEnclosingBlockTree(start.node());
2751 if (startBlock == endBlock) {
2752 if (startBlock->id() == ID_LI) {
2754 #ifdef DEBUG_COMMANDS
2755 kDebug() <<
"[remove list item]" << endl;
2757 NodeImpl *listBlock = startBlock->parent();
2760 if (listBlock->firstChild() == listBlock->lastChild() && listBlock->firstChild() == startBlock) {
2762 #ifdef DEBUG_COMMANDS
2763 kDebug() <<
"[remove list completely]" << endl;
2767 }
else if (!startBlock->previousSibling()) {
2769 NodeImpl *nextSibling;
2770 for (NodeImpl *node = startBlock->firstChild(); node; node = nextSibling) {
2771 nextSibling = node->nextSibling();
2776 }
else if (!startBlock->nextSibling()) {
2778 NodeImpl *nextSibling;
2779 for (NodeImpl *node = startBlock->lastChild(); node; node = nextSibling) {
2780 nextSibling = node->previousSibling();
2787 WTF::PassRefPtr<NodeImpl> newListBlock = listBlock->cloneNode(
false);
2789 NodeImpl *node, *nextSibling;
2790 for (node = startBlock->nextSibling(); node; node = nextSibling) {
2791 nextSibling = node->nextSibling();
2795 for (node = startBlock->firstChild(); node; node = nextSibling) {
2796 nextSibling = node->nextSibling();
2804 ElementImpl *li =
document()->createHTMLElement(
"LI");
2807 for (NodeImpl *node = startBlock->firstChild(); node; node = nextNode) {
2808 #ifdef DEBUG_COMMANDS
2809 kDebug() <<
"[reattach node]" << node << endl;
2811 nextNode = node->nextSibling();
2818 #ifdef DEBUG_COMMANDS
2819 kDebug() <<
"[different blocks are not supported yet]" << endl;
2827 insertCommand->apply();
2844 void IndentOutdentCommandImpl::indent()
2847 #ifdef DEBUG_COMMANDS
2848 kDebug() <<
"[indent selection]" << selection << endl;
2850 NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
2851 NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
2853 if (startBlock == endBlock) {
2855 if (startBlock->id() == ID_LI && (startBlock->previousSibling() || startBlock->nextSibling())) {
2856 #ifdef DEBUG_COMMANDS
2857 kDebug() <<
"[modify list]" << endl;
2859 RefPtr<NodeImpl> newList = startBlock->parent()->cloneNode(
false);
2864 NodeImpl *blockquoteElement =
document()->createHTMLElement(
"blockquote");
2865 if (startBlock->id() == ID_LI) {
2866 startBlock = startBlock->parent();
2867 NodeImpl *parent = startBlock->parent();
2872 NodeImpl *parent = startBlock->parent();
2879 if (startBlock->id() == ID_LI && endBlock->id() == ID_LI && startBlock->parent() == endBlock->parent()) {
2880 #ifdef DEBUG_COMMANDS
2881 kDebug() <<
"[indent some items inside list]" << endl;
2883 RefPtr<NodeImpl> nestedList = startBlock->parent()->cloneNode(
false);
2885 NodeImpl *nextNode = 0;
2886 for (NodeImpl *node = startBlock;; node = nextNode) {
2887 nextNode = node->nextSibling();
2890 if (node == endBlock)
2894 #ifdef DEBUG_COMMANDS
2895 kDebug() <<
"[blocks not from one list are not supported yet]" << endl;
2901 static bool hasPreviousListItem(NodeImpl *node)
2904 node = node->previousSibling();
2905 if (node && node->id() == ID_LI)
2911 static bool hasNextListItem(NodeImpl *node)
2914 node = node->nextSibling();
2915 if (node && node->id() == ID_LI)
2921 void IndentOutdentCommandImpl::outdent()
2924 #ifdef DEBUG_COMMANDS
2925 kDebug() <<
"[indent selection]" << selection << endl;
2927 NodeImpl *startBlock = selection.start().node()->enclosingBlockFlowElement();
2928 NodeImpl *endBlock = selection.end().node()->enclosingBlockFlowElement();
2930 if (startBlock->id() == ID_LI && endBlock->id() == ID_LI && startBlock->parent() == endBlock->parent()) {
2931 #ifdef DEBUG_COMMANDS
2932 kDebug() <<
"[list items selected]" << endl;
2934 bool firstItemSelected = !hasPreviousListItem(startBlock);
2935 bool lastItemSelected = !hasNextListItem(endBlock);
2936 bool listFullySelected = firstItemSelected && lastItemSelected;
2938 #ifdef DEBUG_COMMANDS
2939 kDebug() <<
"[first/last item selected]" << firstItemSelected << lastItemSelected << endl;
2942 NodeImpl *listNode = startBlock->parent();
2943 printEnclosingBlockTree(listNode);
2944 bool hasParentList = listNode->parent()->id() == ID_OL || listNode->parent()->id() == ID_UL;
2946 if (!firstItemSelected && !lastItemSelected) {
2948 RefPtr<NodeImpl> clonedList = listNode->cloneNode(
false);
2949 NodeImpl *nextNode = 0;
2950 for (NodeImpl *node = listNode->firstChild(); node != startBlock; node = nextNode) {
2951 nextNode = node->nextSibling();
2957 firstItemSelected =
true;
2960 NodeImpl *nextNode = 0;
2961 for (NodeImpl *node = firstItemSelected ? startBlock : endBlock;; node = nextNode) {
2962 nextNode = firstItemSelected ? node->nextSibling() : node->previousSibling();
2964 if (firstItemSelected)
2968 if (!hasParentList && node->id() == ID_LI) {
2972 if (node == (firstItemSelected ? endBlock : startBlock))
2975 if (listFullySelected)
2981 if (startBlock == endBlock) {
2982 if (startBlock->id() == ID_BLOCKQUOTE) {
2985 #ifdef DEBUG_COMMANDS
2986 kDebug() <<
"[not the list or blockquote]" << endl;
2990 #ifdef DEBUG_COMMANDS
2991 kDebug() <<
"[blocks not from one list are not supported yet]" << endl;
2998 if (m_commandType ==
Indent)