diff options
author | Steve Block <steveblock@google.com> | 2011-05-13 06:44:40 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-05-13 06:44:40 -0700 |
commit | 08014c20784f3db5df3a89b73cce46037b77eb59 (patch) | |
tree | 47749210d31e19e6e2f64036fa8fae2ad693476f /Source/WebCore/editing/InsertLineBreakCommand.cpp | |
parent | 860220379e56aeb66424861ad602b07ee22b4055 (diff) | |
parent | 4c3661f7918f8b3f139f824efb7855bedccb4c94 (diff) | |
download | external_webkit-08014c20784f3db5df3a89b73cce46037b77eb59.zip external_webkit-08014c20784f3db5df3a89b73cce46037b77eb59.tar.gz external_webkit-08014c20784f3db5df3a89b73cce46037b77eb59.tar.bz2 |
Merge changes Ide388898,Ic49f367c,I1158a808,Iacb6ca5d,I2100dd3a,I5c1abe54,Ib0ef9902,I31dbc523,I570314b3
* changes:
Merge WebKit at r75315: Update WebKit version
Merge WebKit at r75315: Add FrameLoaderClient PageCache stubs
Merge WebKit at r75315: Stub out AXObjectCache::remove()
Merge WebKit at r75315: Fix ImageBuffer
Merge WebKit at r75315: Fix PluginData::initPlugins()
Merge WebKit at r75315: Fix conflicts
Merge WebKit at r75315: Fix Makefiles
Merge WebKit at r75315: Move Android-specific WebCore files to Source
Merge WebKit at r75315: Initial merge by git.
Diffstat (limited to 'Source/WebCore/editing/InsertLineBreakCommand.cpp')
-rw-r--r-- | Source/WebCore/editing/InsertLineBreakCommand.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/Source/WebCore/editing/InsertLineBreakCommand.cpp b/Source/WebCore/editing/InsertLineBreakCommand.cpp new file mode 100644 index 0000000..3070edf --- /dev/null +++ b/Source/WebCore/editing/InsertLineBreakCommand.cpp @@ -0,0 +1,188 @@ +/* + * 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 "Frame.h" +#include "HTMLElement.h" +#include "HTMLNames.h" +#include "Range.h" +#include "RenderObject.h" +#include "Text.h" +#include "VisiblePosition.h" +#include "htmlediting.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. + Element* 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. + Element* 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(); + VisibleSelection selection = endingSelection(); + if (!selection.isNonOrphanedCaretOrRange()) + return; + + VisiblePosition caret(selection.visibleStart()); + // FIXME: If the node is hidden, we should still be able to insert text. + // For now, we return to avoid a crash. https://bugs.webkit.org/show_bug.cgi?id=40342 + if (caret.isNull()) + return; + + 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) && !lineBreakExistsAtVisiblePosition(caret)) { + bool needExtraLineBreak = !pos.node()->hasTagName(hrTag) && !pos.node()->hasTagName(tableTag); + + insertNodeAt(nodeToInsert.get(), pos); + + if (needExtraLineBreak) + insertNodeBefore(nodeToInsert->cloneNode(false), nodeToInsert); + + VisiblePosition endingPosition(Position(nodeToInsert.get(), 0)); + setEndingSelection(VisibleSelection(endingPosition)); + } else if (pos.deprecatedEditingOffset() <= 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(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM)); + // If we're inserting after all of the rendered text in a text node, or into a non-text node, + // a simple insertion is sufficient. + } else if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.node()) || !pos.node()->isTextNode()) { + insertNodeAt(nodeToInsert.get(), pos); + setEndingSelection(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM)); + } else if (pos.node()->isTextNode()) { + // Split a text node + Text* textNode = static_cast<Text*>(pos.node()); + splitTextNode(textNode, pos.deprecatedEditingOffset()); + insertNodeBefore(nodeToInsert, textNode); + Position endingPosition = Position(textNode, 0); + + // Handle whitespace that occurs after the split + updateLayout(); + if (!endingPosition.isRenderedCharacter()) { + Position positionBeforeTextNode(positionInParentBeforeNode(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(VisibleSelection(endingPosition, DOWNSTREAM)); + } + + // Handle the case where there is a typing style. + + RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle(); + + if (typingStyle && !typingStyle->isEmpty()) { + // 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.get(), firstDeepEditingPositionForNode(nodeToInsert.get()), lastDeepEditingPositionForNode(nodeToInsert.get())); + // Even though this applyStyle operates on a Range, it still sets an endingSelection(). + // It tries to set a VisibleSelection around the content it operated on. So, that VisibleSelection + // 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(); +} + +} |