summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:41 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:41 -0800
commit648161bb0edfc3d43db63caed5cc5213bc6cb78f (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /WebCore/editing
parenta65af38181ac7d34544586bdb5cd004de93897ad (diff)
downloadexternal_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.zip
external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.gz
external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/AppendNodeCommand.cpp63
-rw-r--r--WebCore/editing/AppendNodeCommand.h52
-rw-r--r--WebCore/editing/ApplyStyleCommand.cpp1349
-rw-r--r--WebCore/editing/ApplyStyleCommand.h115
-rw-r--r--WebCore/editing/BreakBlockquoteCommand.cpp175
-rw-r--r--WebCore/editing/BreakBlockquoteCommand.h47
-rw-r--r--WebCore/editing/CompositeEditCommand.cpp960
-rw-r--r--WebCore/editing/CompositeEditCommand.h116
-rw-r--r--WebCore/editing/CreateLinkCommand.cpp60
-rw-r--r--WebCore/editing/CreateLinkCommand.h51
-rw-r--r--WebCore/editing/DeleteButton.cpp55
-rw-r--r--WebCore/editing/DeleteButton.h42
-rw-r--r--WebCore/editing/DeleteButtonController.cpp308
-rw-r--r--WebCore/editing/DeleteButtonController.h77
-rw-r--r--WebCore/editing/DeleteFromTextNodeCommand.cpp64
-rw-r--r--WebCore/editing/DeleteFromTextNodeCommand.h56
-rw-r--r--WebCore/editing/DeleteSelectionCommand.cpp790
-rw-r--r--WebCore/editing/DeleteSelectionCommand.h97
-rw-r--r--WebCore/editing/EditAction.h71
-rw-r--r--WebCore/editing/EditCommand.cpp237
-rw-r--r--WebCore/editing/EditCommand.h96
-rw-r--r--WebCore/editing/Editor.cpp2074
-rw-r--r--WebCore/editing/Editor.h302
-rw-r--r--WebCore/editing/EditorCommand.cpp1418
-rw-r--r--WebCore/editing/EditorDeleteAction.h40
-rw-r--r--WebCore/editing/EditorInsertAction.h40
-rw-r--r--WebCore/editing/FormatBlockCommand.cpp134
-rw-r--r--WebCore/editing/FormatBlockCommand.h52
-rw-r--r--WebCore/editing/HTMLInterchange.cpp111
-rw-r--r--WebCore/editing/HTMLInterchange.h46
-rw-r--r--WebCore/editing/IndentOutdentCommand.cpp298
-rw-r--r--WebCore/editing/IndentOutdentCommand.h60
-rw-r--r--WebCore/editing/InsertIntoTextNodeCommand.cpp58
-rw-r--r--WebCore/editing/InsertIntoTextNodeCommand.h55
-rw-r--r--WebCore/editing/InsertLineBreakCommand.cpp187
-rw-r--r--WebCore/editing/InsertLineBreakCommand.h54
-rw-r--r--WebCore/editing/InsertListCommand.cpp265
-rw-r--r--WebCore/editing/InsertListCommand.h62
-rw-r--r--WebCore/editing/InsertNodeBeforeCommand.cpp66
-rw-r--r--WebCore/editing/InsertNodeBeforeCommand.h52
-rw-r--r--WebCore/editing/InsertParagraphSeparatorCommand.cpp332
-rw-r--r--WebCore/editing/InsertParagraphSeparatorCommand.h59
-rw-r--r--WebCore/editing/InsertTextCommand.cpp242
-rw-r--r--WebCore/editing/InsertTextCommand.h61
-rw-r--r--WebCore/editing/JoinTextNodesCommand.cpp76
-rw-r--r--WebCore/editing/JoinTextNodesCommand.h55
-rw-r--r--WebCore/editing/MergeIdenticalElementsCommand.cpp77
-rw-r--r--WebCore/editing/MergeIdenticalElementsCommand.h53
-rw-r--r--WebCore/editing/ModifySelectionListLevel.cpp293
-rw-r--r--WebCore/editing/ModifySelectionListLevel.h80
-rw-r--r--WebCore/editing/MoveSelectionCommand.cpp81
-rw-r--r--WebCore/editing/MoveSelectionCommand.h55
-rw-r--r--WebCore/editing/RemoveCSSPropertyCommand.cpp62
-rw-r--r--WebCore/editing/RemoveCSSPropertyCommand.h56
-rw-r--r--WebCore/editing/RemoveFormatCommand.cpp84
-rw-r--r--WebCore/editing/RemoveFormatCommand.h49
-rw-r--r--WebCore/editing/RemoveNodeAttributeCommand.cpp62
-rw-r--r--WebCore/editing/RemoveNodeAttributeCommand.h54
-rw-r--r--WebCore/editing/RemoveNodeCommand.cpp63
-rw-r--r--WebCore/editing/RemoveNodeCommand.h53
-rw-r--r--WebCore/editing/RemoveNodePreservingChildrenCommand.cpp49
-rw-r--r--WebCore/editing/RemoveNodePreservingChildrenCommand.h50
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.cpp1003
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.h90
-rw-r--r--WebCore/editing/Selection.cpp597
-rw-r--r--WebCore/editing/Selection.h134
-rw-r--r--WebCore/editing/SelectionController.cpp1187
-rw-r--r--WebCore/editing/SelectionController.h186
-rw-r--r--WebCore/editing/SetNodeAttributeCommand.cpp66
-rw-r--r--WebCore/editing/SetNodeAttributeCommand.h55
-rw-r--r--WebCore/editing/SmartReplace.cpp43
-rw-r--r--WebCore/editing/SmartReplace.h35
-rw-r--r--WebCore/editing/SmartReplaceCF.cpp72
-rw-r--r--WebCore/editing/SmartReplaceICU.cpp99
-rw-r--r--WebCore/editing/SplitElementCommand.cpp90
-rw-r--r--WebCore/editing/SplitElementCommand.h53
-rw-r--r--WebCore/editing/SplitTextNodeCommand.cpp90
-rw-r--r--WebCore/editing/SplitTextNodeCommand.h55
-rw-r--r--WebCore/editing/SplitTextNodeContainingElementCommand.cpp59
-rw-r--r--WebCore/editing/SplitTextNodeContainingElementCommand.h51
-rw-r--r--WebCore/editing/TextAffinity.h57
-rw-r--r--WebCore/editing/TextGranularity.h47
-rw-r--r--WebCore/editing/TextIterator.cpp1445
-rw-r--r--WebCore/editing/TextIterator.h253
-rw-r--r--WebCore/editing/TypingCommand.cpp535
-rw-r--r--WebCore/editing/TypingCommand.h103
-rw-r--r--WebCore/editing/UnlinkCommand.cpp50
-rw-r--r--WebCore/editing/UnlinkCommand.h49
-rw-r--r--WebCore/editing/VisiblePosition.cpp654
-rw-r--r--WebCore/editing/VisiblePosition.h141
-rw-r--r--WebCore/editing/WrapContentsInDummySpanCommand.cpp77
-rw-r--r--WebCore/editing/WrapContentsInDummySpanCommand.h52
-rw-r--r--WebCore/editing/android/EditorAndroid.cpp39
-rw-r--r--WebCore/editing/htmlediting.cpp991
-rw-r--r--WebCore/editing/htmlediting.h134
-rw-r--r--WebCore/editing/mac/EditorMac.mm124
-rw-r--r--WebCore/editing/mac/SelectionControllerMac.mm64
-rw-r--r--WebCore/editing/markup.cpp1219
-rw-r--r--WebCore/editing/markup.h56
-rw-r--r--WebCore/editing/qt/EditorQt.cpp47
-rw-r--r--WebCore/editing/visible_units.cpp960
-rw-r--r--WebCore/editing/visible_units.h91
-rw-r--r--WebCore/editing/wx/EditorWx.cpp38
103 files changed, 0 insertions, 23492 deletions
diff --git a/WebCore/editing/AppendNodeCommand.cpp b/WebCore/editing/AppendNodeCommand.cpp
deleted file mode 100644
index 6641877..0000000
--- a/WebCore/editing/AppendNodeCommand.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "AppendNodeCommand.h"
-#include "htmlediting.h"
-
-namespace WebCore {
-
-AppendNodeCommand::AppendNodeCommand(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend)
- : SimpleEditCommand(parentNode->document()), m_parentNode(parentNode), m_childToAppend(childToAppend)
-{
- ASSERT(m_childToAppend);
- ASSERT(m_parentNode);
-}
-
-void AppendNodeCommand::doApply()
-{
- ASSERT(m_childToAppend);
- ASSERT(m_parentNode);
- // If the child to append is already in a tree, appending it will remove it from it's old location
- // in an non-undoable way. We might eventually find it useful to do an undoable remove in this case.
- ASSERT(!m_childToAppend->parent());
- ASSERT(enclosingNodeOfType(Position(m_parentNode.get(), 0), &isContentEditable) || !m_parentNode->attached());
-
- ExceptionCode ec = 0;
- m_parentNode->appendChild(m_childToAppend.get(), ec);
- ASSERT(ec == 0);
-}
-
-void AppendNodeCommand::doUnapply()
-{
- ASSERT(m_childToAppend);
- ASSERT(m_parentNode);
-
- ExceptionCode ec = 0;
- m_parentNode->removeChild(m_childToAppend.get(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/AppendNodeCommand.h b/WebCore/editing/AppendNodeCommand.h
deleted file mode 100644
index 3210512..0000000
--- a/WebCore/editing/AppendNodeCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef AppendNodeCommand_h
-#define AppendNodeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class AppendNodeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<AppendNodeCommand> create(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend)
- {
- return adoptRef(new AppendNodeCommand(parentNode, childToAppend));
- }
-
-private:
- AppendNodeCommand(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Node> m_parentNode;
- RefPtr<Node> m_childToAppend;
-};
-
-} // namespace WebCore
-
-#endif // AppendNodeCommand_h
diff --git a/WebCore/editing/ApplyStyleCommand.cpp b/WebCore/editing/ApplyStyleCommand.cpp
deleted file mode 100644
index 887ae3c..0000000
--- a/WebCore/editing/ApplyStyleCommand.cpp
+++ /dev/null
@@ -1,1349 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ApplyStyleCommand.h"
-
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSParser.h"
-#include "CSSProperty.h"
-#include "CSSPropertyNames.h"
-#include "Document.h"
-#include "HTMLElement.h"
-#include "HTMLInterchange.h"
-#include "HTMLNames.h"
-#include "NodeList.h"
-#include "Range.h"
-#include "RenderObject.h"
-#include "Text.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class StyleChange {
-public:
- enum ELegacyHTMLStyles { DoNotUseLegacyHTMLStyles, UseLegacyHTMLStyles };
-
- explicit StyleChange(CSSStyleDeclaration *, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
- StyleChange(CSSStyleDeclaration *, const Position &, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
-
- static ELegacyHTMLStyles styleModeForParseMode(bool);
-
- String cssStyle() const { return m_cssStyle; }
- bool applyBold() const { return m_applyBold; }
- bool applyItalic() const { return m_applyItalic; }
- bool applyFontColor() const { return m_applyFontColor.length() > 0; }
- bool applyFontFace() const { return m_applyFontFace.length() > 0; }
- bool applyFontSize() const { return m_applyFontSize.length() > 0; }
-
- String fontColor() { return m_applyFontColor; }
- String fontFace() { return m_applyFontFace; }
- String fontSize() { return m_applyFontSize; }
-
- bool usesLegacyStyles() const { return m_usesLegacyStyles; }
-
-private:
- void init(PassRefPtr<CSSStyleDeclaration>, const Position &);
- bool checkForLegacyHTMLStyleChange(const CSSProperty *);
- static bool currentlyHasStyle(const Position &, const CSSProperty *);
-
- String m_cssStyle;
- bool m_applyBold;
- bool m_applyItalic;
- String m_applyFontColor;
- String m_applyFontFace;
- String m_applyFontSize;
- bool m_usesLegacyStyles;
-};
-
-
-
-StyleChange::StyleChange(CSSStyleDeclaration *style, ELegacyHTMLStyles usesLegacyStyles)
- : m_applyBold(false), m_applyItalic(false), m_usesLegacyStyles(usesLegacyStyles)
-{
- init(style, Position());
-}
-
-StyleChange::StyleChange(CSSStyleDeclaration *style, const Position &position, ELegacyHTMLStyles usesLegacyStyles)
- : m_applyBold(false), m_applyItalic(false), m_usesLegacyStyles(usesLegacyStyles)
-{
- init(style, position);
-}
-
-void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position &position)
-{
- RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
-
- String styleText("");
-
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
- const CSSProperty *property = &*it;
-
- // If position is empty or the position passed in already has the
- // style, just move on.
- if (position.isNotNull() && currentlyHasStyle(position, property))
- continue;
-
- // Changing the whitespace style in a tab span would collapse the tab into a space.
- if (property->id() == CSSPropertyWhiteSpace && (isTabSpanTextNode(position.node()) || isTabSpanNode((position.node()))))
- continue;
-
- // If needed, figure out if this change is a legacy HTML style change.
- if (m_usesLegacyStyles && checkForLegacyHTMLStyleChange(property))
- continue;
-
- // Add this property
-
- if (property->id() == CSSPropertyWebkitTextDecorationsInEffect) {
- // we have to special-case text decorations
- CSSProperty alteredProperty = CSSProperty(CSSPropertyTextDecoration, property->value(), property->isImportant());
- styleText += alteredProperty.cssText();
- } else
- styleText += property->cssText();
- }
-
- // Save the result for later
- m_cssStyle = styleText.stripWhiteSpace();
-}
-
-StyleChange::ELegacyHTMLStyles StyleChange::styleModeForParseMode(bool isQuirksMode)
-{
- return isQuirksMode ? UseLegacyHTMLStyles : DoNotUseLegacyHTMLStyles;
-}
-
-bool StyleChange::checkForLegacyHTMLStyleChange(const CSSProperty *property)
-{
- if (!property || !property->value()) {
- return false;
- }
-
- String valueText(property->value()->cssText());
- switch (property->id()) {
- case CSSPropertyFontWeight:
- if (equalIgnoringCase(valueText, "bold")) {
- m_applyBold = true;
- return true;
- }
- break;
- case CSSPropertyFontStyle:
- if (equalIgnoringCase(valueText, "italic") || equalIgnoringCase(valueText, "oblique")) {
- m_applyItalic = true;
- return true;
- }
- break;
- case CSSPropertyColor: {
- RGBA32 rgba = 0;
- CSSParser::parseColor(rgba, valueText);
- Color color(rgba);
- m_applyFontColor = color.name();
- return true;
- }
- case CSSPropertyFontFamily:
- m_applyFontFace = valueText;
- return true;
- case CSSPropertyFontSize:
- if (property->value()->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
- CSSPrimitiveValue *value = static_cast<CSSPrimitiveValue *>(property->value());
-
- if (value->primitiveType() < CSSPrimitiveValue::CSS_PX || value->primitiveType() > CSSPrimitiveValue::CSS_PC)
- // Size keyword or relative unit.
- return false;
-
- float number = value->getFloatValue(CSSPrimitiveValue::CSS_PX);
- if (number <= 9)
- m_applyFontSize = "1";
- else if (number <= 10)
- m_applyFontSize = "2";
- else if (number <= 13)
- m_applyFontSize = "3";
- else if (number <= 16)
- m_applyFontSize = "4";
- else if (number <= 18)
- m_applyFontSize = "5";
- else if (number <= 24)
- m_applyFontSize = "6";
- else
- m_applyFontSize = "7";
- // Huge quirk in Microsft Entourage is that they understand CSS font-size, but also write
- // out legacy 1-7 values in font tags (I guess for mailers that are not CSS-savvy at all,
- // like Eudora). Yes, they write out *both*. We need to write out both as well. Return false.
- return false;
- }
- else {
- // Can't make sense of the number. Put no font size.
- return true;
- }
- }
- return false;
-}
-
-bool StyleChange::currentlyHasStyle(const Position &pos, const CSSProperty *property)
-{
- ASSERT(pos.isNotNull());
- RefPtr<CSSComputedStyleDeclaration> style = pos.computedStyle();
- RefPtr<CSSValue> value = style->getPropertyCSSValue(property->id(), DoNotUpdateLayout);
- if (!value)
- return false;
- return equalIgnoringCase(value->cssText(), property->value()->cssText());
-}
-
-static String &styleSpanClassString()
-{
- static String styleSpanClassString = AppleStyleSpanClass;
- return styleSpanClassString;
-}
-
-bool isStyleSpan(const Node *node)
-{
- if (!node || !node->isHTMLElement())
- return false;
-
- const HTMLElement *elem = static_cast<const HTMLElement *>(node);
- return elem->hasLocalName(spanAttr) && elem->getAttribute(classAttr) == styleSpanClassString();
-}
-
-static bool isUnstyledStyleSpan(const Node *node)
-{
- if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag))
- return false;
-
- const HTMLElement *elem = static_cast<const HTMLElement *>(node);
- CSSMutableStyleDeclaration *inlineStyleDecl = elem->inlineStyleDecl();
- return (!inlineStyleDecl || inlineStyleDecl->length() == 0) && elem->getAttribute(classAttr) == styleSpanClassString();
-}
-
-static bool isEmptyFontTag(const Node *node)
-{
- if (!node || !node->hasTagName(fontTag))
- return false;
-
- const Element *elem = static_cast<const Element *>(node);
- NamedAttrMap *map = elem->attributes(true); // true for read-only
- return (!map || map->length() == 1) && elem->getAttribute(classAttr) == styleSpanClassString();
-}
-
-static PassRefPtr<Element> createFontElement(Document* document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> fontNode = document->createElementNS(xhtmlNamespaceURI, "font", ec);
- ASSERT(ec == 0);
- fontNode->setAttribute(classAttr, styleSpanClassString());
- return fontNode.release();
-}
-
-PassRefPtr<HTMLElement> createStyleSpanElement(Document* document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> styleElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
- ASSERT(ec == 0);
- styleElement->setAttribute(classAttr, styleSpanClassString());
- return static_pointer_cast<HTMLElement>(styleElement.release());
-}
-
-ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, EditAction editingAction, EPropertyLevel propertyLevel)
- : CompositeEditCommand(document)
- , m_style(style->makeMutable())
- , m_editingAction(editingAction)
- , m_propertyLevel(propertyLevel)
- , m_start(endingSelection().start().downstream())
- , m_end(endingSelection().end().upstream())
- , m_useEndingSelection(true)
- , m_styledInlineElement(0)
- , m_removeOnly(false)
-{
-}
-
-ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction, EPropertyLevel propertyLevel)
- : CompositeEditCommand(document)
- , m_style(style->makeMutable())
- , m_editingAction(editingAction)
- , m_propertyLevel(propertyLevel)
- , m_start(start)
- , m_end(end)
- , m_useEndingSelection(false)
- , m_styledInlineElement(0)
- , m_removeOnly(false)
-{
-}
-
-ApplyStyleCommand::ApplyStyleCommand(Element* element, bool removeOnly, EditAction editingAction)
- : CompositeEditCommand(element->document())
- , m_style(CSSMutableStyleDeclaration::create())
- , m_editingAction(editingAction)
- , m_propertyLevel(PropertyDefault)
- , m_start(endingSelection().start().downstream())
- , m_end(endingSelection().end().upstream())
- , m_useEndingSelection(true)
- , m_styledInlineElement(element)
- , m_removeOnly(removeOnly)
-{
-}
-
-void ApplyStyleCommand::updateStartEnd(const Position& newStart, const Position& newEnd)
-{
- ASSERT(Range::compareBoundaryPoints(newEnd, newStart) >= 0);
-
- if (!m_useEndingSelection && (newStart != m_start || newEnd != m_end))
- m_useEndingSelection = true;
-
- setEndingSelection(Selection(newStart, newEnd, VP_DEFAULT_AFFINITY));
- m_start = newStart;
- m_end = newEnd;
-}
-
-Position ApplyStyleCommand::startPosition()
-{
- if (m_useEndingSelection)
- return endingSelection().start();
-
- return m_start;
-}
-
-Position ApplyStyleCommand::endPosition()
-{
- if (m_useEndingSelection)
- return endingSelection().end();
-
- return m_end;
-}
-
-void ApplyStyleCommand::doApply()
-{
- switch (m_propertyLevel) {
- case PropertyDefault: {
- // apply the block-centric properties of the style
- RefPtr<CSSMutableStyleDeclaration> blockStyle = m_style->copyBlockProperties();
- if (blockStyle->length())
- applyBlockStyle(blockStyle.get());
- // apply any remaining styles to the inline elements
- // NOTE: hopefully, this string comparison is the same as checking for a non-null diff
- if (blockStyle->length() < m_style->length() || m_styledInlineElement) {
- RefPtr<CSSMutableStyleDeclaration> inlineStyle = m_style->copy();
- applyRelativeFontStyleChange(inlineStyle.get());
- blockStyle->diff(inlineStyle.get());
- applyInlineStyle(inlineStyle.get());
- }
- break;
- }
- case ForceBlockProperties:
- // Force all properties to be applied as block styles.
- applyBlockStyle(m_style.get());
- break;
- }
-}
-
-EditAction ApplyStyleCommand::editingAction() const
-{
- return m_editingAction;
-}
-
-void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclaration *style)
-{
- // update document layout once before removing styles
- // so that we avoid the expense of updating before each and every call
- // to check a computed style
- updateLayout();
-
- // get positions we want to use for applying style
- Position start = startPosition();
- Position end = endPosition();
- if (Range::compareBoundaryPoints(end, start) < 0) {
- Position swap = start;
- start = end;
- end = swap;
- }
-
- VisiblePosition visibleStart(start);
- VisiblePosition visibleEnd(end);
- // Save and restore the selection endpoints using their indices in the document, since
- // addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoints.
- // Calculate start and end indices from the start of the tree that they're in.
- Node* scope = highestAncestor(visibleStart.deepEquivalent().node());
- Position rangeStart(scope, 0);
- RefPtr<Range> startRange = Range::create(document(), rangeStart, rangeCompliantEquivalent(visibleStart.deepEquivalent()));
- RefPtr<Range> endRange = Range::create(document(), rangeStart, rangeCompliantEquivalent(visibleEnd.deepEquivalent()));
- int startIndex = TextIterator::rangeLength(startRange.get(), true);
- int endIndex = TextIterator::rangeLength(endRange.get(), true);
-
- VisiblePosition paragraphStart(startOfParagraph(visibleStart));
- VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next());
- VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next());
- while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
- StyleChange styleChange(style, paragraphStart.deepEquivalent(), StyleChange::styleModeForParseMode(document()->inCompatMode()));
- if (styleChange.cssStyle().length() > 0 || m_removeOnly) {
- RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().node());
- RefPtr<Node> newBlock = moveParagraphContentsToNewBlockIfNecessary(paragraphStart.deepEquivalent());
- if (newBlock)
- block = newBlock;
- ASSERT(block->isHTMLElement());
- if (block->isHTMLElement()) {
- removeCSSStyle(style, static_cast<HTMLElement*>(block.get()));
- if (!m_removeOnly)
- addBlockStyle(styleChange, static_cast<HTMLElement*>(block.get()));
- }
- }
- paragraphStart = nextParagraphStart;
- nextParagraphStart = endOfParagraph(paragraphStart).next();
- }
-
- startRange = TextIterator::rangeFromLocationAndLength(static_cast<Element*>(scope), startIndex, 0, true);
- endRange = TextIterator::rangeFromLocationAndLength(static_cast<Element*>(scope), endIndex, 0, true);
- if (startRange && endRange)
- updateStartEnd(startRange->startPosition(), endRange->startPosition());
-}
-
-#define NoFontDelta (0.0f)
-#define MinimumFontSize (0.1f)
-
-void ApplyStyleCommand::applyRelativeFontStyleChange(CSSMutableStyleDeclaration *style)
-{
- RefPtr<CSSValue> value = style->getPropertyCSSValue(CSSPropertyFontSize);
- if (value) {
- // Explicit font size overrides any delta.
- style->removeProperty(CSSPropertyWebkitFontSizeDelta);
- return;
- }
-
- // Get the adjustment amount out of the style.
- value = style->getPropertyCSSValue(CSSPropertyWebkitFontSizeDelta);
- if (!value)
- return;
- float adjustment = NoFontDelta;
- if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
- CSSPrimitiveValue *primitiveValue = static_cast<CSSPrimitiveValue *>(value.get());
- if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_PX) {
- // Only PX handled now. If we handle more types in the future, perhaps
- // a switch statement here would be more appropriate.
- adjustment = primitiveValue->getFloatValue();
- }
- }
- style->removeProperty(CSSPropertyWebkitFontSizeDelta);
- if (adjustment == NoFontDelta)
- return;
-
- Position start = startPosition();
- Position end = endPosition();
- if (Range::compareBoundaryPoints(end, start) < 0) {
- Position swap = start;
- start = end;
- end = swap;
- }
-
- // Join up any adjacent text nodes.
- if (start.node()->isTextNode()) {
- joinChildTextNodes(start.node()->parentNode(), start, end);
- start = startPosition();
- end = endPosition();
- }
- if (end.node()->isTextNode() && start.node()->parentNode() != end.node()->parentNode()) {
- joinChildTextNodes(end.node()->parentNode(), start, end);
- start = startPosition();
- end = endPosition();
- }
-
- // Split the start text nodes if needed to apply style.
- bool splitStart = splitTextAtStartIfNeeded(start, end);
- if (splitStart) {
- start = startPosition();
- end = endPosition();
- }
- bool splitEnd = splitTextAtEndIfNeeded(start, end);
- if (splitEnd) {
- start = startPosition();
- end = endPosition();
- }
-
- // Calculate loop end point.
- // If the end node is before the start node (can only happen if the end node is
- // an ancestor of the start node), we gather nodes up to the next sibling of the end node
- Node *beyondEnd;
- if (start.node()->isDescendantOf(end.node()))
- beyondEnd = end.node()->traverseNextSibling();
- else
- beyondEnd = end.node()->traverseNextNode();
-
- start = start.upstream(); // Move upstream to ensure we do not add redundant spans.
- Node *startNode = start.node();
- if (startNode->isTextNode() && start.offset() >= caretMaxOffset(startNode)) // Move out of text node if range does not include its characters.
- startNode = startNode->traverseNextNode();
-
- // Store away font size before making any changes to the document.
- // This ensures that changes to one node won't effect another.
- HashMap<Node*, float> startingFontSizes;
- for (Node *node = startNode; node != beyondEnd; node = node->traverseNextNode())
- startingFontSizes.set(node, computedFontSize(node));
-
- // These spans were added by us. If empty after font size changes, they can be removed.
- DeprecatedPtrList<Node> unstyledSpans;
-
- Node *lastStyledNode = 0;
- for (Node *node = startNode; node != beyondEnd; node = node->traverseNextNode()) {
- HTMLElement *elem = 0;
- if (node->isHTMLElement()) {
- // Only work on fully selected nodes.
- if (!nodeFullySelected(node, start, end))
- continue;
- elem = static_cast<HTMLElement *>(node);
- } else if (node->isTextNode() && node->renderer() && node->parentNode() != lastStyledNode) {
- // Last styled node was not parent node of this text node, but we wish to style this
- // text node. To make this possible, add a style span to surround this text node.
- RefPtr<HTMLElement> span = createStyleSpanElement(document());
- insertNodeBefore(span.get(), node);
- surroundNodeRangeWithElement(node, node, span.get());
- elem = span.get();
- } else {
- // Only handle HTML elements and text nodes.
- continue;
- }
- lastStyledNode = node;
-
- CSSMutableStyleDeclaration* inlineStyleDecl = elem->getInlineStyleDecl();
- float currentFontSize = computedFontSize(node);
- float desiredFontSize = max(MinimumFontSize, startingFontSizes.get(node) + adjustment);
- RefPtr<CSSValue> value = inlineStyleDecl->getPropertyCSSValue(CSSPropertyFontSize);
- if (value) {
- inlineStyleDecl->removeProperty(CSSPropertyFontSize, true);
- currentFontSize = computedFontSize(node);
- }
- if (currentFontSize != desiredFontSize) {
- inlineStyleDecl->setProperty(CSSPropertyFontSize, String::number(desiredFontSize) + "px", false, false);
- setNodeAttribute(elem, styleAttr, inlineStyleDecl->cssText());
- }
- if (inlineStyleDecl->length() == 0) {
- removeNodeAttribute(elem, styleAttr);
- if (isUnstyledStyleSpan(elem))
- unstyledSpans.append(elem);
- }
- }
-
- for (DeprecatedPtrListIterator<Node> it(unstyledSpans); it.current(); ++it)
- removeNodePreservingChildren(it.current());
-}
-
-#undef NoFontDelta
-#undef MinimumFontSize
-
-static Node* dummySpanAncestorForNode(const Node* node)
-{
- while (node && !isStyleSpan(node))
- node = node->parent();
-
- return node ? node->parent() : 0;
-}
-
-void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor)
-{
- if (!dummySpanAncestor)
- return;
-
- // Dummy spans are created when text node is split, so that style information
- // can be propagated, which can result in more splitting. If a dummy span gets
- // cloned/split, the new node is always a sibling of it. Therefore, we scan
- // all the children of the dummy's parent
- Node* next;
- for (Node* node = dummySpanAncestor->firstChild(); node; node = next) {
- next = node->nextSibling();
- if (isUnstyledStyleSpan(node))
- removeNodePreservingChildren(node);
- node = next;
- }
-}
-
-void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
-{
- Node* startDummySpanAncestor = 0;
- Node* endDummySpanAncestor = 0;
-
- // update document layout once before removing styles
- // so that we avoid the expense of updating before each and every call
- // to check a computed style
- updateLayout();
-
- // adjust to the positions we want to use for applying style
- Position start = startPosition();
- Position end = endPosition();
- if (Range::compareBoundaryPoints(end, start) < 0) {
- Position swap = start;
- start = end;
- end = swap;
- }
-
- // split the start node and containing element if the selection starts inside of it
- bool splitStart = splitTextElementAtStartIfNeeded(start, end);
- if (splitStart) {
- start = startPosition();
- end = endPosition();
- startDummySpanAncestor = dummySpanAncestorForNode(start.node());
- }
-
- // split the end node and containing element if the selection ends inside of it
- bool splitEnd = splitTextElementAtEndIfNeeded(start, end);
- if (splitEnd) {
- start = startPosition();
- end = endPosition();
- endDummySpanAncestor = dummySpanAncestorForNode(end.node());
- }
-
- // Remove style from the selection.
- // Use the upstream position of the start for removing style.
- // This will ensure we remove all traces of the relevant styles from the selection
- // and prevent us from adding redundant ones, as described in:
- // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
- removeInlineStyle(style, start.upstream(), end);
- start = startPosition();
- end = endPosition();
-
- if (splitStart) {
- bool mergedStart = mergeStartWithPreviousIfIdentical(start, end);
- if (mergedStart) {
- start = startPosition();
- end = endPosition();
- }
- }
-
- if (splitEnd) {
- mergeEndWithNextIfIdentical(start, end);
- start = startPosition();
- end = endPosition();
- }
-
- // update document layout once before running the rest of the function
- // so that we avoid the expense of updating before each and every call
- // to check a computed style
- updateLayout();
-
- Node* node = start.node();
-
- bool rangeIsEmpty = false;
-
- if (start.offset() >= caretMaxOffset(start.node())) {
- node = node->traverseNextNode();
- Position newStart = Position(node, 0);
- if (Range::compareBoundaryPoints(end, newStart) < 0)
- rangeIsEmpty = true;
- }
-
- if (!rangeIsEmpty) {
- // FIXME: Callers should perform this operation on a Range that includes the br
- // if they want style applied to the empty line.
- if (start == end && start.node()->hasTagName(brTag))
- end = positionAfterNode(start.node());
- // Add the style to selected inline runs.
- Node* pastLast = Range::create(document(), rangeCompliantEquivalent(start), rangeCompliantEquivalent(end))->pastLastNode();
- for (Node* next; node && node != pastLast; node = next) {
-
- next = node->traverseNextNode();
-
- if (!node->renderer() || !node->isContentEditable())
- continue;
-
- if (!node->isContentRichlyEditable() && node->isHTMLElement()) {
- // This is a plaintext-only region. Only proceed if it's fully selected.
- if (end.node()->isDescendantOf(node))
- break;
- // Add to this element's inline style and skip over its contents.
- HTMLElement* element = static_cast<HTMLElement*>(node);
- RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineStyleDecl()->copy();
- inlineStyle->merge(style);
- setNodeAttribute(element, styleAttr, inlineStyle->cssText());
- next = node->traverseNextSibling();
- continue;
- }
-
- if (isBlock(node))
- continue;
-
- if (node->childNodeCount()) {
- if (editingIgnoresContent(node)) {
- next = node->traverseNextSibling();
- continue;
- }
- continue;
- }
-
- Node* runStart = node;
- // Find the end of the run.
- Node* sibling = node->nextSibling();
- while (sibling && sibling != pastLast && (!sibling->isElementNode() || sibling->hasTagName(brTag)) && !isBlock(sibling)) {
- node = sibling;
- sibling = node->nextSibling();
- }
- // Recompute next, since node has changed.
- next = node->traverseNextNode();
- // Apply the style to the run.
- addInlineStyleIfNeeded(style, runStart, node);
- }
- }
-
- // Remove dummy style spans created by splitting text elements.
- cleanupUnstyledAppleStyleSpans(startDummySpanAncestor);
- if (endDummySpanAncestor != startDummySpanAncestor)
- cleanupUnstyledAppleStyleSpans(endDummySpanAncestor);
-}
-
-bool ApplyStyleCommand::isHTMLStyleNode(CSSMutableStyleDeclaration *style, HTMLElement *elem)
-{
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
- switch ((*it).id()) {
- case CSSPropertyFontWeight:
- if (elem->hasLocalName(bTag))
- return true;
- break;
- case CSSPropertyFontStyle:
- if (elem->hasLocalName(iTag))
- return true;
- }
- }
-
- return false;
-}
-
-void ApplyStyleCommand::removeHTMLStyleNode(HTMLElement *elem)
-{
- // This node can be removed.
- // EDIT FIXME: This does not handle the case where the node
- // has attributes. But how often do people add attributes to <B> tags?
- // Not so often I think.
- ASSERT(elem);
- removeNodePreservingChildren(elem);
-}
-
-void ApplyStyleCommand::removeHTMLFontStyle(CSSMutableStyleDeclaration *style, HTMLElement *elem)
-{
- ASSERT(style);
- ASSERT(elem);
-
- if (!elem->hasLocalName(fontTag))
- return;
-
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
- switch ((*it).id()) {
- case CSSPropertyColor:
- removeNodeAttribute(elem, colorAttr);
- break;
- case CSSPropertyFontFamily:
- removeNodeAttribute(elem, faceAttr);
- break;
- case CSSPropertyFontSize:
- removeNodeAttribute(elem, sizeAttr);
- break;
- }
- }
-
- if (isEmptyFontTag(elem))
- removeNodePreservingChildren(elem);
-}
-
-void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration *style, HTMLElement *elem)
-{
- ASSERT(style);
- ASSERT(elem);
-
- CSSMutableStyleDeclaration *decl = elem->inlineStyleDecl();
- if (!decl)
- return;
-
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
- int propertyID = (*it).id();
- RefPtr<CSSValue> value = decl->getPropertyCSSValue(propertyID);
- if (value && (propertyID != CSSPropertyWhiteSpace || !isTabSpanNode(elem)))
- removeCSSProperty(decl, propertyID);
- }
-
- if (isUnstyledStyleSpan(elem))
- removeNodePreservingChildren(elem);
-}
-
-void ApplyStyleCommand::removeBlockStyle(CSSMutableStyleDeclaration *style, const Position &start, const Position &end)
-{
- ASSERT(start.isNotNull());
- ASSERT(end.isNotNull());
- ASSERT(start.node()->inDocument());
- ASSERT(end.node()->inDocument());
- ASSERT(Range::compareBoundaryPoints(start, end) <= 0);
-
-}
-
-static bool hasTextDecorationProperty(Node *node)
-{
- if (!node->isElementNode())
- return false;
-
- RefPtr<CSSValue> value = computedStyle(node)->getPropertyCSSValue(CSSPropertyTextDecoration, DoNotUpdateLayout);
- return value && !equalIgnoringCase(value->cssText(), "none");
-}
-
-static Node* highestAncestorWithTextDecoration(Node *node)
-{
- Node *result = NULL;
-
- for (Node *n = node; n; n = n->parentNode()) {
- if (hasTextDecorationProperty(n))
- result = n;
- }
-
- return result;
-}
-
-PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractTextDecorationStyle(Node* node)
-{
- ASSERT(node);
- ASSERT(node->isElementNode());
-
- // non-html elements not handled yet
- if (!node->isHTMLElement())
- return 0;
-
- HTMLElement *element = static_cast<HTMLElement *>(node);
- RefPtr<CSSMutableStyleDeclaration> style = element->inlineStyleDecl();
- if (!style)
- return 0;
-
- int properties[1] = { CSSPropertyTextDecoration };
- RefPtr<CSSMutableStyleDeclaration> textDecorationStyle = style->copyPropertiesInSet(properties, 1);
-
- RefPtr<CSSValue> property = style->getPropertyCSSValue(CSSPropertyTextDecoration);
- if (property && !equalIgnoringCase(property->cssText(), "none"))
- removeCSSProperty(style.get(), CSSPropertyTextDecoration);
-
- return textDecorationStyle.release();
-}
-
-PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractAndNegateTextDecorationStyle(Node* node)
-{
- ASSERT(node);
- ASSERT(node->isElementNode());
-
- // non-html elements not handled yet
- if (!node->isHTMLElement())
- return 0;
-
- RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
- ASSERT(nodeStyle);
-
- int properties[1] = { CSSPropertyTextDecoration };
- RefPtr<CSSMutableStyleDeclaration> textDecorationStyle = nodeStyle->copyPropertiesInSet(properties, 1);
-
- RefPtr<CSSValue> property = nodeStyle->getPropertyCSSValue(CSSPropertyTextDecoration);
- if (property && !equalIgnoringCase(property->cssText(), "none")) {
- RefPtr<CSSMutableStyleDeclaration> newStyle = textDecorationStyle->copy();
- newStyle->setProperty(CSSPropertyTextDecoration, "none");
- applyTextDecorationStyle(node, newStyle.get());
- }
-
- return textDecorationStyle.release();
-}
-
-void ApplyStyleCommand::applyTextDecorationStyle(Node *node, CSSMutableStyleDeclaration *style)
-{
- ASSERT(node);
-
- if (!style || !style->cssText().length())
- return;
-
- if (node->isTextNode()) {
- RefPtr<HTMLElement> styleSpan = createStyleSpanElement(document());
- insertNodeBefore(styleSpan.get(), node);
- surroundNodeRangeWithElement(node, node, styleSpan.get());
- node = styleSpan.get();
- }
-
- if (!node->isElementNode())
- return;
-
- HTMLElement *element = static_cast<HTMLElement *>(node);
-
- StyleChange styleChange(style, Position(element, 0), StyleChange::styleModeForParseMode(document()->inCompatMode()));
- if (styleChange.cssStyle().length() > 0) {
- String cssText = styleChange.cssStyle();
- CSSMutableStyleDeclaration *decl = element->inlineStyleDecl();
- if (decl)
- cssText += decl->cssText();
- setNodeAttribute(element, styleAttr, cssText);
- }
-}
-
-void ApplyStyleCommand::pushDownTextDecorationStyleAroundNode(Node *node, const Position &start, const Position &end, bool force)
-{
- Node *highestAncestor = highestAncestorWithTextDecoration(node);
-
- if (highestAncestor) {
- Node *nextCurrent;
- Node *nextChild;
- for (Node *current = highestAncestor; current != node; current = nextCurrent) {
- ASSERT(current);
-
- nextCurrent = NULL;
-
- RefPtr<CSSMutableStyleDeclaration> decoration = force ? extractAndNegateTextDecorationStyle(current) : extractTextDecorationStyle(current);
-
- for (Node *child = current->firstChild(); child; child = nextChild) {
- nextChild = child->nextSibling();
-
- if (node == child) {
- nextCurrent = child;
- } else if (node->isDescendantOf(child)) {
- applyTextDecorationStyle(child, decoration.get());
- nextCurrent = child;
- } else {
- applyTextDecorationStyle(child, decoration.get());
- }
- }
- }
- }
-}
-
-void ApplyStyleCommand::pushDownTextDecorationStyleAtBoundaries(const Position &start, const Position &end)
-{
- // We need to work in two passes. First we push down any inline
- // styles that set text decoration. Then we look for any remaining
- // styles (caused by stylesheets) and explicitly negate text
- // decoration while pushing down.
-
- pushDownTextDecorationStyleAroundNode(start.node(), start, end, false);
- updateLayout();
- pushDownTextDecorationStyleAroundNode(start.node(), start, end, true);
-
- pushDownTextDecorationStyleAroundNode(end.node(), start, end, false);
- updateLayout();
- pushDownTextDecorationStyleAroundNode(end.node(), start, end, true);
-}
-
-static int maxRangeOffset(Node *n)
-{
- if (n->offsetInCharacters())
- return n->maxCharacterOffset();
-
- if (n->isElementNode())
- return n->childNodeCount();
-
- return 1;
-}
-
-void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration> style, const Position &start, const Position &end)
-{
- ASSERT(start.isNotNull());
- ASSERT(end.isNotNull());
- ASSERT(start.node()->inDocument());
- ASSERT(end.node()->inDocument());
- ASSERT(Range::compareBoundaryPoints(start, end) <= 0);
-
- RefPtr<CSSValue> textDecorationSpecialProperty = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
-
- if (textDecorationSpecialProperty) {
- pushDownTextDecorationStyleAtBoundaries(start.downstream(), end.upstream());
- style = style->copy();
- style->setProperty(CSSPropertyTextDecoration, textDecorationSpecialProperty->cssText(), style->getPropertyPriority(CSSPropertyWebkitTextDecorationsInEffect));
- }
-
- // The s and e variables store the positions used to set the ending selection after style removal
- // takes place. This will help callers to recognize when either the start node or the end node
- // are removed from the document during the work of this function.
- Position s = start;
- Position e = end;
-
- Node *node = start.node();
- while (node) {
- Node *next = node->traverseNextNode();
- if (node->isHTMLElement() && nodeFullySelected(node, start, end)) {
- HTMLElement *elem = static_cast<HTMLElement *>(node);
- Node *prev = elem->traversePreviousNodePostOrder();
- Node *next = elem->traverseNextNode();
- if (m_styledInlineElement && elem->hasTagName(m_styledInlineElement->tagQName()))
- removeNodePreservingChildren(elem);
- if (isHTMLStyleNode(style.get(), elem))
- removeHTMLStyleNode(elem);
- else {
- removeHTMLFontStyle(style.get(), elem);
- removeCSSStyle(style.get(), elem);
- }
- if (!elem->inDocument()) {
- if (s.node() == elem) {
- // Since elem must have been fully selected, and it is at the start
- // of the selection, it is clear we can set the new s offset to 0.
- ASSERT(s.offset() <= caretMinOffset(s.node()));
- s = Position(next, 0);
- }
- if (e.node() == elem) {
- // Since elem must have been fully selected, and it is at the end
- // of the selection, it is clear we can set the new e offset to
- // the max range offset of prev.
- ASSERT(e.offset() >= maxRangeOffset(e.node()));
- e = Position(prev, maxRangeOffset(prev));
- }
- }
- }
- if (node == end.node())
- break;
- node = next;
- }
-
- ASSERT(s.node()->inDocument());
- ASSERT(e.node()->inDocument());
- updateStartEnd(s, e);
-}
-
-bool ApplyStyleCommand::nodeFullySelected(Node *node, const Position &start, const Position &end) const
-{
- ASSERT(node);
- ASSERT(node->isElementNode());
-
- Position pos = Position(node, node->childNodeCount()).upstream();
- return Range::compareBoundaryPoints(node, 0, start.node(), start.offset()) >= 0 &&
- Range::compareBoundaryPoints(pos, end) <= 0;
-}
-
-bool ApplyStyleCommand::nodeFullyUnselected(Node *node, const Position &start, const Position &end) const
-{
- ASSERT(node);
- ASSERT(node->isElementNode());
-
- Position pos = Position(node, node->childNodeCount()).upstream();
- bool isFullyBeforeStart = Range::compareBoundaryPoints(pos, start) < 0;
- bool isFullyAfterEnd = Range::compareBoundaryPoints(node, 0, end.node(), end.offset()) > 0;
-
- return isFullyBeforeStart || isFullyAfterEnd;
-}
-
-
-bool ApplyStyleCommand::splitTextAtStartIfNeeded(const Position &start, const Position &end)
-{
- if (start.node()->isTextNode() && start.offset() > caretMinOffset(start.node()) && start.offset() < caretMaxOffset(start.node())) {
- int endOffsetAdjustment = start.node() == end.node() ? start.offset() : 0;
- Text *text = static_cast<Text *>(start.node());
- splitTextNode(text, start.offset());
- updateStartEnd(Position(start.node(), 0), Position(end.node(), end.offset() - endOffsetAdjustment));
- return true;
- }
- return false;
-}
-
-bool ApplyStyleCommand::splitTextAtEndIfNeeded(const Position &start, const Position &end)
-{
- if (end.node()->isTextNode() && end.offset() > caretMinOffset(end.node()) && end.offset() < caretMaxOffset(end.node())) {
- Text *text = static_cast<Text *>(end.node());
- splitTextNode(text, end.offset());
-
- Node *prevNode = text->previousSibling();
- ASSERT(prevNode);
- Node *startNode = start.node() == end.node() ? prevNode : start.node();
- ASSERT(startNode);
- updateStartEnd(Position(startNode, start.offset()), Position(prevNode, caretMaxOffset(prevNode)));
- return true;
- }
- return false;
-}
-
-bool ApplyStyleCommand::splitTextElementAtStartIfNeeded(const Position &start, const Position &end)
-{
- if (start.node()->isTextNode() && start.offset() > caretMinOffset(start.node()) && start.offset() < caretMaxOffset(start.node())) {
- int endOffsetAdjustment = start.node() == end.node() ? start.offset() : 0;
- Text *text = static_cast<Text *>(start.node());
- splitTextNodeContainingElement(text, start.offset());
-
- updateStartEnd(Position(start.node()->parentNode(), start.node()->nodeIndex()), Position(end.node(), end.offset() - endOffsetAdjustment));
- return true;
- }
- return false;
-}
-
-bool ApplyStyleCommand::splitTextElementAtEndIfNeeded(const Position &start, const Position &end)
-{
- if (end.node()->isTextNode() && end.offset() > caretMinOffset(end.node()) && end.offset() < caretMaxOffset(end.node())) {
- Text *text = static_cast<Text *>(end.node());
- splitTextNodeContainingElement(text, end.offset());
-
- Node *prevNode = text->parent()->previousSibling()->lastChild();
- ASSERT(prevNode);
- Node *startNode = start.node() == end.node() ? prevNode : start.node();
- ASSERT(startNode);
- updateStartEnd(Position(startNode, start.offset()), Position(prevNode->parent(), prevNode->nodeIndex() + 1));
- return true;
- }
- return false;
-}
-
-static bool areIdenticalElements(Node *first, Node *second)
-{
- // check that tag name and all attribute names and values are identical
-
- if (!first->isElementNode())
- return false;
-
- if (!second->isElementNode())
- return false;
-
- Element *firstElement = static_cast<Element *>(first);
- Element *secondElement = static_cast<Element *>(second);
-
- if (!firstElement->tagQName().matches(secondElement->tagQName()))
- return false;
-
- NamedAttrMap *firstMap = firstElement->attributes();
- NamedAttrMap *secondMap = secondElement->attributes();
-
- unsigned firstLength = firstMap->length();
-
- if (firstLength != secondMap->length())
- return false;
-
- for (unsigned i = 0; i < firstLength; i++) {
- Attribute *attribute = firstMap->attributeItem(i);
- Attribute *secondAttribute = secondMap->getAttributeItem(attribute->name());
-
- if (!secondAttribute || attribute->value() != secondAttribute->value())
- return false;
- }
-
- return true;
-}
-
-bool ApplyStyleCommand::mergeStartWithPreviousIfIdentical(const Position &start, const Position &end)
-{
- Node *startNode = start.node();
- int startOffset = start.offset();
-
- if (isAtomicNode(start.node())) {
- if (start.offset() != 0)
- return false;
-
- // note: prior siblings could be unrendered elements. it's silly to miss the
- // merge opportunity just for that.
- if (start.node()->previousSibling())
- return false;
-
- startNode = start.node()->parent();
- startOffset = 0;
- }
-
- if (!startNode->isElementNode())
- return false;
-
- if (startOffset != 0)
- return false;
-
- Node *previousSibling = startNode->previousSibling();
-
- if (previousSibling && areIdenticalElements(startNode, previousSibling)) {
- Element *previousElement = static_cast<Element *>(previousSibling);
- Element *element = static_cast<Element *>(startNode);
- Node *startChild = element->firstChild();
- ASSERT(startChild);
- mergeIdenticalElements(previousElement, element);
-
- int startOffsetAdjustment = startChild->nodeIndex();
- int endOffsetAdjustment = startNode == end.node() ? startOffsetAdjustment : 0;
- updateStartEnd(Position(startNode, startOffsetAdjustment), Position(end.node(), end.offset() + endOffsetAdjustment));
- return true;
- }
-
- return false;
-}
-
-bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position &start, const Position &end)
-{
- Node *endNode = end.node();
- int endOffset = end.offset();
-
- if (isAtomicNode(endNode)) {
- if (endOffset < caretMaxOffset(endNode))
- return false;
-
- unsigned parentLastOffset = end.node()->parent()->childNodes()->length() - 1;
- if (end.node()->nextSibling())
- return false;
-
- endNode = end.node()->parent();
- endOffset = parentLastOffset;
- }
-
- if (!endNode->isElementNode() || endNode->hasTagName(brTag))
- return false;
-
- Node *nextSibling = endNode->nextSibling();
-
- if (nextSibling && areIdenticalElements(endNode, nextSibling)) {
- Element *nextElement = static_cast<Element *>(nextSibling);
- Element *element = static_cast<Element *>(endNode);
- Node *nextChild = nextElement->firstChild();
-
- mergeIdenticalElements(element, nextElement);
-
- Node *startNode = start.node() == endNode ? nextElement : start.node();
- ASSERT(startNode);
-
- int endOffset = nextChild ? nextChild->nodeIndex() : nextElement->childNodes()->length();
- updateStartEnd(Position(startNode, start.offset()), Position(nextElement, endOffset));
- return true;
- }
-
- return false;
-}
-
-void ApplyStyleCommand::surroundNodeRangeWithElement(Node *startNode, Node *endNode, Element *element)
-{
- ASSERT(startNode);
- ASSERT(endNode);
- ASSERT(element);
-
- Node *node = startNode;
- while (1) {
- Node *next = node->traverseNextNode();
- if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) {
- removeNode(node);
- appendNode(node, element);
- }
- if (node == endNode)
- break;
- node = next;
- }
- // FIXME: We should probably call updateStartEnd if the start or end was in the node
- // range so that the endingSelection() is canonicalized. See the comments at the end of
- // Selection::validate().
-}
-
-void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElement* block)
-{
- // Do not check for legacy styles here. Those styles, like <B> and <I>, only apply for
- // inline content.
- if (!block)
- return;
-
- String cssText = styleChange.cssStyle();
- CSSMutableStyleDeclaration* decl = block->inlineStyleDecl();
- if (decl)
- cssText += decl->cssText();
- setNodeAttribute(block, styleAttr, cssText);
-}
-
-void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style, Node *startNode, Node *endNode)
-{
- if (m_removeOnly)
- return;
-
- StyleChange styleChange(style, Position(startNode, 0), StyleChange::styleModeForParseMode(document()->inCompatMode()));
- ExceptionCode ec = 0;
-
- //
- // Font tags need to go outside of CSS so that CSS font sizes override leagcy font sizes.
- //
- if (styleChange.applyFontColor() || styleChange.applyFontFace() || styleChange.applyFontSize()) {
- RefPtr<Element> fontElement = createFontElement(document());
- ASSERT(ec == 0);
- insertNodeBefore(fontElement.get(), startNode);
- if (styleChange.applyFontColor())
- fontElement->setAttribute(colorAttr, styleChange.fontColor());
- if (styleChange.applyFontFace())
- fontElement->setAttribute(faceAttr, styleChange.fontFace());
- if (styleChange.applyFontSize())
- fontElement->setAttribute(sizeAttr, styleChange.fontSize());
- surroundNodeRangeWithElement(startNode, endNode, fontElement.get());
- }
-
- if (styleChange.cssStyle().length() > 0) {
- RefPtr<Element> styleElement = createStyleSpanElement(document());
- styleElement->setAttribute(styleAttr, styleChange.cssStyle());
- insertNodeBefore(styleElement.get(), startNode);
- surroundNodeRangeWithElement(startNode, endNode, styleElement.get());
- }
-
- if (styleChange.applyBold()) {
- RefPtr<Element> boldElement = document()->createElementNS(xhtmlNamespaceURI, "b", ec);
- ASSERT(ec == 0);
- insertNodeBefore(boldElement.get(), startNode);
- surroundNodeRangeWithElement(startNode, endNode, boldElement.get());
- }
-
- if (styleChange.applyItalic()) {
- RefPtr<Element> italicElement = document()->createElementNS(xhtmlNamespaceURI, "i", ec);
- ASSERT(ec == 0);
- insertNodeBefore(italicElement.get(), startNode);
- surroundNodeRangeWithElement(startNode, endNode, italicElement.get());
- }
-
- if (m_styledInlineElement) {
- RefPtr<Element> clonedElement = static_pointer_cast<Element>(m_styledInlineElement->cloneNode(false));
- insertNodeBefore(clonedElement.get(), startNode);
- surroundNodeRangeWithElement(startNode, endNode, clonedElement.get());
- }
-}
-
-float ApplyStyleCommand::computedFontSize(const Node *node)
-{
- if (!node)
- return 0;
-
- Position pos(const_cast<Node *>(node), 0);
- RefPtr<CSSComputedStyleDeclaration> computedStyle = pos.computedStyle();
- if (!computedStyle)
- return 0;
-
- RefPtr<CSSPrimitiveValue> value = static_pointer_cast<CSSPrimitiveValue>(computedStyle->getPropertyCSSValue(CSSPropertyFontSize));
- if (!value)
- return 0;
-
- return value->getFloatValue(CSSPrimitiveValue::CSS_PX);
-}
-
-void ApplyStyleCommand::joinChildTextNodes(Node *node, const Position &start, const Position &end)
-{
- if (!node)
- return;
-
- Position newStart = start;
- Position newEnd = end;
-
- Node *child = node->firstChild();
- while (child) {
- Node *next = child->nextSibling();
- if (child->isTextNode() && next && next->isTextNode()) {
- Text *childText = static_cast<Text *>(child);
- Text *nextText = static_cast<Text *>(next);
- if (next == start.node())
- newStart = Position(childText, childText->length() + start.offset());
- if (next == end.node())
- newEnd = Position(childText, childText->length() + end.offset());
- String textToMove = nextText->data();
- insertTextIntoNode(childText, childText->length(), textToMove);
- removeNode(next);
- // don't move child node pointer. it may want to merge with more text nodes.
- }
- else {
- child = child->nextSibling();
- }
- }
-
- updateStartEnd(newStart, newEnd);
-}
-
-}
diff --git a/WebCore/editing/ApplyStyleCommand.h b/WebCore/editing/ApplyStyleCommand.h
deleted file mode 100644
index 8df76a0..0000000
--- a/WebCore/editing/ApplyStyleCommand.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ApplyStyleCommand_h
-#define ApplyStyleCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class HTMLElement;
-class StyleChange;
-
-class ApplyStyleCommand : public CompositeEditCommand {
-public:
- enum EPropertyLevel { PropertyDefault, ForceBlockProperties };
-
- static PassRefPtr<ApplyStyleCommand> create(Document* document, CSSStyleDeclaration* style, EditAction action = EditActionChangeAttributes, EPropertyLevel level = PropertyDefault)
- {
- return adoptRef(new ApplyStyleCommand(document, style, action, level));
- }
- static PassRefPtr<ApplyStyleCommand> create(Document* document, CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction action = EditActionChangeAttributes, EPropertyLevel level = PropertyDefault)
- {
- return adoptRef(new ApplyStyleCommand(document, style, start, end, action, level));
- }
- static PassRefPtr<ApplyStyleCommand> create(Element* element, bool removeOnly = false, EditAction action = EditActionChangeAttributes)
- {
- return adoptRef(new ApplyStyleCommand(element, removeOnly, action));
- }
-
-private:
- ApplyStyleCommand(Document*, CSSStyleDeclaration*, EditAction, EPropertyLevel);
- ApplyStyleCommand(Document*, CSSStyleDeclaration*, const Position& start, const Position& end, EditAction, EPropertyLevel);
- ApplyStyleCommand(Element*, bool removeOnly, EditAction);
-
- virtual void doApply();
- virtual EditAction editingAction() const;
-
- CSSMutableStyleDeclaration* style() const { return m_style.get(); }
-
- // style-removal helpers
- bool isHTMLStyleNode(CSSMutableStyleDeclaration*, HTMLElement*);
- void removeHTMLStyleNode(HTMLElement*);
- void removeHTMLFontStyle(CSSMutableStyleDeclaration*, HTMLElement*);
- void removeCSSStyle(CSSMutableStyleDeclaration*, HTMLElement*);
- void removeBlockStyle(CSSMutableStyleDeclaration*, const Position& start, const Position& end);
- void removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>, const Position& start, const Position& end);
- bool nodeFullySelected(Node*, const Position& start, const Position& end) const;
- bool nodeFullyUnselected(Node*, const Position& start, const Position& end) const;
- PassRefPtr<CSSMutableStyleDeclaration> extractTextDecorationStyle(Node*);
- PassRefPtr<CSSMutableStyleDeclaration> extractAndNegateTextDecorationStyle(Node*);
- void applyTextDecorationStyle(Node*, CSSMutableStyleDeclaration *style);
- void pushDownTextDecorationStyleAroundNode(Node*, const Position& start, const Position& end, bool force);
- void pushDownTextDecorationStyleAtBoundaries(const Position& start, const Position& end);
-
- // style-application helpers
- void applyBlockStyle(CSSMutableStyleDeclaration*);
- void applyRelativeFontStyleChange(CSSMutableStyleDeclaration*);
- void applyInlineStyle(CSSMutableStyleDeclaration*);
- void addBlockStyle(const StyleChange&, HTMLElement*);
- void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, Node* start, Node* end);
- bool splitTextAtStartIfNeeded(const Position& start, const Position& end);
- bool splitTextAtEndIfNeeded(const Position& start, const Position& end);
- bool splitTextElementAtStartIfNeeded(const Position& start, const Position& end);
- bool splitTextElementAtEndIfNeeded(const Position& start, const Position& end);
- bool mergeStartWithPreviousIfIdentical(const Position& start, const Position& end);
- bool mergeEndWithNextIfIdentical(const Position& start, const Position& end);
- void cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor);
-
- void surroundNodeRangeWithElement(Node* start, Node* end, Element* element);
- float computedFontSize(const Node*);
- void joinChildTextNodes(Node*, const Position& start, const Position& end);
-
- void updateStartEnd(const Position& newStart, const Position& newEnd);
- Position startPosition();
- Position endPosition();
-
- RefPtr<CSSMutableStyleDeclaration> m_style;
- EditAction m_editingAction;
- EPropertyLevel m_propertyLevel;
- Position m_start;
- Position m_end;
- bool m_useEndingSelection;
- RefPtr<Element> m_styledInlineElement;
- bool m_removeOnly;
-};
-
-bool isStyleSpan(const Node*);
-PassRefPtr<HTMLElement> createStyleSpanElement(Document*);
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/editing/BreakBlockquoteCommand.cpp b/WebCore/editing/BreakBlockquoteCommand.cpp
deleted file mode 100644
index a172953..0000000
--- a/WebCore/editing/BreakBlockquoteCommand.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "BreakBlockquoteCommand.h"
-
-#include "Element.h"
-#include "HTMLNames.h"
-#include "Text.h"
-#include "VisiblePosition.h"
-#include "htmlediting.h"
-#include "RenderListItem.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-BreakBlockquoteCommand::BreakBlockquoteCommand(Document *document)
- : CompositeEditCommand(document)
-{
-}
-
-void BreakBlockquoteCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- // Delete the current selection.
- if (endingSelection().isRange())
- deleteSelection(false, false);
-
- VisiblePosition visiblePos = endingSelection().visibleStart();
- // pos is a position equivalent to the caret. We use downstream() so that pos will
- // be in the first node that we need to move (there are a few exceptions to this, see below).
- Position pos = endingSelection().start().downstream();
-
- // startNode is the first node that we need to move to the new blockquote.
- Node* startNode = pos.node();
- // Find the top-most blockquote from the start.
- Node* topBlockquote = 0;
- for (Node *node = startNode->parentNode(); node; node = node->parentNode()) {
- if (isMailBlockquote(node))
- topBlockquote = node;
- }
- if (!topBlockquote || !topBlockquote->parentNode())
- return;
-
- // Insert a break after the top blockquote.
- RefPtr<Element> breakNode = createBreakElement(document());
- insertNodeAfter(breakNode.get(), topBlockquote);
-
- if (isLastVisiblePositionInNode(visiblePos, topBlockquote)) {
- setEndingSelection(Selection(Position(breakNode.get(), 0), DOWNSTREAM));
- rebalanceWhitespace();
- return;
- }
-
- // Don't move a line break just after the caret. Doing so would create an extra, empty paragraph
- // in the new blockquote.
- if (lineBreakExistsAtPosition(visiblePos))
- pos = pos.next();
-
- // Split at pos if in the middle of a text node.
- if (startNode->isTextNode()) {
- Text* textNode = static_cast<Text*>(startNode);
- if ((unsigned)pos.offset() >= textNode->length()) {
- startNode = startNode->traverseNextNode();
- ASSERT(startNode);
- } else if (pos.offset() > 0)
- splitTextNode(textNode, pos.offset());
- } else if (pos.offset() > 0) {
- startNode = startNode->traverseNextNode();
- ASSERT(startNode);
- }
-
- // If there's nothing inside topBlockquote to move, we're finished.
- if (!startNode->isDescendantOf(topBlockquote)) {
- setEndingSelection(Selection(VisiblePosition(Position(startNode, 0))));
- return;
- }
-
- // Build up list of ancestors in between the start node and the top blockquote.
- Vector<Node*> ancestors;
- for (Node* node = startNode->parentNode(); node != topBlockquote; node = node->parentNode())
- ancestors.append(node);
-
- // Insert a clone of the top blockquote after the break.
- RefPtr<Node> clonedBlockquote = topBlockquote->cloneNode(false);
- insertNodeAfter(clonedBlockquote.get(), breakNode.get());
-
- // Clone startNode's ancestors into the cloned blockquote.
- // On exiting this loop, clonedAncestor is the lowest ancestor
- // that was cloned (i.e. the clone of either ancestors.last()
- // or clonedBlockquote if ancestors is empty).
- RefPtr<Node> clonedAncestor = clonedBlockquote;
- for (size_t i = ancestors.size(); i != 0; --i) {
- RefPtr<Node> clonedChild = ancestors[i - 1]->cloneNode(false); // shallow clone
- // Preserve list item numbering in cloned lists.
- if (clonedChild->isElementNode() && clonedChild->hasTagName(olTag)) {
- Node* listChildNode = i > 1 ? ancestors[i - 2] : startNode;
- // The first child of the cloned list might not be a list item element,
- // find the first one so that we know where to start numbering.
- while (listChildNode && !listChildNode->hasTagName(liTag))
- listChildNode = listChildNode->nextSibling();
- if (listChildNode && listChildNode->renderer())
- setNodeAttribute(static_cast<Element*>(clonedChild.get()), startAttr, String::number(static_cast<RenderListItem*>(listChildNode->renderer())->value()));
- }
-
- appendNode(clonedChild.get(), clonedAncestor.get());
- clonedAncestor = clonedChild;
- }
-
- // Move the startNode and its siblings.
- Node *moveNode = startNode;
- while (moveNode) {
- Node *next = moveNode->nextSibling();
- removeNode(moveNode);
- appendNode(moveNode, clonedAncestor.get());
- moveNode = next;
- }
-
- // Hold open startNode's original parent if we emptied it
- if (!ancestors.isEmpty()) {
- addBlockPlaceholderIfNeeded(ancestors.first());
-
- // Split the tree up the ancestor chain until the topBlockquote
- // Throughout this loop, clonedParent is the clone of ancestor's parent.
- // This is so we can clone ancestor's siblings and place the clones
- // into the clone corresponding to the ancestor's parent.
- Node* ancestor;
- Node* clonedParent;
- for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentNode();
- ancestor && ancestor != topBlockquote;
- ancestor = ancestor->parentNode(), clonedParent = clonedParent->parentNode()) {
- moveNode = ancestor->nextSibling();
- while (moveNode) {
- Node *next = moveNode->nextSibling();
- removeNode(moveNode);
- appendNode(moveNode, clonedParent);
- moveNode = next;
- }
- }
- }
-
- // Make sure the cloned block quote renders.
- addBlockPlaceholderIfNeeded(clonedBlockquote.get());
-
- // Put the selection right before the break.
- setEndingSelection(Selection(Position(breakNode.get(), 0), DOWNSTREAM));
- rebalanceWhitespace();
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/BreakBlockquoteCommand.h b/WebCore/editing/BreakBlockquoteCommand.h
deleted file mode 100644
index 885e5d6..0000000
--- a/WebCore/editing/BreakBlockquoteCommand.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BreakBlockquoteCommand_h
-#define BreakBlockquoteCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class BreakBlockquoteCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<BreakBlockquoteCommand> create(Document* document)
- {
- return adoptRef(new BreakBlockquoteCommand(document));
- }
-
-private:
- BreakBlockquoteCommand(Document*);
- virtual void doApply();
-};
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/editing/CompositeEditCommand.cpp b/WebCore/editing/CompositeEditCommand.cpp
deleted file mode 100644
index 3700023..0000000
--- a/WebCore/editing/CompositeEditCommand.cpp
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "CompositeEditCommand.h"
-
-#include "AppendNodeCommand.h"
-#include "ApplyStyleCommand.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "CharacterNames.h"
-#include "DeleteFromTextNodeCommand.h"
-#include "DeleteSelectionCommand.h"
-#include "Document.h"
-#include "DocumentFragment.h"
-#include "EditorInsertAction.h"
-#include "Element.h"
-#include "HTMLNames.h"
-#include "InlineTextBox.h"
-#include "InsertIntoTextNodeCommand.h"
-#include "InsertLineBreakCommand.h"
-#include "InsertNodeBeforeCommand.h"
-#include "InsertParagraphSeparatorCommand.h"
-#include "InsertTextCommand.h"
-#include "JoinTextNodesCommand.h"
-#include "MergeIdenticalElementsCommand.h"
-#include "Range.h"
-#include "RemoveCSSPropertyCommand.h"
-#include "RemoveNodeAttributeCommand.h"
-#include "RemoveNodeCommand.h"
-#include "RemoveNodePreservingChildrenCommand.h"
-#include "ReplaceSelectionCommand.h"
-#include "SetNodeAttributeCommand.h"
-#include "SplitElementCommand.h"
-#include "SplitTextNodeCommand.h"
-#include "SplitTextNodeContainingElementCommand.h"
-#include "Text.h"
-#include "TextIterator.h"
-#include "WrapContentsInDummySpanCommand.h"
-#include "htmlediting.h"
-#include "markup.h"
-#include "visible_units.h"
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-CompositeEditCommand::CompositeEditCommand(Document *document)
- : EditCommand(document)
-{
-}
-
-void CompositeEditCommand::doUnapply()
-{
- size_t size = m_commands.size();
- for (size_t i = size; i != 0; --i)
- m_commands[i - 1]->unapply();
-}
-
-void CompositeEditCommand::doReapply()
-{
- size_t size = m_commands.size();
- for (size_t i = 0; i != size; ++i)
- m_commands[i]->reapply();
-}
-
-//
-// sugary-sweet convenience functions to help create and apply edit commands in composite commands
-//
-void CompositeEditCommand::applyCommandToComposite(PassRefPtr<EditCommand> cmd)
-{
- cmd->setParent(this);
- cmd->apply();
- m_commands.append(cmd);
-}
-
-void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
-{
- applyCommandToComposite(ApplyStyleCommand::create(document(), style, editingAction));
-}
-
-void CompositeEditCommand::applyStyle(CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction)
-{
- applyCommandToComposite(ApplyStyleCommand::create(document(), style, start, end, editingAction));
-}
-
-void CompositeEditCommand::applyStyledElement(Element* element)
-{
- applyCommandToComposite(ApplyStyleCommand::create(element, false));
-}
-
-void CompositeEditCommand::removeStyledElement(Element* element)
-{
- applyCommandToComposite(ApplyStyleCommand::create(element, true));
-}
-
-void CompositeEditCommand::insertParagraphSeparator(bool useDefaultParagraphElement)
-{
- applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), useDefaultParagraphElement));
-}
-
-void CompositeEditCommand::insertLineBreak()
-{
- applyCommandToComposite(InsertLineBreakCommand::create(document()));
-}
-
-void CompositeEditCommand::insertNodeBefore(Node* insertChild, Node* refChild)
-{
- ASSERT(!refChild->hasTagName(bodyTag));
- applyCommandToComposite(InsertNodeBeforeCommand::create(insertChild, refChild));
-}
-
-void CompositeEditCommand::insertNodeAfter(Node* insertChild, Node* refChild)
-{
- ASSERT(!refChild->hasTagName(bodyTag));
- if (refChild->parentNode()->lastChild() == refChild)
- appendNode(insertChild, refChild->parentNode());
- else {
- ASSERT(refChild->nextSibling());
- insertNodeBefore(insertChild, refChild->nextSibling());
- }
-}
-
-void CompositeEditCommand::insertNodeAt(Node* insertChild, const Position& editingPosition)
-{
- ASSERT(isEditablePosition(editingPosition));
- // For editing positions like [table, 0], insert before the table,
- // likewise for replaced elements, brs, etc.
- Position p = rangeCompliantEquivalent(editingPosition);
- Node* refChild = p.node();
- int offset = p.offset();
-
- if (canHaveChildrenForEditing(refChild)) {
- Node* child = refChild->firstChild();
- for (int i = 0; child && i < offset; i++)
- child = child->nextSibling();
- if (child)
- insertNodeBefore(insertChild, child);
- else
- appendNode(insertChild, refChild);
- } else if (caretMinOffset(refChild) >= offset) {
- insertNodeBefore(insertChild, refChild);
- } else if (refChild->isTextNode() && caretMaxOffset(refChild) > offset) {
- splitTextNode(static_cast<Text *>(refChild), offset);
- insertNodeBefore(insertChild, refChild);
- } else {
- insertNodeAfter(insertChild, refChild);
- }
-}
-
-void CompositeEditCommand::appendNode(Node* newChild, Node* parent)
-{
- ASSERT(canHaveChildrenForEditing(parent));
- applyCommandToComposite(AppendNodeCommand::create(parent, newChild));
-}
-
-void CompositeEditCommand::removeChildrenInRange(Node* node, int from, int to)
-{
- Node* nodeToRemove = node->childNode(from);
- for (int i = from; i < to; i++) {
- ASSERT(nodeToRemove);
- Node* next = nodeToRemove->nextSibling();
- removeNode(nodeToRemove);
- nodeToRemove = next;
- }
-}
-
-void CompositeEditCommand::removeNode(Node* removeChild)
-{
- applyCommandToComposite(RemoveNodeCommand::create(removeChild));
-}
-
-void CompositeEditCommand::removeNodePreservingChildren(Node* removeChild)
-{
- applyCommandToComposite(RemoveNodePreservingChildrenCommand::create(removeChild));
-}
-
-void CompositeEditCommand::removeNodeAndPruneAncestors(Node* node)
-{
- RefPtr<Node> parent = node->parentNode();
- removeNode(node);
- prune(parent);
-}
-
-static bool hasARenderedDescendant(Node* node)
-{
- Node* n = node->firstChild();
- while (n) {
- if (n->renderer())
- return true;
- n = n->traverseNextNode(node);
- }
- return false;
-}
-
-void CompositeEditCommand::prune(PassRefPtr<Node> node)
-{
- while (node) {
- // If you change this rule you may have to add an updateLayout() here.
- RenderObject* renderer = node->renderer();
- if (renderer && (!renderer->canHaveChildren() || hasARenderedDescendant(node.get()) || node->rootEditableElement() == node))
- return;
-
- RefPtr<Node> next = node->parentNode();
- removeNode(node.get());
- node = next;
- }
-}
-
-void CompositeEditCommand::splitTextNode(Text *text, int offset)
-{
- applyCommandToComposite(SplitTextNodeCommand::create(text, offset));
-}
-
-void CompositeEditCommand::splitElement(Element* element, Node* atChild)
-{
- applyCommandToComposite(SplitElementCommand::create(element, atChild));
-}
-
-void CompositeEditCommand::mergeIdenticalElements(Element* first, Element* second)
-{
- ASSERT(!first->isDescendantOf(second) && second != first);
- if (first->nextSibling() != second) {
- removeNode(second);
- insertNodeAfter(second, first);
- }
- applyCommandToComposite(MergeIdenticalElementsCommand::create(first, second));
-}
-
-void CompositeEditCommand::wrapContentsInDummySpan(Element* element)
-{
- applyCommandToComposite(WrapContentsInDummySpanCommand::create(element));
-}
-
-void CompositeEditCommand::splitTextNodeContainingElement(Text *text, int offset)
-{
- applyCommandToComposite(SplitTextNodeContainingElementCommand::create(text, offset));
-}
-
-void CompositeEditCommand::joinTextNodes(Text *text1, Text *text2)
-{
- applyCommandToComposite(JoinTextNodesCommand::create(text1, text2));
-}
-
-void CompositeEditCommand::inputText(const String &text, bool selectInsertedText)
-{
- int offset = 0;
- int length = text.length();
- RefPtr<Range> startRange = Range::create(document(), Position(document()->documentElement(), 0), endingSelection().start());
- int startIndex = TextIterator::rangeLength(startRange.get());
- int newline;
- do {
- newline = text.find('\n', offset);
- if (newline != offset) {
- RefPtr<InsertTextCommand> command = InsertTextCommand::create(document());
- applyCommandToComposite(command);
- int substringLength = newline == -1 ? length - offset : newline - offset;
- command->input(text.substring(offset, substringLength), false);
- }
- if (newline != -1)
- insertLineBreak();
-
- offset = newline + 1;
- } while (newline != -1 && offset != length);
-
- if (selectInsertedText) {
- RefPtr<Range> selectedRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, length);
- setEndingSelection(Selection(selectedRange.get()));
- }
-}
-
-void CompositeEditCommand::insertTextIntoNode(Text *node, int offset, const String &text)
-{
- applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, text));
-}
-
-void CompositeEditCommand::deleteTextFromNode(Text *node, int offset, int count)
-{
- applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));
-}
-
-void CompositeEditCommand::replaceTextInNode(Text *node, int offset, int count, const String &replacementText)
-{
- applyCommandToComposite(DeleteFromTextNodeCommand::create(node, offset, count));
- applyCommandToComposite(InsertIntoTextNodeCommand::create(node, offset, replacementText));
-}
-
-Position CompositeEditCommand::positionOutsideTabSpan(const Position& pos)
-{
- if (!isTabSpanTextNode(pos.node()))
- return pos;
-
- Node* tabSpan = tabSpanNode(pos.node());
-
- if (pos.offset() <= caretMinOffset(pos.node()))
- return positionBeforeNode(tabSpan);
-
- if (pos.offset() >= caretMaxOffset(pos.node()))
- return positionAfterNode(tabSpan);
-
- splitTextNodeContainingElement(static_cast<Text *>(pos.node()), pos.offset());
- return positionBeforeNode(tabSpan);
-}
-
-void CompositeEditCommand::insertNodeAtTabSpanPosition(Node* node, const Position& pos)
-{
- // insert node before, after, or at split of tab span
- Position insertPos = positionOutsideTabSpan(pos);
- insertNodeAt(node, insertPos);
-}
-
-void CompositeEditCommand::deleteSelection(bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
-{
- if (endingSelection().isRange())
- applyCommandToComposite(DeleteSelectionCommand::create(document(), smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
-}
-
-void CompositeEditCommand::deleteSelection(const Selection &selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
-{
- if (selection.isRange())
- applyCommandToComposite(DeleteSelectionCommand::create(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
-}
-
-void CompositeEditCommand::removeCSSProperty(CSSStyleDeclaration *decl, int property)
-{
- applyCommandToComposite(RemoveCSSPropertyCommand::create(document(), decl, property));
-}
-
-void CompositeEditCommand::removeNodeAttribute(Element* element, const QualifiedName& attribute)
-{
- if (element->getAttribute(attribute).isNull())
- return;
- applyCommandToComposite(RemoveNodeAttributeCommand::create(element, attribute));
-}
-
-void CompositeEditCommand::setNodeAttribute(Element* element, const QualifiedName& attribute, const String &value)
-{
- applyCommandToComposite(SetNodeAttributeCommand::create(element, attribute, value));
-}
-
-static inline bool isWhitespace(UChar c)
-{
- return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
-}
-
-// FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
-void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
-{
- Node* node = position.node();
- if (!node || !node->isTextNode())
- return;
- Text* textNode = static_cast<Text*>(node);
-
- if (textNode->length() == 0)
- return;
- RenderObject* renderer = textNode->renderer();
- if (renderer && !renderer->style()->collapseWhiteSpace())
- return;
-
- String text = textNode->data();
- ASSERT(!text.isEmpty());
-
- int offset = position.offset();
- // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
- if (!isWhitespace(text[offset])) {
- offset--;
- if (offset < 0 || !isWhitespace(text[offset]))
- return;
- }
-
- // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
- int upstream = offset;
- while (upstream > 0 && isWhitespace(text[upstream - 1]))
- upstream--;
-
- int downstream = offset;
- while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
- downstream++;
-
- int length = downstream - upstream + 1;
- ASSERT(length > 0);
-
- VisiblePosition visibleUpstreamPos(Position(position.node(), upstream));
- VisiblePosition visibleDownstreamPos(Position(position.node(), downstream + 1));
-
- String string = text.substring(upstream, length);
- String rebalancedString = stringWithRebalancedWhitespace(string,
- // FIXME: Because of the problem mentioned at the top of this function, we must also use nbsps at the start/end of the string because
- // this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
- isStartOfParagraph(visibleUpstreamPos) || upstream == 0,
- isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);
-
- if (string != rebalancedString)
- replaceTextInNode(textNode, upstream, length, rebalancedString);
-}
-
-void CompositeEditCommand::prepareWhitespaceAtPositionForSplit(Position& position)
-{
- Node* node = position.node();
- if (!node || !node->isTextNode())
- return;
- Text* textNode = static_cast<Text*>(node);
-
- if (textNode->length() == 0)
- return;
- RenderObject* renderer = textNode->renderer();
- if (renderer && !renderer->style()->collapseWhiteSpace())
- return;
-
- // Delete collapsed whitespace so that inserting nbsps doesn't uncollapse it.
- Position upstreamPos = position.upstream();
- deleteInsignificantText(position.upstream(), position.downstream());
- position = upstreamPos.downstream();
-
- VisiblePosition visiblePos(position);
- VisiblePosition previousVisiblePos(visiblePos.previous());
- Position previous(previousVisiblePos.deepEquivalent());
-
- if (isCollapsibleWhitespace(previousVisiblePos.characterAfter()) && previous.node()->isTextNode() && !previous.node()->hasTagName(brTag))
- replaceTextInNode(static_cast<Text*>(previous.node()), previous.offset(), 1, nonBreakingSpaceString());
- if (isCollapsibleWhitespace(visiblePos.characterAfter()) && position.node()->isTextNode() && !position.node()->hasTagName(brTag))
- replaceTextInNode(static_cast<Text*>(position.node()), position.offset(), 1, nonBreakingSpaceString());
-}
-
-void CompositeEditCommand::rebalanceWhitespace()
-{
- Selection selection = endingSelection();
- if (selection.isNone())
- return;
-
- rebalanceWhitespaceAt(selection.start());
- if (selection.isRange())
- rebalanceWhitespaceAt(selection.end());
-}
-
-void CompositeEditCommand::deleteInsignificantText(Text* textNode, int start, int end)
-{
- if (!textNode || !textNode->renderer() || start >= end)
- return;
-
- RenderText* textRenderer = static_cast<RenderText*>(textNode->renderer());
- InlineTextBox* box = textRenderer->firstTextBox();
- if (!box) {
- // whole text node is empty
- removeNode(textNode);
- return;
- }
-
- int length = textNode->length();
- if (start >= length || end > length)
- return;
-
- int removed = 0;
- InlineTextBox* prevBox = 0;
- String str;
-
- // This loop structure works to process all gaps preceding a box,
- // and also will look at the gap after the last box.
- while (prevBox || box) {
- int gapStart = prevBox ? prevBox->m_start + prevBox->m_len : 0;
- if (end < gapStart)
- // No more chance for any intersections
- break;
-
- int gapEnd = box ? box->m_start : length;
- bool indicesIntersect = start <= gapEnd && end >= gapStart;
- int gapLen = gapEnd - gapStart;
- if (indicesIntersect && gapLen > 0) {
- gapStart = max(gapStart, start);
- gapEnd = min(gapEnd, end);
- if (str.isNull())
- str = textNode->string()->substring(start, end - start);
- // remove text in the gap
- str.remove(gapStart - start - removed, gapLen);
- removed += gapLen;
- }
-
- prevBox = box;
- if (box)
- box = box->nextTextBox();
- }
-
- if (!str.isNull()) {
- // Replace the text between start and end with our pruned version.
- if (!str.isEmpty())
- replaceTextInNode(textNode, start, end - start, str);
- else {
- // Assert that we are not going to delete all of the text in the node.
- // If we were, that should have been done above with the call to
- // removeNode and return.
- ASSERT(start > 0 || (unsigned)end - start < textNode->length());
- deleteTextFromNode(textNode, start, end - start);
- }
- }
-}
-
-void CompositeEditCommand::deleteInsignificantText(const Position& start, const Position& end)
-{
- if (start.isNull() || end.isNull())
- return;
-
- if (Range::compareBoundaryPoints(start, end) >= 0)
- return;
-
- Node* next;
- for (Node* node = start.node(); node; node = next) {
- next = node->traverseNextNode();
- if (node->isTextNode()) {
- Text* textNode = static_cast<Text*>(node);
- int startOffset = node == start.node() ? start.offset() : 0;
- int endOffset = node == end.node() ? end.offset() : textNode->length();
- deleteInsignificantText(textNode, startOffset, endOffset);
- }
- if (node == end.node())
- break;
- }
-}
-
-void CompositeEditCommand::deleteInsignificantTextDownstream(const Position& pos)
-{
- Position end = VisiblePosition(pos, VP_DEFAULT_AFFINITY).next().deepEquivalent().downstream();
- deleteInsignificantText(pos, end);
-}
-
-PassRefPtr<Node> CompositeEditCommand::appendBlockPlaceholder(Node* node)
-{
- if (!node)
- return 0;
-
- // Should assert isBlockFlow || isInlineFlow when deletion improves. See 4244964.
- ASSERT(node->renderer());
-
- RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
- appendNode(placeholder.get(), node);
- return placeholder.release();
-}
-
-PassRefPtr<Node> CompositeEditCommand::insertBlockPlaceholder(const Position& pos)
-{
- if (pos.isNull())
- return 0;
-
- // Should assert isBlockFlow || isInlineFlow when deletion improves. See 4244964.
- ASSERT(pos.node()->renderer());
-
- RefPtr<Node> placeholder = createBlockPlaceholderElement(document());
- insertNodeAt(placeholder.get(), pos);
- return placeholder.release();
-}
-
-PassRefPtr<Node> CompositeEditCommand::addBlockPlaceholderIfNeeded(Node* node)
-{
- if (!node)
- return 0;
-
- updateLayout();
-
- RenderObject *renderer = node->renderer();
- if (!renderer || !renderer->isBlockFlow())
- return 0;
-
- // append the placeholder to make sure it follows
- // any unrendered blocks
- if (renderer->height() == 0 || (renderer->isListItem() && renderer->isEmpty()))
- return appendBlockPlaceholder(node);
-
- return 0;
-}
-
-// Removes '\n's and brs that will collapse when content is inserted just before them.
-// FIXME: We shouldn't really have to remove placeholders, but removing them is a workaround for 9661.
-void CompositeEditCommand::removePlaceholderAt(const VisiblePosition& visiblePosition)
-{
- if (visiblePosition.isNull())
- return;
-
- Position p = visiblePosition.deepEquivalent().downstream();
- // If a br or '\n' is at the end of a block and not at the start of a paragraph,
- // then it is superfluous, so adding content before a br or '\n' that is at
- // the start of a paragraph will render it superfluous.
- // FIXME: This doesn't remove placeholders at the end of anonymous blocks.
- if (isEndOfBlock(visiblePosition) && isStartOfParagraph(visiblePosition)) {
- if (p.node()->hasTagName(brTag) && p.offset() == 0)
- removeNode(p.node());
- else if (lineBreakExistsAtPosition(visiblePosition))
- deleteTextFromNode(static_cast<Text*>(p.node()), p.offset(), 1);
- }
-}
-
-PassRefPtr<Node> CompositeEditCommand::moveParagraphContentsToNewBlockIfNecessary(const Position& pos)
-{
- if (pos.isNull())
- return 0;
-
- updateLayout();
-
- VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
- VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
- VisiblePosition visibleParagraphEnd = endOfParagraph(visiblePos);
- VisiblePosition next = visibleParagraphEnd.next();
- VisiblePosition visibleEnd = next.isNotNull() ? next : visibleParagraphEnd;
-
- Position paragraphStart = visibleParagraphStart.deepEquivalent().upstream();
- Position end = visibleEnd.deepEquivalent().upstream();
-
- // If there are no VisiblePositions in the same block as pos then
- // paragraphStart will be outside the paragraph
- if (Range::compareBoundaryPoints(pos, paragraphStart) < 0)
- return 0;
-
- // Perform some checks to see if we need to perform work in this function.
- if (isBlock(paragraphStart.node())) {
- if (isBlock(end.node())) {
- if (!end.node()->isDescendantOf(paragraphStart.node())) {
- // If the paragraph end is a descendant of paragraph start, then we need to run
- // the rest of this function. If not, we can bail here.
- return 0;
- }
- }
- else if (enclosingBlock(end.node()) != paragraphStart.node()) {
- // The visibleEnd. It must be an ancestor of the paragraph start.
- // We can bail as we have a full block to work with.
- ASSERT(paragraphStart.node()->isDescendantOf(enclosingBlock(end.node())));
- return 0;
- }
- else if (isEndOfDocument(visibleEnd)) {
- // At the end of the document. We can bail here as well.
- return 0;
- }
- }
-
- RefPtr<Node> newBlock = createDefaultParagraphElement(document());
- appendNode(createBreakElement(document()).get(), newBlock.get());
- insertNodeAt(newBlock.get(), paragraphStart);
-
- moveParagraphs(visibleParagraphStart, visibleParagraphEnd, VisiblePosition(Position(newBlock.get(), 0)));
-
- return newBlock.get();
-}
-
-void CompositeEditCommand::pushAnchorElementDown(Node* anchorNode)
-{
- if (!anchorNode)
- return;
-
- ASSERT(anchorNode->isLink());
-
- setEndingSelection(Selection::selectionFromContentsOfNode(anchorNode));
- applyStyledElement(static_cast<Element*>(anchorNode));
- // Clones of anchorNode have been pushed down, now remove it.
- if (anchorNode->inDocument())
- removeNodePreservingChildren(anchorNode);
-}
-
-// We must push partially selected anchors down before creating or removing
-// links from a selection to create fully selected chunks that can be removed.
-// ApplyStyleCommand doesn't do this for us because styles can be nested.
-// Anchors cannot be nested.
-void CompositeEditCommand::pushPartiallySelectedAnchorElementsDown()
-{
- Selection originalSelection = endingSelection();
- VisiblePosition visibleStart(originalSelection.start());
- VisiblePosition visibleEnd(originalSelection.end());
-
- Node* startAnchor = enclosingAnchorElement(originalSelection.start());
- VisiblePosition startOfStartAnchor(Position(startAnchor, 0));
- if (startAnchor && startOfStartAnchor != visibleStart)
- pushAnchorElementDown(startAnchor);
-
- Node* endAnchor = enclosingAnchorElement(originalSelection.end());
- VisiblePosition endOfEndAnchor(Position(endAnchor, 0));
- if (endAnchor && endOfEndAnchor != visibleEnd)
- pushAnchorElementDown(endAnchor);
-
- ASSERT(originalSelection.start().node()->inDocument() && originalSelection.end().node()->inDocument());
- setEndingSelection(originalSelection);
-}
-
-// This moves a paragraph preserving its style.
-void CompositeEditCommand::moveParagraph(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
-{
- ASSERT(isStartOfParagraph(startOfParagraphToMove));
- ASSERT(isEndOfParagraph(endOfParagraphToMove));
- moveParagraphs(startOfParagraphToMove, endOfParagraphToMove, destination, preserveSelection, preserveStyle);
-}
-
-void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, const VisiblePosition& destination, bool preserveSelection, bool preserveStyle)
-{
- if (startOfParagraphToMove == destination)
- return;
-
- int startIndex = -1;
- int endIndex = -1;
- int destinationIndex = -1;
- if (preserveSelection && !endingSelection().isNone()) {
- VisiblePosition visibleStart = endingSelection().visibleStart();
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
-
- bool startAfterParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) > 0;
- bool endBeforeParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) < 0;
-
- if (!startAfterParagraph && !endBeforeParagraph) {
- bool startInParagraph = Range::compareBoundaryPoints(visibleStart.deepEquivalent(), startOfParagraphToMove.deepEquivalent()) >= 0;
- bool endInParagraph = Range::compareBoundaryPoints(visibleEnd.deepEquivalent(), endOfParagraphToMove.deepEquivalent()) <= 0;
-
- startIndex = 0;
- if (startInParagraph) {
- RefPtr<Range> startRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleStart.deepEquivalent()));
- startIndex = TextIterator::rangeLength(startRange.get(), true);
- }
-
- endIndex = 0;
- if (endInParagraph) {
- RefPtr<Range> endRange = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(visibleEnd.deepEquivalent()));
- endIndex = TextIterator::rangeLength(endRange.get(), true);
- }
- }
- }
-
- VisiblePosition beforeParagraph = startOfParagraphToMove.previous();
- VisiblePosition afterParagraph(endOfParagraphToMove.next());
-
- // We upstream() the end and downstream() the start so that we don't include collapsed whitespace in the move.
- // When we paste a fragment, spaces after the end and before the start are treated as though they were rendered.
- Position start = startOfParagraphToMove.deepEquivalent().downstream();
- Position end = endOfParagraphToMove.deepEquivalent().upstream();
-
- // start and end can't be used directly to create a Range; they are "editing positions"
- Position startRangeCompliant = rangeCompliantEquivalent(start);
- Position endRangeCompliant = rangeCompliantEquivalent(end);
- RefPtr<Range> range = Range::create(document(), startRangeCompliant.node(), startRangeCompliant.offset(), endRangeCompliant.node(), endRangeCompliant.offset());
-
- // FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
- // shouldn't matter though, since moved paragraphs will usually be quite small.
- RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "") : 0;
-
- // A non-empty paragraph's style is moved when we copy and move it. We don't move
- // anything if we're given an empty paragraph, but an empty paragraph can have style
- // too, <div><b><br></b></div> for example. Save it so that we can preserve it later.
- RefPtr<CSSMutableStyleDeclaration> styleInEmptyParagraph;
- if (startOfParagraphToMove == endOfParagraphToMove && preserveStyle) {
- styleInEmptyParagraph = styleAtPosition(startOfParagraphToMove.deepEquivalent());
- // The moved paragraph should assume the block style of the destination.
- styleInEmptyParagraph->removeBlockProperties();
- }
-
- // FIXME (5098931): We should add a new insert action "WebViewInsertActionMoved" and call shouldInsertFragment here.
-
- setEndingSelection(Selection(start, end, DOWNSTREAM));
- deleteSelection(false, false, false, false);
-
- ASSERT(destination.deepEquivalent().node()->inDocument());
-
- // There are bugs in deletion when it removes a fully selected table/list.
- // It expands and removes the entire table/list, but will let content
- // before and after the table/list collapse onto one line.
-
- // Deleting a paragraph will leave a placeholder. Remove it (and prune
- // empty or unrendered parents).
- VisiblePosition caretAfterDelete = endingSelection().visibleStart();
- if (isStartOfParagraph(caretAfterDelete) && isEndOfParagraph(caretAfterDelete)) {
- // Note: We want the rightmost candidate.
- Position position = caretAfterDelete.deepEquivalent().downstream();
- Node* node = position.node();
- // Normally deletion will leave a br as a placeholder.
- if (node->hasTagName(brTag))
- removeNodeAndPruneAncestors(node);
- // If the selection to move was empty and in an empty block that
- // doesn't require a placeholder to prop itself open (like a bordered
- // div or an li), remove it during the move (the list removal code
- // expects this behavior).
- else if (isBlock(node))
- removeNodeAndPruneAncestors(node);
- else if (lineBreakExistsAtPosition(caretAfterDelete)) {
- // There is a preserved '\n' at caretAfterDelete.
- Text* textNode = static_cast<Text*>(node);
- if (textNode->length() == 1)
- removeNodeAndPruneAncestors(node);
- else
- deleteTextFromNode(textNode, position.offset(), 1);
- }
- }
-
- // Add a br if pruning an empty block level element caused a collapse. For example:
- // foo^
- // <div>bar</div>
- // baz
- // Imagine moving 'bar' to ^. 'bar' will be deleted and its div pruned. That would
- // cause 'baz' to collapse onto the line with 'foobar' unless we insert a br.
- // Must recononicalize these two VisiblePositions after the pruning above.
- beforeParagraph = VisiblePosition(beforeParagraph.deepEquivalent());
- afterParagraph = VisiblePosition(afterParagraph.deepEquivalent());
- if (beforeParagraph.isNotNull() && (!isEndOfParagraph(beforeParagraph) || beforeParagraph == afterParagraph)) {
- // FIXME: Trim text between beforeParagraph and afterParagraph if they aren't equal.
- insertNodeAt(createBreakElement(document()).get(), beforeParagraph.deepEquivalent());
- // Need an updateLayout here in case inserting the br has split a text node.
- updateLayout();
- }
-
- RefPtr<Range> startToDestinationRange(Range::create(document(), Position(document(), 0), rangeCompliantEquivalent(destination.deepEquivalent())));
- destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
-
- setEndingSelection(destination);
- applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment.get(), true, false, !preserveStyle, false, true));
- // Restore styles from an empty paragraph to the new empty paragraph.
- if (styleInEmptyParagraph)
- applyStyle(styleInEmptyParagraph.get());
-
- if (preserveSelection && startIndex != -1) {
- // Fragment creation (using createMarkup) incorrectly uses regular
- // spaces instead of nbsps for some spaces that were rendered (11475), which
- // causes spaces to be collapsed during the move operation. This results
- // in a call to rangeFromLocationAndLength with a location past the end
- // of the document (which will return null).
- RefPtr<Range> start = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + startIndex, 0, true);
- RefPtr<Range> end = TextIterator::rangeFromLocationAndLength(document()->documentElement(), destinationIndex + endIndex, 0, true);
- if (start && end)
- setEndingSelection(Selection(start->startPosition(), end->startPosition(), DOWNSTREAM));
- }
-}
-
-// FIXME: Send an appropriate shouldDeleteRange call.
-bool CompositeEditCommand::breakOutOfEmptyListItem()
-{
- Node* emptyListItem = enclosingEmptyListItem(endingSelection().visibleStart());
- if (!emptyListItem)
- return false;
-
- RefPtr<CSSMutableStyleDeclaration> style = styleAtPosition(endingSelection().start());
-
- Node* listNode = emptyListItem->parentNode();
-
- if (!listNode->isContentEditable())
- return false;
-
- RefPtr<Node> newBlock = isListElement(listNode->parentNode()) ? createListItemElement(document()) : createDefaultParagraphElement(document());
-
- if (emptyListItem->renderer()->nextSibling()) {
- if (emptyListItem->renderer()->previousSibling())
- splitElement(static_cast<Element*>(listNode), emptyListItem);
- insertNodeBefore(newBlock.get(), listNode);
- removeNode(emptyListItem);
- } else {
- insertNodeAfter(newBlock.get(), listNode);
- removeNode(emptyListItem->renderer()->previousSibling() ? emptyListItem : listNode);
- }
-
- appendBlockPlaceholder(newBlock.get());
- setEndingSelection(Selection(Position(newBlock.get(), 0), DOWNSTREAM));
-
- computedStyle(endingSelection().start().node())->diff(style.get());
- if (style->length() > 0)
- applyStyle(style.get());
-
- return true;
-}
-
-// Operations use this function to avoid inserting content into an anchor when at the start or the end of
-// that anchor, as in NSTextView.
-// FIXME: This is only an approximation of NSTextViews insertion behavior, which varies depending on how
-// the caret was made.
-Position CompositeEditCommand::positionAvoidingSpecialElementBoundary(const Position& original, bool alwaysAvoidAnchors)
-{
- if (original.isNull())
- return original;
-
- VisiblePosition visiblePos(original);
- Node* enclosingAnchor = enclosingAnchorElement(original);
- Position result = original;
- // Don't avoid block level anchors, because that would insert content into the wrong paragraph.
- if (enclosingAnchor && !isBlock(enclosingAnchor)) {
- VisiblePosition firstInAnchor(Position(enclosingAnchor, 0));
- VisiblePosition lastInAnchor(Position(enclosingAnchor, maxDeepOffset(enclosingAnchor)));
- // If visually just after the anchor, insert *inside* the anchor unless it's the last
- // VisiblePosition in the document, to match NSTextView.
- if (visiblePos == lastInAnchor && (isEndOfDocument(visiblePos) || alwaysAvoidAnchors)) {
- // Make sure anchors are pushed down before avoiding them so that we don't
- // also avoid structural elements like lists and blocks (5142012).
- if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
- pushAnchorElementDown(enclosingAnchor);
- enclosingAnchor = enclosingAnchorElement(original);
- if (!enclosingAnchor)
- return original;
- }
- // Don't insert outside an anchor if doing so would skip over a line break. It would
- // probably be safe to move the line break so that we could still avoid the anchor here.
- Position downstream(visiblePos.deepEquivalent().downstream());
- if (lineBreakExistsAtPosition(visiblePos) && downstream.node()->isDescendantOf(enclosingAnchor))
- return original;
-
- result = positionAfterNode(enclosingAnchor);
- }
- // If visually just before an anchor, insert *outside* the anchor unless it's the first
- // VisiblePosition in a paragraph, to match NSTextView.
- if (visiblePos == firstInAnchor && (!isStartOfParagraph(visiblePos) || alwaysAvoidAnchors)) {
- // Make sure anchors are pushed down before avoiding them so that we don't
- // also avoid structural elements like lists and blocks (5142012).
- if (original.node() != enclosingAnchor && original.node()->parentNode() != enclosingAnchor) {
- pushAnchorElementDown(enclosingAnchor);
- enclosingAnchor = enclosingAnchorElement(original);
- }
- result = positionBeforeNode(enclosingAnchor);
- }
- }
-
- if (result.isNull() || !editableRootForPosition(result))
- result = original;
-
- return result;
-}
-
-// Splits the tree parent by parent until we reach the specified ancestor. We use VisiblePositions
-// to determine if the split is necessary. Returns the last split node.
-PassRefPtr<Node> CompositeEditCommand::splitTreeToNode(Node* start, Node* end, bool splitAncestor)
-{
- RefPtr<Node> node;
- for (node = start; node && node->parent() != end; node = node->parent()) {
- VisiblePosition positionInParent(Position(node->parent(), 0), DOWNSTREAM);
- VisiblePosition positionInNode(Position(node, 0), DOWNSTREAM);
- if (positionInParent != positionInNode)
- applyCommandToComposite(SplitElementCommand::create(static_cast<Element*>(node->parent()), node));
- }
- if (splitAncestor)
- return splitTreeToNode(end, end->parent());
- return node.release();
-}
-
-PassRefPtr<Element> createBlockPlaceholderElement(Document* document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
- ASSERT(ec == 0);
- return breakNode.release();
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/CompositeEditCommand.h b/WebCore/editing/CompositeEditCommand.h
deleted file mode 100644
index bbf8b59..0000000
--- a/WebCore/editing/CompositeEditCommand.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef CompositeEditCommand_h
-#define CompositeEditCommand_h
-
-#include "EditCommand.h"
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class CSSStyleDeclaration;
-class Text;
-
-class CompositeEditCommand : public EditCommand {
-public:
- bool isFirstCommand(EditCommand* command) { return !m_commands.isEmpty() && m_commands.first() == command; }
-
-protected:
- CompositeEditCommand(Document*);
-
- //
- // sugary-sweet convenience functions to help create and apply edit commands in composite commands
- //
- void appendNode(Node* appendChild, Node* parentNode);
- void applyCommandToComposite(PassRefPtr<EditCommand>);
- void applyStyle(CSSStyleDeclaration*, EditAction = EditActionChangeAttributes);
- void applyStyle(CSSStyleDeclaration*, const Position& start, const Position& end, EditAction = EditActionChangeAttributes);
- void applyStyledElement(Element*);
- void removeStyledElement(Element*);
- void deleteSelection(bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true);
- void deleteSelection(const Selection&, bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true);
- virtual void deleteTextFromNode(Text* node, int offset, int count);
- void inputText(const String&, bool selectInsertedText = false);
- void insertNodeAfter(Node* insertChild, Node* refChild);
- void insertNodeAt(Node* insertChild, const Position&);
- void insertNodeBefore(Node* insertChild, Node* refChild);
- void insertParagraphSeparator(bool useDefaultParagraphElement = false);
- void insertLineBreak();
- void insertTextIntoNode(Text* node, int offset, const String& text);
- void joinTextNodes(Text*, Text*);
- void rebalanceWhitespace();
- void rebalanceWhitespaceAt(const Position&);
- void prepareWhitespaceAtPositionForSplit(Position& position);
- void removeCSSProperty(CSSStyleDeclaration*, int property);
- void removeNodeAttribute(Element*, const QualifiedName& attribute);
- void removeChildrenInRange(Node*, int from, int to);
- virtual void removeNode(Node*);
- void removeNodePreservingChildren(Node*);
- void removeNodeAndPruneAncestors(Node*);
- void prune(PassRefPtr<Node>);
- void replaceTextInNode(Text* node, int offset, int count, const String& replacementText);
- Position positionOutsideTabSpan(const Position&);
- void insertNodeAtTabSpanPosition(Node*, const Position&);
- void setNodeAttribute(Element*, const QualifiedName& attribute, const String& value);
- void splitTextNode(Text*, int offset);
- void splitElement(Element*, Node* atChild);
- void mergeIdenticalElements(Element*, Element*);
- void wrapContentsInDummySpan(Element*);
- void splitTextNodeContainingElement(Text*, int offset);
-
- void deleteInsignificantText(Text*, int start, int end);
- void deleteInsignificantText(const Position& start, const Position& end);
- void deleteInsignificantTextDownstream(const Position&);
-
- PassRefPtr<Node> appendBlockPlaceholder(Node*);
- PassRefPtr<Node> insertBlockPlaceholder(const Position&);
- PassRefPtr<Node> addBlockPlaceholderIfNeeded(Node*);
- void removePlaceholderAt(const VisiblePosition&);
-
- PassRefPtr<Node> moveParagraphContentsToNewBlockIfNecessary(const Position&);
-
- void pushAnchorElementDown(Node*);
- void pushPartiallySelectedAnchorElementsDown();
-
- void moveParagraph(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
- void moveParagraphs(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
-
- bool breakOutOfEmptyListItem();
-
- Position positionAvoidingSpecialElementBoundary(const Position&, bool alwaysAvoidAnchors = true);
-
- PassRefPtr<Node> splitTreeToNode(Node*, Node*, bool splitAncestor = false);
-
- Vector<RefPtr<EditCommand> > m_commands;
-
-private:
- virtual void doUnapply();
- virtual void doReapply();
-};
-
-} // namespace WebCore
-
-#endif // CompositeEditCommand_h
diff --git a/WebCore/editing/CreateLinkCommand.cpp b/WebCore/editing/CreateLinkCommand.cpp
deleted file mode 100644
index c5d68dd..0000000
--- a/WebCore/editing/CreateLinkCommand.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "CreateLinkCommand.h"
-#include "htmlediting.h"
-#include "Text.h"
-
-#include "HTMLAnchorElement.h"
-
-namespace WebCore {
-
-CreateLinkCommand::CreateLinkCommand(Document* document, const String& url)
- : CompositeEditCommand(document)
-{
- m_url = url;
-}
-
-void CreateLinkCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- RefPtr<HTMLAnchorElement> anchorElement = new HTMLAnchorElement(document());
- anchorElement->setHref(m_url);
-
- if (endingSelection().isRange()) {
- pushPartiallySelectedAnchorElementsDown();
- applyStyledElement(anchorElement.get());
- } else {
- insertNodeAt(anchorElement.get(), endingSelection().start());
- RefPtr<Text> textNode = new Text(document(), m_url);
- appendNode(textNode.get(), anchorElement.get());
- setEndingSelection(Selection(positionBeforeNode(anchorElement.get()), positionAfterNode(anchorElement.get()), DOWNSTREAM));
- }
-}
-
-}
diff --git a/WebCore/editing/CreateLinkCommand.h b/WebCore/editing/CreateLinkCommand.h
deleted file mode 100644
index ba5fe6f..0000000
--- a/WebCore/editing/CreateLinkCommand.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef CreateLinkCommand_h
-#define CreateLinkCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class CreateLinkCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<CreateLinkCommand> create(Document* document, const String& linkURL)
- {
- return adoptRef(new CreateLinkCommand(document, linkURL));
- }
-
-private:
- CreateLinkCommand(Document*, const String& linkURL);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return EditActionCreateLink; }
-
- String m_url;
-};
-
-} // namespace WebCore
-
-#endif // CreateLinkCommand_h
diff --git a/WebCore/editing/DeleteButton.cpp b/WebCore/editing/DeleteButton.cpp
deleted file mode 100644
index 449b5b2..0000000
--- a/WebCore/editing/DeleteButton.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DeleteButton.h"
-
-#include "DeleteButtonController.h"
-#include "Document.h"
-#include "Editor.h"
-#include "Event.h"
-#include "EventNames.h"
-#include "Frame.h"
-
-namespace WebCore {
-
-DeleteButton::DeleteButton(Document* document)
- : HTMLImageElement(document)
-{
-}
-
-void DeleteButton::defaultEventHandler(Event* event)
-{
- if (event->isMouseEvent()) {
- if (event->type() == eventNames().clickEvent) {
- document()->frame()->editor()->deleteButtonController()->deleteTarget();
- event->setDefaultHandled();
- }
- }
-
- HTMLImageElement::defaultEventHandler(event);
-}
-
-} // namespace
diff --git a/WebCore/editing/DeleteButton.h b/WebCore/editing/DeleteButton.h
deleted file mode 100644
index ac3cdac..0000000
--- a/WebCore/editing/DeleteButton.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DeleteButton_h
-#define DeleteButton_h
-
-#include "HTMLImageElement.h"
-
-namespace WebCore {
-
-class DeleteButton : public HTMLImageElement {
-public:
- DeleteButton(Document*);
-
- virtual void defaultEventHandler(Event*);
-};
-
-} // namespace
-
-#endif
diff --git a/WebCore/editing/DeleteButtonController.cpp b/WebCore/editing/DeleteButtonController.cpp
deleted file mode 100644
index d00220d..0000000
--- a/WebCore/editing/DeleteButtonController.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DeleteButtonController.h"
-
-#include "CachedImage.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "CSSPrimitiveValue.h"
-#include "CSSPropertyNames.h"
-#include "CSSValueKeywords.h"
-#include "DeleteButton.h"
-#include "Document.h"
-#include "Editor.h"
-#include "Frame.h"
-#include "htmlediting.h"
-#include "HTMLDivElement.h"
-#include "HTMLNames.h"
-#include "Image.h"
-#include "Node.h"
-#include "Range.h"
-#include "RemoveNodeCommand.h"
-#include "RenderObject.h"
-#include "SelectionController.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-const char* const DeleteButtonController::containerElementIdentifier = "WebKit-Editing-Delete-Container";
-const char* const DeleteButtonController::buttonElementIdentifier = "WebKit-Editing-Delete-Button";
-const char* const DeleteButtonController::outlineElementIdentifier = "WebKit-Editing-Delete-Outline";
-
-DeleteButtonController::DeleteButtonController(Frame* frame)
- : m_frame(frame)
- , m_wasStaticPositioned(false)
- , m_wasAutoZIndex(false)
- , m_disableStack(0)
-{
-}
-
-static bool isDeletableElement(const Node* node)
-{
- if (!node || !node->isHTMLElement() || !node->inDocument() || !node->isContentEditable())
- return false;
-
- const int minimumWidth = 25;
- const int minimumHeight = 25;
- const unsigned minimumVisibleBorders = 3;
-
- RenderObject* renderer = node->renderer();
- if (!renderer || renderer->width() < minimumWidth || renderer->height() < minimumHeight)
- return false;
-
- if (renderer->isTable())
- return true;
-
- if (node->hasTagName(ulTag) || node->hasTagName(olTag))
- return true;
-
- if (renderer->isPositioned())
- return true;
-
- // allow block elements (excluding table cells) that have some non-transparent borders
- if (renderer->isRenderBlock() && !renderer->isTableCell()) {
- RenderStyle* style = renderer->style();
- if (style && style->hasBorder()) {
- unsigned visibleBorders = style->borderTop().isVisible() + style->borderBottom().isVisible() + style->borderLeft().isVisible() + style->borderRight().isVisible();
- if (visibleBorders >= minimumVisibleBorders)
- return true;
- }
- }
-
- return false;
-}
-
-static HTMLElement* enclosingDeletableElement(const Selection& selection)
-{
- if (!selection.isContentEditable())
- return 0;
-
- RefPtr<Range> range = selection.toRange();
- if (!range)
- return 0;
-
- ExceptionCode ec = 0;
- Node* container = range->commonAncestorContainer(ec);
- ASSERT(container);
- ASSERT(ec == 0);
-
- // The enclosingNodeOfType function only works on nodes that are editable
- // (which is strange, given its name).
- if (!container->isContentEditable())
- return 0;
-
- Node* element = enclosingNodeOfType(Position(container, 0), &isDeletableElement);
- if (!element)
- return 0;
-
- ASSERT(element->isHTMLElement());
- return static_cast<HTMLElement*>(element);
-}
-
-void DeleteButtonController::respondToChangedSelection(const Selection& oldSelection)
-{
- if (!enabled())
- return;
-
- HTMLElement* oldElement = enclosingDeletableElement(oldSelection);
- HTMLElement* newElement = enclosingDeletableElement(m_frame->selection()->selection());
- if (oldElement == newElement)
- return;
-
- // If the base is inside a deletable element, give the element a delete widget.
- if (newElement)
- show(newElement);
- else
- hide();
-}
-
-void DeleteButtonController::createDeletionUI()
-{
- RefPtr<HTMLDivElement> container = new HTMLDivElement(m_target->document());
- container->setId(containerElementIdentifier);
-
- CSSMutableStyleDeclaration* style = container->getInlineStyleDecl();
- style->setProperty(CSSPropertyWebkitUserDrag, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserSelect, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserModify, CSSValueNone);
-
- RefPtr<HTMLDivElement> outline = new HTMLDivElement(m_target->document());
- outline->setId(outlineElementIdentifier);
-
- const int borderWidth = 4;
- const int borderRadius = 6;
-
- style = outline->getInlineStyleDecl();
- style->setProperty(CSSPropertyPosition, CSSValueAbsolute);
- style->setProperty(CSSPropertyCursor, CSSValueDefault);
- style->setProperty(CSSPropertyWebkitUserDrag, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserSelect, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserModify, CSSValueNone);
- style->setProperty(CSSPropertyZIndex, String::number(-1000000));
- style->setProperty(CSSPropertyTop, String::number(-borderWidth - m_target->renderer()->borderTop()) + "px");
- style->setProperty(CSSPropertyRight, String::number(-borderWidth - m_target->renderer()->borderRight()) + "px");
- style->setProperty(CSSPropertyBottom, String::number(-borderWidth - m_target->renderer()->borderBottom()) + "px");
- style->setProperty(CSSPropertyLeft, String::number(-borderWidth - m_target->renderer()->borderLeft()) + "px");
- style->setProperty(CSSPropertyBorder, String::number(borderWidth) + "px solid rgba(0, 0, 0, 0.6)");
- style->setProperty(CSSPropertyWebkitBorderRadius, String::number(borderRadius) + "px");
-
- ExceptionCode ec = 0;
- container->appendChild(outline.get(), ec);
- ASSERT(ec == 0);
- if (ec)
- return;
-
- RefPtr<DeleteButton> button = new DeleteButton(m_target->document());
- button->setId(buttonElementIdentifier);
-
- const int buttonWidth = 30;
- const int buttonHeight = 30;
- const int buttonBottomShadowOffset = 2;
-
- style = button->getInlineStyleDecl();
- style->setProperty(CSSPropertyPosition, CSSValueAbsolute);
- style->setProperty(CSSPropertyCursor, CSSValueDefault);
- style->setProperty(CSSPropertyWebkitUserDrag, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserSelect, CSSValueNone);
- style->setProperty(CSSPropertyWebkitUserModify, CSSValueNone);
- style->setProperty(CSSPropertyZIndex, String::number(1000000));
- style->setProperty(CSSPropertyTop, String::number((-buttonHeight / 2) - m_target->renderer()->borderTop() - (borderWidth / 2) + buttonBottomShadowOffset) + "px");
- style->setProperty(CSSPropertyLeft, String::number((-buttonWidth / 2) - m_target->renderer()->borderLeft() - (borderWidth / 2)) + "px");
- style->setProperty(CSSPropertyWidth, String::number(buttonWidth) + "px");
- style->setProperty(CSSPropertyHeight, String::number(buttonHeight) + "px");
-
- RefPtr<Image> buttonImage = Image::loadPlatformResource("deleteButton");
- if (buttonImage->isNull())
- return;
-
- button->setCachedImage(new CachedImage(buttonImage.get()));
-
- container->appendChild(button.get(), ec);
- ASSERT(ec == 0);
- if (ec)
- return;
-
- m_containerElement = container.release();
- m_outlineElement = outline.release();
- m_buttonElement = button.release();
-}
-
-void DeleteButtonController::show(HTMLElement* element)
-{
- hide();
-
- if (!enabled() || !element || !element->inDocument() || !isDeletableElement(element))
- return;
-
- if (!m_frame->editor()->shouldShowDeleteInterface(static_cast<HTMLElement*>(element)))
- return;
-
- // we rely on the renderer having current information, so we should update the layout if needed
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
-
- m_target = element;
-
- if (!m_containerElement) {
- createDeletionUI();
- if (!m_containerElement) {
- hide();
- return;
- }
- }
-
- ExceptionCode ec = 0;
- m_target->appendChild(m_containerElement.get(), ec);
- ASSERT(ec == 0);
- if (ec) {
- hide();
- return;
- }
-
- if (m_target->renderer()->style()->position() == StaticPosition) {
- m_target->getInlineStyleDecl()->setProperty(CSSPropertyPosition, CSSValueRelative);
- m_wasStaticPositioned = true;
- }
-
- if (m_target->renderer()->style()->hasAutoZIndex()) {
- m_target->getInlineStyleDecl()->setProperty(CSSPropertyZIndex, "0");
- m_wasAutoZIndex = true;
- }
-}
-
-void DeleteButtonController::hide()
-{
- m_outlineElement = 0;
- m_buttonElement = 0;
-
- ExceptionCode ec = 0;
- if (m_containerElement && m_containerElement->parentNode())
- m_containerElement->parentNode()->removeChild(m_containerElement.get(), ec);
-
- if (m_target) {
- if (m_wasStaticPositioned)
- m_target->getInlineStyleDecl()->setProperty(CSSPropertyPosition, CSSValueStatic);
- if (m_wasAutoZIndex)
- m_target->getInlineStyleDecl()->setProperty(CSSPropertyZIndex, CSSValueAuto);
- }
-
- m_wasStaticPositioned = false;
- m_wasAutoZIndex = false;
-}
-
-void DeleteButtonController::enable()
-{
- ASSERT(m_disableStack > 0);
- if (m_disableStack > 0)
- m_disableStack--;
- if (enabled())
- show(enclosingDeletableElement(m_frame->selection()->selection()));
-}
-
-void DeleteButtonController::disable()
-{
- if (enabled())
- hide();
- m_disableStack++;
-}
-
-void DeleteButtonController::deleteTarget()
-{
- if (!enabled() || !m_target)
- return;
-
- RefPtr<Node> element = m_target;
- hide();
-
- // Because the deletion UI only appears when the selection is entirely
- // within the target, we unconditionally update the selection to be
- // a caret where the target had been.
- Position pos = positionBeforeNode(element.get());
- applyCommand(RemoveNodeCommand::create(element.release()));
- m_frame->selection()->setSelection(VisiblePosition(pos));
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/DeleteButtonController.h b/WebCore/editing/DeleteButtonController.h
deleted file mode 100644
index ab2d0b0..0000000
--- a/WebCore/editing/DeleteButtonController.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DeleteButtonController_h
-#define DeleteButtonController_h
-
-#include "DeleteButton.h"
-
-namespace WebCore {
-
-class DeleteButton;
-class Frame;
-class HTMLElement;
-class RenderObject;
-class Selection;
-
-class DeleteButtonController {
-public:
- DeleteButtonController(Frame*);
-
- static const char* const containerElementIdentifier;
-
- HTMLElement* target() const { return m_target.get(); }
- HTMLElement* containerElement() const { return m_containerElement.get(); }
-
- void respondToChangedSelection(const Selection& oldSelection);
-
- void show(HTMLElement*);
- void hide();
-
- bool enabled() const { return (m_disableStack == 0); }
- void enable();
- void disable();
-
- void deleteTarget();
-
-private:
- static const char* const buttonElementIdentifier;
- static const char* const outlineElementIdentifier;
-
- void createDeletionUI();
-
- Frame* m_frame;
- RefPtr<HTMLElement> m_target;
- RefPtr<HTMLElement> m_containerElement;
- RefPtr<HTMLElement> m_outlineElement;
- RefPtr<DeleteButton> m_buttonElement;
- bool m_wasStaticPositioned;
- bool m_wasAutoZIndex;
- unsigned m_disableStack;
-};
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/editing/DeleteFromTextNodeCommand.cpp b/WebCore/editing/DeleteFromTextNodeCommand.cpp
deleted file mode 100644
index 93a974f..0000000
--- a/WebCore/editing/DeleteFromTextNodeCommand.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DeleteFromTextNodeCommand.h"
-
-#include "Text.h"
-
-namespace WebCore {
-
-DeleteFromTextNodeCommand::DeleteFromTextNodeCommand(PassRefPtr<Text> node, int offset, int count)
- : SimpleEditCommand(node->document()), m_node(node), m_offset(offset), m_count(count)
-{
- ASSERT(m_node);
- ASSERT(m_offset >= 0);
- ASSERT(m_offset < (int)m_node->length());
- ASSERT(m_count >= 0);
-}
-
-void DeleteFromTextNodeCommand::doApply()
-{
- ASSERT(m_node);
-
- ExceptionCode ec = 0;
- m_text = m_node->substringData(m_offset, m_count, ec);
- ASSERT(ec == 0);
-
- m_node->deleteData(m_offset, m_count, ec);
- ASSERT(ec == 0);
-}
-
-void DeleteFromTextNodeCommand::doUnapply()
-{
- ASSERT(m_node);
- ASSERT(!m_text.isEmpty());
-
- ExceptionCode ec = 0;
- m_node->insertData(m_offset, m_text, ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/DeleteFromTextNodeCommand.h b/WebCore/editing/DeleteFromTextNodeCommand.h
deleted file mode 100644
index b3bf10b..0000000
--- a/WebCore/editing/DeleteFromTextNodeCommand.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DeleteFromTextNodeCommand_h
-#define DeleteFromTextNodeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class Text;
-
-class DeleteFromTextNodeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<DeleteFromTextNodeCommand> create(PassRefPtr<Text> node, int offset, int count)
- {
- return adoptRef(new DeleteFromTextNodeCommand(node, offset, count));
- }
-
-private:
- DeleteFromTextNodeCommand(PassRefPtr<Text>, int offset, int count);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Text> m_node;
- int m_offset;
- int m_count;
- String m_text;
-};
-
-} // namespace WebCore
-
-#endif // DeleteFromTextNodeCommand_h
diff --git a/WebCore/editing/DeleteSelectionCommand.cpp b/WebCore/editing/DeleteSelectionCommand.cpp
deleted file mode 100644
index 0c9d68a..0000000
--- a/WebCore/editing/DeleteSelectionCommand.cpp
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DeleteSelectionCommand.h"
-
-#include "Document.h"
-#include "DocumentFragment.h"
-#include "Editor.h"
-#include "EditorClient.h"
-#include "Element.h"
-#include "Frame.h"
-#include "Logging.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "htmlediting.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "markup.h"
-#include "ReplaceSelectionCommand.h"
-#include "Text.h"
-#include "TextIterator.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-static bool isTableRow(const Node* node)
-{
- return node && node->hasTagName(trTag);
-}
-
-static bool isTableCellEmpty(Node* cell)
-{
- ASSERT(isTableCell(cell));
- VisiblePosition firstInCell(Position(cell, 0));
- VisiblePosition lastInCell(Position(cell, maxDeepOffset(cell)));
- return firstInCell == lastInCell;
-}
-
-static bool isTableRowEmpty(Node* row)
-{
- if (!isTableRow(row))
- return false;
-
- for (Node* child = row->firstChild(); child; child = child->nextSibling())
- if (isTableCell(child) && !isTableCellEmpty(child))
- return false;
-
- return true;
-}
-
-DeleteSelectionCommand::DeleteSelectionCommand(Document *document, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
- : CompositeEditCommand(document),
- m_hasSelectionToDelete(false),
- m_smartDelete(smartDelete),
- m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
- m_replace(replace),
- m_expandForSpecialElements(expandForSpecialElements),
- m_startBlock(0),
- m_endBlock(0),
- m_typingStyle(0),
- m_deleteIntoBlockquoteStyle(0)
-{
-}
-
-DeleteSelectionCommand::DeleteSelectionCommand(const Selection& selection, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements)
- : CompositeEditCommand(selection.start().node()->document()),
- m_hasSelectionToDelete(true),
- m_smartDelete(smartDelete),
- m_mergeBlocksAfterDelete(mergeBlocksAfterDelete),
- m_replace(replace),
- m_expandForSpecialElements(expandForSpecialElements),
- m_selectionToDelete(selection),
- m_startBlock(0),
- m_endBlock(0),
- m_typingStyle(0),
- m_deleteIntoBlockquoteStyle(0)
-{
-}
-
-void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end)
-{
- Node* startSpecialContainer = 0;
- Node* endSpecialContainer = 0;
-
- start = m_selectionToDelete.start();
- end = m_selectionToDelete.end();
-
- // For HRs, we'll get a position at (HR,1) when hitting delete from the beginning of the previous line, or (HR,0) when forward deleting,
- // but in these cases, we want to delete it, so manually expand the selection
- if (start.node()->hasTagName(hrTag))
- start = Position(start.node(), 0);
- else if (end.node()->hasTagName(hrTag))
- end = Position(end.node(), 1);
-
- // FIXME: This is only used so that moveParagraphs can avoid the bugs in special element expanion.
- if (!m_expandForSpecialElements)
- return;
-
- while (1) {
- startSpecialContainer = 0;
- endSpecialContainer = 0;
-
- Position s = positionBeforeContainingSpecialElement(start, &startSpecialContainer);
- Position e = positionAfterContainingSpecialElement(end, &endSpecialContainer);
-
- if (!startSpecialContainer && !endSpecialContainer)
- break;
-
- if (VisiblePosition(start) != m_selectionToDelete.visibleStart() || VisiblePosition(end) != m_selectionToDelete.visibleEnd())
- break;
-
- // If we're going to expand to include the startSpecialContainer, it must be fully selected.
- if (startSpecialContainer && !endSpecialContainer && Range::compareBoundaryPoints(positionAfterNode(startSpecialContainer), end) > -1)
- break;
-
- // If we're going to expand to include the endSpecialContainer, it must be fully selected.
- if (endSpecialContainer && !startSpecialContainer && Range::compareBoundaryPoints(start, positionBeforeNode(endSpecialContainer)) > -1)
- break;
-
- if (startSpecialContainer && startSpecialContainer->isDescendantOf(endSpecialContainer))
- // Don't adjust the end yet, it is the end of a special element that contains the start
- // special element (which may or may not be fully selected).
- start = s;
- else if (endSpecialContainer && endSpecialContainer->isDescendantOf(startSpecialContainer))
- // Don't adjust the start yet, it is the start of a special element that contains the end
- // special element (which may or may not be fully selected).
- end = e;
- else {
- start = s;
- end = e;
- }
- }
-}
-
-void DeleteSelectionCommand::initializePositionData()
-{
- Position start, end;
- initializeStartEnd(start, end);
-
- m_upstreamStart = start.upstream();
- m_downstreamStart = start.downstream();
- m_upstreamEnd = end.upstream();
- m_downstreamEnd = end.downstream();
-
- m_startRoot = editableRootForPosition(start);
- m_endRoot = editableRootForPosition(end);
-
- m_startTableRow = enclosingNodeOfType(start, &isTableRow);
- m_endTableRow = enclosingNodeOfType(end, &isTableRow);
-
- // Don't move content out of a table cell.
- // If the cell is non-editable, enclosingNodeOfType won't return it by default, so
- // tell that function that we don't care if it returns non-editable nodes.
- Node* startCell = enclosingNodeOfType(m_upstreamStart, &isTableCell, false);
- Node* endCell = enclosingNodeOfType(m_downstreamEnd, &isTableCell, false);
- // FIXME: This isn't right. A borderless table with two rows and a single column would appear as two paragraphs.
- if (endCell && endCell != startCell)
- m_mergeBlocksAfterDelete = false;
-
- // Usually the start and the end of the selection to delete are pulled together as a result of the deletion.
- // Sometimes they aren't (like when no merge is requested), so we must choose one position to hold the caret
- // and receive the placeholder after deletion.
- VisiblePosition visibleEnd(m_downstreamEnd);
- if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd))
- m_endingPosition = m_downstreamEnd;
- else
- m_endingPosition = m_downstreamStart;
-
- // Handle leading and trailing whitespace, as well as smart delete adjustments to the selection
- m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.affinity());
- m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
-
- if (m_smartDelete) {
-
- // skip smart delete if the selection to delete already starts or ends with whitespace
- Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.affinity()).deepEquivalent();
- bool skipSmartDelete = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
- if (!skipSmartDelete)
- skipSmartDelete = m_downstreamEnd.leadingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull();
-
- // extend selection upstream if there is whitespace there
- bool hasLeadingWhitespaceBeforeAdjustment = m_upstreamStart.leadingWhitespacePosition(m_selectionToDelete.affinity(), true).isNotNull();
- if (!skipSmartDelete && hasLeadingWhitespaceBeforeAdjustment) {
- VisiblePosition visiblePos = VisiblePosition(m_upstreamStart, VP_DEFAULT_AFFINITY).previous();
- pos = visiblePos.deepEquivalent();
- // Expand out one character upstream for smart delete and recalculate
- // positions based on this change.
- m_upstreamStart = pos.upstream();
- m_downstreamStart = pos.downstream();
- m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(visiblePos.affinity());
- }
-
- // trailing whitespace is only considered for smart delete if there is no leading
- // whitespace, as in the case where you double-click the first word of a paragraph.
- if (!skipSmartDelete && !hasLeadingWhitespaceBeforeAdjustment && m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY, true).isNotNull()) {
- // Expand out one character downstream for smart delete and recalculate
- // positions based on this change.
- pos = VisiblePosition(m_downstreamEnd, VP_DEFAULT_AFFINITY).next().deepEquivalent();
- m_upstreamEnd = pos.upstream();
- m_downstreamEnd = pos.downstream();
- m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
- }
- }
-
- // We must pass the positions through rangeCompliantEquivalent, since some editing positions
- // that appear inside their nodes aren't really inside them. [hr, 0] is one example.
- // FIXME: rangeComplaintEquivalent should eventually be moved into enclosing element getters
- // like the one below, since editing functions should obviously accept editing positions.
- // FIXME: Passing false to enclosingNodeOfType tells it that it's OK to return a non-editable
- // node. This was done to match existing behavior, but it seems wrong.
- m_startBlock = enclosingNodeOfType(rangeCompliantEquivalent(m_downstreamStart), &isBlock, false);
- m_endBlock = enclosingNodeOfType(rangeCompliantEquivalent(m_upstreamEnd), &isBlock, false);
-}
-
-void DeleteSelectionCommand::saveTypingStyleState()
-{
- // A common case is deleting characters that are all from the same text node. In
- // that case, the style at the start of the selection before deletion will be the
- // same as the style at the start of the selection after deletion (since those
- // two positions will be identical). Therefore there is no need to save the
- // typing style at the start of the selection, nor is there a reason to
- // compute the style at the start of the selection after deletion (see the
- // early return in calculateTypingStyleAfterDelete).
- if (m_upstreamStart.node() == m_downstreamEnd.node() && m_upstreamStart.node()->isTextNode())
- return;
-
- // Figure out the typing style in effect before the delete is done.
- RefPtr<CSSComputedStyleDeclaration> computedStyle = positionBeforeTabSpan(m_selectionToDelete.start()).computedStyle();
- m_typingStyle = computedStyle->copyInheritableProperties();
-
- // If we're deleting into a Mail blockquote, save the style at end() instead of start()
- // We'll use this later in computeTypingStyleAfterDelete if we end up outside of a Mail blockquote
- if (nearestMailBlockquote(m_selectionToDelete.start().node())) {
- computedStyle = m_selectionToDelete.end().computedStyle();
- m_deleteIntoBlockquoteStyle = computedStyle->copyInheritableProperties();
- } else
- m_deleteIntoBlockquoteStyle = 0;
-}
-
-bool DeleteSelectionCommand::handleSpecialCaseBRDelete()
-{
- // Check for special-case where the selection contains only a BR on a line by itself after another BR.
- bool upstreamStartIsBR = m_upstreamStart.node()->hasTagName(brTag);
- bool downstreamStartIsBR = m_downstreamStart.node()->hasTagName(brTag);
- bool isBROnLineByItself = upstreamStartIsBR && downstreamStartIsBR && m_downstreamStart.node() == m_upstreamEnd.node();
- if (isBROnLineByItself) {
- removeNode(m_downstreamStart.node());
- return true;
- }
-
- // Not a special-case delete per se, but we can detect that the merging of content between blocks
- // should not be done.
- if (upstreamStartIsBR && downstreamStartIsBR) {
- m_mergeBlocksAfterDelete = false;
- m_endingPosition = m_downstreamEnd;
- }
-
- return false;
-}
-
-static void updatePositionForNodeRemoval(Node* node, Position& position)
-{
- if (position.isNull())
- return;
- if (node->parent() == position.node() && node->nodeIndex() < (unsigned)position.offset())
- position = Position(position.node(), position.offset() - 1);
- if (position.node() == node || position.node()->isDescendantOf(node))
- position = positionBeforeNode(node);
-}
-
-void DeleteSelectionCommand::removeNode(Node *node)
-{
- if (!node)
- return;
-
- if (m_startRoot != m_endRoot && !(node->isDescendantOf(m_startRoot.get()) && node->isDescendantOf(m_endRoot.get()))) {
- // If a node is not in both the start and end editable roots, remove it only if its inside an editable region.
- if (!node->parentNode()->isContentEditable()) {
- // Don't remove non-editable atomic nodes.
- if (!node->firstChild())
- return;
- // Search this non-editable region for editable regions to empty.
- RefPtr<Node> child = node->firstChild();
- while (child) {
- RefPtr<Node> nextChild = child->nextSibling();
- removeNode(child.get());
- // Bail if nextChild is no longer node's child.
- if (nextChild && nextChild->parentNode() != node)
- return;
- child = nextChild;
- }
-
- // Don't remove editable regions that are inside non-editable ones, just clear them.
- return;
- }
- }
-
- if (isTableStructureNode(node) || node == node->rootEditableElement()) {
- // Do not remove an element of table structure; remove its contents.
- // Likewise for the root editable element.
- Node *child = node->firstChild();
- while (child) {
- Node *remove = child;
- child = child->nextSibling();
- removeNode(remove);
- }
-
- // make sure empty cell has some height
- updateLayout();
- RenderObject *r = node->renderer();
- if (r && r->isTableCell() && r->contentHeight() <= 0)
- insertBlockPlaceholder(Position(node,0));
- return;
- }
-
- if (node == m_startBlock && !isEndOfBlock(VisiblePosition(m_startBlock.get(), 0, DOWNSTREAM).previous()))
- m_needPlaceholder = true;
- else if (node == m_endBlock && !isStartOfBlock(VisiblePosition(m_endBlock.get(), maxDeepOffset(m_endBlock.get()), DOWNSTREAM).next()))
- m_needPlaceholder = true;
-
- // FIXME: Update the endpoints of the range being deleted.
- updatePositionForNodeRemoval(node, m_endingPosition);
- updatePositionForNodeRemoval(node, m_leadingWhitespace);
- updatePositionForNodeRemoval(node, m_trailingWhitespace);
-
- CompositeEditCommand::removeNode(node);
-}
-
-
-void updatePositionForTextRemoval(Node* node, int offset, int count, Position& position)
-{
- if (position.node() == node) {
- if (position.offset() > offset + count)
- position = Position(position.node(), position.offset() - count);
- else if (position.offset() > offset)
- position = Position(position.node(), offset);
- }
-}
-
-void DeleteSelectionCommand::deleteTextFromNode(Text *node, int offset, int count)
-{
- // FIXME: Update the endpoints of the range being deleted.
- updatePositionForTextRemoval(node, offset, count, m_endingPosition);
- updatePositionForTextRemoval(node, offset, count, m_leadingWhitespace);
- updatePositionForTextRemoval(node, offset, count, m_trailingWhitespace);
-
- CompositeEditCommand::deleteTextFromNode(node, offset, count);
-}
-
-void DeleteSelectionCommand::handleGeneralDelete()
-{
- int startOffset = m_upstreamStart.offset();
- Node* startNode = m_upstreamStart.node();
-
- // Never remove the start block unless it's a table, in which case we won't merge content in.
- if (startNode == m_startBlock && startOffset == 0 && canHaveChildrenForEditing(startNode) && !startNode->hasTagName(tableTag)) {
- startOffset = 0;
- startNode = startNode->traverseNextNode();
- }
-
- if (startOffset >= caretMaxOffset(startNode) && startNode->isTextNode()) {
- Text *text = static_cast<Text *>(startNode);
- if (text->length() > (unsigned)caretMaxOffset(startNode))
- deleteTextFromNode(text, caretMaxOffset(startNode), text->length() - caretMaxOffset(startNode));
- }
-
- if (startOffset >= maxDeepOffset(startNode)) {
- startNode = startNode->traverseNextSibling();
- startOffset = 0;
- }
-
- // Done adjusting the start. See if we're all done.
- if (!startNode)
- return;
-
- if (startNode == m_downstreamEnd.node()) {
- // The selection to delete is all in one node.
- if (!startNode->renderer() ||
- (startOffset == 0 && m_downstreamEnd.offset() >= maxDeepOffset(startNode))) {
- // just delete
- removeNode(startNode);
- } else if (m_downstreamEnd.offset() - startOffset > 0) {
- if (startNode->isTextNode()) {
- // in a text node that needs to be trimmed
- Text *text = static_cast<Text *>(startNode);
- deleteTextFromNode(text, startOffset, m_downstreamEnd.offset() - startOffset);
- } else {
- removeChildrenInRange(startNode, startOffset, m_downstreamEnd.offset());
- m_endingPosition = m_upstreamStart;
- }
- }
- }
- else {
- bool startNodeWasDescendantOfEndNode = m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node());
- // The selection to delete spans more than one node.
- RefPtr<Node> node(startNode);
-
- if (startOffset > 0) {
- if (startNode->isTextNode()) {
- // in a text node that needs to be trimmed
- Text *text = static_cast<Text *>(node.get());
- deleteTextFromNode(text, startOffset, text->length() - startOffset);
- node = node->traverseNextNode();
- } else {
- node = startNode->childNode(startOffset);
- }
- }
-
- // handle deleting all nodes that are completely selected
- while (node && node != m_downstreamEnd.node()) {
- if (Range::compareBoundaryPoints(Position(node.get(), 0), m_downstreamEnd) >= 0) {
- // traverseNextSibling just blew past the end position, so stop deleting
- node = 0;
- } else if (!m_downstreamEnd.node()->isDescendantOf(node.get())) {
- RefPtr<Node> nextNode = node->traverseNextSibling();
- // if we just removed a node from the end container, update end position so the
- // check above will work
- if (node->parentNode() == m_downstreamEnd.node()) {
- ASSERT(node->nodeIndex() < (unsigned)m_downstreamEnd.offset());
- m_downstreamEnd = Position(m_downstreamEnd.node(), m_downstreamEnd.offset() - 1);
- }
- removeNode(node.get());
- node = nextNode.get();
- } else {
- Node* n = node->lastDescendant();
- if (m_downstreamEnd.node() == n && m_downstreamEnd.offset() >= caretMaxOffset(n)) {
- removeNode(node.get());
- node = 0;
- } else
- node = node->traverseNextNode();
- }
- }
-
- if (m_downstreamEnd.node() != startNode && !m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node()) && m_downstreamEnd.node()->inDocument() && m_downstreamEnd.offset() >= caretMinOffset(m_downstreamEnd.node())) {
- if (m_downstreamEnd.offset() >= maxDeepOffset(m_downstreamEnd.node()) && !canHaveChildrenForEditing(m_downstreamEnd.node())) {
- // The node itself is fully selected, not just its contents. Delete it.
- removeNode(m_downstreamEnd.node());
- } else {
- if (m_downstreamEnd.node()->isTextNode()) {
- // in a text node that needs to be trimmed
- Text *text = static_cast<Text *>(m_downstreamEnd.node());
- if (m_downstreamEnd.offset() > 0) {
- deleteTextFromNode(text, 0, m_downstreamEnd.offset());
- m_downstreamEnd = Position(text, 0);
- }
- // Remove children of m_downstreamEnd.node() that come after m_upstreamStart.
- // Don't try to remove children if m_upstreamStart was inside m_downstreamEnd.node()
- // and m_upstreamStart has been removed from the document, because then we don't
- // know how many children to remove.
- // FIXME: Make m_upstreamStart a position we update as we remove content, then we can
- // always know which children to remove.
- } else if (!(startNodeWasDescendantOfEndNode && !m_upstreamStart.node()->inDocument())) {
- int offset = 0;
- if (m_upstreamStart.node()->isDescendantOf(m_downstreamEnd.node())) {
- Node *n = m_upstreamStart.node();
- while (n && n->parentNode() != m_downstreamEnd.node())
- n = n->parentNode();
- if (n)
- offset = n->nodeIndex() + 1;
- }
- removeChildrenInRange(m_downstreamEnd.node(), offset, m_downstreamEnd.offset());
- m_downstreamEnd = Position(m_downstreamEnd.node(), offset);
- }
- }
- }
- }
-}
-
-void DeleteSelectionCommand::fixupWhitespace()
-{
- updateLayout();
- // FIXME: isRenderedCharacter should be removed, and we should use VisiblePosition::characterAfter and VisiblePosition::characterBefore
- if (m_leadingWhitespace.isNotNull() && !m_leadingWhitespace.isRenderedCharacter()) {
- Text* textNode = static_cast<Text*>(m_leadingWhitespace.node());
- ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
- replaceTextInNode(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
- }
- if (m_trailingWhitespace.isNotNull() && !m_trailingWhitespace.isRenderedCharacter()) {
- Text* textNode = static_cast<Text*>(m_trailingWhitespace.node());
- ASSERT(!textNode->renderer() ||textNode->renderer()->style()->collapseWhiteSpace());
- replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
- }
-}
-
-// If a selection starts in one block and ends in another, we have to merge to bring content before the
-// start together with content after the end.
-void DeleteSelectionCommand::mergeParagraphs()
-{
- if (!m_mergeBlocksAfterDelete)
- return;
-
- // FIXME: Deletion should adjust selection endpoints as it removes nodes so that we never get into this state (4099839).
- if (!m_downstreamEnd.node()->inDocument() || !m_upstreamStart.node()->inDocument())
- return;
-
- // FIXME: The deletion algorithm shouldn't let this happen.
- if (Range::compareBoundaryPoints(m_upstreamStart, m_downstreamEnd) > 0)
- return;
-
- // FIXME: Merging will always be unnecessary in this case, but we really bail here because this is a case where
- // deletion commonly fails to adjust its endpoints, which would cause the visible position comparison below to false negative.
- if (m_endBlock == m_startBlock)
- return;
-
- VisiblePosition startOfParagraphToMove(m_downstreamEnd);
- VisiblePosition mergeDestination(m_upstreamStart);
-
- // m_downstreamEnd's block has been emptied out by deletion. There is no content inside of it to
- // move, so just remove it.
- Element* endBlock = static_cast<Element*>(enclosingBlock(m_downstreamEnd.node()));
- if (!startOfParagraphToMove.deepEquivalent().node() || !endBlock->contains(startOfParagraphToMove.deepEquivalent().node())) {
- removeNode(enclosingBlock(m_downstreamEnd.node()));
- return;
- }
-
- // We need to merge into m_upstreamStart's block, but it's been emptied out and collapsed by deletion.
- if (!mergeDestination.deepEquivalent().node() || !mergeDestination.deepEquivalent().node()->isDescendantOf(m_upstreamStart.node()->enclosingBlockFlowElement())) {
- insertNodeAt(createBreakElement(document()).get(), m_upstreamStart);
- mergeDestination = VisiblePosition(m_upstreamStart);
- }
-
- if (mergeDestination == startOfParagraphToMove)
- return;
-
- VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove);
-
- if (mergeDestination == endOfParagraphToMove)
- return;
-
- // The rule for merging into an empty block is: only do so if its farther to the right.
- // FIXME: Consider RTL.
- // FIXME: handleSpecialCaseBRDelete prevents us from getting here in a case like <ul><li>foo<br><br></li></ul>^foo
- if (isStartOfParagraph(mergeDestination) && startOfParagraphToMove.caretRect().x() > mergeDestination.caretRect().x()) {
- ASSERT(mergeDestination.deepEquivalent().downstream().node()->hasTagName(brTag));
- removeNodeAndPruneAncestors(mergeDestination.deepEquivalent().downstream().node());
- m_endingPosition = startOfParagraphToMove.deepEquivalent();
- return;
- }
-
- RefPtr<Range> range = Range::create(document(), rangeCompliantEquivalent(startOfParagraphToMove.deepEquivalent()), rangeCompliantEquivalent(endOfParagraphToMove.deepEquivalent()));
- RefPtr<Range> rangeToBeReplaced = Range::create(document(), rangeCompliantEquivalent(mergeDestination.deepEquivalent()), rangeCompliantEquivalent(mergeDestination.deepEquivalent()));
- if (!document()->frame()->editor()->client()->shouldMoveRangeAfterDelete(range.get(), rangeToBeReplaced.get()))
- return;
-
- // moveParagraphs will insert placeholders if it removes blocks that would require their use, don't let block
- // removals that it does cause the insertion of *another* placeholder.
- bool needPlaceholder = m_needPlaceholder;
- moveParagraph(startOfParagraphToMove, endOfParagraphToMove, mergeDestination);
- m_needPlaceholder = needPlaceholder;
- // The endingPosition was likely clobbered by the move, so recompute it (moveParagraph selects the moved paragraph).
- m_endingPosition = endingSelection().start();
-}
-
-void DeleteSelectionCommand::removePreviouslySelectedEmptyTableRows()
-{
- if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow) {
- Node* row = m_endTableRow->previousSibling();
- while (row && row != m_startTableRow) {
- RefPtr<Node> previousRow = row->previousSibling();
- if (isTableRowEmpty(row))
- // Use a raw removeNode, instead of DeleteSelectionCommand's, because
- // that won't remove rows, it only empties them in preparation for this function.
- CompositeEditCommand::removeNode(row);
- row = previousRow.get();
- }
- }
-
- // Remove empty rows after the start row.
- if (m_startTableRow && m_startTableRow->inDocument() && m_startTableRow != m_endTableRow) {
- Node* row = m_startTableRow->nextSibling();
- while (row && row != m_endTableRow) {
- RefPtr<Node> nextRow = row->nextSibling();
- if (isTableRowEmpty(row))
- CompositeEditCommand::removeNode(row);
- row = nextRow.get();
- }
- }
-
- if (m_endTableRow && m_endTableRow->inDocument() && m_endTableRow != m_startTableRow)
- if (isTableRowEmpty(m_endTableRow.get())) {
- // Don't remove m_endTableRow if it's where we're putting the ending selection.
- if (!m_endingPosition.node()->isDescendantOf(m_endTableRow.get())) {
- // FIXME: We probably shouldn't remove m_endTableRow unless it's fully selected, even if it is empty.
- // We'll need to start adjusting the selection endpoints during deletion to know whether or not m_endTableRow
- // was fully selected here.
- CompositeEditCommand::removeNode(m_endTableRow.get());
- }
- }
-}
-
-void DeleteSelectionCommand::calculateTypingStyleAfterDelete()
-{
- if (!m_typingStyle)
- return;
-
- // Compute the difference between the style before the delete and the style now
- // after the delete has been done. Set this style on the frame, so other editing
- // commands being composed with this one will work, and also cache it on the command,
- // so the Frame::appliedEditing can set it after the whole composite command
- // has completed.
-
- // If we deleted into a blockquote, but are now no longer in a blockquote, use the alternate typing style
- if (m_deleteIntoBlockquoteStyle && !nearestMailBlockquote(m_endingPosition.node()))
- m_typingStyle = m_deleteIntoBlockquoteStyle;
- m_deleteIntoBlockquoteStyle = 0;
-
- RefPtr<CSSComputedStyleDeclaration> endingStyle = computedStyle(m_endingPosition.node());
- endingStyle->diff(m_typingStyle.get());
- if (!m_typingStyle->length())
- m_typingStyle = 0;
- VisiblePosition visibleEnd(m_endingPosition);
- if (m_typingStyle &&
- isStartOfParagraph(visibleEnd) &&
- isEndOfParagraph(visibleEnd) &&
- lineBreakExistsAtPosition(visibleEnd)) {
- // Apply style to the placeholder that is now holding open the empty paragraph.
- // This makes sure that the paragraph has the right height, and that the paragraph
- // takes on the right style and retains it even if you move the selection away and
- // then move it back (which will clear typing style).
-
- setEndingSelection(visibleEnd);
- applyStyle(m_typingStyle.get(), EditActionUnspecified);
- // applyStyle can destroy the placeholder that was at m_endingPosition if it needs to
- // move it, but it will set an endingSelection() at [movedPlaceholder, 0] if it does so.
- m_endingPosition = endingSelection().start();
- m_typingStyle = 0;
- }
- // This is where we've deleted all traces of a style but not a whole paragraph (that's handled above).
- // In this case if we start typing, the new characters should have the same style as the just deleted ones,
- // but, if we change the selection, come back and start typing that style should be lost. Also see
- // preserveTypingStyle() below.
- document()->frame()->setTypingStyle(m_typingStyle.get());
-}
-
-void DeleteSelectionCommand::clearTransientState()
-{
- m_selectionToDelete = Selection();
- m_upstreamStart.clear();
- m_downstreamStart.clear();
- m_upstreamEnd.clear();
- m_downstreamEnd.clear();
- m_endingPosition.clear();
- m_leadingWhitespace.clear();
- m_trailingWhitespace.clear();
-}
-
-void DeleteSelectionCommand::saveFullySelectedAnchor()
-{
- // If deleting an anchor element, save it away so that it can be restored
- // when the user begins entering text.
-
- Position start = m_selectionToDelete.start();
- Node* startAnchor = enclosingNodeWithTag(start.downstream(), aTag);
- if (!startAnchor)
- return;
-
- Position end = m_selectionToDelete.end();
- Node* endAnchor = enclosingNodeWithTag(end.upstream(), aTag);
- if (startAnchor != endAnchor)
- return;
-
- VisiblePosition visibleStart(m_selectionToDelete.visibleStart());
- VisiblePosition visibleEnd(m_selectionToDelete.visibleEnd());
-
- Node* beforeStartAnchor = enclosingNodeWithTag(visibleStart.previous().deepEquivalent().downstream(), aTag);
- Node* afterEndAnchor = enclosingNodeWithTag(visibleEnd.next().deepEquivalent().upstream(), aTag);
-
- if (startAnchor && startAnchor == endAnchor && startAnchor != beforeStartAnchor && endAnchor != afterEndAnchor)
- document()->frame()->editor()->setRemovedAnchor(startAnchor->cloneNode(false));
-}
-
-void DeleteSelectionCommand::doApply()
-{
- // If selection has not been set to a custom selection when the command was created,
- // use the current ending selection.
- if (!m_hasSelectionToDelete)
- m_selectionToDelete = endingSelection();
-
- if (!m_selectionToDelete.isRange())
- return;
-
- // If the deletion is occurring in a text field, and we're not deleting to replace the selection, then let the frame call across the bridge to notify the form delegate.
- if (!m_replace) {
- Node* startNode = m_selectionToDelete.start().node();
- Node* ancestorNode = startNode ? startNode->shadowAncestorNode() : 0;
- if (ancestorNode && ancestorNode->hasTagName(inputTag)
- && static_cast<HTMLInputElement*>(ancestorNode)->isTextField()
- && ancestorNode->focused())
- document()->frame()->textWillBeDeletedInTextField(static_cast<Element*>(ancestorNode));
- }
-
- // save this to later make the selection with
- EAffinity affinity = m_selectionToDelete.affinity();
-
- Position downstreamEnd = m_selectionToDelete.end().downstream();
- m_needPlaceholder = isStartOfParagraph(m_selectionToDelete.visibleStart()) &&
- isEndOfParagraph(m_selectionToDelete.visibleEnd()) &&
- !lineBreakExistsAtPosition(m_selectionToDelete.visibleEnd());
- if (m_needPlaceholder) {
- // Don't need a placeholder when deleting a selection that starts just before a table
- // and ends inside it (we do need placeholders to hold open empty cells, but that's
- // handled elsewhere).
- if (Node* table = isLastPositionBeforeTable(m_selectionToDelete.visibleStart()))
- if (m_selectionToDelete.end().node()->isDescendantOf(table))
- m_needPlaceholder = false;
- }
-
-
- // set up our state
- initializePositionData();
-
- // Delete any text that may hinder our ability to fixup whitespace after the delete
- deleteInsignificantTextDownstream(m_trailingWhitespace);
-
- saveTypingStyleState();
-
- saveFullySelectedAnchor();
-
- // deleting just a BR is handled specially, at least because we do not
- // want to replace it with a placeholder BR!
- if (handleSpecialCaseBRDelete()) {
- calculateTypingStyleAfterDelete();
- setEndingSelection(Selection(m_endingPosition, affinity));
- clearTransientState();
- rebalanceWhitespace();
- return;
- }
-
- handleGeneralDelete();
-
- fixupWhitespace();
-
- mergeParagraphs();
-
- removePreviouslySelectedEmptyTableRows();
-
- RefPtr<Node> placeholder = m_needPlaceholder ? createBreakElement(document()).get() : 0;
-
- if (placeholder)
- insertNodeAt(placeholder.get(), m_endingPosition);
-
- rebalanceWhitespaceAt(m_endingPosition);
-
- calculateTypingStyleAfterDelete();
-
- setEndingSelection(Selection(m_endingPosition, affinity));
- clearTransientState();
-}
-
-EditAction DeleteSelectionCommand::editingAction() const
-{
- // Note that DeleteSelectionCommand is also used when the user presses the Delete key,
- // but in that case there's a TypingCommand that supplies the editingAction(), so
- // the Undo menu correctly shows "Undo Typing"
- return EditActionCut;
-}
-
-// Normally deletion doesn't preserve the typing style that was present before it. For example,
-// type a character, Bold, then delete the character and start typing. The Bold typing style shouldn't
-// stick around. Deletion should preserve a typing style that *it* sets, however.
-bool DeleteSelectionCommand::preservesTypingStyle() const
-{
- return m_typingStyle;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/DeleteSelectionCommand.h b/WebCore/editing/DeleteSelectionCommand.h
deleted file mode 100644
index 4a1a817..0000000
--- a/WebCore/editing/DeleteSelectionCommand.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DeleteSelectionCommand_h
-#define DeleteSelectionCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class DeleteSelectionCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<DeleteSelectionCommand> create(Document* document, bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = false)
- {
- return adoptRef(new DeleteSelectionCommand(document, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
- }
- static PassRefPtr<DeleteSelectionCommand> create(const Selection& selection, bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = false)
- {
- return adoptRef(new DeleteSelectionCommand(selection, smartDelete, mergeBlocksAfterDelete, replace, expandForSpecialElements));
- }
-
-private:
- DeleteSelectionCommand(Document*, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements);
- DeleteSelectionCommand(const Selection&, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpecialElements);
-
- virtual void doApply();
- virtual EditAction editingAction() const;
-
- virtual bool preservesTypingStyle() const;
-
- void initializeStartEnd(Position&, Position&);
- void initializePositionData();
- void saveTypingStyleState();
- void saveFullySelectedAnchor();
- void insertPlaceholderForAncestorBlockContent();
- bool handleSpecialCaseBRDelete();
- void handleGeneralDelete();
- void fixupWhitespace();
- void mergeParagraphs();
- void removePreviouslySelectedEmptyTableRows();
- void calculateEndingPosition();
- void calculateTypingStyleAfterDelete();
- void clearTransientState();
- virtual void removeNode(Node*);
- virtual void deleteTextFromNode(Text*, int, int);
-
- bool m_hasSelectionToDelete;
- bool m_smartDelete;
- bool m_mergeBlocksAfterDelete;
- bool m_needPlaceholder;
- bool m_replace;
- bool m_expandForSpecialElements;
-
- // This data is transient and should be cleared at the end of the doApply function.
- Selection m_selectionToDelete;
- Position m_upstreamStart;
- Position m_downstreamStart;
- Position m_upstreamEnd;
- Position m_downstreamEnd;
- Position m_endingPosition;
- Position m_leadingWhitespace;
- Position m_trailingWhitespace;
- RefPtr<Node> m_startBlock;
- RefPtr<Node> m_endBlock;
- RefPtr<CSSMutableStyleDeclaration> m_typingStyle;
- RefPtr<CSSMutableStyleDeclaration> m_deleteIntoBlockquoteStyle;
- RefPtr<Node> m_startRoot;
- RefPtr<Node> m_endRoot;
- RefPtr<Node> m_startTableRow;
- RefPtr<Node> m_endTableRow;
-};
-
-} // namespace WebCore
-
-#endif // DeleteSelectionCommand_h
diff --git a/WebCore/editing/EditAction.h b/WebCore/editing/EditAction.h
deleted file mode 100644
index 8046f3c..0000000
--- a/WebCore/editing/EditAction.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef EditAction_h
-#define EditAction_h
-
-namespace WebCore {
- typedef enum {
- EditActionUnspecified,
- EditActionSetColor,
- EditActionSetBackgroundColor,
- EditActionTurnOffKerning,
- EditActionTightenKerning,
- EditActionLoosenKerning,
- EditActionUseStandardKerning,
- EditActionTurnOffLigatures,
- EditActionUseStandardLigatures,
- EditActionUseAllLigatures,
- EditActionRaiseBaseline,
- EditActionLowerBaseline,
- EditActionSetTraditionalCharacterShape,
- EditActionSetFont,
- EditActionChangeAttributes,
- EditActionAlignLeft,
- EditActionAlignRight,
- EditActionCenter,
- EditActionJustify,
- EditActionSetWritingDirection,
- EditActionSubscript,
- EditActionSuperscript,
- EditActionUnderline,
- EditActionOutline,
- EditActionUnscript,
- EditActionDrag,
- EditActionCut,
- EditActionPaste,
- EditActionPasteFont,
- EditActionPasteRuler,
- EditActionTyping,
- EditActionCreateLink,
- EditActionUnlink,
- EditActionFormatBlock,
- EditActionInsertList,
- EditActionIndent,
- EditActionOutdent
- } EditAction;
-}
-
-#endif
diff --git a/WebCore/editing/EditCommand.cpp b/WebCore/editing/EditCommand.cpp
deleted file mode 100644
index f9f8b80..0000000
--- a/WebCore/editing/EditCommand.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "EditCommand.h"
-
-#include "CompositeEditCommand.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "DeleteButtonController.h"
-#include "Document.h"
-#include "Editor.h"
-#include "Element.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "SelectionController.h"
-#include "VisiblePosition.h"
-#include "htmlediting.h"
-
-namespace WebCore {
-
-EditCommand::EditCommand(Document* document)
- : m_document(document)
- , m_parent(0)
-{
- ASSERT(m_document);
- ASSERT(m_document->frame());
- DeleteButtonController* deleteButton = m_document->frame()->editor()->deleteButtonController();
- setStartingSelection(avoidIntersectionWithNode(m_document->frame()->selection()->selection(), deleteButton ? deleteButton->containerElement() : 0));
- setEndingSelection(m_startingSelection);
-}
-
-EditCommand::~EditCommand()
-{
-}
-
-void EditCommand::apply()
-{
- ASSERT(m_document);
- ASSERT(m_document->frame());
-
- Frame* frame = m_document->frame();
-
- if (!m_parent) {
- if (!endingSelection().isContentRichlyEditable()) {
- switch (editingAction()) {
- case EditActionTyping:
- case EditActionPaste:
- case EditActionDrag:
- case EditActionSetWritingDirection:
- case EditActionCut:
- case EditActionUnspecified:
- break;
- default:
- ASSERT_NOT_REACHED();
- return;
- }
- }
- }
-
- // Changes to the document may have been made since the last editing operation that
- // require a layout, as in <rdar://problem/5658603>. Low level operations, like
- // RemoveNodeCommand, don't require a layout because the high level operations that
- // use them perform one if one is necessary (like for the creation of VisiblePositions).
- if (!m_parent)
- updateLayout();
-
- // All high level commands, and all commands that a TypingCommand spawns, except for
- // text insertions, which should restore a removed anchor, should clear it.
- if (!m_parent && !isTypingCommand())
- frame->editor()->setRemovedAnchor(0);
- if (m_parent && m_parent->isTypingCommand() && !isInsertTextCommand())
- frame->editor()->setRemovedAnchor(0);
-
- DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
- deleteButtonController->disable();
- doApply();
- deleteButtonController->enable();
-
- if (!m_parent) {
- updateLayout();
- frame->editor()->appliedEditing(this);
- }
-}
-
-void EditCommand::unapply()
-{
- ASSERT(m_document);
- ASSERT(m_document->frame());
-
- Frame* frame = m_document->frame();
-
- // Changes to the document may have been made since the last editing operation that
- // require a layout, as in <rdar://problem/5658603>. Low level operations, like
- // RemoveNodeCommand, don't require a layout because the high level operations that
- // use them perform one if one is necessary (like for the creation of VisiblePositions).
- if (!m_parent)
- updateLayout();
-
- DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
- deleteButtonController->disable();
- doUnapply();
- deleteButtonController->enable();
-
- if (!m_parent) {
- updateLayout();
- frame->editor()->unappliedEditing(this);
- }
-}
-
-void EditCommand::reapply()
-{
- ASSERT(m_document);
- ASSERT(m_document->frame());
-
- Frame* frame = m_document->frame();
-
- // Changes to the document may have been made since the last editing operation that
- // require a layout, as in <rdar://problem/5658603>. Low level operations, like
- // RemoveNodeCommand, don't require a layout because the high level operations that
- // use them perform one if one is necessary (like for the creation of VisiblePositions).
- if (!m_parent)
- updateLayout();
-
- DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
- deleteButtonController->disable();
- doReapply();
- deleteButtonController->enable();
-
- if (!m_parent) {
- updateLayout();
- frame->editor()->reappliedEditing(this);
- }
-}
-
-void EditCommand::doReapply()
-{
- doApply();
-}
-
-EditAction EditCommand::editingAction() const
-{
- return EditActionUnspecified;
-}
-
-void EditCommand::setStartingSelection(const Selection& s)
-{
- Element* root = s.rootEditableElement();
- for (EditCommand* cmd = this; ; cmd = cmd->m_parent) {
- cmd->m_startingSelection = s;
- cmd->m_startingRootEditableElement = root;
- if (!cmd->m_parent || cmd->m_parent->isFirstCommand(cmd))
- break;
- }
-}
-
-void EditCommand::setEndingSelection(const Selection &s)
-{
- Element* root = s.rootEditableElement();
- for (EditCommand* cmd = this; cmd; cmd = cmd->m_parent) {
- cmd->m_endingSelection = s;
- cmd->m_endingRootEditableElement = root;
- }
-}
-
-bool EditCommand::preservesTypingStyle() const
-{
- return false;
-}
-
-bool EditCommand::isInsertTextCommand() const
-{
- return false;
-}
-
-bool EditCommand::isTypingCommand() const
-{
- return false;
-}
-
-PassRefPtr<CSSMutableStyleDeclaration> EditCommand::styleAtPosition(const Position &pos)
-{
- RefPtr<CSSMutableStyleDeclaration> style = positionBeforeTabSpan(pos).computedStyle()->copyInheritableProperties();
-
- // FIXME: It seems misleading to also include the typing style when returning the style at some arbitrary
- // position in the document.
- CSSMutableStyleDeclaration* typingStyle = document()->frame()->typingStyle();
- if (typingStyle)
- style->merge(typingStyle);
-
- return style.release();
-}
-
-void EditCommand::updateLayout() const
-{
- document()->updateLayoutIgnorePendingStylesheets();
-}
-
-void EditCommand::setParent(CompositeEditCommand* parent)
-{
- ASSERT(parent);
- ASSERT(!m_parent);
- m_parent = parent;
- m_startingSelection = parent->m_endingSelection;
- m_endingSelection = parent->m_endingSelection;
- m_startingRootEditableElement = parent->m_endingRootEditableElement;
- m_endingRootEditableElement = parent->m_endingRootEditableElement;
-}
-
-void applyCommand(PassRefPtr<EditCommand> command)
-{
- command->apply();
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/EditCommand.h b/WebCore/editing/EditCommand.h
deleted file mode 100644
index 78490f8..0000000
--- a/WebCore/editing/EditCommand.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef EditCommand_h
-#define EditCommand_h
-
-#include "EditAction.h"
-#include "Element.h"
-#include "Selection.h"
-
-namespace WebCore {
-
-class CompositeEditCommand;
-class CSSMutableStyleDeclaration;
-
-class EditCommand : public RefCounted<EditCommand> {
-public:
- virtual ~EditCommand();
-
- void setParent(CompositeEditCommand*);
-
- void apply();
- void unapply();
- void reapply();
-
- virtual EditAction editingAction() const;
-
- const Selection& startingSelection() const { return m_startingSelection; }
- const Selection& endingSelection() const { return m_endingSelection; }
-
- Element* startingRootEditableElement() const { return m_startingRootEditableElement.get(); }
- Element* endingRootEditableElement() const { return m_endingRootEditableElement.get(); }
-
- virtual bool isInsertTextCommand() const;
- virtual bool isTypingCommand() const;
-
- virtual bool preservesTypingStyle() const;
-
-protected:
- EditCommand(Document*);
-
- Document* document() const { return m_document.get(); }
-
- void setStartingSelection(const Selection&);
- void setEndingSelection(const Selection&);
-
- PassRefPtr<CSSMutableStyleDeclaration> styleAtPosition(const Position&);
- void updateLayout() const;
-
-private:
- virtual void doApply() = 0;
- virtual void doUnapply() = 0;
- virtual void doReapply(); // calls doApply()
-
- RefPtr<Document> m_document;
- Selection m_startingSelection;
- Selection m_endingSelection;
- RefPtr<Element> m_startingRootEditableElement;
- RefPtr<Element> m_endingRootEditableElement;
- CompositeEditCommand* m_parent;
-
- friend void applyCommand(PassRefPtr<EditCommand>);
-};
-
-class SimpleEditCommand : public EditCommand {
-protected:
- SimpleEditCommand(Document* document) : EditCommand(document) { }
-};
-
-void applyCommand(PassRefPtr<EditCommand>);
-
-} // namespace WebCore
-
-#endif // EditCommand_h
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
deleted file mode 100644
index 1890338..0000000
--- a/WebCore/editing/Editor.cpp
+++ /dev/null
@@ -1,2074 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Editor.h"
-
-#include "AXObjectCache.h"
-#include "ApplyStyleCommand.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSProperty.h"
-#include "CSSPropertyNames.h"
-#include "ClipboardEvent.h"
-#include "DeleteButtonController.h"
-#include "DeleteSelectionCommand.h"
-#include "DocLoader.h"
-#include "DocumentFragment.h"
-#include "EditorClient.h"
-#include "EventHandler.h"
-#include "EventNames.h"
-#include "FocusController.h"
-#include "Frame.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "HTMLInputElement.h"
-#include "HTMLTextAreaElement.h"
-#include "HitTestResult.h"
-#include "IndentOutdentCommand.h"
-#include "InsertListCommand.h"
-#include "KeyboardEvent.h"
-#include "ModifySelectionListLevel.h"
-#include "Page.h"
-#include "Pasteboard.h"
-#include "RemoveFormatCommand.h"
-#include "RenderBlock.h"
-#include "RenderPart.h"
-#include "ReplaceSelectionCommand.h"
-#include "Sound.h"
-#include "Text.h"
-#include "TextIterator.h"
-#include "TypingCommand.h"
-#include "htmlediting.h"
-#include "markup.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace std;
-using namespace HTMLNames;
-
-// When an event handler has moved the selection outside of a text control
-// we should use the target control's selection for this editing operation.
-Selection Editor::selectionForCommand(Event* event)
-{
- Selection selection = m_frame->selection()->selection();
- if (!event)
- return selection;
- // If the target is a text control, and the current selection is outside of its shadow tree,
- // then use the saved selection for that text control.
- Node* target = event->target()->toNode();
- Node* selectionStart = selection.start().node();
- if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
- if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
- return static_cast<HTMLInputElement*>(target)->selection();
- if (target->hasTagName(textareaTag))
- return static_cast<HTMLTextAreaElement*>(target)->selection();
- }
- return selection;
-}
-
-EditorClient* Editor::client() const
-{
- if (Page* page = m_frame->page())
- return page->editorClient();
- return 0;
-}
-
-void Editor::handleKeyboardEvent(KeyboardEvent* event)
-{
- if (EditorClient* c = client())
- if (selectionForCommand(event).isContentEditable())
- c->handleKeyboardEvent(event);
-}
-
-void Editor::handleInputMethodKeydown(KeyboardEvent* event)
-{
- if (EditorClient* c = client())
- if (selectionForCommand(event).isContentEditable())
- c->handleInputMethodKeydown(event);
-}
-
-bool Editor::canEdit() const
-{
- return m_frame->selection()->isContentEditable();
-}
-
-bool Editor::canEditRichly() const
-{
- return m_frame->selection()->isContentRichlyEditable();
-}
-
-// WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items. They
-// also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
-// We need to use onbeforecopy as a real menu enabler because we allow elements that are not
-// normally selectable to implement copy/paste (like divs, or a document body).
-
-bool Editor::canDHTMLCut()
-{
- return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, ClipboardNumb);
-}
-
-bool Editor::canDHTMLCopy()
-{
- return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb);
-}
-
-bool Editor::canDHTMLPaste()
-{
- return !dispatchCPPEvent(eventNames().beforepasteEvent, ClipboardNumb);
-}
-
-bool Editor::canCut() const
-{
- return canCopy() && canDelete();
-}
-
-static HTMLImageElement* imageElementFromImageDocument(Document* document)
-{
- if (!document)
- return 0;
- if (!document->isImageDocument())
- return 0;
-
- HTMLElement* body = document->body();
- if (!body)
- return 0;
-
- Node* node = body->firstChild();
- if (!node)
- return 0;
- if (!node->hasTagName(imgTag))
- return 0;
- return static_cast<HTMLImageElement*>(node);
-}
-
-bool Editor::canCopy() const
-{
- if (imageElementFromImageDocument(m_frame->document()))
- return true;
- SelectionController* selection = m_frame->selection();
- return selection->isRange() && !selection->isInPasswordField();
-}
-
-bool Editor::canPaste() const
-{
- return canEdit();
-}
-
-bool Editor::canDelete() const
-{
- SelectionController* selection = m_frame->selection();
- return selection->isRange() && selection->isContentEditable();
-}
-
-bool Editor::canDeleteRange(Range* range) const
-{
- ExceptionCode ec = 0;
- Node* startContainer = range->startContainer(ec);
- Node* endContainer = range->endContainer(ec);
- if (!startContainer || !endContainer)
- return false;
-
- if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
- return false;
-
- if (range->collapsed(ec)) {
- VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
- VisiblePosition previous = start.previous();
- // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
- if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
- return false;
- }
- return true;
-}
-
-bool Editor::smartInsertDeleteEnabled()
-{
- return client() && client()->smartInsertDeleteEnabled();
-}
-
-bool Editor::canSmartCopyOrDelete()
-{
- return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
-}
-
-bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
-{
- // Delete the selection, if there is one.
- // If not, make a selection using the passed-in direction and granularity.
-
- if (!canEdit())
- return false;
-
- if (m_frame->selection()->isRange()) {
- if (killRing)
- addToKillRing(selectedRange().get(), false);
- if (isTypingAction) {
- if (m_frame->document()) {
- TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity);
- revealSelectionAfterEditingOperation();
- }
- } else {
- deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
- // Implicitly calls revealSelectionAfterEditingOperation().
- }
- } else {
- SelectionController selectionToDelete;
- selectionToDelete.setSelection(m_frame->selection()->selection());
- selectionToDelete.modify(SelectionController::EXTEND, direction, granularity);
- if (killRing && selectionToDelete.isCaret() && granularity != CharacterGranularity)
- selectionToDelete.modify(SelectionController::EXTEND, direction, CharacterGranularity);
-
- RefPtr<Range> range = selectionToDelete.toRange();
-
- if (killRing)
- addToKillRing(range.get(), false);
-
- if (!m_frame->selection()->setSelectedRange(range.get(), DOWNSTREAM, (granularity != CharacterGranularity)))
- return true;
-
- switch (direction) {
- case SelectionController::FORWARD:
- case SelectionController::RIGHT:
- if (m_frame->document())
- TypingCommand::forwardDeleteKeyPressed(m_frame->document(), false, granularity);
- break;
- case SelectionController::BACKWARD:
- case SelectionController::LEFT:
- if (m_frame->document())
- TypingCommand::deleteKeyPressed(m_frame->document(), false, granularity);
- break;
- }
- revealSelectionAfterEditingOperation();
- }
-
- // clear the "start new kill ring sequence" setting, because it was set to true
- // when the selection was updated by deleting the range
- if (killRing)
- setStartNewKillRingSequence(false);
-
- return true;
-}
-
-void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
-{
- if (m_frame->selection()->isNone())
- return;
-
- applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));
-}
-
-void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
-{
- String text = pasteboard->plainText(m_frame);
- if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
- replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
-}
-
-void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
-{
- RefPtr<Range> range = selectedRange();
- bool chosePlainText;
- RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
- if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
- replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
-}
-
-bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
-{
- return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
-}
-
-bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
-{
- if (!client())
- return false;
-
- Node* child = fragment->firstChild();
- if (child && fragment->lastChild() == child && child->isCharacterDataNode())
- return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
-
- return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
-}
-
-void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
-{
- if (m_frame->selection()->isNone() || !fragment)
- return;
-
- applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
- revealSelectionAfterEditingOperation();
-}
-
-void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
-{
- replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true);
-}
-
-PassRefPtr<Range> Editor::selectedRange()
-{
- if (!m_frame)
- return 0;
- return m_frame->selection()->toRange();
-}
-
-bool Editor::shouldDeleteRange(Range* range) const
-{
- ExceptionCode ec;
- if (!range || range->collapsed(ec))
- return false;
-
- if (!canDeleteRange(range))
- return false;
-
- return client() && client()->shouldDeleteRange(range);
-}
-
-bool Editor::tryDHTMLCopy()
-{
- if (m_frame->selection()->isInPasswordField())
- return false;
-
- // Must be done before oncopy adds types and data to the pboard,
- // also done for security, as it erases data from the last copy/paste.
- Pasteboard::generalPasteboard()->clear();
-
- return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);
-}
-
-bool Editor::tryDHTMLCut()
-{
- if (m_frame->selection()->isInPasswordField())
- return false;
-
- // Must be done before oncut adds types and data to the pboard,
- // also done for security, as it erases data from the last copy/paste.
- Pasteboard::generalPasteboard()->clear();
-
- return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable);
-}
-
-bool Editor::tryDHTMLPaste()
-{
- return !dispatchCPPEvent(eventNames().pasteEvent, ClipboardReadable);
-}
-
-void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
-{
- pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
-}
-
-bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
-{
- return client() && client()->shouldInsertText(text, range, action);
-}
-
-bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
-{
- return client() && client()->shouldShowDeleteInterface(element);
-}
-
-void Editor::respondToChangedSelection(const Selection& oldSelection)
-{
- if (client())
- client()->respondToChangedSelection();
- m_deleteButtonController->respondToChangedSelection(oldSelection);
-}
-
-void Editor::respondToChangedContents(const Selection& endingSelection)
-{
- if (AXObjectCache::accessibilityEnabled()) {
- Node* node = endingSelection.start().node();
- if (node)
- m_frame->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
- }
-
- if (client())
- client()->respondToChangedContents();
-}
-
-const SimpleFontData* Editor::fontForSelection(bool& hasMultipleFonts) const
-{
-#if !PLATFORM(QT)
- hasMultipleFonts = false;
-
- if (!m_frame->selection()->isRange()) {
- Node* nodeToRemove;
- RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
-
- const SimpleFontData* result = 0;
- if (style)
- result = style->font().primaryFont();
-
- if (nodeToRemove) {
- ExceptionCode ec;
- nodeToRemove->remove(ec);
- ASSERT(ec == 0);
- }
-
- return result;
- }
-
- const SimpleFontData* font = 0;
-
- RefPtr<Range> range = m_frame->selection()->toRange();
- Node* startNode = range->editingStartPosition().node();
- if (startNode) {
- Node* pastEnd = range->pastLastNode();
- // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
- // unreproducible case where this didn't happen, so check for nil also.
- for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
- RenderObject *renderer = n->renderer();
- if (!renderer)
- continue;
- // FIXME: Are there any node types that have renderers, but that we should be skipping?
- const SimpleFontData* f = renderer->style()->font().primaryFont();
- if (!font)
- font = f;
- else if (font != f) {
- hasMultipleFonts = true;
- break;
- }
- }
- }
-
- return font;
-#else
- return 0;
-#endif
-}
-
-TriState Editor::selectionUnorderedListState() const
-{
- if (m_frame->selection()->isCaret()) {
- if (enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag))
- return TrueTriState;
- } else if (m_frame->selection()->isRange()) {
- Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), ulTag);
- Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), ulTag);
- if (startNode && endNode && startNode == endNode)
- return TrueTriState;
- }
-
- return FalseTriState;
-}
-
-TriState Editor::selectionOrderedListState() const
-{
- if (m_frame->selection()->isCaret()) {
- if (enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag))
- return TrueTriState;
- } else if (m_frame->selection()->isRange()) {
- Node* startNode = enclosingNodeWithTag(m_frame->selection()->selection().start(), olTag);
- Node* endNode = enclosingNodeWithTag(m_frame->selection()->selection().end(), olTag);
- if (startNode && endNode && startNode == endNode)
- return TrueTriState;
- }
-
- return FalseTriState;
-}
-
-PassRefPtr<Node> Editor::insertOrderedList()
-{
- if (!canEditRichly())
- return 0;
-
- RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::OrderedList);
- revealSelectionAfterEditingOperation();
- return newList;
-}
-
-PassRefPtr<Node> Editor::insertUnorderedList()
-{
- if (!canEditRichly())
- return 0;
-
- RefPtr<Node> newList = InsertListCommand::insertList(m_frame->document(), InsertListCommand::UnorderedList);
- revealSelectionAfterEditingOperation();
- return newList;
-}
-
-bool Editor::canIncreaseSelectionListLevel()
-{
- return canEditRichly() && IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(m_frame->document());
-}
-
-bool Editor::canDecreaseSelectionListLevel()
-{
- return canEditRichly() && DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(m_frame->document());
-}
-
-PassRefPtr<Node> Editor::increaseSelectionListLevel()
-{
- if (!canEditRichly() || m_frame->selection()->isNone())
- return 0;
-
- RefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevel(m_frame->document());
- revealSelectionAfterEditingOperation();
- return newList;
-}
-
-PassRefPtr<Node> Editor::increaseSelectionListLevelOrdered()
-{
- if (!canEditRichly() || m_frame->selection()->isNone())
- return 0;
-
- PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(m_frame->document());
- revealSelectionAfterEditingOperation();
- return newList;
-}
-
-PassRefPtr<Node> Editor::increaseSelectionListLevelUnordered()
-{
- if (!canEditRichly() || m_frame->selection()->isNone())
- return 0;
-
- PassRefPtr<Node> newList = IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(m_frame->document());
- revealSelectionAfterEditingOperation();
- return newList;
-}
-
-void Editor::decreaseSelectionListLevel()
-{
- if (!canEditRichly() || m_frame->selection()->isNone())
- return;
-
- DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(m_frame->document());
- revealSelectionAfterEditingOperation();
-}
-
-void Editor::removeFormattingAndStyle()
-{
- applyCommand(RemoveFormatCommand::create(m_frame->document()));
-}
-
-void Editor::clearLastEditCommand()
-{
- m_lastEditCommand.clear();
-}
-
-// Returns whether caller should continue with "the default processing", which is the same as
-// the event handler NOT setting the return value to false
-bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
-{
- Node* target = m_frame->selection()->start().element();
- if (!target && m_frame->document())
- target = m_frame->document()->body();
- if (!target)
- return true;
- target = target->shadowAncestorNode();
-
- RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
-
- ExceptionCode ec = 0;
- RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
- EventTargetNodeCast(target)->dispatchEvent(evt, ec);
- bool noDefaultProcessing = evt->defaultPrevented();
-
- // invalidate clipboard here for security
- clipboard->setAccessPolicy(ClipboardNumb);
-
- return !noDefaultProcessing;
-}
-
-void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
-{
- switch (m_frame->selection()->state()) {
- case Selection::NONE:
- // do nothing
- break;
- case Selection::CARET:
- m_frame->computeAndSetTypingStyle(style, editingAction);
- break;
- case Selection::RANGE:
- if (m_frame->document() && style)
- applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction));
- break;
- }
-}
-
-bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
-{
- return client()->shouldApplyStyle(style, range);
-}
-
-void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
-{
- switch (m_frame->selection()->state()) {
- case Selection::NONE:
- // do nothing
- break;
- case Selection::CARET:
- case Selection::RANGE:
- if (m_frame->document() && style)
- applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
- break;
- }
-}
-
-void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
-{
- if (!style || style->length() == 0 || !canEditRichly())
- return;
-
- if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toRange().get()))
- applyStyle(style, editingAction);
-}
-
-void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
-{
- if (!style || style->length() == 0 || !canEditRichly())
- return;
-
- if (client() && client()->shouldApplyStyle(style, m_frame->selection()->toRange().get()))
- applyParagraphStyle(style, editingAction);
-}
-
-bool Editor::clientIsEditable() const
-{
- return client() && client()->isEditable();
-}
-
-bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
-{
- Node* nodeToRemove;
- RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
- if (!selectionStyle)
- return false;
-
- RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
-
- bool match = true;
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
- int propertyID = (*it).id();
- if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
- match = false;
- break;
- }
- }
-
- if (nodeToRemove) {
- ExceptionCode ec = 0;
- nodeToRemove->remove(ec);
- ASSERT(ec == 0);
- }
-
- return match;
-}
-
-static void updateState(CSSMutableStyleDeclaration* desiredStyle, CSSComputedStyleDeclaration* computedStyle, bool& atStart, TriState& state)
-{
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
- int propertyID = (*it).id();
- String desiredProperty = desiredStyle->getPropertyValue(propertyID);
- String computedProperty = computedStyle->getPropertyValue(propertyID);
- TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
- ? TrueTriState : FalseTriState;
- if (atStart) {
- state = propertyState;
- atStart = false;
- } else if (state != propertyState) {
- state = MixedTriState;
- break;
- }
- }
-}
-
-TriState Editor::selectionHasStyle(CSSStyleDeclaration* style) const
-{
- bool atStart = true;
- TriState state = FalseTriState;
-
- RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
-
- if (!m_frame->selection()->isRange()) {
- Node* nodeToRemove;
- RefPtr<CSSComputedStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
- if (!selectionStyle)
- return FalseTriState;
- updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
- if (nodeToRemove) {
- ExceptionCode ec = 0;
- nodeToRemove->remove(ec);
- ASSERT(ec == 0);
- }
- } else {
- for (Node* node = m_frame->selection()->start().node(); node; node = node->traverseNextNode()) {
- RefPtr<CSSComputedStyleDeclaration> nodeStyle = computedStyle(node);
- if (nodeStyle)
- updateState(mutableStyle.get(), nodeStyle.get(), atStart, state);
- if (state == MixedTriState)
- break;
- if (node == m_frame->selection()->end().node())
- break;
- }
- }
-
- return state;
-}
-void Editor::indent()
-{
- applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
-}
-
-void Editor::outdent()
-{
- applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Outdent));
-}
-
-static void dispatchEditableContentChangedEvents(const EditCommand& command)
-{
- Element* startRoot = command.startingRootEditableElement();
- Element* endRoot = command.endingRootEditableElement();
- ExceptionCode ec;
- if (startRoot)
- startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
- if (endRoot && endRoot != startRoot)
- endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false), ec);
-}
-
-void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
-{
- dispatchEditableContentChangedEvents(*cmd);
-
- Selection newSelection(cmd->endingSelection());
- // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
- // because there is work that it must do in this situation.
- // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
- // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
- // Don't clear the typing style or removedAnchor with this selection change. We do those things elsewhere if necessary.
- if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
- m_frame->selection()->setSelection(newSelection, false, false);
-
- if (!cmd->preservesTypingStyle())
- m_frame->setTypingStyle(0);
-
- // Command will be equal to last edit command only in the case of typing
- if (m_lastEditCommand.get() == cmd)
- ASSERT(cmd->isTypingCommand());
- else {
- // Only register a new undo command if the command passed in is
- // different from the last command
- m_lastEditCommand = cmd;
- if (client())
- client()->registerCommandForUndo(m_lastEditCommand);
- }
- respondToChangedContents(newSelection);
-}
-
-void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
-{
- dispatchEditableContentChangedEvents(*cmd);
-
- Selection newSelection(cmd->startingSelection());
- // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
- // because there is work that it must do in this situation.
- // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
- // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
- if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
- m_frame->selection()->setSelection(newSelection, true);
-
- m_lastEditCommand = 0;
- if (client())
- client()->registerCommandForRedo(cmd);
- respondToChangedContents(newSelection);
-}
-
-void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
-{
- dispatchEditableContentChangedEvents(*cmd);
-
- Selection newSelection(cmd->endingSelection());
- // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
- // because there is work that it must do in this situation.
- // The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
- // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
- if (newSelection == m_frame->selection()->selection() || m_frame->shouldChangeSelection(newSelection))
- m_frame->selection()->setSelection(newSelection, true);
-
- m_lastEditCommand = 0;
- if (client())
- client()->registerCommandForUndo(cmd);
- respondToChangedContents(newSelection);
-}
-
-Editor::Editor(Frame* frame)
- : m_frame(frame)
- , m_deleteButtonController(new DeleteButtonController(frame))
- , m_ignoreCompositionSelectionChange(false)
- , m_shouldStartNewKillRingSequence(false)
-{
-}
-
-Editor::~Editor()
-{
-}
-
-void Editor::clear()
-{
- m_compositionNode = 0;
- m_customCompositionUnderlines.clear();
-}
-
-bool Editor::insertText(const String& text, Event* triggeringEvent)
-{
- return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
-}
-
-bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
-{
- if (text.isEmpty())
- return false;
-
- Selection selection = selectionForCommand(triggeringEvent);
- if (!selection.isContentEditable())
- return false;
- RefPtr<Range> range = selection.toRange();
-
- if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
- return true;
-
- // Get the selection to use for the event that triggered this insertText.
- // If the event handler changed the selection, we may want to use a different selection
- // that is contained in the event target.
- selection = selectionForCommand(triggeringEvent);
- if (selection.isContentEditable()) {
- if (Node* selectionStart = selection.start().node()) {
- RefPtr<Document> document = selectionStart->document();
-
- // Insert the text
- TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
-
- // Reveal the current selection
- if (Frame* editedFrame = document->frame())
- if (Page* page = editedFrame->page())
- page->focusController()->focusedOrMainFrame()->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
- }
- }
-
- return true;
-}
-
-bool Editor::insertLineBreak()
-{
- if (!canEdit())
- return false;
-
- if (!shouldInsertText("\n", m_frame->selection()->toRange().get(), EditorInsertActionTyped))
- return true;
-
- TypingCommand::insertLineBreak(m_frame->document());
- revealSelectionAfterEditingOperation();
- return true;
-}
-
-bool Editor::insertParagraphSeparator()
-{
- if (!canEdit())
- return false;
-
- if (!canEditRichly())
- return insertLineBreak();
-
- if (!shouldInsertText("\n", m_frame->selection()->toRange().get(), EditorInsertActionTyped))
- return true;
-
- TypingCommand::insertParagraphSeparator(m_frame->document());
- revealSelectionAfterEditingOperation();
- return true;
-}
-
-void Editor::cut()
-{
- if (tryDHTMLCut())
- return; // DHTML did the whole operation
- if (!canCut()) {
- systemBeep();
- return;
- }
- RefPtr<Range> selection = selectedRange();
- if (shouldDeleteRange(selection.get())) {
- Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
- didWriteSelectionToPasteboard();
- deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
- }
-}
-
-void Editor::copy()
-{
- if (tryDHTMLCopy())
- return; // DHTML did the whole operation
- if (!canCopy()) {
- systemBeep();
- return;
- }
-
- Document* document = m_frame->document();
- if (HTMLImageElement* imageElement = imageElementFromImageDocument(document))
- Pasteboard::generalPasteboard()->writeImage(imageElement, document->url(), document->title());
- else
- Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
-
- didWriteSelectionToPasteboard();
-}
-
-#if !PLATFORM(MAC)
-
-void Editor::paste()
-{
- ASSERT(m_frame->document());
- if (tryDHTMLPaste())
- return; // DHTML did the whole operation
- if (!canPaste())
- return;
- DocLoader* loader = m_frame->document()->docLoader();
- loader->setAllowStaleResources(true);
- if (m_frame->selection()->isContentRichlyEditable())
- pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
- else
- pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
- loader->setAllowStaleResources(false);
-}
-
-#endif
-
-void Editor::pasteAsPlainText()
-{
- if (!canPaste())
- return;
- pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
-}
-
-void Editor::performDelete()
-{
- if (!canDelete()) {
- systemBeep();
- return;
- }
-
- addToKillRing(selectedRange().get(), false);
- deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
-
- // clear the "start new kill ring sequence" setting, because it was set to true
- // when the selection was updated by deleting the range
- setStartNewKillRingSequence(false);
-}
-
-void Editor::copyURL(const KURL& url, const String& title)
-{
- Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
-}
-
-void Editor::copyImage(const HitTestResult& result)
-{
- KURL url = result.absoluteLinkURL();
- if (url.isEmpty())
- url = result.absoluteImageURL();
-
- Pasteboard::generalPasteboard()->writeImage(result.innerNonSharedNode(), url, result.altDisplayString());
-}
-
-bool Editor::isContinuousSpellCheckingEnabled()
-{
- return client() && client()->isContinuousSpellCheckingEnabled();
-}
-
-void Editor::toggleContinuousSpellChecking()
-{
- if (client())
- client()->toggleContinuousSpellChecking();
-}
-
-bool Editor::isGrammarCheckingEnabled()
-{
- return client() && client()->isGrammarCheckingEnabled();
-}
-
-void Editor::toggleGrammarChecking()
-{
- if (client())
- client()->toggleGrammarChecking();
-}
-
-int Editor::spellCheckerDocumentTag()
-{
- return client() ? client()->spellCheckerDocumentTag() : 0;
-}
-
-bool Editor::shouldEndEditing(Range* range)
-{
- return client() && client()->shouldEndEditing(range);
-}
-
-bool Editor::shouldBeginEditing(Range* range)
-{
- return client() && client()->shouldBeginEditing(range);
-}
-
-void Editor::clearUndoRedoOperations()
-{
- if (client())
- client()->clearUndoRedoOperations();
-}
-
-bool Editor::canUndo()
-{
- return client() && client()->canUndo();
-}
-
-void Editor::undo()
-{
- if (client())
- client()->undo();
-}
-
-bool Editor::canRedo()
-{
- return client() && client()->canRedo();
-}
-
-void Editor::redo()
-{
- if (client())
- client()->redo();
-}
-
-void Editor::didBeginEditing()
-{
- if (client())
- client()->didBeginEditing();
-}
-
-void Editor::didEndEditing()
-{
- if (client())
- client()->didEndEditing();
-}
-
-void Editor::didWriteSelectionToPasteboard()
-{
- if (client())
- client()->didWriteSelectionToPasteboard();
-}
-
-void Editor::toggleBold()
-{
- command("ToggleBold").execute();
-}
-
-void Editor::toggleUnderline()
-{
- command("ToggleUnderline").execute();
-}
-
-void Editor::setBaseWritingDirection(WritingDirection direction)
-{
- Node* focusedNode = frame()->document()->focusedNode();
- if (focusedNode && (focusedNode->hasTagName(textareaTag)
- || focusedNode->hasTagName(inputTag) && (static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::TEXT
- || static_cast<HTMLInputElement*>(focusedNode)->inputType() == HTMLInputElement::SEARCH))) {
- if (direction == NaturalWritingDirection)
- return;
- static_cast<HTMLElement*>(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
- frame()->document()->updateRendering();
- return;
- }
-
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDirection ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", false);
- applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
-}
-
-void Editor::selectComposition()
-{
- RefPtr<Range> range = compositionRange();
- if (!range)
- return;
-
- // The composition can start inside a composed character sequence, so we have to override checks.
- // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
- Selection selection;
- selection.setWithoutValidation(range->startPosition(), range->endPosition());
- m_frame->selection()->setSelection(selection, false, false);
-}
-
-void Editor::confirmComposition()
-{
- if (!m_compositionNode)
- return;
- confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
-}
-
-void Editor::confirmCompositionWithoutDisturbingSelection()
-{
- if (!m_compositionNode)
- return;
- confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
-}
-
-void Editor::confirmComposition(const String& text)
-{
- confirmComposition(text, false);
-}
-
-void Editor::confirmComposition(const String& text, bool preserveSelection)
-{
- setIgnoreCompositionSelectionChange(true);
-
- Selection oldSelection = m_frame->selection()->selection();
-
- selectComposition();
-
- if (m_frame->selection()->isNone()) {
- setIgnoreCompositionSelectionChange(false);
- return;
- }
-
- // If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
- // will delete the old composition with an optimized replace operation.
- if (text.isEmpty())
- TypingCommand::deleteSelection(m_frame->document(), false);
-
- m_compositionNode = 0;
- m_customCompositionUnderlines.clear();
-
- insertText(text, 0);
-
- if (preserveSelection)
- m_frame->selection()->setSelection(oldSelection, false, false);
-
- setIgnoreCompositionSelectionChange(false);
-}
-
-void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
-{
- setIgnoreCompositionSelectionChange(true);
-
- selectComposition();
-
- if (m_frame->selection()->isNone()) {
- setIgnoreCompositionSelectionChange(false);
- return;
- }
-
- // If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
- // will delete the old composition with an optimized replace operation.
- if (text.isEmpty())
- TypingCommand::deleteSelection(m_frame->document(), false);
-
- m_compositionNode = 0;
- m_customCompositionUnderlines.clear();
-
- if (!text.isEmpty()) {
- TypingCommand::insertText(m_frame->document(), text, true, true);
-
- Node* baseNode = m_frame->selection()->base().node();
- unsigned baseOffset = m_frame->selection()->base().offset();
- Node* extentNode = m_frame->selection()->extent().node();
- unsigned extentOffset = m_frame->selection()->extent().offset();
-
- if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
- m_compositionNode = static_cast<Text*>(baseNode);
- m_compositionStart = baseOffset;
- m_compositionEnd = extentOffset;
- m_customCompositionUnderlines = underlines;
- size_t numUnderlines = m_customCompositionUnderlines.size();
- for (size_t i = 0; i < numUnderlines; ++i) {
- m_customCompositionUnderlines[i].startOffset += baseOffset;
- m_customCompositionUnderlines[i].endOffset += baseOffset;
- }
- if (baseNode->renderer())
- baseNode->renderer()->repaint();
-
- unsigned start = min(baseOffset + selectionStart, extentOffset);
- unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
- RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);
- m_frame->selection()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
- }
- }
-
- setIgnoreCompositionSelectionChange(false);
-}
-
-void Editor::ignoreSpelling()
-{
- if (!client())
- return;
-
- RefPtr<Range> selectedRange = frame()->selection()->toRange();
- if (selectedRange)
- frame()->document()->removeMarkers(selectedRange.get(), DocumentMarker::Spelling);
-
- String text = frame()->selectedText();
- ASSERT(text.length() != 0);
- client()->ignoreWordInSpellDocument(text);
-}
-
-void Editor::learnSpelling()
-{
- if (!client())
- return;
-
- // FIXME: We don't call this on the Mac, and it should remove misppelling markers around the
- // learned word, see <rdar://problem/5396072>.
-
- String text = frame()->selectedText();
- ASSERT(text.length() != 0);
- client()->learnWord(text);
-}
-
-static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll)
-{
- ASSERT_ARG(client, client);
- ASSERT_ARG(searchRange, searchRange);
-
- WordAwareIterator it(searchRange);
- firstMisspellingOffset = 0;
-
- String firstMisspelling;
- int currentChunkOffset = 0;
-
- while (!it.atEnd()) {
- const UChar* chars = it.characters();
- int len = it.length();
-
- // Skip some work for one-space-char hunks
- if (!(len == 1 && chars[0] == ' ')) {
-
- int misspellingLocation = -1;
- int misspellingLength = 0;
- client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);
-
- // 5490627 shows that there was some code path here where the String constructor below crashes.
- // We don't know exactly what combination of bad input caused this, so we're making this much
- // more robust against bad input on release builds.
- ASSERT(misspellingLength >= 0);
- ASSERT(misspellingLocation >= -1);
- ASSERT(misspellingLength == 0 || misspellingLocation >= 0);
- ASSERT(misspellingLocation < len);
- ASSERT(misspellingLength <= len);
- ASSERT(misspellingLocation + misspellingLength <= len);
-
- if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {
-
- // Remember first-encountered misspelling and its offset
- if (!firstMisspelling) {
- firstMisspellingOffset = currentChunkOffset + misspellingLocation;
- firstMisspelling = String(chars + misspellingLocation, misspellingLength);
- }
-
- // Mark this instance if we're marking all instances. Otherwise bail out because we found the first one.
- if (!markAll)
- break;
-
- // Compute range of misspelled word
- RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
-
- // Store marker for misspelled word
- ExceptionCode ec = 0;
- misspellingRange->startContainer(ec)->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
- ASSERT(ec == 0);
- }
- }
-
- currentChunkOffset += len;
- it.advance();
- }
-
- return firstMisspelling;
-}
-
-#ifndef BUILDING_ON_TIGER
-
-static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
-{
- ASSERT_ARG(arbitraryRange, arbitraryRange);
-
- ExceptionCode ec = 0;
-
- // Expand range to paragraph boundaries
- RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
- setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
- setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
-
- // Compute offset from start of expanded range to start of original range
- RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());
- offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
-
- // Fill in out parameter with string representing entire paragraph range.
- // Someday we might have a caller that doesn't use this, but for now all callers do.
- paragraphString = plainText(paragraphRange.get());
-
- return paragraphRange;
-}
-
-static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int badGrammarPhraseLength, Range *searchRange, int startOffset, int endOffset, bool markAll)
-{
- // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
- // Optionally add a DocumentMarker for each detail in the range.
- int earliestDetailLocationSoFar = -1;
- int earliestDetailIndex = -1;
- for (unsigned i = 0; i < grammarDetails.size(); i++) {
- const GrammarDetail* detail = &grammarDetails[i];
- ASSERT(detail->length > 0 && detail->location >= 0);
-
- int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
-
- // Skip this detail if it starts before the original search range
- if (detailStartOffsetInParagraph < startOffset)
- continue;
-
- // Skip this detail if it starts after the original search range
- if (detailStartOffsetInParagraph >= endOffset)
- continue;
-
- if (markAll) {
- RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
- ExceptionCode ec = 0;
- badGrammarRange->startContainer(ec)->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
- ASSERT(ec == 0);
- }
-
- // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
- if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
- earliestDetailIndex = i;
- earliestDetailLocationSoFar = detail->location;
- }
- }
-
- return earliestDetailIndex;
-}
-
-static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
-{
- ASSERT_ARG(client, client);
- ASSERT_ARG(searchRange, searchRange);
-
- // Initialize out parameters; these will be updated if we find something to return.
- outGrammarDetail.location = -1;
- outGrammarDetail.length = 0;
- outGrammarDetail.guesses.clear();
- outGrammarDetail.userDescription = "";
- outGrammarPhraseOffset = 0;
-
- String firstBadGrammarPhrase;
-
- // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.
- // Determine the character offset from the start of the paragraph to the start of the original search range,
- // since we will want to ignore results in this area.
- int searchRangeStartOffset;
- String paragraphString;
- RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);
-
- // Determine the character offset from the start of the paragraph to the end of the original search range,
- // since we will want to ignore results in this area also.
- int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);
-
- // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.
- int startOffset = 0;
- while (startOffset < searchRangeEndOffset) {
- Vector<GrammarDetail> grammarDetails;
- int badGrammarPhraseLocation = -1;
- int badGrammarPhraseLength = 0;
- client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
-
- if (badGrammarPhraseLength == 0) {
- ASSERT(badGrammarPhraseLocation == -1);
- return String();
- }
-
- ASSERT(badGrammarPhraseLocation >= 0);
- badGrammarPhraseLocation += startOffset;
-
-
- // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
- int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
- if (badGrammarIndex >= 0) {
- ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
- outGrammarDetail = grammarDetails[badGrammarIndex];
- }
-
- // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
- // kept going so we could mark all instances).
- if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
- outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
- firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
-
- // Found one. We're done now, unless we're marking each instance.
- if (!markAll)
- break;
- }
-
- // These results were all between the start of the paragraph and the start of the search range; look
- // beyond this phrase.
- startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
- }
-
- return firstBadGrammarPhrase;
-}
-
-#endif /* not BUILDING_ON_TIGER */
-
-void Editor::advanceToNextMisspelling(bool startBeforeSelection)
-{
- ExceptionCode ec = 0;
-
- // The basic approach is to search in two phases - from the selection end to the end of the doc, and
- // then we wrap and search from the doc start to (approximately) where we started.
-
- // Start at the end of the selection, search to edge of document. Starting at the selection end makes
- // repeated "check spelling" commands work.
- Selection selection(frame()->selection()->selection());
- RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
- bool startedWithSelection = false;
- if (selection.start().node()) {
- startedWithSelection = true;
- if (startBeforeSelection) {
- VisiblePosition start(selection.visibleStart());
- // We match AppKit's rule: Start 1 character before the selection.
- VisiblePosition oneBeforeStart = start.previous();
- setStart(spellingSearchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
- } else
- setStart(spellingSearchRange.get(), selection.visibleEnd());
- }
-
- Position position = spellingSearchRange->startPosition();
- if (!isEditablePosition(position)) {
- // This shouldn't happen in very often because the Spelling menu items aren't enabled unless the
- // selection is editable.
- // This can happen in Mail for a mix of non-editable and editable content (like Stationary),
- // when spell checking the whole document before sending the message.
- // In that case the document might not be editable, but there are editable pockets that need to be spell checked.
-
- position = firstEditablePositionAfterPositionInRoot(position, frame()->document()->documentElement()).deepEquivalent();
- if (position.isNull())
- return;
-
- Position rangeCompliantPosition = rangeCompliantEquivalent(position);
- spellingSearchRange->setStart(rangeCompliantPosition.node(), rangeCompliantPosition.offset(), ec);
- startedWithSelection = false; // won't need to wrap
- }
-
- // topNode defines the whole range we want to operate on
- Node* topNode = highestEditableRoot(position);
- spellingSearchRange->setEnd(topNode, maxDeepOffset(topNode), ec);
-
- // If spellingSearchRange starts in the middle of a word, advance to the next word so we start checking
- // at a word boundary. Going back by one char and then forward by a word does the trick.
- if (startedWithSelection) {
- VisiblePosition oneBeforeStart = startVisiblePosition(spellingSearchRange.get(), DOWNSTREAM).previous();
- if (oneBeforeStart.isNotNull()) {
- setStart(spellingSearchRange.get(), endOfWord(oneBeforeStart));
- } // else we were already at the start of the editable node
- }
-
- if (spellingSearchRange->collapsed(ec))
- return; // nothing to search in
-
- // Get the spell checker if it is available
- if (!client())
- return;
-
- // We go to the end of our first range instead of the start of it, just to be sure
- // we don't get foiled by any word boundary problems at the start. It means we might
- // do a tiny bit more searching.
- Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec);
- int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec);
-
- int misspellingOffset;
- String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
-
- String badGrammarPhrase;
-
-#ifndef BUILDING_ON_TIGER
- int grammarPhraseOffset = 0;
- GrammarDetail grammarDetail;
-
- // Search for bad grammar that occurs prior to the next misspelled word (if any)
- RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec);
- if (!misspelledWord.isEmpty()) {
- // Stop looking at start of next misspelled word
- CharacterIterator chars(grammarSearchRange.get());
- chars.advance(misspellingOffset);
- grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
- }
-
- if (isGrammarCheckingEnabled())
- badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
-#endif
-
- // If we found neither bad grammar nor a misspelled word, wrap and try again (but don't bother if we started at the beginning of the
- // block rather than at a selection).
- if (startedWithSelection && !misspelledWord && !badGrammarPhrase) {
- spellingSearchRange->setStart(topNode, 0, ec);
- // going until the end of the very first chunk we tested is far enough
- spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfterWrap, ec);
-
- misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false);
-
-#ifndef BUILDING_ON_TIGER
- grammarSearchRange = spellingSearchRange->cloneRange(ec);
- if (!misspelledWord.isEmpty()) {
- // Stop looking at start of next misspelled word
- CharacterIterator chars(grammarSearchRange.get());
- chars.advance(misspellingOffset);
- grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
- }
- if (isGrammarCheckingEnabled())
- badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
-#endif
- }
-
- if (!badGrammarPhrase.isEmpty()) {
-#ifdef BUILDING_ON_TIGER
- ASSERT_NOT_REACHED();
-#else
- // We found bad grammar. Since we only searched for bad grammar up to the first misspelled word, the bad grammar
- // takes precedence and we ignore any potential misspelled word. Select the grammar detail, update the spelling
- // panel, and store a marker so we draw the green squiggle later.
-
- ASSERT(badGrammarPhrase.length() > 0);
- ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0);
-
- // FIXME 4859190: This gets confused with doubled punctuation at the end of a paragraph
- RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarSearchRange.get(), grammarPhraseOffset + grammarDetail.location, grammarDetail.length);
- frame()->selection()->setSelection(Selection(badGrammarRange.get(), SEL_DEFAULT_AFFINITY));
- frame()->revealSelection();
-
- client()->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
- frame()->document()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, grammarDetail.userDescription);
-#endif
- } else if (!misspelledWord.isEmpty()) {
- // We found a misspelling, but not any earlier bad grammar. Select the misspelling, update the spelling panel, and store
- // a marker so we draw the red squiggle later.
-
- RefPtr<Range> misspellingRange = TextIterator::subrange(spellingSearchRange.get(), misspellingOffset, misspelledWord.length());
- frame()->selection()->setSelection(Selection(misspellingRange.get(), DOWNSTREAM));
- frame()->revealSelection();
-
- client()->updateSpellingUIWithMisspelledWord(misspelledWord);
- frame()->document()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
- }
-}
-
-bool Editor::isSelectionMisspelled()
-{
- String selectedString = frame()->selectedText();
- int length = selectedString.length();
- if (length == 0)
- return false;
-
- if (!client())
- return false;
-
- int misspellingLocation = -1;
- int misspellingLength = 0;
- client()->checkSpellingOfString(selectedString.characters(), length, &misspellingLocation, &misspellingLength);
-
- // The selection only counts as misspelled if the selected text is exactly one misspelled word
- if (misspellingLength != length)
- return false;
-
- // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
- // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
- // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
- // or a grammar error.
- client()->updateSpellingUIWithMisspelledWord(selectedString);
-
- return true;
-}
-
-#ifndef BUILDING_ON_TIGER
-static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
-{
- if (!client)
- return false;
-
- ExceptionCode ec;
- if (!range || range->collapsed(ec))
- return false;
-
- // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous
- // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,
- // or overlapping the range; the ranges must exactly match.
- guessesVector.clear();
- int grammarPhraseOffset;
-
- GrammarDetail grammarDetail;
- String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);
-
- // No bad grammar in these parts at all.
- if (badGrammarPhrase.isEmpty())
- return false;
-
- // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
- if (grammarPhraseOffset > 0)
- return false;
-
- ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);
-
- // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range
- if (grammarDetail.location + grammarPhraseOffset != 0)
- return false;
-
- // Bad grammar at start of range, but end of bad grammar is before or after end of range
- if (grammarDetail.length != TextIterator::rangeLength(range))
- return false;
-
- // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
- // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
- // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
- // or a grammar error.
- client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
-
- return true;
-}
-#endif
-
-bool Editor::isSelectionUngrammatical()
-{
-#ifdef BUILDING_ON_TIGER
- return false;
-#else
- Vector<String> ignoredGuesses;
- return isRangeUngrammatical(client(), frame()->selection()->toRange().get(), ignoredGuesses);
-#endif
-}
-
-Vector<String> Editor::guessesForUngrammaticalSelection()
-{
-#ifdef BUILDING_ON_TIGER
- return Vector<String>();
-#else
- Vector<String> guesses;
- // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
- isRangeUngrammatical(client(), frame()->selection()->toRange().get(), guesses);
- return guesses;
-#endif
-}
-
-Vector<String> Editor::guessesForMisspelledSelection()
-{
- String selectedString = frame()->selectedText();
- ASSERT(selectedString.length() != 0);
-
- Vector<String> guesses;
- if (client())
- client()->getGuessesForWord(selectedString, guesses);
- return guesses;
-}
-
-void Editor::showSpellingGuessPanel()
-{
- if (!client()) {
- LOG_ERROR("No NSSpellChecker");
- return;
- }
-
-#ifndef BUILDING_ON_TIGER
- // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
- // to match rest of OS X.
- if (client()->spellingUIIsShowing()) {
- client()->showSpellingUI(false);
- return;
- }
-#endif
-
- advanceToNextMisspelling(true);
- client()->showSpellingUI(true);
-}
-
-bool Editor::spellingPanelIsShowing()
-{
- if (!client())
- return false;
- return client()->spellingUIIsShowing();
-}
-
-void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
-{
- if (!isContinuousSpellCheckingEnabled())
- return;
-
- // Check spelling of one word
- markMisspellings(Selection(startOfWord(p, LeftWordIfOnBoundary), endOfWord(p, RightWordIfOnBoundary)));
-
- if (!isGrammarCheckingEnabled())
- return;
-
- // Check grammar of entire sentence
- markBadGrammar(Selection(startOfSentence(p), endOfSentence(p)));
-}
-
-static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange)
-{
- // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
- // all we need to do is mark every instance.
- int ignoredOffset;
- findFirstMisspellingInRange(client, searchRange, ignoredOffset, true);
-}
-
-#ifndef BUILDING_ON_TIGER
-static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
-{
- // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
- // do is mark every instance.
- GrammarDetail ignoredGrammarDetail;
- int ignoredOffset;
- findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
-}
-#endif
-
-static void markMisspellingsOrBadGrammar(Editor* editor, const Selection& selection, bool checkSpelling)
-{
- // This function is called with a selection already expanded to word boundaries.
- // Might be nice to assert that here.
-
- // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
- // grammar checking can only be on if spell checking is also on.
- if (!editor->isContinuousSpellCheckingEnabled())
- return;
-
- RefPtr<Range> searchRange(selection.toRange());
- if (!searchRange)
- return;
-
- // If we're not in an editable node, bail.
- Node* editableNode = searchRange->startContainer();
- if (!editableNode || !editableNode->isContentEditable())
- return;
-
- // Get the spell checker if it is available
- if (!editor->client())
- return;
-
- if (checkSpelling)
- markAllMisspellingsInRange(editor->client(), searchRange.get());
- else {
-#ifdef BUILDING_ON_TIGER
- ASSERT_NOT_REACHED();
-#else
- if (editor->isGrammarCheckingEnabled())
- markAllBadGrammarInRange(editor->client(), searchRange.get());
-#endif
- }
-}
-
-void Editor::markMisspellings(const Selection& selection)
-{
- markMisspellingsOrBadGrammar(this, selection, true);
-}
-
-void Editor::markBadGrammar(const Selection& selection)
-{
-#ifndef BUILDING_ON_TIGER
- markMisspellingsOrBadGrammar(this, selection, false);
-#endif
-}
-
-PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
-{
- Document* document = m_frame->documentAtPoint(windowPoint);
- if (!document)
- return 0;
-
- Frame* frame = document->frame();
- ASSERT(frame);
- FrameView* frameView = frame->view();
- if (!frameView)
- return 0;
- IntPoint framePoint = frameView->windowToContents(windowPoint);
- Selection selection(frame->visiblePositionForPoint(framePoint));
- return avoidIntersectionWithNode(selection.toRange().get(), deleteButtonController() ? deleteButtonController()->containerElement() : 0);
-}
-
-void Editor::revealSelectionAfterEditingOperation()
-{
- if (m_ignoreCompositionSelectionChange)
- return;
-
- m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
-}
-
-void Editor::setIgnoreCompositionSelectionChange(bool ignore)
-{
- if (m_ignoreCompositionSelectionChange == ignore)
- return;
-
- m_ignoreCompositionSelectionChange = ignore;
- if (!ignore)
- revealSelectionAfterEditingOperation();
-}
-
-PassRefPtr<Range> Editor::compositionRange() const
-{
- if (!m_compositionNode)
- return 0;
- unsigned length = m_compositionNode->length();
- unsigned start = min(m_compositionStart, length);
- unsigned end = min(max(start, m_compositionEnd), length);
- if (start >= end)
- return 0;
- return Range::create(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
-}
-
-bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
-{
- if (!m_compositionNode)
- return false;
- Position start = m_frame->selection()->start();
- if (start.node() != m_compositionNode)
- return false;
- Position end = m_frame->selection()->end();
- if (end.node() != m_compositionNode)
- return false;
-
- if (static_cast<unsigned>(start.offset()) < m_compositionStart)
- return false;
- if (static_cast<unsigned>(end.offset()) > m_compositionEnd)
- return false;
-
- selectionStart = start.offset() - m_compositionStart;
- selectionEnd = start.offset() - m_compositionEnd;
- return true;
-}
-
-void Editor::transpose()
-{
- if (!canEdit())
- return;
-
- Selection selection = m_frame->selection()->selection();
- if (!selection.isCaret())
- return;
-
- // Make a selection that goes back one character and forward two characters.
- VisiblePosition caret = selection.visibleStart();
- VisiblePosition next = isEndOfParagraph(caret) ? caret : caret.next();
- VisiblePosition previous = next.previous();
- if (next == previous)
- return;
- previous = previous.previous();
- if (!inSameParagraph(next, previous))
- return;
- RefPtr<Range> range = makeRange(previous, next);
- if (!range)
- return;
- Selection newSelection(range.get(), DOWNSTREAM);
-
- // Transpose the two characters.
- String text = plainText(range.get());
- if (text.length() != 2)
- return;
- String transposed = text.right(1) + text.left(1);
-
- // Select the two characters.
- if (newSelection != m_frame->selection()->selection()) {
- if (!m_frame->shouldChangeSelection(newSelection))
- return;
- m_frame->selection()->setSelection(newSelection);
- }
-
- // Insert the transposed characters.
- if (!shouldInsertText(transposed, range.get(), EditorInsertActionTyped))
- return;
- replaceSelectionWithText(transposed, false, false);
-}
-
-void Editor::addToKillRing(Range* range, bool prepend)
-{
- if (m_shouldStartNewKillRingSequence)
- startNewKillRingSequence();
-
- String text = plainText(range);
- text.replace('\\', m_frame->backslashAsCurrencySymbol());
- if (prepend)
- prependToKillRing(text);
- else
- appendToKillRing(text);
- m_shouldStartNewKillRingSequence = false;
-}
-
-#if !PLATFORM(MAC)
-
-void Editor::appendToKillRing(const String&)
-{
-}
-
-void Editor::prependToKillRing(const String&)
-{
-}
-
-String Editor::yankFromKillRing()
-{
- return String();
-}
-
-void Editor::startNewKillRingSequence()
-{
-}
-
-void Editor::setKillRingToYankedState()
-{
-}
-
-#endif
-
-bool Editor::insideVisibleArea(const IntPoint& point) const
-{
- if (m_frame->excludeFromTextSearch())
- return false;
-
- // Right now, we only check the visibility of a point for disconnected frames. For all other
- // frames, we assume visibility.
- Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
- if (!frame->isDisconnected())
- return true;
-
- RenderPart* renderer = frame->ownerRenderer();
- RenderBlock* container = renderer->containingBlock();
- if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
- return true;
-
- IntRect rectInPageCoords = container->getOverflowClipRect(0, 0);
- IntRect rectInFrameCoords = IntRect(renderer->xPos() * -1, renderer->yPos() * -1,
- rectInPageCoords.width(), rectInPageCoords.height());
-
- return rectInFrameCoords.contains(point);
-}
-
-bool Editor::insideVisibleArea(Range* range) const
-{
- if (!range)
- return true;
-
- if (m_frame->excludeFromTextSearch())
- return false;
-
- // Right now, we only check the visibility of a range for disconnected frames. For all other
- // frames, we assume visibility.
- Frame* frame = m_frame->isDisconnected() ? m_frame : m_frame->tree()->top(true);
- if (!frame->isDisconnected())
- return true;
-
- RenderPart* renderer = frame->ownerRenderer();
- RenderBlock* container = renderer->containingBlock();
- if (!(container->style()->overflowX() == OHIDDEN || container->style()->overflowY() == OHIDDEN))
- return true;
-
- IntRect rectInPageCoords = container->getOverflowClipRect(0, 0);
- IntRect rectInFrameCoords = IntRect(renderer->xPos() * -1, renderer->yPos() * -1,
- rectInPageCoords.width(), rectInPageCoords.height());
- IntRect resultRect = range->boundingBox();
-
- return rectInFrameCoords.contains(resultRect);
-}
-
-PassRefPtr<Range> Editor::firstVisibleRange(const String& target, bool caseFlag)
-{
- RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
- RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
- ExceptionCode ec = 0;
-
- while (!insideVisibleArea(resultRange.get())) {
- searchRange->setStartAfter(resultRange->endContainer(), ec);
- if (searchRange->startContainer() == searchRange->endContainer())
- return Range::create(m_frame->document());
- resultRange = findPlainText(searchRange.get(), target, true, caseFlag);
- }
-
- return resultRange;
-}
-
-PassRefPtr<Range> Editor::lastVisibleRange(const String& target, bool caseFlag)
-{
- RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
- RefPtr<Range> resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
- ExceptionCode ec = 0;
-
- while (!insideVisibleArea(resultRange.get())) {
- searchRange->setEndBefore(resultRange->startContainer(), ec);
- if (searchRange->startContainer() == searchRange->endContainer())
- return Range::create(m_frame->document());
- resultRange = findPlainText(searchRange.get(), target, false, caseFlag);
- }
-
- return resultRange;
-}
-
-PassRefPtr<Range> Editor::nextVisibleRange(Range* currentRange, const String& target, bool forward, bool caseFlag, bool wrapFlag)
-{
- if (m_frame->excludeFromTextSearch())
- return Range::create(m_frame->document());
-
- RefPtr<Range> resultRange = currentRange;
- RefPtr<Range> searchRange(rangeOfContents(m_frame->document()));
- ExceptionCode ec = 0;
-
- for ( ; !insideVisibleArea(resultRange.get()); resultRange = findPlainText(searchRange.get(), target, forward, caseFlag)) {
- if (resultRange->collapsed(ec)) {
- if (!resultRange->startContainer()->isInShadowTree())
- break;
- searchRange = rangeOfContents(m_frame->document());
- if (forward)
- searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
- else
- searchRange->setEndBefore(resultRange->startContainer()->shadowAncestorNode(), ec);
- continue;
- }
-
- if (forward)
- searchRange->setStartAfter(resultRange->endContainer(), ec);
- else
- searchRange->setEndBefore(resultRange->startContainer(), ec);
-
- Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
- if (searchRange->collapsed(ec) && shadowTreeRoot) {
- if (forward)
- searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
- else
- searchRange->setStartBefore(shadowTreeRoot, ec);
- }
-
- if (searchRange->startContainer()->isDocumentNode() && searchRange->endContainer()->isDocumentNode())
- break;
- }
-
- if (insideVisibleArea(resultRange.get()))
- return resultRange;
-
- if (!wrapFlag)
- return Range::create(m_frame->document());
-
- if (forward)
- return firstVisibleRange(target, caseFlag);
-
- return lastVisibleRange(target, caseFlag);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/Editor.h b/WebCore/editing/Editor.h
deleted file mode 100644
index 7478ff9..0000000
--- a/WebCore/editing/Editor.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Editor_h
-#define Editor_h
-
-#include "ClipboardAccessPolicy.h"
-#include "Color.h"
-#include "EditAction.h"
-#include "EditorDeleteAction.h"
-#include "EditorInsertAction.h"
-#include "SelectionController.h"
-
-namespace WebCore {
-
-class CSSStyleDeclaration;
-class Clipboard;
-class DeleteButtonController;
-class EditCommand;
-class EditorClient;
-class EditorInternalCommand;
-class HTMLElement;
-class HitTestResult;
-class Pasteboard;
-class SimpleFontData;
-class Text;
-
-struct CompositionUnderline {
- CompositionUnderline()
- : startOffset(0), endOffset(0), thick(false) { }
- CompositionUnderline(unsigned s, unsigned e, const Color& c, bool t)
- : startOffset(s), endOffset(e), color(c), thick(t) { }
- unsigned startOffset;
- unsigned endOffset;
- Color color;
- bool thick;
-};
-
-enum TriState { FalseTriState, TrueTriState, MixedTriState };
-enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
-enum WritingDirection { NaturalWritingDirection, LeftToRightWritingDirection, RightToLeftWritingDirection };
-
-class Editor {
-public:
- Editor(Frame*);
- ~Editor();
-
- EditorClient* client() const;
- Frame* frame() const { return m_frame; }
- DeleteButtonController* deleteButtonController() const { return m_deleteButtonController.get(); }
- EditCommand* lastEditCommand() { return m_lastEditCommand.get(); }
-
- void handleKeyboardEvent(KeyboardEvent*);
- void handleInputMethodKeydown(KeyboardEvent*);
-
- bool canEdit() const;
- bool canEditRichly() const;
-
- bool canDHTMLCut();
- bool canDHTMLCopy();
- bool canDHTMLPaste();
- bool tryDHTMLCopy();
- bool tryDHTMLCut();
- bool tryDHTMLPaste();
-
- bool canCut() const;
- bool canCopy() const;
- bool canPaste() const;
- bool canDelete() const;
- bool canSmartCopyOrDelete();
-
- void cut();
- void copy();
- void paste();
- void pasteAsPlainText();
- void performDelete();
-
- void copyURL(const KURL&, const String&);
- void copyImage(const HitTestResult&);
-
- void indent();
- void outdent();
- void transpose();
-
- bool shouldInsertFragment(PassRefPtr<DocumentFragment>, PassRefPtr<Range>, EditorInsertAction);
- bool shouldInsertText(const String&, Range*, EditorInsertAction) const;
- bool shouldShowDeleteInterface(HTMLElement*) const;
- bool shouldDeleteRange(Range*) const;
- bool shouldApplyStyle(CSSStyleDeclaration*, Range*);
-
- void respondToChangedSelection(const Selection& oldSelection);
- void respondToChangedContents(const Selection& endingSelection);
-
- TriState selectionHasStyle(CSSStyleDeclaration*) const;
- const SimpleFontData* fontForSelection(bool&) const;
-
- TriState selectionUnorderedListState() const;
- TriState selectionOrderedListState() const;
- PassRefPtr<Node> insertOrderedList();
- PassRefPtr<Node> insertUnorderedList();
- bool canIncreaseSelectionListLevel();
- bool canDecreaseSelectionListLevel();
- PassRefPtr<Node> increaseSelectionListLevel();
- PassRefPtr<Node> increaseSelectionListLevelOrdered();
- PassRefPtr<Node> increaseSelectionListLevelUnordered();
- void decreaseSelectionListLevel();
-
- void removeFormattingAndStyle();
-
- void clearLastEditCommand();
-
- bool deleteWithDirection(SelectionController::EDirection, TextGranularity, bool killRing, bool isTypingAction);
- void deleteSelectionWithSmartDelete(bool smartDelete);
- bool dispatchCPPEvent(const AtomicString&, ClipboardAccessPolicy);
-
- Node* removedAnchor() const { return m_removedAnchor.get(); }
- void setRemovedAnchor(PassRefPtr<Node> n) { m_removedAnchor = n; }
-
- void applyStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
- void applyParagraphStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
- void applyStyleToSelection(CSSStyleDeclaration*, EditAction);
- void applyParagraphStyleToSelection(CSSStyleDeclaration*, EditAction);
-
- void appliedEditing(PassRefPtr<EditCommand>);
- void unappliedEditing(PassRefPtr<EditCommand>);
- void reappliedEditing(PassRefPtr<EditCommand>);
-
- bool selectionStartHasStyle(CSSStyleDeclaration*) const;
-
- bool clientIsEditable() const;
-
- class Command {
- public:
- Command();
- Command(PassRefPtr<Frame>, const EditorInternalCommand*, EditorCommandSource);
-
- bool execute(const String& parameter = String(), Event* triggeringEvent = 0) const;
- bool execute(Event* triggeringEvent) const;
-
- bool isSupported() const;
- bool isEnabled(Event* triggeringEvent = 0) const;
-
- TriState state(Event* triggeringEvent = 0) const;
- String value(Event* triggeringEvent = 0) const;
-
- bool isTextInsertion() const;
-
- private:
- RefPtr<Frame> m_frame;
- const EditorInternalCommand* m_command;
- EditorCommandSource m_source;
- };
- Command command(const String& commandName); // Default is CommandFromMenuOrKeyBinding.
- Command command(const String& commandName, EditorCommandSource);
-
- bool insertText(const String&, Event* triggeringEvent);
- bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, Event* triggeringEvent);
- bool insertLineBreak();
- bool insertParagraphSeparator();
-
- bool isContinuousSpellCheckingEnabled();
- void toggleContinuousSpellChecking();
- bool isGrammarCheckingEnabled();
- void toggleGrammarChecking();
- void ignoreSpelling();
- void learnSpelling();
- int spellCheckerDocumentTag();
- bool isSelectionUngrammatical();
- bool isSelectionMisspelled();
- Vector<String> guessesForMisspelledSelection();
- Vector<String> guessesForUngrammaticalSelection();
- void markMisspellingsAfterTypingToPosition(const VisiblePosition&);
- void markMisspellings(const Selection&);
- void markBadGrammar(const Selection&);
- void advanceToNextMisspelling(bool startBeforeSelection = false);
- void showSpellingGuessPanel();
- bool spellingPanelIsShowing();
-
- bool shouldBeginEditing(Range*);
- bool shouldEndEditing(Range*);
-
- void clearUndoRedoOperations();
- bool canUndo();
- void undo();
- bool canRedo();
- void redo();
-
- void didBeginEditing();
- void didEndEditing();
- void didWriteSelectionToPasteboard();
-
- void showFontPanel();
- void showStylesPanel();
- void showColorPanel();
- void toggleBold();
- void toggleUnderline();
- void setBaseWritingDirection(WritingDirection);
-
- bool smartInsertDeleteEnabled();
-
- // international text input composition
- bool hasComposition() const { return m_compositionNode; }
- void setComposition(const String&, const Vector<CompositionUnderline>&, unsigned selectionStart, unsigned selectionEnd);
- void confirmComposition();
- void confirmComposition(const String&); // if no existing composition, replaces selection
- void confirmCompositionWithoutDisturbingSelection();
- PassRefPtr<Range> compositionRange() const;
- bool getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const;
-
- // getting international text input composition state (for use by InlineTextBox)
- Text* compositionNode() const { return m_compositionNode.get(); }
- unsigned compositionStart() const { return m_compositionStart; }
- unsigned compositionEnd() const { return m_compositionEnd; }
- bool compositionUsesCustomUnderlines() const { return !m_customCompositionUnderlines.isEmpty(); }
- const Vector<CompositionUnderline>& customCompositionUnderlines() const { return m_customCompositionUnderlines; }
-
- bool ignoreCompositionSelectionChange() const { return m_ignoreCompositionSelectionChange; }
-
- void setStartNewKillRingSequence(bool);
-
- PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
-
- void clear();
-
- Selection selectionForCommand(Event*);
-
- void appendToKillRing(const String&);
- void prependToKillRing(const String&);
- String yankFromKillRing();
- void startNewKillRingSequence();
- void setKillRingToYankedState();
-
- PassRefPtr<Range> selectedRange();
-
- // We should make these functions private when their callers in Frame are moved over here to Editor
- bool insideVisibleArea(const IntPoint&) const;
- bool insideVisibleArea(Range*) const;
- PassRefPtr<Range> nextVisibleRange(Range*, const String&, bool forward, bool caseFlag, bool wrapFlag);
-
-private:
- Frame* m_frame;
- OwnPtr<DeleteButtonController> m_deleteButtonController;
- RefPtr<EditCommand> m_lastEditCommand;
- RefPtr<Node> m_removedAnchor;
-
- RefPtr<Text> m_compositionNode;
- unsigned m_compositionStart;
- unsigned m_compositionEnd;
- Vector<CompositionUnderline> m_customCompositionUnderlines;
- bool m_ignoreCompositionSelectionChange;
- bool m_shouldStartNewKillRingSequence;
-
- bool canDeleteRange(Range*) const;
- bool canSmartReplaceWithPasteboard(Pasteboard*);
- PassRefPtr<Clipboard> newGeneralClipboard(ClipboardAccessPolicy);
- void pasteAsPlainTextWithPasteboard(Pasteboard*);
- void pasteWithPasteboard(Pasteboard*, bool allowPlainText);
- void replaceSelectionWithFragment(PassRefPtr<DocumentFragment>, bool selectReplacement, bool smartReplace, bool matchStyle);
- void replaceSelectionWithText(const String&, bool selectReplacement, bool smartReplace);
- void writeSelectionToPasteboard(Pasteboard*);
- void revealSelectionAfterEditingOperation();
-
- void selectComposition();
- void confirmComposition(const String&, bool preserveSelection);
- void setIgnoreCompositionSelectionChange(bool ignore);
-
- void addToKillRing(Range*, bool prepend);
-
- PassRefPtr<Range> firstVisibleRange(const String&, bool caseFlag);
- PassRefPtr<Range> lastVisibleRange(const String&, bool caseFlag);
-};
-
-inline void Editor::setStartNewKillRingSequence(bool flag)
-{
- m_shouldStartNewKillRingSequence = flag;
-}
-
-} // namespace WebCore
-
-#endif // Editor_h
diff --git a/WebCore/editing/EditorCommand.cpp b/WebCore/editing/EditorCommand.cpp
deleted file mode 100644
index bd896ad..0000000
--- a/WebCore/editing/EditorCommand.cpp
+++ /dev/null
@@ -1,1418 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "AtomicString.h"
-#include "CSSPropertyNames.h"
-#include "CreateLinkCommand.h"
-#include "DocumentFragment.h"
-#include "Editor.h"
-#include "EditorClient.h"
-#include "Event.h"
-#include "EventHandler.h"
-#include "Frame.h"
-#include "FormatBlockCommand.h"
-#include "HTMLFontElement.h"
-#include "HTMLImageElement.h"
-#include "IndentOutdentCommand.h"
-#include "InsertListCommand.h"
-#include "Page.h"
-#include "ReplaceSelectionCommand.h"
-#include "Scrollbar.h"
-#include "Settings.h"
-#include "Sound.h"
-#include "TypingCommand.h"
-#include "UnlinkCommand.h"
-#include "htmlediting.h"
-#include "markup.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class EditorInternalCommand {
-public:
- bool (*execute)(Frame*, Event*, EditorCommandSource, const String&);
- bool (*isSupported)(Frame*, EditorCommandSource);
- bool (*isEnabled)(Frame*, Event*, EditorCommandSource);
- TriState (*state)(Frame*, Event*);
- String (*value)(Frame*, Event*);
- bool isTextInsertion;
- bool allowExecutionWhenDisabled;
-};
-
-typedef HashMap<String, const EditorInternalCommand*, CaseFoldingHash> CommandMap;
-
-static const bool notTextInsertion = false;
-static const bool isTextInsertion = true;
-
-static const bool allowExecutionWhenDisabled = true;
-static const bool doNotAllowExecutionWhenDisabled = false;
-
-// Related to Editor::selectionForCommand.
-// Certain operations continue to use the target control's selection even if the event handler
-// already moved the selection outside of the text control.
-static Frame* targetFrame(Frame* frame, Event* event)
-{
- if (!event)
- return frame;
- Node* node = event->target()->toNode();
- if (!node)
- return frame;
- return node->document()->frame();
-}
-
-static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const String& propertyValue)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, propertyValue);
- // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- frame->editor()->applyStyleToSelection(style.get(), action);
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- frame->editor()->applyStyle(style.get());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const char* propertyValue)
-{
- return executeApplyStyle(frame, source, action, propertyID, String(propertyValue));
-}
-
-static bool executeApplyStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, int propertyValue)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, propertyValue);
- // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- frame->editor()->applyStyleToSelection(style.get(), action);
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- frame->editor()->applyStyle(style.get());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeToggleStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const char* offValue, const char* onValue)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, onValue);
- style->setProperty(propertyID, frame->editor()->selectionStartHasStyle(style.get()) ? offValue : onValue);
- // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- frame->editor()->applyStyleToSelection(style.get(), action);
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- frame->editor()->applyStyle(style.get());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeApplyParagraphStyle(Frame* frame, EditorCommandSource source, EditAction action, int propertyID, const String& propertyValue)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, propertyValue);
- // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- frame->editor()->applyParagraphStyleToSelection(style.get(), action);
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- frame->editor()->applyParagraphStyle(style.get());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeInsertFragment(Frame* frame, PassRefPtr<DocumentFragment> fragment)
-{
- applyCommand(ReplaceSelectionCommand::create(frame->document(), fragment,
- false, false, false, true, false, EditActionUnspecified));
- return true;
-}
-
-static bool executeInsertNode(Frame* frame, PassRefPtr<Node> content)
-{
- RefPtr<DocumentFragment> fragment = new DocumentFragment(frame->document());
- ExceptionCode ec = 0;
- fragment->appendChild(content, ec);
- if (ec)
- return false;
- return executeInsertFragment(frame, fragment.release());
-}
-
-static bool expandSelectionToGranularity(Frame* frame, TextGranularity granularity)
-{
- Selection selection = frame->selection()->selection();
- selection.expandUsingGranularity(granularity);
- RefPtr<Range> newRange = selection.toRange();
- if (!newRange)
- return false;
- ExceptionCode ec = 0;
- if (newRange->collapsed(ec))
- return false;
- RefPtr<Range> oldRange = frame->selection()->selection().toRange();
- EAffinity affinity = frame->selection()->affinity();
- if (!frame->editor()->client()->shouldChangeSelectedRange(oldRange.get(), newRange.get(), affinity, false))
- return false;
- frame->selection()->setSelectedRange(newRange.get(), affinity, true);
- return true;
-}
-
-static TriState stateStyle(Frame* frame, int propertyID, const char* desiredValue)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- style->setProperty(propertyID, desiredValue);
- return frame->editor()->selectionHasStyle(style.get());
-}
-
-static String valueStyle(Frame* frame, int propertyID)
-{
- return frame->selectionStartStylePropertyValue(propertyID);
-}
-
-static int verticalScrollDistance(Frame* frame)
-{
- Node* focusedNode = frame->document()->focusedNode();
- if (!focusedNode)
- return 0;
- RenderObject* renderer = focusedNode->renderer();
- if (!renderer)
- return 0;
- RenderStyle* style = renderer->style();
- if (!style)
- return 0;
- if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || renderer->isTextArea()))
- return 0;
- int height = renderer->clientHeight();
- return max((height + 1) / 2, height - cAmountToKeepWhenPaging);
-}
-
-static RefPtr<Range> unionDOMRanges(Range* a, Range* b)
-{
- ExceptionCode ec = 0;
- Range* start = a->compareBoundaryPoints(Range::START_TO_START, b, ec) <= 0 ? a : b;
- ASSERT(!ec);
- Range* end = a->compareBoundaryPoints(Range::END_TO_END, b, ec) <= 0 ? b : a;
- ASSERT(!ec);
-
- return Range::create(a->startContainer(ec)->ownerDocument(), start->startContainer(ec), start->startOffset(ec), end->endContainer(ec), end->endOffset(ec));
-}
-
-// Execute command functions
-
-static bool executeBackColor(Frame* frame, Event*, EditorCommandSource source, const String& value)
-{
- return executeApplyStyle(frame, source, EditActionSetBackgroundColor, CSSPropertyBackgroundColor, value);
-}
-
-static bool executeCopy(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->copy();
- return true;
-}
-
-static bool executeCreateLink(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- // FIXME: If userInterface is true, we should display a dialog box to let the user enter a URL.
- if (value.isEmpty())
- return false;
- applyCommand(CreateLinkCommand::create(frame->document(), value));
- return true;
-}
-
-static bool executeCut(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->cut();
- return true;
-}
-
-static bool executeDelete(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- // Doesn't modify the text if the current selection isn't a range.
- frame->editor()->performDelete();
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- // If the current selection is a caret, delete the preceding character. IE performs forwardDelete, but we currently side with Firefox.
- // Doesn't scroll to make the selection visible, or modify the kill ring (this time, siding with IE, not Firefox).
- TypingCommand::deleteKeyPressed(frame->document(), frame->selectionGranularity() == WordGranularity);
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeDeleteBackward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
- return true;
-}
-
-static bool executeDeleteBackwardByDecomposingPreviousCharacter(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- LOG_ERROR("DeleteBackwardByDecomposingPreviousCharacter is not implemented, doing DeleteBackward instead");
- frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
- return true;
-}
-
-static bool executeDeleteForward(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
- return true;
-}
-
-static bool executeDeleteToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::BACKWARD, LineBoundary, true, false);
- return true;
-}
-
-static bool executeDeleteToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::BACKWARD, ParagraphBoundary, true, false);
- return true;
-}
-
-static bool executeDeleteToEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- // Despite its name, this command should delete the newline at the end of
- // a paragraph if you are at the end of a paragraph (like DeleteToEndOfParagraph).
- frame->editor()->deleteWithDirection(SelectionController::FORWARD, LineBoundary, true, false);
- return true;
-}
-
-static bool executeDeleteToEndOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- // Despite its name, this command should delete the newline at the end of
- // a paragraph if you are at the end of a paragraph.
- frame->editor()->deleteWithDirection(SelectionController::FORWARD, ParagraphBoundary, true, false);
- return true;
-}
-
-static bool executeDeleteToMark(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- RefPtr<Range> mark = frame->mark().toRange();
- if (mark) {
- SelectionController* selection = frame->selection();
- bool selected = selection->setSelectedRange(unionDOMRanges(mark.get(), frame->editor()->selectedRange().get()).get(), DOWNSTREAM, true);
- ASSERT(selected);
- if (!selected)
- return false;
- }
- frame->editor()->performDelete();
- frame->setMark(frame->selection()->selection());
- return true;
-}
-
-static bool executeDeleteWordBackward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
- return true;
-}
-
-static bool executeDeleteWordForward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
- return true;
-}
-
-static bool executeFindString(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- return frame->findString(value, true, false, true, false);
-}
-
-static bool executeFontName(Frame* frame, Event*, EditorCommandSource source, const String& value)
-{
- return executeApplyStyle(frame, source, EditActionSetFont, CSSPropertyFontFamily, value);
-}
-
-static bool executeFontSize(Frame* frame, Event*, EditorCommandSource source, const String& value)
-{
- int size;
- if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
- return false;
- return executeApplyStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontSize, size);
-}
-
-static bool executeFontSizeDelta(Frame* frame, Event*, EditorCommandSource source, const String& value)
-{
- return executeApplyStyle(frame, source, EditActionChangeAttributes, CSSPropertyWebkitFontSizeDelta, value);
-}
-
-static bool executeForeColor(Frame* frame, Event*, EditorCommandSource source, const String& value)
-{
- return executeApplyStyle(frame, source, EditActionSetColor, CSSPropertyColor, value);
-}
-
-static bool executeFormatBlock(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- String tagName = value.lower();
- if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>')
- tagName = tagName.substring(1, tagName.length() - 2);
- if (!validBlockTag(tagName))
- return false;
- applyCommand(FormatBlockCommand::create(frame->document(), tagName));
- return true;
-}
-
-static bool executeForwardDelete(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- // Doesn't scroll to make the selection visible, or modify the kill ring.
- // ForwardDelete is not implemented in IE or Firefox, so this behavior is only needed for
- // backward compatibility with ourselves, and for consistency with Delete.
- TypingCommand::forwardDeleteKeyPressed(frame->document());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeIgnoreSpelling(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->ignoreSpelling();
- return true;
-}
-
-static bool executeIndent(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- applyCommand(IndentOutdentCommand::create(frame->document(), IndentOutdentCommand::Indent));
- return true;
-}
-
-static bool executeInsertBacktab(Frame* frame, Event* event, EditorCommandSource, const String&)
-{
- return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, true);
-}
-
-static bool executeInsertHorizontalRule(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- RefPtr<HTMLElement> hr = new HTMLElement(hrTag, frame->document());
- if (!value.isEmpty())
- hr->setId(value);
- return executeInsertNode(frame, hr.release());
-}
-
-static bool executeInsertHTML(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- return executeInsertFragment(frame, createFragmentFromMarkup(frame->document(), value, ""));
-}
-
-static bool executeInsertImage(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
- RefPtr<HTMLImageElement> image = new HTMLImageElement(imgTag, frame->document());
- image->setSrc(value);
- return executeInsertNode(frame, image.release());
-}
-
-static bool executeInsertLineBreak(Frame* frame, Event* event, EditorCommandSource source, const String&)
-{
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\n", event, true);
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- // Doesn't scroll to make the selection visible, or modify the kill ring.
- // InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
- // backward compatibility with ourselves, and for consistency with other commands.
- TypingCommand::insertLineBreak(frame->document());
- return true;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool executeInsertNewline(Frame* frame, Event* event, EditorCommandSource, const String&)
-{
- Frame* targetFrame = WebCore::targetFrame(frame, event);
- return targetFrame->eventHandler()->handleTextInputEvent("\n", event, !targetFrame->editor()->canEditRichly());
-}
-
-static bool executeInsertNewlineInQuotedContent(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- TypingCommand::insertParagraphSeparatorInQuotedContent(frame->document());
- return true;
-}
-
-static bool executeInsertOrderedList(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- applyCommand(InsertListCommand::create(frame->document(), InsertListCommand::OrderedList, value));
- return true;
-}
-
-static bool executeInsertParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- TypingCommand::insertParagraphSeparator(frame->document());
- return true;
-}
-
-static bool executeInsertTab(Frame* frame, Event* event, EditorCommandSource, const String&)
-{
- return targetFrame(frame, event)->eventHandler()->handleTextInputEvent("\t", event, false, false);
-}
-
-static bool executeInsertText(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- TypingCommand::insertText(frame->document(), value);
- return true;
-}
-
-static bool executeInsertUnorderedList(Frame* frame, Event*, EditorCommandSource, const String& value)
-{
- applyCommand(InsertListCommand::create(frame->document(), InsertListCommand::UnorderedList, value));
- return true;
-}
-
-static bool executeJustifyCenter(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyParagraphStyle(frame, source, EditActionCenter, CSSPropertyTextAlign, "center");
-}
-
-static bool executeJustifyFull(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyParagraphStyle(frame, source, EditActionJustify, CSSPropertyTextAlign, "justify");
-}
-
-static bool executeJustifyLeft(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyParagraphStyle(frame, source, EditActionAlignLeft, CSSPropertyTextAlign, "left");
-}
-
-static bool executeJustifyRight(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyParagraphStyle(frame, source, EditActionAlignRight, CSSPropertyTextAlign, "right");
-}
-
-static bool executeMoveBackward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveDown(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
- return true;
-}
-
-static bool executeMoveDownAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
- return true;
-}
-
-static bool executeMoveForward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveLeft(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMovePageDown(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- int distance = verticalScrollDistance(frame);
- if (!distance)
- return false;
- return frame->selection()->modify(SelectionController::MOVE, distance, true);
-}
-
-static bool executeMovePageDownAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- int distance = verticalScrollDistance(frame);
- if (!distance)
- return false;
- return frame->selection()->modify(SelectionController::EXTEND, distance, true);
-}
-
-static bool executeMovePageUp(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- int distance = verticalScrollDistance(frame);
- if (!distance)
- return false;
- return frame->selection()->modify(SelectionController::MOVE, -distance, true);
-}
-
-static bool executeMovePageUpAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- int distance = verticalScrollDistance(frame);
- if (!distance)
- return false;
- return frame->selection()->modify(SelectionController::EXTEND, -distance, true);
-}
-
-static bool executeMoveRight(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfSentence(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
- return true;
-}
-
-static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfSentence(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfLine(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfLineAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
- return true;
-}
-
-static bool executeMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
- return true;
-}
-
-static bool executeMoveParagraphBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
- return true;
-}
-
-static bool executeMoveParagraphForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
- return true;
-}
-
-static bool executeMoveUp(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
- return true;
-}
-
-static bool executeMoveUpAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
- return true;
-}
-
-static bool executeMoveWordBackward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordBackwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordForward(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordForwardAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordLeft(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordLeftAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordRight(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
- return true;
-}
-
-static bool executeMoveWordRightAndModifySelection(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
- return true;
-}
-
-static bool executeOutdent(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- applyCommand(IndentOutdentCommand::create(frame->document(), IndentOutdentCommand::Outdent));
- return true;
-}
-
-static bool executePaste(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->paste();
- return true;
-}
-
-static bool executePasteAndMatchStyle(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->pasteAsPlainText();
- return true;
-}
-
-static bool executePrint(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- Page* page = frame->page();
- if (!page)
- return false;
- page->chrome()->print(frame);
- return true;
-}
-
-static bool executeRedo(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->redo();
- return true;
-}
-
-static bool executeRemoveFormat(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->removeFormattingAndStyle();
- return true;
-}
-
-static bool executeSelectAll(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->selectAll();
- return true;
-}
-
-static bool executeSelectLine(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- return expandSelectionToGranularity(frame, LineGranularity);
-}
-
-static bool executeSelectParagraph(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- return expandSelectionToGranularity(frame, ParagraphGranularity);
-}
-
-static bool executeSelectSentence(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- return expandSelectionToGranularity(frame, SentenceGranularity);
-}
-
-static bool executeSelectToMark(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- RefPtr<Range> mark = frame->mark().toRange();
- RefPtr<Range> selection = frame->editor()->selectedRange();
- if (!mark || !selection) {
- systemBeep();
- return false;
- }
- frame->selection()->setSelectedRange(unionDOMRanges(mark.get(), selection.get()).get(), DOWNSTREAM, true);
- return true;
-}
-
-static bool executeSelectWord(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- return expandSelectionToGranularity(frame, WordGranularity);
-}
-
-static bool executeSetMark(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->setMark(frame->selection()->selection());
- return true;
-}
-
-static bool executeStrikethrough(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeToggleStyle(frame, source, EditActionChangeAttributes, CSSPropertyWebkitTextDecorationsInEffect, "none", "line-through");
-}
-
-static bool executeSubscript(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyStyle(frame, source, EditActionSubscript, CSSPropertyVerticalAlign, "sub");
-}
-
-static bool executeSuperscript(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyStyle(frame, source, EditActionSuperscript, CSSPropertyVerticalAlign, "super");
-}
-
-static bool executeSwapWithMark(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- const Selection& mark = frame->mark();
- const Selection& selection = frame->selection()->selection();
- if (mark.isNone() || selection.isNone()) {
- systemBeep();
- return false;
- }
- frame->selection()->setSelection(mark);
- frame->setMark(selection);
- return true;
-}
-
-static bool executeToggleBold(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeToggleStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontWeight, "normal", "bold");
-}
-
-static bool executeToggleItalic(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeToggleStyle(frame, source, EditActionChangeAttributes, CSSPropertyFontStyle, "normal", "italic");
-}
-
-static bool executeTranspose(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->transpose();
- return true;
-}
-
-static bool executeUnderline(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- // FIXME: This currently clears overline, line-through, and blink as an unwanted side effect.
- return executeToggleStyle(frame, source, EditActionUnderline, CSSPropertyWebkitTextDecorationsInEffect, "none", "underline");
-}
-
-static bool executeUndo(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->undo();
- return true;
-}
-
-static bool executeUnlink(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- applyCommand(UnlinkCommand::create(frame->document()));
- return true;
-}
-
-static bool executeUnscript(Frame* frame, Event*, EditorCommandSource source, const String&)
-{
- return executeApplyStyle(frame, source, EditActionUnscript, CSSPropertyVerticalAlign, "baseline");
-}
-
-static bool executeUnselect(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->selection()->clear();
- return true;
-}
-
-static bool executeYank(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->insertTextWithoutSendingTextEvent(frame->editor()->yankFromKillRing(), false, 0);
- frame->editor()->setKillRingToYankedState();
- return true;
-}
-
-static bool executeYankAndSelect(Frame* frame, Event*, EditorCommandSource, const String&)
-{
- frame->editor()->insertTextWithoutSendingTextEvent(frame->editor()->yankFromKillRing(), true, 0);
- frame->editor()->setKillRingToYankedState();
- return true;
-}
-
-// Supported functions
-
-static bool supported(Frame*, EditorCommandSource)
-{
- return true;
-}
-
-static bool supportedFromMenuOrKeyBinding(Frame*, EditorCommandSource source)
-{
- return source == CommandFromMenuOrKeyBinding;
-}
-
-static bool supportedPaste(Frame* frame, EditorCommandSource source)
-{
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- return true;
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface: {
- Settings* settings = frame ? frame->settings() : 0;
- return settings && settings->isDOMPasteAllowed();
- }
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-// Enabled functions
-
-static bool enabled(Frame*, Event*, EditorCommandSource)
-{
- return true;
-}
-
-static bool enabledAnySelection(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->selection()->isCaretOrRange();
-}
-
-static bool enabledAnySelectionAndMark(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->selection()->isCaretOrRange() && frame->mark().isCaretOrRange();
-}
-
-static bool enableCaretInEditableText(Frame* frame, Event* event, EditorCommandSource)
-{
- const Selection& selection = frame->editor()->selectionForCommand(event);
- return selection.isCaret() && selection.isContentEditable();
-}
-
-static bool enabledCopy(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
-}
-
-static bool enabledCut(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->canDHTMLCut() || frame->editor()->canCut();
-}
-
-static bool enabledDelete(Frame* frame, Event* event, EditorCommandSource source)
-{
- switch (source) {
- case CommandFromMenuOrKeyBinding:
- // "Delete" from menu only affects selected range, just like Cut but without affecting pasteboard
- return frame->editor()->canDHTMLCut() || frame->editor()->canCut();
- case CommandFromDOM:
- case CommandFromDOMWithUserInterface:
- // "Delete" from DOM is like delete/backspace keypress, affects selected range if non-empty,
- // otherwise removes a character
- return frame->editor()->selectionForCommand(event).isContentEditable();
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-static bool enabledInEditableText(Frame* frame, Event* event, EditorCommandSource)
-{
- return frame->editor()->selectionForCommand(event).isContentEditable();
-}
-
-static bool enabledInRichlyEditableText(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->selection()->isCaretOrRange() && frame->selection()->isContentRichlyEditable();
-}
-
-static bool enabledPaste(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->canPaste();
-}
-
-static bool enabledRangeInEditableText(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->selection()->isRange() && frame->selection()->isContentEditable();
-}
-
-static bool enabledRangeInRichlyEditableText(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->selection()->isRange() && frame->selection()->isContentRichlyEditable();
-}
-
-static bool enabledRedo(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->canRedo();
-}
-
-static bool enabledUndo(Frame* frame, Event*, EditorCommandSource)
-{
- return frame->editor()->canUndo();
-}
-
-// State functions
-
-static TriState stateNone(Frame*, Event*)
-{
- return FalseTriState;
-}
-
-static TriState stateBold(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyFontWeight, "bold");
-}
-
-static TriState stateItalic(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyFontStyle, "italic");
-}
-
-static TriState stateOrderedList(Frame* frame, Event*)
-{
- return frame->editor()->selectionOrderedListState();
-}
-
-static TriState stateStrikethrough(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyTextDecoration, "line-through");
-}
-
-static TriState stateSubscript(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyVerticalAlign, "sub");
-}
-
-static TriState stateSuperscript(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyVerticalAlign, "super");
-}
-
-static TriState stateUnderline(Frame* frame, Event*)
-{
- return stateStyle(frame, CSSPropertyTextDecoration, "underline");
-}
-
-static TriState stateUnorderedList(Frame* frame, Event*)
-{
- return frame->editor()->selectionUnorderedListState();
-}
-
-// Value functions
-
-static String valueNull(Frame*, Event*)
-{
- return String();
-}
-
-String valueBackColor(Frame* frame, Event*)
-{
- return valueStyle(frame, CSSPropertyBackgroundColor);
-}
-
-String valueFontName(Frame* frame, Event*)
-{
- return valueStyle(frame, CSSPropertyFontFamily);
-}
-
-String valueFontSize(Frame* frame, Event*)
-{
- return valueStyle(frame, CSSPropertyFontSize);
-}
-
-String valueFontSizeDelta(Frame* frame, Event*)
-{
- return valueStyle(frame, CSSPropertyWebkitFontSizeDelta);
-}
-
-String valueForeColor(Frame* frame, Event*)
-{
- return valueStyle(frame, CSSPropertyColor);
-}
-
-// Map of functions
-
-static const CommandMap& createCommandMap()
-{
- struct CommandEntry { const char* name; EditorInternalCommand command; };
-
- static const CommandEntry commands[] = {
- { "AlignCenter", { executeJustifyCenter, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "AlignJustified", { executeJustifyFull, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "AlignLeft", { executeJustifyLeft, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "AlignRight", { executeJustifyRight, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "BackColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueBackColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "BackwardDelete", { executeDeleteBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } }, // FIXME: remove BackwardDelete when Safari for Windows stops using it.
- { "Bold", { executeToggleBold, supported, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Copy", { executeCopy, supported, enabledCopy, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
- { "CreateLink", { executeCreateLink, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Cut", { executeCut, supported, enabledCut, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
- { "Delete", { executeDelete, supported, enabledDelete, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteBackward", { executeDeleteBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteBackwardByDecomposingPreviousCharacter", { executeDeleteBackwardByDecomposingPreviousCharacter, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteForward", { executeDeleteForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteToBeginningOfLine", { executeDeleteToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteToBeginningOfParagraph", { executeDeleteToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteToEndOfLine", { executeDeleteToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteToEndOfParagraph", { executeDeleteToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteToMark", { executeDeleteToMark, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteWordBackward", { executeDeleteWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "DeleteWordForward", { executeDeleteWordForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "FindString", { executeFindString, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "FontName", { executeFontName, supported, enabledInEditableText, stateNone, valueFontName, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "FontSize", { executeFontSize, supported, enabledInEditableText, stateNone, valueFontSize, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "FontSizeDelta", { executeFontSizeDelta, supported, enabledInEditableText, stateNone, valueFontSizeDelta, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "ForeColor", { executeForeColor, supported, enabledInRichlyEditableText, stateNone, valueForeColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "ForwardDelete", { executeForwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "HiliteColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "IgnoreSpelling", { executeIgnoreSpelling, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Indent", { executeIndent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertBacktab", { executeInsertBacktab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertHorizontalRule", { executeInsertHorizontalRule, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertHTML", { executeInsertHTML, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertImage", { executeInsertImage, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertLineBreak", { executeInsertLineBreak, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertNewline", { executeInsertNewline, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertNewlineInQuotedContent", { executeInsertNewlineInQuotedContent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertOrderedList", { executeInsertOrderedList, supported, enabledInRichlyEditableText, stateOrderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertParagraph", { executeInsertParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertTab", { executeInsertTab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertText", { executeInsertText, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "InsertUnorderedList", { executeInsertUnorderedList, supported, enabledInRichlyEditableText, stateUnorderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Italic", { executeToggleItalic, supported, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "JustifyCenter", { executeJustifyCenter, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "JustifyFull", { executeJustifyFull, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "JustifyLeft", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "JustifyNone", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "JustifyRight", { executeJustifyRight, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveBackward", { executeMoveBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveBackwardAndModifySelection", { executeMoveBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveDown", { executeMoveDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveDownAndModifySelection", { executeMoveDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveForward", { executeMoveForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveForwardAndModifySelection", { executeMoveForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveLeft", { executeMoveLeft, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveLeftAndModifySelection", { executeMoveLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MovePageDown", { executeMovePageDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MovePageDownAndModifySelection", { executeMovePageDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MovePageUp", { executeMovePageUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MovePageUpAndModifySelection", { executeMovePageUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveParagraphBackwardAndModifySelection", { executeMoveParagraphBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveParagraphForwardAndModifySelection", { executeMoveParagraphForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveRight", { executeMoveRight, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveRightAndModifySelection", { executeMoveRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfDocument", { executeMoveToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfDocumentAndModifySelection", { executeMoveToBeginningOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfLine", { executeMoveToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfLineAndModifySelection", { executeMoveToBeginningOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfParagraph", { executeMoveToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfParagraphAndModifySelection", { executeMoveToBeginningOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfSentence", { executeMoveToBeginningOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToBeginningOfSentenceAndModifySelection", { executeMoveToBeginningOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfDocument", { executeMoveToEndOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfDocumentAndModifySelection", { executeMoveToEndOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfLine", { executeMoveToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfLineAndModifySelection", { executeMoveToEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfParagraph", { executeMoveToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfParagraphAndModifySelection", { executeMoveToEndOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfSentence", { executeMoveToEndOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveToEndOfSentenceAndModifySelection", { executeMoveToEndOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveUp", { executeMoveUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveUpAndModifySelection", { executeMoveUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordBackward", { executeMoveWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordBackwardAndModifySelection", { executeMoveWordBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordForward", { executeMoveWordForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordForwardAndModifySelection", { executeMoveWordForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordLeft", { executeMoveWordLeft, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordLeftAndModifySelection", { executeMoveWordLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordRight", { executeMoveWordRight, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "MoveWordRightAndModifySelection", { executeMoveWordRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Outdent", { executeOutdent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Paste", { executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
- { "PasteAndMatchStyle", { executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
- { "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectAll", { executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectLine", { executeSelectLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectParagraph", { executeSelectParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectSentence", { executeSelectSentence, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectToMark", { executeSelectToMark, supportedFromMenuOrKeyBinding, enabledAnySelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SelectWord", { executeSelectWord, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SetMark", { executeSetMark, supportedFromMenuOrKeyBinding, enabledAnySelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Strikethrough", { executeStrikethrough, supported, enabledInRichlyEditableText, stateStrikethrough, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Subscript", { executeSubscript, supported, enabledInRichlyEditableText, stateSubscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Superscript", { executeSuperscript, supported, enabledInRichlyEditableText, stateSuperscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "SwapWithMark", { executeSwapWithMark, supportedFromMenuOrKeyBinding, enabledAnySelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "ToggleBold", { executeToggleBold, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "ToggleItalic", { executeToggleItalic, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "ToggleUnderline", { executeUnderline, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Transpose", { executeTranspose, supported, enableCaretInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Underline", { executeUnderline, supported, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Undo", { executeUndo, supported, enabledUndo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Unlink", { executeUnlink, supported, enabledRangeInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Unscript", { executeUnscript, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Unselect", { executeUnselect, supported, enabledAnySelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "Yank", { executeYank, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- { "YankAndSelect", { executeYankAndSelect, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
- };
-
- // These unsupported commands are listed here since they appear in the Microsoft
- // documentation used as the starting point for our DOM executeCommand support.
- //
- // 2D-Position (not supported)
- // AbsolutePosition (not supported)
- // BlockDirLTR (not supported)
- // BlockDirRTL (not supported)
- // BrowseMode (not supported)
- // ClearAuthenticationCache (not supported)
- // CreateBookmark (not supported)
- // DirLTR (not supported)
- // DirRTL (not supported)
- // EditMode (not supported)
- // InlineDirLTR (not supported)
- // InlineDirRTL (not supported)
- // InsertButton (not supported)
- // InsertFieldSet (not supported)
- // InsertIFrame (not supported)
- // InsertInputButton (not supported)
- // InsertInputCheckbox (not supported)
- // InsertInputFileUpload (not supported)
- // InsertInputHidden (not supported)
- // InsertInputImage (not supported)
- // InsertInputPassword (not supported)
- // InsertInputRadio (not supported)
- // InsertInputReset (not supported)
- // InsertInputSubmit (not supported)
- // InsertInputText (not supported)
- // InsertMarquee (not supported)
- // InsertSelectDropDown (not supported)
- // InsertSelectListBox (not supported)
- // InsertTextArea (not supported)
- // LiveResize (not supported)
- // MultipleSelection (not supported)
- // Open (not supported)
- // Overwrite (not supported)
- // PlayImage (not supported)
- // Refresh (not supported)
- // RemoveParaFormat (not supported)
- // SaveAs (not supported)
- // SizeToControl (not supported)
- // SizeToControlHeight (not supported)
- // SizeToControlWidth (not supported)
- // Stop (not supported)
- // StopImage (not supported)
- // Unbookmark (not supported)
-
- CommandMap& commandMap = *new CommandMap;
-
- const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
- for (unsigned i = 0; i < numCommands; i++) {
- ASSERT(!commandMap.get(commands[i].name));
- commandMap.set(commands[i].name, &commands[i].command);
- }
-
- return commandMap;
-}
-
-Editor::Command Editor::command(const String& commandName)
-{
- return command(commandName, CommandFromMenuOrKeyBinding);
-}
-
-Editor::Command Editor::command(const String& commandName, EditorCommandSource source)
-{
- if (commandName.isEmpty())
- return Command();
-
- static const CommandMap& commandMap = createCommandMap();
- const EditorInternalCommand* internalCommand = commandMap.get(commandName);
- return internalCommand ? Command(m_frame, internalCommand, source) : Command();
-}
-
-Editor::Command::Command()
- : m_command(0)
- , m_source()
-{
-}
-
-Editor::Command::Command(PassRefPtr<Frame> frame, const EditorInternalCommand* command, EditorCommandSource source)
- : m_frame(frame)
- , m_command(command)
- , m_source(source)
-{
- ASSERT(m_frame);
- ASSERT(m_command);
-}
-
-bool Editor::Command::execute(const String& parameter, Event* triggeringEvent) const
-{
- if (!isEnabled(triggeringEvent)) {
- // Let certain commands be executed when performed explicitly even if they are disabled.
- if (!isSupported() || !m_frame || !m_frame->document() || !m_command->allowExecutionWhenDisabled)
- return false;
- }
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
- return m_command->execute(m_frame.get(), triggeringEvent, m_source, parameter);
-}
-
-bool Editor::Command::execute(Event* triggeringEvent) const
-{
- return execute(String(), triggeringEvent);
-}
-
-bool Editor::Command::isSupported() const
-{
- return m_command && m_command->isSupported(m_frame.get(), m_source);
-}
-
-bool Editor::Command::isEnabled(Event* triggeringEvent) const
-{
- if (!isSupported() || !m_frame || !m_frame->document())
- return false;
- return m_command->isEnabled(m_frame.get(), triggeringEvent, m_source);
-}
-
-TriState Editor::Command::state(Event* triggeringEvent) const
-{
- if (!isSupported() || !m_frame || !m_frame->document())
- return FalseTriState;
- return m_command->state(m_frame.get(), triggeringEvent);
-}
-
-String Editor::Command::value(Event* triggeringEvent) const
-{
- if (!isSupported() || !m_frame || !m_frame->document())
- return String();
- return m_command->value(m_frame.get(), triggeringEvent);
-}
-
-bool Editor::Command::isTextInsertion() const
-{
- return m_command && m_command->isTextInsertion;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/EditorDeleteAction.h b/WebCore/editing/EditorDeleteAction.h
deleted file mode 100644
index 00bf683..0000000
--- a/WebCore/editing/EditorDeleteAction.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef EditorDeleteAction_h
-#define EditorDeleteAction_h
-
-namespace WebCore {
-
-enum EditorDeleteAction {
- deleteSelectionAction,
- deleteKeyAction,
- forwardDeleteKeyAction
-};
-
-} // namespace
-
-#endif
-
diff --git a/WebCore/editing/EditorInsertAction.h b/WebCore/editing/EditorInsertAction.h
deleted file mode 100644
index 5b732dc..0000000
--- a/WebCore/editing/EditorInsertAction.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef EditorInsertAction_h
-#define EditorInsertAction_h
-
-namespace WebCore {
-
-// This must be kept in sync with WebViewInsertAction defined in WebEditingDelegate.h
-enum EditorInsertAction {
- EditorInsertActionTyped,
- EditorInsertActionPasted,
- EditorInsertActionDropped,
-};
-
-} // namespace
-
-#endif
diff --git a/WebCore/editing/FormatBlockCommand.cpp b/WebCore/editing/FormatBlockCommand.cpp
deleted file mode 100644
index 64f7c2d..0000000
--- a/WebCore/editing/FormatBlockCommand.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Element.h"
-#include "FormatBlockCommand.h"
-#include "Document.h"
-#include "htmlediting.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-FormatBlockCommand::FormatBlockCommand(Document* document, const String& tagName)
- : CompositeEditCommand(document), m_tagName(tagName)
-{
-}
-
-bool FormatBlockCommand::modifyRange()
-{
- ASSERT(endingSelection().isRange());
- VisiblePosition visibleStart = endingSelection().visibleStart();
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
- VisiblePosition startOfLastParagraph = startOfParagraph(visibleEnd);
-
- if (startOfParagraph(visibleStart) == startOfLastParagraph)
- return false;
-
- setEndingSelection(visibleStart);
- doApply();
- visibleStart = endingSelection().visibleStart();
- VisiblePosition nextParagraph = endOfParagraph(visibleStart).next();
- while (nextParagraph.isNotNull() && nextParagraph != startOfLastParagraph) {
- setEndingSelection(nextParagraph);
- doApply();
- nextParagraph = endOfParagraph(endingSelection().visibleStart()).next();
- }
- setEndingSelection(visibleEnd);
- doApply();
- visibleEnd = endingSelection().visibleEnd();
- setEndingSelection(Selection(visibleStart.deepEquivalent(), visibleEnd.deepEquivalent(), DOWNSTREAM));
-
- return true;
-}
-
-void FormatBlockCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- if (!endingSelection().rootEditableElement())
- return;
-
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
- VisiblePosition visibleStart = endingSelection().visibleStart();
- // When a selection ends at the start of a paragraph, we rarely paint
- // the selection gap before that paragraph, because there often is no gap.
- // In a case like this, it's not obvious to the user that the selection
- // ends "inside" that paragraph, so it would be confusing if FormatBlock
- // operated on that paragraph.
- // FIXME: We paint the gap before some paragraphs that are indented with left
- // margin/padding, but not others. We should make the gap painting more consistent and
- // then use a left margin/padding rule here.
- if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
- setEndingSelection(Selection(visibleStart, visibleEnd.previous(true)));
-
- if (endingSelection().isRange() && modifyRange())
- return;
-
- ExceptionCode ec;
- String localName, prefix;
- if (!Document::parseQualifiedName(m_tagName, prefix, localName, ec))
- return;
- QualifiedName qTypeOfBlock(prefix, localName, xhtmlNamespaceURI);
-
- Node* refNode = enclosingBlockFlowElement(endingSelection().visibleStart());
- if (refNode->hasTagName(qTypeOfBlock))
- // We're already in a block with the format we want, so we don't have to do anything
- return;
-
- VisiblePosition paragraphStart = startOfParagraph(endingSelection().visibleStart());
- VisiblePosition paragraphEnd = endOfParagraph(endingSelection().visibleStart());
- VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart());
- VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart());
- RefPtr<Node> blockNode = createElement(document(), m_tagName);
- RefPtr<Node> placeholder = createBreakElement(document());
-
- Node* root = endingSelection().start().node()->rootEditableElement();
- if (validBlockTag(refNode->nodeName().lower()) &&
- paragraphStart == blockStart && paragraphEnd == blockEnd &&
- refNode != root && !root->isDescendantOf(refNode))
- // Already in a valid block tag that only contains the current paragraph, so we can swap with the new tag
- insertNodeBefore(blockNode.get(), refNode);
- else {
- // Avoid inserting inside inline elements that surround paragraphStart with upstream().
- // This is only to avoid creating bloated markup.
- insertNodeAt(blockNode.get(), paragraphStart.deepEquivalent().upstream());
- }
- appendNode(placeholder.get(), blockNode.get());
-
- VisiblePosition destination(Position(placeholder.get(), 0));
- if (paragraphStart == paragraphEnd && !lineBreakExistsAtPosition(paragraphStart)) {
- setEndingSelection(destination);
- return;
- }
- moveParagraph(paragraphStart, paragraphEnd, destination, true, false);
-}
-
-}
diff --git a/WebCore/editing/FormatBlockCommand.h b/WebCore/editing/FormatBlockCommand.h
deleted file mode 100644
index 0e84bc1..0000000
--- a/WebCore/editing/FormatBlockCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef FormatBlockCommand_h
-#define FormatBlockCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class FormatBlockCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<FormatBlockCommand> create(Document* document, const String& tagName)
- {
- return adoptRef(new FormatBlockCommand(document, tagName));
- }
-
-private:
- FormatBlockCommand(Document*, const String& tagName);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return EditActionFormatBlock; }
-
- bool modifyRange();
- String m_tagName;
-};
-
-} // namespace WebCore
-
-#endif // FormatBlockCommand_h
diff --git a/WebCore/editing/HTMLInterchange.cpp b/WebCore/editing/HTMLInterchange.cpp
deleted file mode 100644
index 024ac9f..0000000
--- a/WebCore/editing/HTMLInterchange.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "HTMLInterchange.h"
-
-#include "CharacterNames.h"
-#include "Text.h"
-#include "TextIterator.h"
-
-namespace WebCore {
-
-namespace {
-
-String convertedSpaceString()
-{
- static String convertedSpaceString;
- if (convertedSpaceString.isNull()) {
- convertedSpaceString = "<span class=\"";
- convertedSpaceString += AppleConvertedSpace;
- convertedSpaceString += "\">";
- convertedSpaceString.append(noBreakSpace);
- convertedSpaceString += "</span>";
- }
- return convertedSpaceString;
-}
-
-} // end anonymous namespace
-
-String convertHTMLTextToInterchangeFormat(const String& in, const Text* node)
-{
- // Assume all the text comes from node.
- if (node->renderer() && node->renderer()->style()->preserveNewline())
- return in;
-
- Vector<UChar> s;
-
- unsigned i = 0;
- unsigned consumed = 0;
- while (i < in.length()) {
- consumed = 1;
- if (isCollapsibleWhitespace(in[i])) {
- // count number of adjoining spaces
- unsigned j = i + 1;
- while (j < in.length() && isCollapsibleWhitespace(in[j]))
- j++;
- unsigned count = j - i;
- consumed = count;
- while (count) {
- unsigned add = count % 3;
- switch (add) {
- case 0:
- append(s, convertedSpaceString());
- s.append(' ');
- append(s, convertedSpaceString());
- add = 3;
- break;
- case 1:
- if (i == 0 || i + 1 == in.length()) // at start or end of string
- append(s, convertedSpaceString());
- else
- s.append(' ');
- break;
- case 2:
- if (i == 0) {
- // at start of string
- append(s, convertedSpaceString());
- s.append(' ');
- } else if (i + 2 == in.length()) {
- // at end of string
- append(s, convertedSpaceString());
- append(s, convertedSpaceString());
- } else {
- append(s, convertedSpaceString());
- s.append(' ');
- }
- break;
- }
- count -= add;
- }
- } else
- s.append(in[i]);
- i += consumed;
- }
-
- return String::adopt(s);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/HTMLInterchange.h b/WebCore/editing/HTMLInterchange.h
deleted file mode 100644
index 3b68efb..0000000
--- a/WebCore/editing/HTMLInterchange.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef HTMLInterchange_h
-#define HTMLInterchange_h
-
-namespace WebCore {
-
-class String;
-class Text;
-
-#define AppleInterchangeNewline "Apple-interchange-newline"
-#define AppleConvertedSpace "Apple-converted-space"
-#define ApplePasteAsQuotation "Apple-paste-as-quotation"
-#define AppleStyleSpanClass "Apple-style-span"
-#define AppleTabSpanClass "Apple-tab-span"
-
-enum EAnnotateForInterchange { DoNotAnnotateForInterchange, AnnotateForInterchange };
-
-String convertHTMLTextToInterchangeFormat(const String&, const Text*);
-
-}
-
-#endif
diff --git a/WebCore/editing/IndentOutdentCommand.cpp b/WebCore/editing/IndentOutdentCommand.cpp
deleted file mode 100644
index 385f1b7..0000000
--- a/WebCore/editing/IndentOutdentCommand.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (IndentOutdentCommandINCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Element.h"
-#include "IndentOutdentCommand.h"
-#include "InsertListCommand.h"
-#include "Document.h"
-#include "htmlediting.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "InsertLineBreakCommand.h"
-#include "Range.h"
-#include "SplitElementCommand.h"
-#include "TextIterator.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-static String indentBlockquoteString()
-{
- static String string = "webkit-indent-blockquote";
- return string;
-}
-
-static PassRefPtr<Element> createIndentBlockquoteElement(Document* document)
-{
- RefPtr<Element> indentBlockquoteElement = createElement(document, "blockquote");
- indentBlockquoteElement->setAttribute(classAttr, indentBlockquoteString());
- indentBlockquoteElement->setAttribute(styleAttr, "margin: 0 0 0 40px; border: none; padding: 0px;");
- return indentBlockquoteElement.release();
-}
-
-static bool isIndentBlockquote(const Node* node)
-{
- if (!node || !node->hasTagName(blockquoteTag) || !node->isElementNode())
- return false;
-
- const Element* elem = static_cast<const Element*>(node);
- return elem->getAttribute(classAttr) == indentBlockquoteString();
-}
-
-static bool isListOrIndentBlockquote(const Node* node)
-{
- return node && (node->hasTagName(ulTag) || node->hasTagName(olTag) || isIndentBlockquote(node));
-}
-
-IndentOutdentCommand::IndentOutdentCommand(Document* document, EIndentType typeOfAction, int marginInPixels)
- : CompositeEditCommand(document), m_typeOfAction(typeOfAction), m_marginInPixels(marginInPixels)
-{}
-
-// This function is a workaround for moveParagraph's tendency to strip blockquotes. It updates lastBlockquote to point to the
-// correct level for the current paragraph, and returns a pointer to a placeholder br where the insertion should be performed.
-Node* IndentOutdentCommand::prepareBlockquoteLevelForInsertion(VisiblePosition& currentParagraph, Node** lastBlockquote)
-{
- int currentBlockquoteLevel = 0;
- int lastBlockquoteLevel = 0;
- Node* node = currentParagraph.deepEquivalent().node();
- while ((node = enclosingNodeOfType(Position(node->parentNode(), 0), &isIndentBlockquote)))
- currentBlockquoteLevel++;
- node = *lastBlockquote;
- while ((node = enclosingNodeOfType(Position(node->parentNode(), 0), &isIndentBlockquote)))
- lastBlockquoteLevel++;
- while (currentBlockquoteLevel > lastBlockquoteLevel) {
- RefPtr<Node> newBlockquote = createIndentBlockquoteElement(document());
- appendNode(newBlockquote.get(), *lastBlockquote);
- *lastBlockquote = newBlockquote.get();
- lastBlockquoteLevel++;
- }
- while (currentBlockquoteLevel < lastBlockquoteLevel) {
- *lastBlockquote = enclosingNodeOfType(Position((*lastBlockquote)->parentNode(), 0), &isIndentBlockquote);
- lastBlockquoteLevel--;
- }
- RefPtr<Node> placeholder = createBreakElement(document());
- appendNode(placeholder.get(), *lastBlockquote);
- // Add another br before the placeholder if it collapsed.
- VisiblePosition visiblePos(Position(placeholder.get(), 0));
- if (!isStartOfParagraph(visiblePos))
- insertNodeBefore(createBreakElement(document()).get(), placeholder.get());
- return placeholder.get();
-}
-
-void IndentOutdentCommand::indentRegion()
-{
- Selection selection = selectionForParagraphIteration(endingSelection());
- VisiblePosition startOfSelection = selection.visibleStart();
- VisiblePosition endOfSelection = selection.visibleEnd();
- int startIndex = indexForVisiblePosition(startOfSelection);
- int endIndex = indexForVisiblePosition(endOfSelection);
-
- ASSERT(!startOfSelection.isNull());
- ASSERT(!endOfSelection.isNull());
-
- // Special case empty root editable elements because there's nothing to split
- // and there's nothing to move.
- Position start = startOfSelection.deepEquivalent().downstream();
- if (start.node() == editableRootForPosition(start)) {
- RefPtr<Node> blockquote = createIndentBlockquoteElement(document());
- insertNodeAt(blockquote.get(), start);
- RefPtr<Node> placeholder = createBreakElement(document());
- appendNode(placeholder.get(), blockquote.get());
- setEndingSelection(Selection(Position(placeholder.get(), 0), DOWNSTREAM));
- return;
- }
-
- Node* previousListNode = 0;
- Node* newListNode = 0;
- Node* newBlockquote = 0;
- VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection);
- VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
- while (endOfCurrentParagraph != endAfterSelection) {
- // Iterate across the selected paragraphs...
- VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
- Node* listNode = enclosingList(endOfCurrentParagraph.deepEquivalent().node());
- Node* insertionPoint;
- if (listNode) {
- RefPtr<Node> placeholder = createBreakElement(document());
- insertionPoint = placeholder.get();
- newBlockquote = 0;
- RefPtr<Node> listItem = createListItemElement(document());
- if (listNode == previousListNode) {
- // The previous paragraph was inside the same list, so add this list item to the list we already created
- appendNode(listItem.get(), newListNode);
- appendNode(placeholder.get(), listItem.get());
- } else {
- // Clone the list element, insert it before the current paragraph, and move the paragraph into it.
- RefPtr<Node> clonedList = static_cast<Element*>(listNode)->cloneNode(false);
- insertNodeBefore(clonedList.get(), enclosingListChild(endOfCurrentParagraph.deepEquivalent().node()));
- appendNode(listItem.get(), clonedList.get());
- appendNode(placeholder.get(), listItem.get());
- newListNode = clonedList.get();
- previousListNode = listNode;
- }
- } else if (newBlockquote)
- // The previous paragraph was put into a new blockquote, so move this paragraph there as well
- insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, &newBlockquote);
- else {
- // Create a new blockquote and insert it as a child of the root editable element. We accomplish
- // this by splitting all parents of the current paragraph up to that point.
- RefPtr<Node> blockquote = createIndentBlockquoteElement(document());
- Position start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
-
- Node* enclosingCell = enclosingNodeOfType(start, &isTableCell);
- Node* nodeToSplitTo = enclosingCell ? enclosingCell : editableRootForPosition(start);
- RefPtr<Node> startOfNewBlock = splitTreeToNode(start.node(), nodeToSplitTo);
- insertNodeBefore(blockquote.get(), startOfNewBlock.get());
- newBlockquote = blockquote.get();
- insertionPoint = prepareBlockquoteLevelForInsertion(endOfCurrentParagraph, &newBlockquote);
- // Don't put the next paragraph in the blockquote we just created for this paragraph unless
- // the next paragraph is in the same cell.
- if (enclosingCell && enclosingCell != enclosingNodeOfType(endOfNextParagraph.deepEquivalent(), &isTableCell))
- newBlockquote = 0;
- }
- moveParagraph(startOfParagraph(endOfCurrentParagraph), endOfCurrentParagraph, VisiblePosition(Position(insertionPoint, 0)), true);
- // moveParagraph should not destroy content that contains endOfNextParagraph, but if it does, return here
- // to avoid a crash.
- if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().node()->inDocument()) {
- ASSERT_NOT_REACHED();
- return;
- }
- endOfCurrentParagraph = endOfNextParagraph;
- }
-
- RefPtr<Range> startRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, 0, true);
- RefPtr<Range> endRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endIndex, 0, true);
- if (startRange && endRange)
- setEndingSelection(Selection(startRange->startPosition(), endRange->startPosition(), DOWNSTREAM));
-}
-
-void IndentOutdentCommand::outdentParagraph()
-{
- VisiblePosition visibleStartOfParagraph = startOfParagraph(endingSelection().visibleStart());
- VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagraph);
-
- Node* enclosingNode = enclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), &isListOrIndentBlockquote);
- if (!enclosingNode)
- return;
-
- // Use InsertListCommand to remove the selection from the list
- if (enclosingNode->hasTagName(olTag)) {
- applyCommandToComposite(InsertListCommand::create(document(), InsertListCommand::OrderedList, ""));
- return;
- }
- if (enclosingNode->hasTagName(ulTag)) {
- applyCommandToComposite(InsertListCommand::create(document(), InsertListCommand::UnorderedList, ""));
- return;
- }
-
- // The selection is inside a blockquote
- VisiblePosition positionInEnclosingBlock = VisiblePosition(Position(enclosingNode, 0));
- VisiblePosition startOfEnclosingBlock = startOfBlock(positionInEnclosingBlock);
- VisiblePosition endOfEnclosingBlock = endOfBlock(positionInEnclosingBlock);
- if (visibleStartOfParagraph == startOfEnclosingBlock &&
- visibleEndOfParagraph == endOfEnclosingBlock) {
- // The blockquote doesn't contain anything outside the paragraph, so it can be totally removed.
- removeNodePreservingChildren(enclosingNode);
- updateLayout();
- visibleStartOfParagraph = VisiblePosition(visibleStartOfParagraph.deepEquivalent());
- visibleEndOfParagraph = VisiblePosition(visibleEndOfParagraph.deepEquivalent());
- if (visibleStartOfParagraph.isNotNull() && !isStartOfParagraph(visibleStartOfParagraph))
- insertNodeAt(createBreakElement(document()).get(), visibleStartOfParagraph.deepEquivalent());
- if (visibleEndOfParagraph.isNotNull() && !isEndOfParagraph(visibleEndOfParagraph))
- insertNodeAt(createBreakElement(document()).get(), visibleEndOfParagraph.deepEquivalent());
- return;
- }
- Node* enclosingBlockFlow = enclosingBlockFlowElement(visibleStartOfParagraph);
- RefPtr<Node> splitBlockquoteNode = enclosingNode;
- if (enclosingBlockFlow != enclosingNode)
- splitBlockquoteNode = splitTreeToNode(enclosingBlockFlowElement(visibleStartOfParagraph), enclosingNode, true);
- RefPtr<Node> placeholder = createBreakElement(document());
- insertNodeBefore(placeholder.get(), splitBlockquoteNode.get());
- moveParagraph(startOfParagraph(visibleStartOfParagraph), endOfParagraph(visibleEndOfParagraph), VisiblePosition(Position(placeholder.get(), 0)), true);
-}
-
-void IndentOutdentCommand::outdentRegion()
-{
- VisiblePosition startOfSelection = endingSelection().visibleStart();
- VisiblePosition endOfSelection = endingSelection().visibleEnd();
- VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection);
-
- ASSERT(!startOfSelection.isNull());
- ASSERT(!endOfSelection.isNull());
-
- if (endOfParagraph(startOfSelection) == endOfLastParagraph) {
- outdentParagraph();
- return;
- }
-
- Position originalSelectionEnd = endingSelection().end();
- setEndingSelection(endingSelection().visibleStart());
- outdentParagraph();
- Position originalSelectionStart = endingSelection().start();
- VisiblePosition endOfCurrentParagraph = endOfParagraph(endOfParagraph(endingSelection().visibleStart()).next(true));
- VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next());
- while (endOfCurrentParagraph != endAfterSelection) {
- VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next());
- if (endOfCurrentParagraph == endOfLastParagraph)
- setEndingSelection(Selection(originalSelectionEnd, DOWNSTREAM));
- else
- setEndingSelection(endOfCurrentParagraph);
- outdentParagraph();
- endOfCurrentParagraph = endOfNextParagraph;
- }
- setEndingSelection(Selection(originalSelectionStart, endingSelection().end(), DOWNSTREAM));
-}
-
-void IndentOutdentCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- if (!endingSelection().rootEditableElement())
- return;
-
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
- VisiblePosition visibleStart = endingSelection().visibleStart();
- // When a selection ends at the start of a paragraph, we rarely paint
- // the selection gap before that paragraph, because there often is no gap.
- // In a case like this, it's not obvious to the user that the selection
- // ends "inside" that paragraph, so it would be confusing if Indent/Outdent
- // operated on that paragraph.
- // FIXME: We paint the gap before some paragraphs that are indented with left
- // margin/padding, but not others. We should make the gap painting more consistent and
- // then use a left margin/padding rule here.
- if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
- setEndingSelection(Selection(visibleStart, visibleEnd.previous(true)));
-
- if (m_typeOfAction == Indent)
- indentRegion();
- else
- outdentRegion();
-}
-
-}
diff --git a/WebCore/editing/IndentOutdentCommand.h b/WebCore/editing/IndentOutdentCommand.h
deleted file mode 100644
index c2ba1ea..0000000
--- a/WebCore/editing/IndentOutdentCommand.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef IndentOutdentCommand_h
-#define IndentOutdentCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class IndentOutdentCommand : public CompositeEditCommand {
-public:
- enum EIndentType { Indent, Outdent };
- static PassRefPtr<IndentOutdentCommand> create(Document* document, EIndentType type, int marginInPixels = 0)
- {
- return adoptRef(new IndentOutdentCommand(document, type, marginInPixels));
- }
-
- virtual bool preservesTypingStyle() const { return true; }
-
-private:
- IndentOutdentCommand(Document*, EIndentType, int marginInPixels);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return m_typeOfAction == Indent ? EditActionIndent : EditActionOutdent; }
-
- void indentRegion();
- void outdentRegion();
- void outdentParagraph();
- Node* prepareBlockquoteLevelForInsertion(VisiblePosition&, Node**);
-
- EIndentType m_typeOfAction;
- int m_marginInPixels;
-};
-
-} // namespace WebCore
-
-#endif // IndentOutdentCommand_h
diff --git a/WebCore/editing/InsertIntoTextNodeCommand.cpp b/WebCore/editing/InsertIntoTextNodeCommand.cpp
deleted file mode 100644
index 9d5ea6e..0000000
--- a/WebCore/editing/InsertIntoTextNodeCommand.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InsertIntoTextNodeCommand.h"
-
-#include "Text.h"
-
-namespace WebCore {
-
-InsertIntoTextNodeCommand::InsertIntoTextNodeCommand(PassRefPtr<Text> node, int offset, const String& text)
- : SimpleEditCommand(node->document())
- , m_node(node)
- , m_offset(offset)
- , m_text(text)
-{
- ASSERT(m_node);
- ASSERT(offset >= 0);
- ASSERT(!text.isEmpty());
-}
-
-void InsertIntoTextNodeCommand::doApply()
-{
- ExceptionCode ec = 0;
- m_node->insertData(m_offset, m_text, ec);
- ASSERT(ec == 0);
-}
-
-void InsertIntoTextNodeCommand::doUnapply()
-{
- ExceptionCode ec = 0;
- m_node->deleteData(m_offset, m_text.length(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/InsertIntoTextNodeCommand.h b/WebCore/editing/InsertIntoTextNodeCommand.h
deleted file mode 100644
index aed5da8..0000000
--- a/WebCore/editing/InsertIntoTextNodeCommand.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertIntoTextNodeCommand_h
-#define InsertIntoTextNodeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class Text;
-
-class InsertIntoTextNodeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<InsertIntoTextNodeCommand> create(PassRefPtr<Text> node, int offset, const String& text)
- {
- return adoptRef(new InsertIntoTextNodeCommand(node, offset, text));
- }
-
-private:
- InsertIntoTextNodeCommand(PassRefPtr<Text> node, int offset, const String& text);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Text> m_node;
- int m_offset;
- String m_text;
-};
-
-} // namespace WebCore
-
-#endif // InsertIntoTextNodeCommand_h
diff --git a/WebCore/editing/InsertLineBreakCommand.cpp b/WebCore/editing/InsertLineBreakCommand.cpp
deleted file mode 100644
index d6b4f56..0000000
--- a/WebCore/editing/InsertLineBreakCommand.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InsertLineBreakCommand.h"
-
-#include "CSSMutableStyleDeclaration.h"
-#include "Document.h"
-#include "Element.h"
-#include "Frame.h"
-#include "Text.h"
-#include "VisiblePosition.h"
-#include "Range.h"
-#include "htmlediting.h"
-#include "HTMLNames.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-InsertLineBreakCommand::InsertLineBreakCommand(Document* document)
- : CompositeEditCommand(document)
-{
-}
-
-bool InsertLineBreakCommand::preservesTypingStyle() const
-{
- return true;
-}
-
-void InsertLineBreakCommand::insertNodeAfterPosition(Node *node, const Position &pos)
-{
- // Insert the BR after the caret position. In the case the
- // position is a block, do an append. We don't want to insert
- // the BR *after* the block.
- Node *cb = pos.node()->enclosingBlockFlowElement();
- if (cb == pos.node())
- appendNode(node, cb);
- else
- insertNodeAfter(node, pos.node());
-}
-
-void InsertLineBreakCommand::insertNodeBeforePosition(Node *node, const Position &pos)
-{
- // Insert the BR after the caret position. In the case the
- // position is a block, do an append. We don't want to insert
- // the BR *before* the block.
- Node *cb = pos.node()->enclosingBlockFlowElement();
- if (cb == pos.node())
- appendNode(node, cb);
- else
- insertNodeBefore(node, pos.node());
-}
-
-// Whether we should insert a break element or a '\n'.
-bool InsertLineBreakCommand::shouldUseBreakElement(const Position& insertionPos)
-{
- // An editing position like [input, 0] actually refers to the position before
- // the input element, and in that case we need to check the input element's
- // parent's renderer.
- Position p(rangeCompliantEquivalent(insertionPos));
- return p.node()->renderer() && !p.node()->renderer()->style()->preserveNewline();
-}
-
-void InsertLineBreakCommand::doApply()
-{
- deleteSelection();
- Selection selection = endingSelection();
- if (selection.isNone())
- return;
-
- VisiblePosition caret(selection.visibleStart());
- Position pos(caret.deepEquivalent());
-
- pos = positionAvoidingSpecialElementBoundary(pos);
-
- pos = positionOutsideTabSpan(pos);
-
- RefPtr<Node> nodeToInsert;
- if (shouldUseBreakElement(pos))
- nodeToInsert = createBreakElement(document());
- else
- nodeToInsert = document()->createTextNode("\n");
-
- // FIXME: Need to merge text nodes when inserting just after or before text.
-
- if (isEndOfParagraph(caret) && !lineBreakExistsAtPosition(caret)) {
- bool needExtraLineBreak = !pos.node()->hasTagName(hrTag) && !pos.node()->hasTagName(tableTag);
-
- insertNodeAt(nodeToInsert.get(), pos);
-
- if (needExtraLineBreak)
- insertNodeBefore(nodeToInsert->cloneNode(false).get(), nodeToInsert.get());
-
- VisiblePosition endingPosition(Position(nodeToInsert.get(), 0));
- setEndingSelection(Selection(endingPosition));
- } else if (pos.offset() <= caretMinOffset(pos.node())) {
- insertNodeAt(nodeToInsert.get(), pos);
-
- // Insert an extra br or '\n' if the just inserted one collapsed.
- if (!isStartOfParagraph(VisiblePosition(Position(nodeToInsert.get(), 0))))
- insertNodeBefore(nodeToInsert->cloneNode(false).get(), nodeToInsert.get());
-
- setEndingSelection(Selection(positionAfterNode(nodeToInsert.get()), DOWNSTREAM));
- } else if (pos.offset() >= caretMaxOffset(pos.node())) {
- insertNodeAt(nodeToInsert.get(), pos);
- setEndingSelection(Selection(positionAfterNode(nodeToInsert.get()), DOWNSTREAM));
- } else {
- // Split a text node
- ASSERT(pos.node()->isTextNode());
-
- // Do the split
- ExceptionCode ec = 0;
- Text *textNode = static_cast<Text *>(pos.node());
- RefPtr<Text> textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.start().offset(), ec));
- deleteTextFromNode(textNode, 0, pos.offset());
- insertNodeBefore(textBeforeNode.get(), textNode);
- insertNodeBefore(nodeToInsert.get(), textNode);
- Position endingPosition = Position(textNode, 0);
-
- // Handle whitespace that occurs after the split
- updateLayout();
- if (!endingPosition.isRenderedCharacter()) {
- Position positionBeforeTextNode(positionBeforeNode(textNode));
- // Clear out all whitespace and insert one non-breaking space
- deleteInsignificantTextDownstream(endingPosition);
- ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
- // Deleting insignificant whitespace will remove textNode if it contains nothing but insignificant whitespace.
- if (textNode->inDocument())
- insertTextIntoNode(textNode, 0, nonBreakingSpaceString());
- else {
- RefPtr<Text> nbspNode = document()->createTextNode(nonBreakingSpaceString());
- insertNodeAt(nbspNode.get(), positionBeforeTextNode);
- endingPosition = Position(nbspNode.get(), 0);
- }
- }
-
- setEndingSelection(Selection(endingPosition, DOWNSTREAM));
- }
-
- // Handle the case where there is a typing style.
-
- CSSMutableStyleDeclaration* typingStyle = document()->frame()->typingStyle();
-
- if (typingStyle && typingStyle->length() > 0) {
- // Apply the typing style to the inserted line break, so that if the selection
- // leaves and then comes back, new input will have the right style.
- // FIXME: We shouldn't always apply the typing style to the line break here,
- // see <rdar://problem/5794462>.
- applyStyle(typingStyle, Position(nodeToInsert.get(), 0),
- Position(nodeToInsert.get(), maxDeepOffset(nodeToInsert.get())));
- // Even though this applyStyle operates on a Range, it still sets an endingSelection().
- // It tries to set a Selection around the content it operated on. So, that Selection
- // will either (a) select the line break we inserted, or it will (b) be a caret just
- // before the line break (if the line break is at the end of a block it isn't selectable).
- // So, this next call sets the endingSelection() to a caret just after the line break
- // that we inserted, or just before it if it's at the end of a block.
- setEndingSelection(endingSelection().visibleEnd());
- }
-
- rebalanceWhitespace();
-}
-
-}
diff --git a/WebCore/editing/InsertLineBreakCommand.h b/WebCore/editing/InsertLineBreakCommand.h
deleted file mode 100644
index 9e73add..0000000
--- a/WebCore/editing/InsertLineBreakCommand.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertLineBreakCommand_h
-#define InsertLineBreakCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class InsertLineBreakCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<InsertLineBreakCommand> create(Document* document)
- {
- return adoptRef(new InsertLineBreakCommand(document));
- }
-
-private:
- InsertLineBreakCommand(Document*);
-
- virtual void doApply();
-
- virtual bool preservesTypingStyle() const;
-
- void insertNodeAfterPosition(Node*, const Position&);
- void insertNodeBeforePosition(Node*, const Position&);
- bool shouldUseBreakElement(const Position&);
-};
-
-} // namespace WebCore
-
-#endif // InsertLineBreakCommand_h
diff --git a/WebCore/editing/InsertListCommand.cpp b/WebCore/editing/InsertListCommand.cpp
deleted file mode 100644
index 7433516..0000000
--- a/WebCore/editing/InsertListCommand.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Element.h"
-#include "InsertListCommand.h"
-#include "DocumentFragment.h"
-#include "htmlediting.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "TextIterator.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-PassRefPtr<Node> InsertListCommand::insertList(Document* document, Type type)
-{
- RefPtr<InsertListCommand> insertCommand = new InsertListCommand(document, type, "");
- insertCommand->apply();
- return insertCommand->m_listElement;
-}
-
-Node* InsertListCommand::fixOrphanedListChild(Node* node)
-{
- RefPtr<Element> listElement = createUnorderedListElement(document());
- insertNodeBefore(listElement.get(), node);
- removeNode(node);
- appendNode(node, listElement.get());
- m_listElement = listElement;
- return listElement.get();
-}
-
-InsertListCommand::InsertListCommand(Document* document, Type type, const String& id)
- : CompositeEditCommand(document), m_type(type), m_id(id), m_forceCreateList(false)
-{
-}
-
-bool InsertListCommand::modifyRange()
-{
- Selection selection = selectionForParagraphIteration(endingSelection());
- ASSERT(selection.isRange());
- VisiblePosition startOfSelection = selection.visibleStart();
- VisiblePosition endOfSelection = selection.visibleEnd();
- VisiblePosition startOfLastParagraph = startOfParagraph(endOfSelection);
-
- if (startOfParagraph(startOfSelection) == startOfLastParagraph)
- return false;
-
- Node* startList = enclosingList(startOfSelection.deepEquivalent().node());
- Node* endList = enclosingList(endOfSelection.deepEquivalent().node());
- if (!startList || startList != endList)
- m_forceCreateList = true;
-
- setEndingSelection(startOfSelection);
- doApply();
- // Fetch the start of the selection after moving the first paragraph,
- // because moving the paragraph will invalidate the original start.
- // We'll use the new start to restore the original selection after
- // we modified all selected paragraphs.
- startOfSelection = endingSelection().visibleStart();
- VisiblePosition startOfCurrentParagraph = startOfNextParagraph(startOfSelection);
- while (startOfCurrentParagraph != startOfLastParagraph) {
- // doApply() may operate on and remove the last paragraph of the selection from the document
- // if it's in the same list item as startOfCurrentParagraph. Return early to avoid an
- // infinite loop and because there is no more work to be done.
- // FIXME(<rdar://problem/5983974>): The endingSelection() may be incorrect here. Compute
- // the new location of endOfSelection and use it as the end of the new selection.
- if (!startOfLastParagraph.deepEquivalent().node()->inDocument())
- return true;
- setEndingSelection(startOfCurrentParagraph);
- doApply();
- startOfCurrentParagraph = startOfNextParagraph(endingSelection().visibleStart());
- }
- setEndingSelection(endOfSelection);
- doApply();
- // Fetch the end of the selection, for the reason mentioned above.
- endOfSelection = endingSelection().visibleEnd();
- setEndingSelection(Selection(startOfSelection, endOfSelection));
- m_forceCreateList = false;
- return true;
-}
-
-void InsertListCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- if (!endingSelection().rootEditableElement())
- return;
-
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
- VisiblePosition visibleStart = endingSelection().visibleStart();
- // When a selection ends at the start of a paragraph, we rarely paint
- // the selection gap before that paragraph, because there often is no gap.
- // In a case like this, it's not obvious to the user that the selection
- // ends "inside" that paragraph, so it would be confusing if InsertUn{Ordered}List
- // operated on that paragraph.
- // FIXME: We paint the gap before some paragraphs that are indented with left
- // margin/padding, but not others. We should make the gap painting more consistent and
- // then use a left margin/padding rule here.
- if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
- setEndingSelection(Selection(visibleStart, visibleEnd.previous(true)));
-
- if (endingSelection().isRange() && modifyRange())
- return;
-
- // FIXME: This will produce unexpected results for a selection that starts just before a
- // table and ends inside the first cell, selectionForParagraphIteration should probably
- // be renamed and deployed inside setEndingSelection().
- Node* selectionNode = endingSelection().start().node();
- const QualifiedName listTag = (m_type == OrderedList) ? olTag : ulTag;
- Node* listChildNode = enclosingListChild(selectionNode);
- bool switchListType = false;
- if (listChildNode) {
- // Remove the list chlild.
- Node* listNode = enclosingList(listChildNode);
- if (!listNode)
- listNode = fixOrphanedListChild(listChildNode);
- if (!listNode->hasTagName(listTag))
- // listChildNode will be removed from the list and a list of type m_type will be created.
- switchListType = true;
- Node* nextListChild;
- Node* previousListChild;
- VisiblePosition start;
- VisiblePosition end;
- if (listChildNode->hasTagName(liTag)) {
- start = VisiblePosition(Position(listChildNode, 0));
- end = VisiblePosition(Position(listChildNode, maxDeepOffset(listChildNode)));
- nextListChild = listChildNode->nextSibling();
- previousListChild = listChildNode->previousSibling();
- } else {
- // A paragraph is visually a list item minus a list marker. The paragraph will be moved.
- start = startOfParagraph(endingSelection().visibleStart());
- end = endOfParagraph(endingSelection().visibleEnd());
- nextListChild = enclosingListChild(end.next().deepEquivalent().node());
- ASSERT(nextListChild != listChildNode);
- if (enclosingList(nextListChild) != listNode)
- nextListChild = 0;
- previousListChild = enclosingListChild(start.previous().deepEquivalent().node());
- ASSERT(previousListChild != listChildNode);
- if (enclosingList(previousListChild) != listNode)
- previousListChild = 0;
- }
- // When removing a list, we must always create a placeholder to act as a point of insertion
- // for the list content being removed.
- RefPtr<Element> placeholder = createBreakElement(document());
- RefPtr<Node> nodeToInsert = placeholder;
- // If the content of the list item will be moved into another list, put it in a list item
- // so that we don't create an orphaned list child.
- if (enclosingList(listNode)) {
- nodeToInsert = createListItemElement(document());
- appendNode(placeholder.get(), nodeToInsert.get());
- }
-
- if (nextListChild && previousListChild) {
- // We want to pull listChildNode out of listNode, and place it before nextListChild
- // and after previousListChild, so we split listNode and insert it between the two lists.
- // But to split listNode, we must first split ancestors of listChildNode between it and listNode,
- // if any exist.
- // FIXME: We appear to split at nextListChild as opposed to listChildNode so that when we remove
- // listChildNode below in moveParagraphs, previousListChild will be removed along with it if it is
- // unrendered. But we ought to remove nextListChild too, if it is unrendered.
- splitElement(static_cast<Element*>(listNode), splitTreeToNode(nextListChild, listNode).get());
- insertNodeBefore(nodeToInsert.get(), listNode);
- } else if (nextListChild || listChildNode->parentNode() != listNode) {
- // Just because listChildNode has no previousListChild doesn't mean there isn't any content
- // in listNode that comes before listChildNode, as listChildNode could have ancestors
- // between it and listNode. So, we split up to listNode before inserting the placeholder
- // where we're about to move listChildNode to.
- if (listChildNode->parentNode() != listNode)
- splitElement(static_cast<Element *>(listNode), splitTreeToNode(listChildNode, listNode).get());
- insertNodeBefore(nodeToInsert.get(), listNode);
- } else
- insertNodeAfter(nodeToInsert.get(), listNode);
-
- VisiblePosition insertionPoint = VisiblePosition(Position(placeholder.get(), 0));
- moveParagraphs(start, end, insertionPoint, true);
- }
- if (!listChildNode || switchListType || m_forceCreateList) {
- // Create list.
- VisiblePosition start = startOfParagraph(endingSelection().visibleStart());
- VisiblePosition end = endOfParagraph(endingSelection().visibleEnd());
-
- // Check for adjoining lists.
- VisiblePosition previousPosition = start.previous(true);
- VisiblePosition nextPosition = end.next(true);
- RefPtr<Element> listItemElement = createListItemElement(document());
- RefPtr<Element> placeholder = createBreakElement(document());
- appendNode(placeholder.get(), listItemElement.get());
- Node* previousList = outermostEnclosingList(previousPosition.deepEquivalent().node());
- Node* nextList = outermostEnclosingList(nextPosition.deepEquivalent().node());
- Node* startNode = start.deepEquivalent().node();
- Node* previousCell = enclosingTableCell(previousPosition.deepEquivalent());
- Node* nextCell = enclosingTableCell(nextPosition.deepEquivalent());
- Node* currentCell = enclosingTableCell(start.deepEquivalent());
- if (previousList && (!previousList->hasTagName(listTag) || startNode->isDescendantOf(previousList) || previousCell != currentCell))
- previousList = 0;
- if (nextList && (!nextList->hasTagName(listTag) || startNode->isDescendantOf(nextList) || nextCell != currentCell))
- nextList = 0;
- // Place list item into adjoining lists.
- if (previousList)
- appendNode(listItemElement.get(), previousList);
- else if (nextList)
- insertNodeAt(listItemElement.get(), Position(nextList, 0));
- else {
- // Create the list.
- RefPtr<Element> listElement = m_type == OrderedList ? createOrderedListElement(document()) : createUnorderedListElement(document());
- m_listElement = listElement;
- if (!m_id.isEmpty())
- static_cast<HTMLElement*>(listElement.get())->setId(m_id);
- appendNode(listItemElement.get(), listElement.get());
-
- if (start == end && isBlock(start.deepEquivalent().node())) {
- // Inserting the list into an empty paragraph that isn't held open
- // by a br or a '\n', will invalidate start and end. Insert
- // a placeholder and then recompute start and end.
- RefPtr<Node> placeholder = insertBlockPlaceholder(start.deepEquivalent());
- start = VisiblePosition(Position(placeholder.get(), 0));
- end = start;
- }
-
- // Insert the list at a position visually equivalent to start of the
- // paragraph that is being moved into the list.
- // Try to avoid inserting it somewhere where it will be surrounded by
- // inline ancestors of start, since it is easier for editing to produce
- // clean markup when inline elements are pushed down as far as possible.
- Position insertionPos(start.deepEquivalent().upstream());
- // Also avoid the containing list item.
- Node* listChild = enclosingListChild(insertionPos.node());
- if (listChild && listChild->hasTagName(liTag))
- insertionPos = positionBeforeNode(listChild);
-
- insertNodeAt(listElement.get(), insertionPos);
- }
- moveParagraph(start, end, VisiblePosition(Position(placeholder.get(), 0)), true);
- if (nextList && previousList)
- mergeIdenticalElements(static_cast<Element*>(previousList), static_cast<Element*>(nextList));
- }
-}
-
-}
diff --git a/WebCore/editing/InsertListCommand.h b/WebCore/editing/InsertListCommand.h
deleted file mode 100644
index e9a8da9..0000000
--- a/WebCore/editing/InsertListCommand.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertListCommand_h
-#define InsertListCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class InsertListCommand : public CompositeEditCommand {
-public:
- enum Type { OrderedList, UnorderedList };
-
- static PassRefPtr<InsertListCommand> create(Document* document, Type listType, const String& listID)
- {
- return adoptRef(new InsertListCommand(document, listType, listID));
- }
-
- static PassRefPtr<Node> insertList(Document*, Type);
-
- virtual bool preservesTypingStyle() const { return true; }
-
-private:
- InsertListCommand(Document*, Type, const String&);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return EditActionInsertList; }
-
- Node* fixOrphanedListChild(Node*);
- bool modifyRange();
- RefPtr<Node> m_listElement;
- Type m_type;
- String m_id;
- bool m_forceCreateList;
-};
-
-} // namespace WebCore
-
-#endif // InsertListCommand_h
diff --git a/WebCore/editing/InsertNodeBeforeCommand.cpp b/WebCore/editing/InsertNodeBeforeCommand.cpp
deleted file mode 100644
index 2315597..0000000
--- a/WebCore/editing/InsertNodeBeforeCommand.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InsertNodeBeforeCommand.h"
-
-#include "htmlediting.h"
-
-namespace WebCore {
-
-InsertNodeBeforeCommand::InsertNodeBeforeCommand(PassRefPtr<Node> insertChild, PassRefPtr<Node> refChild)
- : SimpleEditCommand(refChild->document()), m_insertChild(insertChild), m_refChild(refChild)
-{
- ASSERT(m_insertChild);
- ASSERT(m_refChild);
-}
-
-void InsertNodeBeforeCommand::doApply()
-{
- ASSERT(m_insertChild);
- ASSERT(m_refChild);
- ASSERT(m_refChild->parentNode());
- // If the child to insert is already in a tree, inserting it will remove it from it's old location
- // in an non-undoable way. We might eventually find it useful to do an undoable remove in this case.
- ASSERT(!m_insertChild->parent());
- ASSERT(enclosingNodeOfType(Position(m_refChild->parentNode(), 0), &isContentEditable) || !m_refChild->parentNode()->attached());
-
- ExceptionCode ec = 0;
- m_refChild->parentNode()->insertBefore(m_insertChild.get(), m_refChild.get(), ec);
- ASSERT(ec == 0);
-}
-
-void InsertNodeBeforeCommand::doUnapply()
-{
- ASSERT(m_insertChild);
- ASSERT(m_refChild);
- ASSERT(m_refChild->parentNode());
-
- ExceptionCode ec = 0;
- m_refChild->parentNode()->removeChild(m_insertChild.get(), ec);
- ASSERT(ec == 0);
-}
-
-}
diff --git a/WebCore/editing/InsertNodeBeforeCommand.h b/WebCore/editing/InsertNodeBeforeCommand.h
deleted file mode 100644
index 0904502..0000000
--- a/WebCore/editing/InsertNodeBeforeCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertNodeBeforeCommand_h
-#define InsertNodeBeforeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class InsertNodeBeforeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<InsertNodeBeforeCommand> create(PassRefPtr<Node> childToInsert, PassRefPtr<Node> childToInsertBefore)
- {
- return adoptRef(new InsertNodeBeforeCommand(childToInsert, childToInsertBefore));
- }
-
-private:
- InsertNodeBeforeCommand(PassRefPtr<Node> childToInsert, PassRefPtr<Node> childToInsertBefore);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Node> m_insertChild;
- RefPtr<Node> m_refChild;
-};
-
-} // namespace WebCore
-
-#endif // InsertNodeBeforeCommand_h
diff --git a/WebCore/editing/InsertParagraphSeparatorCommand.cpp b/WebCore/editing/InsertParagraphSeparatorCommand.cpp
deleted file mode 100644
index bcd2bfa..0000000
--- a/WebCore/editing/InsertParagraphSeparatorCommand.cpp
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InsertParagraphSeparatorCommand.h"
-
-#include "Document.h"
-#include "Logging.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSPropertyNames.h"
-#include "Text.h"
-#include "htmlediting.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "InsertLineBreakCommand.h"
-#include "RenderObject.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand(Document *document, bool mustUseDefaultParagraphElement)
- : CompositeEditCommand(document)
- , m_mustUseDefaultParagraphElement(mustUseDefaultParagraphElement)
-{
-}
-
-bool InsertParagraphSeparatorCommand::preservesTypingStyle() const
-{
- return true;
-}
-
-void InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion(const Position &pos)
-{
- // It is only important to set a style to apply later if we're at the boundaries of
- // a paragraph. Otherwise, content that is moved as part of the work of the command
- // will lend their styles to the new paragraph without any extra work needed.
- VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
- if (!isStartOfParagraph(visiblePos) && !isEndOfParagraph(visiblePos))
- return;
-
- m_style = styleAtPosition(pos);
-}
-
-void InsertParagraphSeparatorCommand::applyStyleAfterInsertion(Node* originalEnclosingBlock)
-{
- // Not only do we break out of header tags, but we also do not preserve the typing style,
- // in order to match other browsers.
- if (originalEnclosingBlock->hasTagName(h1Tag) ||
- originalEnclosingBlock->hasTagName(h2Tag) ||
- originalEnclosingBlock->hasTagName(h3Tag) ||
- originalEnclosingBlock->hasTagName(h4Tag) ||
- originalEnclosingBlock->hasTagName(h5Tag))
- return;
-
- if (!m_style)
- return;
-
- computedStyle(endingSelection().start().node())->diff(m_style.get());
- if (m_style->length() > 0)
- applyStyle(m_style.get());
-}
-
-bool InsertParagraphSeparatorCommand::shouldUseDefaultParagraphElement(Node* enclosingBlock) const
-{
- if (m_mustUseDefaultParagraphElement)
- return true;
-
- // Assumes that if there was a range selection, it was already deleted.
- if (!isEndOfBlock(endingSelection().visibleStart()))
- return false;
-
- return enclosingBlock->hasTagName(h1Tag) ||
- enclosingBlock->hasTagName(h2Tag) ||
- enclosingBlock->hasTagName(h3Tag) ||
- enclosingBlock->hasTagName(h4Tag) ||
- enclosingBlock->hasTagName(h5Tag);
-}
-
-void InsertParagraphSeparatorCommand::doApply()
-{
- bool splitText = false;
- if (endingSelection().isNone())
- return;
-
- Position pos = endingSelection().start();
-
- EAffinity affinity = endingSelection().affinity();
-
- // Delete the current selection.
- if (endingSelection().isRange()) {
- calculateStyleBeforeInsertion(pos);
- deleteSelection(false, true);
- pos = endingSelection().start();
- affinity = endingSelection().affinity();
- }
-
- // FIXME: The rangeCompliantEquivalent conversion needs to be moved into enclosingBlock.
- Node* startBlock = enclosingBlock(rangeCompliantEquivalent(pos).node());
- Position canonicalPos = VisiblePosition(pos).deepEquivalent();
- if (!startBlock || !startBlock->parentNode() ||
- isTableCell(startBlock) ||
- startBlock->hasTagName(formTag) ||
- canonicalPos.node()->renderer() && canonicalPos.node()->renderer()->isTable() ||
- canonicalPos.node()->hasTagName(hrTag)) {
- applyCommandToComposite(InsertLineBreakCommand::create(document()));
- return;
- }
-
- // Use the leftmost candidate.
- pos = pos.upstream();
- if (!pos.isCandidate())
- pos = pos.downstream();
-
- // Adjust the insertion position after the delete
- pos = positionAvoidingSpecialElementBoundary(pos);
- VisiblePosition visiblePos(pos, affinity);
- calculateStyleBeforeInsertion(pos);
-
- //---------------------------------------------------------------------
- // Handle special case of typing return on an empty list item
- if (breakOutOfEmptyListItem())
- return;
-
- //---------------------------------------------------------------------
- // Prepare for more general cases.
- // FIXME: We shouldn't peel off the node here because then we lose track of
- // the fact that it's the node that belongs to an editing position and
- // not a rangeCompliantEquivalent.
- Node *startNode = pos.node();
-
- bool isFirstInBlock = isStartOfBlock(visiblePos);
- bool isLastInBlock = isEndOfBlock(visiblePos);
- bool nestNewBlock = false;
-
- // Create block to be inserted.
- RefPtr<Node> blockToInsert;
- if (startBlock == startBlock->rootEditableElement()) {
- blockToInsert = static_pointer_cast<Node>(createDefaultParagraphElement(document()));
- nestNewBlock = true;
- } else if (shouldUseDefaultParagraphElement(startBlock))
- blockToInsert = static_pointer_cast<Node>(createDefaultParagraphElement(document()));
- else
- blockToInsert = startBlock->cloneNode(false);
-
- //---------------------------------------------------------------------
- // Handle case when position is in the last visible position in its block,
- // including when the block is empty.
- if (isLastInBlock) {
- if (nestNewBlock) {
- if (isFirstInBlock && !lineBreakExistsAtPosition(visiblePos)) {
- // The block is empty. Create an empty block to
- // represent the paragraph that we're leaving.
- RefPtr<Node> extraBlock = createDefaultParagraphElement(document());
- appendNode(extraBlock.get(), startBlock);
- appendBlockPlaceholder(extraBlock.get());
- }
- appendNode(blockToInsert.get(), startBlock);
- } else
- insertNodeAfter(blockToInsert.get(), startBlock);
-
- appendBlockPlaceholder(blockToInsert.get());
- setEndingSelection(Selection(Position(blockToInsert.get(), 0), DOWNSTREAM));
- applyStyleAfterInsertion(startBlock);
- return;
- }
-
- //---------------------------------------------------------------------
- // Handle case when position is in the first visible position in its block, and
- // similar case where previous position is in another, presumeably nested, block.
- if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) {
- Node *refNode;
- if (isFirstInBlock && !nestNewBlock)
- refNode = startBlock;
- else if (pos.node() == startBlock && nestNewBlock) {
- refNode = startBlock->childNode(pos.offset());
- ASSERT(refNode); // must be true or we'd be in the end of block case
- } else
- refNode = pos.node();
-
- // find ending selection position easily before inserting the paragraph
- pos = pos.downstream();
-
- insertNodeBefore(blockToInsert.get(), refNode);
- appendBlockPlaceholder(blockToInsert.get());
- setEndingSelection(Selection(Position(blockToInsert.get(), 0), DOWNSTREAM));
- applyStyleAfterInsertion(startBlock);
- setEndingSelection(Selection(pos, DOWNSTREAM));
- return;
- }
-
- //---------------------------------------------------------------------
- // Handle the (more complicated) general case,
-
- // All of the content in the current block after visiblePos is
- // about to be wrapped in a new paragraph element. Add a br before
- // it if visiblePos is at the start of a paragraph so that the
- // content will move down a line.
- if (isStartOfParagraph(visiblePos)) {
- RefPtr<Element> br = createBreakElement(document());
- insertNodeAt(br.get(), pos);
- pos = positionAfterNode(br.get());
- }
-
- // Move downstream. Typing style code will take care of carrying along the
- // style of the upstream position.
- pos = pos.downstream();
- startNode = pos.node();
-
- // Build up list of ancestors in between the start node and the start block.
- Vector<Node*> ancestors;
- if (startNode != startBlock)
- for (Node* n = startNode->parentNode(); n && n != startBlock; n = n->parentNode())
- ancestors.append(n);
-
- // Make sure we do not cause a rendered space to become unrendered.
- // FIXME: We need the affinity for pos, but pos.downstream() does not give it
- Position leadingWhitespace = pos.leadingWhitespacePosition(VP_DEFAULT_AFFINITY);
- // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
- // after the preserved newline, causing the newline to be turned into a nbsp.
- if (leadingWhitespace.isNotNull()) {
- Text* textNode = static_cast<Text*>(leadingWhitespace.node());
- ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
- replaceTextInNode(textNode, leadingWhitespace.offset(), 1, nonBreakingSpaceString());
- }
-
- // Split at pos if in the middle of a text node.
- if (startNode->isTextNode()) {
- Text *textNode = static_cast<Text *>(startNode);
- bool atEnd = (unsigned)pos.offset() >= textNode->length();
- if (pos.offset() > 0 && !atEnd) {
- splitTextNode(textNode, pos.offset());
- pos = Position(startNode, 0);
- visiblePos = VisiblePosition(pos);
- splitText = true;
- }
- }
-
- // Put the added block in the tree.
- if (nestNewBlock)
- appendNode(blockToInsert.get(), startBlock);
- else
- insertNodeAfter(blockToInsert.get(), startBlock);
-
- updateLayout();
-
- // Make clones of ancestors in between the start node and the start block.
- RefPtr<Node> parent = blockToInsert;
- for (size_t i = ancestors.size(); i != 0; --i) {
- RefPtr<Node> child = ancestors[i - 1]->cloneNode(false); // shallow clone
- appendNode(child.get(), parent.get());
- parent = child.release();
- }
-
- // If the paragraph separator was inserted at the end of a paragraph, an empty line must be
- // created. All of the nodes, starting at visiblePos, are about to be added to the new paragraph
- // element. If the first node to be inserted won't be one that will hold an empty line open, add a br.
- if (isEndOfParagraph(visiblePos) && !lineBreakExistsAtPosition(visiblePos))
- appendNode(createBreakElement(document()).get(), blockToInsert.get());
-
- // Move the start node and the siblings of the start node.
- if (startNode != startBlock) {
- Node *n = startNode;
- if (pos.offset() >= caretMaxOffset(startNode))
- n = startNode->nextSibling();
-
- while (n && n != blockToInsert) {
- Node *next = n->nextSibling();
- removeNode(n);
- appendNode(n, parent.get());
- n = next;
- }
- }
-
- // Move everything after the start node.
- if (!ancestors.isEmpty()) {
- Node* leftParent = ancestors.first();
- while (leftParent && leftParent != startBlock) {
- parent = parent->parentNode();
- Node* n = leftParent->nextSibling();
- while (n && n != blockToInsert) {
- Node* next = n->nextSibling();
- removeNode(n);
- appendNode(n, parent.get());
- n = next;
- }
- leftParent = leftParent->parentNode();
- }
- }
-
- // Handle whitespace that occurs after the split
- if (splitText) {
- updateLayout();
- pos = Position(startNode, 0);
- if (!pos.isRenderedCharacter()) {
- // Clear out all whitespace and insert one non-breaking space
- ASSERT(startNode);
- ASSERT(startNode->isTextNode());
- ASSERT(!startNode->renderer() || startNode->renderer()->style()->collapseWhiteSpace());
- deleteInsignificantTextDownstream(pos);
- insertTextIntoNode(static_cast<Text*>(startNode), 0, nonBreakingSpaceString());
- }
- }
-
- setEndingSelection(Selection(Position(blockToInsert.get(), 0), DOWNSTREAM));
- applyStyleAfterInsertion(startBlock);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/InsertParagraphSeparatorCommand.h b/WebCore/editing/InsertParagraphSeparatorCommand.h
deleted file mode 100644
index 01c08bf..0000000
--- a/WebCore/editing/InsertParagraphSeparatorCommand.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertParagraphSeparatorCommand_h
-#define InsertParagraphSeparatorCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class InsertParagraphSeparatorCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<InsertParagraphSeparatorCommand> create(Document* document, bool useDefaultParagraphElement = false)
- {
- return adoptRef(new InsertParagraphSeparatorCommand(document, useDefaultParagraphElement));
- }
-
-private:
- InsertParagraphSeparatorCommand(Document*, bool useDefaultParagraphElement);
-
- virtual void doApply();
-
- void calculateStyleBeforeInsertion(const Position&);
- void applyStyleAfterInsertion(Node* originalEnclosingBlock);
-
- bool shouldUseDefaultParagraphElement(Node*) const;
-
- virtual bool preservesTypingStyle() const;
-
- RefPtr<CSSMutableStyleDeclaration> m_style;
-
- bool m_mustUseDefaultParagraphElement;
-};
-
-}
-
-#endif
diff --git a/WebCore/editing/InsertTextCommand.cpp b/WebCore/editing/InsertTextCommand.cpp
deleted file mode 100644
index a831859..0000000
--- a/WebCore/editing/InsertTextCommand.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InsertTextCommand.h"
-
-#include "CharacterNames.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "Document.h"
-#include "Element.h"
-#include "EditingText.h"
-#include "Editor.h"
-#include "Frame.h"
-#include "Logging.h"
-#include "HTMLInterchange.h"
-#include "htmlediting.h"
-#include "TextIterator.h"
-#include "TypingCommand.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-InsertTextCommand::InsertTextCommand(Document *document)
- : CompositeEditCommand(document), m_charactersAdded(0)
-{
-}
-
-void InsertTextCommand::doApply()
-{
-}
-
-Position InsertTextCommand::prepareForTextInsertion(const Position& p)
-{
- Position pos = p;
- // If an anchor was removed and the selection hasn't changed, we restore it.
- RefPtr<Node> anchor = document()->frame()->editor()->removedAnchor();
- if (anchor) {
- insertNodeAt(anchor.get(), pos);
- document()->frame()->editor()->setRemovedAnchor(0);
- pos = Position(anchor.get(), 0);
- }
- // Prepare for text input by looking at the specified position.
- // It may be necessary to insert a text node to receive characters.
- if (!pos.node()->isTextNode()) {
- RefPtr<Node> textNode = document()->createEditingTextNode("");
- insertNodeAt(textNode.get(), pos);
- return Position(textNode.get(), 0);
- }
-
- if (isTabSpanTextNode(pos.node())) {
- RefPtr<Node> textNode = document()->createEditingTextNode("");
- insertNodeAtTabSpanPosition(textNode.get(), pos);
- return Position(textNode.get(), 0);
- }
-
- return pos;
-}
-
-// This avoids the expense of a full fledged delete operation, and avoids a layout that typically results
-// from text removal.
-bool InsertTextCommand::performTrivialReplace(const String& text, bool selectInsertedText)
-{
- if (!endingSelection().isRange())
- return false;
-
- if (text.contains('\t') || text.contains(' ') || text.contains('\n'))
- return false;
-
- Position start = endingSelection().start();
- Position end = endingSelection().end();
-
- if (start.node() != end.node() || !start.node()->isTextNode() || isTabSpanTextNode(start.node()))
- return false;
-
- replaceTextInNode(static_cast<Text*>(start.node()), start.offset(), end.offset() - start.offset(), text);
-
- Position endPosition(start.node(), start.offset() + text.length());
-
- // We could have inserted a part of composed character sequence,
- // so we are basically treating ending selection as a range to avoid validation.
- // <http://bugs.webkit.org/show_bug.cgi?id=15781>
- Selection forcedEndingSelection;
- forcedEndingSelection.setWithoutValidation(start, endPosition);
- setEndingSelection(forcedEndingSelection);
-
- if (!selectInsertedText)
- setEndingSelection(Selection(endingSelection().visibleEnd()));
-
- return true;
-}
-
-void InsertTextCommand::input(const String& originalText, bool selectInsertedText)
-{
- String text = originalText;
-
- ASSERT(text.find('\n') == -1);
-
- if (endingSelection().isNone())
- return;
-
- if (RenderObject* renderer = endingSelection().start().node()->renderer())
- if (renderer->style()->collapseWhiteSpace())
- // Turn all spaces into non breaking spaces, to make sure that they are treated
- // literally, and aren't collapsed after insertion. They will be rebalanced
- // (turned into a sequence of regular and non breaking spaces) below.
- text.replace(' ', noBreakSpace);
-
- // Delete the current selection.
- // FIXME: This delete operation blows away the typing style.
- if (endingSelection().isRange()) {
- if (performTrivialReplace(text, selectInsertedText))
- return;
- deleteSelection(false, true, true, false);
- }
-
- // Insert the character at the leftmost candidate.
- Position startPosition = endingSelection().start().upstream();
- // It is possible for the node that contains startPosition to contain only unrendered whitespace,
- // and so deleteInsignificantText could remove it. Save the position before the node in case that happens.
- Position positionBeforeStartNode(positionBeforeNode(startPosition.node()));
- deleteInsignificantText(startPosition.upstream(), startPosition.downstream());
- if (!startPosition.node()->inDocument())
- startPosition = positionBeforeStartNode;
- if (!startPosition.isCandidate())
- startPosition = startPosition.downstream();
-
- // FIXME: This typing around anchor behavior doesn't exactly match TextEdit. In TextEdit,
- // you won't be placed inside a link when typing after it if you've just placed the caret
- // there with the mouse.
- startPosition = positionAvoidingSpecialElementBoundary(startPosition, false);
-
- Position endPosition;
-
- if (text == "\t") {
- endPosition = insertTab(startPosition);
- startPosition = endPosition.previous();
- removePlaceholderAt(VisiblePosition(startPosition));
- m_charactersAdded += 1;
- } else {
- // Make sure the document is set up to receive text
- startPosition = prepareForTextInsertion(startPosition);
- removePlaceholderAt(VisiblePosition(startPosition));
- Text *textNode = static_cast<Text *>(startPosition.node());
- int offset = startPosition.offset();
-
- insertTextIntoNode(textNode, offset, text);
- endPosition = Position(textNode, offset + text.length());
-
- // The insertion may require adjusting adjacent whitespace, if it is present.
- rebalanceWhitespaceAt(endPosition);
- // Rebalancing on both sides isn't necessary if we've inserted a space.
- if (originalText != " ")
- rebalanceWhitespaceAt(startPosition);
-
- m_charactersAdded += text.length();
- }
-
- // We could have inserted a part of composed character sequence,
- // so we are basically treating ending selection as a range to avoid validation.
- // <http://bugs.webkit.org/show_bug.cgi?id=15781>
- Selection forcedEndingSelection;
- forcedEndingSelection.setWithoutValidation(startPosition, endPosition);
- setEndingSelection(forcedEndingSelection);
-
- // Handle the case where there is a typing style.
- CSSMutableStyleDeclaration* typingStyle = document()->frame()->typingStyle();
- RefPtr<CSSComputedStyleDeclaration> endingStyle = endPosition.computedStyle();
- endingStyle->diff(typingStyle);
- if (typingStyle && typingStyle->length() > 0)
- applyStyle(typingStyle);
-
- if (!selectInsertedText)
- setEndingSelection(Selection(endingSelection().end(), endingSelection().affinity()));
-}
-
-Position InsertTextCommand::insertTab(const Position& pos)
-{
- Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent();
-
- Node *node = insertPos.node();
- unsigned int offset = insertPos.offset();
-
- // keep tabs coalesced in tab span
- if (isTabSpanTextNode(node)) {
- insertTextIntoNode(static_cast<Text *>(node), offset, "\t");
- return Position(node, offset + 1);
- }
-
- // create new tab span
- RefPtr<Element> spanNode = createTabSpanElement(document());
-
- // place it
- if (!node->isTextNode()) {
- insertNodeAt(spanNode.get(), insertPos);
- } else {
- Text *textNode = static_cast<Text *>(node);
- if (offset >= textNode->length()) {
- insertNodeAfter(spanNode.get(), textNode);
- } else {
- // split node to make room for the span
- // NOTE: splitTextNode uses textNode for the
- // second node in the split, so we need to
- // insert the span before it.
- if (offset > 0)
- splitTextNode(textNode, offset);
- insertNodeBefore(spanNode.get(), textNode);
- }
- }
-
- // return the position following the new tab
- return Position(spanNode->lastChild(), caretMaxOffset(spanNode->lastChild()));
-}
-
-bool InsertTextCommand::isInsertTextCommand() const
-{
- return true;
-}
-
-}
diff --git a/WebCore/editing/InsertTextCommand.h b/WebCore/editing/InsertTextCommand.h
deleted file mode 100644
index 650ca65..0000000
--- a/WebCore/editing/InsertTextCommand.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef InsertTextCommand_h
-#define InsertTextCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class InsertTextCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<InsertTextCommand> create(Document* document)
- {
- return adoptRef(new InsertTextCommand(document));
- }
-
- void input(const String& text, bool selectInsertedText = false);
-
-private:
- InsertTextCommand(Document*);
-
- void deleteCharacter();
- unsigned charactersAdded() const { return m_charactersAdded; }
-
- virtual void doApply();
- virtual bool isInsertTextCommand() const;
-
- Position prepareForTextInsertion(const Position&);
- Position insertTab(const Position&);
-
- bool performTrivialReplace(const String&, bool selectInsertedText);
-
- unsigned m_charactersAdded;
-};
-
-} // namespace WebCore
-
-#endif // InsertTextCommand_h
diff --git a/WebCore/editing/JoinTextNodesCommand.cpp b/WebCore/editing/JoinTextNodesCommand.cpp
deleted file mode 100644
index dddf43c..0000000
--- a/WebCore/editing/JoinTextNodesCommand.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "JoinTextNodesCommand.h"
-
-#include "Text.h"
-
-namespace WebCore {
-
-JoinTextNodesCommand::JoinTextNodesCommand(PassRefPtr<Text> text1, PassRefPtr<Text> text2)
- : SimpleEditCommand(text1->document()), m_text1(text1), m_text2(text2)
-{
- ASSERT(m_text1);
- ASSERT(m_text2);
- ASSERT(m_text1->nextSibling() == m_text2);
- ASSERT(m_text1->length() > 0);
- ASSERT(m_text2->length() > 0);
-}
-
-void JoinTextNodesCommand::doApply()
-{
- ASSERT(m_text1);
- ASSERT(m_text2);
- ASSERT(m_text1->nextSibling() == m_text2);
-
- ExceptionCode ec = 0;
- m_text2->insertData(0, m_text1->data(), ec);
- ASSERT(ec == 0);
-
- m_text2->parentNode()->removeChild(m_text1.get(), ec);
- ASSERT(ec == 0);
-
- m_offset = m_text1->length();
-}
-
-void JoinTextNodesCommand::doUnapply()
-{
- ASSERT(m_text2);
- ASSERT(m_offset > 0);
-
- ExceptionCode ec = 0;
-
- m_text2->deleteData(0, m_offset, ec);
- ASSERT(ec == 0);
-
- m_text2->parentNode()->insertBefore(m_text1.get(), m_text2.get(), ec);
- ASSERT(ec == 0);
-
- ASSERT(m_text2->previousSibling()->isTextNode());
- ASSERT(m_text2->previousSibling() == m_text1);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/JoinTextNodesCommand.h b/WebCore/editing/JoinTextNodesCommand.h
deleted file mode 100644
index 6fb5c56..0000000
--- a/WebCore/editing/JoinTextNodesCommand.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef JoinTextNodesCommand_h
-#define JoinTextNodesCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class Text;
-
-class JoinTextNodesCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<JoinTextNodesCommand> create(PassRefPtr<Text> text1, PassRefPtr<Text> text2)
- {
- return adoptRef(new JoinTextNodesCommand(text1, text2));
- }
-
-private:
- JoinTextNodesCommand(PassRefPtr<Text>, PassRefPtr<Text>);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Text> m_text1;
- RefPtr<Text> m_text2;
- unsigned m_offset;
-};
-
-} // namespace WebCore
-
-#endif // JoinTextNodesCommand_h
diff --git a/WebCore/editing/MergeIdenticalElementsCommand.cpp b/WebCore/editing/MergeIdenticalElementsCommand.cpp
deleted file mode 100644
index 1819b92..0000000
--- a/WebCore/editing/MergeIdenticalElementsCommand.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MergeIdenticalElementsCommand.h"
-
-#include "Element.h"
-
-namespace WebCore {
-
-MergeIdenticalElementsCommand::MergeIdenticalElementsCommand(PassRefPtr<Element> first, PassRefPtr<Element> second)
- : SimpleEditCommand(first->document()), m_element1(first), m_element2(second)
-{
- ASSERT(m_element1);
- ASSERT(m_element2);
-}
-
-void MergeIdenticalElementsCommand::doApply()
-{
- ASSERT(m_element1);
- ASSERT(m_element2);
- ASSERT(m_element1->nextSibling() == m_element2);
-
- ExceptionCode ec = 0;
-
- if (!m_atChild)
- m_atChild = m_element2->firstChild();
-
- while (m_element1->lastChild()) {
- m_element2->insertBefore(m_element1->lastChild(), m_element2->firstChild(), ec);
- ASSERT(ec == 0);
- }
-
- m_element2->parentNode()->removeChild(m_element1.get(), ec);
- ASSERT(ec == 0);
-}
-
-void MergeIdenticalElementsCommand::doUnapply()
-{
- ASSERT(m_element1);
- ASSERT(m_element2);
-
- ExceptionCode ec = 0;
-
- m_element2->parent()->insertBefore(m_element1.get(), m_element2.get(), ec);
- ASSERT(ec == 0);
-
- while (m_element2->firstChild() != m_atChild) {
- ASSERT(m_element2->firstChild());
- m_element1->appendChild(m_element2->firstChild(), ec);
- ASSERT(ec == 0);
- }
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/MergeIdenticalElementsCommand.h b/WebCore/editing/MergeIdenticalElementsCommand.h
deleted file mode 100644
index 1ce6302..0000000
--- a/WebCore/editing/MergeIdenticalElementsCommand.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef MergeIdenticalElementsCommand_h
-#define MergeIdenticalElementsCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class MergeIdenticalElementsCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<MergeIdenticalElementsCommand> create(PassRefPtr<Element> element1, PassRefPtr<Element> element2)
- {
- return adoptRef(new MergeIdenticalElementsCommand(element1, element2));
- }
-
-private:
- MergeIdenticalElementsCommand(PassRefPtr<Element>, PassRefPtr<Element>);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Element> m_element1;
- RefPtr<Element> m_element2;
- RefPtr<Node> m_atChild;
-};
-
-} // namespace WebCore
-
-#endif // MergeIdenticalElementsCommand_h
diff --git a/WebCore/editing/ModifySelectionListLevel.cpp b/WebCore/editing/ModifySelectionListLevel.cpp
deleted file mode 100644
index 0b1123b..0000000
--- a/WebCore/editing/ModifySelectionListLevel.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ModifySelectionListLevel.h"
-
-#include "Document.h"
-#include "Element.h"
-#include "Frame.h"
-#include "RenderObject.h"
-#include "SelectionController.h"
-#include "htmlediting.h"
-
-namespace WebCore {
-
-ModifySelectionListLevelCommand::ModifySelectionListLevelCommand(Document* document)
- : CompositeEditCommand(document)
-{
-}
-
-bool ModifySelectionListLevelCommand::preservesTypingStyle() const
-{
- return true;
-}
-
-// This needs to be static so it can be called by canIncreaseSelectionListLevel and canDecreaseSelectionListLevel
-static bool getStartEndListChildren(const Selection& selection, Node*& start, Node*& end)
-{
- if (selection.isNone())
- return false;
-
- // start must be in a list child
- Node* startListChild = enclosingListChild(selection.start().node());
- if (!startListChild)
- return false;
-
- // end must be in a list child
- Node* endListChild = selection.isRange() ? enclosingListChild(selection.end().node()) : startListChild;
- if (!endListChild)
- return false;
-
- // For a range selection we want the following behavior:
- // - the start and end must be within the same overall list
- // - the start must be at or above the level of the rest of the range
- // - if the end is anywhere in a sublist lower than start, the whole sublist gets moved
- // In terms of this function, this means:
- // - endListChild must start out being be a sibling of startListChild, or be in a
- // sublist of startListChild or a sibling
- // - if endListChild is in a sublist of startListChild or a sibling, it must be adjusted
- // to be the ancestor that is startListChild or its sibling
- while (startListChild->parentNode() != endListChild->parentNode()) {
- endListChild = endListChild->parentNode();
- if (!endListChild)
- return false;
- }
-
- // if the selection ends on a list item with a sublist, include the entire sublist
- if (endListChild->renderer()->isListItem()) {
- RenderObject* r = endListChild->renderer()->nextSibling();
- if (r && isListElement(r->element()))
- endListChild = r->element();
- }
-
- start = startListChild;
- end = endListChild;
- return true;
-}
-
-void ModifySelectionListLevelCommand::insertSiblingNodeRangeBefore(Node* startNode, Node* endNode, Node* refNode)
-{
- Node* node = startNode;
- while (1) {
- Node* next = node->nextSibling();
- removeNode(node);
- insertNodeBefore(node, refNode);
-
- if (node == endNode)
- break;
-
- node = next;
- }
-}
-
-void ModifySelectionListLevelCommand::insertSiblingNodeRangeAfter(Node* startNode, Node* endNode, Node* refNode)
-{
- Node* node = startNode;
- while (1) {
- Node* next = node->nextSibling();
- removeNode(node);
- insertNodeAfter(node, refNode);
-
- if (node == endNode)
- break;
-
- refNode = node;
- node = next;
- }
-}
-
-void ModifySelectionListLevelCommand::appendSiblingNodeRange(Node* startNode, Node* endNode, Node* newParent)
-{
- Node* node = startNode;
- while (1) {
- Node* next = node->nextSibling();
- removeNode(node);
- appendNode(node, newParent);
-
- if (node == endNode)
- break;
-
- node = next;
- }
-}
-
-IncreaseSelectionListLevelCommand::IncreaseSelectionListLevelCommand(Document* document, Type listType)
- : ModifySelectionListLevelCommand(document)
- , m_listType(listType)
-{
-}
-
-// This needs to be static so it can be called by canIncreaseSelectionListLevel
-static bool canIncreaseListLevel(const Selection& selection, Node*& start, Node*& end)
-{
- if (!getStartEndListChildren(selection, start, end))
- return false;
-
- // start must not be the first child (because you need a prior one
- // to increase relative to)
- if (!start->renderer()->previousSibling())
- return false;
-
- return true;
-}
-
-// For the moment, this is SPI and the only client (Mail.app) is satisfied.
-// Here are two things to re-evaluate when making into API.
-// 1. Currently, InheritedListType uses clones whereas OrderedList and
-// UnorderedList create a new list node of the specified type. That is
-// inconsistent wrt style. If that is not OK, here are some alternatives:
-// - new nodes always inherit style (probably the best choice)
-// - new nodes have always have no style
-// - new nodes of the same type inherit style
-// 2. Currently, the node we return may be either a pre-existing one or
-// a new one. Is it confusing to return the pre-existing one without
-// somehow indicating that it is not new? If so, here are some alternatives:
-// - only return the list node if we created it
-// - indicate whether the list node is new or pre-existing
-// - (silly) client specifies whether to return pre-existing list nodes
-void IncreaseSelectionListLevelCommand::doApply()
-{
- Node* startListChild;
- Node* endListChild;
- if (!canIncreaseListLevel(endingSelection(), startListChild, endListChild))
- return;
-
- Node* previousItem = startListChild->renderer()->previousSibling()->element();
- if (isListElement(previousItem)) {
- // move nodes up into preceding list
- appendSiblingNodeRange(startListChild, endListChild, previousItem);
- m_listElement = previousItem;
- } else {
- // create a sublist for the preceding element and move nodes there
- RefPtr<Node> newParent;
- switch (m_listType) {
- case InheritedListType:
- newParent = startListChild->parentNode()->cloneNode(false);
- break;
- case OrderedList:
- newParent = createOrderedListElement(document());
- break;
- case UnorderedList:
- newParent = createUnorderedListElement(document());
- break;
- }
- insertNodeBefore(newParent.get(), startListChild);
- appendSiblingNodeRange(startListChild, endListChild, newParent.get());
- m_listElement = newParent.get();
- }
-}
-
-bool IncreaseSelectionListLevelCommand::canIncreaseSelectionListLevel(Document* document)
-{
- Node* startListChild;
- Node* endListChild;
- return canIncreaseListLevel(document->frame()->selection()->selection(), startListChild, endListChild);
-}
-
-PassRefPtr<Node> IncreaseSelectionListLevelCommand::increaseSelectionListLevelWithType(Document* document, Type listType)
-{
- ASSERT(document);
- ASSERT(document->frame());
- RefPtr<IncreaseSelectionListLevelCommand> modCommand = new IncreaseSelectionListLevelCommand(document, listType);
- modCommand->apply();
- return modCommand->m_listElement;
-}
-
-PassRefPtr<Node> IncreaseSelectionListLevelCommand::increaseSelectionListLevel(Document* document)
-{
- return increaseSelectionListLevelWithType(document, InheritedListType);
-}
-
-PassRefPtr<Node> IncreaseSelectionListLevelCommand::increaseSelectionListLevelOrdered(Document* document)
-{
- return increaseSelectionListLevelWithType(document, OrderedList);
-}
-
-PassRefPtr<Node> IncreaseSelectionListLevelCommand::increaseSelectionListLevelUnordered(Document* document)
-{
- return increaseSelectionListLevelWithType(document, UnorderedList);
-}
-
-DecreaseSelectionListLevelCommand::DecreaseSelectionListLevelCommand(Document* document)
- : ModifySelectionListLevelCommand(document)
-{
-}
-
-// This needs to be static so it can be called by canDecreaseSelectionListLevel
-static bool canDecreaseListLevel(const Selection& selection, Node*& start, Node*& end)
-{
- if (!getStartEndListChildren(selection, start, end))
- return false;
-
- // there must be a destination list to move the items to
- if (!isListElement(start->parentNode()->parentNode()))
- return false;
-
- return true;
-}
-
-void DecreaseSelectionListLevelCommand::doApply()
-{
- Node* startListChild;
- Node* endListChild;
- if (!canDecreaseListLevel(endingSelection(), startListChild, endListChild))
- return;
-
- Node* previousItem = startListChild->renderer()->previousSibling() ? startListChild->renderer()->previousSibling()->element() : 0;
- Node* nextItem = endListChild->renderer()->nextSibling() ? endListChild->renderer()->nextSibling()->element() : 0;
- Node* listNode = startListChild->parentNode();
-
- if (!previousItem) {
- // at start of sublist, move the child(ren) to before the sublist
- insertSiblingNodeRangeBefore(startListChild, endListChild, listNode);
- // if that was the whole sublist we moved, remove the sublist node
- if (!nextItem)
- removeNode(listNode);
- } else if (!nextItem) {
- // at end of list, move the child(ren) to after the sublist
- insertSiblingNodeRangeAfter(startListChild, endListChild, listNode);
- } else {
- // in the middle of list, split the list and move the children to the divide
- splitElement(static_cast<Element*>(listNode), startListChild);
- insertSiblingNodeRangeBefore(startListChild, endListChild, listNode);
- }
-}
-
-bool DecreaseSelectionListLevelCommand::canDecreaseSelectionListLevel(Document* document)
-{
- Node* startListChild;
- Node* endListChild;
- return canDecreaseListLevel(document->frame()->selection()->selection(), startListChild, endListChild);
-}
-
-void DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(Document* document)
-{
- ASSERT(document);
- ASSERT(document->frame());
- applyCommand(new DecreaseSelectionListLevelCommand(document));
-}
-
-}
diff --git a/WebCore/editing/ModifySelectionListLevel.h b/WebCore/editing/ModifySelectionListLevel.h
deleted file mode 100644
index 1e66d10..0000000
--- a/WebCore/editing/ModifySelectionListLevel.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ModifySelectionListLevel_h
-#define ModifySelectionListLevel_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-// ModifySelectionListLevelCommand provides functions useful for both increasing and decreasing the list level.
-// It is the base class of IncreaseSelectionListLevelCommand and DecreaseSelectionListLevelCommand.
-// It is not used on its own.
-class ModifySelectionListLevelCommand : public CompositeEditCommand {
-protected:
- ModifySelectionListLevelCommand(Document*);
-
- void appendSiblingNodeRange(Node* startNode, Node* endNode, Node* newParent);
- void insertSiblingNodeRangeBefore(Node* startNode, Node* endNode, Node* refNode);
- void insertSiblingNodeRangeAfter(Node* startNode, Node* endNode, Node* refNode);
-
-private:
- virtual bool preservesTypingStyle() const;
-};
-
-// IncreaseSelectionListLevelCommand moves the selected list items one level deeper.
-class IncreaseSelectionListLevelCommand : public ModifySelectionListLevelCommand {
-public:
- static bool canIncreaseSelectionListLevel(Document*);
- static PassRefPtr<Node> increaseSelectionListLevel(Document*);
- static PassRefPtr<Node> increaseSelectionListLevelOrdered(Document*);
- static PassRefPtr<Node> increaseSelectionListLevelUnordered(Document*);
-
-private:
- enum Type { InheritedListType, OrderedList, UnorderedList };
- static PassRefPtr<Node> increaseSelectionListLevelWithType(Document*, Type listType);
-
- IncreaseSelectionListLevelCommand(Document*, Type);
- virtual void doApply();
-
- Type m_listType;
- RefPtr<Node> m_listElement;
-};
-
-// DecreaseSelectionListLevelCommand moves the selected list items one level shallower.
-class DecreaseSelectionListLevelCommand : public ModifySelectionListLevelCommand {
-public:
- static bool canDecreaseSelectionListLevel(Document*);
- static void decreaseSelectionListLevel(Document*);
-
-private:
- DecreaseSelectionListLevelCommand(Document*);
- virtual void doApply();
-};
-
-} // namespace WebCore
-
-#endif // ModifySelectionListLevel_h
diff --git a/WebCore/editing/MoveSelectionCommand.cpp b/WebCore/editing/MoveSelectionCommand.cpp
deleted file mode 100644
index 08587cb..0000000
--- a/WebCore/editing/MoveSelectionCommand.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MoveSelectionCommand.h"
-
-#include "DocumentFragment.h"
-#include "ReplaceSelectionCommand.h"
-
-namespace WebCore {
-
-MoveSelectionCommand::MoveSelectionCommand(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartMove)
- : CompositeEditCommand(position.node()->document()), m_fragment(fragment), m_position(position), m_smartMove(smartMove)
-{
- ASSERT(m_fragment);
-}
-
-void MoveSelectionCommand::doApply()
-{
- Selection selection = endingSelection();
- ASSERT(selection.isRange());
-
- Position pos = m_position;
- if (pos.isNull())
- return;
-
- // Update the position otherwise it may become invalid after the selection is deleted.
- Node *positionNode = m_position.node();
- int positionOffset = m_position.offset();
- Position selectionEnd = selection.end();
- int selectionEndOffset = selectionEnd.offset();
- if (selectionEnd.node() == positionNode && selectionEndOffset < positionOffset) {
- positionOffset -= selectionEndOffset;
- Position selectionStart = selection.start();
- if (selectionStart.node() == positionNode) {
- positionOffset += selectionStart.offset();
- }
- pos = Position(positionNode, positionOffset);
- }
-
- deleteSelection(m_smartMove);
-
- // If the node for the destination has been removed as a result of the deletion,
- // set the destination to the ending point after the deletion.
- // Fixes: <rdar://problem/3910425> REGRESSION (Mail): Crash in ReplaceSelectionCommand;
- // selection is empty, leading to null deref
- if (!pos.node()->inDocument())
- pos = endingSelection().start();
-
- setEndingSelection(Selection(pos, endingSelection().affinity()));
- applyCommandToComposite(ReplaceSelectionCommand::create(positionNode->document(), m_fragment, true, m_smartMove));
-}
-
-EditAction MoveSelectionCommand::editingAction() const
-{
- return EditActionDrag;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/MoveSelectionCommand.h b/WebCore/editing/MoveSelectionCommand.h
deleted file mode 100644
index 253c02c..0000000
--- a/WebCore/editing/MoveSelectionCommand.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef MoveSelectionCommand_h
-#define MoveSelectionCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class DocumentFragment;
-
-class MoveSelectionCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<MoveSelectionCommand> create(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartMove = false)
- {
- return adoptRef(new MoveSelectionCommand(fragment, position, smartMove));
- }
-
-private:
- MoveSelectionCommand(PassRefPtr<DocumentFragment>, const Position&, bool smartMove);
-
- virtual void doApply();
- virtual EditAction editingAction() const;
-
- RefPtr<DocumentFragment> m_fragment;
- Position m_position;
- bool m_smartMove;
-};
-
-} // namespace WebCore
-
-#endif // MoveSelectionCommand_h
diff --git a/WebCore/editing/RemoveCSSPropertyCommand.cpp b/WebCore/editing/RemoveCSSPropertyCommand.cpp
deleted file mode 100644
index d4afed0..0000000
--- a/WebCore/editing/RemoveCSSPropertyCommand.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RemoveCSSPropertyCommand.h"
-
-#include "CSSMutableStyleDeclaration.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-RemoveCSSPropertyCommand::RemoveCSSPropertyCommand(Document* document, CSSStyleDeclaration* decl, int property)
- : SimpleEditCommand(document)
- , m_decl(decl->makeMutable())
- , m_property(property)
- , m_important(false)
-{
- ASSERT(m_decl);
-}
-
-void RemoveCSSPropertyCommand::doApply()
-{
- ASSERT(m_decl);
-
- m_oldValue = m_decl->getPropertyValue(m_property);
- ASSERT(!m_oldValue.isNull());
-
- m_important = m_decl->getPropertyPriority(m_property);
- m_decl->removeProperty(m_property);
-}
-
-void RemoveCSSPropertyCommand::doUnapply()
-{
- ASSERT(m_decl);
- ASSERT(!m_oldValue.isNull());
-
- m_decl->setProperty(m_property, m_oldValue, m_important);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/RemoveCSSPropertyCommand.h b/WebCore/editing/RemoveCSSPropertyCommand.h
deleted file mode 100644
index 8a96b4b..0000000
--- a/WebCore/editing/RemoveCSSPropertyCommand.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RemoveCSSPropertyCommand_h
-#define RemoveCSSPropertyCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class CSSStyleDeclaration;
-
-class RemoveCSSPropertyCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<RemoveCSSPropertyCommand> create(Document* document, CSSStyleDeclaration* style, int property)
- {
- return adoptRef(new RemoveCSSPropertyCommand(document, style, property));
- }
-
-private:
- RemoveCSSPropertyCommand(Document*, CSSStyleDeclaration*, int property);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<CSSMutableStyleDeclaration> m_decl;
- int m_property;
- String m_oldValue;
- bool m_important;
-};
-
-} // namespace WebCore
-
-#endif // RemoveCSSPropertyCommand_h
diff --git a/WebCore/editing/RemoveFormatCommand.cpp b/WebCore/editing/RemoveFormatCommand.cpp
deleted file mode 100644
index 71f4015..0000000
--- a/WebCore/editing/RemoveFormatCommand.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RemoveFormatCommand.h"
-
-#include "CSSComputedStyleDeclaration.h"
-#include "Editor.h"
-#include "Frame.h"
-#include "HTMLNames.h"
-#include "Selection.h"
-#include "SelectionController.h"
-#include "TextIterator.h"
-#include "TypingCommand.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-RemoveFormatCommand::RemoveFormatCommand(Document* document)
- : CompositeEditCommand(document)
-{
-}
-
-void RemoveFormatCommand::doApply()
-{
- Frame* frame = document()->frame();
-
- // Make a plain text string from the selection to remove formatting like tables and lists.
- String string = plainText(frame->selection()->selection().toRange().get());
-
- // Get the default style for this editable root, it's the style that we'll give the
- // content that we're operating on.
- Node* root = frame->selection()->rootEditableElement();
- RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle(root)->copyInheritableProperties();
-
- // Delete the selected content.
- // FIXME: We should be able to leave this to insertText, but its delete operation
- // doesn't preserve the style we're about to set.
- deleteSelection();
-
- // Delete doesn't remove fully selected lists.
- while (breakOutOfEmptyListItem())
- ;
-
- // If the selection was all formatting (like an empty list) the format-less text will
- // be empty. Early return since we don't need to do any of the work that follows and
- // to avoid the ASSERT that fires if input(...) is called with an empty String.
- if (string.isEmpty())
- return;
-
- // Normally, deleting a fully selected anchor and then inserting text will re-create
- // the removed anchor, but we don't want that behavior here.
- frame->editor()->setRemovedAnchor(0);
- // Insert the content with the default style.
- // See <rdar://problem/5794382> RemoveFormat doesn't always reset text alignment
- frame->setTypingStyle(defaultStyle.get());
-
- inputText(string, true);
-}
-
-}
diff --git a/WebCore/editing/RemoveFormatCommand.h b/WebCore/editing/RemoveFormatCommand.h
deleted file mode 100644
index daca2db..0000000
--- a/WebCore/editing/RemoveFormatCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RemoveFormatCommand_h
-#define RemoveFormatCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class RemoveFormatCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<RemoveFormatCommand> create(Document* document)
- {
- return adoptRef(new RemoveFormatCommand(document));
- }
-
-private:
- RemoveFormatCommand(Document*);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return EditActionUnspecified; }
-};
-
-} // namespace WebCore
-
-#endif // RemoveFormatCommand_h
diff --git a/WebCore/editing/RemoveNodeAttributeCommand.cpp b/WebCore/editing/RemoveNodeAttributeCommand.cpp
deleted file mode 100644
index bcf1fdf..0000000
--- a/WebCore/editing/RemoveNodeAttributeCommand.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RemoveNodeAttributeCommand.h"
-
-#include "Element.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-RemoveNodeAttributeCommand::RemoveNodeAttributeCommand(PassRefPtr<Element> element, const QualifiedName& attribute)
- : SimpleEditCommand(element->document()), m_element(element), m_attribute(attribute)
-{
- ASSERT(m_element);
-}
-
-void RemoveNodeAttributeCommand::doApply()
-{
- ASSERT(m_element);
-
- m_oldValue = m_element->getAttribute(m_attribute);
- ASSERT(!m_oldValue.isNull());
-
- ExceptionCode ec = 0;
- m_element->removeAttribute(m_attribute, ec);
- ASSERT(ec == 0);
-}
-
-void RemoveNodeAttributeCommand::doUnapply()
-{
- ASSERT(m_element);
- ASSERT(!m_oldValue.isNull());
-
- ExceptionCode ec = 0;
- m_element->setAttribute(m_attribute, m_oldValue.impl(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/RemoveNodeAttributeCommand.h b/WebCore/editing/RemoveNodeAttributeCommand.h
deleted file mode 100644
index fd9127e..0000000
--- a/WebCore/editing/RemoveNodeAttributeCommand.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RemoveNodeAttributeCommand_h
-#define RemoveNodeAttributeCommand_h
-
-#include "EditCommand.h"
-#include "QualifiedName.h"
-
-namespace WebCore {
-
-class RemoveNodeAttributeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<RemoveNodeAttributeCommand> create(PassRefPtr<Element> element, const QualifiedName& attribute)
- {
- return adoptRef(new RemoveNodeAttributeCommand(element, attribute));
- }
-
-private:
- RemoveNodeAttributeCommand(PassRefPtr<Element>, const QualifiedName& attribute);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Element> m_element;
- QualifiedName m_attribute;
- AtomicString m_oldValue;
-};
-
-} // namespace WebCore
-
-#endif // RemoveNodeAttributeCommand_h
diff --git a/WebCore/editing/RemoveNodeCommand.cpp b/WebCore/editing/RemoveNodeCommand.cpp
deleted file mode 100644
index 2519730..0000000
--- a/WebCore/editing/RemoveNodeCommand.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RemoveNodeCommand.h"
-
-#include "Node.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-RemoveNodeCommand::RemoveNodeCommand(PassRefPtr<Node> removeChild)
- : SimpleEditCommand(removeChild->document())
- , m_removeChild(removeChild)
- , m_parent(m_removeChild->parentNode())
- , m_refChild(m_removeChild->nextSibling())
-{
- ASSERT(m_parent);
-}
-
-void RemoveNodeCommand::doApply()
-{
- ASSERT(m_parent);
- ASSERT(m_removeChild);
-
- ExceptionCode ec = 0;
- m_parent->removeChild(m_removeChild.get(), ec);
- ASSERT(ec == 0);
-}
-
-void RemoveNodeCommand::doUnapply()
-{
- ASSERT(m_parent);
- ASSERT(m_removeChild);
-
- ExceptionCode ec = 0;
- m_parent->insertBefore(m_removeChild.get(), m_refChild.get(), ec);
- ASSERT(ec == 0);
-}
-
-}
diff --git a/WebCore/editing/RemoveNodeCommand.h b/WebCore/editing/RemoveNodeCommand.h
deleted file mode 100644
index 802cb8b..0000000
--- a/WebCore/editing/RemoveNodeCommand.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RemoveNodeCommand_h
-#define RemoveNodeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class RemoveNodeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<RemoveNodeCommand> create(PassRefPtr<Node> node)
- {
- return adoptRef(new RemoveNodeCommand(node));
- }
-
-private:
- RemoveNodeCommand(PassRefPtr<Node>);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Node> m_removeChild;
- RefPtr<Node> m_parent;
- RefPtr<Node> m_refChild;
-};
-
-} // namespace WebCore
-
-#endif // RemoveNodeCommand_h
diff --git a/WebCore/editing/RemoveNodePreservingChildrenCommand.cpp b/WebCore/editing/RemoveNodePreservingChildrenCommand.cpp
deleted file mode 100644
index f583865..0000000
--- a/WebCore/editing/RemoveNodePreservingChildrenCommand.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "RemoveNodePreservingChildrenCommand.h"
-
-#include "Node.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-RemoveNodePreservingChildrenCommand::RemoveNodePreservingChildrenCommand(PassRefPtr<Node> node)
- : CompositeEditCommand(node->document()), m_node(node)
-{
- ASSERT(m_node);
-}
-
-void RemoveNodePreservingChildrenCommand::doApply()
-{
- while (Node* curr = m_node->firstChild()) {
- removeNode(curr);
- insertNodeBefore(curr, m_node.get());
- }
- removeNode(m_node.get());
-}
-
-}
diff --git a/WebCore/editing/RemoveNodePreservingChildrenCommand.h b/WebCore/editing/RemoveNodePreservingChildrenCommand.h
deleted file mode 100644
index d2b635f..0000000
--- a/WebCore/editing/RemoveNodePreservingChildrenCommand.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef RemoveNodePreservingChildrenCommand_h
-#define RemoveNodePreservingChildrenCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class RemoveNodePreservingChildrenCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<RemoveNodePreservingChildrenCommand> create(PassRefPtr<Node> node)
- {
- return adoptRef(new RemoveNodePreservingChildrenCommand(node));
- }
-
-private:
- RemoveNodePreservingChildrenCommand(PassRefPtr<Node>);
-
- virtual void doApply();
-
- RefPtr<Node> m_node;
-};
-
-} // namespace WebCore
-
-#endif // RemoveNodePreservingChildrenCommand_h
diff --git a/WebCore/editing/ReplaceSelectionCommand.cpp b/WebCore/editing/ReplaceSelectionCommand.cpp
deleted file mode 100644
index 4304af3..0000000
--- a/WebCore/editing/ReplaceSelectionCommand.cpp
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ReplaceSelectionCommand.h"
-
-#include "ApplyStyleCommand.h"
-#include "BeforeTextInsertedEvent.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSProperty.h"
-#include "CSSPropertyNames.h"
-#include "CSSValueKeywords.h"
-#include "Document.h"
-#include "DocumentFragment.h"
-#include "EditingText.h"
-#include "EventNames.h"
-#include "Element.h"
-#include "Frame.h"
-#include "HTMLElement.h"
-#include "HTMLInterchange.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "SelectionController.h"
-#include "SmartReplace.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-#include "markup.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
-
-// --- ReplacementFragment helper class
-
-class ReplacementFragment : Noncopyable {
-public:
- ReplacementFragment(Document*, DocumentFragment*, bool matchStyle, const Selection&);
-
- Node* firstChild() const;
- Node* lastChild() const;
-
- bool isEmpty() const;
-
- bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
- bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
-
- void removeNode(PassRefPtr<Node>);
- void removeNodePreservingChildren(Node*);
-
-private:
- PassRefPtr<Node> insertFragmentForTestRendering(Node* context);
- void removeUnrenderedNodes(Node*);
- void restoreTestRenderingNodesToFragment(Node*);
- void removeInterchangeNodes(Node*);
-
- void insertNodeBefore(Node* node, Node* refNode);
-
- RefPtr<Document> m_document;
- RefPtr<DocumentFragment> m_fragment;
- bool m_matchStyle;
- bool m_hasInterchangeNewlineAtStart;
- bool m_hasInterchangeNewlineAtEnd;
-};
-
-static bool isInterchangeNewlineNode(const Node *node)
-{
- static String interchangeNewlineClassString(AppleInterchangeNewline);
- return node && node->hasTagName(brTag) &&
- static_cast<const Element *>(node)->getAttribute(classAttr) == interchangeNewlineClassString;
-}
-
-static bool isInterchangeConvertedSpaceSpan(const Node *node)
-{
- static String convertedSpaceSpanClassString(AppleConvertedSpace);
- return node->isHTMLElement() &&
- static_cast<const HTMLElement *>(node)->getAttribute(classAttr) == convertedSpaceSpanClassString;
-}
-
-ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* fragment, bool matchStyle, const Selection& selection)
- : m_document(document),
- m_fragment(fragment),
- m_matchStyle(matchStyle),
- m_hasInterchangeNewlineAtStart(false),
- m_hasInterchangeNewlineAtEnd(false)
-{
- if (!m_document)
- return;
- if (!m_fragment)
- return;
- if (!m_fragment->firstChild())
- return;
-
- Element* editableRoot = selection.rootEditableElement();
- ASSERT(editableRoot);
- if (!editableRoot)
- return;
-
- Node* shadowAncestorNode = editableRoot->shadowAncestorNode();
-
- if (!editableRoot->inlineEventListenerForType(eventNames().webkitBeforeTextInsertedEvent) &&
- // FIXME: Remove these checks once textareas and textfields actually register an event handler.
- !(shadowAncestorNode && shadowAncestorNode->renderer() && shadowAncestorNode->renderer()->isTextField()) &&
- !(shadowAncestorNode && shadowAncestorNode->renderer() && shadowAncestorNode->renderer()->isTextArea()) &&
- editableRoot->isContentRichlyEditable()) {
- removeInterchangeNodes(m_fragment->firstChild());
- return;
- }
-
- Node* styleNode = selection.base().node();
- RefPtr<Node> holder = insertFragmentForTestRendering(styleNode);
-
- RefPtr<Range> range = Selection::selectionFromContentsOfNode(holder.get()).toRange();
- String text = plainText(range.get());
- // Give the root a chance to change the text.
- RefPtr<BeforeTextInsertedEvent> evt = BeforeTextInsertedEvent::create(text);
- ExceptionCode ec = 0;
- editableRoot->dispatchEvent(evt, ec);
- ASSERT(ec == 0);
- if (text != evt->text() || !editableRoot->isContentRichlyEditable()) {
- restoreTestRenderingNodesToFragment(holder.get());
- removeNode(holder);
-
- m_fragment = createFragmentFromText(selection.toRange().get(), evt->text());
- if (!m_fragment->firstChild())
- return;
- holder = insertFragmentForTestRendering(styleNode);
- }
-
- removeInterchangeNodes(holder->firstChild());
-
- removeUnrenderedNodes(holder.get());
- restoreTestRenderingNodesToFragment(holder.get());
- removeNode(holder);
-}
-
-bool ReplacementFragment::isEmpty() const
-{
- return (!m_fragment || !m_fragment->firstChild()) && !m_hasInterchangeNewlineAtStart && !m_hasInterchangeNewlineAtEnd;
-}
-
-Node *ReplacementFragment::firstChild() const
-{
- return m_fragment ? m_fragment->firstChild() : 0;
-}
-
-Node *ReplacementFragment::lastChild() const
-{
- return m_fragment ? m_fragment->lastChild() : 0;
-}
-
-void ReplacementFragment::removeNodePreservingChildren(Node *node)
-{
- if (!node)
- return;
-
- while (RefPtr<Node> n = node->firstChild()) {
- removeNode(n);
- insertNodeBefore(n.get(), node);
- }
- removeNode(node);
-}
-
-void ReplacementFragment::removeNode(PassRefPtr<Node> node)
-{
- if (!node)
- return;
-
- Node *parent = node->parentNode();
- if (!parent)
- return;
-
- ExceptionCode ec = 0;
- parent->removeChild(node.get(), ec);
- ASSERT(ec == 0);
-}
-
-void ReplacementFragment::insertNodeBefore(Node *node, Node *refNode)
-{
- if (!node || !refNode)
- return;
-
- Node *parent = refNode->parentNode();
- if (!parent)
- return;
-
- ExceptionCode ec = 0;
- parent->insertBefore(node, refNode, ec);
- ASSERT(ec == 0);
-}
-
-PassRefPtr<Node> ReplacementFragment::insertFragmentForTestRendering(Node* context)
-{
- Node* body = m_document->body();
- if (!body)
- return 0;
-
- RefPtr<StyledElement> holder = static_pointer_cast<StyledElement>(createDefaultParagraphElement(m_document.get()));
-
- ExceptionCode ec = 0;
-
- // Copy the whitespace and user-select style from the context onto this element.
- // FIXME: We should examine other style properties to see if they would be appropriate to consider during the test rendering.
- Node* n = context;
- while (n && !n->isElementNode())
- n = n->parentNode();
- if (n) {
- RefPtr<CSSComputedStyleDeclaration> conFontStyle = computedStyle(n);
- CSSStyleDeclaration* style = holder->style();
- style->setProperty(CSSPropertyWhiteSpace, conFontStyle->getPropertyValue(CSSPropertyWhiteSpace), false, ec);
- ASSERT(ec == 0);
- style->setProperty(CSSPropertyWebkitUserSelect, conFontStyle->getPropertyValue(CSSPropertyWebkitUserSelect), false, ec);
- ASSERT(ec == 0);
- }
-
- holder->appendChild(m_fragment, ec);
- ASSERT(ec == 0);
-
- body->appendChild(holder.get(), ec);
- ASSERT(ec == 0);
-
- m_document->updateLayoutIgnorePendingStylesheets();
-
- return holder.release();
-}
-
-void ReplacementFragment::restoreTestRenderingNodesToFragment(Node *holder)
-{
- if (!holder)
- return;
-
- ExceptionCode ec = 0;
- while (RefPtr<Node> node = holder->firstChild()) {
- holder->removeChild(node.get(), ec);
- ASSERT(ec == 0);
- m_fragment->appendChild(node.get(), ec);
- ASSERT(ec == 0);
- }
-}
-
-void ReplacementFragment::removeUnrenderedNodes(Node* holder)
-{
- Vector<Node*> unrendered;
-
- for (Node* node = holder->firstChild(); node; node = node->traverseNextNode(holder))
- if (!isNodeRendered(node) && !isTableStructureNode(node))
- unrendered.append(node);
-
- size_t n = unrendered.size();
- for (size_t i = 0; i < n; ++i)
- removeNode(unrendered[i]);
-}
-
-void ReplacementFragment::removeInterchangeNodes(Node* startNode)
-{
- Node* node = startNode;
- Node* newlineAtStartNode = 0;
- Node* newlineAtEndNode = 0;
- while (node) {
- Node *next = node->traverseNextNode();
- if (isInterchangeNewlineNode(node)) {
- if (next || node == startNode) {
- m_hasInterchangeNewlineAtStart = true;
- newlineAtStartNode = node;
- }
- else {
- m_hasInterchangeNewlineAtEnd = true;
- newlineAtEndNode = node;
- }
- }
- else if (isInterchangeConvertedSpaceSpan(node)) {
- RefPtr<Node> n = 0;
- while ((n = node->firstChild())) {
- removeNode(n);
- insertNodeBefore(n.get(), node);
- }
- removeNode(node);
- if (n)
- next = n->traverseNextNode();
- }
- node = next;
- }
-
- if (newlineAtStartNode)
- removeNode(newlineAtStartNode);
- if (newlineAtEndNode)
- removeNode(newlineAtEndNode);
-}
-
-ReplaceSelectionCommand::ReplaceSelectionCommand(Document* document, PassRefPtr<DocumentFragment> fragment,
- bool selectReplacement, bool smartReplace, bool matchStyle, bool preventNesting, bool movingParagraph,
- EditAction editAction)
- : CompositeEditCommand(document),
- m_selectReplacement(selectReplacement),
- m_smartReplace(smartReplace),
- m_matchStyle(matchStyle),
- m_documentFragment(fragment),
- m_preventNesting(preventNesting),
- m_movingParagraph(movingParagraph),
- m_editAction(editAction)
-{
-}
-
-bool ReplaceSelectionCommand::shouldMergeStart(bool selectionStartWasStartOfParagraph, bool fragmentHasInterchangeNewlineAtStart)
-{
- VisiblePosition startOfInsertedContent(positionAtStartOfInsertedContent());
- VisiblePosition prev = startOfInsertedContent.previous(true);
- if (prev.isNull())
- return false;
-
- return !selectionStartWasStartOfParagraph &&
- !fragmentHasInterchangeNewlineAtStart &&
- isStartOfParagraph(startOfInsertedContent) &&
- !startOfInsertedContent.deepEquivalent().node()->hasTagName(brTag) &&
- shouldMerge(startOfInsertedContent, prev);
-}
-
-bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
-{
- VisiblePosition endOfInsertedContent(positionAtEndOfInsertedContent());
- VisiblePosition next = endOfInsertedContent.next(true);
- if (next.isNull())
- return false;
-
- return !selectionEndWasEndOfParagraph &&
- isEndOfParagraph(endOfInsertedContent) &&
- !endOfInsertedContent.deepEquivalent().node()->hasTagName(brTag) &&
- shouldMerge(endOfInsertedContent, next);
-}
-
-static bool isMailPasteAsQuotationNode(const Node* node)
-{
- return node && node->hasTagName(blockquoteTag) && node->isElementNode() && static_cast<const Element*>(node)->getAttribute(classAttr) == ApplePasteAsQuotation;
-}
-
-// Wrap CompositeEditCommand::removeNodePreservingChildren() so we can update the nodes we track
-void ReplaceSelectionCommand::removeNodePreservingChildren(Node* node)
-{
- if (m_firstNodeInserted == node)
- m_firstNodeInserted = node->traverseNextNode();
- if (m_lastLeafInserted == node)
- m_lastLeafInserted = node->lastChild() ? node->lastChild() : node->traverseNextSibling();
- CompositeEditCommand::removeNodePreservingChildren(node);
-}
-
-// Wrap CompositeEditCommand::removeNodeAndPruneAncestors() so we can update the nodes we track
-void ReplaceSelectionCommand::removeNodeAndPruneAncestors(Node* node)
-{
- // prepare in case m_firstNodeInserted and/or m_lastLeafInserted get removed
- // FIXME: shouldn't m_lastLeafInserted be adjusted using traversePreviousNode()?
- Node* afterFirst = m_firstNodeInserted ? m_firstNodeInserted->traverseNextSibling() : 0;
- Node* afterLast = m_lastLeafInserted ? m_lastLeafInserted->traverseNextSibling() : 0;
-
- CompositeEditCommand::removeNodeAndPruneAncestors(node);
-
- // adjust m_firstNodeInserted and m_lastLeafInserted since either or both may have been removed
- if (m_lastLeafInserted && !m_lastLeafInserted->inDocument())
- m_lastLeafInserted = afterLast;
- if (m_firstNodeInserted && !m_firstNodeInserted->inDocument())
- m_firstNodeInserted = m_lastLeafInserted && m_lastLeafInserted->inDocument() ? afterFirst : 0;
-}
-
-bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& from, const VisiblePosition& to)
-{
- if (from.isNull() || to.isNull())
- return false;
-
- Node* fromNode = from.deepEquivalent().node();
- Node* toNode = to.deepEquivalent().node();
- Node* fromNodeBlock = enclosingBlock(fromNode);
- return !enclosingNodeOfType(from.deepEquivalent(), &isMailPasteAsQuotationNode) &&
- fromNodeBlock && (!fromNodeBlock->hasTagName(blockquoteTag) || isMailBlockquote(fromNodeBlock)) &&
- enclosingListChild(fromNode) == enclosingListChild(toNode) &&
- enclosingTableCell(from.deepEquivalent()) == enclosingTableCell(from.deepEquivalent()) &&
- // Don't merge to or from a position before or after a block because it would
- // be a no-op and cause infinite recursion.
- !isBlock(fromNode) && !isBlock(toNode);
-}
-
-// Style rules that match just inserted elements could change their appearance, like
-// a div inserted into a document with div { display:inline; }.
-void ReplaceSelectionCommand::negateStyleRulesThatAffectAppearance()
-{
- for (RefPtr<Node> node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {
- // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
- if (isStyleSpan(node.get())) {
- HTMLElement* e = static_cast<HTMLElement*>(node.get());
- // There are other styles that style rules can give to style spans,
- // but these are the two important ones because they'll prevent
- // inserted content from appearing in the right paragraph.
- // FIXME: Hyatt is concerned that selectively using display:inline will give inconsistent
- // results. We already know one issue because td elements ignore their display property
- // in quirks mode (which Mail.app is always in). We should look for an alternative.
- if (isBlock(e))
- e->getInlineStyleDecl()->setProperty(CSSPropertyDisplay, CSSValueInline);
- if (e->renderer() && e->renderer()->style()->floating() != FNONE)
- e->getInlineStyleDecl()->setProperty(CSSPropertyFloat, CSSValueNone);
- }
- if (node == m_lastLeafInserted)
- break;
- }
-}
-
-void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds()
-{
- document()->updateLayoutIgnorePendingStylesheets();
- if (!m_lastLeafInserted->renderer() &&
- m_lastLeafInserted->isTextNode() &&
- !enclosingNodeWithTag(Position(m_lastLeafInserted.get(), 0), selectTag) &&
- !enclosingNodeWithTag(Position(m_lastLeafInserted.get(), 0), scriptTag)) {
- if (m_firstNodeInserted == m_lastLeafInserted) {
- removeNode(m_lastLeafInserted.get());
- m_lastLeafInserted = 0;
- m_firstNodeInserted = 0;
- return;
- }
- RefPtr<Node> previous = m_lastLeafInserted->traversePreviousNode();
- removeNode(m_lastLeafInserted.get());
- m_lastLeafInserted = previous;
- }
-
- // We don't have to make sure that m_firstNodeInserted isn't inside a select or script element, because
- // it is a top level node in the fragment and the user can't insert into those elements.
- if (!m_firstNodeInserted->renderer() &&
- m_firstNodeInserted->isTextNode()) {
- if (m_firstNodeInserted == m_lastLeafInserted) {
- removeNode(m_firstNodeInserted.get());
- m_firstNodeInserted = 0;
- m_lastLeafInserted = 0;
- return;
- }
- RefPtr<Node> next = m_firstNodeInserted->traverseNextSibling();
- removeNode(m_firstNodeInserted.get());
- m_firstNodeInserted = next;
- }
-}
-
-void ReplaceSelectionCommand::handlePasteAsQuotationNode()
-{
- Node* node = m_firstNodeInserted.get();
- if (isMailPasteAsQuotationNode(node))
- removeNodeAttribute(static_cast<Element*>(node), classAttr);
-}
-
-VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent()
-{
- Node* lastNode = m_lastLeafInserted.get();
- Node* enclosingSelect = enclosingNodeWithTag(Position(lastNode, 0), selectTag);
- if (enclosingSelect)
- lastNode = enclosingSelect;
- return VisiblePosition(Position(lastNode, maxDeepOffset(lastNode)));
-}
-
-VisiblePosition ReplaceSelectionCommand::positionAtStartOfInsertedContent()
-{
- // Return the inserted content's first VisiblePosition.
- return VisiblePosition(nextCandidate(positionBeforeNode(m_firstNodeInserted.get())));
-}
-
-// Remove style spans before insertion if they are unnecessary. It's faster because we'll
-// avoid doing a layout.
-static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const Position& insertionPos)
-{
- Node* topNode = fragment.firstChild();
-
- // Handling this case is more complicated (see handleStyleSpans) and doesn't receive the optimization.
- if (isMailPasteAsQuotationNode(topNode))
- return false;
-
- // Either there are no style spans in the fragment or a WebKit client has added content to the fragment
- // before inserting it. Look for and handle style spans after insertion.
- if (!isStyleSpan(topNode))
- return false;
-
- Node* sourceDocumentStyleSpan = topNode;
- RefPtr<Node> copiedRangeStyleSpan = sourceDocumentStyleSpan->firstChild();
-
- RefPtr<CSSMutableStyleDeclaration> styleAtInsertionPos = rangeCompliantEquivalent(insertionPos).computedStyle()->copyInheritableProperties();
- String styleText = styleAtInsertionPos->cssText();
-
- if (styleText == static_cast<Element*>(sourceDocumentStyleSpan)->getAttribute(styleAttr)) {
- fragment.removeNodePreservingChildren(sourceDocumentStyleSpan);
- if (!isStyleSpan(copiedRangeStyleSpan.get()))
- return true;
- }
-
- if (isStyleSpan(copiedRangeStyleSpan.get()) && styleText == static_cast<Element*>(copiedRangeStyleSpan.get())->getAttribute(styleAttr)) {
- fragment.removeNodePreservingChildren(copiedRangeStyleSpan.get());
- return true;
- }
-
- return false;
-}
-
-// At copy time, WebKit wraps copied content in a span that contains the source document's
-// default styles. If the copied Range inherits any other styles from its ancestors, we put
-// those styles on a second span.
-// This function removes redundant styles from those spans, and removes the spans if all their
-// styles are redundant.
-// We should remove the Apple-style-span class when we're done, see <rdar://problem/5685600>.
-// We should remove styles from spans that are overridden by all of their children, either here
-// or at copy time.
-void ReplaceSelectionCommand::handleStyleSpans()
-{
- Node* sourceDocumentStyleSpan = 0;
- Node* copiedRangeStyleSpan = 0;
- // The style span that contains the source document's default style should be at
- // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation),
- // so search for the top level style span instead of assuming it's at the top.
- for (Node* node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {
- if (isStyleSpan(node)) {
- sourceDocumentStyleSpan = node;
- // If the copied Range's common ancestor had user applied inheritable styles
- // on it, they'll be on a second style span, just below the one that holds the
- // document defaults.
- if (isStyleSpan(node->firstChild()))
- copiedRangeStyleSpan = node->firstChild();
- break;
- }
- }
-
- // There might not be any style spans if we're pasting from another application or if
- // we are here because of a document.execCommand("InsertHTML", ...) call.
- if (!sourceDocumentStyleSpan)
- return;
-
- RefPtr<CSSMutableStyleDeclaration> sourceDocumentStyle = static_cast<HTMLElement*>(sourceDocumentStyleSpan)->getInlineStyleDecl()->copy();
- Node* context = sourceDocumentStyleSpan->parentNode();
-
- // If Mail wraps the fragment with a Paste as Quotation blockquote, styles from that element are
- // allowed to override those from the source document, see <rdar://problem/4930986>.
- if (isMailPasteAsQuotationNode(context)) {
- RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = computedStyle(context)->copyInheritableProperties();
- RefPtr<CSSMutableStyleDeclaration> parentStyle = computedStyle(context->parentNode())->copyInheritableProperties();
- parentStyle->diff(blockquoteStyle.get());
-
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = blockquoteStyle->valuesIterator(); it != end; ++it) {
- const CSSProperty& property = *it;
- sourceDocumentStyle->removeProperty(property.id());
- }
-
- context = context->parentNode();
- }
-
- RefPtr<CSSMutableStyleDeclaration> contextStyle = computedStyle(context)->copyInheritableProperties();
- contextStyle->diff(sourceDocumentStyle.get());
-
- // Remove block properties in the span's style. This prevents properties that probably have no effect
- // currently from affecting blocks later if the style is cloned for a new block element during a future
- // editing operation.
- // FIXME: They *can* have an effect currently if blocks beneath the style span aren't individually marked
- // with block styles by the editing engine used to style them. WebKit doesn't do this, but others might.
- sourceDocumentStyle->removeBlockProperties();
-
- // The styles on sourceDocumentStyleSpan are all redundant, and there is no copiedRangeStyleSpan
- // to consider. We're finished.
- if (sourceDocumentStyle->length() == 0 && !copiedRangeStyleSpan) {
- removeNodePreservingChildren(sourceDocumentStyleSpan);
- return;
- }
-
- // There are non-redundant styles on sourceDocumentStyleSpan, but there is no
- // copiedRangeStyleSpan. Clear the redundant styles from sourceDocumentStyleSpan
- // and return.
- if (sourceDocumentStyle->length() > 0 && !copiedRangeStyleSpan) {
- setNodeAttribute(static_cast<Element*>(sourceDocumentStyleSpan), styleAttr, sourceDocumentStyle->cssText());
- return;
- }
-
- RefPtr<CSSMutableStyleDeclaration> copiedRangeStyle = static_cast<HTMLElement*>(copiedRangeStyleSpan)->getInlineStyleDecl()->copy();
-
- // We're going to put sourceDocumentStyleSpan's non-redundant styles onto copiedRangeStyleSpan,
- // as long as they aren't overridden by ones on copiedRangeStyleSpan.
- sourceDocumentStyle->merge(copiedRangeStyle.get(), true);
- copiedRangeStyle = sourceDocumentStyle;
-
- removeNodePreservingChildren(sourceDocumentStyleSpan);
-
- // Remove redundant styles.
- context = copiedRangeStyleSpan->parentNode();
- contextStyle = computedStyle(context)->copyInheritableProperties();
- contextStyle->diff(copiedRangeStyle.get());
-
- // See the comments above about removing block properties.
- copiedRangeStyle->removeBlockProperties();
-
- // All the styles on copiedRangeStyleSpan are redundant, remove it.
- if (copiedRangeStyle->length() == 0) {
- removeNodePreservingChildren(copiedRangeStyleSpan);
- return;
- }
-
- // Clear the redundant styles from the span's style attribute.
- // FIXME: If font-family:-webkit-monospace is non-redundant, then the font-size should stay, even if it
- // appears redundant.
- setNodeAttribute(static_cast<Element*>(copiedRangeStyleSpan), styleAttr, copiedRangeStyle->cssText());
-}
-
-void ReplaceSelectionCommand::doApply()
-{
- Selection selection = endingSelection();
- ASSERT(selection.isCaretOrRange());
- ASSERT(selection.start().node());
- if (selection.isNone() || !selection.start().node())
- return;
-
- bool selectionIsPlainText = !selection.isContentRichlyEditable();
-
- Element* currentRoot = selection.rootEditableElement();
- ReplacementFragment fragment(document(), m_documentFragment.get(), m_matchStyle, selection);
-
- if (m_matchStyle)
- m_insertionStyle = styleAtPosition(selection.start());
-
- VisiblePosition visibleStart = selection.visibleStart();
- VisiblePosition visibleEnd = selection.visibleEnd();
-
- bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
- bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
-
- Node* startBlock = enclosingBlock(visibleStart.deepEquivalent().node());
-
- if (selectionStartWasStartOfParagraph && selectionEndWasEndOfParagraph ||
- startBlock == currentRoot ||
- startBlock && startBlock->renderer() && startBlock->renderer()->isListItem() ||
- selectionIsPlainText)
- m_preventNesting = false;
-
- Position insertionPos = selection.start();
-
- if (selection.isRange()) {
- // When the end of the selection being pasted into is at the end of a paragraph, and that selection
- // spans multiple blocks, not merging may leave an empty line.
- // When the start of the selection being pasted into is at the start of a block, not merging
- // will leave hanging block(s).
- bool mergeBlocksAfterDelete = isEndOfParagraph(visibleEnd) || isStartOfBlock(visibleStart);
- // FIXME: We should only expand to include fully selected special elements if we are copying a
- // selection and pasting it on top of itself.
- deleteSelection(false, mergeBlocksAfterDelete, true, false);
- visibleStart = endingSelection().visibleStart();
- if (fragment.hasInterchangeNewlineAtStart()) {
- if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
- if (!isEndOfDocument(visibleStart))
- setEndingSelection(visibleStart.next());
- } else
- insertParagraphSeparator();
- }
- insertionPos = endingSelection().start();
- } else {
- ASSERT(selection.isCaret());
- if (fragment.hasInterchangeNewlineAtStart()) {
- VisiblePosition next = visibleStart.next(true);
- if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart) && next.isNotNull())
- setEndingSelection(next);
- else
- insertParagraphSeparator();
- }
- // We split the current paragraph in two to avoid nesting the blocks from the fragment inside the current block.
- // For example paste <div>foo</div><div>bar</div><div>baz</div> into <div>x^x</div>, where ^ is the caret.
- // As long as the div styles are the same, visually you'd expect: <div>xbar</div><div>bar</div><div>bazx</div>,
- // not <div>xbar<div>bar</div><div>bazx</div></div>
- if (m_preventNesting && !isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
- insertParagraphSeparator();
- setEndingSelection(endingSelection().visibleStart().previous());
- }
- insertionPos = endingSelection().start();
- }
-
- // Inserting content could cause whitespace to collapse, e.g. inserting <div>foo</div> into hello^ world.
- prepareWhitespaceAtPositionForSplit(insertionPos);
-
- // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after
- // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed
- // away, there are positions after the br which map to the same visible position as [br, 0]).
- Node* endBR = insertionPos.downstream().node()->hasTagName(brTag) ? insertionPos.downstream().node() : 0;
- VisiblePosition originalVisPosBeforeEndBR;
- if (endBR)
- originalVisPosBeforeEndBR = VisiblePosition(endBR, 0, DOWNSTREAM).previous();
-
- startBlock = enclosingBlock(insertionPos.node());
-
- // Adjust insertionPos to prevent nesting.
- if (m_preventNesting && startBlock) {
- ASSERT(startBlock != currentRoot);
- VisiblePosition visibleInsertionPos(insertionPos);
- if (isEndOfBlock(visibleInsertionPos) && !(isStartOfBlock(visibleInsertionPos) && fragment.hasInterchangeNewlineAtEnd()))
- insertionPos = positionAfterNode(startBlock);
- else if (isStartOfBlock(visibleInsertionPos))
- insertionPos = positionBeforeNode(startBlock);
- }
-
- // Paste into run of tabs splits the tab span.
- insertionPos = positionOutsideTabSpan(insertionPos);
-
- // Paste at start or end of link goes outside of link.
- insertionPos = positionAvoidingSpecialElementBoundary(insertionPos);
-
- // FIXME: Can this wait until after the operation has been performed? There doesn't seem to be
- // any work performed after this that queries or uses the typing style.
- if (Frame* frame = document()->frame())
- frame->clearTypingStyle();
-
- bool handledStyleSpans = handleStyleSpansBeforeInsertion(fragment, insertionPos);
-
- // We're finished if there is nothing to add.
- if (fragment.isEmpty() || !fragment.firstChild())
- return;
-
- // 1) Insert the content.
- // 2) Remove redundant styles and style tags, this inner <b> for example: <b>foo <b>bar</b> baz</b>.
- // 3) Merge the start of the added content with the content before the position being pasted into.
- // 4) Do one of the following: a) expand the last br if the fragment ends with one and it collapsed,
- // b) merge the last paragraph of the incoming fragment with the paragraph that contained the
- // end of the selection that was pasted into, or c) handle an interchange newline at the end of the
- // incoming fragment.
- // 5) Add spaces for smart replace.
- // 6) Select the replacement if requested, and match style if requested.
-
- VisiblePosition startOfInsertedContent, endOfInsertedContent;
-
- RefPtr<Node> refNode = fragment.firstChild();
- RefPtr<Node> node = refNode->nextSibling();
-
- fragment.removeNode(refNode);
- insertNodeAtAndUpdateNodesInserted(refNode.get(), insertionPos);
-
- while (node) {
- Node* next = node->nextSibling();
- fragment.removeNode(node);
- insertNodeAfterAndUpdateNodesInserted(node.get(), refNode.get());
- refNode = node;
- node = next;
- }
-
- removeUnrenderedTextNodesAtEnds();
-
- negateStyleRulesThatAffectAppearance();
-
- if (!handledStyleSpans)
- handleStyleSpans();
-
- // Mutation events (bug 20161) may have already removed the inserted content
- if (!m_firstNodeInserted || !m_firstNodeInserted->inDocument())
- return;
-
- endOfInsertedContent = positionAtEndOfInsertedContent();
- startOfInsertedContent = positionAtStartOfInsertedContent();
-
- // We inserted before the startBlock to prevent nesting, and the content before the startBlock wasn't in its own block and
- // didn't have a br after it, so the inserted content ended up in the same paragraph.
- if (startBlock && insertionPos.node() == startBlock->parentNode() && (unsigned)insertionPos.offset() < startBlock->nodeIndex() && !isStartOfParagraph(startOfInsertedContent))
- insertNodeAt(createBreakElement(document()).get(), startOfInsertedContent.deepEquivalent());
-
- Position lastPositionToSelect;
-
- bool interchangeNewlineAtEnd = fragment.hasInterchangeNewlineAtEnd();
-
- if (shouldRemoveEndBR(endBR, originalVisPosBeforeEndBR))
- removeNodeAndPruneAncestors(endBR);
-
- if (shouldMergeStart(selectionStartWasStartOfParagraph, fragment.hasInterchangeNewlineAtStart())) {
- // Bail to avoid infinite recursion.
- if (m_movingParagraph) {
- // setting display:inline does not work for td elements in quirks mode
- ASSERT(m_firstNodeInserted->hasTagName(tdTag));
- return;
- }
- VisiblePosition destination = startOfInsertedContent.previous();
- VisiblePosition startOfParagraphToMove = startOfInsertedContent;
-
- // Merging the the first paragraph of inserted content with the content that came
- // before the selection that was pasted into would also move content after
- // the selection that was pasted into if: only one paragraph was being pasted,
- // and it was not wrapped in a block, the selection that was pasted into ended
- // at the end of a block and the next paragraph didn't start at the start of a block.
- // Insert a line break just after the inserted content to separate it from what
- // comes after and prevent that from happening.
- VisiblePosition endOfInsertedContent = positionAtEndOfInsertedContent();
- if (startOfParagraph(endOfInsertedContent) == startOfParagraphToMove)
- insertNodeAt(createBreakElement(document()).get(), endOfInsertedContent.deepEquivalent());
-
- // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes. The nodes are
- // only ever used to create positions where inserted content starts/ends.
- moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
- m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().downstream().node();
- if (!m_lastLeafInserted->inDocument())
- m_lastLeafInserted = endingSelection().visibleEnd().deepEquivalent().upstream().node();
- }
-
- endOfInsertedContent = positionAtEndOfInsertedContent();
- startOfInsertedContent = positionAtStartOfInsertedContent();
-
- if (interchangeNewlineAtEnd) {
- VisiblePosition next = endOfInsertedContent.next(true);
-
- if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
- if (!isStartOfParagraph(endOfInsertedContent)) {
- setEndingSelection(endOfInsertedContent);
- // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
- // block's style seems to annoy users.
- insertParagraphSeparator(true);
-
- // Select up to the paragraph separator that was added.
- lastPositionToSelect = endingSelection().visibleStart().deepEquivalent();
- updateNodesInserted(lastPositionToSelect.node());
- }
- } else {
- // Select up to the beginning of the next paragraph.
- lastPositionToSelect = next.deepEquivalent().downstream();
- }
-
- } else if (shouldMergeEnd(selectionEndWasEndOfParagraph)) {
- // Bail to avoid infinite recursion.
- if (m_movingParagraph) {
- ASSERT_NOT_REACHED();
- return;
- }
- // Merging two paragraphs will destroy the moved one's block styles. Always move forward to preserve
- // the block style of the paragraph already in the document, unless the paragraph to move would include the
- // what was the start of the selection that was pasted into.
- bool mergeForward = !inSameParagraph(startOfInsertedContent, endOfInsertedContent) || isStartOfParagraph(startOfInsertedContent);
-
- VisiblePosition destination = mergeForward ? endOfInsertedContent.next() : endOfInsertedContent;
- VisiblePosition startOfParagraphToMove = mergeForward ? startOfParagraph(endOfInsertedContent) : endOfInsertedContent.next();
-
- moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
- // Merging forward will remove m_lastLeafInserted from the document.
- // FIXME: Maintain positions for the start and end of inserted content instead of keeping nodes. The nodes are
- // only ever used to create positions where inserted content starts/ends.
- if (mergeForward) {
- m_lastLeafInserted = destination.previous().deepEquivalent().node();
- if (!m_firstNodeInserted->inDocument())
- m_firstNodeInserted = endingSelection().visibleStart().deepEquivalent().node();
- }
- }
-
- handlePasteAsQuotationNode();
-
- endOfInsertedContent = positionAtEndOfInsertedContent();
- startOfInsertedContent = positionAtStartOfInsertedContent();
-
- // Add spaces for smart replace.
- if (m_smartReplace && currentRoot) {
- // Disable smart replace for password fields.
- Node* start = currentRoot->shadowAncestorNode();
- if (start->hasTagName(inputTag) && static_cast<HTMLInputElement*>(start)->inputType() == HTMLInputElement::PASSWORD)
- m_smartReplace = false;
- }
- if (m_smartReplace) {
- bool needsTrailingSpace = !isEndOfParagraph(endOfInsertedContent) &&
- !isCharacterSmartReplaceExempt(endOfInsertedContent.characterAfter(), false);
- if (needsTrailingSpace) {
- RenderObject* renderer = m_lastLeafInserted->renderer();
- bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
- Node* endNode = positionAtEndOfInsertedContent().deepEquivalent().upstream().node();
- if (endNode->isTextNode()) {
- Text* text = static_cast<Text*>(endNode);
- insertTextIntoNode(text, text->length(), collapseWhiteSpace ? nonBreakingSpaceString() : " ");
- } else {
- RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
- insertNodeAfterAndUpdateNodesInserted(node.get(), endNode);
- }
- }
-
- bool needsLeadingSpace = !isStartOfParagraph(startOfInsertedContent) &&
- !isCharacterSmartReplaceExempt(startOfInsertedContent.previous().characterAfter(), true);
- if (needsLeadingSpace) {
- RenderObject* renderer = m_lastLeafInserted->renderer();
- bool collapseWhiteSpace = !renderer || renderer->style()->collapseWhiteSpace();
- Node* startNode = positionAtStartOfInsertedContent().deepEquivalent().downstream().node();
- if (startNode->isTextNode()) {
- Text* text = static_cast<Text*>(startNode);
- insertTextIntoNode(text, 0, collapseWhiteSpace ? nonBreakingSpaceString() : " ");
- } else {
- RefPtr<Node> node = document()->createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
- // Don't updateNodesInserted. Doing so would set m_lastLeafInserted to be the node containing the
- // leading space, but m_lastLeafInserted is supposed to mark the end of pasted content.
- insertNodeBefore(node.get(), startNode);
- // FIXME: Use positions to track the start/end of inserted content.
- m_firstNodeInserted = node;
- }
- }
- }
-
- completeHTMLReplacement(lastPositionToSelect);
-}
-
-bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePosition& originalVisPosBeforeEndBR)
-{
- if (!endBR || !endBR->inDocument())
- return false;
-
- VisiblePosition visiblePos(Position(endBR, 0));
-
- // Don't remove the br if nothing was inserted.
- if (visiblePos.previous() == originalVisPosBeforeEndBR)
- return false;
-
- // Remove the br if it is collapsed away and so is unnecessary.
- if (!document()->inStrictMode() && isEndOfBlock(visiblePos) && !isStartOfParagraph(visiblePos))
- return true;
-
- // A br that was originally holding a line open should be displaced by inserted content or turned into a line break.
- // A br that was originally acting as a line break should still be acting as a line break, not as a placeholder.
- return isStartOfParagraph(visiblePos) && isEndOfParagraph(visiblePos);
-}
-
-void ReplaceSelectionCommand::completeHTMLReplacement(const Position &lastPositionToSelect)
-{
- Position start;
- Position end;
-
- // FIXME: This should never not be the case.
- if (m_firstNodeInserted && m_firstNodeInserted->inDocument() && m_lastLeafInserted && m_lastLeafInserted->inDocument()) {
-
- start = positionAtStartOfInsertedContent().deepEquivalent();
- end = positionAtEndOfInsertedContent().deepEquivalent();
-
- // FIXME (11475): Remove this and require that the creator of the fragment to use nbsps.
- rebalanceWhitespaceAt(start);
- rebalanceWhitespaceAt(end);
-
- if (m_matchStyle) {
- ASSERT(m_insertionStyle);
- applyStyle(m_insertionStyle.get(), start, end);
- }
-
- if (lastPositionToSelect.isNotNull())
- end = lastPositionToSelect;
- } else if (lastPositionToSelect.isNotNull())
- start = end = lastPositionToSelect;
- else
- return;
-
- if (m_selectReplacement)
- setEndingSelection(Selection(start, end, SEL_DEFAULT_AFFINITY));
- else
- setEndingSelection(Selection(end, SEL_DEFAULT_AFFINITY));
-}
-
-EditAction ReplaceSelectionCommand::editingAction() const
-{
- return m_editAction;
-}
-
-void ReplaceSelectionCommand::insertNodeAfterAndUpdateNodesInserted(Node *insertChild, Node *refChild)
-{
- insertNodeAfter(insertChild, refChild);
- updateNodesInserted(insertChild);
-}
-
-void ReplaceSelectionCommand::insertNodeAtAndUpdateNodesInserted(Node *insertChild, const Position& p)
-{
- insertNodeAt(insertChild, p);
- updateNodesInserted(insertChild);
-}
-
-void ReplaceSelectionCommand::insertNodeBeforeAndUpdateNodesInserted(Node *insertChild, Node *refChild)
-{
- insertNodeBefore(insertChild, refChild);
- updateNodesInserted(insertChild);
-}
-
-void ReplaceSelectionCommand::updateNodesInserted(Node *node)
-{
- if (!node)
- return;
-
- if (!m_firstNodeInserted)
- m_firstNodeInserted = node;
-
- if (node == m_lastLeafInserted)
- return;
-
- m_lastLeafInserted = node->lastDescendant();
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/ReplaceSelectionCommand.h b/WebCore/editing/ReplaceSelectionCommand.h
deleted file mode 100644
index dc669a3..0000000
--- a/WebCore/editing/ReplaceSelectionCommand.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ReplaceSelectionCommand_h
-#define ReplaceSelectionCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class DocumentFragment;
-
-class ReplaceSelectionCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<ReplaceSelectionCommand> create(Document* document, PassRefPtr<DocumentFragment> fragment,
- bool selectReplacement = true, bool smartReplace = false, bool matchStyle = false, bool preventNesting = true, bool movingParagraph = false,
- EditAction action = EditActionPaste)
- {
- return adoptRef(new ReplaceSelectionCommand(document, fragment, selectReplacement, smartReplace, matchStyle, preventNesting, movingParagraph, action));
- }
-
-private:
- ReplaceSelectionCommand(Document*, PassRefPtr<DocumentFragment>,
- bool selectReplacement, bool smartReplace, bool matchStyle, bool preventNesting, bool movingParagraph, EditAction);
-
- virtual void doApply();
- virtual EditAction editingAction() const;
-
- void completeHTMLReplacement(const Position& lastPositionToSelect);
-
- void insertNodeAfterAndUpdateNodesInserted(Node* insertChild, Node* refChild);
- void insertNodeAtAndUpdateNodesInserted(Node*, const Position&);
- void insertNodeBeforeAndUpdateNodesInserted(Node* insertChild, Node* refChild);
-
- void updateNodesInserted(Node*);
- bool shouldRemoveEndBR(Node*, const VisiblePosition&);
-
- bool shouldMergeStart(bool, bool);
- bool shouldMergeEnd(bool);
- bool shouldMerge(const VisiblePosition&, const VisiblePosition&);
-
- void removeUnrenderedTextNodesAtEnds();
-
- void negateStyleRulesThatAffectAppearance();
- void handleStyleSpans();
- void handlePasteAsQuotationNode();
-
- virtual void removeNodePreservingChildren(Node*);
- virtual void removeNodeAndPruneAncestors(Node*);
-
- VisiblePosition positionAtStartOfInsertedContent();
- VisiblePosition positionAtEndOfInsertedContent();
-
- RefPtr<Node> m_firstNodeInserted;
- RefPtr<Node> m_lastLeafInserted;
- RefPtr<CSSMutableStyleDeclaration> m_insertionStyle;
- bool m_selectReplacement;
- bool m_smartReplace;
- bool m_matchStyle;
- RefPtr<DocumentFragment> m_documentFragment;
- bool m_preventNesting;
- bool m_movingParagraph;
- EditAction m_editAction;
-};
-
-} // namespace WebCore
-
-#endif // ReplaceSelectionCommand_h
diff --git a/WebCore/editing/Selection.cpp b/WebCore/editing/Selection.cpp
deleted file mode 100644
index 9b17567..0000000
--- a/WebCore/editing/Selection.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Selection.h"
-
-#include "CString.h"
-#include "Document.h"
-#include "Element.h"
-#include "htmlediting.h"
-#include "VisiblePosition.h"
-#include "visible_units.h"
-#include "Range.h"
-#include <wtf/Assertions.h>
-#include <stdio.h>
-
-namespace WebCore {
-
-Selection::Selection()
- : m_affinity(DOWNSTREAM)
- , m_granularity(CharacterGranularity)
- , m_state(NONE)
- , m_baseIsFirst(true)
-{
-}
-
-Selection::Selection(const Position& pos, EAffinity affinity)
- : m_base(pos)
- , m_extent(pos)
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const Position& base, const Position& extent, EAffinity affinity)
- : m_base(base)
- , m_extent(extent)
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const VisiblePosition& pos)
- : m_base(pos.deepEquivalent())
- , m_extent(pos.deepEquivalent())
- , m_affinity(pos.affinity())
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const VisiblePosition& base, const VisiblePosition& extent)
- : m_base(base.deepEquivalent())
- , m_extent(extent.deepEquivalent())
- , m_affinity(base.affinity())
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const Range* range, EAffinity affinity)
- : m_base(range->startPosition())
- , m_extent(range->endPosition())
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection Selection::selectionFromContentsOfNode(Node* node)
-{
- return Selection(Position(node, 0), Position(node, maxDeepOffset(node)), DOWNSTREAM);
-}
-
-void Selection::setBase(const Position& position)
-{
- m_base = position;
- validate();
-}
-
-void Selection::setBase(const VisiblePosition& visiblePosition)
-{
- m_base = visiblePosition.deepEquivalent();
- validate();
-}
-
-void Selection::setExtent(const Position& position)
-{
- m_extent = position;
- validate();
-}
-
-void Selection::setExtent(const VisiblePosition& visiblePosition)
-{
- m_extent = visiblePosition.deepEquivalent();
- validate();
-}
-
-PassRefPtr<Range> Selection::toRange() const
-{
- if (isNone())
- return 0;
-
- // Make sure we have an updated layout since this function is called
- // in the course of running edit commands which modify the DOM.
- // Failing to call this can result in equivalentXXXPosition calls returning
- // incorrect results.
- m_start.node()->document()->updateLayout();
-
- // Check again, because updating layout can clear the selection.
- if (isNone())
- return 0;
-
- Position s, e;
- if (isCaret()) {
- // If the selection is a caret, move the range start upstream. This helps us match
- // the conventions of text editors tested, which make style determinations based
- // on the character before the caret, if any.
- s = rangeCompliantEquivalent(m_start.upstream());
- e = s;
- } else {
- // If the selection is a range, select the minimum range that encompasses the selection.
- // Again, this is to match the conventions of text editors tested, which make style
- // determinations based on the first character of the selection.
- // For instance, this operation helps to make sure that the "X" selected below is the
- // only thing selected. The range should not be allowed to "leak" out to the end of the
- // previous text node, or to the beginning of the next text node, each of which has a
- // different style.
- //
- // On a treasure map, <b>X</b> marks the spot.
- // ^ selected
- //
- ASSERT(isRange());
- s = m_start.downstream();
- e = m_end.upstream();
- if (Range::compareBoundaryPoints(s.node(), s.offset(), e.node(), e.offset()) > 0) {
- // Make sure the start is before the end.
- // The end can wind up before the start if collapsed whitespace is the only thing selected.
- Position tmp = s;
- s = e;
- e = tmp;
- }
- s = rangeCompliantEquivalent(s);
- e = rangeCompliantEquivalent(e);
- }
-
- ExceptionCode ec = 0;
- RefPtr<Range> result(Range::create(s.node()->document()));
- result->setStart(s.node(), s.offset(), ec);
- if (ec) {
- LOG_ERROR("Exception setting Range start from Selection: %d", ec);
- return 0;
- }
- result->setEnd(e.node(), e.offset(), ec);
- if (ec) {
- LOG_ERROR("Exception setting Range end from Selection: %d", ec);
- return 0;
- }
- return result.release();
-}
-
-bool Selection::expandUsingGranularity(TextGranularity granularity)
-{
- if (isNone())
- return false;
-
- m_granularity = granularity;
- validate();
- return true;
-}
-
-void Selection::validate()
-{
- // Move the selection to rendered positions, if possible.
- bool baseAndExtentEqual = m_base == m_extent;
- if (m_base.isNotNull()) {
- m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
- if (baseAndExtentEqual)
- m_extent = m_base;
- }
- if (m_extent.isNotNull() && !baseAndExtentEqual)
- m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
-
- // Make sure we do not have a dangling base or extent.
- if (m_base.isNull() && m_extent.isNull())
- m_baseIsFirst = true;
- else if (m_base.isNull()) {
- m_base = m_extent;
- m_baseIsFirst = true;
- } else if (m_extent.isNull()) {
- m_extent = m_base;
- m_baseIsFirst = true;
- } else {
- m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
- }
-
- if (m_baseIsFirst) {
- m_start = m_base;
- m_end = m_extent;
- } else {
- m_start = m_extent;
- m_end = m_base;
- }
-
- // Expand the selection if requested.
- switch (m_granularity) {
- case CharacterGranularity:
- // Don't do any expansion.
- break;
- case WordGranularity: {
- // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary).
- // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in
- // the document, select that last word (LeftWordIfOnBoundary).
- // Edge case: If the caret is after the last word in a paragraph, select from the the end of the
- // last word to the line break (also RightWordIfOnBoundary);
- VisiblePosition start = VisiblePosition(m_start, m_affinity);
- VisiblePosition originalEnd(m_end, m_affinity);
- EWordSide side = RightWordIfOnBoundary;
- if (isEndOfDocument(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start)))
- side = LeftWordIfOnBoundary;
- m_start = startOfWord(start, side).deepEquivalent();
- side = RightWordIfOnBoundary;
- if (isEndOfDocument(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd)))
- side = LeftWordIfOnBoundary;
-
- VisiblePosition wordEnd(endOfWord(originalEnd, side));
- VisiblePosition end(wordEnd);
-
- if (isEndOfParagraph(originalEnd)) {
- // Select the paragraph break (the space from the end of a paragraph to the start of
- // the next one) to match TextEdit.
- end = wordEnd.next();
-
- if (Node* table = isFirstPositionAfterTable(end)) {
- // The paragraph break after the last paragraph in the last cell of a block table ends
- // at the start of the paragraph after the table.
- if (isBlock(table))
- end = end.next(true);
- else
- end = wordEnd;
- }
-
- if (end.isNull())
- end = wordEnd;
-
- }
-
- m_end = end.deepEquivalent();
- break;
- }
- case SentenceGranularity: {
- m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- }
- case LineGranularity: {
- m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
- // If the end of this line is at the end of a paragraph, include the space
- // after the end of the line in the selection.
- if (isEndOfParagraph(end)) {
- VisiblePosition next = end.next();
- if (next.isNotNull())
- end = next;
- }
- m_end = end.deepEquivalent();
- break;
- }
- case LineBoundary:
- m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case ParagraphGranularity: {
- VisiblePosition pos(m_start, m_affinity);
- if (isStartOfLine(pos) && isEndOfDocument(pos))
- pos = pos.previous();
- m_start = startOfParagraph(pos).deepEquivalent();
- VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity));
-
- // Include the "paragraph break" (the space from the end of this paragraph to the start
- // of the next one) in the selection.
- VisiblePosition end(visibleParagraphEnd.next());
-
- if (Node* table = isFirstPositionAfterTable(end)) {
- // The paragraph break after the last paragraph in the last cell of a block table ends
- // at the start of the paragraph after the table, not at the position just after the table.
- if (isBlock(table))
- end = end.next(true);
- // There is no parargraph break after the last paragraph in the last cell of an inline table.
- else
- end = visibleParagraphEnd;
- }
-
- if (end.isNull())
- end = visibleParagraphEnd;
-
- m_end = end.deepEquivalent();
- break;
- }
- case DocumentBoundary:
- m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case ParagraphBoundary:
- m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case SentenceBoundary:
- m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- }
-
- // Make sure we do not have a dangling start or end.
- if (m_start.isNull())
- m_start = m_end;
- if (m_end.isNull())
- m_end = m_start;
-
- adjustForEditableContent();
-
- // adjust the state
- if (m_start.isNull()) {
- ASSERT(m_end.isNull());
- m_state = NONE;
-
- // enforce downstream affinity if not caret, as affinity only
- // makes sense for caret
- m_affinity = DOWNSTREAM;
- } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
- m_state = CARET;
- } else {
- m_state = RANGE;
-
- // enforce downstream affinity if not caret, as affinity only
- // makes sense for caret
- m_affinity = DOWNSTREAM;
-
- // "Constrain" the selection to be the smallest equivalent range of nodes.
- // This is a somewhat arbitrary choice, but experience shows that it is
- // useful to make to make the selection "canonical" (if only for
- // purposes of comparing selections). This is an ideal point of the code
- // to do this operation, since all selection changes that result in a RANGE
- // come through here before anyone uses it.
- // FIXME: Canonicalizing is good, but haven't we already done it (when we
- // set these two positions to VisiblePosition deepEquivalent()s above)?
- m_start = m_start.downstream();
- m_end = m_end.upstream();
- }
-}
-
-// FIXME: This function breaks the invariant of this class.
-// But because we use Selection to store values in editing commands for use when
-// undoing the command, we need to be able to create a selection that while currently
-// invalid, will be valid once the changes are undone. This is a design problem.
-// To fix it we either need to change the invariants of Selection or create a new
-// class for editing to use that can manipulate selections that are not currently valid.
-void Selection::setWithoutValidation(const Position& base, const Position& extent)
-{
- ASSERT(!base.isNull());
- ASSERT(!extent.isNull());
- ASSERT(base != extent);
- ASSERT(m_affinity == DOWNSTREAM);
- ASSERT(m_granularity == CharacterGranularity);
- m_base = base;
- m_extent = extent;
- m_baseIsFirst = comparePositions(base, extent) <= 0;
- if (m_baseIsFirst) {
- m_start = base;
- m_end = extent;
- } else {
- m_start = extent;
- m_end = base;
- }
- m_state = RANGE;
-}
-
-void Selection::adjustForEditableContent()
-{
- if (m_base.isNull() || m_start.isNull() || m_end.isNull())
- return;
-
- Node* baseRoot = highestEditableRoot(m_base);
- Node* startRoot = highestEditableRoot(m_start);
- Node* endRoot = highestEditableRoot(m_end);
-
- Node* baseEditableAncestor = lowestEditableAncestor(m_base.node());
-
- // The base, start and end are all in the same region. No adjustment necessary.
- if (baseRoot == startRoot && baseRoot == endRoot)
- return;
-
- // The selection is based in editable content.
- if (baseRoot) {
- // If the start is outside the base's editable root, cap it at the start of that root.
- // If the start is in non-editable content that is inside the base's editable root, put it
- // at the first editable position after start inside the base's editable root.
- if (startRoot != baseRoot) {
- VisiblePosition first = firstEditablePositionAfterPositionInRoot(m_start, baseRoot);
- m_start = first.deepEquivalent();
- if (m_start.isNull()) {
- ASSERT_NOT_REACHED();
- m_start = m_end;
- }
- }
- // If the end is outside the base's editable root, cap it at the end of that root.
- // If the end is in non-editable content that is inside the base's root, put it
- // at the last editable position before the end inside the base's root.
- if (endRoot != baseRoot) {
- VisiblePosition last = lastEditablePositionBeforePositionInRoot(m_end, baseRoot);
- m_end = last.deepEquivalent();
- if (m_end.isNull()) {
- ASSERT_NOT_REACHED();
- m_end = m_start;
- }
- }
- // The selection is based in non-editable content.
- } else {
- // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable
- // pieces in non-editable content are atomic.
-
- // The selection ends in editable content or non-editable content inside a different editable ancestor,
- // move backward until non-editable content inside the same lowest editable ancestor is reached.
- Node* endEditableAncestor = lowestEditableAncestor(m_end.node());
- if (endRoot || endEditableAncestor != baseEditableAncestor) {
-
- Position p = previousVisuallyDistinctCandidate(m_end);
- Node* shadowAncestor = endRoot ? endRoot->shadowAncestorNode() : 0;
- if (p.isNull() && endRoot && (shadowAncestor != endRoot))
- p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
- Node* root = editableRootForPosition(p);
- shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
- if (p.isNull() && (shadowAncestor != root))
- p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
- }
- VisiblePosition previous(p);
-
- if (previous.isNull()) {
- ASSERT_NOT_REACHED();
- m_base = Position();
- m_extent = Position();
- validate();
- return;
- }
- m_end = previous.deepEquivalent();
- }
-
- // The selection starts in editable content or non-editable content inside a different editable ancestor,
- // move forward until non-editable content inside the same lowest editable ancestor is reached.
- Node* startEditableAncestor = lowestEditableAncestor(m_start.node());
- if (startRoot || startEditableAncestor != baseEditableAncestor) {
- Position p = nextVisuallyDistinctCandidate(m_start);
- Node* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0;
- if (p.isNull() && startRoot && (shadowAncestor != startRoot))
- p = Position(shadowAncestor, 0);
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
- Node* root = editableRootForPosition(p);
- shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
- if (p.isNull() && (shadowAncestor != root))
- p = Position(shadowAncestor, 0);
- }
- VisiblePosition next(p);
-
- if (next.isNull()) {
- ASSERT_NOT_REACHED();
- m_base = Position();
- m_extent = Position();
- validate();
- return;
- }
- m_start = next.deepEquivalent();
- }
- }
-
- // Correct the extent if necessary.
- if (baseEditableAncestor != lowestEditableAncestor(m_extent.node()))
- m_extent = m_baseIsFirst ? m_end : m_start;
-}
-
-bool Selection::isContentEditable() const
-{
- return isEditablePosition(start());
-}
-
-bool Selection::isContentRichlyEditable() const
-{
- return isRichlyEditablePosition(start());
-}
-
-Element* Selection::rootEditableElement() const
-{
- return editableRootForPosition(start());
-}
-
-Node* Selection::shadowTreeRootNode() const
-{
- return start().node() ? start().node()->shadowTreeRootNode() : 0;
-}
-
-void Selection::debugPosition() const
-{
- if (!m_start.node())
- return;
-
- fprintf(stderr, "Selection =================\n");
-
- if (m_start == m_end) {
- Position pos = m_start;
- fprintf(stderr, "pos: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- } else {
- Position pos = m_start;
- fprintf(stderr, "start: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- fprintf(stderr, "-----------------------------------\n");
- pos = m_end;
- fprintf(stderr, "end: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- fprintf(stderr, "-----------------------------------\n");
- }
-
- fprintf(stderr, "================================\n");
-}
-
-#ifndef NDEBUG
-
-void Selection::formatForDebugger(char* buffer, unsigned length) const
-{
- String result;
- String s;
-
- if (isNone()) {
- result = "<none>";
- } else {
- const int FormatBufferSize = 1024;
- char s[FormatBufferSize];
- result += "from ";
- start().formatForDebugger(s, FormatBufferSize);
- result += s;
- result += " to ";
- end().formatForDebugger(s, FormatBufferSize);
- result += s;
- }
-
- strncpy(buffer, result.utf8().data(), length - 1);
-}
-
-void Selection::showTreeForThis() const
-{
- if (start().node()) {
- start().node()->showTreeAndMark(start().node(), "S", end().node(), "E");
- fprintf(stderr, "start offset: %d, end offset: %d\n", start().offset(), end().offset());
- }
-}
-
-#endif
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-
-void showTree(const WebCore::Selection& sel)
-{
- sel.showTreeForThis();
-}
-
-void showTree(const WebCore::Selection* sel)
-{
- if (sel)
- sel->showTreeForThis();
-}
-
-#endif
diff --git a/WebCore/editing/Selection.h b/WebCore/editing/Selection.h
deleted file mode 100644
index ae50073..0000000
--- a/WebCore/editing/Selection.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Selection_h
-#define Selection_h
-
-#include "TextGranularity.h"
-#include "VisiblePosition.h"
-
-namespace WebCore {
-
-class Position;
-
-const EAffinity SEL_DEFAULT_AFFINITY = DOWNSTREAM;
-
-class Selection {
-public:
- enum EState { NONE, CARET, RANGE };
- enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
-
- Selection();
-
- Selection(const Position&, EAffinity);
- Selection(const Position&, const Position&, EAffinity);
-
- Selection(const Range*, EAffinity = SEL_DEFAULT_AFFINITY);
-
- Selection(const VisiblePosition&);
- Selection(const VisiblePosition&, const VisiblePosition&);
-
- static Selection selectionFromContentsOfNode(Node*);
-
- EState state() const { return m_state; }
-
- void setAffinity(EAffinity affinity) { m_affinity = affinity; }
- EAffinity affinity() const { return m_affinity; }
-
- void setBase(const Position&);
- void setBase(const VisiblePosition&);
- void setExtent(const Position&);
- void setExtent(const VisiblePosition&);
-
- Position base() const { return m_base; }
- Position extent() const { return m_extent; }
- Position start() const { return m_start; }
- Position end() const { return m_end; }
-
- VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? DOWNSTREAM : affinity()); }
- VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? UPSTREAM : affinity()); }
-
- bool isNone() const { return state() == NONE; }
- bool isCaret() const { return state() == CARET; }
- bool isRange() const { return state() == RANGE; }
- bool isCaretOrRange() const { return state() != NONE; }
-
- bool isBaseFirst() const { return m_baseIsFirst; }
-
- bool expandUsingGranularity(TextGranularity granularity);
- TextGranularity granularity() const { return m_granularity; }
-
- PassRefPtr<Range> toRange() const;
-
- Element* rootEditableElement() const;
- bool isContentEditable() const;
- bool isContentRichlyEditable() const;
- Node* shadowTreeRootNode() const;
-
- void debugPosition() const;
-
-#ifndef NDEBUG
- void formatForDebugger(char* buffer, unsigned length) const;
- void showTreeForThis() const;
-#endif
-
- void setWithoutValidation(const Position&, const Position&);
-
-private:
- void validate();
- void adjustForEditableContent();
-
- Position m_base; // base position for the selection
- Position m_extent; // extent position for the selection
- Position m_start; // start position for the selection
- Position m_end; // end position for the selection
-
- EAffinity m_affinity; // the upstream/downstream affinity of the caret
- TextGranularity m_granularity; // granularity of start/end selection
-
- // these are cached, can be recalculated by validate()
- EState m_state; // the state of the selection
- bool m_baseIsFirst; // true if base is before the extent
-};
-
-inline bool operator==(const Selection& a, const Selection& b)
-{
- return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity() && a.granularity() == b.granularity() && a.isBaseFirst() == b.isBaseFirst();
-}
-
-inline bool operator!=(const Selection& a, const Selection& b)
-{
- return !(a == b);
-}
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-// Outside the WebCore namespace for ease of invocation from gdb.
-void showTree(const WebCore::Selection&);
-void showTree(const WebCore::Selection*);
-#endif
-
-#endif // Selection_h
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
deleted file mode 100644
index bf52be4..0000000
--- a/WebCore/editing/SelectionController.cpp
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SelectionController.h"
-
-#include "CString.h"
-#include "DeleteSelectionCommand.h"
-#include "Document.h"
-#include "Editor.h"
-#include "Element.h"
-#include "EventHandler.h"
-#include "EventNames.h"
-#include "ExceptionCode.h"
-#include "FocusController.h"
-#include "Frame.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "GraphicsContext.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "HitTestRequest.h"
-#include "HitTestResult.h"
-#include "Page.h"
-#include "Range.h"
-#include "RenderTheme.h"
-#include "RenderView.h"
-#include "TextIterator.h"
-#include "TypingCommand.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-#include <stdio.h>
-
-#define EDIT_DEBUG 0
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-const int NoXPosForVerticalArrowNavigation = INT_MIN;
-
-SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
- : m_needsLayout(true)
- , m_lastChangeWasHorizontalExtension(false)
- , m_frame(frame)
- , m_isDragCaretController(isDragCaretController)
- , m_isCaretBlinkingSuspended(false)
- , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
- , m_focused(false)
-{
-}
-
-void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered)
-{
- setSelection(Selection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
-}
-
-void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered)
-{
- setSelection(Selection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);
-}
-
-void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered)
-{
- setSelection(Selection(pos, affinity), true, true, userTriggered);
-}
-
-void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered)
-{
- setSelection(Selection(startPosition(r), endPosition(r), affinity), true, true, userTriggered);
-}
-
-void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered)
-{
- setSelection(Selection(base, extent, affinity), true, true, userTriggered);
-}
-
-void SelectionController::setSelection(const Selection& s, bool closeTyping, bool clearTypingStyleAndRemovedAnchor, bool userTriggered)
-{
- if (m_isDragCaretController) {
- invalidateCaretRect();
- m_sel = s;
- m_needsLayout = true;
- invalidateCaretRect();
- return;
- }
- if (!m_frame) {
- m_sel = s;
- return;
- }
-
- if (s.base().node() && s.base().node()->document() != m_frame->document()) {
- s.base().node()->document()->frame()->selection()->setSelection(s, closeTyping, clearTypingStyleAndRemovedAnchor, userTriggered);
- return;
- }
-
- if (closeTyping)
- TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());
-
- if (clearTypingStyleAndRemovedAnchor) {
- m_frame->clearTypingStyle();
- m_frame->editor()->setRemovedAnchor(0);
- }
-
- if (m_sel == s)
- return;
-
- Selection oldSelection = m_sel;
-
- m_sel = s;
-
- m_needsLayout = true;
-
- if (!s.isNone())
- m_frame->setFocusedNodeIfNeeded();
-
- m_frame->selectionLayoutChanged();
- // Always clear the x position used for vertical arrow navigation.
- // It will be restored by the vertical arrow navigation code if necessary.
- m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
- selectFrameElementInParentIfFullySelected();
- m_frame->notifyRendererOfSelectionChange(userTriggered);
- m_frame->respondToChangedSelection(oldSelection, closeTyping);
- if (userTriggered)
- m_frame->revealCaret(RenderLayer::gAlignToEdgeIfNeeded);
-
- notifyAccessibilityForSelectionChange();
-}
-
-static bool removingNodeRemovesPosition(Node* node, const Position& position)
-{
- if (!position.node())
- return false;
-
- if (position.node() == node)
- return true;
-
- if (!node->isElementNode())
- return false;
-
- Element* element = static_cast<Element*>(node);
- return element->contains(position.node()) || element->contains(position.node()->shadowAncestorNode());
-}
-
-void SelectionController::nodeWillBeRemoved(Node *node)
-{
- if (isNone())
- return;
-
- // There can't be a selection inside a fragment, so if a fragment's node is being removed,
- // the selection in the document that created the fragment needs no adjustment.
- if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
- return;
-
- bool baseRemoved = removingNodeRemovesPosition(node, m_sel.base());
- bool extentRemoved = removingNodeRemovesPosition(node, m_sel.extent());
- bool startRemoved = removingNodeRemovesPosition(node, m_sel.start());
- bool endRemoved = removingNodeRemovesPosition(node, m_sel.end());
-
- bool clearRenderTreeSelection = false;
- bool clearDOMTreeSelection = false;
-
- if (startRemoved || endRemoved) {
- // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.
- clearRenderTreeSelection = true;
- clearDOMTreeSelection = true;
- } else if (baseRemoved || extentRemoved) {
- // The base and/or extent are about to be removed, but the start and end aren't.
- // Change the base and extent to the start and end, but don't re-validate the
- // selection, since doing so could move the start and end into the node
- // that is about to be removed.
- if (m_sel.isBaseFirst())
- m_sel.setWithoutValidation(m_sel.start(), m_sel.end());
- else
- m_sel.setWithoutValidation(m_sel.end(), m_sel.start());
- // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.
- } else if (Range::compareBoundaryPoints(m_sel.start(), Position(node, 0)) == -1 &&
- Range::compareBoundaryPoints(m_sel.end(), Position(node, 0)) == 1) {
- // If we did nothing here, when this node's renderer was destroyed, the rect that it
- // occupied would be invalidated, but, selection gaps that change as a result of
- // the removal wouldn't be invalidated.
- // FIXME: Don't do so much unnecessary invalidation.
- clearRenderTreeSelection = true;
- }
-
- if (clearRenderTreeSelection) {
- RefPtr<Document> document = m_sel.start().node()->document();
- document->updateRendering();
- if (RenderView* view = static_cast<RenderView*>(document->renderer()))
- view->clearSelection();
- }
-
- if (clearDOMTreeSelection)
- setSelection(Selection(), false, false);
-}
-
-void SelectionController::willBeModified(EAlteration alter, EDirection direction)
-{
- switch (alter) {
- case MOVE:
- m_lastChangeWasHorizontalExtension = false;
- break;
- case EXTEND:
- if (!m_lastChangeWasHorizontalExtension) {
- m_lastChangeWasHorizontalExtension = true;
- Position start = m_sel.start();
- Position end = m_sel.end();
- switch (direction) {
- // FIXME: right for bidi?
- case RIGHT:
- case FORWARD:
- m_sel.setBase(start);
- m_sel.setExtent(end);
- break;
- case LEFT:
- case BACKWARD:
- m_sel.setBase(end);
- m_sel.setExtent(start);
- break;
- }
- }
- break;
- }
-}
-
-VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity granularity)
-{
- VisiblePosition pos(m_sel.extent(), m_sel.affinity());
- switch (granularity) {
- case CharacterGranularity:
- pos = pos.next(true);
- break;
- case WordGranularity:
- pos = nextWordPosition(pos);
- break;
- case SentenceGranularity:
- pos = nextSentencePosition(pos);
- break;
- case LineGranularity:
- pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
- break;
- case ParagraphGranularity:
- pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
- break;
- case SentenceBoundary:
- pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case LineBoundary:
- pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case ParagraphBoundary:
- pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case DocumentBoundary:
- pos = VisiblePosition(m_sel.end(), m_sel.affinity());
- if (isEditablePosition(pos.deepEquivalent()))
- pos = endOfEditableContent(pos);
- else
- pos = endOfDocument(pos);
- break;
- }
-
- return pos;
-}
-
-VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
-{
- VisiblePosition pos;
- switch (granularity) {
- case CharacterGranularity:
- if (isRange())
- pos = VisiblePosition(m_sel.end(), m_sel.affinity());
- else
- pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).right(true);
- break;
- case WordGranularity:
- case SentenceGranularity:
- case LineGranularity:
- case ParagraphGranularity:
- case SentenceBoundary:
- case LineBoundary:
- case ParagraphBoundary:
- case DocumentBoundary:
- // FIXME: Implement all of the above.
- pos = modifyMovingForward(granularity);
- break;
- }
- return pos;
-}
-
-VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
-{
- VisiblePosition pos;
- // FIXME: Stay in editable content for the less common granularities.
- switch (granularity) {
- case CharacterGranularity:
- if (isRange())
- pos = VisiblePosition(m_sel.end(), m_sel.affinity());
- else
- pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next(true);
- break;
- case WordGranularity:
- pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
- break;
- case SentenceGranularity:
- pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
- break;
- case LineGranularity: {
- // down-arrowing from a range selection that ends at the start of a line needs
- // to leave the selection at that line start (no need to call nextLinePosition!)
- pos = VisiblePosition(m_sel.end(), m_sel.affinity());
- if (!isRange() || !isStartOfLine(pos))
- pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
- break;
- }
- case ParagraphGranularity:
- pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
- break;
- case SentenceBoundary:
- pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case LineBoundary:
- pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case ParagraphBoundary:
- pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));
- break;
- case DocumentBoundary:
- pos = VisiblePosition(m_sel.end(), m_sel.affinity());
- if (isEditablePosition(pos.deepEquivalent()))
- pos = endOfEditableContent(pos);
- else
- pos = endOfDocument(pos);
- break;
-
- }
- return pos;
-}
-
-VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity granularity)
-{
- VisiblePosition pos(m_sel.extent(), m_sel.affinity());
-
- // Extending a selection backward by word or character from just after a table selects
- // the table. This "makes sense" from the user perspective, esp. when deleting.
- // It was done here instead of in VisiblePosition because we want VPs to iterate
- // over everything.
- switch (granularity) {
- case CharacterGranularity:
- pos = pos.previous(true);
- break;
- case WordGranularity:
- pos = previousWordPosition(pos);
- break;
- case SentenceGranularity:
- pos = previousSentencePosition(pos);
- break;
- case LineGranularity:
- pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));
- break;
- case ParagraphGranularity:
- pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
- break;
- case SentenceBoundary:
- pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case LineBoundary:
- pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case ParagraphBoundary:
- pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case DocumentBoundary:
- pos = VisiblePosition(m_sel.start(), m_sel.affinity());
- if (isEditablePosition(pos.deepEquivalent()))
- pos = startOfEditableContent(pos);
- else
- pos = startOfDocument(pos);
- break;
- }
- return pos;
-}
-
-VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
-{
- VisiblePosition pos;
- switch (granularity) {
- case CharacterGranularity:
- if (isRange())
- pos = VisiblePosition(m_sel.start(), m_sel.affinity());
- else
- pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).left(true);
- break;
- case WordGranularity:
- case SentenceGranularity:
- case LineGranularity:
- case ParagraphGranularity:
- case SentenceBoundary:
- case LineBoundary:
- case ParagraphBoundary:
- case DocumentBoundary:
- // FIXME: Implement all of the above.
- pos = modifyMovingBackward(granularity);
- break;
- }
- return pos;
-}
-
-VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
-{
- VisiblePosition pos;
- switch (granularity) {
- case CharacterGranularity:
- if (isRange())
- pos = VisiblePosition(m_sel.start(), m_sel.affinity());
- else
- pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).previous(true);
- break;
- case WordGranularity:
- pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
- break;
- case SentenceGranularity:
- pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));
- break;
- case LineGranularity:
- pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
- break;
- case ParagraphGranularity:
- pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));
- break;
- case SentenceBoundary:
- pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case LineBoundary:
- pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case ParagraphBoundary:
- pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));
- break;
- case DocumentBoundary:
- pos = VisiblePosition(m_sel.start(), m_sel.affinity());
- if (isEditablePosition(pos.deepEquivalent()))
- pos = startOfEditableContent(pos);
- else
- pos = startOfDocument(pos);
- break;
- }
- return pos;
-}
-
-bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
-{
- if (userTriggered) {
- SelectionController trialSelectionController;
- trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
- trialSelectionController.setSelection(m_sel);
- trialSelectionController.modify(alter, dir, granularity, false);
-
- bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
- if (!change)
- return false;
- }
-
- if (m_frame)
- m_frame->setSelectionGranularity(granularity);
-
- willBeModified(alter, dir);
-
- VisiblePosition pos;
- switch (dir) {
- case RIGHT:
- if (alter == MOVE)
- pos = modifyMovingRight(granularity);
- else
- pos = modifyExtendingRightForward(granularity);
- break;
- case FORWARD:
- if (alter == EXTEND)
- pos = modifyExtendingRightForward(granularity);
- else
- pos = modifyMovingForward(granularity);
- break;
- case LEFT:
- if (alter == MOVE)
- pos = modifyMovingLeft(granularity);
- else
- pos = modifyExtendingLeftBackward(granularity);
- break;
- case BACKWARD:
- if (alter == EXTEND)
- pos = modifyExtendingLeftBackward(granularity);
- else
- pos = modifyMovingBackward(granularity);
- break;
- }
-
- if (pos.isNull())
- return false;
-
- // Some of the above operations set an xPosForVerticalArrowNavigation.
- // Setting a selection will clear it, so save it to possibly restore later.
- // Note: the START position type is arbitrary because it is unused, it would be
- // the requested position type if there were no xPosForVerticalArrowNavigation set.
- int x = xPosForVerticalArrowNavigation(START);
-
- switch (alter) {
- case MOVE:
- moveTo(pos, userTriggered);
- break;
- case EXTEND:
- setExtent(pos, userTriggered);
- break;
- }
-
- if (granularity == LineGranularity || granularity == ParagraphGranularity)
- m_xPosForVerticalArrowNavigation = x;
-
- if (userTriggered) {
- // User modified selection change also sets the granularity back to character.
- // NOTE: The one exception is that we need to keep word granularity to
- // preserve smart delete behavior when extending by word (e.g. double-click),
- // then shift-option-right arrow, then delete needs to smart delete, per TextEdit.
- if (!(alter == EXTEND && granularity == WordGranularity && m_frame->selectionGranularity() == WordGranularity))
- m_frame->setSelectionGranularity(CharacterGranularity);
- }
-
- setNeedsLayout();
-
- return true;
-}
-
-// FIXME: Maybe baseline would be better?
-static bool caretY(const VisiblePosition &c, int &y)
-{
- IntRect rect = c.caretRect();
- if (rect.isEmpty())
- return false;
- y = rect.y() + rect.height() / 2;
- return true;
-}
-
-bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered)
-{
- if (verticalDistance == 0)
- return false;
-
- if (userTriggered) {
- SelectionController trialSelectionController;
- trialSelectionController.setSelection(m_sel);
- trialSelectionController.modify(alter, verticalDistance, false);
-
- bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
- if (!change)
- return false;
- }
-
- bool up = verticalDistance < 0;
- if (up)
- verticalDistance = -verticalDistance;
-
- willBeModified(alter, up ? BACKWARD : FORWARD);
-
- VisiblePosition pos;
- int xPos = 0;
- switch (alter) {
- case MOVE:
- pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity());
- xPos = xPosForVerticalArrowNavigation(up ? START : END);
- m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM);
- break;
- case EXTEND:
- pos = VisiblePosition(m_sel.extent(), m_sel.affinity());
- xPos = xPosForVerticalArrowNavigation(EXTENT);
- m_sel.setAffinity(DOWNSTREAM);
- break;
- }
-
- int startY;
- if (!caretY(pos, startY))
- return false;
- if (up)
- startY = -startY;
- int lastY = startY;
-
- VisiblePosition result;
- VisiblePosition next;
- for (VisiblePosition p = pos; ; p = next) {
- next = (up ? previousLinePosition : nextLinePosition)(p, xPos);
- if (next.isNull() || next == p)
- break;
- int nextY;
- if (!caretY(next, nextY))
- break;
- if (up)
- nextY = -nextY;
- if (nextY - startY > verticalDistance)
- break;
- if (nextY >= lastY) {
- lastY = nextY;
- result = next;
- }
- }
-
- if (result.isNull())
- return false;
-
- switch (alter) {
- case MOVE:
- moveTo(result, userTriggered);
- break;
- case EXTEND:
- setExtent(result, userTriggered);
- break;
- }
-
- if (userTriggered)
- m_frame->setSelectionGranularity(CharacterGranularity);
-
- return true;
-}
-
-bool SelectionController::expandUsingGranularity(TextGranularity granularity)
-{
- if (isNone())
- return false;
-
- m_sel.expandUsingGranularity(granularity);
- m_needsLayout = true;
- return true;
-}
-
-int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
-{
- int x = 0;
-
- if (isNone())
- return x;
-
- Position pos;
- switch (type) {
- case START:
- pos = m_sel.start();
- break;
- case END:
- pos = m_sel.end();
- break;
- case BASE:
- pos = m_sel.base();
- break;
- case EXTENT:
- pos = m_sel.extent();
- break;
- }
-
- Frame *frame = pos.node()->document()->frame();
- if (!frame)
- return x;
-
- if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) {
- VisiblePosition visiblePosition(pos, m_sel.affinity());
- // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden
- // after the selection is created and before this function is called.
- x = visiblePosition.isNotNull() ? visiblePosition.caretRect().x() : 0;
- m_xPosForVerticalArrowNavigation = x;
- }
- else
- x = m_xPosForVerticalArrowNavigation;
-
- return x;
-}
-
-void SelectionController::clear()
-{
- setSelection(Selection());
-}
-
-void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
-{
- setSelection(Selection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()), true, true, userTriggered);
-}
-
-void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered)
-{
- setSelection(Selection(m_sel.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);
-}
-
-void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered)
-{
- setSelection(Selection(pos, m_sel.extent(), affinity), true, true, userTriggered);
-}
-
-void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered)
-{
- setSelection(Selection(m_sel.base(), pos, affinity), true, true, userTriggered);
-}
-
-void SelectionController::setNeedsLayout(bool flag)
-{
- m_needsLayout = flag;
-}
-
-void SelectionController::layout()
-{
- if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) {
- m_caretRect = IntRect();
- m_caretPositionOnLayout = IntPoint();
- return;
- }
-
- m_sel.start().node()->document()->updateRendering();
-
- m_caretRect = IntRect();
- m_caretPositionOnLayout = IntPoint();
-
- if (isCaret()) {
- VisiblePosition pos(m_sel.start(), m_sel.affinity());
- if (pos.isNotNull()) {
- ASSERT(pos.deepEquivalent().node()->renderer());
- m_caretRect = pos.caretRect();
-
- int x, y;
- pos.deepEquivalent().node()->renderer()->absolutePositionForContent(x, y);
- m_caretPositionOnLayout = IntPoint(x, y);
- }
- }
-
- m_needsLayout = false;
-}
-
-IntRect SelectionController::caretRect() const
-{
- if (m_needsLayout)
- const_cast<SelectionController *>(this)->layout();
-
- IntRect caret = m_caretRect;
-
- if (m_sel.start().node() && m_sel.start().node()->renderer()) {
- int x, y;
- m_sel.start().node()->renderer()->absolutePositionForContent(x, y);
- caret.move(IntPoint(x, y) - m_caretPositionOnLayout);
- }
-
- return caret;
-}
-
-static IntRect repaintRectForCaret(IntRect caret)
-{
- if (caret.isEmpty())
- return IntRect();
- // Ensure that the dirty rect intersects the block that paints the caret even in the case where
- // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>.
- caret.inflateX(1);
- return caret;
-}
-
-IntRect SelectionController::caretRepaintRect() const
-{
- return repaintRectForCaret(caretRect());
-}
-
-bool SelectionController::recomputeCaretRect()
-{
- if (!m_frame || !m_frame->document())
- return false;
-
- FrameView* v = m_frame->document()->view();
- if (!v)
- return false;
-
- if (!m_needsLayout)
- return false;
-
- IntRect oldRect = m_caretRect;
- m_needsLayout = true;
- IntRect newRect = caretRect();
- if (oldRect == newRect)
- return false;
-
- if (RenderView* view = static_cast<RenderView*>(m_frame->document()->renderer())) {
- view->repaintViewRectangle(repaintRectForCaret(oldRect), false);
- view->repaintViewRectangle(repaintRectForCaret(newRect), false);
- }
- return true;
-}
-
-void SelectionController::invalidateCaretRect()
-{
- if (!isCaret())
- return;
-
- Document* d = m_sel.start().node()->document();
-
- bool caretRectChanged = recomputeCaretRect();
-
- // EDIT FIXME: This is an unfortunate hack.
- // Basically, we can't trust this layout position since we
- // can't guarantee that the check to see if we are in unrendered
- // content will work at this point. We may have to wait for
- // a layout and re-render of the document to happen. So, resetting this
- // flag will cause another caret layout to happen the first time
- // that we try to paint the caret after this call. That one will work since
- // it happens after the document has accounted for any editing
- // changes which may have been done.
- // And, we need to leave this layout here so the caret moves right
- // away after clicking.
- m_needsLayout = true;
-
- if (!caretRectChanged) {
- if (RenderView* view = static_cast<RenderView*>(d->renderer()))
- view->repaintViewRectangle(caretRepaintRect(), false);
- }
-}
-
-void SelectionController::paintCaret(GraphicsContext *p, const IntRect &rect)
-{
- if (! m_sel.isCaret())
- return;
-
- if (m_needsLayout)
- layout();
-
- IntRect caret = intersection(caretRect(), rect);
- if (!caret.isEmpty()) {
- Color caretColor = Color::black;
- Element* element = rootEditableElement();
- if (element && element->renderer())
- caretColor = element->renderer()->style()->color();
-
- p->fillRect(caret, caretColor);
- }
-}
-
-void SelectionController::debugRenderer(RenderObject *r, bool selected) const
-{
- if (r->node()->isElementNode()) {
- Element *element = static_cast<Element *>(r->node());
- fprintf(stderr, "%s%s\n", selected ? "==> " : " ", element->localName().string().utf8().data());
- }
- else if (r->isText()) {
- RenderText* textRenderer = static_cast<RenderText*>(r);
- if (textRenderer->textLength() == 0 || !textRenderer->firstTextBox()) {
- fprintf(stderr, "%s#text (empty)\n", selected ? "==> " : " ");
- return;
- }
-
- static const int max = 36;
- String text = textRenderer->text();
- int textLength = text.length();
- if (selected) {
- int offset = 0;
- if (r->node() == m_sel.start().node())
- offset = m_sel.start().offset();
- else if (r->node() == m_sel.end().node())
- offset = m_sel.end().offset();
-
- int pos;
- InlineTextBox *box = textRenderer->findNextInlineTextBox(offset, pos);
- text = text.substring(box->m_start, box->m_len);
-
- String show;
- int mid = max / 2;
- int caret = 0;
-
- // text is shorter than max
- if (textLength < max) {
- show = text;
- caret = pos;
- }
-
- // too few characters to left
- else if (pos - mid < 0) {
- show = text.left(max - 3) + "...";
- caret = pos;
- }
-
- // enough characters on each side
- else if (pos - mid >= 0 && pos + mid <= textLength) {
- show = "..." + text.substring(pos - mid + 3, max - 6) + "...";
- caret = mid;
- }
-
- // too few characters on right
- else {
- show = "..." + text.right(max - 3);
- caret = pos - (textLength - show.length());
- }
-
- show.replace('\n', ' ');
- show.replace('\r', ' ');
- fprintf(stderr, "==> #text : \"%s\" at offset %d\n", show.utf8().data(), pos);
- fprintf(stderr, " ");
- for (int i = 0; i < caret; i++)
- fprintf(stderr, " ");
- fprintf(stderr, "^\n");
- }
- else {
- if ((int)text.length() > max)
- text = text.left(max - 3) + "...";
- else
- text = text.left(max);
- fprintf(stderr, " #text : \"%s\"\n", text.utf8().data());
- }
- }
-}
-
-bool SelectionController::contains(const IntPoint& point)
-{
- Document* document = m_frame->document();
-
- // Treat a collapsed selection like no selection.
- if (!isRange())
- return false;
- if (!document->renderer())
- return false;
-
- HitTestRequest request(true, true);
- HitTestResult result(point);
- document->renderer()->layer()->hitTest(request, result);
- Node* innerNode = result.innerNode();
- if (!innerNode || !innerNode->renderer())
- return false;
-
- VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(result.localPoint()));
- if (visiblePos.isNull())
- return false;
-
- if (m_sel.visibleStart().isNull() || m_sel.visibleEnd().isNull())
- return false;
-
- Position start(m_sel.visibleStart().deepEquivalent());
- Position end(m_sel.visibleEnd().deepEquivalent());
- Position p(visiblePos.deepEquivalent());
-
- return comparePositions(start, p) <= 0 && comparePositions(p, end) <= 0;
-}
-
-// Workaround for the fact that it's hard to delete a frame.
-// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
-// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
-// for the focus to move to another frame. So instead we call it from places where we are selecting with the
-// mouse or the keyboard after setting the selection.
-void SelectionController::selectFrameElementInParentIfFullySelected()
-{
- // Find the parent frame; if there is none, then we have nothing to do.
- Frame* parent = m_frame->tree()->parent();
- if (!parent)
- return;
- Page* page = m_frame->page();
- if (!page)
- return;
-
- // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
- if (!isRange())
- return;
- if (!isStartOfDocument(selection().visibleStart()))
- return;
- if (!isEndOfDocument(selection().visibleEnd()))
- return;
-
- // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
- Document* doc = m_frame->document();
- if (!doc)
- return;
- Element* ownerElement = doc->ownerElement();
- if (!ownerElement)
- return;
- Node* ownerElementParent = ownerElement->parentNode();
- if (!ownerElementParent)
- return;
-
- // This method's purpose is it to make it easier to select iframes (in order to delete them). Don't do anything if the iframe isn't deletable.
- if (!ownerElementParent->isContentEditable())
- return;
-
- // Create compute positions before and after the element.
- unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
- VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
- VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
-
- // Focus on the parent frame, and then select from before this element to after.
- Selection newSelection(beforeOwnerElement, afterOwnerElement);
- if (parent->shouldChangeSelection(newSelection)) {
- page->focusController()->setFocusedFrame(parent);
- parent->selection()->setSelection(newSelection);
- }
-}
-
-void SelectionController::selectAll()
-{
- Document* document = m_frame->document();
- if (!document)
- return;
-
- if (document->focusedNode() && document->focusedNode()->canSelectAll()) {
- document->focusedNode()->selectAll();
- return;
- }
-
- Node* root = 0;
- if (isContentEditable())
- root = highestEditableRoot(m_sel.start());
- else {
- root = shadowTreeRootNode();
- if (!root)
- root = document->documentElement();
- }
- if (!root)
- return;
- Selection newSelection(Selection::selectionFromContentsOfNode(root));
- if (m_frame->shouldChangeSelection(newSelection))
- setSelection(newSelection);
- selectFrameElementInParentIfFullySelected();
- m_frame->notifyRendererOfSelectionChange(true);
-}
-
-bool SelectionController::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
-{
- if (!range)
- return false;
-
- ExceptionCode ec = 0;
- Node* startContainer = range->startContainer(ec);
- if (ec)
- return false;
-
- Node* endContainer = range->endContainer(ec);
- if (ec)
- return false;
-
- ASSERT(startContainer);
- ASSERT(endContainer);
- ASSERT(startContainer->document() == endContainer->document());
-
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
-
- // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
- // they start at the beginning of the next line instead
- bool collapsed = range->collapsed(ec);
- if (ec)
- return false;
-
- int startOffset = range->startOffset(ec);
- if (ec)
- return false;
-
- int endOffset = range->endOffset(ec);
- if (ec)
- return false;
-
- // FIXME: Can we provide extentAffinity?
- VisiblePosition visibleStart(startContainer, startOffset, collapsed ? affinity : DOWNSTREAM);
- VisiblePosition visibleEnd(endContainer, endOffset, SEL_DEFAULT_AFFINITY);
- setSelection(Selection(visibleStart, visibleEnd), closeTyping);
- return true;
-}
-
-bool SelectionController::isInPasswordField() const
-{
- Node* startNode = start().node();
- if (!startNode)
- return false;
-
- startNode = startNode->shadowAncestorNode();
- if (!startNode)
- return false;
-
- if (!startNode->hasTagName(inputTag))
- return false;
-
- return static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
-}
-
-bool SelectionController::isInsideNode() const
-{
- Node* startNode = start().node();
- if (!startNode)
- return false;
- return !isTableElement(startNode) && !editingIgnoresContent(startNode);
-}
-
-void SelectionController::focusedOrActiveStateChanged()
-{
- bool activeAndFocused = isFocusedAndActive();
-
- // Because RenderObject::selectionBackgroundColor() and
- // RenderObject::selectionForegroundColor() check if the frame is active,
- // we have to update places those colors were painted.
- if (RenderView* view = static_cast<RenderView*>(m_frame->document()->renderer()))
- view->repaintViewRectangle(enclosingIntRect(m_frame->selectionRect()));
-
- // Caret appears in the active frame.
- if (activeAndFocused)
- m_frame->setSelectionFromNone();
- m_frame->setCaretVisible(activeAndFocused);
-
- // Update for caps lock state
- m_frame->eventHandler()->capsLockStateMayHaveChanged();
-
- // Because CSSStyleSelector::checkOneSelector() and
- // RenderTheme::isFocused() check if the frame is active, we have to
- // update style and theme state that depended on those.
- if (Node* node = m_frame->document()->focusedNode()) {
- node->setChanged();
- if (RenderObject* renderer = node->renderer())
- if (renderer && renderer->style()->hasAppearance())
- theme()->stateChanged(renderer, FocusState);
- }
-
- // Secure keyboard entry is set by the active frame.
- if (m_frame->document()->useSecureKeyboardEntryWhenActive())
- m_frame->setUseSecureKeyboardEntry(activeAndFocused);
-}
-
-void SelectionController::pageActivationChanged()
-{
- focusedOrActiveStateChanged();
-}
-
-void SelectionController::setFocused(bool flag)
-{
- if (m_focused == flag)
- return;
- m_focused = flag;
-
- focusedOrActiveStateChanged();
-
- if (Document* doc = m_frame->document())
- doc->dispatchWindowEvent(flag ? eventNames().focusEvent : eventNames().blurEvent, false, false);
-}
-
-bool SelectionController::isFocusedAndActive() const
-{
- return m_focused && m_frame->page() && m_frame->page()->focusController()->isActive();
-}
-
-#ifndef NDEBUG
-
-void SelectionController::formatForDebugger(char* buffer, unsigned length) const
-{
- m_sel.formatForDebugger(buffer, length);
-}
-
-void SelectionController::showTreeForThis() const
-{
- m_sel.showTreeForThis();
-}
-
-#endif
-
-}
-
-#ifndef NDEBUG
-
-void showTree(const WebCore::SelectionController& sel)
-{
- sel.showTreeForThis();
-}
-
-void showTree(const WebCore::SelectionController* sel)
-{
- if (sel)
- sel->showTreeForThis();
-}
-
-#endif
diff --git a/WebCore/editing/SelectionController.h b/WebCore/editing/SelectionController.h
deleted file mode 100644
index ba89670..0000000
--- a/WebCore/editing/SelectionController.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SelectionController_h
-#define SelectionController_h
-
-#include "IntRect.h"
-#include "Selection.h"
-#include "Range.h"
-#include <wtf/Noncopyable.h>
-
-namespace WebCore {
-
-class Frame;
-class GraphicsContext;
-class RenderObject;
-class VisiblePosition;
-
-class SelectionController : Noncopyable {
-public:
- enum EAlteration { MOVE, EXTEND };
- enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
-
- SelectionController(Frame* = 0, bool isDragCaretController = false);
-
- Element* rootEditableElement() const { return m_sel.rootEditableElement(); }
- bool isContentEditable() const { return m_sel.isContentEditable(); }
- bool isContentRichlyEditable() const { return m_sel.isContentRichlyEditable(); }
- Node* shadowTreeRootNode() const { return m_sel.shadowTreeRootNode(); }
-
- void moveTo(const Range*, EAffinity, bool userTriggered = false);
- void moveTo(const VisiblePosition&, bool userTriggered = false);
- void moveTo(const VisiblePosition&, const VisiblePosition&, bool userTriggered = false);
- void moveTo(const Position&, EAffinity, bool userTriggered = false);
- void moveTo(const Position&, const Position&, EAffinity, bool userTriggered = false);
-
- const Selection& selection() const { return m_sel; }
- void setSelection(const Selection&, bool closeTyping = true, bool clearTypingStyleAndRemovedAnchor = true, bool userTriggered = false);
- bool setSelectedRange(Range*, EAffinity, bool closeTyping);
- void selectAll();
- void clear();
-
- // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
- void selectFrameElementInParentIfFullySelected();
-
- bool contains(const IntPoint&);
-
- Selection::EState state() const { return m_sel.state(); }
-
- EAffinity affinity() const { return m_sel.affinity(); }
-
- bool modify(EAlteration, EDirection, TextGranularity, bool userTriggered = false);
- bool modify(EAlteration, int verticalDistance, bool userTriggered = false);
- bool expandUsingGranularity(TextGranularity);
-
- void setBase(const VisiblePosition&, bool userTriggered = false);
- void setBase(const Position&, EAffinity, bool userTriggered = false);
- void setExtent(const VisiblePosition&, bool userTriggered = false);
- void setExtent(const Position&, EAffinity, bool userTriggered = false);
-
- Position base() const { return m_sel.base(); }
- Position extent() const { return m_sel.extent(); }
- Position start() const { return m_sel.start(); }
- Position end() const { return m_sel.end(); }
-
- IntRect caretRect() const;
- void setNeedsLayout(bool flag = true);
-
- void setLastChangeWasHorizontalExtension(bool b) { m_lastChangeWasHorizontalExtension = b; }
- void willBeModified(EAlteration, EDirection);
-
- bool isNone() const { return m_sel.isNone(); }
- bool isCaret() const { return m_sel.isCaret(); }
- bool isRange() const { return m_sel.isRange(); }
- bool isCaretOrRange() const { return m_sel.isCaretOrRange(); }
- bool isInPasswordField() const;
- bool isInsideNode() const;
-
- PassRefPtr<Range> toRange() const { return m_sel.toRange(); }
-
- void debugRenderer(RenderObject*, bool selected) const;
-
- void nodeWillBeRemoved(Node*);
-
- bool recomputeCaretRect(); // returns true if caret rect moved
- void invalidateCaretRect();
- void paintCaret(GraphicsContext*, const IntRect&);
-
- // Used to suspend caret blinking while the mouse is down.
- void setCaretBlinkingSuspended(bool suspended) { m_isCaretBlinkingSuspended = suspended; }
- bool isCaretBlinkingSuspended() const { return m_isCaretBlinkingSuspended; }
-
- // Focus
- void setFocused(bool);
- bool isFocusedAndActive() const;
- void pageActivationChanged();
-
-#ifndef NDEBUG
- void formatForDebugger(char* buffer, unsigned length) const;
- void showTreeForThis() const;
-#endif
-
-private:
- enum EPositionType { START, END, BASE, EXTENT };
-
- VisiblePosition modifyExtendingRightForward(TextGranularity);
- VisiblePosition modifyMovingRight(TextGranularity);
- VisiblePosition modifyMovingForward(TextGranularity);
- VisiblePosition modifyExtendingLeftBackward(TextGranularity);
- VisiblePosition modifyMovingLeft(TextGranularity);
- VisiblePosition modifyMovingBackward(TextGranularity);
-
- void layout();
- IntRect caretRepaintRect() const;
-
- int xPosForVerticalArrowNavigation(EPositionType);
-
-#if PLATFORM(MAC)
- void notifyAccessibilityForSelectionChange();
-#else
- void notifyAccessibilityForSelectionChange() {};
-#endif
-
- void focusedOrActiveStateChanged();
-
- Selection m_sel;
-
- IntRect m_caretRect; // caret coordinates, size, and position
-
- // m_caretPositionOnLayout stores the scroll offset on the previous call to SelectionController::layout().
- // When asked for caretRect(), we correct m_caretRect for offset due to scrolling since the last layout().
- // This is faster than doing another layout().
- IntPoint m_caretPositionOnLayout;
-
- bool m_needsLayout : 1; // true if the caret and expectedVisible rectangles need to be calculated
- bool m_lastChangeWasHorizontalExtension : 1;
- Frame* m_frame;
- bool m_isDragCaretController;
-
- bool m_isCaretBlinkingSuspended;
-
- int m_xPosForVerticalArrowNavigation;
- bool m_focused;
-};
-
-inline bool operator==(const SelectionController& a, const SelectionController& b)
-{
- return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity();
-}
-
-inline bool operator!=(const SelectionController& a, const SelectionController& b)
-{
- return !(a == b);
-}
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-// Outside the WebCore namespace for ease of invocation from gdb.
-void showTree(const WebCore::SelectionController&);
-void showTree(const WebCore::SelectionController*);
-#endif
-
-#endif // SelectionController_h
diff --git a/WebCore/editing/SetNodeAttributeCommand.cpp b/WebCore/editing/SetNodeAttributeCommand.cpp
deleted file mode 100644
index 995dd1e..0000000
--- a/WebCore/editing/SetNodeAttributeCommand.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SetNodeAttributeCommand.h"
-
-#include "Element.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-SetNodeAttributeCommand::SetNodeAttributeCommand(PassRefPtr<Element> element,
- const QualifiedName& attribute, const String &value)
- : SimpleEditCommand(element->document()), m_element(element), m_attribute(attribute), m_value(value)
-{
- ASSERT(m_element);
- ASSERT(!m_value.isNull());
-}
-
-void SetNodeAttributeCommand::doApply()
-{
- ASSERT(m_element);
- ASSERT(!m_value.isNull());
-
- ExceptionCode ec = 0;
- m_oldValue = m_element->getAttribute(m_attribute);
- m_element->setAttribute(m_attribute, m_value.impl(), ec);
- ASSERT(ec == 0);
-}
-
-void SetNodeAttributeCommand::doUnapply()
-{
- ASSERT(m_element);
-
- ExceptionCode ec = 0;
- if (m_oldValue.isNull())
- m_element->removeAttribute(m_attribute, ec);
- else
- m_element->setAttribute(m_attribute, m_oldValue.impl(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
-
diff --git a/WebCore/editing/SetNodeAttributeCommand.h b/WebCore/editing/SetNodeAttributeCommand.h
deleted file mode 100644
index aec79a3..0000000
--- a/WebCore/editing/SetNodeAttributeCommand.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SetNodeAttributeCommand_h
-#define SetNodeAttributeCommand_h
-
-#include "EditCommand.h"
-#include "QualifiedName.h"
-
-namespace WebCore {
-
-class SetNodeAttributeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<SetNodeAttributeCommand> create(PassRefPtr<Element> element, const QualifiedName& attribute, const AtomicString& value)
- {
- return adoptRef(new SetNodeAttributeCommand(element, attribute, value));
- }
-
-private:
- SetNodeAttributeCommand(PassRefPtr<Element>, const QualifiedName& attribute, const String& value);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Element> m_element;
- QualifiedName m_attribute;
- AtomicString m_value;
- AtomicString m_oldValue;
-};
-
-} // namespace WebCore
-
-#endif // SetNodeAttributeCommand_h
diff --git a/WebCore/editing/SmartReplace.cpp b/WebCore/editing/SmartReplace.cpp
deleted file mode 100644
index c5f5240..0000000
--- a/WebCore/editing/SmartReplace.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SmartReplace.h"
-
-#if !PLATFORM(CF) && !USE(ICU_UNICODE)
-
-namespace WebCore {
-
-bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter)
-{
- return false;
-}
-
-}
-
-#endif // !PLATFORM(CF)
diff --git a/WebCore/editing/SmartReplace.h b/WebCore/editing/SmartReplace.h
deleted file mode 100644
index 5a37137..0000000
--- a/WebCore/editing/SmartReplace.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <wtf/unicode/Unicode.h>
-
-namespace WebCore {
-
-bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter);
-
-} // namespace WebCore
diff --git a/WebCore/editing/SmartReplaceCF.cpp b/WebCore/editing/SmartReplaceCF.cpp
deleted file mode 100644
index f2fd985..0000000
--- a/WebCore/editing/SmartReplaceCF.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SmartReplace.h"
-
-#include <CoreFoundation/CFCharacterSet.h>
-
-namespace WebCore {
-
-static CFMutableCharacterSetRef getSmartSet(bool isPreviousCharacter)
-{
- static CFMutableCharacterSetRef preSmartSet = NULL;
- static CFMutableCharacterSetRef postSmartSet = NULL;
- CFMutableCharacterSetRef smartSet = isPreviousCharacter ? preSmartSet : postSmartSet;
- if (!smartSet) {
- smartSet = CFCharacterSetCreateMutable(kCFAllocatorDefault);
- CFCharacterSetAddCharactersInString(smartSet, isPreviousCharacter ? CFSTR("([\"\'#$/-`{") : CFSTR(")].,;:?\'!\"%*-/}"));
- CFCharacterSetUnion(smartSet, CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline));
- // Adding CJK ranges
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x1100, 256)); // Hangul Jamo (0x1100 - 0x11FF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x2E80, 352)); // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x2FF0, 464)); // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x3200, 29392)); // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0xAC00, 11183)); // Hangul Syllables (0xAC00 - 0xD7AF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0xF900, 352)); // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0xFE30, 32)); // CJK Compatibility From (0xFE30 - 0xFE4F)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0xFF00, 240)); // Half/Full Width Form (0xFF00 - 0xFFEF)
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x20000, 0xA6D7)); // CJK Ideograph Exntension B
- CFCharacterSetAddCharactersInRange(smartSet, CFRangeMake(0x2F800, 0x021E)); // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)
-
- if (isPreviousCharacter)
- preSmartSet = smartSet;
- else {
- CFCharacterSetUnion(smartSet, CFCharacterSetGetPredefined(kCFCharacterSetPunctuation));
- postSmartSet = smartSet;
- }
- }
- return smartSet;
-}
-
-bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter)
-{
- return CFCharacterSetIsLongCharacterMember(getSmartSet(isPreviousCharacter), c);
-}
-
-}
diff --git a/WebCore/editing/SmartReplaceICU.cpp b/WebCore/editing/SmartReplaceICU.cpp
deleted file mode 100644
index 18be647..0000000
--- a/WebCore/editing/SmartReplaceICU.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Tony Chang <idealisms@gmail.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SmartReplace.h"
-
-#if !PLATFORM(CF) && USE(ICU_UNICODE)
-#include "PlatformString.h"
-#include <unicode/uset.h>
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-static void addAllCodePoints(USet* smartSet, const String& string) {
- const UChar* characters = string.characters();
- for (size_t i = 0; i < string.length(); i++)
- uset_add(smartSet, characters[i]);
-}
-
-// This is mostly a port of the code in WebCore/editing/SmartReplaceCF.cpp
-// except we use icu in place of CoreFoundations character classes.
-static USet* getSmartSet(bool isPreviousCharacter)
-{
- static USet* preSmartSet = NULL;
- static USet* postSmartSet = NULL;
- USet* smartSet = isPreviousCharacter ? preSmartSet : postSmartSet;
- if (!smartSet) {
- // Whitespace and newline (kCFCharacterSetWhitespaceAndNewline)
- UErrorCode ec = U_ZERO_ERROR;
- String whitespaceAndNewline = "[[:WSpace:] [\\u000A\\u000B\\u000C\\u000D\\u0085]]";
- smartSet = uset_openPattern(whitespaceAndNewline.characters(), whitespaceAndNewline.length(), &ec);
- ASSERT(U_SUCCESS(ec));
-
- // CJK ranges
- uset_addRange(smartSet, 0x1100, 0x1100 + 256); // Hangul Jamo (0x1100 - 0x11FF)
- uset_addRange(smartSet, 0x2E80, 0x2E80 + 352); // CJK & Kangxi Radicals (0x2E80 - 0x2FDF)
- uset_addRange(smartSet, 0x2FF0, 0x2FF0 + 464); // Ideograph Descriptions, CJK Symbols, Hiragana, Katakana, Bopomofo, Hangul Compatibility Jamo, Kanbun, & Bopomofo Ext (0x2FF0 - 0x31BF)
- uset_addRange(smartSet, 0x3200, 0x3200 + 29392); // Enclosed CJK, CJK Ideographs (Uni Han & Ext A), & Yi (0x3200 - 0xA4CF)
- uset_addRange(smartSet, 0xAC00, 0xAC00 + 11183); // Hangul Syllables (0xAC00 - 0xD7AF)
- uset_addRange(smartSet, 0xF900, 0xF900 + 352); // CJK Compatibility Ideographs (0xF900 - 0xFA5F)
- uset_addRange(smartSet, 0xFE30, 0xFE30 + 32); // CJK Compatibility From (0xFE30 - 0xFE4F)
- uset_addRange(smartSet, 0xFF00, 0xFF00 + 240); // Half/Full Width Form (0xFF00 - 0xFFEF)
- uset_addRange(smartSet, 0x20000, 0x20000 + 0xA6D7); // CJK Ideograph Exntension B
- uset_addRange(smartSet, 0x2F800, 0x2F800 + 0x021E); // CJK Compatibility Ideographs (0x2F800 - 0x2FA1D)
-
- if (isPreviousCharacter) {
- addAllCodePoints(smartSet, "([\"\'#$/-`{");
- preSmartSet = smartSet;
- } else {
- addAllCodePoints(smartSet, ")].,;:?\'!\"%*-/}");
-
- // Punctuation (kCFCharacterSetPunctuation)
- UErrorCode ec = U_ZERO_ERROR;
- String punctuationClass = "[:P:]";
- USet* icuPunct = uset_openPattern(punctuationClass.characters(), punctuationClass.length(), &ec);
- ASSERT(U_SUCCESS(ec));
- uset_addAll(smartSet, icuPunct);
- uset_close(icuPunct);
-
- postSmartSet = smartSet;
- }
- }
- return smartSet;
-}
-
-bool isCharacterSmartReplaceExempt(UChar32 c, bool isPreviousCharacter)
-{
- return uset_contains(getSmartSet(isPreviousCharacter), c);
-}
-
-}
-
-#endif // !PLATFORM(CF) && USE(ICU_UNICODE)
diff --git a/WebCore/editing/SplitElementCommand.cpp b/WebCore/editing/SplitElementCommand.cpp
deleted file mode 100644
index b056fee..0000000
--- a/WebCore/editing/SplitElementCommand.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SplitElementCommand.h"
-
-#include "Element.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-SplitElementCommand::SplitElementCommand(PassRefPtr<Element> element, PassRefPtr<Node> atChild)
- : SimpleEditCommand(element->document()), m_element2(element), m_atChild(atChild)
-{
- ASSERT(m_element2);
- ASSERT(m_atChild);
-}
-
-void SplitElementCommand::doApply()
-{
- ASSERT(m_element2);
- ASSERT(m_atChild);
- ASSERT(m_atChild->parentNode() == m_element2);
-
- ExceptionCode ec = 0;
-
- if (!m_element1) {
- // create only if needed.
- // if reapplying, this object will already exist.
- m_element1 = static_pointer_cast<Element>(m_element2->cloneNode(false));
- ASSERT(m_element1);
- }
-
- m_element2->parent()->insertBefore(m_element1.get(), m_element2.get(), ec);
- ASSERT(ec == 0);
-
- // Bail if we were asked to split at a bogus child, to avoid hanging below.
- if (!m_atChild || m_atChild->parentNode() != m_element2)
- return;
-
- while (m_element2->firstChild() != m_atChild) {
- ASSERT(m_element2->firstChild());
- m_element1->appendChild(m_element2->firstChild(), ec);
- ASSERT(ec == 0);
- }
-}
-
-void SplitElementCommand::doUnapply()
-{
- ASSERT(m_element1);
- ASSERT(m_element2);
- ASSERT(m_atChild);
-
- ASSERT(m_element1->nextSibling() == m_element2);
- ASSERT(m_element2->firstChild() && m_element2->firstChild() == m_atChild);
-
- ExceptionCode ec = 0;
-
- while (m_element1->lastChild()) {
- m_element2->insertBefore(m_element1->lastChild(), m_element2->firstChild(), ec);
- ASSERT(ec == 0);
- }
-
- m_element2->parentNode()->removeChild(m_element1.get(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/SplitElementCommand.h b/WebCore/editing/SplitElementCommand.h
deleted file mode 100644
index 2732762..0000000
--- a/WebCore/editing/SplitElementCommand.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SplitElementCommand_h
-#define SplitElementCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class SplitElementCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<SplitElementCommand> create(PassRefPtr<Element> element, PassRefPtr<Node> splitPointChild)
- {
- return adoptRef(new SplitElementCommand(element, splitPointChild));
- }
-
-private:
- SplitElementCommand(PassRefPtr<Element>, PassRefPtr<Node> splitPointChild);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Element> m_element1;
- RefPtr<Element> m_element2;
- RefPtr<Node> m_atChild;
-};
-
-} // namespace WebCore
-
-#endif // SplitElementCommand_h
diff --git a/WebCore/editing/SplitTextNodeCommand.cpp b/WebCore/editing/SplitTextNodeCommand.cpp
deleted file mode 100644
index be6cd1d..0000000
--- a/WebCore/editing/SplitTextNodeCommand.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SplitTextNodeCommand.h"
-
-#include "Document.h"
-#include "Text.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-SplitTextNodeCommand::SplitTextNodeCommand(PassRefPtr<Text> text, int offset)
- : SimpleEditCommand(text->document()), m_text2(text), m_offset(offset)
-{
- ASSERT(m_text2);
- ASSERT(m_text2->length() > 0);
-}
-
-void SplitTextNodeCommand::doApply()
-{
- ASSERT(m_text2);
- ASSERT(m_offset > 0);
-
- ExceptionCode ec = 0;
-
- // NOTE: Various callers rely on the fact that the original node becomes
- // the second node (i.e. the new node is inserted before the existing one).
- // That is not a fundamental dependency (i.e. it could be re-coded), but
- // rather is based on how this code happens to work.
- if (!m_text1) {
- // create only if needed.
- // if reapplying, this object will already exist.
- m_text1 = document()->createTextNode(m_text2->substringData(0, m_offset, ec));
- ASSERT(ec == 0);
- ASSERT(m_text1);
- }
-
- document()->copyMarkers(m_text2.get(), 0, m_offset, m_text1.get(), 0);
- m_text2->deleteData(0, m_offset, ec);
- ASSERT(ec == 0);
-
- m_text2->parentNode()->insertBefore(m_text1.get(), m_text2.get(), ec);
- ASSERT(ec == 0);
-
- ASSERT(m_text2->previousSibling()->isTextNode());
- ASSERT(m_text2->previousSibling() == m_text1);
-}
-
-void SplitTextNodeCommand::doUnapply()
-{
- ASSERT(m_text1);
- ASSERT(m_text2);
- ASSERT(m_text1->nextSibling() == m_text2);
-
- ExceptionCode ec = 0;
- m_text2->insertData(0, m_text1->data(), ec);
- ASSERT(ec == 0);
-
- document()->copyMarkers(m_text1.get(), 0, m_offset, m_text2.get(), 0);
-
- m_text2->parentNode()->removeChild(m_text1.get(), ec);
- ASSERT(ec == 0);
-
- m_offset = m_text1->length();
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/SplitTextNodeCommand.h b/WebCore/editing/SplitTextNodeCommand.h
deleted file mode 100644
index 48d444c..0000000
--- a/WebCore/editing/SplitTextNodeCommand.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SplitTextNodeCommand_h
-#define SplitTextNodeCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class Text;
-
-class SplitTextNodeCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<SplitTextNodeCommand> create(PassRefPtr<Text> node, int offset)
- {
- return adoptRef(new SplitTextNodeCommand(node, offset));
- }
-
-private:
- SplitTextNodeCommand(PassRefPtr<Text>, int offset);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Text> m_text1;
- RefPtr<Text> m_text2;
- unsigned m_offset;
-};
-
-} // namespace WebCore
-
-#endif // SplitTextNodeCommand_h
diff --git a/WebCore/editing/SplitTextNodeContainingElementCommand.cpp b/WebCore/editing/SplitTextNodeContainingElementCommand.cpp
deleted file mode 100644
index 7038a17..0000000
--- a/WebCore/editing/SplitTextNodeContainingElementCommand.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SplitTextNodeContainingElementCommand.h"
-
-#include "Element.h"
-#include "Text.h"
-#include "RenderObject.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-SplitTextNodeContainingElementCommand::SplitTextNodeContainingElementCommand(PassRefPtr<Text> text, int offset)
- : CompositeEditCommand(text->document()), m_text(text), m_offset(offset)
-{
- ASSERT(m_text);
- ASSERT(m_text->length() > 0);
-}
-
-void SplitTextNodeContainingElementCommand::doApply()
-{
- ASSERT(m_text);
- ASSERT(m_offset > 0);
-
- splitTextNode(m_text.get(), m_offset);
-
- Node *parentNode = m_text->parentNode();
- if (!parentNode->renderer() || !parentNode->renderer()->isInline()) {
- wrapContentsInDummySpan(static_cast<Element *>(parentNode));
- parentNode = parentNode->firstChild();
- }
-
- splitElement(static_cast<Element *>(parentNode), m_text.get());
-}
-
-}
diff --git a/WebCore/editing/SplitTextNodeContainingElementCommand.h b/WebCore/editing/SplitTextNodeContainingElementCommand.h
deleted file mode 100644
index 4e6af4f..0000000
--- a/WebCore/editing/SplitTextNodeContainingElementCommand.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef SplitTextNodeContainingElementCommand_h
-#define SplitTextNodeContainingElementCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class SplitTextNodeContainingElementCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<SplitTextNodeContainingElementCommand> create(PassRefPtr<Text> node, int offset)
- {
- return adoptRef(new SplitTextNodeContainingElementCommand(node, offset));
- }
-
-private:
- SplitTextNodeContainingElementCommand(PassRefPtr<Text>, int offset);
-
- virtual void doApply();
-
- RefPtr<Text> m_text;
- int m_offset;
-};
-
-} // namespace WebCore
-
-#endif // SplitTextNodeContainingElementCommand_h
diff --git a/WebCore/editing/TextAffinity.h b/WebCore/editing/TextAffinity.h
deleted file mode 100644
index 5562cc4..0000000
--- a/WebCore/editing/TextAffinity.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TextAffinity_h
-#define TextAffinity_h
-
-#include <wtf/Platform.h>
-
-#ifdef __OBJC__
-#include <AppKit/NSTextView.h>
-#endif
-
-namespace WebCore {
-
-// These match the AppKit values for these concepts.
-// From NSTextView.h:
-// NSSelectionAffinityUpstream = 0
-// NSSelectionAffinityDownstream = 1
-typedef enum { UPSTREAM = 0, DOWNSTREAM = 1 } EAffinity;
-
-#ifdef __OBJC__
-inline NSSelectionAffinity kit(EAffinity affinity)
-{
- return static_cast<NSSelectionAffinity>(affinity);
-}
-
-inline EAffinity core(NSSelectionAffinity affinity)
-{
- return static_cast<EAffinity>(affinity);
-}
-#endif
-
-} // namespace WebCore
-
-#endif // TextAffinity_h
diff --git a/WebCore/editing/TextGranularity.h b/WebCore/editing/TextGranularity.h
deleted file mode 100644
index 09cc4ed..0000000
--- a/WebCore/editing/TextGranularity.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TextGranularity_h
-#define TextGranularity_h
-
-namespace WebCore {
-
-// FIXME: This really should be broken up into more than one concept.
-// Frame doesn't need the 3 boundaries in this enum.
-enum TextGranularity {
- CharacterGranularity,
- WordGranularity,
- SentenceGranularity,
- LineGranularity,
- ParagraphGranularity,
- SentenceBoundary,
- LineBoundary,
- ParagraphBoundary,
- DocumentBoundary
-};
-
-}
-
-#endif
diff --git a/WebCore/editing/TextIterator.cpp b/WebCore/editing/TextIterator.cpp
deleted file mode 100644
index 093e851..0000000
--- a/WebCore/editing/TextIterator.cpp
+++ /dev/null
@@ -1,1445 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2005 Alexey Proskuryakov.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextIterator.h"
-
-#include "CharacterNames.h"
-#include "Document.h"
-#include "Element.h"
-#include "HTMLNames.h"
-#include "htmlediting.h"
-#include "InlineTextBox.h"
-#include "Position.h"
-#include "Range.h"
-#include "RenderTableCell.h"
-#include "RenderTableRow.h"
-#include "RenderTextControl.h"
-#include "visible_units.h"
-
-using namespace std;
-using namespace WTF::Unicode;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-// Buffer that knows how to compare with a search target.
-// Keeps enough of the previous text to be able to search in the future, but no more.
-class CircularSearchBuffer : Noncopyable {
-public:
- CircularSearchBuffer(const String& target, bool isCaseSensitive);
-
- void clear() { m_cursor = 0; m_isBufferFull = false; }
- void append(UChar);
-
- bool isMatch() const;
- unsigned length() const;
-
-private:
- void append(UChar, bool isCharacterStart);
-
- String m_target;
- bool m_isCaseSensitive;
-
- Vector<UChar> m_characterBuffer;
- Vector<bool> m_isCharacterStartBuffer;
- bool m_isBufferFull;
- unsigned m_cursor;
-};
-
-// --------
-
-TextIterator::TextIterator()
- : m_startContainer(0)
- , m_startOffset(0)
- , m_endContainer(0)
- , m_endOffset(0)
- , m_positionNode(0)
- , m_lastCharacter(0)
- , m_emitCharactersBetweenAllVisiblePositions(false)
- , m_enterTextControls(false)
-{
-}
-
-TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
- : m_inShadowContent(false)
- , m_startContainer(0)
- , m_startOffset(0)
- , m_endContainer(0)
- , m_endOffset(0)
- , m_positionNode(0)
- , m_emitCharactersBetweenAllVisiblePositions(emitCharactersBetweenAllVisiblePositions)
- , m_enterTextControls(enterTextControls)
-{
- if (!r)
- return;
-
- ExceptionCode ec = 0;
-
- // get and validate the range endpoints
- Node *startContainer = r->startContainer(ec);
- int startOffset = r->startOffset(ec);
- Node *endContainer = r->endContainer(ec);
- int endOffset = r->endOffset(ec);
- if (ec)
- return;
-
- // Callers should be handing us well-formed ranges. If we discover that this isn't
- // the case, we could consider changing this assertion to an early return.
- ASSERT(r->boundaryPointsValid());
-
- // remember range - this does not change
- m_startContainer = startContainer;
- m_startOffset = startOffset;
- m_endContainer = endContainer;
- m_endOffset = endOffset;
-
- for (Node* n = startContainer; n; n = n->parentNode()) {
- if (n->isShadowNode()) {
- m_inShadowContent = true;
- break;
- }
- }
-
- // set up the current node for processing
- m_node = r->firstNode();
- if (m_node == 0)
- return;
- m_offset = m_node == m_startContainer ? m_startOffset : 0;
- m_handledNode = false;
- m_handledChildren = false;
-
- // calculate first out of bounds node
- m_pastEndNode = r->pastLastNode();
-
- // initialize node processing state
- m_needAnotherNewline = false;
- m_textBox = 0;
-
- // initialize record of previous node processing
- m_haveEmitted = false;
- m_lastTextNode = 0;
- m_lastTextNodeEndedWithCollapsedSpace = false;
- m_lastCharacter = 0;
-
-#ifndef NDEBUG
- // need this just because of the assert in advance()
- m_positionNode = m_node;
-#endif
-
- // identify the first run
- advance();
-}
-
-void TextIterator::advance()
-{
- // reset the run information
- m_positionNode = 0;
- m_textLength = 0;
-
- // handle remembered node that needed a newline after the text node's newline
- if (m_needAnotherNewline) {
- // Emit the extra newline, and position it *inside* m_node, after m_node's
- // contents, in case it's a block, in the same way that we position the first
- // newline. The range for the emitted newline should start where the line
- // break begins.
- // FIXME: It would be cleaner if we emitted two newlines during the last
- // iteration, instead of using m_needAnotherNewline.
- Node* baseNode = m_node->lastChild() ? m_node->lastChild() : m_node;
- emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
- m_needAnotherNewline = false;
- return;
- }
-
- // handle remembered text box
- if (m_textBox) {
- handleTextBox();
- if (m_positionNode)
- return;
- }
-
- while (m_node && m_node != m_pastEndNode) {
- // if the range ends at offset 0 of an element, represent the
- // position, but not the content, of that element e.g. if the
- // node is a blockflow element, emit a newline that
- // precedes the element
- if (m_node == m_endContainer && m_endOffset == 0) {
- representNodeOffsetZero();
- m_node = 0;
- return;
- }
-
- RenderObject *renderer = m_node->renderer();
- if (!renderer) {
- m_handledNode = true;
- m_handledChildren = true;
- } else {
- // handle current node according to its type
- if (!m_handledNode) {
- if (renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) // FIXME: What about CDATA_SECTION_NODE?
- m_handledNode = handleTextNode();
- else if (renderer && (renderer->isImage() || renderer->isWidget() || (renderer->element() && renderer->element()->isControl())))
- m_handledNode = handleReplacedElement();
- else
- m_handledNode = handleNonTextNode();
- if (m_positionNode)
- return;
- }
- }
-
- // find a new current node to handle in depth-first manner,
- // calling exitNode() as we come back thru a parent node
- Node *next = m_handledChildren ? 0 : m_node->firstChild();
- m_offset = 0;
- if (!next) {
- next = m_node->nextSibling();
- if (!next) {
- bool pastEnd = m_node->traverseNextNode() == m_pastEndNode;
- Node* parentNode = m_node->parentNode();
- if (!parentNode && m_inShadowContent) {
- m_inShadowContent = false;
- parentNode = m_node->shadowParentNode();
- }
- while (!next && parentNode) {
- if (pastEnd && parentNode == m_endContainer || m_endContainer->isDescendantOf(parentNode))
- return;
- bool haveRenderer = m_node->renderer();
- m_node = parentNode;
- parentNode = m_node->parentNode();
- if (!parentNode && m_inShadowContent) {
- m_inShadowContent = false;
- parentNode = m_node->shadowParentNode();
- }
- if (haveRenderer)
- exitNode();
- if (m_positionNode) {
- m_handledNode = true;
- m_handledChildren = true;
- return;
- }
- next = m_node->nextSibling();
- }
- }
- }
-
- // set the new current node
- m_node = next;
- m_handledNode = false;
- m_handledChildren = false;
-
- // how would this ever be?
- if (m_positionNode)
- return;
- }
-}
-
-static inline bool compareBoxStart(const InlineTextBox *first, const InlineTextBox *second)
-{
- return first->start() < second->start();
-}
-
-bool TextIterator::handleTextNode()
-{
- RenderText* renderer = static_cast<RenderText*>(m_node->renderer());
- if (renderer->style()->visibility() != VISIBLE)
- return false;
-
- m_lastTextNode = m_node;
- String str = renderer->text();
-
- // handle pre-formatted text
- if (!renderer->style()->collapseWhiteSpace()) {
- int runStart = m_offset;
- if (m_lastTextNodeEndedWithCollapsedSpace) {
- emitCharacter(' ', m_node, 0, runStart, runStart);
- return false;
- }
- int strLength = str.length();
- int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
- int runEnd = min(strLength, end);
-
- if (runStart >= runEnd)
- return true;
-
- emitText(m_node, runStart, runEnd);
- return true;
- }
-
- if (!renderer->firstTextBox() && str.length() > 0) {
- m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space
- return true;
- }
-
- // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
- if (renderer->containsReversedText()) {
- m_sortedTextBoxes.clear();
- for (InlineTextBox * textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
- m_sortedTextBoxes.append(textBox);
- }
- std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), compareBoxStart);
- m_sortedTextBoxesPosition = 0;
- }
-
- m_textBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
- handleTextBox();
- return true;
-}
-
-void TextIterator::handleTextBox()
-{
- RenderText *renderer = static_cast<RenderText *>(m_node->renderer());
- String str = renderer->text();
- int start = m_offset;
- int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
- while (m_textBox) {
- int textBoxStart = m_textBox->m_start;
- int runStart = max(textBoxStart, start);
-
- // Check for collapsed space at the start of this run.
- InlineTextBox *firstTextBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
- bool needSpace = m_lastTextNodeEndedWithCollapsedSpace
- || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0);
- if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter) {
- emitCharacter(' ', m_node, 0, runStart, runStart);
- return;
- }
- int textBoxEnd = textBoxStart + m_textBox->m_len;
- int runEnd = min(textBoxEnd, end);
-
- // Determine what the next text box will be, but don't advance yet
- InlineTextBox *nextTextBox = 0;
- if (renderer->containsReversedText()) {
- if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size())
- nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1];
- } else
- nextTextBox = m_textBox->nextTextBox();
-
- if (runStart < runEnd) {
- // Handle either a single newline character (which becomes a space),
- // or a run of characters that does not include a newline.
- // This effectively translates newlines to spaces without copying the text.
- if (str[runStart] == '\n') {
- emitCharacter(' ', m_node, 0, runStart, runStart + 1);
- m_offset = runStart + 1;
- } else {
- int subrunEnd = str.find('\n', runStart);
- if (subrunEnd == -1 || subrunEnd > runEnd)
- subrunEnd = runEnd;
-
- m_offset = subrunEnd;
- emitText(m_node, runStart, subrunEnd);
- }
-
- // If we are doing a subrun that doesn't go to the end of the text box,
- // come back again to finish handling this text box; don't advance to the next one.
- if (m_positionEndOffset < textBoxEnd)
- return;
-
- // Advance and return
- int nextRunStart = nextTextBox ? nextTextBox->m_start : str.length();
- if (nextRunStart > runEnd)
- m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end
- m_textBox = nextTextBox;
- if (renderer->containsReversedText())
- ++m_sortedTextBoxesPosition;
- return;
- }
- // Advance and continue
- m_textBox = nextTextBox;
- if (renderer->containsReversedText())
- ++m_sortedTextBoxesPosition;
- }
-}
-
-bool TextIterator::handleReplacedElement()
-{
- RenderObject* renderer = m_node->renderer();
- if (renderer->style()->visibility() != VISIBLE)
- return false;
-
- if (m_lastTextNodeEndedWithCollapsedSpace) {
- emitCharacter(' ', m_lastTextNode->parentNode(), m_lastTextNode, 1, 1);
- return false;
- }
-
- if (m_enterTextControls && (renderer->isTextArea() || renderer->isTextField())) {
- m_node = static_cast<RenderTextControl*>(renderer)->innerTextElement();
- m_offset = 0;
- m_inShadowContent = true;
- return false;
- }
-
- m_haveEmitted = true;
-
- if (m_emitCharactersBetweenAllVisiblePositions) {
- // We want replaced elements to behave like punctuation for boundary
- // finding, and to simply take up space for the selection preservation
- // code in moveParagraphs, so we use a comma.
- emitCharacter(',', m_node->parentNode(), m_node, 0, 1);
- return true;
- }
-
- m_positionNode = m_node->parentNode();
- m_positionOffsetBaseNode = m_node;
- m_positionStartOffset = 0;
- m_positionEndOffset = 1;
-
- m_textCharacters = 0;
- m_textLength = 0;
-
- m_lastCharacter = 0;
-
- return true;
-}
-
-static bool shouldEmitTabBeforeNode(Node* node)
-{
- RenderObject* r = node->renderer();
-
- // Table cells are delimited by tabs.
- if (!r || !isTableCell(node))
- return false;
-
- // Want a tab before every cell other than the first one
- RenderTableCell* rc = static_cast<RenderTableCell*>(r);
- RenderTable* t = rc->table();
- return t && (t->cellBefore(rc) || t->cellAbove(rc));
-}
-
-static bool shouldEmitNewlineForNode(Node* node)
-{
- // br elements are represented by a single newline.
- RenderObject* r = node->renderer();
- if (!r)
- return node->hasTagName(brTag);
-
- return r->isBR();
-}
-
-static bool shouldEmitNewlinesBeforeAndAfterNode(Node* node)
-{
- // Block flow (versus inline flow) is represented by having
- // a newline both before and after the element.
- RenderObject* r = node->renderer();
- if (!r) {
- return (node->hasTagName(blockquoteTag)
- || node->hasTagName(ddTag)
- || node->hasTagName(divTag)
- || node->hasTagName(dlTag)
- || node->hasTagName(dtTag)
- || node->hasTagName(h1Tag)
- || node->hasTagName(h2Tag)
- || node->hasTagName(h3Tag)
- || node->hasTagName(h4Tag)
- || node->hasTagName(h5Tag)
- || node->hasTagName(h6Tag)
- || node->hasTagName(hrTag)
- || node->hasTagName(liTag)
- || node->hasTagName(listingTag)
- || node->hasTagName(olTag)
- || node->hasTagName(pTag)
- || node->hasTagName(preTag)
- || node->hasTagName(trTag)
- || node->hasTagName(ulTag));
- }
-
- // Need to make an exception for table cells, because they are blocks, but we
- // want them tab-delimited rather than having newlines before and after.
- if (isTableCell(node))
- return false;
-
- // Need to make an exception for table row elements, because they are neither
- // "inline" or "RenderBlock", but we want newlines for them.
- if (r->isTableRow()) {
- RenderTable* t = static_cast<RenderTableRow*>(r)->table();
- if (t && !t->isInline())
- return true;
- }
-
- return !r->isInline() && r->isRenderBlock() && !r->isFloatingOrPositioned() && !r->isBody();
-}
-
-static bool shouldEmitNewlineAfterNode(Node* node)
-{
- // FIXME: It should be better but slower to create a VisiblePosition here.
- if (!shouldEmitNewlinesBeforeAndAfterNode(node))
- return false;
- // Check if this is the very last renderer in the document.
- // If so, then we should not emit a newline.
- while ((node = node->traverseNextSibling()))
- if (node->renderer())
- return true;
- return false;
-}
-
-static bool shouldEmitNewlineBeforeNode(Node* node)
-{
- return shouldEmitNewlinesBeforeAndAfterNode(node);
-}
-
-static bool shouldEmitExtraNewlineForNode(Node* node)
-{
- // When there is a significant collapsed bottom margin, emit an extra
- // newline for a more realistic result. We end up getting the right
- // result even without margin collapsing. For example: <div><p>text</p></div>
- // will work right even if both the <div> and the <p> have bottom margins.
- RenderObject* r = node->renderer();
- if (!r)
- return false;
-
- // NOTE: We only do this for a select set of nodes, and fwiw WinIE appears
- // not to do this at all
- if (node->hasTagName(h1Tag)
- || node->hasTagName(h2Tag)
- || node->hasTagName(h3Tag)
- || node->hasTagName(h4Tag)
- || node->hasTagName(h5Tag)
- || node->hasTagName(h6Tag)
- || node->hasTagName(pTag)) {
- RenderStyle* style = r->style();
- if (style) {
- int bottomMargin = r->collapsedMarginBottom();
- int fontSize = style->fontDescription().computedPixelSize();
- if (bottomMargin * 2 >= fontSize)
- return true;
- }
- }
-
- return false;
-}
-
-bool TextIterator::shouldRepresentNodeOffsetZero()
-{
- if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isTable())
- return true;
-
- // Leave element positioned flush with start of a paragraph
- // (e.g. do not insert tab before a table cell at the start of a paragraph)
- if (m_lastCharacter == '\n')
- return false;
-
- // Otherwise, show the position if we have emitted any characters
- if (m_haveEmitted)
- return true;
-
- // We've not emitted anything yet. Generally, there is no need for any positioning then.
- // The only exception is when the element is visually not in the same line as
- // the start of the range (e.g. the range starts at the end of the previous paragraph).
- // NOTE: Creating VisiblePositions and comparing them is relatively expensive, so we
- // make quicker checks to possibly avoid that. Another check that we could make is
- // is whether the inline vs block flow changed since the previous visible element.
- // I think we're already in a special enough case that that won't be needed, tho.
-
- // If we are at the start, obviously no newline is needed.
- if (m_node == m_startContainer)
- return false;
-
- // If we are outside the start container's subtree, assume we need a newline.
- // FIXME: m_startContainer could be an inline block
- if (!m_node->isDescendantOf(m_startContainer))
- return true;
-
- // If we started as m_startContainer offset 0 and the current node is a descendant of
- // the start container, we already had enough context to correctly decide whether to
- // emit a newline after a preceding block. We chose not to emit (m_haveEmitted is false),
- // so don't second guess that now.
- // NOTE: Is this really correct when m_node is not a leftmost descendant? Probably
- // immaterial since we likely would have already emitted something by now.
- if (m_startOffset == 0)
- return false;
-
- // The currPos.isNotNull() check is needed because positions in non-html content
- // (like svg) do not have visible positions, and we don't want to emit for them either.
- VisiblePosition startPos = VisiblePosition(m_startContainer, m_startOffset, DOWNSTREAM);
- VisiblePosition currPos = VisiblePosition(m_node, 0, DOWNSTREAM);
- return currPos.isNotNull() && !inSameLine(startPos, currPos);
-}
-
-bool TextIterator::shouldEmitSpaceBeforeAndAfterNode(Node* node)
-{
- return node->renderer() && node->renderer()->isTable() && (node->renderer()->isInline() || m_emitCharactersBetweenAllVisiblePositions);
-}
-
-void TextIterator::representNodeOffsetZero()
-{
- // Emit a character to show the positioning of m_node.
-
- // When we haven't been emitting any characters, shouldRepresentNodeOffsetZero() can
- // create VisiblePositions, which is expensive. So, we perform the inexpensive checks
- // on m_node to see if it necessitates emitting a character first and will early return
- // before encountering shouldRepresentNodeOffsetZero()s worse case behavior.
- if (shouldEmitTabBeforeNode(m_node)) {
- if (shouldRepresentNodeOffsetZero())
- emitCharacter('\t', m_node->parentNode(), m_node, 0, 0);
- } else if (shouldEmitNewlineBeforeNode(m_node)) {
- if (shouldRepresentNodeOffsetZero())
- emitCharacter('\n', m_node->parentNode(), m_node, 0, 0);
- } else if (shouldEmitSpaceBeforeAndAfterNode(m_node)) {
- if (shouldRepresentNodeOffsetZero())
- emitCharacter(' ', m_node->parentNode(), m_node, 0, 0);
- }
-}
-
-bool TextIterator::handleNonTextNode()
-{
- if (shouldEmitNewlineForNode(m_node))
- emitCharacter('\n', m_node->parentNode(), m_node, 0, 1);
- else if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isHR())
- emitCharacter(' ', m_node->parentNode(), m_node, 0, 1);
- else
- representNodeOffsetZero();
-
- return true;
-}
-
-void TextIterator::exitNode()
-{
- // prevent emitting a newline when exiting a collapsed block at beginning of the range
- // FIXME: !m_haveEmitted does not necessarily mean there was a collapsed block... it could
- // have been an hr (e.g.). Also, a collapsed block could have height (e.g. a table) and
- // therefore look like a blank line.
- if (!m_haveEmitted)
- return;
-
- // Emit with a position *inside* m_node, after m_node's contents, in
- // case it is a block, because the run should start where the
- // emitted character is positioned visually.
- Node* baseNode = m_node->lastChild() ? m_node->lastChild() : m_node;
- // FIXME: This shouldn't require the m_lastTextNode to be true, but we can't change that without making
- // the logic in _web_attributedStringFromRange match. We'll get that for free when we switch to use
- // TextIterator in _web_attributedStringFromRange.
- // See <rdar://problem/5428427> for an example of how this mismatch will cause problems.
- if (m_lastTextNode && shouldEmitNewlineAfterNode(m_node)) {
- // use extra newline to represent margin bottom, as needed
- bool addNewline = shouldEmitExtraNewlineForNode(m_node);
-
- // FIXME: We need to emit a '\n' as we leave an empty block(s) that
- // contain a VisiblePosition when doing selection preservation.
- if (m_lastCharacter != '\n') {
- // insert a newline with a position following this block's contents.
- emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
- // remember whether to later add a newline for the current node
- ASSERT(!m_needAnotherNewline);
- m_needAnotherNewline = addNewline;
- } else if (addNewline)
- // insert a newline with a position following this block's contents.
- emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);
- }
-
- // If nothing was emitted, see if we need to emit a space.
- if (!m_positionNode && shouldEmitSpaceBeforeAndAfterNode(m_node))
- emitCharacter(' ', baseNode->parentNode(), baseNode, 1, 1);
-}
-
-void TextIterator::emitCharacter(UChar c, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset)
-{
- m_haveEmitted = true;
-
- // remember information with which to construct the TextIterator::range()
- // NOTE: textNode is often not a text node, so the range will specify child nodes of positionNode
- m_positionNode = textNode;
- m_positionOffsetBaseNode = offsetBaseNode;
- m_positionStartOffset = textStartOffset;
- m_positionEndOffset = textEndOffset;
-
- // remember information with which to construct the TextIterator::characters() and length()
- m_singleCharacterBuffer = c;
- m_textCharacters = &m_singleCharacterBuffer;
- m_textLength = 1;
-
- // remember some iteration state
- m_lastTextNodeEndedWithCollapsedSpace = false;
- m_lastCharacter = c;
-}
-
-void TextIterator::emitText(Node *textNode, int textStartOffset, int textEndOffset)
-{
- RenderText* renderer = static_cast<RenderText*>(m_node->renderer());
- String str = renderer->text();
-
- m_positionNode = textNode;
- m_positionOffsetBaseNode = 0;
- m_positionStartOffset = textStartOffset;
- m_positionEndOffset = textEndOffset;
- m_textCharacters = str.characters() + textStartOffset;
- m_textLength = textEndOffset - textStartOffset;
- m_lastCharacter = str[textEndOffset - 1];
-
- m_lastTextNodeEndedWithCollapsedSpace = false;
- m_haveEmitted = true;
-}
-
-PassRefPtr<Range> TextIterator::range() const
-{
- // use the current run information, if we have it
- if (m_positionNode) {
- if (m_positionOffsetBaseNode) {
- int index = m_positionOffsetBaseNode->nodeIndex();
- m_positionStartOffset += index;
- m_positionEndOffset += index;
- m_positionOffsetBaseNode = 0;
- }
- return Range::create(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
- }
-
- // otherwise, return the end of the overall range we were given
- if (m_endContainer)
- return Range::create(m_endContainer->document(), m_endContainer, m_endOffset, m_endContainer, m_endOffset);
-
- return 0;
-}
-
-Node* TextIterator::node() const
-{
- RefPtr<Range> textRange = range();
- if (!textRange)
- return 0;
-
- Node* node = textRange->startContainer();
- if (!node)
- return 0;
- if (node->offsetInCharacters())
- return node;
-
- return node->childNode(textRange->startOffset());
-}
-
-// --------
-
-SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionNode(0)
-{
-}
-
-SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range *r)
-{
- m_positionNode = 0;
-
- if (!r)
- return;
-
- int exception = 0;
- Node *startNode = r->startContainer(exception);
- if (exception)
- return;
- Node *endNode = r->endContainer(exception);
- if (exception)
- return;
- int startOffset = r->startOffset(exception);
- if (exception)
- return;
- int endOffset = r->endOffset(exception);
- if (exception)
- return;
-
- if (!startNode->offsetInCharacters()) {
- if (startOffset >= 0 && startOffset < static_cast<int>(startNode->childNodeCount())) {
- startNode = startNode->childNode(startOffset);
- startOffset = 0;
- }
- }
- if (!endNode->offsetInCharacters()) {
- if (endOffset > 0 && endOffset <= static_cast<int>(endNode->childNodeCount())) {
- endNode = endNode->childNode(endOffset - 1);
- endOffset = endNode->offsetInCharacters() ? endNode->maxCharacterOffset() : endNode->childNodeCount();
- }
- }
-
- m_node = endNode;
- m_offset = endOffset;
- m_handledNode = false;
- m_handledChildren = endOffset == 0;
-
- m_startNode = startNode;
- m_startOffset = startOffset;
- m_endNode = endNode;
- m_endOffset = endOffset;
-
-#ifndef NDEBUG
- // Need this just because of the assert.
- m_positionNode = endNode;
-#endif
-
- m_lastTextNode = 0;
- m_lastCharacter = '\n';
-
- if (startOffset == 0 || !startNode->firstChild()) {
- m_pastStartNode = startNode->previousSibling();
- while (!m_pastStartNode && startNode->parentNode()) {
- startNode = startNode->parentNode();
- m_pastStartNode = startNode->previousSibling();
- }
- } else
- m_pastStartNode = startNode->childNode(startOffset - 1);
-
- advance();
-}
-
-void SimplifiedBackwardsTextIterator::advance()
-{
- ASSERT(m_positionNode);
-
- m_positionNode = 0;
- m_textLength = 0;
-
- while (m_node && m_node != m_pastStartNode) {
- // Don't handle node if we start iterating at [node, 0].
- if (!m_handledNode && !(m_node == m_endNode && m_endOffset == 0)) {
- RenderObject *renderer = m_node->renderer();
- if (renderer && renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) {
- // FIXME: What about CDATA_SECTION_NODE?
- if (renderer->style()->visibility() == VISIBLE && m_offset > 0)
- m_handledNode = handleTextNode();
- } else if (renderer && (renderer->isImage() || renderer->isWidget())) {
- if (renderer->style()->visibility() == VISIBLE && m_offset > 0)
- m_handledNode = handleReplacedElement();
- } else
- m_handledNode = handleNonTextNode();
- if (m_positionNode)
- return;
- }
-
- Node* next = m_handledChildren ? 0 : m_node->lastChild();
- if (!next) {
- // Exit empty containers as we pass over them or containers
- // where [container, 0] is where we started iterating.
- if (!m_handledNode &&
- canHaveChildrenForEditing(m_node) &&
- m_node->parentNode() &&
- (!m_node->lastChild() || m_node == m_endNode && m_endOffset == 0)) {
- exitNode();
- if (m_positionNode) {
- m_handledNode = true;
- m_handledChildren = true;
- return;
- }
- }
- // Exit all other containers.
- next = m_node->previousSibling();
- while (!next) {
- if (!m_node->parentNode())
- break;
- m_node = m_node->parentNode();
- exitNode();
- if (m_positionNode) {
- m_handledNode = true;
- m_handledChildren = true;
- return;
- }
- next = m_node->previousSibling();
- }
- }
-
- m_node = next;
- m_offset = m_node ? caretMaxOffset(m_node) : 0;
- m_handledNode = false;
- m_handledChildren = false;
-
- if (m_positionNode)
- return;
- }
-}
-
-bool SimplifiedBackwardsTextIterator::handleTextNode()
-{
- m_lastTextNode = m_node;
-
- RenderText *renderer = static_cast<RenderText *>(m_node->renderer());
- String str = renderer->text();
-
- if (!renderer->firstTextBox() && str.length() > 0)
- return true;
-
- m_positionEndOffset = m_offset;
-
- m_offset = (m_node == m_startNode) ? m_startOffset : 0;
- m_positionNode = m_node;
- m_positionStartOffset = m_offset;
- m_textLength = m_positionEndOffset - m_positionStartOffset;
- m_textCharacters = str.characters() + m_positionStartOffset;
-
- m_lastCharacter = str[m_positionEndOffset - 1];
-
- return true;
-}
-
-bool SimplifiedBackwardsTextIterator::handleReplacedElement()
-{
- unsigned index = m_node->nodeIndex();
- // We want replaced elements to behave like punctuation for boundary
- // finding, and to simply take up space for the selection preservation
- // code in moveParagraphs, so we use a comma. Unconditionally emit
- // here because this iterator is only used for boundary finding.
- emitCharacter(',', m_node->parentNode(), index, index + 1);
- return true;
-}
-
-bool SimplifiedBackwardsTextIterator::handleNonTextNode()
-{
- // We can use a linefeed in place of a tab because this simple iterator is only used to
- // find boundaries, not actual content. A linefeed breaks words, sentences, and paragraphs.
- if (shouldEmitNewlineForNode(m_node) ||
- shouldEmitNewlineAfterNode(m_node) ||
- shouldEmitTabBeforeNode(m_node)) {
- unsigned index = m_node->nodeIndex();
- // The start of this emitted range is wrong, ensuring correctness would require
- // VisiblePositions and so would be slow. previousBoundary expects this.
- emitCharacter('\n', m_node->parentNode(), index + 1, index + 1);
- }
-
- return true;
-}
-
-void SimplifiedBackwardsTextIterator::exitNode()
-{
- if (shouldEmitNewlineForNode(m_node) ||
- shouldEmitNewlineBeforeNode(m_node) ||
- shouldEmitTabBeforeNode(m_node))
- // The start of this emitted range is wrong, ensuring correctness would require
- // VisiblePositions and so would be slow. previousBoundary expects this.
- emitCharacter('\n', m_node, 0, 0);
-}
-
-void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, Node *node, int startOffset, int endOffset)
-{
- m_singleCharacterBuffer = c;
- m_positionNode = node;
- m_positionStartOffset = startOffset;
- m_positionEndOffset = endOffset;
- m_textCharacters = &m_singleCharacterBuffer;
- m_textLength = 1;
- m_lastCharacter = c;
-}
-
-PassRefPtr<Range> SimplifiedBackwardsTextIterator::range() const
-{
- if (m_positionNode)
- return Range::create(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
-
- return Range::create(m_startNode->document(), m_startNode, m_startOffset, m_startNode, m_startOffset);
-}
-
-// --------
-
-CharacterIterator::CharacterIterator()
- : m_offset(0)
- , m_runOffset(0)
- , m_atBreak(true)
-{
-}
-
-CharacterIterator::CharacterIterator(const Range *r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
- : m_offset(0)
- , m_runOffset(0)
- , m_atBreak(true)
- , m_textIterator(r, emitCharactersBetweenAllVisiblePositions, enterTextControls)
-{
- while (!atEnd() && m_textIterator.length() == 0)
- m_textIterator.advance();
-}
-
-PassRefPtr<Range> CharacterIterator::range() const
-{
- RefPtr<Range> r = m_textIterator.range();
- if (!m_textIterator.atEnd()) {
- if (m_textIterator.length() <= 1) {
- ASSERT(m_runOffset == 0);
- } else {
- int exception = 0;
- Node *n = r->startContainer(exception);
- ASSERT(n == r->endContainer(exception));
- int offset = r->startOffset(exception) + m_runOffset;
- r->setStart(n, offset, exception);
- r->setEnd(n, offset + 1, exception);
- }
- }
- return r.release();
-}
-
-void CharacterIterator::advance(int count)
-{
- if (count <= 0) {
- ASSERT(count == 0);
- return;
- }
-
- m_atBreak = false;
-
- // easy if there is enough left in the current m_textIterator run
- int remaining = m_textIterator.length() - m_runOffset;
- if (count < remaining) {
- m_runOffset += count;
- m_offset += count;
- return;
- }
-
- // exhaust the current m_textIterator run
- count -= remaining;
- m_offset += remaining;
-
- // move to a subsequent m_textIterator run
- for (m_textIterator.advance(); !atEnd(); m_textIterator.advance()) {
- int runLength = m_textIterator.length();
- if (runLength == 0)
- m_atBreak = true;
- else {
- // see whether this is m_textIterator to use
- if (count < runLength) {
- m_runOffset = count;
- m_offset += count;
- return;
- }
-
- // exhaust this m_textIterator run
- count -= runLength;
- m_offset += runLength;
- }
- }
-
- // ran to the end of the m_textIterator... no more runs left
- m_atBreak = true;
- m_runOffset = 0;
-}
-
-String CharacterIterator::string(int numChars)
-{
- Vector<UChar> result;
- result.reserveCapacity(numChars);
- while (numChars > 0 && !atEnd()) {
- int runSize = min(numChars, length());
- result.append(characters(), runSize);
- numChars -= runSize;
- advance(runSize);
- }
- return String::adopt(result);
-}
-
-// --------
-
-WordAwareIterator::WordAwareIterator()
-: m_previousText(0), m_didLookAhead(false)
-{
-}
-
-WordAwareIterator::WordAwareIterator(const Range *r)
-: m_previousText(0), m_didLookAhead(false), m_textIterator(r)
-{
- m_didLookAhead = true; // so we consider the first chunk from the text iterator
- advance(); // get in position over the first chunk of text
-}
-
-// We're always in one of these modes:
-// - The current chunk in the text iterator is our current chunk
-// (typically its a piece of whitespace, or text that ended with whitespace)
-// - The previous chunk in the text iterator is our current chunk
-// (we looked ahead to the next chunk and found a word boundary)
-// - We built up our own chunk of text from many chunks from the text iterator
-
-// FIXME: Perf could be bad for huge spans next to each other that don't fall on word boundaries
-
-void WordAwareIterator::advance()
-{
- m_previousText = 0;
- m_buffer.clear(); // toss any old buffer we built up
-
- // If last time we did a look-ahead, start with that looked-ahead chunk now
- if (!m_didLookAhead) {
- ASSERT(!m_textIterator.atEnd());
- m_textIterator.advance();
- }
- m_didLookAhead = false;
-
- // Go to next non-empty chunk
- while (!m_textIterator.atEnd() && m_textIterator.length() == 0)
- m_textIterator.advance();
- m_range = m_textIterator.range();
-
- if (m_textIterator.atEnd())
- return;
-
- while (1) {
- // If this chunk ends in whitespace we can just use it as our chunk.
- if (isSpaceOrNewline(m_textIterator.characters()[m_textIterator.length() - 1]))
- return;
-
- // If this is the first chunk that failed, save it in previousText before look ahead
- if (m_buffer.isEmpty()) {
- m_previousText = m_textIterator.characters();
- m_previousLength = m_textIterator.length();
- }
-
- // Look ahead to next chunk. If it is whitespace or a break, we can use the previous stuff
- m_textIterator.advance();
- if (m_textIterator.atEnd() || m_textIterator.length() == 0 || isSpaceOrNewline(m_textIterator.characters()[0])) {
- m_didLookAhead = true;
- return;
- }
-
- if (m_buffer.isEmpty()) {
- // Start gobbling chunks until we get to a suitable stopping point
- m_buffer.append(m_previousText, m_previousLength);
- m_previousText = 0;
- }
- m_buffer.append(m_textIterator.characters(), m_textIterator.length());
- int exception = 0;
- m_range->setEnd(m_textIterator.range()->endContainer(exception), m_textIterator.range()->endOffset(exception), exception);
- }
-}
-
-int WordAwareIterator::length() const
-{
- if (!m_buffer.isEmpty())
- return m_buffer.size();
- if (m_previousText)
- return m_previousLength;
- return m_textIterator.length();
-}
-
-const UChar* WordAwareIterator::characters() const
-{
- if (!m_buffer.isEmpty())
- return m_buffer.data();
- if (m_previousText)
- return m_previousText;
- return m_textIterator.characters();
-}
-
-// --------
-
-CircularSearchBuffer::CircularSearchBuffer(const String& s, bool isCaseSensitive)
- : m_target(isCaseSensitive ? s : s.foldCase())
- , m_isCaseSensitive(isCaseSensitive)
- , m_characterBuffer(m_target.length())
- , m_isCharacterStartBuffer(m_target.length())
- , m_isBufferFull(false)
- , m_cursor(0)
-{
- ASSERT(!m_target.isEmpty());
- m_target.replace(noBreakSpace, ' ');
-}
-
-inline void CircularSearchBuffer::append(UChar c, bool isStart)
-{
- m_characterBuffer[m_cursor] = c == noBreakSpace ? ' ' : c;
- m_isCharacterStartBuffer[m_cursor] = isStart;
- if (++m_cursor == m_target.length()) {
- m_cursor = 0;
- m_isBufferFull = true;
- }
-}
-
-inline void CircularSearchBuffer::append(UChar c)
-{
- if (m_isCaseSensitive) {
- append(c, true);
- return;
- }
- const int maxFoldedCharacters = 16; // sensible maximum is 3, this should be more than enough
- UChar foldedCharacters[maxFoldedCharacters];
- bool error;
- int numFoldedCharacters = foldCase(foldedCharacters, maxFoldedCharacters, &c, 1, &error);
- ASSERT(!error);
- ASSERT(numFoldedCharacters);
- ASSERT(numFoldedCharacters <= maxFoldedCharacters);
- if (!error && numFoldedCharacters) {
- numFoldedCharacters = min(numFoldedCharacters, maxFoldedCharacters);
- append(foldedCharacters[0], true);
- for (int i = 1; i < numFoldedCharacters; ++i)
- append(foldedCharacters[i], false);
- }
-}
-
-inline bool CircularSearchBuffer::isMatch() const
-{
- if (!m_isBufferFull)
- return false;
- if (!m_isCharacterStartBuffer[m_cursor])
- return false;
-
- unsigned tailSpace = m_target.length() - m_cursor;
- return memcmp(&m_characterBuffer[m_cursor], m_target.characters(), tailSpace * sizeof(UChar)) == 0
- && memcmp(&m_characterBuffer[0], m_target.characters() + tailSpace, m_cursor * sizeof(UChar)) == 0;
-}
-
-// Returns the number of characters that were appended to the buffer (what we are searching in).
-// That's not necessarily the same length as the passed-in target string, because case folding
-// can make two strings match even though they're not the same length.
-unsigned CircularSearchBuffer::length() const
-{
- ASSERT(isMatch());
-
- unsigned bufferSize = m_target.length();
- unsigned length = 0;
- for (unsigned i = 0; i < bufferSize; ++i)
- length += m_isCharacterStartBuffer[i];
- return length;
-}
-
-// --------
-
-int TextIterator::rangeLength(const Range *r, bool forSelectionPreservation)
-{
- int length = 0;
- for (TextIterator it(r, forSelectionPreservation); !it.atEnd(); it.advance())
- length += it.length();
-
- return length;
-}
-
-PassRefPtr<Range> TextIterator::subrange(Range* entireRange, int characterOffset, int characterCount)
-{
- CharacterIterator chars(entireRange);
-
- chars.advance(characterOffset);
- RefPtr<Range> start = chars.range();
-
- chars.advance(characterCount);
- RefPtr<Range> end = chars.range();
-
- ExceptionCode ec = 0;
- RefPtr<Range> result(Range::create(entireRange->ownerDocument(),
- start->startContainer(ec),
- start->startOffset(ec),
- end->startContainer(ec),
- end->startOffset(ec)));
- ASSERT(!ec);
-
- return result.release();
-}
-
-PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element *scope, int rangeLocation, int rangeLength, bool forSelectionPreservation)
-{
- RefPtr<Range> resultRange = scope->document()->createRange();
-
- int docTextPosition = 0;
- int rangeEnd = rangeLocation + rangeLength;
- bool startRangeFound = false;
-
- RefPtr<Range> textRunRange;
-
- TextIterator it(rangeOfContents(scope).get(), forSelectionPreservation);
-
- // FIXME: the atEnd() check shouldn't be necessary, workaround for <http://bugs.webkit.org/show_bug.cgi?id=6289>.
- if (rangeLocation == 0 && rangeLength == 0 && it.atEnd()) {
- int exception = 0;
- textRunRange = it.range();
-
- resultRange->setStart(textRunRange->startContainer(exception), 0, exception);
- ASSERT(exception == 0);
- resultRange->setEnd(textRunRange->startContainer(exception), 0, exception);
- ASSERT(exception == 0);
-
- return resultRange.release();
- }
-
- for (; !it.atEnd(); it.advance()) {
- int len = it.length();
- textRunRange = it.range();
-
- bool foundStart = rangeLocation >= docTextPosition && rangeLocation <= docTextPosition + len;
- bool foundEnd = rangeEnd >= docTextPosition && rangeEnd <= docTextPosition + len;
-
- // Fix textRunRange->endPosition(), but only if foundStart || foundEnd, because it is only
- // in those cases that textRunRange is used.
- if (foundStart || foundEnd) {
- // FIXME: This is a workaround for the fact that the end of a run is often at the wrong
- // position for emitted '\n's.
- if (len == 1 && it.characters()[0] == UChar('\n')) {
- Position runStart = textRunRange->startPosition();
- Position runEnd = VisiblePosition(runStart).next().deepEquivalent();
- if (runEnd.isNotNull()) {
- ExceptionCode ec = 0;
- textRunRange->setEnd(runEnd.node(), runEnd.offset(), ec);
- }
- }
- }
-
- if (foundStart) {
- startRangeFound = true;
- int exception = 0;
- if (textRunRange->startContainer(exception)->isTextNode()) {
- int offset = rangeLocation - docTextPosition;
- resultRange->setStart(textRunRange->startContainer(exception), offset + textRunRange->startOffset(exception), exception);
- } else {
- if (rangeLocation == docTextPosition)
- resultRange->setStart(textRunRange->startContainer(exception), textRunRange->startOffset(exception), exception);
- else
- resultRange->setStart(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
- }
- }
-
- if (foundEnd) {
- int exception = 0;
- if (textRunRange->startContainer(exception)->isTextNode()) {
- int offset = rangeEnd - docTextPosition;
- resultRange->setEnd(textRunRange->startContainer(exception), offset + textRunRange->startOffset(exception), exception);
- } else {
- if (rangeEnd == docTextPosition)
- resultRange->setEnd(textRunRange->startContainer(exception), textRunRange->startOffset(exception), exception);
- else
- resultRange->setEnd(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
- }
- docTextPosition += len;
- break;
- }
- docTextPosition += len;
- }
-
- if (!startRangeFound)
- return 0;
-
- if (rangeLength != 0 && rangeEnd > docTextPosition) { // rangeEnd is out of bounds
- int exception = 0;
- resultRange->setEnd(textRunRange->endContainer(exception), textRunRange->endOffset(exception), exception);
- }
-
- return resultRange.release();
-}
-
-// --------
-
-UChar* plainTextToMallocAllocatedBuffer(const Range* r, unsigned& bufferLength)
-{
- UChar* result = 0;
-
- // Do this in pieces to avoid massive reallocations if there is a large amount of text.
- // Use system malloc for buffers since they can consume lots of memory and current TCMalloc is unable return it back to OS.
- static const unsigned cMaxSegmentSize = 1 << 16;
- bufferLength = 0;
- typedef pair<UChar*, unsigned> TextSegment;
- Vector<TextSegment>* textSegments = 0;
- Vector<UChar> textBuffer;
- textBuffer.reserveCapacity(cMaxSegmentSize);
- for (TextIterator it(r); !it.atEnd(); it.advance()) {
- if (textBuffer.size() && textBuffer.size() + it.length() > cMaxSegmentSize) {
- UChar* newSegmentBuffer = static_cast<UChar*>(malloc(textBuffer.size() * sizeof(UChar)));
- if (!newSegmentBuffer)
- goto exit;
- memcpy(newSegmentBuffer, textBuffer.data(), textBuffer.size() * sizeof(UChar));
- if (!textSegments)
- textSegments = new Vector<TextSegment>;
- textSegments->append(make_pair(newSegmentBuffer, (unsigned)textBuffer.size()));
- textBuffer.clear();
- }
- textBuffer.append(it.characters(), it.length());
- bufferLength += it.length();
- }
-
- if (!bufferLength)
- return 0;
-
- // Since we know the size now, we can make a single buffer out of the pieces with one big alloc
- result = static_cast<UChar*>(malloc(bufferLength * sizeof(UChar)));
- if (!result)
- goto exit;
-
- {
- UChar* resultPos = result;
- if (textSegments) {
- unsigned size = textSegments->size();
- for (unsigned i = 0; i < size; ++i) {
- const TextSegment& segment = textSegments->at(i);
- memcpy(resultPos, segment.first, segment.second * sizeof(UChar));
- resultPos += segment.second;
- }
- }
- memcpy(resultPos, textBuffer.data(), textBuffer.size() * sizeof(UChar));
- }
-
-exit:
- if (textSegments) {
- unsigned size = textSegments->size();
- for (unsigned i = 0; i < size; ++i)
- free(textSegments->at(i).first);
- delete textSegments;
- }
- return result;
-}
-
-String plainText(const Range* r)
-{
- unsigned length;
- UChar* buf = plainTextToMallocAllocatedBuffer(r, length);
- if (!buf)
- return "";
- String result(buf, length);
- free(buf);
- return result;
-}
-
-PassRefPtr<Range> findPlainText(const Range* range, const String& target, bool forward, bool caseSensitive)
-{
- // FIXME: Can we do Boyer-Moore or equivalent instead for speed?
-
- ExceptionCode ec = 0;
- RefPtr<Range> result = range->cloneRange(ec);
- result->collapse(!forward, ec);
-
- // FIXME: This code does not allow \n at the moment because of issues with <br>.
- // Once we fix those, we can remove this check.
- if (target.isEmpty() || target.find('\n') != -1)
- return result.release();
-
- unsigned matchStart = 0;
- unsigned matchLength = 0;
- {
- CircularSearchBuffer searchBuffer(target, caseSensitive);
- CharacterIterator it(range, false, true);
- for (;;) {
- if (searchBuffer.isMatch()) {
- // Note that we found a match, and where we found it.
- unsigned matchEnd = it.characterOffset();
- matchLength = searchBuffer.length();
- ASSERT(matchLength);
- ASSERT(matchEnd >= matchLength);
- matchStart = matchEnd - matchLength;
- // If searching forward, stop on the first match.
- // If searching backward, don't stop, so we end up with the last match.
- if (forward)
- break;
- }
- if (it.atBreak()) {
- if (it.atEnd())
- break;
- searchBuffer.clear();
- }
- searchBuffer.append(it.characters()[0]);
- it.advance(1);
- }
- }
-
- if (matchLength) {
- CharacterIterator it(range, false, true);
- it.advance(matchStart);
- result->setStart(it.range()->startContainer(ec), it.range()->startOffset(ec), ec);
- it.advance(matchLength - 1);
- result->setEnd(it.range()->endContainer(ec), it.range()->endOffset(ec), ec);
- }
-
- return result.release();
-}
-
-}
diff --git a/WebCore/editing/TextIterator.h b/WebCore/editing/TextIterator.h
deleted file mode 100644
index 11a8354..0000000
--- a/WebCore/editing/TextIterator.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TextIterator_h
-#define TextIterator_h
-
-#include "InlineTextBox.h"
-#include "Range.h"
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-// FIXME: Can't really answer this question correctly without knowing the white-space mode.
-// FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
-inline bool isCollapsibleWhitespace(UChar c)
-{
- switch (c) {
- case ' ':
- case '\n':
- return true;
- default:
- return false;
- }
-}
-
-String plainText(const Range*);
-UChar* plainTextToMallocAllocatedBuffer(const Range*, unsigned& bufferLength);
-PassRefPtr<Range> findPlainText(const Range*, const String&, bool forward, bool caseSensitive);
-
-// Iterates through the DOM range, returning all the text, and 0-length boundaries
-// at points where replaced elements break up the text flow. The text comes back in
-// chunks so as to optimize for performance of the iteration.
-
-class TextIterator {
-public:
- TextIterator();
- explicit TextIterator(const Range*, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
-
- bool atEnd() const { return !m_positionNode; }
- void advance();
-
- int length() const { return m_textLength; }
- const UChar* characters() const { return m_textCharacters; }
-
- PassRefPtr<Range> range() const;
- Node* node() const;
-
- static int rangeLength(const Range*, bool spacesForReplacedElements = false);
- static PassRefPtr<Range> rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
- static PassRefPtr<Range> subrange(Range* entireRange, int characterOffset, int characterCount);
-
-private:
- void exitNode();
- bool shouldRepresentNodeOffsetZero();
- bool shouldEmitSpaceBeforeAndAfterNode(Node*);
- void representNodeOffsetZero();
- bool handleTextNode();
- bool handleReplacedElement();
- bool handleNonTextNode();
- void handleTextBox();
- void emitCharacter(UChar, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset);
- void emitText(Node *textNode, int textStartOffset, int textEndOffset);
-
- // Current position, not necessarily of the text being returned, but position
- // as we walk through the DOM tree.
- Node *m_node;
- int m_offset;
- bool m_handledNode;
- bool m_handledChildren;
- bool m_inShadowContent;
-
- // The range.
- Node *m_startContainer;
- int m_startOffset;
- Node *m_endContainer;
- int m_endOffset;
- Node *m_pastEndNode;
-
- // The current text and its position, in the form to be returned from the iterator.
- Node *m_positionNode;
- mutable Node *m_positionOffsetBaseNode;
- mutable int m_positionStartOffset;
- mutable int m_positionEndOffset;
- const UChar* m_textCharacters;
- int m_textLength;
-
- // Used when there is still some pending text from the current node; when these
- // are false and 0, we go back to normal iterating.
- bool m_needAnotherNewline;
- InlineTextBox *m_textBox;
-
- // Used to do the whitespace collapsing logic.
- Node *m_lastTextNode;
- bool m_lastTextNodeEndedWithCollapsedSpace;
- UChar m_lastCharacter;
-
- // Used for whitespace characters that aren't in the DOM, so we can point at them.
- UChar m_singleCharacterBuffer;
-
- // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
- Vector<InlineTextBox*> m_sortedTextBoxes;
- size_t m_sortedTextBoxesPosition;
-
- // Used when deciding whether to emit a "positioning" (e.g. newline) before any other content
- bool m_haveEmitted;
-
- // Used by selection preservation code. There should be one character emitted between every VisiblePosition
- // in the Range used to create the TextIterator.
- // FIXME <rdar://problem/6028818>: This functionality should eventually be phased out when we rewrite
- // moveParagraphs to not clone/destroy moved content.
- bool m_emitCharactersBetweenAllVisiblePositions;
- bool m_enterTextControls;
-};
-
-// Iterates through the DOM range, returning all the text, and 0-length boundaries
-// at points where replaced elements break up the text flow. The text comes back in
-// chunks so as to optimize for performance of the iteration.
-class SimplifiedBackwardsTextIterator {
-public:
- SimplifiedBackwardsTextIterator();
- explicit SimplifiedBackwardsTextIterator(const Range *);
-
- bool atEnd() const { return !m_positionNode; }
- void advance();
-
- int length() const { return m_textLength; }
- const UChar* characters() const { return m_textCharacters; }
-
- PassRefPtr<Range> range() const;
-
-private:
- void exitNode();
- bool handleTextNode();
- bool handleReplacedElement();
- bool handleNonTextNode();
- void emitCharacter(UChar, Node *Node, int startOffset, int endOffset);
-
- // Current position, not necessarily of the text being returned, but position
- // as we walk through the DOM tree.
- Node* m_node;
- int m_offset;
- bool m_handledNode;
- bool m_handledChildren;
-
- // End of the range.
- Node* m_startNode;
- int m_startOffset;
- // Start of the range.
- Node* m_endNode;
- int m_endOffset;
-
- // The current text and its position, in the form to be returned from the iterator.
- Node* m_positionNode;
- int m_positionStartOffset;
- int m_positionEndOffset;
- const UChar* m_textCharacters;
- int m_textLength;
-
- // Used to do the whitespace logic.
- Node* m_lastTextNode;
- UChar m_lastCharacter;
-
- // Used for whitespace characters that aren't in the DOM, so we can point at them.
- UChar m_singleCharacterBuffer;
-
- // The node after the last node this iterator should process.
- Node* m_pastStartNode;
-};
-
-// Builds on the text iterator, adding a character position so we can walk one
-// character at a time, or faster, as needed. Useful for searching.
-class CharacterIterator {
-public:
- CharacterIterator();
- explicit CharacterIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
-
- void advance(int numCharacters);
-
- bool atBreak() const { return m_atBreak; }
- bool atEnd() const { return m_textIterator.atEnd(); }
-
- int length() const { return m_textIterator.length() - m_runOffset; }
- const UChar* characters() const { return m_textIterator.characters() + m_runOffset; }
- String string(int numChars);
-
- int characterOffset() const { return m_offset; }
- PassRefPtr<Range> range() const;
-
-private:
- int m_offset;
- int m_runOffset;
- bool m_atBreak;
-
- TextIterator m_textIterator;
-};
-
-// Very similar to the TextIterator, except that the chunks of text returned are "well behaved",
-// meaning they never end split up a word. This is useful for spellcheck or (perhaps one day) searching.
-class WordAwareIterator {
-public:
- WordAwareIterator();
- explicit WordAwareIterator(const Range *r);
-
- bool atEnd() const { return !m_didLookAhead && m_textIterator.atEnd(); }
- void advance();
-
- int length() const;
- const UChar* characters() const;
-
- // Range of the text we're currently returning
- PassRefPtr<Range> range() const { return m_range; }
-
-private:
- // text from the previous chunk from the textIterator
- const UChar* m_previousText;
- int m_previousLength;
-
- // many chunks from textIterator concatenated
- Vector<UChar> m_buffer;
-
- // Did we have to look ahead in the textIterator to confirm the current chunk?
- bool m_didLookAhead;
-
- RefPtr<Range> m_range;
-
- TextIterator m_textIterator;
-};
-
-}
-
-#endif
diff --git a/WebCore/editing/TypingCommand.cpp b/WebCore/editing/TypingCommand.cpp
deleted file mode 100644
index ef144a1..0000000
--- a/WebCore/editing/TypingCommand.cpp
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TypingCommand.h"
-
-#include "BeforeTextInsertedEvent.h"
-#include "BreakBlockquoteCommand.h"
-#include "DeleteSelectionCommand.h"
-#include "Document.h"
-#include "Editor.h"
-#include "Element.h"
-#include "Frame.h"
-#include "InsertLineBreakCommand.h"
-#include "InsertParagraphSeparatorCommand.h"
-#include "InsertTextCommand.h"
-#include "SelectionController.h"
-#include "VisiblePosition.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, bool selectInsertedText, TextGranularity granularity)
- : CompositeEditCommand(document),
- m_commandType(commandType),
- m_textToInsert(textToInsert),
- m_openForMoreTyping(true),
- m_applyEditing(false),
- m_selectInsertedText(selectInsertedText),
- m_smartDelete(false),
- m_granularity(granularity),
- m_openedByBackwardDelete(false)
-{
-}
-
-void TypingCommand::deleteSelection(Document* document, bool smartDelete)
-{
- ASSERT(document);
-
- Frame* frame = document->frame();
- ASSERT(frame);
-
- if (!frame->selection()->isRange())
- return;
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->deleteSelection(smartDelete);
- return;
- }
-
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteSelection, "", false);
- typingCommand->setSmartDelete(smartDelete);
- typingCommand->apply();
-}
-
-void TypingCommand::deleteKeyPressed(Document *document, bool smartDelete, TextGranularity granularity)
-{
- ASSERT(document);
-
- Frame *frame = document->frame();
- ASSERT(frame);
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->deleteKeyPressed(granularity);
- return;
- }
-
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, DeleteKey, "", false, granularity);
- typingCommand->setSmartDelete(smartDelete);
- typingCommand->apply();
-}
-
-void TypingCommand::forwardDeleteKeyPressed(Document *document, bool smartDelete, TextGranularity granularity)
-{
- // FIXME: Forward delete in TextEdit appears to open and close a new typing command.
- ASSERT(document);
-
- Frame *frame = document->frame();
- ASSERT(frame);
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->forwardDeleteKeyPressed(granularity);
- return;
- }
-
- RefPtr<TypingCommand> typingCommand = TypingCommand::create(document, ForwardDeleteKey, "", false, granularity);
- typingCommand->setSmartDelete(smartDelete);
- typingCommand->apply();
-}
-
-void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, bool insertedTextIsComposition)
-{
- ASSERT(document);
-
- Frame* frame = document->frame();
- ASSERT(frame);
-
- insertText(document, text, frame->selection()->selection(), selectInsertedText, insertedTextIsComposition);
-}
-
-void TypingCommand::insertText(Document* document, const String& text, const Selection& selectionForInsertion, bool selectInsertedText, bool insertedTextIsComposition)
-{
- ASSERT(document);
-
- RefPtr<Frame> frame = document->frame();
- ASSERT(frame);
-
- Selection currentSelection = frame->selection()->selection();
- bool changeSelection = currentSelection != selectionForInsertion;
-
- String newText = text;
- Node* startNode = selectionForInsertion.start().node();
-
- if (startNode && startNode->rootEditableElement() && !insertedTextIsComposition) {
- // Send BeforeTextInsertedEvent. The event handler will update text if necessary.
- ExceptionCode ec = 0;
- RefPtr<BeforeTextInsertedEvent> evt = BeforeTextInsertedEvent::create(text);
- startNode->rootEditableElement()->dispatchEvent(evt, ec);
- newText = evt->text();
- }
-
- if (newText.isEmpty())
- return;
-
- // Set the starting and ending selection appropriately if we are using a selection
- // that is different from the current selection. In the future, we should change EditCommand
- // to deal with custom selections in a general way that can be used by all of the commands.
- RefPtr<EditCommand> lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand.get())) {
- TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand.get());
- if (changeSelection) {
- lastTypingCommand->setStartingSelection(selectionForInsertion);
- lastTypingCommand->setEndingSelection(selectionForInsertion);
- }
- lastTypingCommand->insertText(newText, selectInsertedText);
- if (changeSelection) {
- lastTypingCommand->setEndingSelection(currentSelection);
- frame->selection()->setSelection(currentSelection);
- }
- return;
- }
-
- RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText);
- if (changeSelection) {
- cmd->setStartingSelection(selectionForInsertion);
- cmd->setEndingSelection(selectionForInsertion);
- }
- applyCommand(cmd);
- if (changeSelection) {
- cmd->setEndingSelection(currentSelection);
- frame->selection()->setSelection(currentSelection);
- }
-}
-
-void TypingCommand::insertLineBreak(Document *document)
-{
- ASSERT(document);
-
- Frame *frame = document->frame();
- ASSERT(frame);
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->insertLineBreak();
- return;
- }
-
- applyCommand(TypingCommand::create(document, InsertLineBreak));
-}
-
-void TypingCommand::insertParagraphSeparatorInQuotedContent(Document *document)
-{
- ASSERT(document);
-
- Frame *frame = document->frame();
- ASSERT(frame);
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparatorInQuotedContent();
- return;
- }
-
- applyCommand(TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent));
-}
-
-void TypingCommand::insertParagraphSeparator(Document *document)
-{
- ASSERT(document);
-
- Frame *frame = document->frame();
- ASSERT(frame);
-
- EditCommand* lastEditCommand = frame->editor()->lastEditCommand();
- if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparator();
- return;
- }
-
- applyCommand(TypingCommand::create(document, InsertParagraphSeparator));
-}
-
-bool TypingCommand::isOpenForMoreTypingCommand(const EditCommand* cmd)
-{
- return cmd && cmd->isTypingCommand() && static_cast<const TypingCommand*>(cmd)->isOpenForMoreTyping();
-}
-
-void TypingCommand::closeTyping(EditCommand* cmd)
-{
- if (isOpenForMoreTypingCommand(cmd))
- static_cast<TypingCommand*>(cmd)->closeTyping();
-}
-
-void TypingCommand::doApply()
-{
- if (endingSelection().isNone())
- return;
-
- if (m_commandType == DeleteKey)
- if (m_commands.isEmpty())
- m_openedByBackwardDelete = true;
-
- switch (m_commandType) {
- case DeleteSelection:
- deleteSelection(m_smartDelete);
- return;
- case DeleteKey:
- deleteKeyPressed(m_granularity);
- return;
- case ForwardDeleteKey:
- forwardDeleteKeyPressed(m_granularity);
- return;
- case InsertLineBreak:
- insertLineBreak();
- return;
- case InsertParagraphSeparator:
- insertParagraphSeparator();
- return;
- case InsertParagraphSeparatorInQuotedContent:
- insertParagraphSeparatorInQuotedContent();
- return;
- case InsertText:
- insertText(m_textToInsert, m_selectInsertedText);
- return;
- }
-
- ASSERT_NOT_REACHED();
-}
-
-EditAction TypingCommand::editingAction() const
-{
- return EditActionTyping;
-}
-
-void TypingCommand::markMisspellingsAfterTyping()
-{
- if (!document()->frame()->editor()->isContinuousSpellCheckingEnabled())
- return;
- // Take a look at the selection that results after typing and determine whether we need to spellcheck.
- // Since the word containing the current selection is never marked, this does a check to
- // see if typing made a new word that is not in the current selection. Basically, you
- // get this by being at the end of a word and typing a space.
- VisiblePosition start(endingSelection().start(), endingSelection().affinity());
- VisiblePosition previous = start.previous();
- if (previous.isNotNull()) {
- VisiblePosition p1 = startOfWord(previous, LeftWordIfOnBoundary);
- VisiblePosition p2 = startOfWord(start, LeftWordIfOnBoundary);
- if (p1 != p2)
- document()->frame()->editor()->markMisspellingsAfterTypingToPosition(p1);
- }
-}
-
-void TypingCommand::typingAddedToOpenCommand()
-{
- markMisspellingsAfterTyping();
- // Do not apply editing to the frame on the first time through.
- // The frame will get told in the same way as all other commands.
- // But since this command stays open and is used for additional typing,
- // we need to tell the frame here as other commands are added.
- if (m_applyEditing)
- document()->frame()->editor()->appliedEditing(this);
- m_applyEditing = true;
-}
-
-void TypingCommand::insertText(const String &text, bool selectInsertedText)
-{
- // FIXME: Need to implement selectInsertedText for cases where more than one insert is involved.
- // This requires support from insertTextRunWithoutNewlines and insertParagraphSeparator for extending
- // an existing selection; at the moment they can either put the caret after what's inserted or
- // select what's inserted, but there's no way to "extend selection" to include both an old selection
- // that ends just before where we want to insert text and the newly inserted text.
- int offset = 0;
- int newline;
- while ((newline = text.find('\n', offset)) != -1) {
- if (newline != offset)
- insertTextRunWithoutNewlines(text.substring(offset, newline - offset), false);
- insertParagraphSeparator();
- offset = newline + 1;
- }
- if (offset == 0)
- insertTextRunWithoutNewlines(text, selectInsertedText);
- else {
- int length = text.length();
- if (length != offset) {
- insertTextRunWithoutNewlines(text.substring(offset, length - offset), selectInsertedText);
- }
- }
-}
-
-void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool selectInsertedText)
-{
- RefPtr<InsertTextCommand> command;
- if (!document()->frame()->typingStyle() && !m_commands.isEmpty()) {
- EditCommand* lastCommand = m_commands.last().get();
- if (lastCommand->isInsertTextCommand())
- command = static_cast<InsertTextCommand*>(lastCommand);
- }
- if (!command) {
- command = InsertTextCommand::create(document());
- applyCommandToComposite(command);
- }
- command->input(text, selectInsertedText);
- typingAddedToOpenCommand();
-}
-
-void TypingCommand::insertLineBreak()
-{
- applyCommandToComposite(InsertLineBreakCommand::create(document()));
- typingAddedToOpenCommand();
-}
-
-void TypingCommand::insertParagraphSeparator()
-{
- applyCommandToComposite(InsertParagraphSeparatorCommand::create(document()));
- typingAddedToOpenCommand();
-}
-
-void TypingCommand::insertParagraphSeparatorInQuotedContent()
-{
- applyCommandToComposite(BreakBlockquoteCommand::create(document()));
- typingAddedToOpenCommand();
-}
-
-void TypingCommand::deleteKeyPressed(TextGranularity granularity)
-{
- Selection selectionToDelete;
- Selection selectionAfterUndo;
-
- switch (endingSelection().state()) {
- case Selection::RANGE:
- selectionToDelete = endingSelection();
- selectionAfterUndo = selectionToDelete;
- break;
- case Selection::CARET: {
- m_smartDelete = false;
-
- SelectionController selection;
- selection.setSelection(endingSelection());
- selection.modify(SelectionController::EXTEND, SelectionController::BACKWARD, granularity);
-
- // When the caret is at the start of the editable area in an empty list item, break out of the list item.
- if (endingSelection().visibleStart().previous(true).isNull()) {
- if (breakOutOfEmptyListItem()) {
- typingAddedToOpenCommand();
- return;
- }
- }
-
- VisiblePosition visibleStart(endingSelection().visibleStart());
- // If the caret is at the start of a paragraph after a table, move content into the last table cell.
- if (isStartOfParagraph(visibleStart) && isFirstPositionAfterTable(visibleStart.previous(true))) {
- // Unless the caret is just before a table. We don't want to move a table into the last table cell.
- if (isLastPositionBeforeTable(visibleStart))
- return;
- // Extend the selection backward into the last cell, then deletion will handle the move.
- selection.modify(SelectionController::EXTEND, SelectionController::BACKWARD, granularity);
- // If the caret is just after a table, select the table and don't delete anything.
- } else if (Node* table = isFirstPositionAfterTable(visibleStart)) {
- setEndingSelection(Selection(Position(table, 0), endingSelection().start(), DOWNSTREAM));
- typingAddedToOpenCommand();
- return;
- }
-
- selectionToDelete = selection.selection();
- if (!startingSelection().isRange() || selectionToDelete.base() != startingSelection().start())
- selectionAfterUndo = selectionToDelete;
- else
- // It's a little tricky to compute what the starting selection would have been in the original document.
- // We can't let the Selection class's validation kick in or it'll adjust for us based on
- // the current state of the document and we'll get the wrong result.
- selectionAfterUndo.setWithoutValidation(startingSelection().end(), selectionToDelete.extent());
- break;
- }
- case Selection::NONE:
- ASSERT_NOT_REACHED();
- break;
- }
-
- if (selectionToDelete.isCaretOrRange() && document()->frame()->shouldDeleteSelection(selectionToDelete)) {
- // Make undo select everything that has been deleted, unless an undo will undo more than just this deletion.
- // FIXME: This behaves like TextEdit except for the case where you open with text insertion and then delete
- // more text than you insert. In that case all of the text that was around originally should be selected.
- if (m_openedByBackwardDelete)
- setStartingSelection(selectionAfterUndo);
- CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete);
- setSmartDelete(false);
- typingAddedToOpenCommand();
- }
-}
-
-void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity)
-{
- Selection selectionToDelete;
- Selection selectionAfterUndo;
-
- switch (endingSelection().state()) {
- case Selection::RANGE:
- selectionToDelete = endingSelection();
- selectionAfterUndo = selectionToDelete;
- break;
- case Selection::CARET: {
- m_smartDelete = false;
-
- // Handle delete at beginning-of-block case.
- // Do nothing in the case that the caret is at the start of a
- // root editable element or at the start of a document.
- SelectionController selection;
- selection.setSelection(endingSelection());
- selection.modify(SelectionController::EXTEND, SelectionController::FORWARD, granularity);
- Position downstreamEnd = endingSelection().end().downstream();
- VisiblePosition visibleEnd = endingSelection().visibleEnd();
- if (visibleEnd == endOfParagraph(visibleEnd))
- downstreamEnd = visibleEnd.next(true).deepEquivalent().downstream();
- // When deleting tables: Select the table first, then perform the deletion
- if (downstreamEnd.node() && downstreamEnd.node()->renderer() && downstreamEnd.node()->renderer()->isTable() && downstreamEnd.offset() == 0) {
- setEndingSelection(Selection(endingSelection().end(), Position(downstreamEnd.node(), maxDeepOffset(downstreamEnd.node())), DOWNSTREAM));
- typingAddedToOpenCommand();
- return;
- }
-
- // deleting to end of paragraph when at end of paragraph needs to merge the next paragraph (if any)
- if (granularity == ParagraphBoundary && selection.selection().isCaret() && isEndOfParagraph(selection.selection().visibleEnd()))
- selection.modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity);
-
- selectionToDelete = selection.selection();
- if (!startingSelection().isRange() || selectionToDelete.base() != startingSelection().start())
- selectionAfterUndo = selectionToDelete;
- else {
- // It's a little tricky to compute what the starting selection would have been in the original document.
- // We can't let the Selection class's validation kick in or it'll adjust for us based on
- // the current state of the document and we'll get the wrong result.
- Position extent = startingSelection().end();
- if (extent.node() != selectionToDelete.end().node())
- extent = selectionToDelete.extent();
- else {
- int extraCharacters;
- if (selectionToDelete.start().node() == selectionToDelete.end().node())
- extraCharacters = selectionToDelete.end().offset() - selectionToDelete.start().offset();
- else
- extraCharacters = selectionToDelete.end().offset();
- extent = Position(extent.node(), extent.offset() + extraCharacters);
- }
- selectionAfterUndo.setWithoutValidation(startingSelection().start(), extent);
- }
- break;
- }
- case Selection::NONE:
- ASSERT_NOT_REACHED();
- break;
- }
-
- if (selectionToDelete.isCaretOrRange() && document()->frame()->shouldDeleteSelection(selectionToDelete)) {
- // make undo select what was deleted
- setStartingSelection(selectionAfterUndo);
- CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete);
- setSmartDelete(false);
- typingAddedToOpenCommand();
- }
-}
-
-void TypingCommand::deleteSelection(bool smartDelete)
-{
- CompositeEditCommand::deleteSelection(smartDelete);
- typingAddedToOpenCommand();
-}
-
-bool TypingCommand::preservesTypingStyle() const
-{
- switch (m_commandType) {
- case DeleteSelection:
- case DeleteKey:
- case ForwardDeleteKey:
- case InsertParagraphSeparator:
- case InsertLineBreak:
- return true;
- case InsertParagraphSeparatorInQuotedContent:
- case InsertText:
- return false;
- }
- ASSERT_NOT_REACHED();
- return false;
-}
-
-bool TypingCommand::isTypingCommand() const
-{
- return true;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/TypingCommand.h b/WebCore/editing/TypingCommand.h
deleted file mode 100644
index 17ea526..0000000
--- a/WebCore/editing/TypingCommand.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TypingCommand_h
-#define TypingCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class TypingCommand : public CompositeEditCommand {
-public:
- enum ETypingCommand {
- DeleteSelection,
- DeleteKey,
- ForwardDeleteKey,
- InsertText,
- InsertLineBreak,
- InsertParagraphSeparator,
- InsertParagraphSeparatorInQuotedContent
- };
-
- static void deleteSelection(Document*, bool smartDelete = false);
- static void deleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity);
- static void forwardDeleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity);
- static void insertText(Document*, const String&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
- static void insertText(Document*, const String&, const Selection&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
- static void insertLineBreak(Document*);
- static void insertParagraphSeparator(Document*);
- static void insertParagraphSeparatorInQuotedContent(Document*);
- static bool isOpenForMoreTypingCommand(const EditCommand*);
- static void closeTyping(EditCommand*);
-
- bool isOpenForMoreTyping() const { return m_openForMoreTyping; }
- void closeTyping() { m_openForMoreTyping = false; }
-
- void insertText(const String &text, bool selectInsertedText);
- void insertTextRunWithoutNewlines(const String &text, bool selectInsertedText);
- void insertLineBreak();
- void insertParagraphSeparatorInQuotedContent();
- void insertParagraphSeparator();
- void deleteKeyPressed(TextGranularity);
- void forwardDeleteKeyPressed(TextGranularity);
- void deleteSelection(bool);
-
-private:
- static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text = "", bool selectInsertedText = false, TextGranularity granularity = CharacterGranularity)
- {
- return adoptRef(new TypingCommand(document, command, text, selectInsertedText, granularity));
- }
-
- TypingCommand(Document*, ETypingCommand, const String& text, bool selectInsertedText, TextGranularity);
-
- bool smartDelete() const { return m_smartDelete; }
- void setSmartDelete(bool smartDelete) { m_smartDelete = smartDelete; }
-
- virtual void doApply();
- virtual EditAction editingAction() const;
- virtual bool isTypingCommand() const;
- virtual bool preservesTypingStyle() const;
-
- void markMisspellingsAfterTyping();
- void typingAddedToOpenCommand();
-
- ETypingCommand m_commandType;
- String m_textToInsert;
- bool m_openForMoreTyping;
- bool m_applyEditing;
- bool m_selectInsertedText;
- bool m_smartDelete;
- TextGranularity m_granularity;
-
- // Undoing a series of backward deletes will restore a selection around all of the
- // characters that were deleted, but only if the typing command being undone
- // was opened with a backward delete.
- bool m_openedByBackwardDelete;
-};
-
-} // namespace WebCore
-
-#endif // TypingCommand_h
diff --git a/WebCore/editing/UnlinkCommand.cpp b/WebCore/editing/UnlinkCommand.cpp
deleted file mode 100644
index 0ba9a06..0000000
--- a/WebCore/editing/UnlinkCommand.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "UnlinkCommand.h"
-
-#include "HTMLAnchorElement.h"
-
-namespace WebCore {
-
-UnlinkCommand::UnlinkCommand(Document* document)
- : CompositeEditCommand(document)
-{
-}
-
-void UnlinkCommand::doApply()
-{
- // FIXME: If a caret is inside a link, remove it.
- if (!endingSelection().isRange())
- return;
-
- pushPartiallySelectedAnchorElementsDown();
-
- HTMLAnchorElement* anchorElement = new HTMLAnchorElement(document());
- removeStyledElement(anchorElement);
-}
-
-}
diff --git a/WebCore/editing/UnlinkCommand.h b/WebCore/editing/UnlinkCommand.h
deleted file mode 100644
index f3d560f..0000000
--- a/WebCore/editing/UnlinkCommand.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef UnlinkCommand_h
-#define UnlinkCommand_h
-
-#include "CompositeEditCommand.h"
-
-namespace WebCore {
-
-class UnlinkCommand : public CompositeEditCommand {
-public:
- static PassRefPtr<UnlinkCommand> create(Document* document)
- {
- return adoptRef(new UnlinkCommand(document));
- }
-
-private:
- UnlinkCommand(Document*);
-
- virtual void doApply();
- virtual EditAction editingAction() const { return EditActionUnlink; }
-};
-
-} // namespace WebCore
-
-#endif // UnlinkCommand_h
diff --git a/WebCore/editing/VisiblePosition.cpp b/WebCore/editing/VisiblePosition.cpp
deleted file mode 100644
index 626c5b4..0000000
--- a/WebCore/editing/VisiblePosition.cpp
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "VisiblePosition.h"
-
-#include "CString.h"
-#include "Document.h"
-#include "Element.h"
-#include "HTMLNames.h"
-#include "InlineTextBox.h"
-#include "Logging.h"
-#include "Range.h"
-#include "Text.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-#include <stdio.h>
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
-{
- init(pos, affinity);
-}
-
-VisiblePosition::VisiblePosition(Node *node, int offset, EAffinity affinity)
-{
- ASSERT(offset >= 0);
- init(Position(node, offset), affinity);
-}
-
-void VisiblePosition::init(const Position& position, EAffinity affinity)
-{
- m_affinity = affinity;
-
- m_deepPosition = canonicalPosition(position);
-
- // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
- if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
- m_affinity = DOWNSTREAM;
-}
-
-VisiblePosition VisiblePosition::next(bool stayInEditableContent) const
-{
- VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
-
- if (!stayInEditableContent)
- return next;
-
- return honorEditableBoundaryAtOrAfter(next);
-}
-
-VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
-{
- // find first previous DOM position that is visible
- Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
-
- // return null visible position if there is no previous visible position
- if (pos.atStart())
- return VisiblePosition();
-
- VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
- ASSERT(prev != *this);
-
-#ifndef NDEBUG
- // we should always be able to make the affinity DOWNSTREAM, because going previous from an
- // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
- if (prev.isNotNull() && m_affinity == UPSTREAM) {
- VisiblePosition temp = prev;
- temp.setAffinity(UPSTREAM);
- ASSERT(inSameLine(temp, prev));
- }
-#endif
-
- if (!stayInEditableContent)
- return prev;
-
- return honorEditableBoundaryAtOrBefore(prev);
-}
-
-Position VisiblePosition::leftVisuallyDistinctCandidate() const
-{
- Position p = m_deepPosition;
- if (!p.node())
- return Position();
-
- Position downstreamStart = p.downstream();
- TextDirection primaryDirection = LTR;
- for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
- if (r->isBlockFlow()) {
- primaryDirection = r->style()->direction();
- break;
- }
- }
-
- while (true) {
- InlineBox* box;
- int offset;
- p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
- if (!box)
- return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
-
- RenderObject* renderer = box->object();
-
- while (true) {
- if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
- return box->direction() == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
-
- offset = box->direction() == LTR ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
-
- int caretMinOffset = box->caretMinOffset();
- int caretMaxOffset = box->caretMaxOffset();
-
- if (offset > caretMinOffset && offset < caretMaxOffset)
- break;
-
- if (box->direction() == LTR ? offset < caretMinOffset : offset > caretMaxOffset) {
- // Overshot to the left.
- InlineBox* prevBox = box->prevLeafChild();
- if (!prevBox)
- return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
-
- // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
- box = prevBox;
- renderer = box->object();
- offset = prevBox->caretRightmostOffset();
- continue;
- }
-
- ASSERT(offset == box->caretLeftmostOffset());
-
- unsigned char level = box->bidiLevel();
- InlineBox* prevBox = box->prevLeafChild();
-
- if (box->direction() == primaryDirection) {
- if (!prevBox || prevBox->bidiLevel() >= level)
- break;
-
- level = prevBox->bidiLevel();
-
- InlineBox* nextBox = box;
- do {
- nextBox = nextBox->nextLeafChild();
- } while (nextBox && nextBox->bidiLevel() > level);
-
- if (nextBox && nextBox->bidiLevel() == level)
- break;
-
- while (InlineBox* prevBox = box->prevLeafChild()) {
- if (prevBox->bidiLevel() < level)
- break;
- box = prevBox;
- }
- renderer = box->object();
- offset = box->caretRightmostOffset();
- if (box->direction() == primaryDirection)
- break;
- continue;
- }
-
- if (prevBox) {
- box = prevBox;
- renderer = box->object();
- offset = box->caretRightmostOffset();
- if (box->bidiLevel() > level) {
- do {
- prevBox = box->prevLeafChild();
- } while (prevBox && prevBox->bidiLevel() > level);
-
- if (!prevBox || prevBox->bidiLevel() < level)
- continue;
- }
- } else {
- // Trailing edge of a secondary run. Set to the leading edge of the entire run.
- while (true) {
- while (InlineBox* nextBox = box->nextLeafChild()) {
- if (nextBox->bidiLevel() < level)
- break;
- box = nextBox;
- }
- if (box->bidiLevel() == level)
- break;
- level = box->bidiLevel();
- while (InlineBox* prevBox = box->prevLeafChild()) {
- if (prevBox->bidiLevel() < level)
- break;
- box = prevBox;
- }
- if (box->bidiLevel() == level)
- break;
- level = box->bidiLevel();
- }
- renderer = box->object();
- offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
- }
- break;
- }
-
- p = Position(renderer->element(), offset);
-
- if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
- return p;
- }
-}
-
-VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
-{
- Position pos = leftVisuallyDistinctCandidate();
- if (pos.atStart() || pos.atEnd())
- return VisiblePosition();
-
- VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
- ASSERT(left != *this);
-
- if (!stayInEditableContent)
- return left;
-
- // FIXME: This may need to do something different from "before".
- return honorEditableBoundaryAtOrBefore(left);
-}
-
-Position VisiblePosition::rightVisuallyDistinctCandidate() const
-{
- Position p = m_deepPosition;
- if (!p.node())
- return Position();
-
- Position downstreamStart = p.downstream();
- TextDirection primaryDirection = LTR;
- for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
- if (r->isBlockFlow()) {
- primaryDirection = r->style()->direction();
- break;
- }
- }
-
- while (true) {
- InlineBox* box;
- int offset;
- p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
- if (!box)
- return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
-
- RenderObject* renderer = box->object();
-
- while (true) {
- if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
- return box->direction() == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
-
- offset = box->direction() == LTR ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
-
- int caretMinOffset = box->caretMinOffset();
- int caretMaxOffset = box->caretMaxOffset();
-
- if (offset > caretMinOffset && offset < caretMaxOffset)
- break;
-
- if (box->direction() == LTR ? offset > caretMaxOffset : offset < caretMinOffset) {
- // Overshot to the right.
- InlineBox* nextBox = box->nextLeafChild();
- if (!nextBox)
- return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
-
- // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
- box = nextBox;
- renderer = box->object();
- offset = nextBox->caretLeftmostOffset();
- continue;
- }
-
- ASSERT(offset == box->caretRightmostOffset());
-
- unsigned char level = box->bidiLevel();
- InlineBox* nextBox = box->nextLeafChild();
-
- if (box->direction() == primaryDirection) {
- if (!nextBox || nextBox->bidiLevel() >= level)
- break;
-
- level = nextBox->bidiLevel();
-
- InlineBox* prevBox = box;
- do {
- prevBox = prevBox->prevLeafChild();
- } while (prevBox && prevBox->bidiLevel() > level);
-
- if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
- break;
-
- // For example, abc 123 ^ CBA
- while (InlineBox* nextBox = box->nextLeafChild()) {
- if (nextBox->bidiLevel() < level)
- break;
- box = nextBox;
- }
- renderer = box->object();
- offset = box->caretLeftmostOffset();
- if (box->direction() == primaryDirection)
- break;
- continue;
- }
-
- if (nextBox) {
- box = nextBox;
- renderer = box->object();
- offset = box->caretLeftmostOffset();
- if (box->bidiLevel() > level) {
- do {
- nextBox = box->nextLeafChild();
- } while (nextBox && nextBox->bidiLevel() > level);
-
- if (!nextBox || nextBox->bidiLevel() < level)
- continue;
- }
- } else {
- // Trailing edge of a secondary run. Set to the leading edge of the entire run.
- while (true) {
- while (InlineBox* prevBox = box->prevLeafChild()) {
- if (prevBox->bidiLevel() < level)
- break;
- box = prevBox;
- }
- if (box->bidiLevel() == level)
- break;
- level = box->bidiLevel();
- while (InlineBox* nextBox = box->nextLeafChild()) {
- if (nextBox->bidiLevel() < level)
- break;
- box = nextBox;
- }
- if (box->bidiLevel() == level)
- break;
- level = box->bidiLevel();
- }
- renderer = box->object();
- offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
- }
- break;
- }
-
- p = Position(renderer->element(), offset);
-
- if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
- return p;
- }
-}
-
-VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
-{
- Position pos = rightVisuallyDistinctCandidate();
- if (pos.atStart() || pos.atEnd())
- return VisiblePosition();
-
- VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
- ASSERT(right != *this);
-
- if (!stayInEditableContent)
- return right;
-
- // FIXME: This may need to do something different from "after".
- return honorEditableBoundaryAtOrAfter(right);
-}
-
-VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePosition &pos) const
-{
- if (pos.isNull())
- return pos;
-
- Node* highestRoot = highestEditableRoot(deepEquivalent());
-
- // Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
- return VisiblePosition();
-
- // Return pos itself if the two are from the very same editable region, or both are non-editable
- // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
- // to it is allowed. Selection::adjustForEditableContent has this problem too.
- if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
- return pos;
-
- // Return empty position if this position is non-editable, but pos is editable
- // FIXME: Move to the previous non-editable region.
- if (!highestRoot)
- return VisiblePosition();
-
- // Return the last position before pos that is in the same editable region as this position
- return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
-}
-
-VisiblePosition VisiblePosition::honorEditableBoundaryAtOrAfter(const VisiblePosition &pos) const
-{
- if (pos.isNull())
- return pos;
-
- Node* highestRoot = highestEditableRoot(deepEquivalent());
-
- // Return empty position if pos is not somewhere inside the editable region containing this position
- if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot))
- return VisiblePosition();
-
- // Return pos itself if the two are from the very same editable region, or both are non-editable
- // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
- // to it is allowed. Selection::adjustForEditableContent has this problem too.
- if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
- return pos;
-
- // Return empty position if this position is non-editable, but pos is editable
- // FIXME: Move to the next non-editable region.
- if (!highestRoot)
- return VisiblePosition();
-
- // Return the next position after pos that is in the same editable region as this position
- return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
-}
-
-Position canonicalizeCandidate(const Position& candidate)
-{
- if (candidate.isNull())
- return Position();
- ASSERT(candidate.isCandidate());
- Position upstream = candidate.upstream();
- if (upstream.isCandidate())
- return upstream;
- return candidate;
-}
-
-Position VisiblePosition::canonicalPosition(const Position& position)
-{
- // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
- // ask renderers to paint downstream carets for other renderers.
- // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
- // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
- // unless the affinity is upstream.
- Node* node = position.node();
- if (!node)
- return Position();
-
- node->document()->updateLayoutIgnorePendingStylesheets();
-
- Position candidate = position.upstream();
- if (candidate.isCandidate())
- return candidate;
- candidate = position.downstream();
- if (candidate.isCandidate())
- return candidate;
-
- // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
- // blocks or enter new ones), we search forward and backward until we find one.
- Position next = canonicalizeCandidate(nextCandidate(position));
- Position prev = canonicalizeCandidate(previousCandidate(position));
- Node* nextNode = next.node();
- Node* prevNode = prev.node();
-
- // The new position must be in the same editable element. Enforce that first.
- // Unless the descent is from a non-editable html element to an editable body.
- if (node->hasTagName(htmlTag) && !node->isContentEditable())
- return next.isNotNull() ? next : prev;
-
- Node* editingRoot = editableRootForPosition(position);
-
- // If the html element is editable, descending into its body will look like a descent
- // from non-editable to editable content since rootEditableElement() always stops at the body.
- if (editingRoot && editingRoot->hasTagName(htmlTag) || position.node()->isDocumentNode())
- return next.isNotNull() ? next : prev;
-
- bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
- bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
- if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
- return prev;
-
- if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
- return next;
-
- if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
- return Position();
-
- // The new position should be in the same block flow element. Favor that.
- Node *originalBlock = node->enclosingBlockFlowElement();
- bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
- bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
- if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
- return prev;
-
- return next;
-}
-
-UChar VisiblePosition::characterAfter() const
-{
- // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
- // is the one that will be inside the text node containing the character after this visible position.
- Position pos = m_deepPosition.downstream();
- Node* node = pos.node();
- if (!node || !node->isTextNode())
- return 0;
- Text* textNode = static_cast<Text*>(pos.node());
- int offset = pos.offset();
- if ((unsigned)offset >= textNode->length())
- return 0;
- return textNode->data()[offset];
-}
-
-IntRect VisiblePosition::caretRect() const
-{
- Node* node = m_deepPosition.node();
- if (!node)
- return IntRect();
-
- RenderObject* renderer = node->renderer();
- if (!renderer)
- return IntRect();
-
- InlineBox* inlineBox;
- int caretOffset;
- getInlineBoxAndOffset(inlineBox, caretOffset);
-
- if (inlineBox)
- renderer = inlineBox->object();
-
- return renderer->caretRect(inlineBox, caretOffset);
-}
-
-void VisiblePosition::debugPosition(const char* msg) const
-{
- if (isNull())
- fprintf(stderr, "Position [%s]: null\n", msg);
- else
- fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().utf8().data(), m_deepPosition.node(), m_deepPosition.offset());
-}
-
-#ifndef NDEBUG
-
-void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
-{
- m_deepPosition.formatForDebugger(buffer, length);
-}
-
-void VisiblePosition::showTreeForThis() const
-{
- m_deepPosition.showTreeForThis();
-}
-
-#endif
-
-PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
-{
- Position s = rangeCompliantEquivalent(start);
- Position e = rangeCompliantEquivalent(end);
- return Range::create(s.node()->document(), s.node(), s.offset(), e.node(), e.offset());
-}
-
-VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
-{
- int exception = 0;
- return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);
-}
-
-VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
-{
- int exception = 0;
- return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);
-}
-
-bool setStart(Range *r, const VisiblePosition &visiblePosition)
-{
- if (!r)
- return false;
- Position p = rangeCompliantEquivalent(visiblePosition);
- int code = 0;
- r->setStart(p.node(), p.offset(), code);
- return code == 0;
-}
-
-bool setEnd(Range *r, const VisiblePosition &visiblePosition)
-{
- if (!r)
- return false;
- Position p = rangeCompliantEquivalent(visiblePosition);
- int code = 0;
- r->setEnd(p.node(), p.offset(), code);
- return code == 0;
-}
-
-Node *enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
-{
- if (visiblePosition.isNull())
- return NULL;
-
- return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();
-}
-
-bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
-{
- if (visiblePosition.isNull())
- return false;
-
- if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
- return false;
-
- VisiblePosition previous = visiblePosition.previous();
- return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);
-}
-
-bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
-{
- if (visiblePosition.isNull())
- return false;
-
- if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node))
- return false;
-
- VisiblePosition next = visiblePosition.next();
- return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);
-}
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-
-void showTree(const WebCore::VisiblePosition* vpos)
-{
- if (vpos)
- vpos->showTreeForThis();
-}
-
-void showTree(const WebCore::VisiblePosition& vpos)
-{
- vpos.showTreeForThis();
-}
-
-#endif
diff --git a/WebCore/editing/VisiblePosition.h b/WebCore/editing/VisiblePosition.h
deleted file mode 100644
index 79f3a57..0000000
--- a/WebCore/editing/VisiblePosition.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef VisiblePosition_h
-#define VisiblePosition_h
-
-#include "Node.h"
-#include "Position.h"
-#include "TextDirection.h"
-
-namespace WebCore {
-
-// VisiblePosition default affinity is downstream because
-// the callers do not really care (they just want the
-// deep position without regard to line position), and this
-// is cheaper than UPSTREAM
-#define VP_DEFAULT_AFFINITY DOWNSTREAM
-
-// Callers who do not know where on the line the position is,
-// but would like UPSTREAM if at a line break or DOWNSTREAM
-// otherwise, need a clear way to specify that. The
-// constructors auto-correct UPSTREAM to DOWNSTREAM if the
-// position is not at a line break.
-#define VP_UPSTREAM_IF_POSSIBLE UPSTREAM
-
-class InlineBox;
-
-class VisiblePosition {
-public:
- // NOTE: UPSTREAM affinity will be used only if pos is at end of a wrapped line,
- // otherwise it will be converted to DOWNSTREAM
- VisiblePosition() : m_affinity(VP_DEFAULT_AFFINITY) { }
- VisiblePosition(Node*, int offset, EAffinity);
- VisiblePosition(const Position&, EAffinity = VP_DEFAULT_AFFINITY);
-
- void clear() { m_deepPosition.clear(); }
-
- bool isNull() const { return m_deepPosition.isNull(); }
- bool isNotNull() const { return m_deepPosition.isNotNull(); }
-
- Position deepEquivalent() const { return m_deepPosition; }
- EAffinity affinity() const { ASSERT(m_affinity == UPSTREAM || m_affinity == DOWNSTREAM); return m_affinity; }
- void setAffinity(EAffinity affinity) { m_affinity = affinity; }
-
- // next() and previous() will increment/decrement by a character cluster.
- VisiblePosition next(bool stayInEditableContent = false) const;
- VisiblePosition previous(bool stayInEditableContent = false) const;
- VisiblePosition honorEditableBoundaryAtOrBefore(const VisiblePosition&) const;
- VisiblePosition honorEditableBoundaryAtOrAfter(const VisiblePosition&) const;
-
- VisiblePosition left(bool stayInEditableContent = false) const;
- VisiblePosition right(bool stayInEditableContent = false) const;
-
- UChar characterAfter() const;
- UChar characterBefore() const { return previous().characterAfter(); }
-
- void debugPosition(const char* msg = "") const;
-
- Element* rootEditableElement() const { return m_deepPosition.isNotNull() ? m_deepPosition.node()->rootEditableElement() : 0; }
-
- void getInlineBoxAndOffset(InlineBox*& inlineBox, int& caretOffset) const
- {
- m_deepPosition.getInlineBoxAndOffset(m_affinity, inlineBox, caretOffset);
- }
-
- void getInlineBoxAndOffset(TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
- {
- m_deepPosition.getInlineBoxAndOffset(m_affinity, primaryDirection, inlineBox, caretOffset);
- }
-
- IntRect caretRect() const;
-
-#ifndef NDEBUG
- void formatForDebugger(char* buffer, unsigned length) const;
- void showTreeForThis() const;
-#endif
-
-private:
- void init(const Position&, EAffinity);
- Position canonicalPosition(const Position&);
-
- Position leftVisuallyDistinctCandidate() const;
- Position rightVisuallyDistinctCandidate() const;
-
- Position m_deepPosition;
- EAffinity m_affinity;
-};
-
-// FIXME: This shouldn't ignore affinity.
-inline bool operator==(const VisiblePosition& a, const VisiblePosition& b)
-{
- return a.deepEquivalent() == b.deepEquivalent();
-}
-
-inline bool operator!=(const VisiblePosition& a, const VisiblePosition& b)
-{
- return !(a == b);
-}
-
-PassRefPtr<Range> makeRange(const VisiblePosition&, const VisiblePosition&);
-bool setStart(Range*, const VisiblePosition&);
-bool setEnd(Range*, const VisiblePosition&);
-VisiblePosition startVisiblePosition(const Range*, EAffinity);
-VisiblePosition endVisiblePosition(const Range*, EAffinity);
-
-Node *enclosingBlockFlowElement(const VisiblePosition&);
-
-bool isFirstVisiblePositionInNode(const VisiblePosition&, const Node*);
-bool isLastVisiblePositionInNode(const VisiblePosition&, const Node*);
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-// Outside the WebCore namespace for ease of invocation from gdb.
-void showTree(const WebCore::VisiblePosition*);
-void showTree(const WebCore::VisiblePosition&);
-#endif
-
-#endif // VisiblePosition_h
diff --git a/WebCore/editing/WrapContentsInDummySpanCommand.cpp b/WebCore/editing/WrapContentsInDummySpanCommand.cpp
deleted file mode 100644
index 86bf440..0000000
--- a/WebCore/editing/WrapContentsInDummySpanCommand.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "WrapContentsInDummySpanCommand.h"
-
-#include "ApplyStyleCommand.h"
-#include "HTMLElement.h"
-
-namespace WebCore {
-
-WrapContentsInDummySpanCommand::WrapContentsInDummySpanCommand(PassRefPtr<Element> element)
- : SimpleEditCommand(element->document()), m_element(element)
-{
- ASSERT(m_element);
-}
-
-void WrapContentsInDummySpanCommand::doApply()
-{
- ASSERT(m_element);
-
- ExceptionCode ec = 0;
-
- if (!m_dummySpan)
- m_dummySpan = static_pointer_cast<HTMLElement>(createStyleSpanElement(document()));
-
- while (m_element->firstChild()) {
- m_dummySpan->appendChild(m_element->firstChild(), ec);
- ASSERT(ec == 0);
- }
-
- m_element->appendChild(m_dummySpan.get(), ec);
- ASSERT(ec == 0);
-}
-
-void WrapContentsInDummySpanCommand::doUnapply()
-{
- ASSERT(m_element);
- ASSERT(m_dummySpan);
-
- ASSERT(m_element->firstChild() == m_dummySpan);
- ASSERT(!m_element->firstChild()->nextSibling());
-
- ExceptionCode ec = 0;
-
- while (m_dummySpan->firstChild()) {
- m_element->appendChild(m_dummySpan->firstChild(), ec);
- ASSERT(ec == 0);
- }
-
- m_element->removeChild(m_dummySpan.get(), ec);
- ASSERT(ec == 0);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/WrapContentsInDummySpanCommand.h b/WebCore/editing/WrapContentsInDummySpanCommand.h
deleted file mode 100644
index 63a2ae7..0000000
--- a/WebCore/editing/WrapContentsInDummySpanCommand.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WrapContentsInDummySpanCommand_h
-#define WrapContentsInDummySpanCommand_h
-
-#include "EditCommand.h"
-
-namespace WebCore {
-
-class WrapContentsInDummySpanCommand : public SimpleEditCommand {
-public:
- static PassRefPtr<WrapContentsInDummySpanCommand> create(PassRefPtr<Element> element)
- {
- return adoptRef(new WrapContentsInDummySpanCommand(element));
- }
-
-private:
- WrapContentsInDummySpanCommand(PassRefPtr<Element>);
-
- virtual void doApply();
- virtual void doUnapply();
-
- RefPtr<Element> m_element;
- RefPtr<Element> m_dummySpan;
-};
-
-} // namespace WebCore
-
-#endif // WrapContentsInDummySpanCommand_h
diff --git a/WebCore/editing/android/EditorAndroid.cpp b/WebCore/editing/android/EditorAndroid.cpp
deleted file mode 100644
index 8e00326..0000000
--- a/WebCore/editing/android/EditorAndroid.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2009, The Android Open Source Project
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Editor.h"
-
-#include "ClipboardAndroid.h"
-
-namespace WebCore {
-
-PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
-{
- return new ClipboardAndroid(policy, false);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
deleted file mode 100644
index 68ea754..0000000
--- a/WebCore/editing/htmlediting.cpp
+++ /dev/null
@@ -1,991 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "htmlediting.h"
-
-#include "CharacterNames.h"
-#include "Document.h"
-#include "EditingText.h"
-#include "HTMLElement.h"
-#include "HTMLInterchange.h"
-#include "HTMLNames.h"
-#include "PositionIterator.h"
-#include "RenderObject.h"
-#include "RegularExpression.h"
-#include "Range.h"
-#include "Selection.h"
-#include "Text.h"
-#include "TextIterator.h"
-#include "VisiblePosition.h"
-#include "visible_units.h"
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-// Atomic means that the node has no children, or has children which are ignored for the
-// purposes of editing.
-bool isAtomicNode(const Node *node)
-{
- return node && (!node->hasChildNodes() || editingIgnoresContent(node));
-}
-
-// Returns true for nodes that either have no content, or have content that is ignored (skipped
-// over) while editing. There are no VisiblePositions inside these nodes.
-bool editingIgnoresContent(const Node* node)
-{
- return !canHaveChildrenForEditing(node) && !node->isTextNode();
-}
-
-bool canHaveChildrenForEditing(const Node* node)
-{
- return !node->hasTagName(hrTag) &&
- !node->hasTagName(brTag) &&
- !node->hasTagName(imgTag) &&
- !node->hasTagName(buttonTag) &&
- !node->hasTagName(inputTag) &&
- !node->hasTagName(textareaTag) &&
- !node->hasTagName(objectTag) &&
- !node->hasTagName(iframeTag) &&
- !node->hasTagName(embedTag) &&
- !node->hasTagName(appletTag) &&
- !node->hasTagName(selectTag) &&
- !node->isTextNode();
-}
-
-// Compare two positions, taking into account the possibility that one or both
-// could be inside a shadow tree. Only works for non-null values.
-int comparePositions(const Position& a, const Position& b)
-{
- Node* nodeA = a.node();
- ASSERT(nodeA);
- Node* nodeB = b.node();
- ASSERT(nodeB);
- int offsetA = a.offset();
- int offsetB = b.offset();
-
- Node* shadowAncestorA = nodeA->shadowAncestorNode();
- if (shadowAncestorA == nodeA)
- shadowAncestorA = 0;
- Node* shadowAncestorB = nodeB->shadowAncestorNode();
- if (shadowAncestorB == nodeB)
- shadowAncestorB = 0;
-
- int bias = 0;
- if (shadowAncestorA != shadowAncestorB) {
- if (shadowAncestorA) {
- nodeA = shadowAncestorA;
- offsetA = 0;
- bias = 1;
- }
- if (shadowAncestorB) {
- nodeB = shadowAncestorB;
- offsetB = 0;
- bias = -1;
- }
- }
-
- int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
- return result ? result : bias;
-}
-
-Node* highestEditableRoot(const Position& position)
-{
- Node* node = position.node();
- if (!node)
- return 0;
-
- Node* highestRoot = editableRootForPosition(position);
- if (!highestRoot)
- return 0;
-
- node = highestRoot;
- while (node) {
- if (node->isContentEditable())
- highestRoot = node;
- if (node->hasTagName(bodyTag))
- break;
- node = node->parentNode();
- }
-
- return highestRoot;
-}
-
-Node* lowestEditableAncestor(Node* node)
-{
- if (!node)
- return 0;
-
- Node *lowestRoot = 0;
- while (node) {
- if (node->isContentEditable())
- return node->rootEditableElement();
- if (node->hasTagName(bodyTag))
- break;
- node = node->parentNode();
- }
-
- return lowestRoot;
-}
-
-bool isEditablePosition(const Position& p)
-{
- Node* node = p.node();
- if (!node)
- return false;
-
- if (node->renderer() && node->renderer()->isTable())
- node = node->parentNode();
-
- return node->isContentEditable();
-}
-
-bool isRichlyEditablePosition(const Position& p)
-{
- Node* node = p.node();
- if (!node)
- return false;
-
- if (node->renderer() && node->renderer()->isTable())
- node = node->parentNode();
-
- return node->isContentRichlyEditable();
-}
-
-Element* editableRootForPosition(const Position& p)
-{
- Node* node = p.node();
- if (!node)
- return 0;
-
- if (node->renderer() && node->renderer()->isTable())
- node = node->parentNode();
-
- return node->rootEditableElement();
-}
-
-bool isContentEditable(const Node* node)
-{
- return node->isContentEditable();
-}
-
-Position nextCandidate(const Position& position)
-{
- PositionIterator p = position;
- while (!p.atEnd()) {
- p.increment();
- if (p.isCandidate())
- return p;
- }
- return Position();
-}
-
-Position nextVisuallyDistinctCandidate(const Position& position)
-{
- Position p = position;
- Position downstreamStart = p.downstream();
- while (!p.atEnd()) {
- p = p.next(UsingComposedCharacters);
- if (p.isCandidate() && p.downstream() != downstreamStart)
- return p;
- }
- return Position();
-}
-
-Position previousCandidate(const Position& position)
-{
- PositionIterator p = position;
- while (!p.atStart()) {
- p.decrement();
- if (p.isCandidate())
- return p;
- }
- return Position();
-}
-
-Position previousVisuallyDistinctCandidate(const Position& position)
-{
- Position p = position;
- Position downstreamStart = p.downstream();
- while (!p.atStart()) {
- p = p.previous(UsingComposedCharacters);
- if (p.isCandidate() && p.downstream() != downstreamStart)
- return p;
- }
- return Position();
-}
-
-VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
-{
- // position falls before highestRoot.
- if (comparePositions(position, Position(highestRoot, 0)) == -1 && highestRoot->isContentEditable())
- return VisiblePosition(Position(highestRoot, 0));
-
- Position p = position;
-
- if (Node* shadowAncestor = p.node()->shadowAncestorNode())
- if (shadowAncestor != p.node())
- p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
-
- while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
- p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
-
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
- return VisiblePosition();
-
- return VisiblePosition(p);
-}
-
-VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
-{
- // When position falls after highestRoot, the result is easy to compute.
- if (comparePositions(position, Position(highestRoot, maxDeepOffset(highestRoot))) == 1)
- return VisiblePosition(Position(highestRoot, maxDeepOffset(highestRoot)));
-
- Position p = position;
-
- if (Node* shadowAncestor = p.node()->shadowAncestorNode())
- if (shadowAncestor != p.node())
- p = Position(shadowAncestor, 0);
-
- while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
- p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
-
- if (p.node() && !p.node()->isDescendantOf(highestRoot))
- return VisiblePosition();
-
- return VisiblePosition(p);
-}
-
-// Whether or not content before and after this node will collapse onto the same line as it.
-bool isBlock(const Node* node)
-{
- return node && node->renderer() && !node->renderer()->isInline();
-}
-
-// FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
-// FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the
-// block that contains the table and not the table, and this function should be the only one responsible for
-// knowing about these kinds of special cases.
-Node* enclosingBlock(Node* node)
-{
- return enclosingNodeOfType(Position(node, 0), &isBlock);
-}
-
-Position rangeCompliantEquivalent(const Position& pos)
-{
- if (pos.isNull())
- return Position();
-
- Node *node = pos.node();
-
- if (pos.offset() <= 0) {
- if (node->parentNode() && (editingIgnoresContent(node) || isTableElement(node)))
- return positionBeforeNode(node);
- return Position(node, 0);
- }
-
- if (node->offsetInCharacters())
- return Position(node, min(node->maxCharacterOffset(), pos.offset()));
-
- int maxCompliantOffset = node->childNodeCount();
- if (pos.offset() > maxCompliantOffset) {
- if (node->parentNode())
- return positionAfterNode(node);
-
- // there is no other option at this point than to
- // use the highest allowed position in the node
- return Position(node, maxCompliantOffset);
- }
-
- // Editing should never generate positions like this.
- if ((pos.offset() < maxCompliantOffset) && editingIgnoresContent(node)) {
- ASSERT_NOT_REACHED();
- return node->parentNode() ? positionBeforeNode(node) : Position(node, 0);
- }
-
- if (pos.offset() == maxCompliantOffset && (editingIgnoresContent(node) || isTableElement(node)))
- return positionAfterNode(node);
-
- return Position(pos);
-}
-
-Position rangeCompliantEquivalent(const VisiblePosition& vpos)
-{
- return rangeCompliantEquivalent(vpos.deepEquivalent());
-}
-
-// This method is used to create positions in the DOM. It returns the maximum valid offset
-// in a node. It returns 1 for some elements even though they do not have children, which
-// creates technically invalid DOM Positions. Be sure to call rangeCompliantEquivalent
-// on a Position before using it to create a DOM Range, or an exception will be thrown.
-int maxDeepOffset(const Node *node)
-{
- ASSERT(node);
- if (!node)
- return 0;
- if (node->offsetInCharacters())
- return node->maxCharacterOffset();
-
- if (node->hasChildNodes())
- return node->childNodeCount();
-
- // NOTE: This should preempt the childNodeCount for, e.g., select nodes
- if (editingIgnoresContent(node))
- return 1;
-
- return 0;
-}
-
-String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
-{
- static String twoSpaces(" ");
- static String nbsp("\xa0");
- static String pattern(" \xa0");
-
- String rebalancedString = string;
-
- rebalancedString.replace(noBreakSpace, ' ');
- rebalancedString.replace('\n', ' ');
- rebalancedString.replace('\t', ' ');
-
- rebalancedString.replace(twoSpaces, pattern);
-
- if (startIsStartOfParagraph && rebalancedString[0] == ' ')
- rebalancedString.replace(0, 1, nbsp);
- int end = rebalancedString.length() - 1;
- if (endIsEndOfParagraph && rebalancedString[end] == ' ')
- rebalancedString.replace(end, 1, nbsp);
-
- return rebalancedString;
-}
-
-bool isTableStructureNode(const Node *node)
-{
- RenderObject *r = node->renderer();
- return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
-}
-
-const String& nonBreakingSpaceString()
-{
- static String nonBreakingSpaceString = String(&noBreakSpace, 1);
- return nonBreakingSpaceString;
-}
-
-// FIXME: need to dump this
-bool isSpecialElement(const Node *n)
-{
- if (!n)
- return false;
-
- if (!n->isHTMLElement())
- return false;
-
- if (n->isLink())
- return true;
-
- RenderObject *renderer = n->renderer();
- if (!renderer)
- return false;
-
- if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
- return true;
-
- if (renderer->style()->isFloating())
- return true;
-
- if (renderer->style()->position() != StaticPosition)
- return true;
-
- return false;
-}
-
-// Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
-bool validBlockTag(const String& blockTag)
-{
- if (blockTag == "address" ||
- blockTag == "blockquote" ||
- blockTag == "dd" ||
- blockTag == "div" ||
- blockTag == "dl" ||
- blockTag == "dt" ||
- blockTag == "h1" ||
- blockTag == "h2" ||
- blockTag == "h3" ||
- blockTag == "h4" ||
- blockTag == "h5" ||
- blockTag == "h6" ||
- blockTag == "p" ||
- blockTag == "pre")
- return true;
- return false;
-}
-
-static Node* firstInSpecialElement(const Position& pos)
-{
- Node* rootEditableElement = pos.node()->rootEditableElement();
- for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
- if (isSpecialElement(n)) {
- VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
- VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
- if (isTableElement(n) && vPos == firstInElement.next())
- return n;
- if (vPos == firstInElement)
- return n;
- }
- return 0;
-}
-
-static Node* lastInSpecialElement(const Position& pos)
-{
- Node* rootEditableElement = pos.node()->rootEditableElement();
- for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
- if (isSpecialElement(n)) {
- VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
- VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
- if (isTableElement(n) && vPos == lastInElement.previous())
- return n;
- if (vPos == lastInElement)
- return n;
- }
- return 0;
-}
-
-bool isFirstVisiblePositionInSpecialElement(const Position& pos)
-{
- return firstInSpecialElement(pos);
-}
-
-Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
-{
- Node* n = firstInSpecialElement(pos);
- if (!n)
- return pos;
- Position result = positionBeforeNode(n);
- if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
- return pos;
- if (containingSpecialElement)
- *containingSpecialElement = n;
- return result;
-}
-
-bool isLastVisiblePositionInSpecialElement(const Position& pos)
-{
- return lastInSpecialElement(pos);
-}
-
-Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
-{
- Node* n = lastInSpecialElement(pos);
- if (!n)
- return pos;
- Position result = positionAfterNode(n);
- if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
- return pos;
- if (containingSpecialElement)
- *containingSpecialElement = n;
- return result;
-}
-
-Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
-{
- if (isFirstVisiblePositionInSpecialElement(pos))
- return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
- if (isLastVisiblePositionInSpecialElement(pos))
- return positionAfterContainingSpecialElement(pos, containingSpecialElement);
- return pos;
-}
-
-Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
-{
- Position upstream(visiblePosition.deepEquivalent().upstream());
- if (upstream.node() && upstream.node()->renderer() && upstream.node()->renderer()->isTable() && upstream.offset() == maxDeepOffset(upstream.node()))
- return upstream.node();
-
- return 0;
-}
-
-Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
-{
- Position downstream(visiblePosition.deepEquivalent().downstream());
- if (downstream.node() && downstream.node()->renderer() && downstream.node()->renderer()->isTable() && downstream.offset() == 0)
- return downstream.node();
-
- return 0;
-}
-
-Position positionBeforeNode(const Node *node)
-{
- return Position(node->parentNode(), node->nodeIndex());
-}
-
-Position positionAfterNode(const Node *node)
-{
- return Position(node->parentNode(), node->nodeIndex() + 1);
-}
-
-bool isListElement(Node *n)
-{
- return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
-}
-
-Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
-{
- if (p.isNull())
- return 0;
-
- Node* root = highestEditableRoot(p);
- for (Node* n = p.node(); n; n = n->parentNode()) {
- if (root && !isContentEditable(n))
- continue;
- if (n->hasTagName(tagName))
- return n;
- if (n == root)
- return 0;
- }
-
- return 0;
-}
-
-Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes)
-{
- if (p.isNull())
- return 0;
-
- Node* root = highestEditableRoot(p);
- for (Node* n = p.node(); n; n = n->parentNode()) {
- // Don't return a non-editable node if the input position was editable, since
- // the callers from editing will no doubt want to perform editing inside the returned node.
- if (root && !isContentEditable(n) && onlyReturnEditableNodes)
- continue;
- if ((*nodeIsOfType)(n))
- return n;
- if (n == root)
- return 0;
- }
-
- return 0;
-}
-
-Node* enclosingTableCell(const Position& p)
-{
- return enclosingNodeOfType(p, &isTableCell);
-}
-
-Node* enclosingAnchorElement(const Position& p)
-{
- if (p.isNull())
- return 0;
-
- Node* node = p.node();
- while (node && !(node->isElementNode() && node->isLink()))
- node = node->parentNode();
- return node;
-}
-
-Node* enclosingList(Node* node)
-{
- if (!node)
- return 0;
-
- Node* root = highestEditableRoot(Position(node, 0));
-
- for (Node* n = node->parentNode(); n; n = n->parentNode()) {
- if (n->hasTagName(ulTag) || n->hasTagName(olTag))
- return n;
- if (n == root)
- return 0;
- }
-
- return 0;
-}
-
-Node* enclosingListChild(Node *node)
-{
- if (!node)
- return 0;
- // Check for a list item element, or for a node whose parent is a list element. Such a node
- // will appear visually as a list item (but without a list marker)
- Node* root = highestEditableRoot(Position(node, 0));
-
- // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
- for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
- if (n->hasTagName(liTag) || isListElement(n->parentNode()))
- return n;
- if (n == root || isTableCell(n))
- return 0;
- }
-
- return 0;
-}
-
-static Node* embeddedSublist(Node* listItem)
-{
- // Check the DOM so that we'll find collapsed sublists without renderers.
- for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
- if (isListElement(n))
- return n;
- }
-
- return 0;
-}
-
-static Node* appendedSublist(Node* listItem)
-{
- // Check the DOM so that we'll find collapsed sublists without renderers.
- for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
- if (isListElement(n))
- return n;
- if (n->renderer() && n->renderer()->isListItem())
- return 0;
- }
-
- return 0;
-}
-
-Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
-{
- // Check that position is on a line by itself inside a list item
- Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
- if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
- return 0;
-
- VisiblePosition firstInListChild(Position(listChildNode, 0));
- VisiblePosition lastInListChild(Position(listChildNode, maxDeepOffset(listChildNode)));
-
- if (firstInListChild != visiblePos || lastInListChild != visiblePos)
- return 0;
-
- if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
- return 0;
-
- return listChildNode;
-}
-
-Node* outermostEnclosingListChild(Node* node)
-{
- Node* listNode = 0;
- Node* nextNode = node;
- while ((nextNode = enclosingListChild(nextNode)))
- listNode = nextNode;
- return listNode;
-}
-
-Node* outermostEnclosingList(Node* node)
-{
- Node* listNode = 0;
- Node* nextNode = node;
- while ((nextNode = enclosingList(nextNode)))
- listNode = nextNode;
- return listNode;
-}
-
-Node* highestAncestor(Node* node)
-{
- ASSERT(node);
- Node* parent = node;
- while ((node = node->parentNode()))
- parent = node;
- return parent;
-}
-
-// FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
-bool isTableElement(Node* n)
-{
- if (!n || !n->isElementNode())
- return false;
-
- RenderObject* renderer = n->renderer();
- return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
-}
-
-bool isTableCell(const Node* node)
-{
- RenderObject* r = node->renderer();
- if (!r)
- return node->hasTagName(tdTag) || node->hasTagName(thTag);
-
- return r->isTableCell();
-}
-
-PassRefPtr<Element> createDefaultParagraphElement(Document *document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "div", ec);
- ASSERT(ec == 0);
- return element.release();
-}
-
-PassRefPtr<Element> createBreakElement(Document *document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
- ASSERT(ec == 0);
- return breakNode.release();
-}
-
-PassRefPtr<Element> createOrderedListElement(Document *document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ol", ec);
- ASSERT(ec == 0);
- return element.release();
-}
-
-PassRefPtr<Element> createUnorderedListElement(Document *document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ul", ec);
- ASSERT(ec == 0);
- return element.release();
-}
-
-PassRefPtr<Element> createListItemElement(Document *document)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "li", ec);
- ASSERT(ec == 0);
- return breakNode.release();
-}
-
-PassRefPtr<Element> createElement(Document* document, const String& tagName)
-{
- ExceptionCode ec = 0;
- RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
- ASSERT(ec == 0);
- return breakNode.release();
-}
-
-bool isTabSpanNode(const Node *node)
-{
- return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass;
-}
-
-bool isTabSpanTextNode(const Node *node)
-{
- return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
-}
-
-Node *tabSpanNode(const Node *node)
-{
- return isTabSpanTextNode(node) ? node->parentNode() : 0;
-}
-
-Position positionBeforeTabSpan(const Position& pos)
-{
- Node *node = pos.node();
- if (isTabSpanTextNode(node))
- node = tabSpanNode(node);
- else if (!isTabSpanNode(node))
- return pos;
-
- return positionBeforeNode(node);
-}
-
-PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode)
-{
- // make the span to hold the tab
- ExceptionCode ec = 0;
- RefPtr<Element> spanElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
- ASSERT(ec == 0);
- spanElement->setAttribute(classAttr, AppleTabSpanClass);
- spanElement->setAttribute(styleAttr, "white-space:pre");
-
- // add tab text to that span
- if (!tabTextNode)
- tabTextNode = document->createEditingTextNode("\t");
- spanElement->appendChild(tabTextNode, ec);
- ASSERT(ec == 0);
-
- return spanElement.release();
-}
-
-PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
-{
- return createTabSpanElement(document, document->createTextNode(tabText));
-}
-
-PassRefPtr<Element> createTabSpanElement(Document* document)
-{
- return createTabSpanElement(document, PassRefPtr<Node>());
-}
-
-bool isNodeRendered(const Node *node)
-{
- if (!node)
- return false;
-
- RenderObject *renderer = node->renderer();
- if (!renderer)
- return false;
-
- return renderer->style()->visibility() == VISIBLE;
-}
-
-Node *nearestMailBlockquote(const Node *node)
-{
- for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
- if (isMailBlockquote(n))
- return n;
- }
- return 0;
-}
-
-bool isMailBlockquote(const Node *node)
-{
- if (!node || !node->isElementNode() && !node->hasTagName(blockquoteTag))
- return false;
-
- return static_cast<const Element *>(node)->getAttribute("type") == "cite";
-}
-
-int caretMinOffset(const Node* n)
-{
- RenderObject* r = n->renderer();
- ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
- return r ? r->caretMinOffset() : 0;
-}
-
-int caretMaxOffset(const Node* n)
-{
- RenderObject* r = n->renderer();
- ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
- if (r)
- return r->caretMaxOffset();
-
- if (n->isCharacterDataNode()) {
- const CharacterData* c = static_cast<const CharacterData*>(n);
- return static_cast<int>(c->length());
- }
- return 1;
-}
-
-bool lineBreakExistsAtPosition(const VisiblePosition& visiblePosition)
-{
- if (visiblePosition.isNull())
- return false;
-
- Position downstream(visiblePosition.deepEquivalent().downstream());
- return downstream.node()->hasTagName(brTag) ||
- downstream.node()->isTextNode() && downstream.node()->renderer()->style()->preserveNewline() && visiblePosition.characterAfter() == '\n';
-}
-
-// Modifies selections that have an end point at the edge of a table
-// that contains the other endpoint so that they don't confuse
-// code that iterates over selected paragraphs.
-Selection selectionForParagraphIteration(const Selection& original)
-{
- Selection newSelection(original);
- VisiblePosition startOfSelection(newSelection.visibleStart());
- VisiblePosition endOfSelection(newSelection.visibleEnd());
-
- // If the end of the selection to modify is just after a table, and
- // if the start of the selection is inside that table, then the last paragraph
- // that we'll want modify is the last one inside the table, not the table itself
- // (a table is itself a paragraph).
- if (Node* table = isFirstPositionAfterTable(endOfSelection))
- if (startOfSelection.deepEquivalent().node()->isDescendantOf(table))
- newSelection = Selection(startOfSelection, endOfSelection.previous(true));
-
- // If the start of the selection to modify is just before a table,
- // and if the end of the selection is inside that table, then the first paragraph
- // we'll want to modify is the first one inside the table, not the paragraph
- // containing the table itself.
- if (Node* table = isLastPositionBeforeTable(startOfSelection))
- if (endOfSelection.deepEquivalent().node()->isDescendantOf(table))
- newSelection = Selection(startOfSelection.next(true), endOfSelection);
-
- return newSelection;
-}
-
-
-int indexForVisiblePosition(VisiblePosition& visiblePosition)
-{
- if (visiblePosition.isNull())
- return 0;
- Position p(visiblePosition.deepEquivalent());
- RefPtr<Range> range = Range::create(p.node()->document(), Position(p.node()->document(), 0), rangeCompliantEquivalent(p));
- return TextIterator::rangeLength(range.get(), true);
-}
-
-PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
-{
- if (!range)
- return 0;
-
- Document* document = range->ownerDocument();
-
- Node* startContainer = range->startContainer();
- int startOffset = range->startOffset();
- Node* endContainer = range->endContainer();
- int endOffset = range->endOffset();
-
- if (!startContainer)
- return 0;
-
- ASSERT(endContainer);
-
- if (startContainer == node || startContainer->isDescendantOf(node)) {
- ASSERT(node->parentNode());
- startContainer = node->parentNode();
- startOffset = node->nodeIndex();
- }
- if (endContainer == node || endContainer->isDescendantOf(node)) {
- ASSERT(node->parentNode());
- endContainer = node->parentNode();
- endOffset = node->nodeIndex();
- }
-
- return Range::create(document, startContainer, startOffset, endContainer, endOffset);
-}
-
-Selection avoidIntersectionWithNode(const Selection& selection, Node* node)
-{
- if (selection.isNone())
- return Selection(selection);
-
- Selection updatedSelection(selection);
- Node* base = selection.base().node();
- Node* extent = selection.extent().node();
- ASSERT(base);
- ASSERT(extent);
-
- if (base == node || base->isDescendantOf(node)) {
- ASSERT(node->parentNode());
- updatedSelection.setBase(Position(node->parentNode(), node->nodeIndex()));
- }
-
- if (extent == node || extent->isDescendantOf(node)) {
- ASSERT(node->parentNode());
- updatedSelection.setExtent(Position(node->parentNode(), node->nodeIndex()));
- }
-
- return updatedSelection;
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/htmlediting.h b/WebCore/editing/htmlediting.h
deleted file mode 100644
index 84d3434..0000000
--- a/WebCore/editing/htmlediting.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef htmlediting_h
-#define htmlediting_h
-
-#include <wtf/Forward.h>
-#include "HTMLNames.h"
-
-namespace WebCore {
-
-class Document;
-class Element;
-class Node;
-class Position;
-class Range;
-class Selection;
-class String;
-class VisiblePosition;
-
-Position rangeCompliantEquivalent(const Position&);
-Position rangeCompliantEquivalent(const VisiblePosition&);
-int maxDeepOffset(const Node*);
-bool isAtomicNode(const Node*);
-bool editingIgnoresContent(const Node*);
-bool canHaveChildrenForEditing(const Node*);
-Node* highestEditableRoot(const Position&);
-VisiblePosition firstEditablePositionAfterPositionInRoot(const Position&, Node*);
-VisiblePosition lastEditablePositionBeforePositionInRoot(const Position&, Node*);
-int comparePositions(const Position&, const Position&);
-Node* lowestEditableAncestor(Node*);
-bool isContentEditable(const Node*);
-Position nextCandidate(const Position&);
-Position nextVisuallyDistinctCandidate(const Position&);
-Position previousCandidate(const Position&);
-Position previousVisuallyDistinctCandidate(const Position&);
-bool isEditablePosition(const Position&);
-bool isRichlyEditablePosition(const Position&);
-Element* editableRootForPosition(const Position&);
-bool isBlock(const Node*);
-Node* enclosingBlock(Node*);
-
-String stringWithRebalancedWhitespace(const String&, bool, bool);
-const String& nonBreakingSpaceString();
-
-//------------------------------------------------------------------------------------------
-
-Position positionBeforeNode(const Node*);
-Position positionAfterNode(const Node*);
-
-PassRefPtr<Range> avoidIntersectionWithNode(const Range*, Node*);
-Selection avoidIntersectionWithNode(const Selection&, Node*);
-
-bool isSpecialElement(const Node*);
-bool validBlockTag(const String&);
-
-PassRefPtr<Element> createDefaultParagraphElement(Document*);
-PassRefPtr<Element> createBreakElement(Document*);
-PassRefPtr<Element> createOrderedListElement(Document*);
-PassRefPtr<Element> createUnorderedListElement(Document*);
-PassRefPtr<Element> createListItemElement(Document*);
-PassRefPtr<Element> createElement(Document*, const String&);
-
-bool isTabSpanNode(const Node*);
-bool isTabSpanTextNode(const Node*);
-Node* tabSpanNode(const Node*);
-Position positionBeforeTabSpan(const Position&);
-PassRefPtr<Element> createTabSpanElement(Document*);
-PassRefPtr<Element> createTabSpanElement(Document*, PassRefPtr<Node> tabTextNode);
-PassRefPtr<Element> createTabSpanElement(Document*, const String& tabText);
-
-bool isNodeRendered(const Node*);
-bool isMailBlockquote(const Node*);
-Node* nearestMailBlockquote(const Node*);
-int caretMinOffset(const Node*);
-int caretMaxOffset(const Node*);
-
-//------------------------------------------------------------------------------------------
-
-bool isTableStructureNode(const Node*);
-PassRefPtr<Element> createBlockPlaceholderElement(Document*);
-
-bool isFirstVisiblePositionInSpecialElement(const Position&);
-Position positionBeforeContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
-bool isLastVisiblePositionInSpecialElement(const Position&);
-Position positionAfterContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
-Position positionOutsideContainingSpecialElement(const Position&, Node** containingSpecialElement=0);
-Node* isLastPositionBeforeTable(const VisiblePosition&);
-Node* isFirstPositionAfterTable(const VisiblePosition&);
-
-Node* enclosingNodeWithTag(const Position&, const QualifiedName&);
-Node* enclosingNodeOfType(const Position&, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes = true);
-Node* enclosingTableCell(const Position&);
-Node* enclosingEmptyListItem(const VisiblePosition&);
-Node* enclosingAnchorElement(const Position&);
-bool isListElement(Node*);
-Node* enclosingList(Node*);
-Node* outermostEnclosingList(Node*);
-Node* enclosingListChild(Node*);
-Node* highestAncestor(Node*);
-bool isTableElement(Node*);
-bool isTableCell(const Node*);
-
-bool lineBreakExistsAtPosition(const VisiblePosition&);
-
-Selection selectionForParagraphIteration(const Selection&);
-
-int indexForVisiblePosition(VisiblePosition&);
-
-}
-
-#endif
diff --git a/WebCore/editing/mac/EditorMac.mm b/WebCore/editing/mac/EditorMac.mm
deleted file mode 100644
index b98fc00..0000000
--- a/WebCore/editing/mac/EditorMac.mm
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "Editor.h"
-
-#import "ClipboardMac.h"
-#import "DocLoader.h"
-#import "Frame.h"
-#import "FrameView.h"
-
-namespace WebCore {
-
-extern "C" {
-
-// Kill ring calls. Would be better to use NSKillRing.h, but that's not available as API or SPI.
-
-void _NSInitializeKillRing();
-void _NSAppendToKillRing(NSString *);
-void _NSPrependToKillRing(NSString *);
-NSString *_NSYankFromKillRing();
-void _NSNewKillRingSequence();
-void _NSSetKillRingToYankedState();
-
-}
-
-PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
-{
- return ClipboardMac::create(false, [NSPasteboard generalPasteboard], policy, 0);
-}
-
-static void initializeKillRingIfNeeded()
-{
- static bool initializedKillRing = false;
- if (!initializedKillRing) {
- initializedKillRing = true;
- _NSInitializeKillRing();
- }
-}
-
-void Editor::appendToKillRing(const String& string)
-{
- initializeKillRingIfNeeded();
- _NSAppendToKillRing(string);
-}
-
-void Editor::prependToKillRing(const String& string)
-{
- initializeKillRingIfNeeded();
- _NSPrependToKillRing(string);
-}
-
-String Editor::yankFromKillRing()
-{
- initializeKillRingIfNeeded();
- return _NSYankFromKillRing();
-}
-
-void Editor::startNewKillRingSequence()
-{
- initializeKillRingIfNeeded();
- _NSNewKillRingSequence();
-}
-
-void Editor::setKillRingToYankedState()
-{
- initializeKillRingIfNeeded();
- _NSSetKillRingToYankedState();
-}
-
-void Editor::showFontPanel()
-{
- [[NSFontManager sharedFontManager] orderFrontFontPanel:nil];
-}
-
-void Editor::showStylesPanel()
-{
- [[NSFontManager sharedFontManager] orderFrontStylesPanel:nil];
-}
-
-void Editor::showColorPanel()
-{
- [[NSApplication sharedApplication] orderFrontColorPanel:nil];
-}
-
-// FIXME: We want to use the platform-independent code instead. But when we last
-// tried to do so it seemed that we first need to move more of the logic from
-// -[WebHTMLView.cpp _documentFragmentFromPasteboard] into PasteboardMac.
-
-void Editor::paste()
-{
- ASSERT(m_frame->document());
- FrameView* view = m_frame->view();
- if (!view)
- return;
- DocLoader* loader = m_frame->document()->docLoader();
- loader->setAllowStaleResources(true);
- [view->documentView() tryToPerform:@selector(paste:) with:nil];
- loader->setAllowStaleResources(false);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/mac/SelectionControllerMac.mm b/WebCore/editing/mac/SelectionControllerMac.mm
deleted file mode 100644
index e07024a..0000000
--- a/WebCore/editing/mac/SelectionControllerMac.mm
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "SelectionController.h"
-
-#import "AXObjectCache.h"
-#import "Document.h"
-#import "Frame.h"
-#import "FrameView.h"
-#import "RenderView.h"
-#import "Selection.h"
-
-#import <ApplicationServices/ApplicationServices.h>
-
-namespace WebCore {
-
-void SelectionController::notifyAccessibilityForSelectionChange()
-{
- if (AXObjectCache::accessibilityEnabled() && m_sel.start().isNotNull() && m_sel.end().isNotNull())
- m_frame->document()->axObjectCache()->postNotification(m_sel.start().node()->renderer(), "AXSelectedTextChanged");
-
- // if zoom feature is enabled, insertion point changes should update the zoom
- if (UAZoomEnabled() && m_sel.isCaret() && m_sel.start().node()) {
- RenderView *renderView = static_cast<RenderView*>(m_sel.start().node()->renderer());
- if (renderView) {
- IntRect selectionRect = caretRect();
- IntRect viewRect = renderView->viewRect();
- FrameView* frameView = renderView->view()->frameView();
- if (frameView) {
- selectionRect = frameView->contentsToScreen(selectionRect);
- viewRect = frameView->contentsToScreen(viewRect);
- CGRect cgCaretRect = CGRectMake(selectionRect.x(), selectionRect.y(), selectionRect.width(), selectionRect.height());
- CGRect cgViewRect = CGRectMake(viewRect.x(), viewRect.y(), viewRect.width(), viewRect.height());
- (void)UAZoomChangeFocus(&cgViewRect, &cgCaretRect, kUAZoomFocusTypeInsertionPoint);
- }
- }
- }
-}
-
-
-} // namespace WebCore
diff --git a/WebCore/editing/markup.cpp b/WebCore/editing/markup.cpp
deleted file mode 100644
index b067002..0000000
--- a/WebCore/editing/markup.cpp
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "markup.h"
-
-#include "CDATASection.h"
-#include "CharacterNames.h"
-#include "Comment.h"
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSPrimitiveValue.h"
-#include "CSSProperty.h"
-#include "CSSPropertyNames.h"
-#include "CSSRule.h"
-#include "CSSRuleList.h"
-#include "CSSStyleRule.h"
-#include "CSSStyleSelector.h"
-#include "CSSValue.h"
-#include "CSSValueKeywords.h"
-#include "DeleteButtonController.h"
-#include "Document.h"
-#include "DocumentFragment.h"
-#include "DocumentType.h"
-#include "Editor.h"
-#include "Frame.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "InlineTextBox.h"
-#include "Logging.h"
-#include "ProcessingInstruction.h"
-#include "QualifiedName.h"
-#include "Range.h"
-#include "Selection.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-static inline bool shouldSelfClose(const Node *node);
-
-class AttributeChange {
-public:
- AttributeChange()
- : m_name(nullAtom, nullAtom, nullAtom)
- {
- }
-
- AttributeChange(PassRefPtr<Element> element, const QualifiedName& name, const String& value)
- : m_element(element), m_name(name), m_value(value)
- {
- }
-
- void apply()
- {
- m_element->setAttribute(m_name, m_value);
- }
-
-private:
- RefPtr<Element> m_element;
- QualifiedName m_name;
- String m_value;
-};
-
-static void appendAttributeValue(Vector<UChar>& result, const String& attr, bool escapeNBSP)
-{
- const UChar* uchars = attr.characters();
- unsigned len = attr.length();
- unsigned lastCopiedFrom = 0;
-
- static const String ampEntity("&amp;");
- static const String gtEntity("&gt;");
- static const String ltEntity("&lt;");
- static const String quotEntity("&quot;");
- static const String nbspEntity("&nbsp;");
-
- for (unsigned i = 0; i < len; ++i) {
- UChar c = uchars[i];
- switch (c) {
- case '&':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, ampEntity);
- lastCopiedFrom = i + 1;
- break;
- case '<':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, ltEntity);
- lastCopiedFrom = i + 1;
- break;
- case '>':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, gtEntity);
- lastCopiedFrom = i + 1;
- break;
- case '"':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, quotEntity);
- lastCopiedFrom = i + 1;
- break;
- case noBreakSpace:
- if (escapeNBSP) {
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, nbspEntity);
- lastCopiedFrom = i + 1;
- }
- break;
- }
- }
-
- result.append(uchars + lastCopiedFrom, len - lastCopiedFrom);
-}
-
-static void appendEscapedContent(Vector<UChar>& result, pair<const UChar*, size_t> range, bool escapeNBSP)
-{
- const UChar* uchars = range.first;
- unsigned len = range.second;
- unsigned lastCopiedFrom = 0;
-
- static const String ampEntity("&amp;");
- static const String gtEntity("&gt;");
- static const String ltEntity("&lt;");
- static const String nbspEntity("&nbsp;");
-
- for (unsigned i = 0; i < len; ++i) {
- UChar c = uchars[i];
- switch (c) {
- case '&':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, ampEntity);
- lastCopiedFrom = i + 1;
- break;
- case '<':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, ltEntity);
- lastCopiedFrom = i + 1;
- break;
- case '>':
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, gtEntity);
- lastCopiedFrom = i + 1;
- break;
- case noBreakSpace:
- if (escapeNBSP) {
- result.append(uchars + lastCopiedFrom, i - lastCopiedFrom);
- append(result, nbspEntity);
- lastCopiedFrom = i + 1;
- }
- break;
- }
- }
-
- result.append(uchars + lastCopiedFrom, len - lastCopiedFrom);
-}
-
-static String escapeContentText(const String& in, bool escapeNBSP)
-{
- Vector<UChar> buffer;
- appendEscapedContent(buffer, make_pair(in.characters(), in.length()), escapeNBSP);
- return String::adopt(buffer);
-}
-
-static void appendQuotedURLAttributeValue(Vector<UChar>& result, const String& urlString)
-{
- UChar quoteChar = '\"';
- String strippedURLString = urlString.stripWhiteSpace();
- if (protocolIs(strippedURLString, "javascript")) {
- // minimal escaping for javascript urls
- if (strippedURLString.contains('"')) {
- if (strippedURLString.contains('\''))
- strippedURLString.replace('\"', "&quot;");
- else
- quoteChar = '\'';
- }
- result.append(quoteChar);
- append(result, strippedURLString);
- result.append(quoteChar);
- return;
- }
-
- // FIXME: This does not fully match other browsers. Firefox percent-escapes non-ASCII characters for innerHTML.
- result.append(quoteChar);
- appendAttributeValue(result, urlString, false);
- result.append(quoteChar);
-}
-
-static String stringValueForRange(const Node* node, const Range* range)
-{
- if (!range)
- return node->nodeValue();
-
- String str = node->nodeValue();
- ExceptionCode ec;
- if (node == range->endContainer(ec))
- str.truncate(range->endOffset(ec));
- if (node == range->startContainer(ec))
- str.remove(0, range->startOffset(ec));
- return str;
-}
-
-static inline pair<const UChar*, size_t> ucharRange(const Node *node, const Range *range)
-{
- String str = node->nodeValue();
- const UChar* characters = str.characters();
- size_t length = str.length();
-
- if (range) {
- ExceptionCode ec;
- if (node == range->endContainer(ec))
- length = range->endOffset(ec);
- if (node == range->startContainer(ec)) {
- size_t start = range->startOffset(ec);
- characters += start;
- length -= start;
- }
- }
-
- return make_pair(characters, length);
-}
-
-static inline void appendUCharRange(Vector<UChar>& result, const pair<const UChar*, size_t> range)
-{
- result.append(range.first, range.second);
-}
-
-static String renderedText(const Node* node, const Range* range)
-{
- if (!node->isTextNode())
- return String();
-
- ExceptionCode ec;
- const Text* textNode = static_cast<const Text*>(node);
- unsigned startOffset = 0;
- unsigned endOffset = textNode->length();
-
- if (range && node == range->startContainer(ec))
- startOffset = range->startOffset(ec);
- if (range && node == range->endContainer(ec))
- endOffset = range->endOffset(ec);
-
- Position start(const_cast<Node*>(node), startOffset);
- Position end(const_cast<Node*>(node), endOffset);
- return plainText(Range::create(node->document(), start, end).get());
-}
-
-static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesForElement(Element* element, bool authorOnly = true)
-{
- RefPtr<CSSMutableStyleDeclaration> style = CSSMutableStyleDeclaration::create();
- RefPtr<CSSRuleList> matchedRules = element->document()->styleSelector()->styleRulesForElement(element, authorOnly);
- if (matchedRules) {
- for (unsigned i = 0; i < matchedRules->length(); i++) {
- if (matchedRules->item(i)->type() == CSSRule::STYLE_RULE) {
- RefPtr<CSSMutableStyleDeclaration> s = static_cast<CSSStyleRule*>(matchedRules->item(i))->style();
- style->merge(s.get(), true);
- }
- }
- }
-
- return style.release();
-}
-
-static void removeEnclosingMailBlockquoteStyle(CSSMutableStyleDeclaration* style, Node* node)
-{
- Node* blockquote = nearestMailBlockquote(node);
- if (!blockquote || !blockquote->parentNode())
- return;
-
- RefPtr<CSSMutableStyleDeclaration> parentStyle = Position(blockquote->parentNode(), 0).computedStyle()->copyInheritableProperties();
- RefPtr<CSSMutableStyleDeclaration> blockquoteStyle = Position(blockquote, 0).computedStyle()->copyInheritableProperties();
- parentStyle->diff(blockquoteStyle.get());
- blockquoteStyle->diff(style);
-}
-
-static void removeDefaultStyles(CSSMutableStyleDeclaration* style, Document* document)
-{
- if (!document || !document->documentElement())
- return;
-
- RefPtr<CSSMutableStyleDeclaration> documentStyle = computedStyle(document->documentElement())->copyInheritableProperties();
- documentStyle->diff(style);
-}
-
-static bool shouldAddNamespaceElem(const Element* elem)
-{
- // Don't add namespace attribute if it is already defined for this elem.
- const AtomicString& prefix = elem->prefix();
- AtomicString attr = !prefix.isEmpty() ? "xmlns:" + prefix : "xmlns";
- return !elem->hasAttribute(attr);
-}
-
-static bool shouldAddNamespaceAttr(const Attribute* attr, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
-{
- // Don't add namespace attributes twice
- static const AtomicString xmlnsURI = "http://www.w3.org/2000/xmlns/";
- static const QualifiedName xmlnsAttr(nullAtom, "xmlns", xmlnsURI);
- if (attr->name() == xmlnsAttr) {
- namespaces.set(emptyAtom.impl(), attr->value().impl());
- return false;
- }
-
- QualifiedName xmlnsPrefixAttr("xmlns", attr->localName(), xmlnsURI);
- if (attr->name() == xmlnsPrefixAttr) {
- namespaces.set(attr->localName().impl(), attr->value().impl());
- return false;
- }
-
- return true;
-}
-
-static void appendNamespace(Vector<UChar>& result, const AtomicString& prefix, const AtomicString& ns, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
-{
- if (ns.isEmpty())
- return;
-
- // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key
- AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl();
- AtomicStringImpl* foundNS = namespaces.get(pre);
- if (foundNS != ns.impl()) {
- namespaces.set(pre, ns.impl());
- static const String xmlns("xmlns");
- result.append(' ');
- append(result, xmlns);
- if (!prefix.isEmpty()) {
- result.append(':');
- append(result, prefix);
- }
-
- result.append('=');
- result.append('"');
- appendAttributeValue(result, ns, false);
- result.append('"');
- }
-}
-
-static void appendDocumentType(Vector<UChar>& result, const DocumentType* n)
-{
- if (n->name().isEmpty())
- return;
-
- append(result, "<!DOCTYPE ");
- append(result, n->name());
- if (!n->publicId().isEmpty()) {
- append(result, " PUBLIC \"");
- append(result, n->publicId());
- append(result, "\"");
- if (!n->systemId().isEmpty()) {
- append(result, " \"");
- append(result, n->systemId());
- append(result, "\"");
- }
- } else if (!n->systemId().isEmpty()) {
- append(result, " SYSTEM \"");
- append(result, n->systemId());
- append(result, "\"");
- }
- if (!n->internalSubset().isEmpty()) {
- append(result, " [");
- append(result, n->internalSubset());
- append(result, "]");
- }
- append(result, ">");
-}
-
-static void appendStartMarkup(Vector<UChar>& result, const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
-{
- bool documentIsHTML = node->document()->isHTMLDocument();
- switch (node->nodeType()) {
- case Node::TEXT_NODE: {
- if (Node* parent = node->parentNode()) {
- if (parent->hasTagName(scriptTag)
- || parent->hasTagName(styleTag)
- || parent->hasTagName(textareaTag)
- || parent->hasTagName(xmpTag)) {
- appendUCharRange(result, ucharRange(node, range));
- break;
- }
- }
- if (!annotate) {
- appendEscapedContent(result, ucharRange(node, range), documentIsHTML);
- break;
- }
-
- bool useRenderedText = !enclosingNodeWithTag(Position(const_cast<Node*>(node), 0), selectTag);
- String markup = escapeContentText(useRenderedText ? renderedText(node, range) : stringValueForRange(node, range), false);
- if (annotate)
- markup = convertHTMLTextToInterchangeFormat(markup, static_cast<const Text*>(node));
- append(result, markup);
- break;
- }
- case Node::COMMENT_NODE:
- // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->".
- append(result, "<!--");
- append(result, static_cast<const Comment*>(node)->nodeValue());
- append(result, "-->");
- break;
- case Node::DOCUMENT_NODE:
- case Node::DOCUMENT_FRAGMENT_NODE:
- break;
- case Node::DOCUMENT_TYPE_NODE:
- appendDocumentType(result, static_cast<const DocumentType*>(node));
- break;
- case Node::PROCESSING_INSTRUCTION_NODE: {
- // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>".
- const ProcessingInstruction* n = static_cast<const ProcessingInstruction*>(node);
- append(result, "<?");
- append(result, n->target());
- append(result, " ");
- append(result, n->data());
- append(result, "?>");
- break;
- }
- case Node::ELEMENT_NODE: {
- result.append('<');
- const Element* el = static_cast<const Element*>(node);
- bool convert = convertBlocksToInlines & isBlock(const_cast<Node*>(node));
- append(result, el->nodeNamePreservingCase());
- NamedAttrMap *attrs = el->attributes();
- unsigned length = attrs->length();
- if (!documentIsHTML && namespaces && shouldAddNamespaceElem(el))
- appendNamespace(result, el->prefix(), el->namespaceURI(), *namespaces);
-
- for (unsigned int i = 0; i < length; i++) {
- Attribute *attr = attrs->attributeItem(i);
- // We'll handle the style attribute separately, below.
- if (attr->name() == styleAttr && el->isHTMLElement() && (annotate || convert))
- continue;
- result.append(' ');
-
- if (documentIsHTML)
- append(result, attr->name().localName());
- else
- append(result, attr->name().toString());
-
- result.append('=');
-
- if (el->isURLAttribute(attr))
- appendQuotedURLAttributeValue(result, attr->value());
- else {
- result.append('\"');
- appendAttributeValue(result, attr->value(), documentIsHTML);
- result.append('\"');
- }
-
- if (!documentIsHTML && namespaces && shouldAddNamespaceAttr(attr, *namespaces))
- appendNamespace(result, attr->prefix(), attr->namespaceURI(), *namespaces);
- }
-
- if (el->isHTMLElement() && (annotate || convert)) {
- Element* element = const_cast<Element*>(el);
- RefPtr<CSSMutableStyleDeclaration> style = static_cast<HTMLElement*>(element)->getInlineStyleDecl()->copy();
- if (annotate) {
- RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(const_cast<Element*>(el));
- // Styles from the inline style declaration, held in the variable "style", take precedence
- // over those from matched rules.
- styleFromMatchedRules->merge(style.get());
- style = styleFromMatchedRules;
-
- RefPtr<CSSComputedStyleDeclaration> computedStyleForElement = computedStyle(element);
- RefPtr<CSSMutableStyleDeclaration> fromComputedStyle = CSSMutableStyleDeclaration::create();
-
- DeprecatedValueListConstIterator<CSSProperty> end;
- for (DeprecatedValueListConstIterator<CSSProperty> it = style->valuesIterator(); it != end; ++it) {
- const CSSProperty& property = *it;
- CSSValue* value = property.value();
- // The property value, if it's a percentage, may not reflect the actual computed value.
- // For example: style="height: 1%; overflow: visible;" in quirksmode
- // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem
- if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE)
- if (static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
- if (RefPtr<CSSValue> computedPropertyValue = computedStyleForElement->getPropertyCSSValue(property.id()))
- fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue));
- }
-
- style->merge(fromComputedStyle.get());
- }
- if (convert)
- style->setProperty(CSSPropertyDisplay, CSSValueInline, true);
- if (style->length() > 0) {
- static const String stylePrefix(" style=\"");
- append(result, stylePrefix);
- appendAttributeValue(result, style->cssText(), documentIsHTML);
- result.append('\"');
- }
- }
-
- if (shouldSelfClose(el)) {
- if (el->isHTMLElement())
- result.append(' '); // XHTML 1.0 <-> HTML compatibility.
- result.append('/');
- }
- result.append('>');
- break;
- }
- case Node::CDATA_SECTION_NODE: {
- // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>".
- const CDATASection* n = static_cast<const CDATASection*>(node);
- append(result, "<![CDATA[");
- append(result, n->data());
- append(result, "]]>");
- break;
- }
- case Node::ATTRIBUTE_NODE:
- case Node::ENTITY_NODE:
- case Node::ENTITY_REFERENCE_NODE:
- case Node::NOTATION_NODE:
- case Node::XPATH_NAMESPACE_NODE:
- ASSERT_NOT_REACHED();
- break;
- }
-}
-
-static String getStartMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
-{
- Vector<UChar> result;
- appendStartMarkup(result, node, range, annotate, convertBlocksToInlines, namespaces);
- return String::adopt(result);
-}
-
-static inline bool doesHTMLForbidEndTag(const Node *node)
-{
- if (node->isHTMLElement()) {
- const HTMLElement* htmlElt = static_cast<const HTMLElement*>(node);
- return (htmlElt->endTagRequirement() == TagStatusForbidden);
- }
- return false;
-}
-
-// Rules of self-closure
-// 1. No elements in HTML documents use the self-closing syntax.
-// 2. Elements w/ children never self-close because they use a separate end tag.
-// 3. HTML elements which do not have a "forbidden" end tag will close with a separate end tag.
-// 4. Other elements self-close.
-static inline bool shouldSelfClose(const Node *node)
-{
- if (node->document()->isHTMLDocument())
- return false;
- if (node->hasChildNodes())
- return false;
- if (node->isHTMLElement() && !doesHTMLForbidEndTag(node))
- return false;
- return true;
-}
-
-static void appendEndMarkup(Vector<UChar>& result, const Node* node)
-{
- if (!node->isElementNode() || shouldSelfClose(node) || (!node->hasChildNodes() && doesHTMLForbidEndTag(node)))
- return;
-
- result.append('<');
- result.append('/');
- append(result, static_cast<const Element*>(node)->nodeNamePreservingCase());
- result.append('>');
-}
-
-static String getEndMarkup(const Node *node)
-{
- Vector<UChar> result;
- appendEndMarkup(result, node);
- return String::adopt(result);
-}
-
-static void appendMarkup(Vector<UChar>& result, Node* startNode, bool onlyIncludeChildren, Vector<Node*>* nodes, const HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
-{
- HashMap<AtomicStringImpl*, AtomicStringImpl*> namespaceHash;
- if (namespaces)
- namespaceHash = *namespaces;
-
- if (!onlyIncludeChildren) {
- if (nodes)
- nodes->append(startNode);
-
- appendStartMarkup(result,startNode, 0, DoNotAnnotateForInterchange, false, &namespaceHash);
- }
- // print children
- if (!(startNode->document()->isHTMLDocument() && doesHTMLForbidEndTag(startNode)))
- for (Node* current = startNode->firstChild(); current; current = current->nextSibling())
- appendMarkup(result, current, false, nodes, &namespaceHash);
-
- // Print my ending tag
- if (!onlyIncludeChildren)
- appendEndMarkup(result, startNode);
-}
-
-static void completeURLs(Node* node, const String& baseURL)
-{
- Vector<AttributeChange> changes;
-
- KURL parsedBaseURL(baseURL);
-
- Node* end = node->traverseNextSibling();
- for (Node* n = node; n != end; n = n->traverseNextNode()) {
- if (n->isElementNode()) {
- Element* e = static_cast<Element*>(n);
- NamedAttrMap* attrs = e->attributes();
- unsigned length = attrs->length();
- for (unsigned i = 0; i < length; i++) {
- Attribute* attr = attrs->attributeItem(i);
- if (e->isURLAttribute(attr))
- changes.append(AttributeChange(e, attr->name(), KURL(parsedBaseURL, attr->value()).string()));
- }
- }
- }
-
- size_t numChanges = changes.size();
- for (size_t i = 0; i < numChanges; ++i)
- changes[i].apply();
-}
-
-static bool needInterchangeNewlineAfter(const VisiblePosition& v)
-{
- VisiblePosition next = v.next();
- Node* upstreamNode = next.deepEquivalent().upstream().node();
- Node* downstreamNode = v.deepEquivalent().downstream().node();
- // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.
- return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);
-}
-
-static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesAndInlineDecl(const Node* node)
-{
- if (!node->isHTMLElement())
- return 0;
-
- // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle
- // the non-const-ness of styleFromMatchedRulesForElement.
- HTMLElement* element = const_cast<HTMLElement*>(static_cast<const HTMLElement*>(node));
- RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesForElement(element);
- RefPtr<CSSMutableStyleDeclaration> inlineStyleDecl = element->getInlineStyleDecl();
- style->merge(inlineStyleDecl.get());
- return style.release();
-}
-
-static bool propertyMissingOrEqualToNone(CSSMutableStyleDeclaration* style, int propertyID)
-{
- if (!style)
- return false;
- RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);
- if (!value)
- return true;
- if (!value->isPrimitiveValue())
- return false;
- return static_cast<CSSPrimitiveValue*>(value.get())->getIdent() == CSSValueNone;
-}
-
-static bool elementHasTextDecorationProperty(const Node* node)
-{
- RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesAndInlineDecl(node);
- if (!style)
- return false;
- return !propertyMissingOrEqualToNone(style.get(), CSSPropertyTextDecoration);
-}
-
-String joinMarkups(const Vector<String> preMarkups, const Vector<String>& postMarkups)
-{
- size_t length = 0;
-
- size_t preCount = preMarkups.size();
- for (size_t i = 0; i < preCount; ++i)
- length += preMarkups[i].length();
-
- size_t postCount = postMarkups.size();
- for (size_t i = 0; i < postCount; ++i)
- length += postMarkups[i].length();
-
- Vector<UChar> result;
- result.reserveCapacity(length);
-
- for (size_t i = preCount; i > 0; --i)
- append(result, preMarkups[i - 1]);
-
- for (size_t i = 0; i < postCount; ++i)
- append(result, postMarkups[i]);
-
- return String::adopt(result);
-}
-
-// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange?
-// FIXME: At least, annotation and style info should probably not be included in range.markupString()
-String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange annotate, bool convertBlocksToInlines)
-{
- static const String interchangeNewlineString = String("<br class=\"") + AppleInterchangeNewline + "\">";
-
- if (!range)
- return "";
-
- Document* document = range->ownerDocument();
- if (!document)
- return "";
-
- bool documentIsHTML = document->isHTMLDocument();
-
- // Disable the delete button so it's elements are not serialized into the markup,
- // but make sure neither endpoint is inside the delete user interface.
- Frame* frame = document->frame();
- DeleteButtonController* deleteButton = frame ? frame->editor()->deleteButtonController() : 0;
- RefPtr<Range> updatedRange = avoidIntersectionWithNode(range, deleteButton ? deleteButton->containerElement() : 0);
- if (!updatedRange)
- return "";
-
- if (deleteButton)
- deleteButton->disable();
-
- ExceptionCode ec = 0;
- bool collapsed = updatedRange->collapsed(ec);
- ASSERT(ec == 0);
- if (collapsed)
- return "";
- Node* commonAncestor = updatedRange->commonAncestorContainer(ec);
- ASSERT(ec == 0);
- if (!commonAncestor)
- return "";
-
- document->updateLayoutIgnorePendingStylesheets();
-
- Vector<String> markups;
- Vector<String> preMarkups;
- Node* pastEnd = updatedRange->pastLastNode();
- Node* lastClosed = 0;
- Vector<Node*> ancestorsToClose;
-
- Node* startNode = updatedRange->firstNode();
- VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFINITY);
- VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY);
- if (annotate && needInterchangeNewlineAfter(visibleStart)) {
- if (visibleStart == visibleEnd.previous()) {
- if (deleteButton)
- deleteButton->enable();
- return interchangeNewlineString;
- }
-
- markups.append(interchangeNewlineString);
- startNode = visibleStart.next().deepEquivalent().node();
- }
-
- Node* next;
- for (Node* n = startNode; n != pastEnd; n = next) {
-
- // According to <rdar://problem/5730668>, it is possible for n to blow past pastEnd and become null here. This
- // shouldn't be possible. This null check will prevent crashes (but create too much markup) and the ASSERT will
- // hopefully lead us to understanding the problem.
- ASSERT(n);
- if (!n)
- break;
-
- next = n->traverseNextNode();
- bool skipDescendants = false;
- bool addMarkupForNode = true;
-
- if (!n->renderer() && !enclosingNodeWithTag(Position(n, 0), selectTag)) {
- skipDescendants = true;
- addMarkupForNode = false;
- next = n->traverseNextSibling();
- // Don't skip over pastEnd.
- if (pastEnd && pastEnd->isDescendantOf(n))
- next = pastEnd;
- }
-
- if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)
- // Don't write out empty block containers that aren't fully selected.
- continue;
-
- // Add the node to the markup.
- if (addMarkupForNode) {
- markups.append(getStartMarkup(n, updatedRange.get(), annotate));
- if (nodes)
- nodes->append(n);
- }
-
- if (n->firstChild() == 0 || skipDescendants) {
- // Node has no children, or we are skipping it's descendants, add its close tag now.
- if (addMarkupForNode) {
- markups.append(getEndMarkup(n));
- lastClosed = n;
- }
-
- // Check if the node is the last leaf of a tree.
- if (!n->nextSibling() || next == pastEnd) {
- if (!ancestorsToClose.isEmpty()) {
- // Close up the ancestors.
- do {
- Node *ancestor = ancestorsToClose.last();
- if (next != pastEnd && next->isDescendantOf(ancestor))
- break;
- // Not at the end of the range, close ancestors up to sibling of next node.
- markups.append(getEndMarkup(ancestor));
- lastClosed = ancestor;
- ancestorsToClose.removeLast();
- } while (!ancestorsToClose.isEmpty());
- }
-
- // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.
- Node* nextParent = next ? next->parentNode() : 0;
- if (next != pastEnd && n != nextParent) {
- Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;
- for (Node *parent = lastAncestorClosedOrSelf->parent(); parent != 0 && parent != nextParent; parent = parent->parentNode()) {
- // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:
- if (!parent->renderer())
- continue;
- // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:
- ASSERT(startNode->isDescendantOf(parent));
- preMarkups.append(getStartMarkup(parent, updatedRange.get(), annotate));
- markups.append(getEndMarkup(parent));
- if (nodes)
- nodes->append(parent);
- lastClosed = parent;
- }
- }
- }
- } else if (addMarkupForNode && !skipDescendants)
- // We added markup for this node, and we're descending into it. Set it to close eventually.
- ancestorsToClose.append(n);
- }
-
- // Include ancestors that aren't completely inside the range but are required to retain
- // the structure and appearance of the copied markup.
- Node* specialCommonAncestor = 0;
- Node* commonAncestorBlock = commonAncestor ? enclosingBlock(commonAncestor) : 0;
- if (annotate && commonAncestorBlock) {
- if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) {
- Node* table = commonAncestorBlock->parentNode();
- while (table && !table->hasTagName(tableTag))
- table = table->parentNode();
- if (table)
- specialCommonAncestor = table;
- } else if (commonAncestorBlock->hasTagName(listingTag)
- || commonAncestorBlock->hasTagName(olTag)
- || commonAncestorBlock->hasTagName(preTag)
- || commonAncestorBlock->hasTagName(tableTag)
- || commonAncestorBlock->hasTagName(ulTag)
- || commonAncestorBlock->hasTagName(xmpTag))
- specialCommonAncestor = commonAncestorBlock;
- }
-
- bool selectedOneOrMoreParagraphs = startOfParagraph(visibleStart) != startOfParagraph(visibleEnd) ||
- isStartOfParagraph(visibleStart) && isEndOfParagraph(visibleEnd);
-
- // Retain the Mail quote level by including all ancestor mail block quotes.
- if (lastClosed && annotate && selectedOneOrMoreParagraphs) {
- for (Node *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode())
- if (isMailBlockquote(ancestor))
- specialCommonAncestor = ancestor;
- }
-
- Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
- if (checkAncestor->renderer()) {
- RefPtr<CSSMutableStyleDeclaration> checkAncestorStyle = computedStyle(checkAncestor)->copyInheritableProperties();
- if (!propertyMissingOrEqualToNone(checkAncestorStyle.get(), CSSPropertyWebkitTextDecorationsInEffect))
- specialCommonAncestor = enclosingNodeOfType(Position(checkAncestor, 0), &elementHasTextDecorationProperty);
- }
-
- // If a single tab is selected, commonAncestor will be a text node inside a tab span.
- // If two or more tabs are selected, commonAncestor will be the tab span.
- // In either case, if there is a specialCommonAncestor already, it will necessarily be above
- // any tab span that needs to be included.
- if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor))
- specialCommonAncestor = commonAncestor->parentNode();
- if (!specialCommonAncestor && isTabSpanNode(commonAncestor))
- specialCommonAncestor = commonAncestor;
-
- if (Node *enclosingAnchor = enclosingNodeWithTag(Position(specialCommonAncestor ? specialCommonAncestor : commonAncestor, 0), aTag))
- specialCommonAncestor = enclosingAnchor;
-
- Node* body = enclosingNodeWithTag(Position(commonAncestor, 0), bodyTag);
- // FIXME: Only include markup for a fully selected root (and ancestors of lastClosed up to that root) if
- // there are styles/attributes on those nodes that need to be included to preserve the appearance of the copied markup.
- // FIXME: Do this for all fully selected blocks, not just the body.
- Node* fullySelectedRoot = body && *Selection::selectionFromContentsOfNode(body).toRange() == *updatedRange ? body : 0;
- if (annotate && fullySelectedRoot)
- specialCommonAncestor = fullySelectedRoot;
-
- if (specialCommonAncestor && lastClosed) {
- // Also include all of the ancestors of lastClosed up to this special ancestor.
- for (Node* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
- if (ancestor == fullySelectedRoot && !convertBlocksToInlines) {
- RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot);
-
- // Bring the background attribute over, but not as an attribute because a background attribute on a div
- // appears to have no effect.
- if (!style->getPropertyCSSValue(CSSPropertyBackgroundImage) && static_cast<Element*>(fullySelectedRoot)->hasAttribute(backgroundAttr))
- style->setProperty(CSSPropertyBackgroundImage, "url('" + static_cast<Element*>(fullySelectedRoot)->getAttribute(backgroundAttr) + "')");
-
- if (style->length()) {
- Vector<UChar> openTag;
- static const String divStyle("<div style=\"");
- append(openTag, divStyle);
- appendAttributeValue(openTag, style->cssText(), documentIsHTML);
- openTag.append('\"');
- openTag.append('>');
- preMarkups.append(String::adopt(openTag));
-
- static const String divCloseTag("</div>");
- markups.append(divCloseTag);
- }
- } else {
- preMarkups.append(getStartMarkup(ancestor, updatedRange.get(), annotate, convertBlocksToInlines));
- markups.append(getEndMarkup(ancestor));
- }
- if (nodes)
- nodes->append(ancestor);
-
- lastClosed = ancestor;
-
- if (ancestor == specialCommonAncestor)
- break;
- }
- }
-
- static const String styleSpanOpen = String("<span class=\"" AppleStyleSpanClass "\" style=\"");
- static const String styleSpanClose("</span>");
-
- // Add a wrapper span with the styles that all of the nodes in the markup inherit.
- Node* parentOfLastClosed = lastClosed ? lastClosed->parentNode() : 0;
- if (parentOfLastClosed && parentOfLastClosed->renderer()) {
- RefPtr<CSSMutableStyleDeclaration> style = computedStyle(parentOfLastClosed)->copyInheritableProperties();
-
- // Styles that Mail blockquotes contribute should only be placed on the Mail blockquote, to help
- // us differentiate those styles from ones that the user has applied. This helps us
- // get the color of content pasted into blockquotes right.
- removeEnclosingMailBlockquoteStyle(style.get(), parentOfLastClosed);
-
- // Document default styles will be added on another wrapper span.
- removeDefaultStyles(style.get(), document);
-
- // Since we are converting blocks to inlines, remove any inherited block properties that are in the style.
- // This cuts out meaningless properties and prevents properties from magically affecting blocks later
- // if the style is cloned for a new block element during a future editing operation.
- if (convertBlocksToInlines)
- style->removeBlockProperties();
-
- if (style->length() > 0) {
- Vector<UChar> openTag;
- append(openTag, styleSpanOpen);
- appendAttributeValue(openTag, style->cssText(), documentIsHTML);
- openTag.append('\"');
- openTag.append('>');
- preMarkups.append(String::adopt(openTag));
-
- markups.append(styleSpanClose);
- }
- }
-
- if (lastClosed && lastClosed != document->documentElement()) {
- // Add a style span with the document's default styles. We add these in a separate
- // span so that at paste time we can differentiate between document defaults and user
- // applied styles.
- RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle(document->documentElement())->copyInheritableProperties();
-
- if (defaultStyle->length() > 0) {
- Vector<UChar> openTag;
- append(openTag, styleSpanOpen);
- appendAttributeValue(openTag, defaultStyle->cssText(), documentIsHTML);
- openTag.append('\"');
- openTag.append('>');
- preMarkups.append(String::adopt(openTag));
- markups.append(styleSpanClose);
- }
- }
-
- // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally.
- if (annotate && needInterchangeNewlineAfter(visibleEnd.previous()))
- markups.append(interchangeNewlineString);
-
- if (deleteButton)
- deleteButton->enable();
-
- return joinMarkups(preMarkups, markups);
-}
-
-PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const String& markup, const String& baseURL)
-{
- ASSERT(document->documentElement()->isHTMLElement());
- // FIXME: What if the document element is not an HTML element?
- HTMLElement *element = static_cast<HTMLElement*>(document->documentElement());
-
- RefPtr<DocumentFragment> fragment = element->createContextualFragment(markup);
-
- if (fragment && !baseURL.isEmpty() && baseURL != blankURL() && baseURL != document->baseURL())
- completeURLs(fragment.get(), baseURL);
-
- return fragment.release();
-}
-
-String createMarkup(const Node* node, EChildrenOnly includeChildren, Vector<Node*>* nodes)
-{
- Vector<UChar> result;
-
- if (!node)
- return "";
-
- Document* document = node->document();
- Frame* frame = document->frame();
- DeleteButtonController* deleteButton = frame ? frame->editor()->deleteButtonController() : 0;
-
- // disable the delete button so it's elements are not serialized into the markup
- if (deleteButton) {
- if (node->isDescendantOf(deleteButton->containerElement()))
- return "";
- deleteButton->disable();
- }
-
- appendMarkup(result, const_cast<Node*>(node), includeChildren, nodes);
-
- if (deleteButton)
- deleteButton->enable();
-
- return String::adopt(result);
-}
-
-static void fillContainerFromString(ContainerNode* paragraph, const String& string)
-{
- Document* document = paragraph->document();
-
- ExceptionCode ec = 0;
- if (string.isEmpty()) {
- paragraph->appendChild(createBlockPlaceholderElement(document), ec);
- ASSERT(ec == 0);
- return;
- }
-
- ASSERT(string.find('\n') == -1);
-
- Vector<String> tabList;
- string.split('\t', true, tabList);
- String tabText = "";
- bool first = true;
- size_t numEntries = tabList.size();
- for (size_t i = 0; i < numEntries; ++i) {
- const String& s = tabList[i];
-
- // append the non-tab textual part
- if (!s.isEmpty()) {
- if (!tabText.isEmpty()) {
- paragraph->appendChild(createTabSpanElement(document, tabText), ec);
- ASSERT(ec == 0);
- tabText = "";
- }
- RefPtr<Node> textNode = document->createTextNode(stringWithRebalancedWhitespace(s, first, i + 1 == numEntries));
- paragraph->appendChild(textNode.release(), ec);
- ASSERT(ec == 0);
- }
-
- // there is a tab after every entry, except the last entry
- // (if the last character is a tab, the list gets an extra empty entry)
- if (i + 1 != numEntries)
- tabText.append('\t');
- else if (!tabText.isEmpty()) {
- paragraph->appendChild(createTabSpanElement(document, tabText), ec);
- ASSERT(ec == 0);
- }
-
- first = false;
- }
-}
-
-PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text)
-{
- if (!context)
- return 0;
-
- Node* styleNode = context->firstNode();
- if (!styleNode) {
- styleNode = context->startPosition().node();
- if (!styleNode)
- return 0;
- }
-
- Document* document = styleNode->document();
- RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
-
- if (text.isEmpty())
- return fragment.release();
-
- String string = text;
- string.replace("\r\n", "\n");
- string.replace('\r', '\n');
-
- ExceptionCode ec = 0;
- RenderObject* renderer = styleNode->renderer();
- if (renderer && renderer->style()->preserveNewline()) {
- fragment->appendChild(document->createTextNode(string), ec);
- ASSERT(ec == 0);
- if (string.endsWith("\n")) {
- RefPtr<Element> element;
- element = document->createElementNS(xhtmlNamespaceURI, "br", ec);
- ASSERT(ec == 0);
- element->setAttribute(classAttr, AppleInterchangeNewline);
- fragment->appendChild(element.release(), ec);
- ASSERT(ec == 0);
- }
- return fragment.release();
- }
-
- // A string with no newlines gets added inline, rather than being put into a paragraph.
- if (string.find('\n') == -1) {
- fillContainerFromString(fragment.get(), string);
- return fragment.release();
- }
-
- // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
- Node* block = enclosingBlock(context->firstNode());
- bool useClonesOfEnclosingBlock = block && !block->hasTagName(bodyTag) && !block->hasTagName(htmlTag) && block != editableRootForPosition(context->startPosition());
-
- Vector<String> list;
- string.split('\n', true, list); // true gets us empty strings in the list
- size_t numLines = list.size();
- for (size_t i = 0; i < numLines; ++i) {
- const String& s = list[i];
-
- RefPtr<Element> element;
- if (s.isEmpty() && i + 1 == numLines) {
- // For last line, use the "magic BR" rather than a P.
- element = document->createElementNS(xhtmlNamespaceURI, "br", ec);
- ASSERT(ec == 0);
- element->setAttribute(classAttr, AppleInterchangeNewline);
- } else {
- element = useClonesOfEnclosingBlock ? static_cast<Element*>(block->cloneNode(false).get()) : createDefaultParagraphElement(document);
- fillContainerFromString(element.get(), s);
- }
- fragment->appendChild(element.release(), ec);
- ASSERT(ec == 0);
- }
- return fragment.release();
-}
-
-PassRefPtr<DocumentFragment> createFragmentFromNodes(Document *document, const Vector<Node*>& nodes)
-{
- if (!document)
- return 0;
-
- // disable the delete button so it's elements are not serialized into the markup
- if (document->frame())
- document->frame()->editor()->deleteButtonController()->disable();
-
- RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
-
- ExceptionCode ec = 0;
- size_t size = nodes.size();
- for (size_t i = 0; i < size; ++i) {
- RefPtr<Element> element = createDefaultParagraphElement(document);
- element->appendChild(nodes[i], ec);
- ASSERT(ec == 0);
- fragment->appendChild(element.release(), ec);
- ASSERT(ec == 0);
- }
-
- if (document->frame())
- document->frame()->editor()->deleteButtonController()->enable();
-
- return fragment.release();
-}
-
-String createFullMarkup(const Node* node)
-{
- if (!node)
- return String();
-
- Document* document = node->document();
- if (!document)
- return String();
-
- Frame* frame = document->frame();
- if (!frame)
- return String();
-
- // FIXME: This is never "for interchange". Is that right?
- String markupString = createMarkup(node, IncludeNode, 0);
- Node::NodeType nodeType = node->nodeType();
- if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE)
- markupString = frame->documentTypeString() + markupString;
-
- return markupString;
-}
-
-String createFullMarkup(const Range* range)
-{
- if (!range)
- return String();
-
- Node* node = range->startContainer();
- if (!node)
- return String();
-
- Document* document = node->document();
- if (!document)
- return String();
-
- Frame* frame = document->frame();
- if (!frame)
- return String();
-
- // FIXME: This is always "for interchange". Is that right? See the previous method.
- return frame->documentTypeString() + createMarkup(range, 0, AnnotateForInterchange);
-}
-
-}
diff --git a/WebCore/editing/markup.h b/WebCore/editing/markup.h
deleted file mode 100644
index 6b7333c..0000000
--- a/WebCore/editing/markup.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef markup_h
-#define markup_h
-
-#include "HTMLInterchange.h"
-#include <wtf/Forward.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
- class Document;
- class DocumentFragment;
- class Node;
- class Range;
- class String;
-
- enum EChildrenOnly { IncludeNode, ChildrenOnly };
-
- PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text);
- PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document*, const String& markup, const String& baseURL);
- PassRefPtr<DocumentFragment> createFragmentFromNodes(Document*, const Vector<Node*>&);
-
- String createMarkup(const Range*,
- Vector<Node*>* = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange, bool convertBlocksToInlines = false);
- String createMarkup(const Node*, EChildrenOnly = IncludeNode, Vector<Node*>* = 0);
-
- String createFullMarkup(const Node*);
- String createFullMarkup(const Range*);
-
-}
-
-#endif // markup_h
diff --git a/WebCore/editing/qt/EditorQt.cpp b/WebCore/editing/qt/EditorQt.cpp
deleted file mode 100644
index 89ee78e..0000000
--- a/WebCore/editing/qt/EditorQt.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2006 Zack Rusin <zack@kde.org>
- * Copyright (C) 2006 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Editor.h"
-
-#include "ClipboardAccessPolicy.h"
-#include "ClipboardQt.h"
-#include "Document.h"
-#include "Element.h"
-#include "Selection.h"
-#include "SelectionController.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-
-namespace WebCore {
-
-PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
-{
- return ClipboardQt::create(policy);
-}
-
-} // namespace WebCore
diff --git a/WebCore/editing/visible_units.cpp b/WebCore/editing/visible_units.cpp
deleted file mode 100644
index 33118f1..0000000
--- a/WebCore/editing/visible_units.cpp
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "visible_units.h"
-
-#include "Document.h"
-#include "Element.h"
-#include "HTMLNames.h"
-#include "RenderBlock.h"
-#include "RenderLayer.h"
-#include "TextBoundaries.h"
-#include "TextBreakIterator.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-static VisiblePosition previousBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
-{
- Position pos = c.deepEquivalent();
- Node *n = pos.node();
- if (!n)
- return VisiblePosition();
- Document *d = n->document();
- Node *de = d->documentElement();
- if (!de)
- return VisiblePosition();
- Node *boundary = n->enclosingBlockFlowElement();
- if (!boundary)
- return VisiblePosition();
- bool isContentEditable = boundary->isContentEditable();
- while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
- boundary = boundary->parentNode();
-
- Position start = rangeCompliantEquivalent(Position(boundary, 0));
- Position end = rangeCompliantEquivalent(pos);
- RefPtr<Range> searchRange = Range::create(d);
-
- int exception = 0;
- searchRange->setStart(start.node(), start.offset(), exception);
- searchRange->setEnd(end.node(), end.offset(), exception);
-
- ASSERT(!exception);
- if (exception)
- return VisiblePosition();
-
- SimplifiedBackwardsTextIterator it(searchRange.get());
- Vector<UChar, 1024> string;
- unsigned next = 0;
- bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
- while (!it.atEnd()) {
- // iterate to get chunks until the searchFunction returns a non-zero value.
- if (!inTextSecurityMode)
- string.prepend(it.characters(), it.length());
- else {
- // Treat bullets used in the text security mode as regular characters when looking for boundaries
- String iteratorString(it.characters(), it.length());
- iteratorString = iteratorString.impl()->secure('x');
- string.prepend(iteratorString.characters(), iteratorString.length());
- }
-
- next = searchFunction(string.data(), string.size());
- if (next != 0)
- break;
- it.advance();
- }
-
- if (it.atEnd() && next == 0) {
- pos = it.range()->startPosition();
- } else if (next != 0) {
- Node *node = it.range()->startContainer(exception);
- if (node->isTextNode() || (node->renderer() && node->renderer()->isBR()))
- // The next variable contains a usable index into a text node
- pos = Position(node, next);
- else {
- // Use the end of the found range, the start is not guaranteed to
- // be correct.
- Position end = it.range()->endPosition();
- VisiblePosition boundary(end);
- unsigned i = it.length() - next;
- while (i--)
- boundary = boundary.previous();
- return boundary;
- }
- }
-
- return VisiblePosition(pos, DOWNSTREAM);
-}
-
-static VisiblePosition nextBoundary(const VisiblePosition &c, unsigned (*searchFunction)(const UChar *, unsigned))
-{
- Position pos = c.deepEquivalent();
- Node *n = pos.node();
- if (!n)
- return VisiblePosition();
- Document *d = n->document();
- Node *de = d->documentElement();
- if (!de)
- return VisiblePosition();
- Node *boundary = n->enclosingBlockFlowElement();
- if (!boundary)
- return VisiblePosition();
- bool isContentEditable = boundary->isContentEditable();
- while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
- boundary = boundary->parentNode();
-
- RefPtr<Range> searchRange(d->createRange());
- Position start(rangeCompliantEquivalent(pos));
- ExceptionCode ec = 0;
- searchRange->selectNodeContents(boundary, ec);
- searchRange->setStart(start.node(), start.offset(), ec);
- TextIterator it(searchRange.get(), true);
- Vector<UChar, 1024> string;
- unsigned next = 0;
- bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
- while (!it.atEnd()) {
- // Keep asking the iterator for chunks until the search function
- // returns an end value not equal to the length of the string passed to it.
- if (!inTextSecurityMode)
- string.append(it.characters(), it.length());
- else {
- // Treat bullets used in the text security mode as regular characters when looking for boundaries
- String iteratorString(it.characters(), it.length());
- iteratorString = iteratorString.impl()->secure('x');
- string.append(iteratorString.characters(), iteratorString.length());
- }
-
- next = searchFunction(string.data(), string.size());
- if (next != string.size())
- break;
- it.advance();
- }
-
- if (it.atEnd() && next == string.size()) {
- pos = it.range()->startPosition();
- } else if (next != 0) {
- // Use the character iterator to translate the next value into a DOM position.
- CharacterIterator charIt(searchRange.get(), true);
- charIt.advance(next - 1);
- pos = charIt.range()->endPosition();
-
- // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
- VisiblePosition visPos = VisiblePosition(pos);
- if (visPos == VisiblePosition(charIt.range()->startPosition()))
- pos = visPos.next(true).deepEquivalent();
- }
-
- // generate VisiblePosition, use UPSTREAM affinity if possible
- return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
-}
-
-// ---------
-
-static unsigned startWordBoundary(const UChar* characters, unsigned length)
-{
- int start, end;
- findWordBoundary(characters, length, length, &start, &end);
- return start;
-}
-
-VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
-{
- // FIXME: This returns a null VP for c at the start of the document
- // and side == LeftWordIfOnBoundary
- VisiblePosition p = c;
- if (side == RightWordIfOnBoundary) {
- // at paragraph end, the startofWord is the current position
- if (isEndOfParagraph(c))
- return c;
-
- p = c.next();
- if (p.isNull())
- return c;
- }
- return previousBoundary(p, startWordBoundary);
-}
-
-static unsigned endWordBoundary(const UChar* characters, unsigned length)
-{
- int start, end;
- findWordBoundary(characters, length, 0, &start, &end);
- return end;
-}
-
-VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
-{
- VisiblePosition p = c;
- if (side == LeftWordIfOnBoundary) {
- if (isStartOfParagraph(c))
- return c;
-
- p = c.previous();
- if (p.isNull())
- return c;
- } else if (isEndOfParagraph(c))
- return c;
-
- return nextBoundary(p, endWordBoundary);
-}
-
-static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length)
-{
- return findNextWordFromIndex(characters, length, length, false);
-}
-
-VisiblePosition previousWordPosition(const VisiblePosition &c)
-{
- VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
- return c.honorEditableBoundaryAtOrAfter(prev);
-}
-
-static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length)
-{
- return findNextWordFromIndex(characters, length, 0, true);
-}
-
-VisiblePosition nextWordPosition(const VisiblePosition &c)
-{
- VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);
- return c.honorEditableBoundaryAtOrBefore(next);
-}
-
-// ---------
-
-static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
-{
- Position p = c.deepEquivalent();
- Node *node = p.node();
- if (!node)
- return 0;
-
- RenderObject *renderer = node->renderer();
- if (!renderer)
- return 0;
-
- InlineBox* box;
- int offset;
- c.getInlineBoxAndOffset(box, offset);
-
- return box ? box->root() : 0;
-}
-
-static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
-{
- // return table offset 0 instead of the first VisiblePosition inside the table
- VisiblePosition previous = c.previous();
- if (isLastPositionBeforeTable(previous))
- return previous;
-
- return c;
-}
-
-static VisiblePosition startPositionForLine(const VisiblePosition& c)
-{
- if (c.isNull())
- return VisiblePosition();
-
- RootInlineBox *rootBox = rootBoxForLine(c);
- if (!rootBox) {
- // There are VisiblePositions at offset 0 in blocks without
- // RootInlineBoxes, like empty editable blocks and bordered blocks.
- Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
- return positionAvoidingFirstPositionInTable(c);
-
- return VisiblePosition();
- }
-
- // Generated content (e.g. list markers and CSS :before and :after
- // pseudoelements) have no corresponding DOM element, and so cannot be
- // represented by a VisiblePosition. Use whatever follows instead.
- InlineBox *startBox = rootBox->firstLeafChild();
- Node *startNode;
- while (1) {
- if (!startBox)
- return VisiblePosition();
-
- RenderObject *startRenderer = startBox->object();
- if (!startRenderer)
- return VisiblePosition();
-
- startNode = startRenderer->element();
- if (startNode)
- break;
-
- startBox = startBox->nextLeafChild();
- }
-
- int startOffset = 0;
- if (startBox->isInlineTextBox()) {
- InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
- startOffset = startTextBox->m_start;
- }
-
- VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
- return positionAvoidingFirstPositionInTable(visPos);
-}
-
-VisiblePosition startOfLine(const VisiblePosition& c)
-{
- VisiblePosition visPos = startPositionForLine(c);
-
- if (visPos.isNotNull()) {
- // Make sure the start of line is not greater than the given input position. Else use the previous position to
- // obtain start of line. This condition happens when the input position is before the space character at the end
- // of a soft-wrapped non-editable line. In this scenario, startPositionForLine would incorrectly hand back a position
- // greater than the input position. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space
- // style versus lines without that style, which would break before a space by default.
- Position p = visPos.deepEquivalent();
- if (p.offset() > c.deepEquivalent().offset() && p.node()->isSameNode(c.deepEquivalent().node())) {
- visPos = c.previous();
- if (visPos.isNull())
- return VisiblePosition();
- visPos = startPositionForLine(visPos);
- }
- }
-
- return c.honorEditableBoundaryAtOrAfter(visPos);
-}
-
-static VisiblePosition endPositionForLine(const VisiblePosition& c)
-{
- if (c.isNull())
- return VisiblePosition();
-
- RootInlineBox *rootBox = rootBoxForLine(c);
- if (!rootBox) {
- // There are VisiblePositions at offset 0 in blocks without
- // RootInlineBoxes, like empty editable blocks and bordered blocks.
- Position p = c.deepEquivalent();
- if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.offset() == 0)
- return c;
- return VisiblePosition();
- }
-
- // Generated content (e.g. list markers and CSS :before and :after
- // pseudoelements) have no corresponding DOM element, and so cannot be
- // represented by a VisiblePosition. Use whatever precedes instead.
- Node *endNode;
- InlineBox *endBox = rootBox->lastLeafChild();
- while (1) {
- if (!endBox)
- return VisiblePosition();
-
- RenderObject *endRenderer = endBox->object();
- if (!endRenderer)
- return VisiblePosition();
-
- endNode = endRenderer->element();
- if (endNode)
- break;
-
- endBox = endBox->prevLeafChild();
- }
-
- int endOffset = 1;
- if (endNode->hasTagName(brTag)) {
- endOffset = 0;
- } else if (endBox->isInlineTextBox()) {
- InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
- endOffset = endTextBox->m_start;
- if (!endTextBox->isLineBreak())
- endOffset += endTextBox->m_len;
- }
-
- return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
-}
-
-VisiblePosition endOfLine(const VisiblePosition& c)
-{
- VisiblePosition visPos = endPositionForLine(c);
-
- // Make sure the end of line is at the same line as the given input position. Else use the previous position to
- // obtain end of line. This condition happens when the input position is before the space character at the end
- // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position
- // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style
- // versus lines without that style, which would break before a space by default.
- if (!inSameLine(c, visPos)) {
- visPos = c.previous();
- if (visPos.isNull())
- return VisiblePosition();
- visPos = endPositionForLine(visPos);
- }
-
- return c.honorEditableBoundaryAtOrBefore(visPos);
-}
-
-bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
-{
- return a.isNotNull() && startOfLine(a) == startOfLine(b);
-}
-
-bool isStartOfLine(const VisiblePosition &p)
-{
- return p.isNotNull() && p == startOfLine(p);
-}
-
-bool isEndOfLine(const VisiblePosition &p)
-{
- return p.isNotNull() && p == endOfLine(p);
-}
-
-// The first leaf before node that has the same editability as node.
-static Node* previousLeafWithSameEditability(Node* node)
-{
- bool editable = node->isContentEditable();
- Node* n = node->previousLeafNode();
- while (n) {
- if (editable == n->isContentEditable())
- return n;
- n = n->previousLeafNode();
- }
- return 0;
-}
-
-VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
-{
- Position p = visiblePosition.deepEquivalent();
- Node *node = p.node();
- Node* highestRoot = highestEditableRoot(p);
- if (!node)
- return VisiblePosition();
-
- node->document()->updateLayoutIgnorePendingStylesheets();
-
- RenderObject *renderer = node->renderer();
- if (!renderer)
- return VisiblePosition();
-
- RenderBlock *containingBlock = 0;
- RootInlineBox *root = 0;
- InlineBox* box;
- int ignoredCaretOffset;
- visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
- if (box) {
- root = box->root()->prevRootBox();
- if (root)
- containingBlock = renderer->containingBlock();
- }
-
- if (!root) {
- // This containing editable block does not have a previous line.
- // Need to move back to previous containing editable block in this root editable
- // block and find the last root line box in that block.
- Node* startBlock = enclosingBlock(node);
- Node* n = previousLeafWithSameEditability(node);
- while (n && startBlock == enclosingBlock(n))
- n = previousLeafWithSameEditability(n);
- while (n) {
- if (highestEditableRoot(Position(n, 0)) != highestRoot)
- break;
- Position pos(n, caretMinOffset(n));
- if (pos.isCandidate()) {
- ASSERT(n->renderer());
- Position maxPos(n, caretMaxOffset(n));
- maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
- if (box) {
- // previous root line box found
- root = box->root();
- containingBlock = n->renderer()->containingBlock();
- break;
- }
-
- return VisiblePosition(pos, DOWNSTREAM);
- }
- n = previousLeafWithSameEditability(n);
- }
- }
-
- if (root) {
- // FIXME: Can be wrong for multi-column layout.
- int absx, absy;
- containingBlock->absolutePositionForContent(absx, absy);
- if (containingBlock->hasOverflowClip())
- containingBlock->layer()->subtractScrollOffset(absx, absy);
- RenderObject *renderer = root->closestLeafChildForXPos(x - absx, isEditablePosition(p))->object();
- Node* node = renderer->element();
- if (editingIgnoresContent(node))
- return Position(node->parent(), node->nodeIndex());
- return renderer->positionForCoordinates(x - absx, root->topOverflow());
- }
-
- // Could not find a previous line. This means we must already be on the first line.
- // Move to the start of the content in this block, which effectively moves us
- // to the start of the line we're on.
- Node* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
- return VisiblePosition(rootElement, 0, DOWNSTREAM);
-}
-
-static Node* nextLeafWithSameEditability(Node* node, int offset)
-{
- bool editable = node->isContentEditable();
- ASSERT(offset >= 0);
- Node* child = node->childNode(offset);
- Node* n = child ? child->nextLeafNode() : node->nextLeafNode();
- while (n) {
- if (editable == n->isContentEditable())
- return n;
- n = n->nextLeafNode();
- }
- return 0;
-}
-
-static Node* nextLeafWithSameEditability(Node* node)
-{
- if (!node)
- return 0;
-
- bool editable = node->isContentEditable();
- Node* n = node->nextLeafNode();
- while (n) {
- if (editable == n->isContentEditable())
- return n;
- n = n->nextLeafNode();
- }
- return 0;
-}
-
-VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
-{
- Position p = visiblePosition.deepEquivalent();
- Node *node = p.node();
- Node* highestRoot = highestEditableRoot(p);
- if (!node)
- return VisiblePosition();
-
- node->document()->updateLayoutIgnorePendingStylesheets();
-
- RenderObject *renderer = node->renderer();
- if (!renderer)
- return VisiblePosition();
-
- RenderBlock *containingBlock = 0;
- RootInlineBox *root = 0;
- InlineBox* box;
- int ignoredCaretOffset;
- visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
- if (box) {
- root = box->root()->nextRootBox();
- if (root)
- containingBlock = renderer->containingBlock();
- }
-
- if (!root) {
- // This containing editable block does not have a next line.
- // Need to move forward to next containing editable block in this root editable
- // block and find the first root line box in that block.
- Node* startBlock = enclosingBlock(node);
- Node* n = nextLeafWithSameEditability(node, p.offset());
- while (n && startBlock == enclosingBlock(n))
- n = nextLeafWithSameEditability(n);
- while (n) {
- if (highestEditableRoot(Position(n, 0)) != highestRoot)
- break;
- Position pos(n, caretMinOffset(n));
- if (pos.isCandidate()) {
- ASSERT(n->renderer());
- pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
- if (box) {
- // next root line box found
- root = box->root();
- containingBlock = n->renderer()->containingBlock();
- break;
- }
-
- return VisiblePosition(pos, DOWNSTREAM);
- }
- n = nextLeafWithSameEditability(n);
- }
- }
-
- if (root) {
- // FIXME: Can be wrong for multi-column layout.
- int absx, absy;
- containingBlock->absolutePositionForContent(absx, absy);
- if (containingBlock->hasOverflowClip())
- containingBlock->layer()->subtractScrollOffset(absx, absy);
- RenderObject *renderer = root->closestLeafChildForXPos(x - absx, isEditablePosition(p))->object();
- Node* node = renderer->element();
- if (editingIgnoresContent(node))
- return Position(node->parent(), node->nodeIndex());
- return renderer->positionForCoordinates(x - absx, root->topOverflow());
- }
-
- // Could not find a next line. This means we must already be on the last line.
- // Move to the end of the content in this block, which effectively moves us
- // to the end of the line we're on.
- Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
- return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
-}
-
-// ---------
-
-static unsigned startSentenceBoundary(const UChar* characters, unsigned length)
-{
- TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
- // FIXME: The following function can return -1; we don't handle that.
- return textBreakPreceding(iterator, length);
-}
-
-VisiblePosition startOfSentence(const VisiblePosition &c)
-{
- return previousBoundary(c, startSentenceBoundary);
-}
-
-static unsigned endSentenceBoundary(const UChar* characters, unsigned length)
-{
- TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
- return textBreakNext(iterator);
-}
-
-// FIXME: This includes the space after the punctuation that marks the end of the sentence.
-VisiblePosition endOfSentence(const VisiblePosition &c)
-{
- return nextBoundary(c, endSentenceBoundary);
-}
-
-static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length)
-{
- // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
- TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
- // FIXME: The following function can return -1; we don't handle that.
- return textBreakPreceding(iterator, length);
-}
-
-VisiblePosition previousSentencePosition(const VisiblePosition &c)
-{
- VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
- return c.honorEditableBoundaryAtOrAfter(prev);
-}
-
-static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length)
-{
- // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs to
- // move to the equivlant position in the following sentence.
- TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
- return textBreakFollowing(iterator, 0);
-}
-
-VisiblePosition nextSentencePosition(const VisiblePosition &c)
-{
- VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);
- return c.honorEditableBoundaryAtOrBefore(next);
-}
-
-// FIXME: Broken for positions before/after images that aren't inline (5027702)
-VisiblePosition startOfParagraph(const VisiblePosition &c)
-{
- Position p = c.deepEquivalent();
- Node *startNode = p.node();
-
- if (!startNode)
- return VisiblePosition();
-
- if (startNode->renderer()
- && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
- || startNode->renderer()->isHR())
- && p.offset() == maxDeepOffset(startNode))
- return VisiblePosition(Position(startNode, 0));
-
- Node* startBlock = enclosingBlock(startNode);
-
- Node *node = startNode;
- int offset = p.offset();
-
- Node *n = startNode;
- while (n) {
- if (n->isContentEditable() != startNode->isContentEditable())
- break;
- RenderObject *r = n->renderer();
- if (!r) {
- n = n->traversePreviousNodePostOrder(startBlock);
- continue;
- }
- RenderStyle *style = r->style();
- if (style->visibility() != VISIBLE) {
- n = n->traversePreviousNodePostOrder(startBlock);
- continue;
- }
-
- if (r->isBR() || isBlock(n))
- break;
-
- if (r->isText()) {
- if (style->preserveNewline()) {
- const UChar* chars = static_cast<RenderText*>(r)->characters();
- int i = static_cast<RenderText*>(r)->textLength();
- int o = offset;
- if (n == startNode && o < i)
- i = max(0, o);
- while (--i >= 0)
- if (chars[i] == '\n')
- return VisiblePosition(n, i + 1, DOWNSTREAM);
- }
- node = n;
- offset = 0;
- n = n->traversePreviousNodePostOrder(startBlock);
- } else if (editingIgnoresContent(n) || isTableElement(n)) {
- node = n;
- offset = 0;
- n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
- } else
- n = n->traversePreviousNodePostOrder(startBlock);
- }
-
- return VisiblePosition(node, offset, DOWNSTREAM);
-}
-
-// FIXME: Broken for positions before/after images that aren't inline (5027702)
-VisiblePosition endOfParagraph(const VisiblePosition &c)
-{
- if (c.isNull())
- return VisiblePosition();
-
- Position p = c.deepEquivalent();
- Node* startNode = p.node();
-
- if (startNode->renderer()
- && ((startNode->renderer()->isTable() && !startNode->renderer()->isInline())
- || startNode->renderer()->isHR())
- && p.offset() == 0)
- return VisiblePosition(Position(startNode, maxDeepOffset(startNode)));
-
- Node* startBlock = enclosingBlock(startNode);
- Node *stayInsideBlock = startBlock;
-
- Node *node = startNode;
- int offset = p.offset();
-
- Node *n = startNode;
- while (n) {
- if (n->isContentEditable() != startNode->isContentEditable())
- break;
- RenderObject *r = n->renderer();
- if (!r) {
- n = n->traverseNextNode(stayInsideBlock);
- continue;
- }
- RenderStyle *style = r->style();
- if (style->visibility() != VISIBLE) {
- n = n->traverseNextNode(stayInsideBlock);
- continue;
- }
-
- if (r->isBR() || isBlock(n))
- break;
-
- // FIXME: We avoid returning a position where the renderer can't accept the caret.
- // We should probably do this in other cases such as startOfParagraph.
- if (r->isText() && r->caretMaxRenderedOffset() > 0) {
- int length = static_cast<RenderText*>(r)->textLength();
- if (style->preserveNewline()) {
- const UChar* chars = static_cast<RenderText*>(r)->characters();
- int o = n == startNode ? offset : 0;
- for (int i = o; i < length; ++i)
- if (chars[i] == '\n')
- return VisiblePosition(n, i, DOWNSTREAM);
- }
- node = n;
- offset = r->caretMaxOffset();
- n = n->traverseNextNode(stayInsideBlock);
- } else if (editingIgnoresContent(n) || isTableElement(n)) {
- node = n;
- offset = maxDeepOffset(n);
- n = n->traverseNextSibling(stayInsideBlock);
- } else
- n = n->traverseNextNode(stayInsideBlock);
- }
-
- return VisiblePosition(node, offset, DOWNSTREAM);
-}
-
-VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
-{
- VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
- VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
- // The position after the last position in the last cell of a table
- // is not the start of the next paragraph.
- if (isFirstPositionAfterTable(afterParagraphEnd))
- return afterParagraphEnd.next(true);
- return afterParagraphEnd;
-}
-
-bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
-{
- return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
-}
-
-bool isStartOfParagraph(const VisiblePosition &pos)
-{
- return pos.isNotNull() && pos == startOfParagraph(pos);
-}
-
-bool isEndOfParagraph(const VisiblePosition &pos)
-{
- return pos.isNotNull() && pos == endOfParagraph(pos);
-}
-
-VisiblePosition previousParagraphPosition(const VisiblePosition &p, int x)
-{
- VisiblePosition pos = p;
- do {
- VisiblePosition n = previousLinePosition(pos, x);
- if (n.isNull() || n == pos)
- return p;
- pos = n;
- } while (inSameParagraph(p, pos));
- return pos;
-}
-
-VisiblePosition nextParagraphPosition(const VisiblePosition &p, int x)
-{
- VisiblePosition pos = p;
- do {
- VisiblePosition n = nextLinePosition(pos, x);
- if (n.isNull() || n == pos)
- return p;
- pos = n;
- } while (inSameParagraph(p, pos));
- return pos;
-}
-
-// ---------
-
-VisiblePosition startOfBlock(const VisiblePosition &c)
-{
- Position p = c.deepEquivalent();
- Node *startNode = p.node();
- if (!startNode)
- return VisiblePosition();
- return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
-}
-
-VisiblePosition endOfBlock(const VisiblePosition &c)
-{
- Position p = c.deepEquivalent();
-
- Node *startNode = p.node();
- if (!startNode)
- return VisiblePosition();
-
- Node *startBlock = startNode->enclosingBlockFlowElement();
-
- return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
-}
-
-bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
-{
- return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
-}
-
-bool isStartOfBlock(const VisiblePosition &pos)
-{
- return pos.isNotNull() && pos == startOfBlock(pos);
-}
-
-bool isEndOfBlock(const VisiblePosition &pos)
-{
- return pos.isNotNull() && pos == endOfBlock(pos);
-}
-
-// ---------
-
-VisiblePosition startOfDocument(const Node* node)
-{
- if (!node)
- return VisiblePosition();
-
- return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
-}
-
-VisiblePosition startOfDocument(const VisiblePosition &c)
-{
- return startOfDocument(c.deepEquivalent().node());
-}
-
-VisiblePosition endOfDocument(const Node* node)
-{
- if (!node || !node->document())
- return VisiblePosition();
-
- Element* doc = node->document()->documentElement();
- return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
-}
-
-VisiblePosition endOfDocument(const VisiblePosition &c)
-{
- return endOfDocument(c.deepEquivalent().node());
-}
-
-bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
-{
- Position ap = a.deepEquivalent();
- Node *an = ap.node();
- if (!an)
- return false;
- Position bp = b.deepEquivalent();
- Node *bn = bp.node();
- if (an == bn)
- return true;
-
- return an->document() == bn->document();
-}
-
-bool isStartOfDocument(const VisiblePosition &p)
-{
- return p.isNotNull() && p.previous().isNull();
-}
-
-bool isEndOfDocument(const VisiblePosition &p)
-{
- return p.isNotNull() && p.next().isNull();
-}
-
-// ---------
-
-VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
-{
- Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
- if (!highestRoot)
- return VisiblePosition();
-
- return VisiblePosition(highestRoot, 0, DOWNSTREAM);
-}
-
-VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
-{
- Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
- if (!highestRoot)
- return VisiblePosition();
-
- return VisiblePosition(highestRoot, maxDeepOffset(highestRoot), DOWNSTREAM);
-}
-
-}
diff --git a/WebCore/editing/visible_units.h b/WebCore/editing/visible_units.h
deleted file mode 100644
index 2663888..0000000
--- a/WebCore/editing/visible_units.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef visible_units_h
-#define visible_units_h
-
-#include "Document.h"
-#include "TextAffinity.h"
-
-namespace WebCore {
-
-class VisiblePosition;
-
-enum EWordSide { RightWordIfOnBoundary = false, LeftWordIfOnBoundary = true };
-
-// words
-VisiblePosition startOfWord(const VisiblePosition &, EWordSide = RightWordIfOnBoundary);
-VisiblePosition endOfWord(const VisiblePosition &, EWordSide = RightWordIfOnBoundary);
-VisiblePosition previousWordPosition(const VisiblePosition &);
-VisiblePosition nextWordPosition(const VisiblePosition &);
-
-// sentences
-VisiblePosition startOfSentence(const VisiblePosition &);
-VisiblePosition endOfSentence(const VisiblePosition &);
-VisiblePosition previousSentencePosition(const VisiblePosition &);
-VisiblePosition nextSentencePosition(const VisiblePosition &);
-
-// lines
-VisiblePosition startOfLine(const VisiblePosition &);
-VisiblePosition endOfLine(const VisiblePosition &);
-VisiblePosition previousLinePosition(const VisiblePosition &, int x);
-VisiblePosition nextLinePosition(const VisiblePosition &, int x);
-bool inSameLine(const VisiblePosition &, const VisiblePosition &);
-bool isStartOfLine(const VisiblePosition &);
-bool isEndOfLine(const VisiblePosition &);
-
-// paragraphs (perhaps a misnomer, can be divided by line break elements)
-VisiblePosition startOfParagraph(const VisiblePosition&);
-VisiblePosition endOfParagraph(const VisiblePosition&);
-VisiblePosition startOfNextParagraph(const VisiblePosition&);
-VisiblePosition previousParagraphPosition(const VisiblePosition &, int x);
-VisiblePosition nextParagraphPosition(const VisiblePosition &, int x);
-bool inSameParagraph(const VisiblePosition &, const VisiblePosition &);
-bool isStartOfParagraph(const VisiblePosition &);
-bool isEndOfParagraph(const VisiblePosition &);
-
-// blocks (true paragraphs; line break elements don't break blocks)
-VisiblePosition startOfBlock(const VisiblePosition &);
-VisiblePosition endOfBlock(const VisiblePosition &);
-bool inSameBlock(const VisiblePosition &, const VisiblePosition &);
-bool isStartOfBlock(const VisiblePosition &);
-bool isEndOfBlock(const VisiblePosition &);
-
-// document
-VisiblePosition startOfDocument(const Node*);
-VisiblePosition endOfDocument(const Node*);
-VisiblePosition startOfDocument(const VisiblePosition &);
-VisiblePosition endOfDocument(const VisiblePosition &);
-bool inSameDocument(const VisiblePosition &, const VisiblePosition &);
-bool isStartOfDocument(const VisiblePosition &);
-bool isEndOfDocument(const VisiblePosition &);
-
-// editable content
-VisiblePosition startOfEditableContent(const VisiblePosition&);
-VisiblePosition endOfEditableContent(const VisiblePosition&);
-
-} // namespace WebCore
-
-#endif // VisiblePosition_h
diff --git a/WebCore/editing/wx/EditorWx.cpp b/WebCore/editing/wx/EditorWx.cpp
deleted file mode 100644
index 0a63215..0000000
--- a/WebCore/editing/wx/EditorWx.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Editor.h"
-
-#include "ClipboardWx.h"
-
-namespace WebCore {
-
-PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
-{
- return ClipboardWx::create(policy, true);
-}
-
-}