diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/editing/ApplyBlockElementCommand.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/editing/ApplyBlockElementCommand.cpp')
-rw-r--r-- | Source/WebCore/editing/ApplyBlockElementCommand.cpp | 94 |
1 files changed, 52 insertions, 42 deletions
diff --git a/Source/WebCore/editing/ApplyBlockElementCommand.cpp b/Source/WebCore/editing/ApplyBlockElementCommand.cpp index 2deb1b46d..6731880ea 100644 --- a/Source/WebCore/editing/ApplyBlockElementCommand.cpp +++ b/Source/WebCore/editing/ApplyBlockElementCommand.cpp @@ -27,12 +27,11 @@ #include "config.h" #include "ApplyBlockElementCommand.h" -#include "HTMLElement.h" +#include "HTMLBRElement.h" #include "HTMLNames.h" #include "RenderElement.h" #include "RenderStyle.h" #include "Text.h" -#include "TextIterator.h" #include "VisibleUnits.h" #include "htmlediting.h" @@ -71,8 +70,12 @@ void ApplyBlockElementCommand::doApply() // FIXME: We paint the gap before some paragraphs that are indented with left // margin/padding, but not others. We should make the gap painting more consistent and // then use a left margin/padding rule here. - if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd)) - setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary), endingSelection().isDirectional())); + if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd)) { + VisibleSelection newSelection(visibleStart, visibleEnd.previous(CannotCrossEditingBoundary), endingSelection().isDirectional()); + if (newSelection.isNone()) + return; + setEndingSelection(newSelection); + } VisibleSelection selection = selectionForParagraphIteration(endingSelection()); VisiblePosition startOfSelection = selection.visibleStart(); @@ -94,6 +97,11 @@ void ApplyBlockElementCommand::doApply() if (startScope == endScope && startIndex >= 0 && startIndex <= endIndex) { VisiblePosition start(visiblePositionForIndex(startIndex, startScope.get())); VisiblePosition end(visiblePositionForIndex(endIndex, endScope.get())); + // Work around the fact indexForVisiblePosition can return a larger index due to TextIterator + // using an extra newline to represent a large margin. + // FIXME: Add a new TextIteratorBehavior to suppress it. + if (start.isNotNull() && end.isNull()) + end = lastPositionInNode(endScope.get()); if (start.isNotNull() && end.isNotNull()) setEndingSelection(VisibleSelection(start, end, endingSelection().isDirectional())); } @@ -104,12 +112,12 @@ void ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSel // Special case empty unsplittable elements because there's nothing to split // and there's nothing to move. Position start = startOfSelection.deepEquivalent().downstream(); - if (isAtUnsplittableElement(start)) { - RefPtr<Element> blockquote = createBlockElement(); - insertNodeAt(blockquote, start); - RefPtr<Element> placeholder = createBreakElement(document()); - appendNode(placeholder, blockquote); - setEndingSelection(VisibleSelection(positionBeforeNode(placeholder.get()), DOWNSTREAM, endingSelection().isDirectional())); + if (isAtUnsplittableElement(start) && startOfParagraph(start) == endOfParagraph(endOfSelection)) { + auto blockquote = createBlockElement(); + insertNodeAt(blockquote.copyRef(), start); + auto placeholder = HTMLBRElement::create(document()); + appendNode(placeholder.copyRef(), WTFMove(blockquote)); + setEndingSelection(VisibleSelection(positionBeforeNode(placeholder.ptr()), DOWNSTREAM, endingSelection().isDirectional())); return; } @@ -127,25 +135,33 @@ void ApplyBlockElementCommand::formatSelection(const VisiblePosition& startOfSel rangeForParagraphSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end); endOfCurrentParagraph = end; + // FIXME: endOfParagraph can errornously return a position at the beginning of a block element + // when the position passed into endOfParagraph is at the beginning of a block. + // Work around this bug here because too much of the existing code depends on the current behavior of endOfParagraph. + if (start == end && startOfBlock(start) != endOfBlock(start) && !isEndOfBlock(end) && start == startOfParagraph(endOfBlock(start))) { + endOfCurrentParagraph = endOfBlock(end); + end = endOfCurrentParagraph.deepEquivalent(); + } + Position afterEnd = end.next(); Node* enclosingCell = enclosingNodeOfType(start, &isTableCell); - VisiblePosition endOfNextParagraph = endOfNextParagrahSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end); + VisiblePosition endOfNextParagraph = endOfNextParagraphSplittingTextNodesIfNeeded(endOfCurrentParagraph, start, end); formatRange(start, end, m_endOfLastParagraph, blockquoteForNextIndent); // Don't put the next paragraph in the blockquote we just created for this paragraph unless // the next paragraph is in the same cell. if (enclosingCell && enclosingCell != enclosingNodeOfType(endOfNextParagraph.deepEquivalent(), &isTableCell)) - blockquoteForNextIndent = 0; + blockquoteForNextIndent = nullptr; // indentIntoBlockquote could move more than one paragraph if the paragraph // is in a list item or a table. As a result, endAfterSelection could refer to a position // no longer in the document. - if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().anchorNode()->inDocument()) + if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent().anchorNode()->isConnected()) break; // Sanity check: Make sure our moveParagraph calls didn't remove endOfNextParagraph.deepEquivalent().deprecatedNode() // If somehow we did, return to prevent crashes. - if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().anchorNode()->inDocument()) { + if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent().anchorNode()->isConnected()) { ASSERT_NOT_REACHED(); return; } @@ -157,29 +173,23 @@ static bool isNewLineAtPosition(const Position& position) { Node* textNode = position.containerNode(); int offset = position.offsetInContainerNode(); - if (!textNode || !textNode->isTextNode() || offset < 0 || offset >= textNode->maxCharacterOffset()) + if (!is<Text>(textNode) || offset < 0 || offset >= textNode->maxCharacterOffset()) return false; - - ExceptionCode ec = 0; - String textAtPosition = toText(textNode)->substringData(offset, 1, ec); - if (ec) - return false; - - return textAtPosition[0] == '\n'; + return downcast<Text>(*textNode).data()[offset] == '\n'; } -RenderStyle* ApplyBlockElementCommand::renderStyleOfEnclosingTextNode(const Position& position) +const RenderStyle* ApplyBlockElementCommand::renderStyleOfEnclosingTextNode(const Position& position) { if (position.anchorType() != Position::PositionIsOffsetInAnchor || !position.containerNode() || !position.containerNode()->isTextNode()) - return 0; + return nullptr; document().updateStyleIfNeeded(); RenderObject* renderer = position.containerNode()->renderer(); if (!renderer) - return 0; + return nullptr; return &renderer->style(); } @@ -190,7 +200,7 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const end = endOfCurrentParagraph.deepEquivalent(); bool isStartAndEndOnSameNode = false; - if (RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start)) { + if (auto* startStyle = renderStyleOfEnclosingTextNode(start)) { isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.containerNode() == end.containerNode(); bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.containerNode() == m_endOfLastParagraph.containerNode(); @@ -215,7 +225,7 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const } } - if (RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end)) { + if (auto* endStyle = renderStyleOfEnclosingTextNode(end)) { bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.deprecatedNode() == m_endOfLastParagraph.deprecatedNode(); // Include \n at the end of line if we're at an empty paragraph if (endStyle->preserveNewline() && start == end && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) { @@ -226,8 +236,8 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const m_endOfLastParagraph = end; } - // If end is in the middle of a text node, split. - if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode() && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) { + // If end is in the middle of a text node and the text node is editable, split. + if (endStyle->userModify() != READ_ONLY && !endStyle->collapseWhiteSpace() && end.offsetInContainerNode() && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) { RefPtr<Text> endContainer = end.containerText(); splitTextNode(endContainer, end.offsetInContainerNode()); if (isStartAndEndOnSameNode) @@ -236,18 +246,18 @@ void ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded(const if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode()) m_endOfLastParagraph = lastPositionInOrAfterNode(endContainer->previousSibling()); else - m_endOfLastParagraph = Position(endContainer, m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode()); + m_endOfLastParagraph = Position(endContainer.get(), m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode()); } end = lastPositionInNode(endContainer->previousSibling()); } } } -VisiblePosition ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded(VisiblePosition& endOfCurrentParagraph, Position& start, Position& end) +VisiblePosition ApplyBlockElementCommand::endOfNextParagraphSplittingTextNodesIfNeeded(VisiblePosition& endOfCurrentParagraph, Position& start, Position& end) { VisiblePosition endOfNextParagraph = endOfParagraph(endOfCurrentParagraph.next()); Position position = endOfNextParagraph.deepEquivalent(); - RenderStyle* style = renderStyleOfEnclosingTextNode(position); + auto* style = renderStyleOfEnclosingTextNode(position); if (!style) return endOfNextParagraph; @@ -260,20 +270,20 @@ VisiblePosition ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfN // Avoid this by splitting "\n" splitTextNode(text, 1); - if (text == start.containerNode() && text->previousSibling() && text->previousSibling()->isTextNode()) { + if (text == start.containerNode() && is<Text>(text->previousSibling())) { ASSERT(start.offsetInContainerNode() < position.offsetInContainerNode()); - start = Position(toText(text->previousSibling()), start.offsetInContainerNode()); + start = Position(downcast<Text>(text->previousSibling()), start.offsetInContainerNode()); } - if (text == end.containerNode() && text->previousSibling() && text->previousSibling()->isTextNode()) { + if (text == end.containerNode() && is<Text>(text->previousSibling())) { ASSERT(end.offsetInContainerNode() < position.offsetInContainerNode()); - end = Position(toText(text->previousSibling()), end.offsetInContainerNode()); + end = Position(downcast<Text>(text->previousSibling()), end.offsetInContainerNode()); } if (text == m_endOfLastParagraph.containerNode()) { if (m_endOfLastParagraph.offsetInContainerNode() < position.offsetInContainerNode()) { // We can only fix endOfLastParagraph if the previous node was still text and hasn't been modified by script. - if (text->previousSibling()->isTextNode() - && static_cast<unsigned>(m_endOfLastParagraph.offsetInContainerNode()) <= toText(text->previousSibling())->length()) - m_endOfLastParagraph = Position(toText(text->previousSibling()), m_endOfLastParagraph.offsetInContainerNode()); + if (is<Text>(*text->previousSibling()) + && static_cast<unsigned>(m_endOfLastParagraph.offsetInContainerNode()) <= downcast<Text>(text->previousSibling())->length()) + m_endOfLastParagraph = Position(downcast<Text>(text->previousSibling()), m_endOfLastParagraph.offsetInContainerNode()); } else m_endOfLastParagraph = Position(text.get(), m_endOfLastParagraph.offsetInContainerNode() - 1); } @@ -281,12 +291,12 @@ VisiblePosition ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfN return Position(text.get(), position.offsetInContainerNode() - 1); } -PassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() +Ref<HTMLElement> ApplyBlockElementCommand::createBlockElement() { - RefPtr<Element> element = createHTMLElement(document(), m_tagName); + auto element = createHTMLElement(document(), m_tagName); if (m_inlineStyle.length()) element->setAttribute(styleAttr, m_inlineStyle); - return element.release(); + return element; } } |