summaryrefslogtreecommitdiff
path: root/Source/WebCore/editing/ApplyBlockElementCommand.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/editing/ApplyBlockElementCommand.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/editing/ApplyBlockElementCommand.cpp')
-rw-r--r--Source/WebCore/editing/ApplyBlockElementCommand.cpp94
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;
}
}