summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.cpp57
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.h1
-rw-r--r--WebCore/editing/SelectionController.cpp77
-rw-r--r--WebCore/editing/SelectionController.h4
4 files changed, 104 insertions, 35 deletions
diff --git a/WebCore/editing/ReplaceSelectionCommand.cpp b/WebCore/editing/ReplaceSelectionCommand.cpp
index f26757e..bac090c 100644
--- a/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -468,6 +468,17 @@ void ReplaceSelectionCommand::negateStyleRulesThatAffectAppearance()
e->getInlineStyleDecl()->setProperty(CSSPropertyDisplay, CSSValueInline);
if (e->renderer() && e->renderer()->style()->floating() != FNONE)
e->getInlineStyleDecl()->setProperty(CSSPropertyFloat, CSSValueNone);
+
+ // Undo the effects of page zoom if we have an absolute font size. When we copy, we
+ // compute the new font size as an absolute size so pasting will cause the zoom to be
+ // applied twice.
+ if (e->renderer() && e->renderer()->style() && e->renderer()->style()->effectiveZoom() != 1.0
+ && e->renderer()->style()->fontDescription().isAbsoluteSize()) {
+ float newSize = e->renderer()->style()->fontDescription().specifiedSize() / e->renderer()->style()->effectiveZoom();
+ ExceptionCode ec = 0;
+ e->style()->setProperty(CSSPropertyFontSize, String::number(newSize), false, ec);
+ ASSERT(!ec);
+ }
}
if (node == m_lastLeafInserted)
break;
@@ -638,10 +649,11 @@ void ReplaceSelectionCommand::handleStyleSpans()
}
// There are non-redundant styles on sourceDocumentStyleSpan, but there is no
- // copiedRangeStyleSpan. Clear the redundant styles from sourceDocumentStyleSpan
- // and return.
+ // copiedRangeStyleSpan. Remove the span, because it could be surrounding block elements,
+ // and apply the styles to its children.
if (sourceDocumentStyle->length() > 0 && !copiedRangeStyleSpan) {
- setNodeAttribute(static_cast<Element*>(sourceDocumentStyleSpan), styleAttr, sourceDocumentStyle->cssText());
+ copyStyleToChildren(sourceDocumentStyleSpan, sourceDocumentStyle.get());
+ removeNodePreservingChildren(sourceDocumentStyleSpan);
return;
}
@@ -673,6 +685,34 @@ void ReplaceSelectionCommand::handleStyleSpans()
setNodeAttribute(static_cast<Element*>(copiedRangeStyleSpan), styleAttr, copiedRangeStyle->cssText());
}
+// Take the style attribute of a span and apply it to it's children instead. This allows us to
+// convert invalid HTML where a span contains block elements into valid HTML while preserving
+// styles.
+void ReplaceSelectionCommand::copyStyleToChildren(Node* parentNode, const CSSMutableStyleDeclaration* parentStyle)
+{
+ ASSERT(parentNode->hasTagName(spanTag));
+ for (Node* childNode = parentNode->firstChild(); childNode; childNode = childNode->nextSibling()) {
+ if (childNode->isTextNode() || !isBlock(childNode) || childNode->hasTagName(preTag)) {
+ // In this case, put a span tag around the child node.
+ RefPtr<Node> newSpan = parentNode->cloneNode(false);
+ setNodeAttribute(static_cast<Element*>(newSpan.get()), styleAttr, parentStyle->cssText());
+ insertNodeAfter(newSpan, childNode);
+ ExceptionCode ec = 0;
+ newSpan->appendChild(childNode, ec);
+ ASSERT(!ec);
+ childNode = newSpan.get();
+ } else if (childNode->isHTMLElement()) {
+ // 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);
+ RefPtr<CSSMutableStyleDeclaration> existingStyles = childElement->getInlineStyleDecl()->copy();
+ existingStyles->merge(newStyle.get(), false);
+ setNodeAttribute(childElement, styleAttr, existingStyles->cssText());
+ }
+ }
+}
+
void ReplaceSelectionCommand::mergeEndIfNeeded()
{
if (!m_shouldMergeEnd)
@@ -871,7 +911,8 @@ void ReplaceSelectionCommand::doApply()
fragment.removeNode(refNode);
Node* blockStart = enclosingBlock(insertionPos.node());
- if (isListElement(refNode.get()) && blockStart->renderer()->isListItem())
+ if ((isListElement(refNode.get()) || (isStyleSpan(refNode.get()) && isListElement(refNode->firstChild())))
+ && blockStart->renderer()->isListItem())
refNode = insertAsListItems(refNode, blockStart, insertionPos);
else
insertNodeAtAndUpdateNodesInserted(refNode, insertionPos);
@@ -1122,15 +1163,15 @@ void ReplaceSelectionCommand::insertNodeBeforeAndUpdateNodesInserted(PassRefPtr<
// If the user is inserting a list into an existing list, instead of nesting the list,
// we put the list items into the existing list.
-Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, Node* insertionNode, const Position& p)
+Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, Node* insertionBlock, const Position& insertPos)
{
while (listElement->hasChildNodes() && isListElement(listElement->firstChild()) && listElement->childNodeCount() == 1)
listElement = listElement->firstChild();
- bool isStart = isStartOfParagraph(p);
- bool isEnd = isEndOfParagraph(p);
+ bool isStart = isStartOfParagraph(insertPos);
+ bool isEnd = isEndOfParagraph(insertPos);
- Node* lastNode = insertionNode;
+ Node* lastNode = insertionBlock;
while (RefPtr<Node> listItem = listElement->firstChild()) {
ExceptionCode ec = 0;
listElement->removeChild(listItem.get(), ec);
diff --git a/WebCore/editing/ReplaceSelectionCommand.h b/WebCore/editing/ReplaceSelectionCommand.h
index 19f63bb..e995e79 100644
--- a/WebCore/editing/ReplaceSelectionCommand.h
+++ b/WebCore/editing/ReplaceSelectionCommand.h
@@ -69,6 +69,7 @@ private:
void negateStyleRulesThatAffectAppearance();
void handleStyleSpans();
+ void copyStyleToChildren(Node* parentNode, const CSSMutableStyleDeclaration* parentStyle);
void handlePasteAsQuotationNode();
virtual void removeNodePreservingChildren(Node*);
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
index 5b2d0d0..25982d4 100644
--- a/WebCore/editing/SelectionController.cpp
+++ b/WebCore/editing/SelectionController.cpp
@@ -265,6 +265,33 @@ TextDirection SelectionController::directionOfEnclosingBlock()
return LTR;
}
+VisiblePosition SelectionController::positionForPlatform(bool isGetStart) const
+{
+ Position pos;
+ Settings* settings = m_frame ? m_frame->settings() : 0;
+ if (settings && settings->editingBehavior() == EditingMacBehavior)
+ pos = isGetStart ? m_selection.start() : m_selection.end();
+ else {
+ // Linux and Windows always extend selections from the extent endpoint.
+ // FIXME: VisibleSelection should be fixed to ensure as an invariant that
+ // base/extent always point to the same nodes as start/end, but which points
+ // to which depends on the value of isBaseFirst. Then this can be changed
+ // to just return m_sel.extent().
+ pos = m_selection.isBaseFirst() ? m_selection.end() : m_selection.start();
+ }
+ return VisiblePosition(pos, m_selection.affinity());
+}
+
+VisiblePosition SelectionController::startForPlatform() const
+{
+ return positionForPlatform(true);
+}
+
+VisiblePosition SelectionController::endForPlatform() const
+{
+ return positionForPlatform(false);
+}
+
VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granularity)
{
VisiblePosition pos(m_selection.extent(), m_selection.affinity());
@@ -298,7 +325,7 @@ VisiblePosition SelectionController::modifyExtendingRight(TextGranularity granul
pos = modifyExtendingForward(granularity);
}
return pos;
-}
+}
VisiblePosition SelectionController::modifyExtendingForward(TextGranularity granularity)
{
@@ -320,16 +347,16 @@ VisiblePosition SelectionController::modifyExtendingForward(TextGranularity gran
pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
break;
case SentenceBoundary:
- pos = endOfSentence(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = endOfSentence(endForPlatform());
break;
case LineBoundary:
- pos = logicalEndOfLine(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = logicalEndOfLine(endForPlatform());
break;
case ParagraphBoundary:
- pos = endOfParagraph(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = endOfParagraph(endForPlatform());
break;
case DocumentBoundary:
- pos = VisiblePosition(m_selection.end(), m_selection.affinity());
+ pos = endForPlatform();
if (isEditablePosition(pos.deepEquivalent()))
pos = endOfEditableContent(pos);
else
@@ -385,25 +412,25 @@ VisiblePosition SelectionController::modifyMovingForward(TextGranularity granula
case LineGranularity: {
// down-arrowing from a range selection that ends at the start of a line needs
// to leave the selection at that line start (no need to call nextLinePosition!)
- pos = VisiblePosition(m_selection.end(), m_selection.affinity());
+ pos = endForPlatform();
if (!isRange() || !isStartOfLine(pos))
pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));
break;
}
case ParagraphGranularity:
- pos = nextParagraphPosition(VisiblePosition(m_selection.end(), m_selection.affinity()), xPosForVerticalArrowNavigation(START));
+ pos = nextParagraphPosition(endForPlatform(), xPosForVerticalArrowNavigation(START));
break;
case SentenceBoundary:
- pos = endOfSentence(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = endOfSentence(endForPlatform());
break;
case LineBoundary:
- pos = logicalEndOfLine(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = logicalEndOfLine(endForPlatform());
break;
case ParagraphBoundary:
- pos = endOfParagraph(VisiblePosition(m_selection.end(), m_selection.affinity()));
+ pos = endOfParagraph(endForPlatform());
break;
case DocumentBoundary:
- pos = VisiblePosition(m_selection.end(), m_selection.affinity());
+ pos = endForPlatform();
if (isEditablePosition(pos.deepEquivalent()))
pos = endOfEditableContent(pos);
else
@@ -473,16 +500,16 @@ VisiblePosition SelectionController::modifyExtendingBackward(TextGranularity gra
pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));
break;
case SentenceBoundary:
- pos = startOfSentence(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = startOfSentence(startForPlatform());
break;
case LineBoundary:
- pos = logicalStartOfLine(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = logicalStartOfLine(startForPlatform());
break;
case ParagraphBoundary:
- pos = startOfParagraph(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = startOfParagraph(startForPlatform());
break;
case DocumentBoundary:
- pos = VisiblePosition(m_selection.start(), m_selection.affinity());
+ pos = startForPlatform();
if (isEditablePosition(pos.deepEquivalent()))
pos = startOfEditableContent(pos);
else
@@ -534,22 +561,22 @@ VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granul
pos = previousSentencePosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
break;
case LineGranularity:
- pos = previousLinePosition(VisiblePosition(m_selection.start(), m_selection.affinity()), xPosForVerticalArrowNavigation(START));
+ pos = previousLinePosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
break;
case ParagraphGranularity:
- pos = previousParagraphPosition(VisiblePosition(m_selection.start(), m_selection.affinity()), xPosForVerticalArrowNavigation(START));
+ pos = previousParagraphPosition(startForPlatform(), xPosForVerticalArrowNavigation(START));
break;
case SentenceBoundary:
- pos = startOfSentence(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = startOfSentence(startForPlatform());
break;
case LineBoundary:
- pos = logicalStartOfLine(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = logicalStartOfLine(startForPlatform());
break;
case ParagraphBoundary:
- pos = startOfParagraph(VisiblePosition(m_selection.start(), m_selection.affinity()));
+ pos = startOfParagraph(startForPlatform());
break;
case DocumentBoundary:
- pos = VisiblePosition(m_selection.start(), m_selection.affinity());
+ pos = startForPlatform();
if (isEditablePosition(pos.deepEquivalent()))
pos = startOfEditableContent(pos);
else
@@ -840,7 +867,6 @@ void SelectionController::layout()
RenderObject* caretPainter = caretRenderer();
// Compute an offset between the renderer and the caretPainter
- IntSize offsetFromPainter;
bool unrooted = false;
while (renderer != caretPainter) {
RenderObject* containerObject = renderer->container();
@@ -848,15 +874,12 @@ void SelectionController::layout()
unrooted = true;
break;
}
- offsetFromPainter += renderer->offsetFromContainer(containerObject);
+ localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
renderer = containerObject;
}
- if (!unrooted) {
- // Move the caret rect to the coords of the painter
- localRect.move(offsetFromPainter);
+ if (!unrooted)
m_caretRect = localRect;
- }
m_absCaretBoundsDirty = true;
}
diff --git a/WebCore/editing/SelectionController.h b/WebCore/editing/SelectionController.h
index 7cad435..6849cb6 100644
--- a/WebCore/editing/SelectionController.h
+++ b/WebCore/editing/SelectionController.h
@@ -140,6 +140,10 @@ private:
TextDirection directionOfEnclosingBlock();
+ VisiblePosition positionForPlatform(bool isGetStart) const;
+ VisiblePosition startForPlatform() const;
+ VisiblePosition endForPlatform() const;
+
VisiblePosition modifyExtendingRight(TextGranularity);
VisiblePosition modifyExtendingForward(TextGranularity);
VisiblePosition modifyMovingRight(TextGranularity);