diff options
Diffstat (limited to 'WebCore/editing/ApplyStyleCommand.cpp')
-rw-r--r-- | WebCore/editing/ApplyStyleCommand.cpp | 236 |
1 files changed, 120 insertions, 116 deletions
diff --git a/WebCore/editing/ApplyStyleCommand.cpp b/WebCore/editing/ApplyStyleCommand.cpp index 4385a16..d104cbe 100644 --- a/WebCore/editing/ApplyStyleCommand.cpp +++ b/WebCore/editing/ApplyStyleCommand.cpp @@ -31,11 +31,13 @@ #include "CSSParser.h" #include "CSSProperty.h" #include "CSSPropertyNames.h" +#include "CSSStyleSelector.h" #include "CSSValueKeywords.h" #include "Document.h" #include "Editor.h" #include "Frame.h" #include "HTMLElement.h" +#include "HTMLFontElement.h" #include "HTMLInterchange.h" #include "HTMLNames.h" #include "NodeList.h" @@ -110,7 +112,7 @@ public: private: void init(PassRefPtr<CSSStyleDeclaration>, const Position&); void reconcileTextDecorationProperties(CSSMutableStyleDeclaration*); - void extractTextStyles(CSSMutableStyleDeclaration*); + void extractTextStyles(Document*, CSSMutableStyleDeclaration*, bool shouldUseFixedFontDefautlSize); String m_cssStyle; bool m_applyBold; @@ -147,7 +149,7 @@ void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& po reconcileTextDecorationProperties(mutableStyle.get()); if (!document->frame()->editor()->shouldStyleWithCSS()) - extractTextStyles(mutableStyle.get()); + extractTextStyles(document, mutableStyle.get(), computedStyle->useFixedFontDefaultSize()); // Changing the whitespace style in a tab span would collapse the tab into a space. if (isTabSpanTextNode(position.node()) || isTabSpanNode((position.node()))) @@ -202,7 +204,7 @@ static void setTextDecorationProperty(CSSMutableStyleDeclaration* style, const C } } -void StyleChange::extractTextStyles(CSSMutableStyleDeclaration* style) +void StyleChange::extractTextStyles(Document* document, CSSMutableStyleDeclaration* style, bool shouldUseFixedFontDefautlSize) { ASSERT(style); @@ -259,28 +261,18 @@ void StyleChange::extractTextStyles(CSSMutableStyleDeclaration* style) style->removeProperty(CSSPropertyFontSize); // Can't make sense of the number. Put no font size. else { CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(fontSize.get()); - - // Only accept absolute scale if (value->primitiveType() >= CSSPrimitiveValue::CSS_PX && value->primitiveType() <= CSSPrimitiveValue::CSS_PC) { - float number = value->getFloatValue(CSSPrimitiveValue::CSS_PX); - if (number <= 9) - m_applyFontSize = "1"; - else if (number <= 10) - m_applyFontSize = "2"; - else if (number <= 13) - m_applyFontSize = "3"; - else if (number <= 16) - m_applyFontSize = "4"; - else if (number <= 18) - m_applyFontSize = "5"; - else if (number <= 24) - m_applyFontSize = "6"; - else - m_applyFontSize = "7"; + 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); } - // Huge quirk in Microsoft Entourage is that they understand CSS font-size, but also write - // out legacy 1-7 values in font tags (I guess for mailers that are not CSS-savvy at all, - // like Eudora). Yes, they write out *both*. We need to write out both as well. } } } @@ -1037,7 +1029,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style) RefPtr<CSSMutableStyleDeclaration> embeddingStyle = CSSMutableStyleDeclaration::create(); embeddingStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed); embeddingStyle->setProperty(CSSPropertyDirection, direction); - applyInlineStyleToRange(embeddingStyle.get(), embeddingApplyStart, embeddingApplyEnd); + fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStart, embeddingApplyEnd); if (styleWithoutEmbedding) styleToApply = styleWithoutEmbedding; @@ -1049,7 +1041,7 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style) } } - applyInlineStyleToRange(styleToApply.get(), start, end); + fixRangeAndApplyInlineStyle(styleToApply.get(), start, end); // Remove dummy style spans created by splitting text elements. cleanupUnstyledAppleStyleSpans(startDummySpanAncestor); @@ -1057,78 +1049,71 @@ void ApplyStyleCommand::applyInlineStyle(CSSMutableStyleDeclaration *style) cleanupUnstyledAppleStyleSpans(endDummySpanAncestor); } -void ApplyStyleCommand::applyInlineStyleToRange(CSSMutableStyleDeclaration* style, const Position& start, const Position& rangeEnd) +void ApplyStyleCommand::fixRangeAndApplyInlineStyle(CSSMutableStyleDeclaration* style, const Position& start, const Position& end) { - Node* node = start.node(); - Position end = rangeEnd; - - bool rangeIsEmpty = false; + Node* startNode = start.node(); if (start.deprecatedEditingOffset() >= caretMaxOffset(start.node())) { - node = node->traverseNextNode(); - Position newStart = Position(node, 0); - if (!node || comparePositions(end, newStart) < 0) - rangeIsEmpty = true; - } - - if (!rangeIsEmpty) { - // pastEndNode is the node after the last fully selected node. - Node* pastEndNode = end.node(); - if (end.deprecatedEditingOffset() >= caretMaxOffset(end.node())) - pastEndNode = end.node()->traverseNextSibling(); - // FIXME: Callers should perform this operation on a Range that includes the br - // if they want style applied to the empty line. - if (start == end && start.node()->hasTagName(brTag)) - pastEndNode = start.node()->traverseNextNode(); - // Add the style to selected inline runs. - for (Node* next; node && node != pastEndNode; node = next) { - - next = node->traverseNextNode(); - - if (!node->renderer() || !node->isContentEditable()) - continue; - - if (!node->isContentRichlyEditable() && node->isHTMLElement()) { - // This is a plaintext-only region. Only proceed if it's fully selected. - // pastEndNode is the node after the last fully selected node, so if it's inside node then - // node isn't fully selected. - if (pastEndNode && pastEndNode->isDescendantOf(node)) - break; - // Add to this element's inline style and skip over its contents. - HTMLElement* element = static_cast<HTMLElement*>(node); - RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineStyleDecl()->copy(); - inlineStyle->merge(style); - setNodeAttribute(element, styleAttr, inlineStyle->cssText()); - next = node->traverseNextSibling(); - continue; - } + startNode = startNode->traverseNextNode(); + if (!startNode || comparePositions(end, Position(startNode, 0)) < 0) + return; + } + + Node* pastEndNode = end.node(); + if (end.deprecatedEditingOffset() >= caretMaxOffset(end.node())) + pastEndNode = end.node()->traverseNextSibling(); + + // FIXME: Callers should perform this operation on a Range that includes the br + // if they want style applied to the empty line. + if (start == end && start.node()->hasTagName(brTag)) + pastEndNode = start.node()->traverseNextNode(); + + applyInlineStyleToNodeRange(style, startNode, pastEndNode); +} + +void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration* style, Node* node, Node* pastEndNode) +{ + for (Node* next; node && node != pastEndNode; node = next) { + next = node->traverseNextNode(); - if (isBlock(node)) - continue; - - if (node->childNodeCount()) { - if (editingIgnoresContent(node)) { - next = node->traverseNextSibling(); - continue; - } - continue; - } - - Node* runStart = node; - // Find the end of the run. - Node* sibling = node->nextSibling(); - StyleChange startChange(style, Position(node, 0)); - while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNode) - && (!isBlock(sibling) || sibling->hasTagName(brTag)) - && StyleChange(style, Position(sibling, 0)) == startChange) { - node = sibling; - sibling = node->nextSibling(); - } - // Recompute next, since node has changed. + if (!node->renderer() || !node->isContentEditable()) + continue; + + if (!node->isContentRichlyEditable() && node->isHTMLElement()) { + // This is a plaintext-only region. Only proceed if it's fully selected. + // pastEndNode is the node after the last fully selected node, so if it's inside node then + // node isn't fully selected. + if (pastEndNode && pastEndNode->isDescendantOf(node)) + break; + // Add to this element's inline style and skip over its contents. + HTMLElement* element = static_cast<HTMLElement*>(node); + RefPtr<CSSMutableStyleDeclaration> inlineStyle = element->getInlineStyleDecl()->copy(); + inlineStyle->merge(style); + setNodeAttribute(element, styleAttr, inlineStyle->cssText()); next = node->traverseNextSibling(); - // Apply the style to the run. - addInlineStyleIfNeeded(style, runStart, node, m_removeOnly ? DoNotAddStyledElement : AddStyledElement); + continue; + } + + if (isBlock(node)) + continue; + + if (node->childNodeCount()) { + if (editingIgnoresContent(node)) + next = node->traverseNextSibling(); + continue; } + + Node* runEnd = node; + Node* sibling = node->nextSibling(); + StyleChange startChange(style, Position(node, 0)); + while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNode) + && (!isBlock(sibling) || sibling->hasTagName(brTag)) + && StyleChange(style, Position(sibling, 0)) == startChange) { + runEnd = sibling; + sibling = runEnd->nextSibling(); + } + next = runEnd->traverseNextSibling(); + addInlineStyleIfNeeded(style, node, runEnd, m_removeOnly ? DoNotAddStyledElement : AddStyledElement); } } @@ -1165,33 +1150,52 @@ struct HTMLEquivalent { int primitiveId; const QualifiedName* element; const QualifiedName* attribute; + PassRefPtr<CSSValue> (*attributeToCSSValue)(int propertyID, const String&); EPushDownType pushDownType; }; +static PassRefPtr<CSSValue> stringToCSSValue(int propertyID, const String& value) +{ + RefPtr<CSSMutableStyleDeclaration> dummyStyle; + dummyStyle = CSSMutableStyleDeclaration::create(); + dummyStyle->setProperty(propertyID, value); + return dummyStyle->getPropertyCSSValue(propertyID); +} + +static PassRefPtr<CSSValue> fontSizeToCSSValue(int propertyID, const String& value) +{ + UNUSED_PARAM(propertyID); + ASSERT(propertyID == CSSPropertyFontSize); + int size; + if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size)) + return 0; + return CSSPrimitiveValue::createIdentifier(size); +} + static const HTMLEquivalent HTMLEquivalents[] = { - { CSSPropertyFontWeight, false, CSSValueBold, &bTag, 0, ShouldBePushedDown }, - { CSSPropertyFontWeight, false, CSSValueBold, &strongTag, 0, ShouldBePushedDown }, - { CSSPropertyVerticalAlign, false, CSSValueSub, &subTag, 0, ShouldBePushedDown }, - { CSSPropertyVerticalAlign, false, CSSValueSuper, &supTag, 0, ShouldBePushedDown }, - { CSSPropertyFontStyle, false, CSSValueItalic, &iTag, 0, ShouldBePushedDown }, - { CSSPropertyFontStyle, false, CSSValueItalic, &emTag, 0, ShouldBePushedDown }, + { CSSPropertyFontWeight, false, CSSValueBold, &bTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyFontWeight, false, CSSValueBold, &strongTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyVerticalAlign, false, CSSValueSub, &subTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyVerticalAlign, false, CSSValueSuper, &supTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyFontStyle, false, CSSValueItalic, &iTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyFontStyle, false, CSSValueItalic, &emTag, 0, 0, ShouldBePushedDown }, // text-decorations should be CSSValueList - { CSSPropertyTextDecoration, true, CSSValueUnderline, &uTag, 0, ShouldBePushedDown }, - { CSSPropertyTextDecoration, true, CSSValueLineThrough, &sTag, 0, ShouldBePushedDown }, - { CSSPropertyTextDecoration, true, CSSValueLineThrough, &strikeTag, 0, ShouldBePushedDown }, - { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueUnderline, &uTag, 0, ShouldBePushedDown }, - { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &sTag, 0, ShouldBePushedDown }, - { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &strikeTag, 0, ShouldBePushedDown }, + { CSSPropertyTextDecoration, true, CSSValueUnderline, &uTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyTextDecoration, true, CSSValueLineThrough, &sTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyTextDecoration, true, CSSValueLineThrough, &strikeTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueUnderline, &uTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &sTag, 0, 0, ShouldBePushedDown }, + { CSSPropertyWebkitTextDecorationsInEffect, true, CSSValueLineThrough, &strikeTag, 0, 0, ShouldBePushedDown }, // FIXME: font attributes should only be removed if values were different - { CSSPropertyColor, false, CSSValueInvalid, &fontTag, &colorAttr, ShouldBePushedDown }, - { CSSPropertyFontFamily, false, CSSValueInvalid, &fontTag, &faceAttr, ShouldBePushedDown }, - { CSSPropertyFontSize, false, CSSValueInvalid, &fontTag, &sizeAttr, ShouldBePushedDown }, + { CSSPropertyColor, false, CSSValueInvalid, &fontTag, &colorAttr, stringToCSSValue, ShouldBePushedDown }, + { CSSPropertyFontFamily, false, CSSValueInvalid, &fontTag, &faceAttr, stringToCSSValue, ShouldBePushedDown }, + { CSSPropertyFontSize, false, CSSValueInvalid, &fontTag, &sizeAttr, fontSizeToCSSValue, ShouldBePushedDown }, // unicode-bidi and direction are pushed down separately so don't push down with other styles. - { CSSPropertyUnicodeBidi, false, CSSValueInvalid, 0, &dirAttr, ShouldNotBePushedDown }, - { CSSPropertyDirection, false, CSSValueInvalid, 0, &dirAttr, ShouldNotBePushedDown }, + { CSSPropertyDirection, false, CSSValueInvalid, 0, &dirAttr, stringToCSSValue, ShouldNotBePushedDown }, + { CSSPropertyUnicodeBidi, false, CSSValueInvalid, 0, &dirAttr, stringToCSSValue, ShouldNotBePushedDown }, }; bool ApplyStyleCommand::removeImplicitlyStyledElement(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle) @@ -1210,19 +1214,19 @@ bool ApplyStyleCommand::removeImplicitlyStyledElement(CSSMutableStyleDeclaration RefPtr<CSSValue> styleValue = style->getPropertyCSSValue(equivalent.propertyID); if (!styleValue) continue; - RefPtr<CSSPrimitiveValue> mapValue = CSSPrimitiveValue::createIdentifier(equivalent.primitiveId); + RefPtr<CSSValue> mapValue; + if (equivalent.attribute) + mapValue = equivalent.attributeToCSSValue(equivalent.propertyID, element->getAttribute(*equivalent.attribute)); + else + mapValue = CSSPrimitiveValue::createIdentifier(equivalent.primitiveId).get(); if (equivalent.isValueList && styleValue->isValueList() && static_cast<CSSValueList*>(styleValue.get())->hasValue(mapValue.get())) continue; // If CSS value assumes CSSValueList, then only skip if the value was present in style to apply. - else if (styleValue->cssText() == mapValue->cssText()) + else if (mapValue && styleValue->cssText() == mapValue->cssText()) continue; // If CSS value is primitive, then skip if they are equal. - if (extractedStyle) { - if (equivalent.primitiveId == CSSValueInvalid) - extractedStyle->setProperty(equivalent.propertyID, element->getAttribute(*equivalent.attribute)); - else - extractedStyle->setProperty(equivalent.propertyID, mapValue->cssText()); - } + if (extractedStyle) + extractedStyle->setProperty(equivalent.propertyID, mapValue->cssText()); if (mode == RemoveNone) return true; |