diff options
author | Ben Murdoch <benm@google.com> | 2010-06-15 19:36:43 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-06-16 14:52:28 +0100 |
commit | 545e470e52f0ac6a3a072bf559c796b42c6066b6 (patch) | |
tree | c0c14763654d84d37577dde512c3d3b4699a9e86 /WebCore/editing | |
parent | 719298a66237d38ea5c05f1547123ad8aacbc237 (diff) | |
download | external_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.cpp | 6 | ||||
-rw-r--r-- | WebCore/editing/EditingAllInOne.cpp | 74 | ||||
-rw-r--r-- | WebCore/editing/EditingBehavior.h | 58 | ||||
-rw-r--r-- | WebCore/editing/EditingBehaviorTypes.h | 46 | ||||
-rw-r--r-- | WebCore/editing/Editor.cpp | 10 | ||||
-rw-r--r-- | WebCore/editing/Editor.h | 3 | ||||
-rw-r--r-- | WebCore/editing/EditorCommand.cpp | 5 | ||||
-rw-r--r-- | WebCore/editing/InsertListCommand.cpp | 265 | ||||
-rw-r--r-- | WebCore/editing/InsertListCommand.h | 2 | ||||
-rw-r--r-- | WebCore/editing/SelectionController.cpp | 10 | ||||
-rw-r--r-- | WebCore/editing/SetNodeAttributeCommand.h | 1 | ||||
-rw-r--r-- | WebCore/editing/htmlediting.cpp | 30 | ||||
-rw-r--r-- | WebCore/editing/markup.cpp | 2 |
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" |