summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/editing
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-18 13:36:51 +0100
committerSteve Block <steveblock@google.com>2011-05-24 15:38:28 +0100
commit2fc2651226baac27029e38c9d6ef883fa32084db (patch)
treee396d4bf89dcce6ed02071be66212495b1df1dec /Source/WebCore/editing
parentb3725cedeb43722b3b175aaeff70552e562d2c94 (diff)
downloadexternal_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.zip
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.gz
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.bz2
Merge WebKit at r78450: Initial merge by git.
Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1
Diffstat (limited to 'Source/WebCore/editing')
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.cpp164
-rw-r--r--Source/WebCore/editing/ApplyStyleCommand.h9
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.cpp71
-rw-r--r--Source/WebCore/editing/CompositeEditCommand.h3
-rw-r--r--Source/WebCore/editing/DeleteButtonController.cpp4
-rw-r--r--Source/WebCore/editing/EditingStyle.cpp24
-rw-r--r--Source/WebCore/editing/EditingStyle.h10
-rw-r--r--Source/WebCore/editing/Editor.cpp166
-rw-r--r--Source/WebCore/editing/Editor.h4
-rw-r--r--Source/WebCore/editing/EditorCommand.cpp24
-rw-r--r--Source/WebCore/editing/FormatBlockCommand.cpp3
-rw-r--r--Source/WebCore/editing/HTMLInterchange.cpp2
-rw-r--r--Source/WebCore/editing/InsertListCommand.cpp2
-rw-r--r--Source/WebCore/editing/InsertTextCommand.cpp56
-rw-r--r--Source/WebCore/editing/InsertTextCommand.h8
-rw-r--r--Source/WebCore/editing/MarkupAccumulator.cpp2
-rw-r--r--Source/WebCore/editing/MarkupAccumulator.h2
-rw-r--r--Source/WebCore/editing/MoveSelectionCommand.cpp28
-rw-r--r--Source/WebCore/editing/ReplaceSelectionCommand.cpp50
-rw-r--r--Source/WebCore/editing/SelectionController.cpp6
-rw-r--r--Source/WebCore/editing/SpellChecker.cpp2
-rw-r--r--Source/WebCore/editing/TextIterator.cpp11
-rw-r--r--Source/WebCore/editing/TypingCommand.cpp25
-rw-r--r--Source/WebCore/editing/TypingCommand.h21
-rw-r--r--Source/WebCore/editing/VisibleSelection.cpp15
-rw-r--r--Source/WebCore/editing/htmlediting.cpp46
-rw-r--r--Source/WebCore/editing/htmlediting.h14
-rw-r--r--Source/WebCore/editing/mac/SelectionControllerMac.mm17
-rw-r--r--Source/WebCore/editing/markup.cpp19
-rw-r--r--Source/WebCore/editing/visible_units.cpp28
30 files changed, 496 insertions, 340 deletions
diff --git a/Source/WebCore/editing/ApplyStyleCommand.cpp b/Source/WebCore/editing/ApplyStyleCommand.cpp
index 39350b9..ccade74 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.cpp
+++ b/Source/WebCore/editing/ApplyStyleCommand.cpp
@@ -113,7 +113,7 @@ public:
private:
void init(PassRefPtr<CSSStyleDeclaration>, const Position&);
void reconcileTextDecorationProperties(CSSMutableStyleDeclaration*);
- void extractTextStyles(Document*, CSSMutableStyleDeclaration*, bool shouldUseFixedFontDefautlSize);
+ void extractTextStyles(Document*, CSSMutableStyleDeclaration*, bool shouldUseFixedFontDefaultSize);
String m_cssStyle;
bool m_applyBold;
@@ -205,7 +205,31 @@ static void setTextDecorationProperty(CSSMutableStyleDeclaration* style, const C
}
}
-void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclaration* style, bool shouldUseFixedFontDefautlSize)
+static bool isCSSValueLength(CSSPrimitiveValue* value)
+{
+ return value->primitiveType() >= CSSPrimitiveValue::CSS_PX && value->primitiveType() <= CSSPrimitiveValue::CSS_PC;
+}
+
+int legacyFontSizeFromCSSValue(Document* document, CSSPrimitiveValue* value, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode mode)
+{
+ if (isCSSValueLength(value)) {
+ int pixelFontSize = value->getIntValue(CSSPrimitiveValue::CSS_PX);
+ int legacyFontSize = CSSStyleSelector::legacyFontSize(document, pixelFontSize, shouldUseFixedFontDefaultSize);
+ // Use legacy font size only if pixel value matches exactly to that of legacy font size.
+ int cssPrimitiveEquivalent = legacyFontSize - 1 + CSSValueXSmall;
+ if (mode == AlwaysUseLegacyFontSize || CSSStyleSelector::fontSizeForKeyword(document, cssPrimitiveEquivalent, shouldUseFixedFontDefaultSize) == pixelFontSize)
+ return legacyFontSize;
+
+ return 0;
+ }
+
+ if (CSSValueXSmall <= value->getIdent() && value->getIdent() <= CSSValueWebkitXxxLarge)
+ return value->getIdent() - CSSValueXSmall + 1;
+
+ return 0;
+}
+
+void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclaration* style, bool shouldUseFixedFontDefaultSize)
{
ASSERT(style);
@@ -260,20 +284,10 @@ void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclarati
if (RefPtr<CSSValue> fontSize = style->getPropertyCSSValue(CSSPropertyFontSize)) {
if (!fontSize->isPrimitiveValue())
style->removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size.
- else {
- CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(fontSize.get());
- if (value->primitiveType() >= CSSPrimitiveValue::CSS_PX && value->primitiveType() <= CSSPrimitiveValue::CSS_PC) {
- int pixelFontSize = value->getFloatValue(CSSPrimitiveValue::CSS_PX);
- int legacyFontSize = CSSStyleSelector::legacyFontSize(document, pixelFontSize, shouldUseFixedFontDefautlSize);
- // Use legacy font size only if pixel value matches exactly to that of legacy font size.
- if (CSSStyleSelector::fontSizeForKeyword(document, legacyFontSize - 1 + CSSValueXSmall, shouldUseFixedFontDefautlSize) == pixelFontSize) {
- m_applyFontSize = String::number(legacyFontSize);
- style->removeProperty(CSSPropertyFontSize);
- }
- } else if (CSSValueXSmall <= value->getIdent() && value->getIdent() <= CSSValueWebkitXxxLarge) {
- m_applyFontSize = String::number(value->getIdent() - CSSValueXSmall + 1);
- style->removeProperty(CSSPropertyFontSize);
- }
+ else if (int legacyFontSize = legacyFontSizeFromCSSValue(document, static_cast<CSSPrimitiveValue*>(fontSize.get()),
+ shouldUseFixedFontDefaultSize, UseLegacyFontSizeOnlyIfPixelValuesMatch)) {
+ m_applyFontSize = String::number(legacyFontSize);
+ style->removeProperty(CSSPropertyFontSize);
}
}
}
@@ -522,18 +536,17 @@ void ApplyStyleCommand::doApply()
// Apply the block-centric properties of the style.
RefPtr<EditingStyle> blockStyle = m_style->extractAndRemoveBlockProperties();
if (!blockStyle->isEmpty())
- applyBlockStyle(blockStyle->style());
+ applyBlockStyle(blockStyle.get());
// Apply any remaining styles to the inline elements.
if (!m_style->isEmpty() || m_styledInlineElement || m_isInlineElementToRemoveFunction) {
- RefPtr<CSSMutableStyleDeclaration> style = m_style->style() ? m_style->style() : CSSMutableStyleDeclaration::create();
applyRelativeFontStyleChange(m_style.get());
- applyInlineStyle(style.get());
+ applyInlineStyle(m_style.get());
}
break;
}
case ForceBlockProperties:
// Force all properties to be applied as block styles.
- applyBlockStyle(m_style->style());
+ applyBlockStyle(m_style.get());
break;
}
}
@@ -543,7 +556,7 @@ EditAction ApplyStyleCommand::editingAction() const
return m_editingAction;
}
-void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclaration *style)
+void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
{
// update document layout once before removing styles
// so that we avoid the expense of updating before each and every call
@@ -578,7 +591,7 @@ void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclaration *style)
VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next());
VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next());
while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) {
- StyleChange styleChange(style, paragraphStart.deepEquivalent());
+ StyleChange styleChange(style->style(), paragraphStart.deepEquivalent());
if (styleChange.cssStyle().length() || m_removeOnly) {
RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().node());
if (!m_removeOnly) {
@@ -588,9 +601,9 @@ void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclaration *style)
}
ASSERT(block->isHTMLElement());
if (block->isHTMLElement()) {
- removeCSSStyle(style, static_cast<HTMLElement*>(block.get()));
+ removeCSSStyle(style->style(), toHTMLElement(block.get()));
if (!m_removeOnly)
- addBlockStyle(styleChange, static_cast<HTMLElement*>(block.get()));
+ addBlockStyle(styleChange, toHTMLElement(block.get()));
}
if (nextParagraphStart.isOrphan())
@@ -677,7 +690,7 @@ void ApplyStyleCommand::applyRelativeFontStyleChange(EditingStyle* style)
// Only work on fully selected nodes.
if (!nodeFullySelected(node, start, end))
continue;
- element = static_cast<HTMLElement*>(node);
+ element = toHTMLElement(node);
} else if (node->isTextNode() && node->renderer() && node->parentNode() != lastStyledNode) {
// Last styled node was not parent node of this text node, but we wish to style this
// text node. To make this possible, add a style span to surround this text node.
@@ -741,7 +754,7 @@ void ApplyStyleCommand::cleanupUnstyledAppleStyleSpans(Node* dummySpanAncestor)
}
}
-HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool before, int allowedDirection)
+HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool before, WritingDirection allowedDirection)
{
// We are allowed to leave the highest ancestor with unicode-bidi unsplit if it is unicode-bidi: embed and direction: allowedDirection.
// In that case, we return the unsplit ancestor. Otherwise, we return 0.
@@ -766,13 +779,16 @@ HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(Node* node, bool b
HTMLElement* unsplitAncestor = 0;
- if (allowedDirection && highestAncestorUnicodeBidi != CSSValueBidiOverride
- && getIdentifierValue(computedStyle(highestAncestorWithUnicodeBidi).get(), CSSPropertyDirection) == allowedDirection
- && highestAncestorWithUnicodeBidi->isHTMLElement()) {
+ WritingDirection highestAncestorDirection;
+ if (allowedDirection != NaturalWritingDirection
+ && highestAncestorUnicodeBidi != CSSValueBidiOverride
+ && highestAncestorWithUnicodeBidi->isHTMLElement()
+ && EditingStyle::create(highestAncestorWithUnicodeBidi, EditingStyle::AllProperties)->textDirection(highestAncestorDirection)
+ && highestAncestorDirection == allowedDirection) {
if (!nextHighestAncestorWithUnicodeBidi)
- return static_cast<HTMLElement*>(highestAncestorWithUnicodeBidi);
+ return toHTMLElement(highestAncestorWithUnicodeBidi);
- unsplitAncestor = static_cast<HTMLElement*>(highestAncestorWithUnicodeBidi);
+ unsplitAncestor = toHTMLElement(highestAncestorWithUnicodeBidi);
highestAncestorWithUnicodeBidi = nextHighestAncestorWithUnicodeBidi;
}
@@ -836,7 +852,7 @@ static Node* highestEmbeddingAncestor(Node* startNode, Node* enclosingNode)
return 0;
}
-void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
+void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
{
Node* startDummySpanAncestor = 0;
Node* endDummySpanAncestor = 0;
@@ -858,7 +874,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
// split the start node and containing element if the selection starts inside of it
bool splitStart = isValidCaretPositionInTextNode(start);
if (splitStart) {
- if (shouldSplitTextElement(start.node()->parentElement(), style))
+ if (shouldSplitTextElement(start.node()->parentElement(), style->style()))
splitTextElementAtStart(start, end);
else
splitTextAtStart(start, end);
@@ -870,7 +886,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
// split the end node and containing element if the selection ends inside of it
bool splitEnd = isValidCaretPositionInTextNode(end);
if (splitEnd) {
- if (shouldSplitTextElement(end.node()->parentElement(), style))
+ if (shouldSplitTextElement(end.node()->parentElement(), style->style()))
splitTextElementAtEnd(start, end);
else
splitTextAtEnd(start, end);
@@ -885,15 +901,16 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
// and prevent us from adding redundant ones, as described in:
// <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
Position removeStart = start.upstream();
- int unicodeBidi = getIdentifierValue(style, CSSPropertyUnicodeBidi);
- int direction = 0;
- RefPtr<CSSMutableStyleDeclaration> styleWithoutEmbedding;
+ int unicodeBidi = getIdentifierValue(style->style(), CSSPropertyUnicodeBidi);
+ RefPtr<EditingStyle> styleWithoutEmbedding;
+ RefPtr<EditingStyle> embeddingStyle;
if (unicodeBidi) {
+ WritingDirection textDirection = NaturalWritingDirection;
+ style->textDirection(textDirection);
+
// Leave alone an ancestor that provides the desired single level embedding, if there is one.
- if (unicodeBidi == CSSValueEmbed)
- direction = getIdentifierValue(style, CSSPropertyDirection);
- HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.node(), true, direction);
- HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.node(), false, direction);
+ HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.node(), true, textDirection);
+ HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.node(), false, textDirection);
removeEmbeddingUpToEnclosingBlock(start.node(), startUnsplitAncestor);
removeEmbeddingUpToEnclosingBlock(end.node(), endUnsplitAncestor);
@@ -907,18 +924,15 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
embeddingRemoveEnd = positionInParentBeforeNode(endUnsplitAncestor).downstream();
if (embeddingRemoveEnd != removeStart || embeddingRemoveEnd != end) {
- RefPtr<CSSMutableStyleDeclaration> embeddingStyle = CSSMutableStyleDeclaration::create();
- embeddingStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
- embeddingStyle->setProperty(CSSPropertyDirection, direction);
- if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0)
- removeInlineStyle(embeddingStyle, embeddingRemoveStart, embeddingRemoveEnd);
styleWithoutEmbedding = style->copy();
- styleWithoutEmbedding->removeProperty(CSSPropertyUnicodeBidi);
- styleWithoutEmbedding->removeProperty(CSSPropertyDirection);
+ embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirection();
+
+ if (comparePositions(embeddingRemoveStart, embeddingRemoveEnd) <= 0)
+ removeInlineStyle(embeddingStyle->style(), embeddingRemoveStart, embeddingRemoveEnd);
}
}
- removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding.get() : style, removeStart, end);
+ removeInlineStyle(styleWithoutEmbedding ? styleWithoutEmbedding->style() : style->style(), removeStart, end);
start = startPosition();
end = endPosition();
if (start.isNull() || start.isOrphan() || end.isNull() || end.isOrphan())
@@ -942,7 +956,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
// to check a computed style
updateLayout();
- RefPtr<CSSMutableStyleDeclaration> styleToApply = style;
+ RefPtr<CSSMutableStyleDeclaration> styleToApply = style->isEmpty() ? CSSMutableStyleDeclaration::create() : style->style();
if (unicodeBidi) {
// Avoid applying the unicode-bidi and direction properties beneath ancestors that already have them.
Node* embeddingStartNode = highestEmbeddingAncestor(start.node(), enclosingBlock(start.node()));
@@ -953,18 +967,13 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style)
Position embeddingApplyEnd = embeddingEndNode ? positionInParentBeforeNode(embeddingEndNode) : end;
ASSERT(embeddingApplyStart.isNotNull() && embeddingApplyEnd.isNotNull());
- RefPtr<CSSMutableStyleDeclaration> embeddingStyle = CSSMutableStyleDeclaration::create();
- embeddingStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
- embeddingStyle->setProperty(CSSPropertyDirection, direction);
- fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStart, embeddingApplyEnd);
-
- if (styleWithoutEmbedding)
- styleToApply = styleWithoutEmbedding;
- else {
- styleToApply = style->copy();
- styleToApply->removeProperty(CSSPropertyUnicodeBidi);
- styleToApply->removeProperty(CSSPropertyDirection);
+ if (!embeddingStyle) {
+ styleWithoutEmbedding = style->copy();
+ embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDirection();
}
+ fixRangeAndApplyInlineStyle(embeddingStyle->style(), embeddingApplyStart, embeddingApplyEnd);
+
+ styleToApply = styleWithoutEmbedding->style();
}
}
@@ -1040,7 +1049,7 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*
if (pastEndNode && pastEndNode->isDescendantOf(node))
break;
// Add to this element's inline style and skip over its contents.
- HTMLElement* element = static_cast<HTMLElement*>(node);
+ HTMLElement* element = toHTMLElement(node);
RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineStyleDecl()->copy();
inlineStyle->merge(style);
setNodeAttribute(element, styleAttr, inlineStyle->cssText());
@@ -1110,7 +1119,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDec
RefPtr<Node> previousSibling = node->previousSibling();
RefPtr<Node> nextSibling = node->nextSibling();
RefPtr<ContainerNode> parent = node->parentNode();
- removeInlineStyleFromElement(style, static_cast<HTMLElement*>(node.get()), RemoveAlways);
+ removeInlineStyleFromElement(style, toHTMLElement(node.get()), RemoveAlways);
if (!node->inDocument()) {
// FIXME: We might need to update the start and the end of current selection here but need a test.
if (runStart == node)
@@ -1125,7 +1134,6 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDec
bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration* style, PassRefPtr<HTMLElement> element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
{
- ASSERT(style);
ASSERT(element);
if (!element->parentNode() || !element->parentNode()->isContentEditable())
@@ -1141,6 +1149,9 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration*
return true;
}
+ if (!style)
+ return false;
+
bool removed = false;
if (removeImplicitlyStyledElement(style, element.get(), mode, extractedStyle))
removed = true;
@@ -1214,6 +1225,7 @@ static const HTMLEquivalent HTMLEquivalents[] = {
bool ApplyStyleCommand::removeImplicitlyStyledElement(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
{
// Current implementation does not support stylePushedDown when mode == RemoveNone because of early exit.
+ ASSERT(style);
ASSERT(!extractedStyle || mode != RemoveNone);
bool removed = false;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(HTMLEquivalents); ++i) {
@@ -1336,8 +1348,8 @@ HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(CSSMut
Node* unsplittableElement = unsplittableElementForPosition(firstPositionInOrBeforeNode(node));
for (Node *n = node; n; n = n->parentNode()) {
- if (n->isHTMLElement() && shouldRemoveInlineStyleFromElement(style, static_cast<HTMLElement*>(n)))
- result = static_cast<HTMLElement*>(n);
+ if (n->isHTMLElement() && shouldRemoveInlineStyleFromElement(style, toHTMLElement(n)))
+ result = toHTMLElement(n);
// Should stop at the editable root (cannot cross editing boundary) and
// also stop at the unsplittable element to be consistent with other UAs
if (n == unsplittableElement)
@@ -1356,7 +1368,7 @@ void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, CSSMutableStyleDe
RefPtr<CSSMutableStyleDeclaration> newInlineStyle = style;
if (node->isHTMLElement()) {
- HTMLElement* element = static_cast<HTMLElement*>(node);
+ HTMLElement* element = toHTMLElement(node);
CSSMutableStyleDeclaration* existingInlineStyle = element->inlineStyleDecl();
// Avoid overriding existing styles of node
@@ -1392,7 +1404,7 @@ void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, CSSMutableStyleDe
// Since addInlineStyleIfNeeded can't add styles to block-flow render objects, add style attribute instead.
// FIXME: applyInlineStyleToRange should be used here instead.
if ((node->renderer()->isBlockFlow() || node->childNodeCount()) && node->isHTMLElement()) {
- setNodeAttribute(static_cast<HTMLElement*>(node), styleAttr, newInlineStyle->cssText());
+ setNodeAttribute(toHTMLElement(node), styleAttr, newInlineStyle->cssText());
return;
}
@@ -1428,7 +1440,7 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
elementsToPushDown.append(styledElement);
}
RefPtr<CSSMutableStyleDeclaration> styleToPushDown = CSSMutableStyleDeclaration::create();
- removeInlineStyleFromElement(style, static_cast<HTMLElement*>(current), RemoveIfNeeded, styleToPushDown.get());
+ removeInlineStyleFromElement(style, toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
// The inner loop will go through children on each level
// FIXME: we should aggregate inline child elements together so that we don't wrap each child separately.
@@ -1469,8 +1481,8 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>
ASSERT(start.node()->inDocument());
ASSERT(end.node()->inDocument());
ASSERT(comparePositions(start, end) <= 0);
-
- RefPtr<CSSValue> textDecorationSpecialProperty = style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect);
+
+ RefPtr<CSSValue> textDecorationSpecialProperty = style ? style->getPropertyCSSValue(CSSPropertyWebkitTextDecorationsInEffect) : 0;
if (textDecorationSpecialProperty) {
style = style->copy();
style->setProperty(CSSPropertyTextDecoration, textDecorationSpecialProperty->cssText(), style->getPropertyPriority(CSSPropertyWebkitTextDecorationsInEffect));
@@ -1500,7 +1512,7 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>
while (node) {
RefPtr<Node> next = node->traverseNextNode();
if (node->isHTMLElement() && nodeFullySelected(node, start, end)) {
- RefPtr<HTMLElement> elem = static_cast<HTMLElement*>(node);
+ RefPtr<HTMLElement> elem = toHTMLElement(node);
RefPtr<Node> prev = elem->traversePreviousNodePostOrder();
RefPtr<Node> next = elem->traverseNextNode();
RefPtr<CSSMutableStyleDeclaration> styleToPushDown;
@@ -1624,7 +1636,7 @@ bool ApplyStyleCommand::shouldSplitTextElement(Element* element, CSSMutableStyle
if (!element || !element->isHTMLElement())
return false;
- return shouldRemoveInlineStyleFromElement(style, static_cast<HTMLElement*>(element));
+ return shouldRemoveInlineStyleFromElement(style, toHTMLElement(element));
}
bool ApplyStyleCommand::isValidCaretPositionInTextNode(const Position& position)
@@ -1827,10 +1839,10 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style
HTMLElement* styleContainer = 0;
for (Node* container = startNode.get(); container && startNode == endNode; container = container->firstChild()) {
if (container->isHTMLElement() && container->hasTagName(fontTag))
- fontContainer = static_cast<HTMLElement*>(container);
+ fontContainer = toHTMLElement(container);
bool styleContainerIsNotSpan = !styleContainer || !styleContainer->hasTagName(spanTag);
if (container->isHTMLElement() && (container->hasTagName(spanTag) || (styleContainerIsNotSpan && container->childNodeCount())))
- styleContainer = static_cast<HTMLElement*>(container);
+ styleContainer = toHTMLElement(container);
if (!container->firstChild())
break;
startNode = container->firstChild();
@@ -1860,7 +1872,7 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style
if (styleChange.cssStyle().length()) {
if (styleContainer) {
- CSSMutableStyleDeclaration* existingStyle = static_cast<HTMLElement*>(styleContainer)->inlineStyleDecl();
+ CSSMutableStyleDeclaration* existingStyle = toHTMLElement(styleContainer)->inlineStyleDecl();
if (existingStyle)
setNodeAttribute(styleContainer, styleAttr, existingStyle->cssText() + styleChange.cssStyle());
else
diff --git a/Source/WebCore/editing/ApplyStyleCommand.h b/Source/WebCore/editing/ApplyStyleCommand.h
index 05af85c..1b2c2ef 100644
--- a/Source/WebCore/editing/ApplyStyleCommand.h
+++ b/Source/WebCore/editing/ApplyStyleCommand.h
@@ -28,6 +28,7 @@
#include "CompositeEditCommand.h"
#include "HTMLElement.h"
+#include "WritingDirection.h"
namespace WebCore {
@@ -90,9 +91,9 @@ private:
bool nodeFullyUnselected(Node*, const Position& start, const Position& end) const;
// style-application helpers
- void applyBlockStyle(CSSMutableStyleDeclaration*);
+ void applyBlockStyle(EditingStyle*);
void applyRelativeFontStyleChange(EditingStyle*);
- void applyInlineStyle(CSSMutableStyleDeclaration*);
+ void applyInlineStyle(EditingStyle*);
void fixRangeAndApplyInlineStyle(CSSMutableStyleDeclaration*, const Position& start, const Position& end);
void applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*, Node* startNode, Node* pastEndNode);
void addBlockStyle(const StyleChange&, HTMLElement*);
@@ -111,7 +112,7 @@ private:
float computedFontSize(Node*);
void joinChildTextNodes(Node*, const Position& start, const Position& end);
- HTMLElement* splitAncestorsWithUnicodeBidi(Node*, bool before, int allowedDirection);
+ HTMLElement* splitAncestorsWithUnicodeBidi(Node*, bool before, WritingDirection allowedDirection);
void removeEmbeddingUpToEnclosingBlock(Node* node, Node* unsplitAncestor);
void updateStartEnd(const Position& newStart, const Position& newEnd);
@@ -129,6 +130,8 @@ private:
IsInlineElementToRemoveFunction m_isInlineElementToRemoveFunction;
};
+enum LegacyFontSizeMode { AlwaysUseLegacyFontSize, UseLegacyFontSizeOnlyIfPixelValuesMatch };
+int legacyFontSizeFromCSSValue(Document*, CSSPrimitiveValue*, bool shouldUseFixedFontDefaultSize, LegacyFontSizeMode);
bool isStyleSpan(const Node*);
PassRefPtr<HTMLElement> createStyleSpanElement(Document*);
RefPtr<CSSMutableStyleDeclaration> getPropertiesNotIn(CSSStyleDeclaration* styleWithRedundantProperties, CSSStyleDeclaration* baseStyle);
diff --git a/Source/WebCore/editing/CompositeEditCommand.cpp b/Source/WebCore/editing/CompositeEditCommand.cpp
index 552ed79..ac3d761 100644
--- a/Source/WebCore/editing/CompositeEditCommand.cpp
+++ b/Source/WebCore/editing/CompositeEditCommand.cpp
@@ -28,7 +28,6 @@
#include "AppendNodeCommand.h"
#include "ApplyStyleCommand.h"
-#include "CharacterNames.h"
#include "DeleteFromTextNodeCommand.h"
#include "DeleteSelectionCommand.h"
#include "Document.h"
@@ -63,6 +62,7 @@
#include "htmlediting.h"
#include "markup.h"
#include "visible_units.h"
+#include <wtf/unicode/CharacterNames.h>
using namespace std;
@@ -390,57 +390,84 @@ void CompositeEditCommand::setNodeAttribute(PassRefPtr<Element> element, const Q
applyCommandToComposite(SetNodeAttributeCommand::create(element, attribute, value));
}
-static inline bool isWhitespace(UChar c)
+static inline bool containsOnlyWhitespace(const String& text)
{
- return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
+ for (unsigned i = 0; i < text.length(); ++i) {
+ if (!isWhitespace(text.characters()[i]))
+ return false;
+ }
+
+ return true;
}
-// FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
-void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
+bool CompositeEditCommand::shouldRebalanceLeadingWhitespaceFor(const String& text) const
+{
+ return containsOnlyWhitespace(text);
+}
+
+bool CompositeEditCommand::canRebalance(const Position& position) const
{
Node* node = position.containerNode();
if (position.anchorType() != Position::PositionIsOffsetInAnchor || !node || !node->isTextNode())
- return;
- Text* textNode = static_cast<Text*>(node);
+ return false;
+ Text* textNode = static_cast<Text*>(node);
if (textNode->length() == 0)
- return;
+ return false;
+
RenderObject* renderer = textNode->renderer();
if (renderer && !renderer->style()->collapseWhiteSpace())
- return;
+ return false;
- String text = textNode->data();
- ASSERT(!text.isEmpty());
+ return true;
+}
+
+// FIXME: Doesn't go into text nodes that contribute adjacent text (siblings, cousins, etc).
+void CompositeEditCommand::rebalanceWhitespaceAt(const Position& position)
+{
+ Node* node = position.containerNode();
+ if (!canRebalance(position))
+ return;
+ // If the rebalance is for the single offset, and neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
int offset = position.deprecatedEditingOffset();
- // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
+ String text = static_cast<Text*>(node)->data();
if (!isWhitespace(text[offset])) {
offset--;
if (offset < 0 || !isWhitespace(text[offset]))
return;
}
-
+
+ rebalanceWhitespaceOnTextSubstring(static_cast<Text*>(node), position.offsetInContainerNode(), position.offsetInContainerNode());
+}
+
+void CompositeEditCommand::rebalanceWhitespaceOnTextSubstring(RefPtr<Text> textNode, int startOffset, int endOffset)
+{
+ String text = textNode->data();
+ ASSERT(!text.isEmpty());
+
// Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
- int upstream = offset;
+ int upstream = startOffset;
while (upstream > 0 && isWhitespace(text[upstream - 1]))
upstream--;
- int downstream = offset;
- while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
+ int downstream = endOffset;
+ while ((unsigned)downstream < text.length() && isWhitespace(text[downstream]))
downstream++;
- int length = downstream - upstream + 1;
- ASSERT(length > 0);
-
- VisiblePosition visibleUpstreamPos(Position(position.containerNode(), upstream, Position::PositionIsOffsetInAnchor));
- VisiblePosition visibleDownstreamPos(Position(position.containerNode(), downstream + 1, Position::PositionIsOffsetInAnchor));
+ int length = downstream - upstream;
+ if (!length)
+ return;
+
+ VisiblePosition visibleUpstreamPos(Position(textNode, upstream, Position::PositionIsOffsetInAnchor));
+ VisiblePosition visibleDownstreamPos(Position(textNode, downstream, Position::PositionIsOffsetInAnchor));
String string = text.substring(upstream, length);
String rebalancedString = stringWithRebalancedWhitespace(string,
// FIXME: Because of the problem mentioned at the top of this function, we must also use nbsps at the start/end of the string because
// this function doesn't get all surrounding whitespace, just the whitespace in the current text node.
isStartOfParagraph(visibleUpstreamPos) || upstream == 0,
- isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length() - 1);
+ isEndOfParagraph(visibleDownstreamPos) || (unsigned)downstream == text.length());
if (string != rebalancedString)
replaceTextInNode(textNode, upstream, length, rebalancedString);
diff --git a/Source/WebCore/editing/CompositeEditCommand.h b/Source/WebCore/editing/CompositeEditCommand.h
index 6db4eb1..9066b65 100644
--- a/Source/WebCore/editing/CompositeEditCommand.h
+++ b/Source/WebCore/editing/CompositeEditCommand.h
@@ -71,7 +71,10 @@ protected:
void mergeIdenticalElements(PassRefPtr<Element>, PassRefPtr<Element>);
void rebalanceWhitespace();
void rebalanceWhitespaceAt(const Position&);
+ void rebalanceWhitespaceOnTextSubstring(RefPtr<Text>, int startOffset, int endOffset);
void prepareWhitespaceAtPositionForSplit(Position&);
+ bool canRebalance(const Position&) const;
+ bool shouldRebalanceLeadingWhitespaceFor(const String&) const;
void removeCSSProperty(PassRefPtr<StyledElement>, CSSPropertyID);
void removeNodeAttribute(PassRefPtr<Element>, const QualifiedName& attribute);
void removeChildrenInRange(PassRefPtr<Node>, unsigned from, unsigned to);
diff --git a/Source/WebCore/editing/DeleteButtonController.cpp b/Source/WebCore/editing/DeleteButtonController.cpp
index 61e3190..75b9a96 100644
--- a/Source/WebCore/editing/DeleteButtonController.cpp
+++ b/Source/WebCore/editing/DeleteButtonController.cpp
@@ -164,7 +164,7 @@ static HTMLElement* enclosingDeletableElement(const VisibleSelection& selection)
return 0;
ASSERT(element->isHTMLElement());
- return static_cast<HTMLElement*>(element);
+ return toHTMLElement(element);
}
void DeleteButtonController::respondToChangedSelection(const VisibleSelection& oldSelection)
@@ -263,7 +263,7 @@ void DeleteButtonController::show(HTMLElement* element)
if (!enabled() || !element || !element->inDocument() || !isDeletableElement(element))
return;
- if (!m_frame->editor()->shouldShowDeleteInterface(static_cast<HTMLElement*>(element)))
+ if (!m_frame->editor()->shouldShowDeleteInterface(toHTMLElement(element)))
return;
// we rely on the renderer having current information, so we should update the layout if needed
diff --git a/Source/WebCore/editing/EditingStyle.cpp b/Source/WebCore/editing/EditingStyle.cpp
index 8caf4b6..a3f66be 100644
--- a/Source/WebCore/editing/EditingStyle.cpp
+++ b/Source/WebCore/editing/EditingStyle.cpp
@@ -90,18 +90,18 @@ EditingStyle::EditingStyle()
{
}
-EditingStyle::EditingStyle(Node* node)
+EditingStyle::EditingStyle(Node* node, PropertiesToInclude propertiesToInclude)
: m_shouldUseFixedDefaultFontSize(false)
, m_fontSizeDelta(NoFontDelta)
{
- init(node);
+ init(node, propertiesToInclude);
}
EditingStyle::EditingStyle(const Position& position)
: m_shouldUseFixedDefaultFontSize(false)
, m_fontSizeDelta(NoFontDelta)
{
- init(position.node());
+ init(position.node(), OnlyInheritableProperties);
}
EditingStyle::EditingStyle(const CSSStyleDeclaration* style)
@@ -116,10 +116,10 @@ EditingStyle::~EditingStyle()
{
}
-void EditingStyle::init(Node* node)
+void EditingStyle::init(Node* node, PropertiesToInclude propertiesToInclude)
{
RefPtr<CSSComputedStyleDeclaration> computedStyleAtPosition = computedStyle(node);
- m_mutableStyle = editingStyleFromComputedStyle(computedStyleAtPosition);
+ m_mutableStyle = propertiesToInclude == AllProperties && computedStyleAtPosition ? computedStyleAtPosition->copy() : editingStyleFromComputedStyle(computedStyleAtPosition);
if (node && node->computedStyle()) {
RenderStyle* renderStyle = node->computedStyle();
@@ -255,6 +255,20 @@ PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveBlockProperties()
return blockProperties;
}
+PassRefPtr<EditingStyle> EditingStyle::extractAndRemoveTextDirection()
+{
+ RefPtr<EditingStyle> textDirection = EditingStyle::create();
+ textDirection->m_mutableStyle = CSSMutableStyleDeclaration::create();
+ textDirection->m_mutableStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed, m_mutableStyle->getPropertyPriority(CSSPropertyUnicodeBidi));
+ textDirection->m_mutableStyle->setProperty(CSSPropertyDirection, m_mutableStyle->getPropertyValue(CSSPropertyDirection),
+ m_mutableStyle->getPropertyPriority(CSSPropertyDirection));
+
+ m_mutableStyle->removeProperty(CSSPropertyUnicodeBidi);
+ m_mutableStyle->removeProperty(CSSPropertyDirection);
+
+ return textDirection;
+}
+
void EditingStyle::removeBlockProperties()
{
if (!m_mutableStyle)
diff --git a/Source/WebCore/editing/EditingStyle.h b/Source/WebCore/editing/EditingStyle.h
index a71b4ad..129ade5 100644
--- a/Source/WebCore/editing/EditingStyle.h
+++ b/Source/WebCore/editing/EditingStyle.h
@@ -47,6 +47,7 @@ class RenderStyle;
class EditingStyle : public RefCounted<EditingStyle> {
public:
+ enum PropertiesToInclude { AllProperties, OnlyInheritableProperties };
enum ShouldPreserveWritingDirection { PreserveWritingDirection, DoNotPreserveWritingDirection };
static float NoFontDelta;
@@ -55,9 +56,9 @@ public:
return adoptRef(new EditingStyle());
}
- static PassRefPtr<EditingStyle> create(Node* node)
+ static PassRefPtr<EditingStyle> create(Node* node, PropertiesToInclude propertiesToInclude = OnlyInheritableProperties)
{
- return adoptRef(new EditingStyle(node));
+ return adoptRef(new EditingStyle(node, propertiesToInclude));
}
static PassRefPtr<EditingStyle> create(const Position& position)
@@ -80,6 +81,7 @@ public:
void clear();
PassRefPtr<EditingStyle> copy() const;
PassRefPtr<EditingStyle> extractAndRemoveBlockProperties();
+ PassRefPtr<EditingStyle> extractAndRemoveTextDirection();
void removeBlockProperties();
void removeStyleAddedByNode(Node*);
void removeStyleConflictingWithStyleOfNode(Node*);
@@ -91,10 +93,10 @@ public:
private:
EditingStyle();
- EditingStyle(Node*);
+ EditingStyle(Node*, PropertiesToInclude);
EditingStyle(const Position&);
EditingStyle(const CSSStyleDeclaration*);
- void init(Node*);
+ void init(Node*, PropertiesToInclude);
void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
void replaceFontSizeByKeywordIfPossible(RenderStyle*, CSSComputedStyleDeclaration*);
void extractFontSizeDelta();
diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp
index 23b41ce..99624b3 100644
--- a/Source/WebCore/editing/Editor.cpp
+++ b/Source/WebCore/editing/Editor.cpp
@@ -36,7 +36,6 @@
#include "CSSStyleSelector.h"
#include "CSSValueKeywords.h"
#include "CachedResourceLoader.h"
-#include "CharacterNames.h"
#include "ClipboardEvent.h"
#include "CompositionEvent.h"
#include "CreateLinkCommand.h"
@@ -83,6 +82,7 @@
#include "markup.h"
#include "visible_units.h"
#include <wtf/UnusedParam.h>
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -116,6 +116,7 @@ static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection()
if (markerTypesForAutoCorrection.isEmpty()) {
markerTypesForAutoCorrection.append(DocumentMarker::Replacement);
markerTypesForAutoCorrection.append(DocumentMarker::CorrectionIndicator);
+ markerTypesForAutoCorrection.append(DocumentMarker::SpellCheckingExemption);
}
return markerTypesForAutoCorrection;
}
@@ -123,8 +124,10 @@ static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection()
static const Vector<DocumentMarker::MarkerType>& markerTypesForReplacement()
{
DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForReplacement, ());
- if (markerTypesForReplacement.isEmpty())
+ if (markerTypesForReplacement.isEmpty()) {
markerTypesForReplacement.append(DocumentMarker::Replacement);
+ markerTypesForReplacement.append(DocumentMarker::SpellCheckingExemption);
+ }
return markerTypesForReplacement;
}
@@ -505,19 +508,12 @@ bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
{
-#if SUPPORT_AUTOCORRECTION_PANEL
- VisibleSelection currentSelection(frame()->selection()->selection());
- if (currentSelection != oldSelection) {
- stopCorrectionPanelTimer();
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
- }
-#endif // SUPPORT_AUTOCORRECTION_PANEL
-
if (client())
client()->respondToChangedSelection();
m_deleteButtonController->respondToChangedSelection(oldSelection);
#if SUPPORT_AUTOCORRECTION_PANEL
+ VisibleSelection currentSelection(frame()->selection()->selection());
// When user moves caret to the end of autocorrected word and pauses, we show the panel
// containing the original pre-correction word so that user can quickly revert the
// undesired autocorrection. Here, we start correction panel timer once we confirm that
@@ -1051,10 +1047,10 @@ String Editor::selectionStartCSSPropertyValue(int propertyID)
if (propertyID == CSSPropertyFontSize) {
RefPtr<CSSValue> cssValue = selectionStyle->getPropertyCSSValue(CSSPropertyFontSize);
- ASSERT(cssValue->isPrimitiveValue());
- int fontPixelSize = static_cast<CSSPrimitiveValue*>(cssValue.get())->getIntValue(CSSPrimitiveValue::CSS_PX);
- int size = CSSStyleSelector::legacyFontSize(m_frame->document(), fontPixelSize, shouldUseFixedFontDefaultSize);
- value = String::number(size);
+ if (cssValue->isPrimitiveValue()) {
+ value = String::number(legacyFontSizeFromCSSValue(m_frame->document(), static_cast<CSSPrimitiveValue*>(cssValue.get()),
+ shouldUseFixedFontDefaultSize, AlwaysUseLegacyFontSize));
+ }
}
return value;
@@ -1089,14 +1085,20 @@ void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
m_frame->document()->updateLayout();
dispatchEditableContentChangedEvents(*cmd);
-
VisibleSelection newSelection(cmd->endingSelection());
+
+#if SUPPORT_AUTOCORRECTION_PANEL
+ // Check to see if the command introduced paragraph separator. If it did, we remove existing autocorrection underlines. This is in consistency with the behavior in AppKit.
+ if (cmd->isTopLevelCommand() && !inSameParagraph(cmd->startingSelection().start(), newSelection.end()))
+ m_frame->document()->markers()->removeMarkers(DocumentMarker::CorrectionIndicator);
+#endif
+
// Don't clear the typing style with this selection change. We do those things elsewhere if necessary.
changeSelectionAfterCommand(newSelection, false, false);
-
+
if (!cmd->preservesTypingStyle())
m_frame->selection()->clearTypingStyle();
-
+
// Command will be equal to last edit command only in the case of typing
if (m_lastEditCommand.get() == cmd)
ASSERT(cmd->isTypingCommand());
@@ -1173,7 +1175,12 @@ bool Editor::insertText(const String& text, Event* triggeringEvent)
return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
}
-bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
+bool Editor::insertTextForConfirmedComposition(const String& text)
+{
+ return m_frame->eventHandler()->handleTextInputEvent(text, 0, TextEventInputComposition);
+}
+
+bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, TextEvent* triggeringEvent)
{
if (text.isEmpty())
return false;
@@ -1186,6 +1193,9 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
return true;
+ if (text == " " || text == "\t")
+ applyAutocorrectionBeforeTypingIfAppropriate();
+
// Get the selection to use for the event that triggered this insertText.
// If the event handler changed the selection, we may want to use a different selection
// that is contained in the event target.
@@ -1195,7 +1205,8 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
RefPtr<Document> document = selectionStart->document();
// Insert the text
- TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
+ TypingCommand::insertText(document.get(), text, selection, selectInsertedText,
+ triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone);
// Reveal the current selection
if (Frame* editedFrame = document->frame())
@@ -1215,6 +1226,8 @@ bool Editor::insertLineBreak()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
+ applyAutocorrectionBeforeTypingIfAppropriate();
+
TypingCommand::insertLineBreak(m_frame->document());
revealSelectionAfterEditingOperation();
return true;
@@ -1231,6 +1244,8 @@ bool Editor::insertParagraphSeparator()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
+ applyAutocorrectionBeforeTypingIfAppropriate();
+
TypingCommand::insertParagraphSeparator(m_frame->document());
revealSelectionAfterEditingOperation();
return true;
@@ -1543,7 +1558,7 @@ void Editor::setBaseWritingDirection(WritingDirection direction)
if (focusedNode && (focusedNode->hasTagName(textareaTag) || (focusedNode->hasTagName(inputTag) && static_cast<HTMLInputElement*>(focusedNode)->isTextField()))) {
if (direction == NaturalWritingDirection)
return;
- static_cast<HTMLElement*>(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
+ toHTMLElement(focusedNode)->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
frame()->document()->updateStyleIfNeeded();
return;
}
@@ -1618,7 +1633,7 @@ void Editor::confirmComposition(const String& text, bool preserveSelection)
m_compositionNode = 0;
m_customCompositionUnderlines.clear();
- insertText(text, 0);
+ insertTextForConfirmedComposition(text);
if (preserveSelection) {
m_frame->selection()->setSelection(oldSelection, false, false);
@@ -1687,7 +1702,7 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
m_customCompositionUnderlines.clear();
if (!text.isEmpty()) {
- TypingCommand::insertText(m_frame->document(), text, true, true);
+ TypingCommand::insertText(m_frame->document(), text, true, TypingCommand::TextCompositionUpdate);
// Find out what node has the composition now.
Position base = m_frame->selection()->base().downstream();
@@ -2210,6 +2225,9 @@ void Editor::markBadGrammar(const VisibleSelection& selection)
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCheckingOptions, Range* spellingRange, Range* grammarRange)
{
+ // There shouldn't be pending autocorrection at this moment.
+ ASSERT(!m_correctionPanelInfo.rangeToBeReplaced);
+
bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
@@ -2303,6 +2321,10 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingParagraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) {
ASSERT(resultLength > 0 && resultLocation >= 0);
RefPtr<Range> misspellingRange = spellingParagraph.subrange(resultLocation, resultLength);
+#if SUPPORT_AUTOCORRECTION_PANEL
+ if (m_frame->document()->markers()->hasMarkers(misspellingRange.get(), DocumentMarker::SpellCheckingExemption))
+ continue;
+#endif // SUPPORT_AUTOCORRECTION_PANEL
misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
} else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && grammarParagraph.checkingRangeCovers(resultLocation, resultLength)) {
ASSERT(resultLength > 0 && resultLocation >= 0);
@@ -2406,6 +2428,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::SpellCheckingExemption);
}
}
}
@@ -2488,8 +2511,10 @@ void Editor::correctionPanelTimerFired(Timer<Editor>*)
String paragraphText = plainText(TextCheckingParagraph(m_correctionPanelInfo.rangeToBeReplaced).paragraphRange().get());
Vector<String> suggestions;
client()->getGuessesForWord(m_correctionPanelInfo.replacedString, paragraphText, suggestions);
- if (suggestions.isEmpty())
+ if (suggestions.isEmpty()) {
+ m_correctionPanelInfo.rangeToBeReplaced.clear();
break;
+ }
String topSuggestion = suggestions.first();
suggestions.remove(0);
m_correctionPanelInfo.isActive = true;
@@ -2649,44 +2674,8 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
// of marker that contains the word in question, and remove marker on that whole range.
Document* document = m_frame->document();
RefPtr<Range> wordRange = Range::create(document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
- RefPtr<Range> rangeOfFirstWord = Range::create(document, startOfFirstWord.deepEquivalent(), endOfFirstWord.deepEquivalent());
- RefPtr<Range> rangeOfLastWord = Range::create(document, startOfLastWord.deepEquivalent(), endOfLastWord.deepEquivalent());
-
- typedef pair<RefPtr<Range>, DocumentMarker::MarkerType> RangeMarkerPair;
- // It's probably unsafe to remove marker while iterating a vector of markers. So we store the markers and ranges that we want to remove temporarily. Then remove them at the end of function.
- // To avoid allocation on the heap, Give markersToRemove a small inline capacity
- Vector<RangeMarkerPair, 16> markersToRemove;
- for (TextIterator textIterator(wordRange.get()); !textIterator.atEnd(); textIterator.advance()) {
- Node* node = textIterator.node();
- if (!node)
- continue;
- if (node == startOfFirstWord.deepEquivalent().containerNode() || node == endOfLastWord.deepEquivalent().containerNode()) {
- // First word and last word can belong to the same node
- bool processFirstWord = node == startOfFirstWord.deepEquivalent().containerNode() && document->markers()->hasMarkers(rangeOfFirstWord.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator);
- bool processLastWord = node == endOfLastWord.deepEquivalent().containerNode() && document->markers()->hasMarkers(rangeOfLastWord.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator);
- // Take note on the markers whose range overlaps with the range of the first word or the last word.
- Vector<DocumentMarker> markers = document->markers()->markersForNode(node);
- for (size_t i = 0; i < markers.size(); ++i) {
- DocumentMarker marker = markers[i];
- if (processFirstWord && static_cast<int>(marker.endOffset) > startOfFirstWord.deepEquivalent().offsetInContainerNode() && (marker.type == DocumentMarker::Spelling || marker.type == DocumentMarker::CorrectionIndicator)) {
- RefPtr<Range> markerRange = Range::create(document, node, marker.startOffset, node, marker.endOffset);
- markersToRemove.append(std::make_pair(markerRange, marker.type));
- }
- if (processLastWord && static_cast<int>(marker.startOffset) <= endOfLastWord.deepEquivalent().offsetInContainerNode() && (marker.type == DocumentMarker::Spelling || marker.type == DocumentMarker::CorrectionIndicator)) {
- RefPtr<Range> markerRange = Range::create(document, node, marker.startOffset, node, marker.endOffset);
- markersToRemove.append(std::make_pair(markerRange, marker.type));
- }
- }
- } else {
- document->markers()->removeMarkers(node, DocumentMarker::Spelling);
- document->markers()->removeMarkers(node, DocumentMarker::CorrectionIndicator);
- }
- }
- // Actually remove the markers.
- Vector<RangeMarkerPair>::const_iterator pairEnd = markersToRemove.end();
- for (Vector<RangeMarkerPair>::const_iterator pairIterator = markersToRemove.begin(); pairIterator != pairEnd; ++pairIterator)
- document->markers()->removeMarkers(pairIterator->first.get(), pairIterator->second);
+ document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption, DocumentMarkerController::RemovePartiallyOverlappingMarker);
}
void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd)
@@ -2719,7 +2708,6 @@ void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>&
// Take note of the location of autocorrection so that we can add marker after the replacement took place.
int correctionStartOffsetInParagraph = TextIterator::rangeLength(correctionStartOffsetInParagraphAsRange.get());
- Position caretPosition = m_frame->selection()->selection().end();
// Clone the range, since the caller of this method may want to keep the original range around.
RefPtr<Range> rangeToBeReplaced = m_correctionPanelInfo.rangeToBeReplaced->cloneRange(ec);
@@ -2727,17 +2715,34 @@ void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>&
if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
m_frame->selection()->setSelection(selectionToReplace);
replaceSelectionWithText(m_correctionPanelInfo.replacementString, false, false);
- caretPosition.moveToOffset(caretPosition.offsetInContainerNode() + m_correctionPanelInfo.replacementString.length() - m_correctionPanelInfo.replacedString.length());
- setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(caretPosition));
+ setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
size_t size = markerTypesToAdd.size();
- for (size_t i = 0; i < size; ++i)
- markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacementString);
- m_frame->selection()->moveTo(caretPosition, false);
+ for (size_t i = 0; i < size; ++i) {
+ if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
+ markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
+ else
+ markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
+ }
}
}
+void Editor::applyAutocorrectionBeforeTypingIfAppropriate()
+{
+ if (!m_correctionPanelInfo.rangeToBeReplaced || !m_correctionPanelInfo.isActive)
+ return;
+
+ if (m_correctionPanelInfo.panelType != CorrectionPanelInfo::PanelTypeCorrection)
+ return;
+
+ Position caretPosition = m_frame->selection()->selection().start();
+
+ // Pending correction should always be where caret is. But in case this is not always true, we still want to dismiss the panel without accepting the correction.
+ ASSERT(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition);
+ dismissCorrectionPanel(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition ? ReasonForDismissingCorrectionPanelAccepted : ReasonForDismissingCorrectionPanelIgnored);
+}
+
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
{
Document* document = m_frame->documentAtPoint(windowPoint);
@@ -3004,13 +3009,6 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
return;
-#if SUPPORT_AUTOCORRECTION_PANEL
- // Check to see if the command introduced paragraph separator. If it did, we remove existing autocorrection underlines.
- // This is in consistency with the behavior in AppKit
- if (!inSameParagraph(m_frame->selection()->selection().visibleStart(), newSelection.visibleEnd()))
- m_frame->document()->markers()->removeMarkers(DocumentMarker::CorrectionIndicator);
-#endif
-
// If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
// because there is work that it must do in this situation.
// The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
@@ -3018,13 +3016,13 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection))
m_frame->selection()->setSelection(newSelection, closeTyping, clearTypingStyle);
-
+
// Some editing operations change the selection visually without affecting its position within the DOM.
- // For example when you press return in the following (the caret is marked by ^):
+ // For example when you press return in the following (the caret is marked by ^):
// <div contentEditable="true"><div>^Hello</div></div>
// WebCore inserts <div><br></div> *before* the current block, which correctly moves the paragraph down but which doesn't
// change the caret's DOM position (["hello", 0]). In these situations the above SelectionController::setSelection call
- // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and
+ // does not call EditorClient::respondToChangedSelection(), which, on the Mac, sends selection change notifications and
// starts a new kill ring sequence, but we want to do these things (matches AppKit).
if (selectionDidNotChangeDOMPosition)
client()->respondToChangedSelection();
@@ -3142,8 +3140,7 @@ PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shou
if (!m_frame->selection()->typingStyle())
return mutableStyle;
- RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle();
- typingStyle->removeNonEditingProperties();
+ RefPtr<EditingStyle> typingStyle = m_frame->selection()->typingStyle()->copy();
typingStyle->prepareToApplyAt(position);
mutableStyle->merge(typingStyle->style());
@@ -3421,7 +3418,11 @@ unsigned Editor::countMatchesForText(const String& target, Range* range, FindOpt
if (!visibleRect.isEmpty()) {
GraphicsContext context((PlatformGraphicsContext*)0);
context.setPaintingDisabled(true);
+
+ PaintBehavior oldBehavior = m_frame->view()->paintBehavior();
+ m_frame->view()->setPaintBehavior(oldBehavior | PaintBehaviorFlattenCompositingLayers);
m_frame->view()->paintContents(&context, visibleRect);
+ m_frame->view()->setPaintBehavior(oldBehavior);
}
}
}
@@ -3440,6 +3441,15 @@ void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping)
{
+#if SUPPORT_AUTOCORRECTION_PANEL
+ // Make sure there's no pending autocorrection before we call markMisspellingsAndBadGrammar() below.
+ VisibleSelection currentSelection(frame()->selection()->selection());
+ if (currentSelection != oldSelection) {
+ stopCorrectionPanelTimer();
+ dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
+ }
+#endif // SUPPORT_AUTOCORRECTION_PANEL
+
bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && isGrammarCheckingEnabled();
if (isContinuousSpellCheckingEnabled) {
diff --git a/Source/WebCore/editing/Editor.h b/Source/WebCore/editing/Editor.h
index 2e61ce6..0a06a4a 100644
--- a/Source/WebCore/editing/Editor.h
+++ b/Source/WebCore/editing/Editor.h
@@ -198,7 +198,8 @@ public:
static bool commandIsSupportedFromMenuOrKeyBinding(const String& commandName); // Works without a frame.
bool insertText(const String&, Event* triggeringEvent);
- bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, Event* triggeringEvent);
+ bool insertTextForConfirmedComposition(const String& text);
+ bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, TextEvent* triggeringEvent);
bool insertLineBreak();
bool insertParagraphSeparator();
@@ -423,6 +424,7 @@ private:
void stopCorrectionPanelTimer();
void dismissCorrectionPanel(ReasonForDismissingCorrectionPanel);
void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
+ void applyAutocorrectionBeforeTypingIfAppropriate();
};
inline void Editor::setStartNewKillRingSequence(bool flag)
diff --git a/Source/WebCore/editing/EditorCommand.cpp b/Source/WebCore/editing/EditorCommand.cpp
index 9e5bf9f..451d855 100644
--- a/Source/WebCore/editing/EditorCommand.cpp
+++ b/Source/WebCore/editing/EditorCommand.cpp
@@ -930,6 +930,26 @@ static bool executeRemoveFormat(Frame* frame, Event*, EditorCommandSource, const
return true;
}
+static bool executeScrollPageBackward(Frame* frame, Event*, EditorCommandSource, const String&)
+{
+ return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByPage);
+}
+
+static bool executeScrollPageForward(Frame* frame, Event*, EditorCommandSource, const String&)
+{
+ return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByPage);
+}
+
+static bool executeScrollToBeginningOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
+{
+ return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByDocument);
+}
+
+static bool executeScrollToEndOfDocument(Frame* frame, Event*, EditorCommandSource, const String&)
+{
+ return frame->eventHandler()->logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByDocument);
+}
+
static bool executeSelectAll(Frame* frame, Event*, EditorCommandSource, const String&)
{
frame->selection()->selectAll();
@@ -1477,6 +1497,10 @@ static const CommandMap& createCommandMap()
{ "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
{ "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
{ "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+ { "ScrollPageBackward", { executeScrollPageBackward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+ { "ScrollPageForward", { executeScrollPageForward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+ { "ScrollToBeginningOfDocument", { executeScrollToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+ { "ScrollToEndOfDocument", { executeScrollToEndOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
{ "SelectAll", { executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
{ "SelectLine", { executeSelectLine, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
{ "SelectParagraph", { executeSelectParagraph, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
diff --git a/Source/WebCore/editing/FormatBlockCommand.cpp b/Source/WebCore/editing/FormatBlockCommand.cpp
index e43f330..58157af 100644
--- a/Source/WebCore/editing/FormatBlockCommand.cpp
+++ b/Source/WebCore/editing/FormatBlockCommand.cpp
@@ -67,6 +67,9 @@ void FormatBlockCommand::formatRange(const Position& start, const Position& end,
RefPtr<Range> range = Range::create(document(), start, endOfSelection);
Element* refNode = enclosingBlockFlowElement(end);
Element* root = editableRootForPosition(start);
+ // Root is null for elements with contenteditable=false.
+ if (!root)
+ return;
if (isElementForFormatBlock(refNode->tagQName()) && start == startOfBlock(start)
&& (end == endOfBlock(end) || isNodeVisiblyContainedWithin(refNode, range.get()))
&& refNode != root && !root->isDescendantOf(refNode)) {
diff --git a/Source/WebCore/editing/HTMLInterchange.cpp b/Source/WebCore/editing/HTMLInterchange.cpp
index 16b330d..1ce06ab 100644
--- a/Source/WebCore/editing/HTMLInterchange.cpp
+++ b/Source/WebCore/editing/HTMLInterchange.cpp
@@ -26,10 +26,10 @@
#include "config.h"
#include "HTMLInterchange.h"
-#include "CharacterNames.h"
#include "Text.h"
#include "TextIterator.h"
#include <wtf/StdLibExtras.h>
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
diff --git a/Source/WebCore/editing/InsertListCommand.cpp b/Source/WebCore/editing/InsertListCommand.cpp
index 9348786..c24c683 100644
--- a/Source/WebCore/editing/InsertListCommand.cpp
+++ b/Source/WebCore/editing/InsertListCommand.cpp
@@ -72,7 +72,7 @@ PassRefPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists(PassRefPtr<
if (!list || !list->nextElementSibling() || !list->nextElementSibling()->isHTMLElement())
return list.release();
- RefPtr<HTMLElement> nextList = static_cast<HTMLElement*>(list->nextElementSibling());
+ RefPtr<HTMLElement> nextList = toHTMLElement(list->nextElementSibling());
if (canMergeLists(list.get(), nextList.get())) {
mergeIdenticalElements(list, nextList);
return nextList.release();
diff --git a/Source/WebCore/editing/InsertTextCommand.cpp b/Source/WebCore/editing/InsertTextCommand.cpp
index fc18e91..1ec11ad 100644
--- a/Source/WebCore/editing/InsertTextCommand.cpp
+++ b/Source/WebCore/editing/InsertTextCommand.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "InsertTextCommand.h"
-#include "CharacterNames.h"
#include "CSSComputedStyleDeclaration.h"
#include "CSSMutableStyleDeclaration.h"
#include "CSSPropertyNames.h"
@@ -41,6 +40,7 @@
#include "TextIterator.h"
#include "TypingCommand.h"
#include "visible_units.h"
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -61,13 +61,13 @@ Position InsertTextCommand::prepareForTextInsertion(const Position& p)
if (!pos.node()->isTextNode()) {
RefPtr<Node> textNode = document()->createEditingTextNode("");
insertNodeAt(textNode.get(), pos);
- return Position(textNode.get(), 0);
+ return firstPositionInNode(textNode.get());
}
if (isTabSpanTextNode(pos.node())) {
RefPtr<Node> textNode = document()->createEditingTextNode("");
insertNodeAtTabSpanPosition(textNode.get(), pos);
- return Position(textNode.get(), 0);
+ return firstPositionInNode(textNode.get());
}
return pos;
@@ -83,30 +83,32 @@ bool InsertTextCommand::performTrivialReplace(const String& text, bool selectIns
if (text.contains('\t') || text.contains(' ') || text.contains('\n'))
return false;
- Position start = endingSelection().start();
- Position end = endingSelection().end();
-
- if (start.node() != end.node() || !start.node()->isTextNode() || isTabSpanTextNode(start.node()))
+ Position start = endingSelection().start().parentAnchoredEquivalent();
+ Position end = endingSelection().end().parentAnchoredEquivalent();
+ ASSERT(start.anchorType() == Position::PositionIsOffsetInAnchor);
+ ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
+
+ if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode() || isTabSpanTextNode(start.containerNode()))
return false;
-
- replaceTextInNode(static_cast<Text*>(start.node()), start.deprecatedEditingOffset(), end.deprecatedEditingOffset() - start.deprecatedEditingOffset(), text);
-
- Position endPosition(start.node(), start.deprecatedEditingOffset() + text.length());
-
+
+ replaceTextInNode(static_cast<Text*>(start.containerNode()), start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
+
+ Position endPosition(start.containerNode(), start.offsetInContainerNode() + text.length());
+
// 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(start, endPosition);
setEndingSelection(forcedEndingSelection);
-
+
if (!selectInsertedText)
setEndingSelection(VisibleSelection(endingSelection().visibleEnd()));
return true;
}
-void InsertTextCommand::input(const String& text, bool selectInsertedText)
+void InsertTextCommand::input(const String& text, bool selectInsertedText, RebalanceType whitespaceRebalance)
{
ASSERT(text.find('\n') == notFound);
@@ -170,13 +172,19 @@ void InsertTextCommand::input(const String& text, bool selectInsertedText)
int offset = startPosition.deprecatedEditingOffset();
insertTextIntoNode(textNode, offset, text);
- endPosition = Position(textNode, offset + text.length());
-
- // The insertion may require adjusting adjacent whitespace, if it is present.
- rebalanceWhitespaceAt(endPosition);
- // Rebalancing on both sides isn't necessary if we've inserted a space.
- if (text != " ")
- rebalanceWhitespaceAt(startPosition);
+ endPosition = Position(textNode, offset + text.length(), Position::PositionIsOffsetInAnchor);
+
+ if (whitespaceRebalance == 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(text))
+ rebalanceWhitespaceAt(startPosition);
+ } else {
+ ASSERT(whitespaceRebalance == RebalanceAllWhitespaces);
+ if (canRebalance(startPosition) && canRebalance(endPosition))
+ rebalanceWhitespaceOnTextSubstring(textNode, startPosition.deprecatedEditingOffset(), endPosition.deprecatedEditingOffset());
+ }
}
// We could have inserted a part of composed character sequence,
@@ -207,7 +215,7 @@ Position InsertTextCommand::insertTab(const Position& pos)
// keep tabs coalesced in tab span
if (isTabSpanTextNode(node)) {
insertTextIntoNode(static_cast<Text *>(node), offset, "\t");
- return Position(node, offset + 1);
+ return Position(node, offset + 1, Position::PositionIsOffsetInAnchor);
}
// create new tab span
@@ -230,9 +238,9 @@ Position InsertTextCommand::insertTab(const Position& pos)
insertNodeBefore(spanNode, textNode);
}
}
-
+
// return the position following the new tab
- return Position(spanNode->lastChild(), caretMaxOffset(spanNode->lastChild()));
+ return lastPositionInNode(spanNode.get());
}
bool InsertTextCommand::isInsertTextCommand() const
diff --git a/Source/WebCore/editing/InsertTextCommand.h b/Source/WebCore/editing/InsertTextCommand.h
index 77ae016..672e576 100644
--- a/Source/WebCore/editing/InsertTextCommand.h
+++ b/Source/WebCore/editing/InsertTextCommand.h
@@ -32,14 +32,20 @@ namespace WebCore {
class InsertTextCommand : public CompositeEditCommand {
public:
+ enum RebalanceType {
+ RebalanceLeadingAndTrailingWhitespaces,
+ RebalanceAllWhitespaces
+ };
+
static PassRefPtr<InsertTextCommand> create(Document* document)
{
return adoptRef(new InsertTextCommand(document));
}
- void input(const String& text, bool selectInsertedText = false);
+ void input(const String& text, bool selectInsertedText = false, RebalanceType = RebalanceLeadingAndTrailingWhitespaces);
private:
+
InsertTextCommand(Document*);
void deleteCharacter();
diff --git a/Source/WebCore/editing/MarkupAccumulator.cpp b/Source/WebCore/editing/MarkupAccumulator.cpp
index f6dbd8b..f4489c5 100644
--- a/Source/WebCore/editing/MarkupAccumulator.cpp
+++ b/Source/WebCore/editing/MarkupAccumulator.cpp
@@ -28,7 +28,6 @@
#include "MarkupAccumulator.h"
#include "CDATASection.h"
-#include "CharacterNames.h"
#include "Comment.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
@@ -38,6 +37,7 @@
#include "KURL.h"
#include "ProcessingInstruction.h"
#include "XMLNSNames.h"
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
diff --git a/Source/WebCore/editing/MarkupAccumulator.h b/Source/WebCore/editing/MarkupAccumulator.h
index 5a9c884..0bfc6e6 100644
--- a/Source/WebCore/editing/MarkupAccumulator.h
+++ b/Source/WebCore/editing/MarkupAccumulator.h
@@ -72,7 +72,7 @@ public:
String serializeNodes(Node* node, Node* nodeToSkip, EChildrenOnly childrenOnly);
protected:
- void appendString(const String&);
+ virtual void appendString(const String&);
void appendStartTag(Node*, Namespaces* = 0);
void appendEndTag(Node*);
static size_t totalLength(const Vector<String>&);
diff --git a/Source/WebCore/editing/MoveSelectionCommand.cpp b/Source/WebCore/editing/MoveSelectionCommand.cpp
index 3a1cae0..0f23b29 100644
--- a/Source/WebCore/editing/MoveSelectionCommand.cpp
+++ b/Source/WebCore/editing/MoveSelectionCommand.cpp
@@ -39,25 +39,21 @@ MoveSelectionCommand::MoveSelectionCommand(PassRefPtr<DocumentFragment> fragment
void MoveSelectionCommand::doApply()
{
- VisibleSelection selection = endingSelection();
- ASSERT(selection.isNonOrphanedRange());
+ ASSERT(endingSelection().isNonOrphanedRange());
Position pos = m_position;
if (pos.isNull())
return;
-
+
// Update the position otherwise it may become invalid after the selection is deleted.
- Node *positionNode = m_position.node();
- int positionOffset = m_position.deprecatedEditingOffset();
- Position selectionEnd = selection.end();
- int selectionEndOffset = selectionEnd.deprecatedEditingOffset();
- if (selectionEnd.node() == positionNode && selectionEndOffset < positionOffset) {
- positionOffset -= selectionEndOffset;
- Position selectionStart = selection.start();
- if (selectionStart.node() == positionNode) {
- positionOffset += selectionStart.deprecatedEditingOffset();
- }
- pos = Position(positionNode, positionOffset);
+ Position selectionEnd = endingSelection().end();
+ if (pos.anchorType() == Position::PositionIsOffsetInAnchor && selectionEnd.anchorType() == Position::PositionIsOffsetInAnchor
+ && selectionEnd.containerNode() == pos.containerNode() && selectionEnd.offsetInContainerNode() < pos.offsetInContainerNode()) {
+ pos.moveToOffset(pos.offsetInContainerNode() - selectionEnd.offsetInContainerNode());
+
+ Position selectionStart = endingSelection().start();
+ if (selectionStart.anchorType() == Position::PositionIsOffsetInAnchor && selectionStart.containerNode() == pos.containerNode())
+ pos.moveToOffset(pos.offsetInContainerNode() + selectionStart.offsetInContainerNode());
}
deleteSelection(m_smartDelete);
@@ -70,11 +66,11 @@ void MoveSelectionCommand::doApply()
pos = endingSelection().start();
setEndingSelection(VisibleSelection(pos, endingSelection().affinity()));
- if (!positionNode->inDocument()) {
+ if (!pos.anchorNode()->inDocument()) {
// Document was modified out from under us.
return;
}
- applyCommandToComposite(ReplaceSelectionCommand::create(positionNode->document(), m_fragment, true, m_smartInsert));
+ applyCommandToComposite(ReplaceSelectionCommand::create(document(), m_fragment, true, m_smartInsert));
}
EditAction MoveSelectionCommand::editingAction() const
diff --git a/Source/WebCore/editing/ReplaceSelectionCommand.cpp b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
index f47cb4e..846b932 100644
--- a/Source/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/Source/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -476,7 +476,7 @@ void ReplaceSelectionCommand::negateStyleRulesThatAffectAppearance()
for (RefPtr<Node> node = m_firstNodeInserted.get(); node; node = node->traverseNextNode()) {
// FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance
if (isStyleSpan(node.get())) {
- HTMLElement* e = static_cast<HTMLElement*>(node.get());
+ HTMLElement* e = toHTMLElement(node.get());
// There are other styles that style rules can give to style spans,
// but these are the two important ones because they'll prevent
// inserted content from appearing in the right paragraph.
@@ -496,10 +496,10 @@ void ReplaceSelectionCommand::negateStyleRulesThatAffectAppearance()
void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds()
{
document()->updateLayoutIgnorePendingStylesheets();
- if (!m_lastLeafInserted->renderer() &&
- m_lastLeafInserted->isTextNode() &&
- !enclosingNodeWithTag(Position(m_lastLeafInserted.get(), 0), selectTag) &&
- !enclosingNodeWithTag(Position(m_lastLeafInserted.get(), 0), scriptTag)) {
+ if (!m_lastLeafInserted->renderer()
+ && m_lastLeafInserted->isTextNode()
+ && !enclosingNodeWithTag(firstPositionInOrBeforeNode(m_lastLeafInserted.get()), selectTag)
+ && !enclosingNodeWithTag(firstPositionInOrBeforeNode(m_lastLeafInserted.get()), scriptTag)) {
if (m_firstNodeInserted == m_lastLeafInserted) {
removeNode(m_lastLeafInserted.get());
m_lastLeafInserted = 0;
@@ -620,7 +620,7 @@ void ReplaceSelectionCommand::handleStyleSpans()
if (!sourceDocumentStyleSpan)
return;
- RefPtr<EditingStyle> sourceDocumentStyle = EditingStyle::create(static_cast<HTMLElement*>(sourceDocumentStyleSpan)->getInlineStyleDecl());
+ RefPtr<EditingStyle> sourceDocumentStyle = EditingStyle::create(toHTMLElement(sourceDocumentStyleSpan)->getInlineStyleDecl());
ContainerNode* context = sourceDocumentStyleSpan->parentNode();
// If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
@@ -657,7 +657,7 @@ void ReplaceSelectionCommand::handleStyleSpans()
return;
}
- RefPtr<EditingStyle> copiedRangeStyle = EditingStyle::create(static_cast<HTMLElement*>(copiedRangeStyleSpan)->getInlineStyleDecl());
+ RefPtr<EditingStyle> copiedRangeStyle = EditingStyle::create(toHTMLElement(copiedRangeStyleSpan)->getInlineStyleDecl());
// We're going to put sourceDocumentStyleSpan's non-redundant styles onto copiedRangeStyleSpan,
// as long as they aren't overridden by ones on copiedRangeStyleSpan.
@@ -696,7 +696,7 @@ void ReplaceSelectionCommand::copyStyleToChildren(Node* parentNode, const CSSMut
// In this case, put a span tag around the child node.
RefPtr<Node> newNode = parentNode->cloneNode(false);
ASSERT(newNode->hasTagName(spanTag));
- HTMLElement* newSpan = static_cast<HTMLElement*>(newNode.get());
+ HTMLElement* newSpan = toHTMLElement(newNode.get());
setNodeAttribute(newSpan, styleAttr, parentStyle->cssText());
insertNodeAfter(newSpan, childNode);
ExceptionCode ec = 0;
@@ -707,7 +707,7 @@ void ReplaceSelectionCommand::copyStyleToChildren(Node* parentNode, const CSSMut
// Copy the style attribute and merge them into the child node. We don't want to override
// existing styles, so don't clobber on merge.
RefPtr<CSSMutableStyleDeclaration> newStyle = parentStyle->copy();
- HTMLElement* childElement = static_cast<HTMLElement*>(childNode);
+ HTMLElement* childElement = toHTMLElement(childNode);
RefPtr<CSSMutableStyleDeclaration> existingStyles = childElement->getInlineStyleDecl()->copy();
existingStyles->merge(newStyle.get(), false);
setNodeAttribute(childElement, styleAttr, existingStyles->cssText());
@@ -743,7 +743,7 @@ void ReplaceSelectionCommand::mergeEndIfNeeded()
if (endOfParagraph(startOfParagraphToMove) == destination) {
RefPtr<Node> placeholder = createBreakElement(document());
insertNodeBefore(placeholder, startOfParagraphToMove.deepEquivalent().node());
- destination = VisiblePosition(Position(placeholder.get(), 0));
+ destination = VisiblePosition(positionBeforeNode(placeholder.get()));
}
moveParagraph(startOfParagraphToMove, endOfParagraph(startOfParagraphToMove), destination);
@@ -1045,7 +1045,7 @@ void ReplaceSelectionCommand::doApply()
if (isListItem(enclosingNode)) {
RefPtr<Node> newListItem = createListItemElement(document());
insertNodeAfter(newListItem, enclosingNode);
- setEndingSelection(VisiblePosition(Position(newListItem, 0)));
+ setEndingSelection(VisiblePosition(firstPositionInNode(newListItem.get())));
} else
// Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
// block's style seems to annoy users.
@@ -1124,7 +1124,7 @@ bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePositi
if (!endBR || !endBR->inDocument())
return false;
- VisiblePosition visiblePos(Position(endBR, 0));
+ VisiblePosition visiblePos(positionBeforeNode(endBR));
// Don't remove the br if nothing was inserted.
if (visiblePos.previous() == originalVisPosBeforeEndBR)
@@ -1261,7 +1261,7 @@ bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
{
if (!fragment.firstChild() || fragment.firstChild() != fragment.lastChild() || !fragment.firstChild()->isTextNode())
return false;
-
+
// FIXME: Would be nice to handle smart replace in the fast path.
if (m_smartReplace || fragment.hasInterchangeNewlineAtStart() || fragment.hasInterchangeNewlineAtEnd())
return false;
@@ -1270,20 +1270,22 @@ bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
// Our fragment creation code handles tabs, spaces, and newlines, so we don't have to worry about those here.
String text(textNode->data());
- Position start = endingSelection().start();
- Position end = endingSelection().end();
-
- if (start.anchorNode() != end.anchorNode() || !start.anchorNode()->isTextNode())
+ Position start = endingSelection().start().parentAnchoredEquivalent();
+ Position end = endingSelection().end().parentAnchoredEquivalent();
+ ASSERT(start.anchorType() == Position::PositionIsOffsetInAnchor);
+ ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
+
+ if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode())
return false;
-
- replaceTextInNode(static_cast<Text*>(start.anchorNode()), start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
-
- end = Position(start.anchorNode(), start.offsetInContainerNode() + text.length());
-
+
+ replaceTextInNode(static_cast<Text*>(start.containerNode()), start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
+
+ end = Position(start.containerNode(), start.offsetInContainerNode() + text.length(), Position::PositionIsOffsetInAnchor);
+
VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, end);
-
+
setEndingSelection(selectionAfterReplace);
-
+
return true;
}
diff --git a/Source/WebCore/editing/SelectionController.cpp b/Source/WebCore/editing/SelectionController.cpp
index fa0c32d..a574b5a 100644
--- a/Source/WebCore/editing/SelectionController.cpp
+++ b/Source/WebCore/editing/SelectionController.cpp
@@ -1707,7 +1707,7 @@ static HTMLFormElement* scanForForm(Node* start)
for (Node* node = start; node; node = node->traverseNextNode()) {
if (node->hasTagName(formTag))
return static_cast<HTMLFormElement*>(node);
- if (node->isHTMLElement() && static_cast<HTMLElement*>(node)->isFormControlElement())
+ if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
return static_cast<HTMLFormControlElement*>(node)->form();
if (node->hasTagName(frameTag) || node->hasTagName(iframeTag)) {
Node* childDocument = static_cast<HTMLFrameElementBase*>(node)->contentDocument();
@@ -1731,7 +1731,7 @@ HTMLFormElement* SelectionController::currentForm() const
for (node = start; node; node = node->parentNode()) {
if (node->hasTagName(formTag))
return static_cast<HTMLFormElement*>(node);
- if (node->isHTMLElement() && static_cast<HTMLElement*>(node)->isFormControlElement())
+ if (node->isHTMLElement() && toHTMLElement(node)->isFormControlElement())
return static_cast<HTMLFormControlElement*>(node)->form();
}
@@ -1781,7 +1781,7 @@ void SelectionController::setSelectionFromNone()
while (node && !node->hasTagName(bodyTag))
node = node->traverseNextNode();
if (node)
- setSelection(VisibleSelection(Position(node, 0), DOWNSTREAM));
+ setSelection(VisibleSelection(firstPositionInOrBeforeNode(node), DOWNSTREAM));
}
bool SelectionController::shouldChangeSelection(const VisibleSelection& newSelection) const
diff --git a/Source/WebCore/editing/SpellChecker.cpp b/Source/WebCore/editing/SpellChecker.cpp
index 1807474..f14a74d 100644
--- a/Source/WebCore/editing/SpellChecker.cpp
+++ b/Source/WebCore/editing/SpellChecker.cpp
@@ -141,7 +141,7 @@ void SpellChecker::didCheck(int sequence, const Vector<SpellCheckingResult>& res
}
int startOffset = 0;
- PositionIterator start = Position(m_requestNode, 0);
+ PositionIterator start = firstPositionInOrBeforeNode(m_requestNode.get());
for (size_t i = 0; i < results.size(); ++i) {
if (results[i].type() != DocumentMarker::Spelling && results[i].type() != DocumentMarker::Grammar)
continue;
diff --git a/Source/WebCore/editing/TextIterator.cpp b/Source/WebCore/editing/TextIterator.cpp
index 1fc7606..b621dc2 100644
--- a/Source/WebCore/editing/TextIterator.cpp
+++ b/Source/WebCore/editing/TextIterator.cpp
@@ -27,7 +27,6 @@
#include "config.h"
#include "TextIterator.h"
-#include "CharacterNames.h"
#include "Document.h"
#include "HTMLElement.h"
#include "HTMLNames.h"
@@ -42,6 +41,7 @@
#include "TextBreakIterator.h"
#include "VisiblePosition.h"
#include "visible_units.h"
+#include <wtf/unicode/CharacterNames.h>
#if USE(ICU_UNICODE) && !UCONFIG_NO_COLLATION
#include "TextBreakIteratorInternalICU.h"
@@ -543,7 +543,7 @@ void TextIterator::handleTextBox()
unsigned runStart = max(textBoxStart, start);
// Check for collapsed space at the start of this run.
- InlineTextBox* firstTextBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
+ InlineTextBox* firstTextBox = renderer->containsReversedText() ? (m_sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]) : renderer->firstTextBox();
bool needSpace = m_lastTextNodeEndedWithCollapsedSpace
|| (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0);
if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter) {
@@ -551,7 +551,7 @@ void TextIterator::handleTextBox()
unsigned spaceRunStart = runStart - 1;
while (spaceRunStart > 0 && str[spaceRunStart - 1] == ' ')
--spaceRunStart;
- emitText(m_node, spaceRunStart, spaceRunStart + 1);
+ emitText(m_node, renderer, spaceRunStart, spaceRunStart + 1);
} else
emitCharacter(' ', m_node, 0, runStart, runStart);
return;
@@ -1922,6 +1922,11 @@ inline SearchBuffer::SearchBuffer(const String& target, FindOptions options)
inline SearchBuffer::~SearchBuffer()
{
+ // Leave the static object pointing to a valid string.
+ UErrorCode status = U_ZERO_ERROR;
+ usearch_setPattern(WebCore::searcher(), &newlineCharacter, 1, &status);
+ ASSERT(status == U_ZERO_ERROR);
+
unlockSearcher();
}
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index d54b388..9723c2d 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -47,7 +47,8 @@ namespace WebCore {
using namespace HTMLNames;
-TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, bool selectInsertedText, TextGranularity granularity, bool killRing)
+TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, const String &textToInsert, bool selectInsertedText, TextGranularity granularity, TextCompositionType compositionType,
+ bool killRing)
: CompositeEditCommand(document),
m_commandType(commandType),
m_textToInsert(textToInsert),
@@ -55,6 +56,7 @@ TypingCommand::TypingCommand(Document *document, ETypingCommand commandType, con
m_selectInsertedText(selectInsertedText),
m_smartDelete(false),
m_granularity(granularity),
+ m_compositionType(compositionType),
m_killRing(killRing),
m_openedByBackwardDelete(false)
{
@@ -133,18 +135,18 @@ void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(TypingCommand
}
-void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, bool insertedTextIsComposition)
+void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, TextCompositionType composition)
{
ASSERT(document);
Frame* frame = document->frame();
ASSERT(frame);
- insertText(document, text, frame->selection()->selection(), selectInsertedText, insertedTextIsComposition);
+ insertText(document, text, frame->selection()->selection(), selectInsertedText, composition);
}
// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to SelectionController's current selection.
-void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, bool selectInsertedText, bool insertedTextIsComposition)
+void TypingCommand::insertText(Document* document, const String& text, const VisibleSelection& selectionForInsertion, bool selectInsertedText, TextCompositionType compositionType)
{
#if REMOVE_MARKERS_UPON_EDITING
if (!text.isEmpty())
@@ -161,7 +163,7 @@ void TypingCommand::insertText(Document* document, const String& text, const Vis
String newText = text;
Node* startNode = selectionForInsertion.start().node();
- if (startNode && startNode->rootEditableElement() && !insertedTextIsComposition) {
+ if (startNode && startNode->rootEditableElement() && compositionType != TextCompositionUpdate) {
// Send BeforeTextInsertedEvent. The event handler will update text if necessary.
ExceptionCode ec = 0;
RefPtr<BeforeTextInsertedEvent> evt = BeforeTextInsertedEvent::create(text);
@@ -182,11 +184,13 @@ void TypingCommand::insertText(Document* document, const String& text, const Vis
lastTypingCommand->setStartingSelection(selectionForInsertion);
lastTypingCommand->setEndingSelection(selectionForInsertion);
}
+
+ lastTypingCommand->setCompositionType(compositionType);
lastTypingCommand->insertText(newText, selectInsertedText);
return;
}
- RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText);
+ RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText, compositionType);
if (changeSelection) {
cmd->setStartingSelection(selectionForInsertion);
cmd->setEndingSelection(selectionForInsertion);
@@ -386,7 +390,8 @@ void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool select
command->setStartingSelection(endingSelection());
command->setEndingSelection(endingSelection());
}
- command->input(text, selectInsertedText);
+ command->input(text, selectInsertedText,
+ m_compositionType == TextCompositionNone ? InsertTextCommand::RebalanceLeadingAndTrailingWhitespaces : InsertTextCommand::RebalanceAllWhitespaces);
typingAddedToOpenCommand(InsertText);
}
@@ -431,7 +436,7 @@ bool TypingCommand::makeEditableRootEmpty()
removeNode(child);
addBlockPlaceholderIfNeeded(root);
- setEndingSelection(VisibleSelection(Position(root, 0), DOWNSTREAM));
+ setEndingSelection(VisibleSelection(firstPositionInNode(root), DOWNSTREAM));
return true;
}
@@ -490,7 +495,7 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
selection.modify(SelectionController::AlterationExtend, DirectionBackward, granularity);
// If the caret is just after a table, select the table and don't delete anything.
} else if (Node* table = isFirstPositionAfterTable(visibleStart)) {
- setEndingSelection(VisibleSelection(Position(table, 0), endingSelection().start(), DOWNSTREAM));
+ setEndingSelection(VisibleSelection(positionAfterNode(table), endingSelection().start(), DOWNSTREAM));
typingAddedToOpenCommand(DeleteKey);
return;
}
@@ -591,7 +596,7 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
extraCharacters = selectionToDelete.end().deprecatedEditingOffset() - selectionToDelete.start().deprecatedEditingOffset();
else
extraCharacters = selectionToDelete.end().deprecatedEditingOffset();
- extent = Position(extent.node(), extent.deprecatedEditingOffset() + extraCharacters);
+ extent = Position(extent.node(), extent.deprecatedEditingOffset() + extraCharacters, Position::PositionIsOffsetInAnchor);
}
selectionAfterUndo.setWithoutValidation(startingSelection().start(), extent);
}
diff --git a/Source/WebCore/editing/TypingCommand.h b/Source/WebCore/editing/TypingCommand.h
index 284ebc0..b34bdc1 100644
--- a/Source/WebCore/editing/TypingCommand.h
+++ b/Source/WebCore/editing/TypingCommand.h
@@ -42,11 +42,17 @@ public:
InsertParagraphSeparatorInQuotedContent
};
+ enum TextCompositionType {
+ TextCompositionNone,
+ TextCompositionUpdate,
+ TextCompositionConfirm
+ };
+
static void deleteSelection(Document*, bool smartDelete = false);
static void deleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity, bool killRing = false);
static void forwardDeleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity, bool killRing = false);
- static void insertText(Document*, const String&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
- static void insertText(Document*, const String&, const VisibleSelection&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
+ static void insertText(Document*, const String&, bool selectInsertedText = false, TextCompositionType = TextCompositionNone);
+ static void insertText(Document*, const String&, const VisibleSelection&, bool selectInsertedText = false, TextCompositionType = TextCompositionNone);
static void insertLineBreak(Document*);
static void insertParagraphSeparator(Document*);
static void insertParagraphSeparatorInQuotedContent(Document*);
@@ -64,14 +70,20 @@ public:
void deleteKeyPressed(TextGranularity, bool killRing);
void forwardDeleteKeyPressed(TextGranularity, bool killRing);
void deleteSelection(bool smartDelete);
+ void setCompositionType(TextCompositionType type) { m_compositionType = type; }
private:
static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text = "", bool selectInsertedText = false, TextGranularity granularity = CharacterGranularity, bool killRing = false)
{
- return adoptRef(new TypingCommand(document, command, text, selectInsertedText, granularity, killRing));
+ return adoptRef(new TypingCommand(document, command, text, selectInsertedText, granularity, TextCompositionNone, killRing));
+ }
+
+ static PassRefPtr<TypingCommand> create(Document* document, ETypingCommand command, const String& text, bool selectInsertedText, TextCompositionType compositionType)
+ {
+ return adoptRef(new TypingCommand(document, command, text, selectInsertedText, CharacterGranularity, compositionType, false));
}
- TypingCommand(Document*, ETypingCommand, const String& text, bool selectInsertedText, TextGranularity, bool killRing);
+ TypingCommand(Document*, ETypingCommand, const String& text, bool selectInsertedText, TextGranularity, TextCompositionType, bool killRing);
bool smartDelete() const { return m_smartDelete; }
void setSmartDelete(bool smartDelete) { m_smartDelete = smartDelete; }
@@ -94,6 +106,7 @@ private:
bool m_selectInsertedText;
bool m_smartDelete;
TextGranularity m_granularity;
+ TextCompositionType m_compositionType;
bool m_killRing;
bool m_preservesTypingStyle;
diff --git a/Source/WebCore/editing/VisibleSelection.cpp b/Source/WebCore/editing/VisibleSelection.cpp
index 035afb8..9096dc5 100644
--- a/Source/WebCore/editing/VisibleSelection.cpp
+++ b/Source/WebCore/editing/VisibleSelection.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "VisibleSelection.h"
-#include "CharacterNames.h"
#include "Document.h"
#include "Element.h"
#include "htmlediting.h"
@@ -34,10 +33,10 @@
#include "VisiblePosition.h"
#include "visible_units.h"
#include "Range.h"
-
+#include <stdio.h>
#include <wtf/Assertions.h>
#include <wtf/text/CString.h>
-#include <stdio.h>
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -173,6 +172,9 @@ PassRefPtr<Range> VisibleSelection::toNormalizedRange() const
s = s.parentAnchoredEquivalent();
e = e.parentAnchoredEquivalent();
}
+
+ if (s.isNull() || e.isNull())
+ return 0;
// VisibleSelections are supposed to always be valid. This constructor will ASSERT
// if a valid range could not be created, which is fine for this callsite.
@@ -432,7 +434,6 @@ void VisibleSelection::setWithoutValidation(const Position& base, const Position
{
ASSERT(!base.isNull());
ASSERT(!extent.isNull());
- ASSERT(base != extent);
ASSERT(m_affinity == DOWNSTREAM);
m_base = base;
m_extent = extent;
@@ -444,7 +445,7 @@ void VisibleSelection::setWithoutValidation(const Position& base, const Position
m_start = extent;
m_end = base;
}
- m_selectionType = RangeSelection;
+ m_selectionType = base == extent ? CaretSelection : RangeSelection;
}
void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
@@ -526,13 +527,13 @@ void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
Position p = nextVisuallyDistinctCandidate(m_start);
Node* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0;
if (p.isNull() && startRoot && (shadowAncestor != startRoot))
- p = Position(shadowAncestor, 0);
+ p = positionBeforeNode(shadowAncestor);
while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
Node* root = editableRootForPosition(p);
shadowAncestor = root ? root->shadowAncestorNode() : 0;
p = isAtomicNode(p.node()) ? positionInParentAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
if (p.isNull() && (shadowAncestor != root))
- p = Position(shadowAncestor, 0);
+ p = positionBeforeNode(shadowAncestor);
}
VisiblePosition next(p);
diff --git a/Source/WebCore/editing/htmlediting.cpp b/Source/WebCore/editing/htmlediting.cpp
index 90db3ef..cb157d2 100644
--- a/Source/WebCore/editing/htmlediting.cpp
+++ b/Source/WebCore/editing/htmlediting.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "htmlediting.h"
-#include "CharacterNames.h"
#include "Document.h"
#include "EditingText.h"
#include "HTMLBRElement.h"
@@ -46,6 +45,7 @@
#include "VisiblePosition.h"
#include "visible_units.h"
#include <wtf/StdLibExtras.h>
+#include <wtf/unicode/CharacterNames.h>
#if ENABLE(WML)
#include "WMLNames.h"
@@ -356,25 +356,27 @@ int lastOffsetForEditing(const Node* node)
String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
{
- DEFINE_STATIC_LOCAL(String, twoSpaces, (" "));
- DEFINE_STATIC_LOCAL(String, nbsp, ("\xa0"));
- DEFINE_STATIC_LOCAL(String, pattern, (" \xa0"));
+ Vector<UChar> rebalancedString;
+ append(rebalancedString, string);
- String rebalancedString = string;
+ bool previousCharacterWasSpace = false;
+ for (size_t i = 0; i < rebalancedString.size(); i++) {
+ if (!isWhitespace(rebalancedString[i])) {
+ previousCharacterWasSpace = false;
+ continue;
+ }
- rebalancedString.replace(noBreakSpace, ' ');
- rebalancedString.replace('\n', ' ');
- rebalancedString.replace('\t', ' ');
-
- rebalancedString.replace(twoSpaces, pattern);
-
- if (startIsStartOfParagraph && rebalancedString[0] == ' ')
- rebalancedString.replace(0, 1, nbsp);
- int end = rebalancedString.length() - 1;
- if (endIsEndOfParagraph && rebalancedString[end] == ' ')
- rebalancedString.replace(end, 1, nbsp);
+ if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i + 1 == rebalancedString.size() && endIsEndOfParagraph)) {
+ rebalancedString[i] = noBreakSpace;
+ previousCharacterWasSpace = false;
+ } else {
+ rebalancedString[i] = ' ';
+ previousCharacterWasSpace = true;
+ }
+
+ }
- return rebalancedString;
+ return String::adopt(rebalancedString);
}
bool isTableStructureNode(const Node *node)
@@ -660,7 +662,7 @@ HTMLElement* enclosingList(Node* node)
for (ContainerNode* n = node->parentNode(); n; n = n->parentNode()) {
if (n->hasTagName(ulTag) || n->hasTagName(olTag))
- return static_cast<HTMLElement*>(n);
+ return toHTMLElement(n);
if (n == root)
return 0;
}
@@ -668,7 +670,7 @@ HTMLElement* enclosingList(Node* node)
return 0;
}
-HTMLElement* enclosingListChild(Node *node)
+Node* enclosingListChild(Node *node)
{
if (!node)
return 0;
@@ -679,7 +681,7 @@ HTMLElement* enclosingListChild(Node *node)
// FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
if (n->hasTagName(liTag) || isListElement(n->parentNode()))
- return static_cast<HTMLElement*>(n);
+ return n;
if (n == root || isTableCell(n))
return 0;
}
@@ -692,7 +694,7 @@ static HTMLElement* embeddedSublist(Node* listItem)
// Check the DOM so that we'll find collapsed sublists without renderers.
for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
if (isListElement(n))
- return static_cast<HTMLElement*>(n);
+ return toHTMLElement(n);
}
return 0;
@@ -703,7 +705,7 @@ static Node* appendedSublist(Node* listItem)
// Check the DOM so that we'll find collapsed sublists without renderers.
for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
if (isListElement(n))
- return static_cast<HTMLElement*>(n);
+ return toHTMLElement(n);
if (isListItem(listItem))
return 0;
}
diff --git a/Source/WebCore/editing/htmlediting.h b/Source/WebCore/editing/htmlediting.h
index 0208dfb..b71e879 100644
--- a/Source/WebCore/editing/htmlediting.h
+++ b/Source/WebCore/editing/htmlediting.h
@@ -26,10 +26,11 @@
#ifndef htmlediting_h
#define htmlediting_h
-#include <wtf/Forward.h>
-#include "HTMLNames.h"
#include "ExceptionCode.h"
+#include "HTMLNames.h"
#include "Position.h"
+#include <wtf/Forward.h>
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -202,7 +203,7 @@ PassRefPtr<HTMLElement> createHTMLElement(Document*, const AtomicString&);
HTMLElement* enclosingList(Node*);
HTMLElement* outermostEnclosingList(Node*, Node* rootList = 0);
-HTMLElement* enclosingListChild(Node*);
+Node* enclosingListChild(Node*);
// -------------------------------------------------------------------------
// Element
@@ -231,8 +232,11 @@ VisibleSelection avoidIntersectionWithNode(const VisibleSelection&, Node*);
VisibleSelection selectionForParagraphIteration(const VisibleSelection&);
-// Miscellaneous functions on String
-
+// Miscellaneous functions on Text
+inline bool isWhitespace(UChar c)
+{
+ return c == noBreakSpace || c == ' ' || c == '\n' || c == '\t';
+}
String stringWithRebalancedWhitespace(const String&, bool, bool);
const String& nonBreakingSpaceString();
diff --git a/Source/WebCore/editing/mac/SelectionControllerMac.mm b/Source/WebCore/editing/mac/SelectionControllerMac.mm
index 730eb60..119d406 100644
--- a/Source/WebCore/editing/mac/SelectionControllerMac.mm
+++ b/Source/WebCore/editing/mac/SelectionControllerMac.mm
@@ -33,6 +33,19 @@
namespace WebCore {
+static CGRect accessibilityConvertScreenRect(CGRect bounds)
+{
+ NSArray *screens = [NSScreen screens];
+ if ([screens count]) {
+ CGFloat screenHeight = NSHeight([[screens objectAtIndex:0] frame]);
+ bounds.origin.y = (screenHeight - (bounds.origin.y + bounds.size.height));
+ } else
+ bounds = CGRectZero;
+
+ return bounds;
+}
+
+
void SelectionController::notifyAccessibilityForSelectionChange()
{
Document* document = m_frame->document();
@@ -58,8 +71,8 @@ void SelectionController::notifyAccessibilityForSelectionChange()
viewRect = frameView->contentsToScreen(viewRect);
CGRect cgCaretRect = CGRectMake(selectionRect.x(), selectionRect.y(), selectionRect.width(), selectionRect.height());
CGRect cgViewRect = CGRectMake(viewRect.x(), viewRect.y(), viewRect.width(), viewRect.height());
- cgCaretRect = [[WebCoreViewFactory sharedFactory] accessibilityConvertScreenRect:cgCaretRect];
- cgViewRect = [[WebCoreViewFactory sharedFactory] accessibilityConvertScreenRect:cgViewRect];
+ cgCaretRect = accessibilityConvertScreenRect(cgCaretRect);
+ cgViewRect = accessibilityConvertScreenRect(cgViewRect);
UAZoomChangeFocus(&cgViewRect, &cgCaretRect, kUAZoomFocusTypeInsertionPoint);
}
diff --git a/Source/WebCore/editing/markup.cpp b/Source/WebCore/editing/markup.cpp
index 4cbdcce..34c3ec7 100644
--- a/Source/WebCore/editing/markup.cpp
+++ b/Source/WebCore/editing/markup.cpp
@@ -27,7 +27,6 @@
#include "markup.h"
#include "CDATASection.h"
-#include "CharacterNames.h"
#include "CSSComputedStyleDeclaration.h"
#include "CSSMutableStyleDeclaration.h"
#include "CSSPrimitiveValue.h"
@@ -56,6 +55,7 @@
#include "htmlediting.h"
#include "visible_units.h"
#include <wtf/StdLibExtras.h>
+#include <wtf/unicode/CharacterNames.h>
using namespace std;
@@ -124,7 +124,7 @@ public:
}
Node* serializeNodes(Node* startNode, Node* pastEnd);
- void appendString(const String& s) { return MarkupAccumulator::appendString(s); }
+ virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); }
void wrapWithNode(Node*, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode);
void wrapWithStyleNode(CSSStyleDeclaration*, Document*, bool isBlock = false);
String takeResults();
@@ -184,7 +184,8 @@ String StyledMarkupAccumulator::takeResults()
concatenateMarkup(result);
- return String::adopt(result);
+ // We remove '\0' characters because they are not visibly rendered to the user.
+ return String::adopt(result).replace(0, "");
}
void StyledMarkupAccumulator::appendText(Vector<UChar>& out, Text* text)
@@ -194,7 +195,7 @@ void StyledMarkupAccumulator::appendText(Vector<UChar>& out, Text* text)
return;
}
- bool useRenderedText = !enclosingNodeWithTag(Position(text, 0), selectTag);
+ bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag);
String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range);
Vector<UChar> buffer;
appendCharactersReplacingEntities(buffer, content.characters(), content.length(), EntityMaskInPCDATA);
@@ -267,7 +268,7 @@ void StyledMarkupAccumulator::appendElement(Vector<UChar>& out, Element* element
}
if (element->isHTMLElement() && (shouldAnnotate() || addDisplayInline)) {
- RefPtr<CSSMutableStyleDeclaration> style = static_cast<HTMLElement*>(element)->getInlineStyleDecl()->copy();
+ RefPtr<CSSMutableStyleDeclaration> style = toHTMLElement(element)->getInlineStyleDecl()->copy();
if (shouldAnnotate()) {
RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(const_cast<Element*>(element));
// Styles from the inline style declaration, held in the variable "style", take precedence
@@ -337,7 +338,7 @@ Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd)
// Don't write out empty block containers that aren't fully selected.
continue;
- if (!n->renderer() && !enclosingNodeWithTag(Position(n, 0), selectTag)) {
+ if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(n), selectTag)) {
next = n->traverseNextSibling();
// Don't skip over pastEnd.
if (pastEnd && pastEnd->isDescendantOf(n))
@@ -495,7 +496,7 @@ static Node* highestAncestorToWrapMarkup(const Range* range, Node* fullySelected
Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;
if (checkAncestor->renderer()) {
- Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(Position(checkAncestor, 0), &isElementPresentational);
+ Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isElementPresentational);
if (newSpecialCommonAncestor)
specialCommonAncestor = newSpecialCommonAncestor;
}
@@ -509,7 +510,7 @@ static Node* highestAncestorToWrapMarkup(const Range* range, Node* fullySelected
if (!specialCommonAncestor && isTabSpanNode(commonAncestor))
specialCommonAncestor = commonAncestor;
- if (Node *enclosingAnchor = enclosingNodeWithTag(Position(specialCommonAncestor ? specialCommonAncestor : commonAncestor, 0), aTag))
+ if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag))
specialCommonAncestor = enclosingAnchor;
if (shouldAnnotate == AnnotateForInterchange && fullySelectedRoot) {
@@ -579,7 +580,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
}
}
- Node* body = enclosingNodeWithTag(Position(commonAncestor, 0), bodyTag);
+ Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag);
Node* fullySelectedRoot = 0;
// FIXME: Do this for all fully selected blocks, not just the body.
if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range))
diff --git a/Source/WebCore/editing/visible_units.cpp b/Source/WebCore/editing/visible_units.cpp
index 3582aa9..391d6e6 100644
--- a/Source/WebCore/editing/visible_units.cpp
+++ b/Source/WebCore/editing/visible_units.cpp
@@ -292,7 +292,7 @@ static unsigned previousWordPositionBoundary(const UChar* characters, unsigned l
VisiblePosition previousWordPosition(const VisiblePosition &c)
{
VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
- return c.honorEditableBoundaryAtOrAfter(prev);
+ return c.honorEditableBoundaryAtOrBefore(prev);
}
static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
@@ -308,7 +308,7 @@ static unsigned nextWordPositionBoundary(const UChar* characters, unsigned lengt
VisiblePosition nextWordPosition(const VisiblePosition &c)
{
VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);
- return c.honorEditableBoundaryAtOrBefore(next);
+ return c.honorEditableBoundaryAtOrAfter(next);
}
// ---------
@@ -391,7 +391,7 @@ VisiblePosition startOfLine(const VisiblePosition& c)
{
VisiblePosition visPos = startPositionForLine(c);
- return c.honorEditableBoundaryAtOrAfter(visPos);
+ return c.honorEditableBoundaryAtOrBefore(visPos);
}
static VisiblePosition endPositionForLine(const VisiblePosition& c)
@@ -458,7 +458,7 @@ VisiblePosition endOfLine(const VisiblePosition& c)
visPos = endPositionForLine(visPos);
}
- return c.honorEditableBoundaryAtOrBefore(visPos);
+ return c.honorEditableBoundaryAtOrAfter(visPos);
}
bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
@@ -536,7 +536,7 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
n = previousLeafWithSameEditability(n);
while (n) {
- if (highestEditableRoot(Position(n, 0)) != highestRoot)
+ if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot)
break;
Position pos(n, caretMinOffset(n));
if (pos.isCandidate()) {
@@ -567,7 +567,7 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer();
Node* node = renderer->node();
if (node && editingIgnoresContent(node))
- return Position(node->parentNode(), node->nodeIndex());
+ return positionInParentBeforeNode(node);
return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
}
@@ -583,7 +583,7 @@ static Node* nextLeafWithSameEditability(Node* node, int offset)
bool editable = node->isContentEditable();
ASSERT(offset >= 0);
Node* child = node->childNode(offset);
- Node* n = child ? child->nextLeafNode() : node->nextLeafNode();
+ Node* n = child ? child->nextLeafNode() : node->lastDescendant()->nextLeafNode();
while (n) {
if (editable == n->isContentEditable())
return n;
@@ -645,7 +645,7 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
n = nextLeafWithSameEditability(n);
while (n) {
- if (highestEditableRoot(Position(n, 0)) != highestRoot)
+ if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot)
break;
Position pos(n, caretMinOffset(n));
if (pos.isCandidate()) {
@@ -672,7 +672,7 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer();
Node* node = renderer->node();
if (node && editingIgnoresContent(node))
- return Position(node->parentNode(), node->nodeIndex());
+ return positionInParentBeforeNode(node);
return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
}
@@ -720,7 +720,7 @@ static unsigned previousSentencePositionBoundary(const UChar* characters, unsign
VisiblePosition previousSentencePosition(const VisiblePosition &c)
{
VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
- return c.honorEditableBoundaryAtOrAfter(prev);
+ return c.honorEditableBoundaryAtOrBefore(prev);
}
static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
@@ -734,7 +734,7 @@ static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned l
VisiblePosition nextSentencePosition(const VisiblePosition &c)
{
VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);
- return c.honorEditableBoundaryAtOrBefore(next);
+ return c.honorEditableBoundaryAtOrAfter(next);
}
VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
@@ -913,7 +913,7 @@ VisiblePosition startOfBlock(const VisiblePosition &c)
Node *startNode = p.node();
if (!startNode)
return VisiblePosition();
- return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
+ return VisiblePosition(firstPositionInNode(startNode->enclosingBlockFlowElement()), DOWNSTREAM);
}
VisiblePosition endOfBlock(const VisiblePosition &c)
@@ -1133,7 +1133,7 @@ VisiblePosition logicalStartOfLine(const VisiblePosition& c)
// Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
VisiblePosition visPos = logicalStartPositionForLine(c);
- return c.honorEditableBoundaryAtOrAfter(visPos);
+ return c.honorEditableBoundaryAtOrBefore(visPos);
}
static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
@@ -1190,7 +1190,7 @@ VisiblePosition logicalEndOfLine(const VisiblePosition& c)
if (!inSameLogicalLine(c, visPos))
visPos = visPos.previous();
- return c.honorEditableBoundaryAtOrBefore(visPos);
+ return c.honorEditableBoundaryAtOrAfter(visPos);
}
VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction)