1a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/* 2a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) 2010 Google Inc. All rights reserved. 4a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 5a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Redistribution and use in source and binary forms, with or without 6a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * modification, are permitted provided that the following conditions 7a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * are met: 8a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 1. Redistributions of source code must retain the above copyright 9a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * notice, this list of conditions and the following disclaimer. 10a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright 11a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * notice, this list of conditions and the following disclaimer in the 12a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * documentation and/or other materials provided with the distribution. 13a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 14a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */ 26a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 27a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "config.h" 28a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "ApplyBlockElementCommand.h" 29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 30a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HTMLElement.h" 31a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HTMLNames.h" 32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "Text.h" 33a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "TextIterator.h" 34a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "VisiblePosition.h" 35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "htmlediting.h" 36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "visible_units.h" 37a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochnamespace WebCore { 39a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 40a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochusing namespace HTMLNames; 41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 42a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochApplyBlockElementCommand::ApplyBlockElementCommand(Document* document, const QualifiedName& tagName, const AtomicString& className, const AtomicString& inlineStyle) 43a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch : CompositeEditCommand(document) 44a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_tagName(tagName) 45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_className(className) 46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_inlineStyle(inlineStyle) 47a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 48a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 50a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochApplyBlockElementCommand::ApplyBlockElementCommand(Document* document, const QualifiedName& tagName) 51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch : CompositeEditCommand(document) 52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_tagName(tagName) 53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid ApplyBlockElementCommand::doApply() 57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!endingSelection().isNonOrphanedCaretOrRange()) 59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 61a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!endingSelection().rootEditableElement()) 62a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 63a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 64a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition visibleEnd = endingSelection().visibleEnd(); 65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition visibleStart = endingSelection().visibleStart(); 66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // When a selection ends at the start of a paragraph, we rarely paint 67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // the selection gap before that paragraph, because there often is no gap. 68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // In a case like this, it's not obvious to the user that the selection 69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // ends "inside" that paragraph, so it would be confusing if Indent/Outdent 70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // operated on that paragraph. 71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // FIXME: We paint the gap before some paragraphs that are indented with left 72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // margin/padding, but not others. We should make the gap painting more consistent and 73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // then use a left margin/padding rule here. 74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd)) 752bde8e466a4451c7319e3a072d118917957d6554Steve Block setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary))); 76a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisibleSelection selection = selectionForParagraphIteration(endingSelection()); 78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition startOfSelection = selection.visibleStart(); 79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition endOfSelection = selection.visibleEnd(); 80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(!startOfSelection.isNull()); 81a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(!endOfSelection.isNull()); 82a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int startIndex = indexForVisiblePosition(startOfSelection); 83a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int endIndex = indexForVisiblePosition(endOfSelection); 84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 85a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch formatSelection(startOfSelection, endOfSelection); 86a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 87a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch updateLayout(); 88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Range> startRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), startIndex, 0, true); 90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Range> endRange = TextIterator::rangeFromLocationAndLength(document()->documentElement(), endIndex, 0, true); 91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (startRange && endRange) 92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch setEndingSelection(VisibleSelection(startRange->startPosition(), endRange->startPosition(), DOWNSTREAM)); 93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSelection, const VisiblePosition& endOfSelection) 96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Special case empty unsplittable elements because there's nothing to split 98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // and there's nothing to move. 99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Position start = startOfSelection.deepEquivalent().downstream(); 100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (isAtUnsplittableElement(start)) { 101a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Element> blockquote = createBlockElement(); 102a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch insertNodeAt(blockquote, start); 103a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Element> placeholder = createBreakElement(document()); 104a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch appendNode(placeholder, blockquote); 10565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch setEndingSelection(VisibleSelection(positionBeforeNode(placeholder.get()), DOWNSTREAM)); 106a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 107a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Element> blockquoteForNextIndent; 110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection); 111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition endAfterSelection = endOfParagraph(endOfParagraph(endOfSelection).next()); 112f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_endOfLastParagraph = endOfParagraph(endOfSelection).deepEquivalent(); 113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch bool atEnd = false; 115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Position end; 116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch while (endOfCurrentParagraph != endAfterSelection && !atEnd) { 117f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (endOfCurrentParagraph.deepEquivalent() == m_endOfLastParagraph) 118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch atEnd = true; 119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch rangeForParagraphSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end); 121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch endOfCurrentParagraph = end; 122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Position afterEnd = end.next(); 124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Node* enclosingCell = enclosingNodeOfType(start, &isTableCell); 125a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition endOfNextParagraph = endOfNextParagrahSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end); 126a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 127f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch formatRange(start, end, m_endOfLastParagraph, blockquoteForNextIndent); 128a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Don't put the next paragraph in the blockquote we just created for this paragraph unless 130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // the next paragraph is in the same cell. 131a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (enclosingCell && enclosingCell != enclosingNodeOfType(endOfNextParagraph.deepEquivalent(), &isTableCell)) 132a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch blockquoteForNextIndent = 0; 133a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // indentIntoBlockquote could move more than one paragraph if the paragraph 135a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // is in a list item or a table. As a result, endAfterSelection could refer to a position 136a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // no longer in the document. 13781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().anchorNode()->inDocument()) 138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch break; 13981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().deprecatedNode() 140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // If somehow we did, return to prevent crashes. 14181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().anchorNode()->inDocument()) { 142a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT_NOT_REACHED(); 143a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 145a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch endOfCurrentParagraph = endOfNextParagraph; 146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 148a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic bool isNewLineAtPosition(const Position& position) 150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (position.anchorType() != Position::PositionIsOffsetInAnchor) 152a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return false; 153a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Node* textNode = position.containerNode(); 155a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int offset = position.offsetInContainerNode(); 156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!textNode || !textNode->isTextNode() || offset < 0 || offset >= textNode->maxCharacterOffset()) 157a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return false; 158a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 159a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ExceptionCode ec = 0; 160a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch String textAtPosition = static_cast<Text*>(textNode)->substringData(offset, 1, ec); 161a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (ec) 162a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return false; 163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 164a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return textAtPosition[0] == '\n'; 165a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 167a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic RenderStyle* renderStyleOfEnclosingTextNode(const Position& position) 168a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 169a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (position.anchorType() != Position::PositionIsOffsetInAnchor 170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch || !position.containerNode() 171a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch || !position.containerNode()->isTextNode() 172a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch || !position.containerNode()->renderer()) 173a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return 0; 174a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return position.containerNode()->renderer()->style(); 175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 176a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 177a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const VisiblePosition& endOfCurrentParagraph, Position& start, Position& end) 178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch start = startOfParagraph(endOfCurrentParagraph).deepEquivalent(); 180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch end = endOfCurrentParagraph.deepEquivalent(); 181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 182a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start); 183f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch bool isStartAndEndOnSameNode = false; 184a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (startStyle) { 18581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.deprecatedNode() == end.deprecatedNode(); 18681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.deprecatedNode() == m_endOfLastParagraph.deprecatedNode(); 187f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Avoid obtanining the start of next paragraph for start 189a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (startStyle->preserveNewline() && isNewLineAtPosition(start) && !isNewLineAtPosition(start.previous()) && start.offsetInContainerNode() > 0) 190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch start = startOfParagraph(end.previous()).deepEquivalent(); 191a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // If start is in the middle of a text node, split. 193a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) { 194a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int startOffset = start.offsetInContainerNode(); 19581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch splitTextNode(static_cast<Text*>(start.deprecatedNode()), startOffset); 1962bde8e466a4451c7319e3a072d118917957d6554Steve Block start = firstPositionInOrBeforeNode(start.deprecatedNode()); 197f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (isStartAndEndOnSameNode) { 198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(end.offsetInContainerNode() >= startOffset); 19981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch end = Position(end.deprecatedNode(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor); 200a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 201f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (isStartAndEndOfLastParagraphOnSameNode) { 202f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch ASSERT(m_endOfLastParagraph.offsetInContainerNode() >= startOffset); 20381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_endOfLastParagraph = Position(m_endOfLastParagraph.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - startOffset, 204f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch Position::PositionIsOffsetInAnchor); 205f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 206a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end); 210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (endStyle) { 21181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.deprecatedNode() == m_endOfLastParagraph.deprecatedNode(); 212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Include \n at the end of line if we're at an empty paragraph 213a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (endStyle->preserveNewline() && start == end 214a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) { 215a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch int endOffset = end.offsetInContainerNode(); 216a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!isNewLineAtPosition(end.previous()) && isNewLineAtPosition(end)) 21781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch end = Position(end.deprecatedNode(), endOffset + 1, Position::PositionIsOffsetInAnchor); 218f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (isEndAndEndOfLastParagraphOnSameNode && end.offsetInContainerNode() >= m_endOfLastParagraph.offsetInContainerNode()) 219f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_endOfLastParagraph = end; 220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 222a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // If end is in the middle of a text node, split. 223a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode() 224a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) { 22581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch splitTextNode(static_cast<Text*>(end.deprecatedNode()), end.offsetInContainerNode()); 226f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (isStartAndEndOnSameNode) 2272bde8e466a4451c7319e3a072d118917957d6554Steve Block start = firstPositionInOrBeforeNode(end.deprecatedNode()->previousSibling()); 228f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (isEndAndEndOfLastParagraphOnSameNode) { 229f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode()) 23081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_endOfLastParagraph = lastPositionInNode(end.deprecatedNode()->previousSibling()); 231f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else 23281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch m_endOfLastParagraph = Position(end.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode(), 233f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch Position::PositionIsOffsetInAnchor); 234f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 23581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch end = lastPositionInNode(end.deprecatedNode()->previousSibling()); 236a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 237a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 238a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 240a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochVisiblePosition ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded(VisiblePosition& endOfCurrentParagraph, Position& start, Position& end) 241a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 242a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next()); 243a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch Position position = endOfNextParagraph.deepEquivalent(); 244a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RenderStyle* style = renderStyleOfEnclosingTextNode(position); 245a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!style) 246a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return endOfNextParagraph; 247a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Node> containerNode = position.containerNode(); 249a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!style->preserveNewline() || !position.offsetInContainerNode() 250a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch || !isNewLineAtPosition(Position(containerNode.get(), 0, Position::PositionIsOffsetInAnchor))) 251a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return endOfNextParagraph; 252a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 253a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // \n at the beginning of the text node immediately following the current paragraph is trimmed by moveParagraphWithClones. 254a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // If endOfNextParagraph was pointing at this same text node, endOfNextParagraph will be shifted by one paragraph. 255a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Avoid this by splitting "\n" 256a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch splitTextNode(static_cast<Text*>(containerNode.get()), 1); 257a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (start.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == start.containerNode()) { 259a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(start.offsetInContainerNode() < position.offsetInContainerNode()); 260a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch start = Position(containerNode->previousSibling(), start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor); 261a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (end.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == end.containerNode()) { 263a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(end.offsetInContainerNode() < position.offsetInContainerNode()); 264a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch end = Position(containerNode->previousSibling(), end.offsetInContainerNode(), Position::PositionIsOffsetInAnchor); 265a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 266f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (m_endOfLastParagraph.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == m_endOfLastParagraph.containerNode()) { 267f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (m_endOfLastParagraph.offsetInContainerNode() < position.offsetInContainerNode()) 268f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_endOfLastParagraph = Position(containerNode->previousSibling(), m_endOfLastParagraph.offsetInContainerNode(), Position::PositionIsOffsetInAnchor); 269f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else 270f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_endOfLastParagraph = Position(containerNode, m_endOfLastParagraph.offsetInContainerNode() - 1, Position::PositionIsOffsetInAnchor); 271f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 272a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 273a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return Position(containerNode.get(), position.offsetInContainerNode() - 1, Position::PositionIsOffsetInAnchor); 274a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 275a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 276a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochPassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() const 277a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 278a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch RefPtr<Element> element = createHTMLElement(document(), m_tagName); 279a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_className.length()) 280a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch element->setAttribute(classAttr, m_className); 281a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_inlineStyle.length()) 282a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch element->setAttribute(styleAttr, m_inlineStyle); 283a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return element.release(); 284a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 285a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 286a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 287