18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met: 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer. 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * documentation and/or other materials provided with the distribution. 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h" 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "InsertTextCommand.h" 288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h" 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Element.h" 318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EditingText.h" 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Editor.h" 338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h" 348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLInterchange.h" 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h" 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "visible_units.h" 372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h> 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore { 408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectInsertTextCommand::InsertTextCommand(Document *document) 42cad810f21b803229eb11403f9209855525a25d57Steve Block : CompositeEditCommand(document) 438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid InsertTextCommand::doApply() 478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochPosition InsertTextCommand::positionInsideTextNode(const Position& p) 518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position pos = p; 5381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (isTabSpanTextNode(pos.anchorNode())) { 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RefPtr<Node> textNode = document()->createEditingTextNode(""); 5581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch insertNodeAtTabSpanPosition(textNode.get(), pos); 562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return firstPositionInNode(textNode.get()); 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // Prepare for text input by looking at the specified position. 6081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // It may be necessary to insert a text node to receive characters. 6181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!pos.containerNode()->isTextNode()) { 628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RefPtr<Node> textNode = document()->createEditingTextNode(""); 6381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch insertNodeAt(textNode.get(), pos); 642fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return firstPositionInNode(textNode.get()); 658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return pos; 688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// This avoids the expense of a full fledged delete operation, and avoids a layout that typically results 718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// from text removal. 728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool InsertTextCommand::performTrivialReplace(const String& text, bool selectInsertedText) 738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!endingSelection().isRange()) 758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (text.contains('\t') || text.contains(' ') || text.contains('\n')) 788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Position start = endingSelection().start().parentAnchoredEquivalent(); 812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Position end = endingSelection().end().parentAnchoredEquivalent(); 822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(start.anchorType() == Position::PositionIsOffsetInAnchor); 832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor); 842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode() || isTabSpanTextNode(start.containerNode())) 868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block replaceTextInNode(static_cast<Text*>(start.containerNode()), start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text); 892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Position endPosition(start.containerNode(), start.offsetInContainerNode() + text.length()); 912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // We could have inserted a part of composed character sequence, 938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // so we are basically treating ending selection as a range to avoid validation. 948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // <http://bugs.webkit.org/show_bug.cgi?id=15781> 958f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian VisibleSelection forcedEndingSelection; 968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project forcedEndingSelection.setWithoutValidation(start, endPosition); 978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project setEndingSelection(forcedEndingSelection); 982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!selectInsertedText) 1008f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian setEndingSelection(VisibleSelection(endingSelection().visibleEnd())); 1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return true; 1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1052fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid InsertTextCommand::input(const String& text, bool selectInsertedText, RebalanceType whitespaceRebalance) 1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 108f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick ASSERT(text.find('\n') == notFound); 1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 110e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!endingSelection().isNonOrphanedCaretOrRange()) 1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Delete the current selection. 1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: This delete operation blows away the typing style. 1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (endingSelection().isRange()) { 1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (performTrivialReplace(text, selectInsertedText)) 1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project deleteSelection(false, true, true, false); 1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Position startPosition(endingSelection().start()); 1225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Position placeholder; 1245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // We want to remove preserved newlines and brs that will collapse (and thus become unnecessary) when content 1255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // is inserted just before them. 1265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // FIXME: We shouldn't really have to do this, but removing placeholders is a workaround for 9661. 1275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // If the caret is just before a placeholder, downstream will normalize the caret to it. 1285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Position downstream(startPosition.downstream()); 1295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (lineBreakExistsAtPosition(downstream)) { 1305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // FIXME: This doesn't handle placeholders at the end of anonymous blocks. 1315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian VisiblePosition caret(startPosition); 1325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (isEndOfBlock(caret) && isStartOfParagraph(caret)) 1335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian placeholder = downstream; 1345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Don't remove the placeholder yet, otherwise the block we're inserting into would collapse before 1355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // we get a chance to insert into it. We check for a placeholder now, though, because doing so requires 1365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // the creation of a VisiblePosition, and if we did that post-insertion it would force a layout. 1375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Insert the character at the leftmost candidate. 1405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian startPosition = startPosition.upstream(); 1415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // It is possible for the node that contains startPosition to contain only unrendered whitespace, 1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // and so deleteInsignificantText could remove it. Save the position before the node in case that happens. 14481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Position positionBeforeStartNode(positionInParentBeforeNode(startPosition.containerNode())); 1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project deleteInsignificantText(startPosition.upstream(), startPosition.downstream()); 14681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (!startPosition.anchorNode()->inDocument()) 1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project startPosition = positionBeforeStartNode; 1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!startPosition.isCandidate()) 1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project startPosition = startPosition.downstream(); 1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project startPosition = positionAvoidingSpecialElementBoundary(startPosition); 1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position endPosition; 1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (text == "\t") { 1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project endPosition = insertTab(startPosition); 1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project startPosition = endPosition.previous(); 1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (placeholder.isNotNull()) 1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian removePlaceholderAt(placeholder); 1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Make sure the document is set up to receive text 16281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch startPosition = positionInsideTextNode(startPosition); 16381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT(startPosition.anchorType() == Position::PositionIsOffsetInAnchor); 16481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT(startPosition.containerNode()); 16581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch ASSERT(startPosition.containerNode()->isTextNode()); 1665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (placeholder.isNotNull()) 1675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian removePlaceholderAt(placeholder); 16881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Text* textNode = static_cast<Text*>(startPosition.containerNode()); 16981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch const unsigned offset = startPosition.offsetInContainerNode(); 1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project insertTextIntoNode(textNode, offset, text); 1722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block endPosition = Position(textNode, offset + text.length(), Position::PositionIsOffsetInAnchor); 1732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (whitespaceRebalance == RebalanceLeadingAndTrailingWhitespaces) { 1752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // The insertion may require adjusting adjacent whitespace, if it is present. 1762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block rebalanceWhitespaceAt(endPosition); 1772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Rebalancing on both sides isn't necessary if we've inserted only spaces. 1782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!shouldRebalanceLeadingWhitespaceFor(text)) 1792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block rebalanceWhitespaceAt(startPosition); 1802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } else { 1812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(whitespaceRebalance == RebalanceAllWhitespaces); 1822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (canRebalance(startPosition) && canRebalance(endPosition)) 18381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch rebalanceWhitespaceOnTextSubstring(textNode, startPosition.offsetInContainerNode(), endPosition.offsetInContainerNode()); 1842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // We could have inserted a part of composed character sequence, 1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // so we are basically treating ending selection as a range to avoid validation. 1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // <http://bugs.webkit.org/show_bug.cgi?id=15781> 1908f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian VisibleSelection forcedEndingSelection; 1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project forcedEndingSelection.setWithoutValidation(startPosition, endPosition); 1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project setEndingSelection(forcedEndingSelection); 1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Handle the case where there is a typing style. 1954576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (RefPtr<EditingStyle> typingStyle = document()->frame()->selection()->typingStyle()) { 1964576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang typingStyle->prepareToApplyAt(endPosition, EditingStyle::PreserveWritingDirection); 1974576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (!typingStyle->isEmpty()) 198f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch applyStyle(typingStyle.get()); 199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!selectInsertedText) 2028f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian setEndingSelection(VisibleSelection(endingSelection().end(), endingSelection().affinity())); 2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectPosition InsertTextCommand::insertTab(const Position& pos) 2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent(); 2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 20981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* node = insertPos.deprecatedNode(); 2105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian unsigned int offset = insertPos.deprecatedEditingOffset(); 2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // keep tabs coalesced in tab span 2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isTabSpanTextNode(node)) { 2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project insertTextIntoNode(static_cast<Text *>(node), offset, "\t"); 2152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return Position(node, offset + 1, Position::PositionIsOffsetInAnchor); 2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // create new tab span 2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RefPtr<Element> spanNode = createTabSpanElement(document()); 2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // place it 2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node->isTextNode()) { 2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project insertNodeAt(spanNode.get(), insertPos); 2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Text *textNode = static_cast<Text *>(node); 2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (offset >= textNode->length()) { 2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project insertNodeAfter(spanNode.get(), textNode); 2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // split node to make room for the span 2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // NOTE: splitTextNode uses textNode for the 2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // second node in the split, so we need to 2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // insert the span before it. 2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (offset > 0) 2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project splitTextNode(textNode, offset); 235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project insertNodeBefore(spanNode, textNode); 2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // return the position following the new tab 2402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return lastPositionInNode(spanNode.get()); 2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool InsertTextCommand::isInsertTextCommand() const 2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return true; 2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 249