Index: Source/core/editing/InsertTextCommand.cpp |
diff --git a/Source/core/editing/InsertTextCommand.cpp b/Source/core/editing/InsertTextCommand.cpp |
deleted file mode 100644 |
index a62339f3af83b25f33b8bf6ca150f2ec31de6881..0000000000000000000000000000000000000000 |
--- a/Source/core/editing/InsertTextCommand.cpp |
+++ /dev/null |
@@ -1,273 +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 "core/editing/InsertTextCommand.h" |
- |
-#include "core/dom/Document.h" |
-#include "core/dom/Element.h" |
-#include "core/dom/Text.h" |
-#include "core/editing/EditingUtilities.h" |
-#include "core/editing/Editor.h" |
-#include "core/editing/VisibleUnits.h" |
-#include "core/frame/LocalFrame.h" |
-#include "core/html/HTMLSpanElement.h" |
- |
-namespace blink { |
- |
-InsertTextCommand::InsertTextCommand(Document& document, const String& text, bool selectInsertedText, RebalanceType rebalanceType) |
- : CompositeEditCommand(document) |
- , m_text(text) |
- , m_selectInsertedText(selectInsertedText) |
- , m_rebalanceType(rebalanceType) |
-{ |
-} |
- |
-Position InsertTextCommand::positionInsideTextNode(const Position& p) |
-{ |
- Position pos = p; |
- if (isTabHTMLSpanElementTextNode(pos.anchorNode())) { |
- RefPtrWillBeRawPtr<Text> textNode = document().createEditingTextNode(""); |
- insertNodeAtTabSpanPosition(textNode.get(), pos); |
- return firstPositionInNode(textNode.get()); |
- } |
- |
- // Prepare for text input by looking at the specified position. |
- // It may be necessary to insert a text node to receive characters. |
- if (!pos.computeContainerNode()->isTextNode()) { |
- RefPtrWillBeRawPtr<Text> textNode = document().createEditingTextNode(""); |
- insertNodeAt(textNode.get(), pos); |
- return firstPositionInNode(textNode.get()); |
- } |
- |
- return pos; |
-} |
- |
-void InsertTextCommand::setEndingSelectionWithoutValidation(const Position& startPosition, const Position& endPosition) |
-{ |
- // 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> |
- VisibleSelection forcedEndingSelection; |
- forcedEndingSelection.setWithoutValidation(startPosition, endPosition); |
- forcedEndingSelection.setIsDirectional(endingSelection().isDirectional()); |
- setEndingSelection(forcedEndingSelection); |
-} |
- |
-// 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 endPosition = replaceSelectedTextInNode(text); |
- if (endPosition.isNull()) |
- return false; |
- |
- setEndingSelectionWithoutValidation(start, endPosition); |
- if (!selectInsertedText) |
- setEndingSelection(VisibleSelection(endingSelection().visibleEnd(), endingSelection().isDirectional())); |
- |
- return true; |
-} |
- |
-bool InsertTextCommand::performOverwrite(const String& text, bool selectInsertedText) |
-{ |
- Position start = endingSelection().start(); |
- if (start.isNull() || !start.isOffsetInAnchor() || !start.computeContainerNode()->isTextNode()) |
- return false; |
- RefPtrWillBeRawPtr<Text> textNode = toText(start.computeContainerNode()); |
- if (!textNode) |
- return false; |
- |
- unsigned count = std::min(text.length(), textNode->length() - start.offsetInContainerNode()); |
- if (!count) |
- return false; |
- |
- replaceTextInNode(textNode, start.offsetInContainerNode(), count, text); |
- |
- Position endPosition = Position(textNode.release(), start.offsetInContainerNode() + text.length()); |
- setEndingSelectionWithoutValidation(start, endPosition); |
- if (!selectInsertedText) |
- setEndingSelection(VisibleSelection(endingSelection().visibleEnd(), endingSelection().isDirectional())); |
- |
- return true; |
-} |
- |
-void InsertTextCommand::doApply() |
-{ |
- ASSERT(m_text.find('\n') == kNotFound); |
- |
- if (!endingSelection().isNonOrphanedCaretOrRange()) |
- return; |
- |
- // Delete the current selection. |
- // FIXME: This delete operation blows away the typing style. |
- if (endingSelection().isRange()) { |
- if (performTrivialReplace(m_text, m_selectInsertedText)) |
- return; |
- bool endOfSelectionWasAtStartOfBlock = isStartOfBlock(endingSelection().visibleEnd()); |
- deleteSelection(false, true, false, false); |
- // deleteSelection eventually makes a new endingSelection out of a Position. If that Position doesn't have |
- // a layoutObject (e.g. it is on a <frameset> in the DOM), the VisibleSelection cannot be canonicalized to |
- // anything other than NoSelection. The rest of this function requires a real endingSelection, so bail out. |
- if (endingSelection().isNone()) |
- return; |
- if (endOfSelectionWasAtStartOfBlock) { |
- if (EditingStyle* typingStyle = document().frame()->selection().typingStyle()) |
- typingStyle->removeBlockProperties(); |
- } |
- } else if (document().frame()->editor().isOverwriteModeEnabled()) { |
- if (performOverwrite(m_text, m_selectInsertedText)) |
- return; |
- } |
- |
- Position startPosition(endingSelection().start()); |
- |
- Position placeholder; |
- // We want to remove preserved newlines and brs that will collapse (and thus become unnecessary) when content |
- // is inserted just before them. |
- // FIXME: We shouldn't really have to do this, but removing placeholders is a workaround for 9661. |
- // If the caret is just before a placeholder, downstream will normalize the caret to it. |
- Position downstream(startPosition.downstream()); |
- if (lineBreakExistsAtPosition(downstream)) { |
- // FIXME: This doesn't handle placeholders at the end of anonymous blocks. |
- VisiblePosition caret(startPosition); |
- if (isEndOfBlock(caret) && isStartOfParagraph(caret)) |
- placeholder = downstream; |
- // Don't remove the placeholder yet, otherwise the block we're inserting into would collapse before |
- // we get a chance to insert into it. We check for a placeholder now, though, because doing so requires |
- // the creation of a VisiblePosition, and if we did that post-insertion it would force a layout. |
- } |
- |
- // Insert the character at the leftmost candidate. |
- startPosition = startPosition.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. |
- ASSERT(startPosition.computeContainerNode()); |
- Position positionBeforeStartNode(positionInParentBeforeNode(*startPosition.computeContainerNode())); |
- deleteInsignificantText(startPosition, startPosition.downstream()); |
- if (!startPosition.inDocument()) |
- startPosition = positionBeforeStartNode; |
- if (!startPosition.isCandidate()) |
- startPosition = startPosition.downstream(); |
- |
- startPosition = positionAvoidingSpecialElementBoundary(startPosition); |
- |
- Position endPosition; |
- |
- if (m_text == "\t") { |
- endPosition = insertTab(startPosition); |
- startPosition = endPosition.previous(); |
- if (placeholder.isNotNull()) |
- removePlaceholderAt(placeholder); |
- } else { |
- // Make sure the document is set up to receive m_text |
- startPosition = positionInsideTextNode(startPosition); |
- ASSERT(startPosition.isOffsetInAnchor()); |
- ASSERT(startPosition.computeContainerNode()); |
- ASSERT(startPosition.computeContainerNode()->isTextNode()); |
- if (placeholder.isNotNull()) |
- removePlaceholderAt(placeholder); |
- RefPtrWillBeRawPtr<Text> textNode = toText(startPosition.computeContainerNode()); |
- const unsigned offset = startPosition.offsetInContainerNode(); |
- |
- insertTextIntoNode(textNode, offset, m_text); |
- endPosition = Position(textNode, offset + m_text.length()); |
- |
- if (m_rebalanceType == RebalanceLeadingAndTrailingWhitespaces) { |
- // The insertion may require adjusting adjacent whitespace, if it is present. |
- rebalanceWhitespaceAt(endPosition); |
- // Rebalancing on both sides isn't necessary if we've inserted only spaces. |
- if (!shouldRebalanceLeadingWhitespaceFor(m_text)) |
- rebalanceWhitespaceAt(startPosition); |
- } else { |
- ASSERT(m_rebalanceType == RebalanceAllWhitespaces); |
- if (canRebalance(startPosition) && canRebalance(endPosition)) |
- rebalanceWhitespaceOnTextSubstring(textNode, startPosition.offsetInContainerNode(), endPosition.offsetInContainerNode()); |
- } |
- } |
- |
- setEndingSelectionWithoutValidation(startPosition, endPosition); |
- |
- // Handle the case where there is a typing style. |
- if (RefPtrWillBeRawPtr<EditingStyle> typingStyle = document().frame()->selection().typingStyle()) { |
- typingStyle->prepareToApplyAt(endPosition, EditingStyle::PreserveWritingDirection); |
- if (!typingStyle->isEmpty()) |
- applyStyle(typingStyle.get()); |
- } |
- |
- if (!m_selectInsertedText) |
- setEndingSelection(VisibleSelection(endingSelection().end(), endingSelection().affinity(), endingSelection().isDirectional())); |
-} |
- |
-Position InsertTextCommand::insertTab(const Position& pos) |
-{ |
- Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent(); |
- if (insertPos.isNull()) |
- return pos; |
- |
- Node* node = insertPos.computeContainerNode(); |
- unsigned offset = node->isTextNode() ? insertPos.offsetInContainerNode() : 0; |
- |
- // keep tabs coalesced in tab span |
- if (isTabHTMLSpanElementTextNode(node)) { |
- RefPtrWillBeRawPtr<Text> textNode = toText(node); |
- insertTextIntoNode(textNode, offset, "\t"); |
- return Position(textNode.release(), offset + 1); |
- } |
- |
- // create new tab span |
- RefPtrWillBeRawPtr<HTMLSpanElement> spanElement = createTabSpanElement(document()); |
- |
- // place it |
- if (!node->isTextNode()) { |
- insertNodeAt(spanElement.get(), insertPos); |
- } else { |
- RefPtrWillBeRawPtr<Text> textNode = toText(node); |
- if (offset >= textNode->length()) { |
- insertNodeAfter(spanElement, textNode.release()); |
- } 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(spanElement, textNode.release()); |
- } |
- } |
- |
- // return the position following the new tab |
- return lastPositionInNode(spanElement.get()); |
-} |
- |
-} |