summaryrefslogtreecommitdiffstats
path: root/WebCore/editing/ApplyStyleCommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing/ApplyStyleCommand.cpp')
-rw-r--r--WebCore/editing/ApplyStyleCommand.cpp236
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;