diff options
Diffstat (limited to 'WebCore/editing')
-rw-r--r-- | WebCore/editing/ReplaceSelectionCommand.cpp | 57 | ||||
-rw-r--r-- | WebCore/editing/ReplaceSelectionCommand.h | 1 | ||||
-rw-r--r-- | WebCore/editing/SelectionController.cpp | 77 | ||||
-rw-r--r-- | WebCore/editing/SelectionController.h | 4 |
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); |