From db14019a23d96bc8a444b6576a5da8bd1cfbc8b0 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Wed, 4 Aug 2010 11:41:34 +0100 Subject: Merge WebKit at r64523 : Initial merge by git. Change-Id: Ibb796c6802e757b1d9b40f58205cfbe4da95fcd4 --- WebCore/editing/ApplyStyleCommand.cpp | 131 +++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 41 deletions(-) (limited to 'WebCore/editing/ApplyStyleCommand.cpp') diff --git a/WebCore/editing/ApplyStyleCommand.cpp b/WebCore/editing/ApplyStyleCommand.cpp index 8847714..d865468 100644 --- a/WebCore/editing/ApplyStyleCommand.cpp +++ b/WebCore/editing/ApplyStyleCommand.cpp @@ -910,7 +910,10 @@ 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) { - splitTextElementAtStart(start, end); + if (shouldSplitTextElement(start.node()->parentElement(), style)) + splitTextElementAtStart(start, end); + else + splitTextAtStart(start, end); start = startPosition(); end = endPosition(); startDummySpanAncestor = dummySpanAncestorForNode(start.node()); @@ -919,7 +922,10 @@ 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) { - splitTextElementAtEnd(start, end); + if (shouldSplitTextElement(end.node()->parentElement(), style)) + splitTextElementAtEnd(start, end); + else + splitTextAtEnd(start, end); start = startPosition(); end = endPosition(); endDummySpanAncestor = dummySpanAncestorForNode(end.node()); @@ -1176,6 +1182,40 @@ bool ApplyStyleCommand::implicitlyStyledElementShouldBeRemovedWhenApplyingStyle( return false; } +bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode) +{ + ASSERT(style); + ASSERT(element); + + bool removed = false; + + if (m_styledInlineElement && element->hasTagName(m_styledInlineElement->tagQName())) { + removed = true; + if (mode == RemoveAttributesAndElements) + removeNodePreservingChildren(element); + } + + if (implicitlyStyledElementShouldBeRemovedWhenApplyingStyle(element, style)) { + removed = true; + if (mode == RemoveAttributesAndElements) + replaceWithSpanOrRemoveIfWithoutAttributes(element); + } + + if (!element->inDocument()) + return removed; + + // If the node was converted to a span, the span may still contain relevant + // styles which must be removed (e.g. ) + if (removeHTMLFontStyle(style, element, mode)) + removed = true; + if (removeHTMLBidiEmbeddingStyle(style, element, mode)) + removed = true; + if (removeCSSStyle(style, element, mode)) + removed = true; + + return removed; +} + void ApplyStyleCommand::replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*& elem) { bool removeNode = false; @@ -1200,65 +1240,84 @@ void ApplyStyleCommand::replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*& } } -void ApplyStyleCommand::removeHTMLFontStyle(CSSMutableStyleDeclaration *style, HTMLElement *elem) +bool ApplyStyleCommand::removeHTMLFontStyle(CSSMutableStyleDeclaration* style, HTMLElement* elem, InlineStyleRemovalMode mode) { ASSERT(style); ASSERT(elem); if (!elem->hasLocalName(fontTag)) - return; - + return false; + + bool removed = false; CSSMutableStyleDeclaration::const_iterator end = style->end(); for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { + const QualifiedName* attrToRemove = 0; switch ((*it).id()) { - case CSSPropertyColor: - removeNodeAttribute(elem, colorAttr); - break; - case CSSPropertyFontFamily: - removeNodeAttribute(elem, faceAttr); - break; - case CSSPropertyFontSize: - removeNodeAttribute(elem, sizeAttr); - break; + case CSSPropertyColor: + attrToRemove = &colorAttr; + break; + case CSSPropertyFontFamily: + attrToRemove = &faceAttr; + break; + case CSSPropertyFontSize: + attrToRemove = &sizeAttr; + break; + } + + if (attrToRemove) { + removed = true; + if (mode == RemoveAttributesAndElements) + removeNodeAttribute(elem, *attrToRemove); } } - if (isEmptyFontTag(elem)) + if (isEmptyFontTag(elem) && mode == RemoveAttributesAndElements) removeNodePreservingChildren(elem); + + return removed; } -void ApplyStyleCommand::removeHTMLBidiEmbeddingStyle(CSSMutableStyleDeclaration *style, HTMLElement *elem) +bool ApplyStyleCommand::removeHTMLBidiEmbeddingStyle(CSSMutableStyleDeclaration* style, HTMLElement* elem, InlineStyleRemovalMode mode) { ASSERT(style); ASSERT(elem); if (!elem->hasAttribute(dirAttr)) - return; + return false; if (!style->getPropertyCSSValue(CSSPropertyUnicodeBidi) && !style->getPropertyCSSValue(CSSPropertyDirection)) - return; + return false; + + if (mode == RemoveNone) + return true; removeNodeAttribute(elem, dirAttr); // FIXME: should this be isSpanWithoutAttributesOrUnstyleStyleSpan? Need a test. if (isUnstyledStyleSpan(elem)) removeNodePreservingChildren(elem); + + return true; } -void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLElement* elem) +bool ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLElement* elem, InlineStyleRemovalMode mode) { ASSERT(style); ASSERT(elem); CSSMutableStyleDeclaration* decl = elem->inlineStyleDecl(); if (!decl) - return; + return false; + bool removed = false; CSSMutableStyleDeclaration::const_iterator end = style->end(); for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { CSSPropertyID propertyID = static_cast((*it).id()); RefPtr value = decl->getPropertyCSSValue(propertyID); if (value && (propertyID != CSSPropertyWhiteSpace || !isTabSpanNode(elem))) { + removed = true; + if (mode == RemoveNone) + return true; removeCSSProperty(decl, propertyID); if (propertyID == CSSPropertyUnicodeBidi && !decl->getPropertyValue(CSSPropertyDirection).isEmpty()) removeCSSProperty(decl, CSSPropertyDirection); @@ -1271,6 +1330,8 @@ void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLEl if (isSpanWithoutAttributesOrUnstyleStyleSpan(elem)) removeNodePreservingChildren(elem); + + return removed; } static bool hasTextDecorationProperty(Node *node) @@ -1472,19 +1533,7 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr HTMLElement* elem = static_cast(node); Node* prev = elem->traversePreviousNodePostOrder(); Node* next = elem->traverseNextNode(); - if (m_styledInlineElement && elem->hasTagName(m_styledInlineElement->tagQName())) - removeNodePreservingChildren(elem); - - if (implicitlyStyledElementShouldBeRemovedWhenApplyingStyle(elem, style.get())) - replaceWithSpanOrRemoveIfWithoutAttributes(elem); - - // If the node was converted to a span, the span may still contain relevant - // styles which must be removed (e.g. ) - if (elem->inDocument()) { - removeHTMLFontStyle(style.get(), elem); - removeHTMLBidiEmbeddingStyle(style.get(), elem); - removeCSSStyle(style.get(), elem); - } + removeInlineStyleFromElement(style.get(), elem); if (!elem->inDocument()) { if (s.node() == elem) { // Since elem must have been fully selected, and it is at the start @@ -1554,10 +1603,6 @@ void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& en void ApplyStyleCommand::splitTextElementAtStart(const Position& start, const Position& end) { - Node* parent = start.node()->parentNode(); - if (!parent || !parent->parentElement() || !parent->parentElement()->isContentEditable()) - return splitTextAtStart(start, end); - int endOffsetAdjustment = start.node() == end.node() ? start.deprecatedEditingOffset() : 0; Text* text = static_cast(start.node()); splitTextNodeContainingElement(text, start.deprecatedEditingOffset()); @@ -1566,10 +1611,6 @@ void ApplyStyleCommand::splitTextElementAtStart(const Position& start, const Pos void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Position& end) { - Node* parent = end.node()->parentNode(); - if (!parent || !parent->parentElement() || !parent->parentElement()->isContentEditable()) - return splitTextAtEnd(start, end); - Text* text = static_cast(end.node()); splitTextNodeContainingElement(text, end.deprecatedEditingOffset()); @@ -1580,6 +1621,14 @@ void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Posit updateStartEnd(Position(startNode, start.deprecatedEditingOffset()), Position(prevNode->parent(), prevNode->nodeIndex() + 1)); } +bool ApplyStyleCommand::shouldSplitTextElement(Element* element, CSSMutableStyleDeclaration* style) +{ + if (!element || !element->isHTMLElement() || !element->parentElement() || !element->parentElement()->isContentEditable()) + return false; + + return shouldRemoveInlineStyleFromElement(style, static_cast(element)); +} + bool ApplyStyleCommand::isValidCaretPositionInTextNode(const Position& position) { Node* node = position.node(); -- cgit v1.1