summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-06-15 19:36:43 +0100
committerBen Murdoch <benm@google.com>2010-06-16 14:52:28 +0100
commit545e470e52f0ac6a3a072bf559c796b42c6066b6 (patch)
treec0c14763654d84d37577dde512c3d3b4699a9e86 /WebCore/editing
parent719298a66237d38ea5c05f1547123ad8aacbc237 (diff)
downloadexternal_webkit-545e470e52f0ac6a3a072bf559c796b42c6066b6.zip
external_webkit-545e470e52f0ac6a3a072bf559c796b42c6066b6.tar.gz
external_webkit-545e470e52f0ac6a3a072bf559c796b42c6066b6.tar.bz2
Merge webkit.org at r61121: Initial merge by git.
Change-Id: Icd6db395c62285be384d137164d95d7466c98760
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/DeleteButtonController.cpp6
-rw-r--r--WebCore/editing/EditingAllInOne.cpp74
-rw-r--r--WebCore/editing/EditingBehavior.h58
-rw-r--r--WebCore/editing/EditingBehaviorTypes.h46
-rw-r--r--WebCore/editing/Editor.cpp10
-rw-r--r--WebCore/editing/Editor.h3
-rw-r--r--WebCore/editing/EditorCommand.cpp5
-rw-r--r--WebCore/editing/InsertListCommand.cpp265
-rw-r--r--WebCore/editing/InsertListCommand.h2
-rw-r--r--WebCore/editing/SelectionController.cpp10
-rw-r--r--WebCore/editing/SetNodeAttributeCommand.h1
-rw-r--r--WebCore/editing/htmlediting.cpp30
-rw-r--r--WebCore/editing/markup.cpp2
13 files changed, 375 insertions, 137 deletions
diff --git a/WebCore/editing/DeleteButtonController.cpp b/WebCore/editing/DeleteButtonController.cpp
index 4f527af..8b23eaa 100644
--- a/WebCore/editing/DeleteButtonController.cpp
+++ b/WebCore/editing/DeleteButtonController.cpp
@@ -187,7 +187,7 @@ void DeleteButtonController::respondToChangedSelection(const VisibleSelection& o
void DeleteButtonController::createDeletionUI()
{
RefPtr<HTMLDivElement> container = HTMLDivElement::create(m_target->document());
- container->setAttribute(container->idAttributeName(), containerElementIdentifier);
+ container->setIdAttribute(containerElementIdentifier);
CSSMutableStyleDeclaration* style = container->getInlineStyleDecl();
style->setProperty(CSSPropertyWebkitUserDrag, CSSValueNone);
@@ -202,7 +202,7 @@ void DeleteButtonController::createDeletionUI()
style->setProperty(CSSPropertyLeft, "0");
RefPtr<HTMLDivElement> outline = HTMLDivElement::create(m_target->document());
- outline->setAttribute(outline->idAttributeName(), outlineElementIdentifier);
+ outline->setIdAttribute(outlineElementIdentifier);
const int borderWidth = 4;
const int borderRadius = 6;
@@ -225,7 +225,7 @@ void DeleteButtonController::createDeletionUI()
return;
RefPtr<DeleteButton> button = DeleteButton::create(m_target->document());
- button->setAttribute(button->idAttributeName(), buttonElementIdentifier);
+ button->setIdAttribute(buttonElementIdentifier);
const int buttonWidth = 30;
const int buttonHeight = 30;
diff --git a/WebCore/editing/EditingAllInOne.cpp b/WebCore/editing/EditingAllInOne.cpp
new file mode 100644
index 0000000..dda2501
--- /dev/null
+++ b/WebCore/editing/EditingAllInOne.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 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 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.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include <AppendNodeCommand.cpp>
+#include <ApplyStyleCommand.cpp>
+#include <BreakBlockquoteCommand.cpp>
+#include <CompositeEditCommand.cpp>
+#include <CreateLinkCommand.cpp>
+#include <DeleteButton.cpp>
+#include <DeleteButtonController.cpp>
+#include <DeleteFromTextNodeCommand.cpp>
+#include <DeleteSelectionCommand.cpp>
+#include <EditCommand.cpp>
+#include <Editor.cpp>
+#include <EditorCommand.cpp>
+#include <FormatBlockCommand.cpp>
+#include <HTMLInterchange.cpp>
+#include <IndentOutdentCommand.cpp>
+#include <InsertIntoTextNodeCommand.cpp>
+#include <InsertLineBreakCommand.cpp>
+#include <InsertListCommand.cpp>
+#include <InsertNodeBeforeCommand.cpp>
+#include <InsertParagraphSeparatorCommand.cpp>
+#include <InsertTextCommand.cpp>
+#include <JoinTextNodesCommand.cpp>
+#include <MergeIdenticalElementsCommand.cpp>
+#include <ModifySelectionListLevel.cpp>
+#include <MoveSelectionCommand.cpp>
+#include <RemoveCSSPropertyCommand.cpp>
+#include <RemoveFormatCommand.cpp>
+#include <RemoveNodeCommand.cpp>
+#include <RemoveNodePreservingChildrenCommand.cpp>
+#include <ReplaceNodeWithSpanCommand.cpp>
+#include <ReplaceSelectionCommand.cpp>
+#include <SelectionController.cpp>
+#include <SetNodeAttributeCommand.cpp>
+#include <SmartReplace.cpp>
+#include <SmartReplaceCF.cpp>
+#include <SplitElementCommand.cpp>
+#include <SplitTextNodeCommand.cpp>
+#include <SplitTextNodeContainingElementCommand.cpp>
+#include <TextIterator.cpp>
+#include <TypingCommand.cpp>
+#include <UnlinkCommand.cpp>
+#include <VisiblePosition.cpp>
+#include <VisibleSelection.cpp>
+#include <WrapContentsInDummySpanCommand.cpp>
+#include <htmlediting.cpp>
+#include <markup.cpp>
+#include <visible_units.cpp>
diff --git a/WebCore/editing/EditingBehavior.h b/WebCore/editing/EditingBehavior.h
new file mode 100644
index 0000000..fe09e1b
--- /dev/null
+++ b/WebCore/editing/EditingBehavior.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EditingBehavior_h
+#define EditingBehavior_h
+
+#include "EditingBehaviorTypes.h"
+
+namespace WebCore {
+
+class EditingBehavior {
+
+public:
+ EditingBehavior(EditingBehaviorType type)
+ : m_type(type)
+ {
+ }
+
+ // Individual functions for each case where we have more than one style of editing behavior.
+ // Create a new function for any platform difference so we can control it here.
+
+ // When extending a selection beyond the top or bottom boundary of an editable area,
+ // maintain the horizontal position on Windows but extend it to the boundary of the editable
+ // content on Mac.
+ bool shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom() const { return m_type != EditingWindowsBehavior; }
+
+ // On Windows, selections should always be considered as directional, regardless if it is
+ // mouse-based or keyboard-based.
+ bool shouldConsiderSelectionAsDirectional() const { return m_type != EditingMacBehavior; }
+
+ // On Mac, when revealing a selection (for example as a result of a Find operation on the Browser),
+ // content should be scrolled such that the selection gets certer aligned.
+ bool shouldCenterAlignWhenSelectionIsRevealed() const { return m_type == EditingMacBehavior; }
+
+private:
+ EditingBehaviorType m_type;
+};
+
+} // namespace WebCore
+
+#endif // EditingBehavior_h
diff --git a/WebCore/editing/EditingBehaviorTypes.h b/WebCore/editing/EditingBehaviorTypes.h
new file mode 100644
index 0000000..26ba18e
--- /dev/null
+++ b/WebCore/editing/EditingBehaviorTypes.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EditingBehaviorTypes_h
+#define EditingBehaviorTypes_h
+
+namespace WebCore {
+
+// There are multiple editing details that are different on Windows than Macintosh.
+// We use a single switch for all of them. Some examples:
+//
+// 1) Clicking below the last line of an editable area puts the caret at the end
+// of the last line on Mac, but in the middle of the last line on Windows.
+// 2) Pushing the down arrow key on the last line puts the caret at the end of the
+// last line on Mac, but does nothing on Windows. A similar case exists on the
+// top line.
+//
+// This setting is intended to control these sorts of behaviors. There are some other
+// behaviors with individual function calls on EditorClient (smart copy and paste and
+// selecting the space after a double click) that could be combined with this if
+// if possible in the future.
+enum EditingBehaviorType {
+ EditingMacBehavior,
+ EditingWindowsBehavior
+};
+
+} // WebCore namespace
+
+#endif // EditingBehaviorTypes_h
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 8041159..8ae1313 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -63,6 +63,7 @@
#include "RenderBlock.h"
#include "RenderPart.h"
#include "ReplaceSelectionCommand.h"
+#include "Settings.h"
#include "Sound.h"
#include "Text.h"
#include "TextIterator.h"
@@ -97,6 +98,15 @@ VisibleSelection Editor::selectionForCommand(Event* event)
return selection;
}
+// Function considers Mac editing behavior a fallback when Page or Settings is not available.
+EditingBehavior Editor::behavior() const
+{
+ if (!m_frame || !m_frame->settings())
+ return EditingBehavior(EditingMacBehavior);
+
+ return EditingBehavior(m_frame->settings()->editingBehaviorType());
+}
+
EditorClient* Editor::client() const
{
if (Page* page = m_frame->page())
diff --git a/WebCore/editing/Editor.h b/WebCore/editing/Editor.h
index 17dd3bb..3e223dc 100644
--- a/WebCore/editing/Editor.h
+++ b/WebCore/editing/Editor.h
@@ -29,6 +29,7 @@
#include "ClipboardAccessPolicy.h"
#include "Color.h"
#include "EditAction.h"
+#include "EditingBehavior.h"
#include "EditorDeleteAction.h"
#include "EditorInsertAction.h"
#include "SelectionController.h"
@@ -281,6 +282,8 @@ public:
KillRing* killRing() const { return m_killRing.get(); }
+ EditingBehavior behavior() const;
+
PassRefPtr<Range> selectedRange();
// We should make these functions private when their callers in Frame are moved over here to Editor
diff --git a/WebCore/editing/EditorCommand.cpp b/WebCore/editing/EditorCommand.cpp
index 75085fb..6bd75d6 100644
--- a/WebCore/editing/EditorCommand.cpp
+++ b/WebCore/editing/EditorCommand.cpp
@@ -49,6 +49,7 @@
#include "InsertListCommand.h"
#include "KillRing.h"
#include "Page.h"
+#include "RenderBox.h"
#include "ReplaceSelectionCommand.h"
#include "Scrollbar.h"
#include "Settings.h"
@@ -166,7 +167,7 @@ static bool executeToggleStyle(Frame* frame, EditorCommandSource source, EditAct
// other: present throughout the selection
Settings* settings = frame->document()->settings();
bool styleIsPresent;
- if (settings && settings->editingBehavior() == EditingMacBehavior)
+ if (settings && settings->editingBehaviorType() == EditingMacBehavior)
styleIsPresent = frame->editor()->selectionStartHasStyle(style.get());
else
styleIsPresent = frame->editor()->selectionHasStyle(style.get()) == TrueTriState;
@@ -474,7 +475,7 @@ static bool executeInsertHorizontalRule(Frame* frame, Event*, EditorCommandSourc
{
RefPtr<HTMLHRElement> rule = HTMLHRElement::create(frame->document());
if (!value.isEmpty())
- rule->setAttribute(rule->idAttributeName(), value);
+ rule->setIdAttribute(value);
return executeInsertNode(frame, rule.release());
}
diff --git a/WebCore/editing/InsertListCommand.cpp b/WebCore/editing/InsertListCommand.cpp
index cd6838b..07b612f 100644
--- a/WebCore/editing/InsertListCommand.cpp
+++ b/WebCore/editing/InsertListCommand.cpp
@@ -143,134 +143,153 @@ void InsertListCommand::doApply()
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 = firstDeepEditingPositionForNode(listChildNode);
- end = lastDeepEditingPositionForNode(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<Element> 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, nodeToInsert);
- }
-
- 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(listNode, splitTreeToNode(nextListChild, listNode));
- insertNodeBefore(nodeToInsert, 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(listNode, splitTreeToNode(listChildNode, listNode).get());
- insertNodeBefore(nodeToInsert, listNode);
- } else
- insertNodeAfter(nodeToInsert, listNode);
-
- VisiblePosition insertionPoint = VisiblePosition(Position(placeholder.get(), 0));
- moveParagraphs(start, end, insertionPoint, true);
+
+ unlistifyParagraph(endingSelection().visibleStart(), listNode, listChildNode);
}
- if (!listChildNode || switchListType || m_forceCreateList) {
- // Create list.
- VisiblePosition originalStart = endingSelection().visibleStart();
- VisiblePosition start = startOfParagraph(originalStart);
- VisiblePosition end = endOfParagraph(endingSelection().visibleEnd());
-
- // Check for adjoining lists.
- VisiblePosition previousPosition = start.previous(true);
- VisiblePosition nextPosition = end.next(true);
- RefPtr<HTMLElement> listItemElement = createListItemElement(document());
- RefPtr<HTMLElement> placeholder = createBreakElement(document());
- appendNode(placeholder, listItemElement);
- Element* previousList = outermostEnclosingList(previousPosition.deepEquivalent().node());
- Element* 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, previousList);
- else if (nextList)
- insertNodeAt(listItemElement, Position(nextList, 0));
- else {
- // Create the list.
- RefPtr<HTMLElement> listElement = m_type == OrderedList ? createOrderedListElement(document()) : createUnorderedListElement(document());
- m_listElement = listElement;
- appendNode(listItemElement, listElement);
-
- 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 = positionInParentBeforeNode(listChild);
- insertNodeAt(listElement, insertionPos);
+ if (!listChildNode || switchListType || m_forceCreateList)
+ m_listElement = listifyParagraph(endingSelection().visibleStart(), listTag);
+}
+
+void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart, HTMLElement* listNode, Node* listChildNode)
+{
+ Node* nextListChild;
+ Node* previousListChild;
+ VisiblePosition start;
+ VisiblePosition end;
+ if (listChildNode->hasTagName(liTag)) {
+ start = firstDeepEditingPositionForNode(listChildNode);
+ end = lastDeepEditingPositionForNode(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(originalStart);
+ end = endOfParagraph(start);
+ 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<Element> 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, nodeToInsert);
+ }
+
+ 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(listNode, splitTreeToNode(nextListChild, listNode));
+ insertNodeBefore(nodeToInsert, 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(listNode, splitTreeToNode(listChildNode, listNode).get());
+ insertNodeBefore(nodeToInsert, listNode);
+ } else
+ insertNodeAfter(nodeToInsert, listNode);
+
+ VisiblePosition insertionPoint = VisiblePosition(Position(placeholder.get(), 0));
+ moveParagraphs(start, end, insertionPoint, true);
+}
- // We inserted the list at the start of the content we're about to move
- // Update the start of content, so we don't try to move the list into itself. bug 19066
- if (insertionPos == start.deepEquivalent())
- start = startOfParagraph(originalStart);
- previousList = outermostEnclosingList(previousPosition.deepEquivalent().node(), enclosingList(listElement.get()));
- nextList = outermostEnclosingList(nextPosition.deepEquivalent().node(), enclosingList(listElement.get()));
+PassRefPtr<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& originalStart, const QualifiedName& listTag)
+{
+ VisiblePosition start = startOfParagraph(originalStart);
+ VisiblePosition end = endOfParagraph(start);
+
+ // Check for adjoining lists.
+ VisiblePosition previousPosition = start.previous(true);
+ VisiblePosition nextPosition = end.next(true);
+ RefPtr<HTMLElement> listItemElement = createListItemElement(document());
+ RefPtr<HTMLElement> placeholder = createBreakElement(document());
+ appendNode(placeholder, listItemElement);
+ Element* previousList = outermostEnclosingList(previousPosition.deepEquivalent().node());
+ Element* 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.
+ RefPtr<HTMLElement> listElement;
+ if (previousList)
+ appendNode(listItemElement, previousList);
+ else if (nextList)
+ insertNodeAt(listItemElement, Position(nextList, 0));
+ else {
+ // Create the list.
+ listElement = createHTMLElement(document(), listTag);
+ appendNode(listItemElement, listElement);
+
+ 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;
}
- moveParagraph(start, end, VisiblePosition(Position(placeholder.get(), 0)), true);
- if (m_listElement) {
- if (canMergeLists(previousList, m_listElement.get()))
- mergeIdenticalElements(previousList, m_listElement.get());
- if (canMergeLists(m_listElement.get(), nextList))
- mergeIdenticalElements(m_listElement.get(), nextList);
- } else if (canMergeLists(nextList, previousList))
- mergeIdenticalElements(previousList, nextList);
+
+ // 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 = positionInParentBeforeNode(listChild);
+
+ insertNodeAt(listElement, insertionPos);
+
+ // We inserted the list at the start of the content we're about to move
+ // Update the start of content, so we don't try to move the list into itself. bug 19066
+ if (insertionPos == start.deepEquivalent())
+ start = startOfParagraph(originalStart);
+ previousList = outermostEnclosingList(previousPosition.deepEquivalent().node(), enclosingList(listElement.get()));
+ nextList = outermostEnclosingList(nextPosition.deepEquivalent().node(), enclosingList(listElement.get()));
}
+
+ moveParagraph(start, end, VisiblePosition(Position(placeholder.get(), 0)), true);
+
+ // FIXME: listifyParagraph should not depend on a member variable.
+ // Since fixOrphanedListChild is the only other method that updates m_listElement,
+ // we should fix unlistifyParagraph to support orphaned list child to get rid of this assignment.
+ if (!listElement && m_listElement)
+ listElement = m_listElement;
+
+ if (listElement) {
+ if (canMergeLists(previousList, listElement.get()))
+ mergeIdenticalElements(previousList, listElement.get());
+ if (canMergeLists(listElement.get(), nextList))
+ mergeIdenticalElements(listElement.get(), nextList);
+ } else if (canMergeLists(nextList, previousList))
+ mergeIdenticalElements(previousList, nextList);
+
+ return listElement;
}
}
diff --git a/WebCore/editing/InsertListCommand.h b/WebCore/editing/InsertListCommand.h
index ecdd2cf..7f3b07d 100644
--- a/WebCore/editing/InsertListCommand.h
+++ b/WebCore/editing/InsertListCommand.h
@@ -53,6 +53,8 @@ private:
HTMLElement* fixOrphanedListChild(Node*);
bool modifyRange();
+ void unlistifyParagraph(const VisiblePosition& originalStart, HTMLElement* listNode, Node* listChildNode);
+ PassRefPtr<HTMLElement> listifyParagraph(const VisiblePosition& originalStart, const QualifiedName& listTag);
RefPtr<HTMLElement> m_listElement;
Type m_type;
bool m_forceCreateList;
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
index f9b39bb..ca18bc1 100644
--- a/WebCore/editing/SelectionController.cpp
+++ b/WebCore/editing/SelectionController.cpp
@@ -44,6 +44,7 @@
#include "HitTestResult.h"
#include "Page.h"
#include "Range.h"
+#include "RenderLayer.h"
#include "RenderTheme.h"
#include "RenderView.h"
#include "SecureTextInput.h"
@@ -164,7 +165,7 @@ void SelectionController::setSelection(const VisibleSelection& s, bool closeTypi
if (userTriggered) {
ScrollAlignment alignment;
- if (m_frame->settings() && m_frame->settings()->editingBehavior() == EditingMacBehavior)
+ if (m_frame->editor()->behavior().shouldCenterAlignWhenSelectionIsRevealed())
alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
else
alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
@@ -243,8 +244,7 @@ void SelectionController::nodeWillBeRemoved(Node *node)
void SelectionController::setIsDirectional(bool isDirectional)
{
- Settings* settings = m_frame ? m_frame->settings() : 0;
- m_isDirectional = !settings || settings->editingBehavior() != EditingMacBehavior || isDirectional;
+ m_isDirectional = !m_frame || m_frame->editor()->behavior().shouldConsiderSelectionAsDirectional() || isDirectional;
}
void SelectionController::willBeModified(EAlteration alter, EDirection direction)
@@ -299,7 +299,7 @@ VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
{
Position pos;
Settings* settings = m_frame ? m_frame->settings() : 0;
- if (settings && settings->editingBehavior() == EditingMacBehavior)
+ if (settings && settings->editingBehaviorType() == EditingMacBehavior)
pos = isGetStart ? m_selection.start() : m_selection.end();
else {
// Linux and Windows always extend selections from the extent endpoint.
@@ -685,7 +685,7 @@ bool SelectionController::modify(EAlteration alter, EDirection direction, TextGr
moveTo(position, userTriggered);
break;
case AlterationExtend:
- if (!settings || settings->editingBehavior() != EditingMacBehavior || m_selection.isCaret() || !isBoundary(granularity))
+ if (!settings || settings->editingBehaviorType() != EditingMacBehavior || m_selection.isCaret() || !isBoundary(granularity))
setExtent(position, userTriggered);
else {
// Standard Mac behavior when extending to a boundary is grow the selection rather
diff --git a/WebCore/editing/SetNodeAttributeCommand.h b/WebCore/editing/SetNodeAttributeCommand.h
index 899ac62..ce3a1ec 100644
--- a/WebCore/editing/SetNodeAttributeCommand.h
+++ b/WebCore/editing/SetNodeAttributeCommand.h
@@ -27,7 +27,6 @@
#define SetNodeAttributeCommand_h
#include "EditCommand.h"
-#include "QualifiedName.h"
namespace WebCore {
diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
index 3356ed9..9f73167 100644
--- a/WebCore/editing/htmlediting.cpp
+++ b/WebCore/editing/htmlediting.cpp
@@ -869,7 +869,35 @@ bool isTableCell(const Node* node)
bool isEmptyTableCell(const Node* node)
{
- return node && node->renderer() && (node->renderer()->isTableCell() || (node->renderer()->isBR() && node->parentNode()->renderer() && node->parentNode()->renderer()->isTableCell()));
+ // Returns true IFF the passed in node is one of:
+ // .) a table cell with no children,
+ // .) a table cell with a single BR child, and which has no other child renderers, including :before and :after renderers
+ // .) the BR child of such a table cell
+
+ // Find rendered node
+ while (node && !node->renderer())
+ node = node->parent();
+ if (!node)
+ return false;
+
+ // Make sure the rendered node is a table cell or <br>.
+ // If it's a <br>, then the parent node has to be a table cell.
+ RenderObject* renderer = node->renderer();
+ if (renderer->isBR()) {
+ renderer = renderer->parent();
+ if (!renderer)
+ return false;
+ }
+ if (!renderer->isTableCell())
+ return false;
+
+ // Check that the table cell contains no child renderers except for perhaps a single <br>.
+ RenderObject* childRenderer = renderer->firstChild();
+ if (!childRenderer)
+ return true;
+ if (!childRenderer->isBR())
+ return false;
+ return !childRenderer->nextSibling();
}
PassRefPtr<HTMLElement> createDefaultParagraphElement(Document* document)
diff --git a/WebCore/editing/markup.cpp b/WebCore/editing/markup.cpp
index 46f0e94..17f5680 100644
--- a/WebCore/editing/markup.cpp
+++ b/WebCore/editing/markup.cpp
@@ -41,7 +41,6 @@
#include "CSSValue.h"
#include "CSSValueKeywords.h"
#include "DeleteButtonController.h"
-#include "Document.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Editor.h"
@@ -52,7 +51,6 @@
#include "KURL.h"
#include "Logging.h"
#include "ProcessingInstruction.h"
-#include "QualifiedName.h"
#include "Range.h"
#include "VisibleSelection.h"
#include "TextIterator.h"