📄 applystylecommand.cpp
字号:
/* * Copyright (C) 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "ApplyStyleCommand.h"#include "CSSComputedStyleDeclaration.h"#include "CSSParser.h"#include "CSSProperty.h"#include "CSSPropertyNames.h"#include "CSSValueKeywords.h"#include "Document.h"#include "Editor.h"#include "Frame.h"#include "HTMLElement.h"#include "HTMLInterchange.h"#include "HTMLNames.h"#include "NodeList.h"#include "Range.h"#include "RenderObject.h"#include "Text.h"#include "TextIterator.h"#include "htmlediting.h"#include "visible_units.h"#include <wtf/StdLibExtras.h>namespace WebCore {using namespace HTMLNames;class StyleChange {public: explicit StyleChange(CSSStyleDeclaration*, const Position&); String cssStyle() const { return m_cssStyle; } bool applyBold() const { return m_applyBold; } bool applyItalic() const { return m_applyItalic; } bool applySubscript() const { return m_applySubscript; } bool applySuperscript() const { return m_applySuperscript; } bool applyFontColor() const { return m_applyFontColor.length() > 0; } bool applyFontFace() const { return m_applyFontFace.length() > 0; } bool applyFontSize() const { return m_applyFontSize.length() > 0; } String fontColor() { return m_applyFontColor; } String fontFace() { return m_applyFontFace; } String fontSize() { return m_applyFontSize; }private: void init(PassRefPtr<CSSStyleDeclaration>, const Position&); bool checkForLegacyHTMLStyleChange(const CSSProperty*); static bool currentlyHasStyle(const Position&, const CSSProperty*); String m_cssStyle; bool m_applyBold; bool m_applyItalic; bool m_applySubscript; bool m_applySuperscript; String m_applyFontColor; String m_applyFontFace; String m_applyFontSize;};StyleChange::StyleChange(CSSStyleDeclaration* style, const Position& position) : m_applyBold(false) , m_applyItalic(false) , m_applySubscript(false) , m_applySuperscript(false){ init(style, position);}void StyleChange::init(PassRefPtr<CSSStyleDeclaration> style, const Position& position){ Document* document = position.node() ? position.node()->document() : 0; if (!document || !document->frame()) return; bool useHTMLFormattingTags = !document->frame()->editor()->shouldStyleWithCSS(); RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable(); String styleText(""); bool addedDirection = false; CSSMutableStyleDeclaration::const_iterator end = mutableStyle->end(); for (CSSMutableStyleDeclaration::const_iterator it = mutableStyle->begin(); it != end; ++it) { const CSSProperty *property = &*it; // If position is empty or the position passed in already has the // style, just move on. if (position.isNotNull() && currentlyHasStyle(position, property)) continue; // Changing the whitespace style in a tab span would collapse the tab into a space. if (property->id() == CSSPropertyWhiteSpace && (isTabSpanTextNode(position.node()) || isTabSpanNode((position.node())))) continue; // If needed, figure out if this change is a legacy HTML style change. if (useHTMLFormattingTags && checkForLegacyHTMLStyleChange(property)) continue; if (property->id() == CSSPropertyDirection) { if (addedDirection) continue; addedDirection = true; } // Add this property if (property->id() == CSSPropertyWebkitTextDecorationsInEffect) { // we have to special-case text decorations // FIXME: Why? CSSProperty alteredProperty(CSSPropertyTextDecoration, property->value(), property->isImportant()); styleText += alteredProperty.cssText(); } else styleText += property->cssText(); if (!addedDirection && property->id() == CSSPropertyUnicodeBidi) { styleText += "direction: " + style->getPropertyValue(CSSPropertyDirection) + "; "; addedDirection = true; } } // Save the result for later m_cssStyle = styleText.stripWhiteSpace();}// This function is the mapping from CSS styles to styling tags (like font-weight: bold to <b>)bool StyleChange::checkForLegacyHTMLStyleChange(const CSSProperty* property){ if (!property || !property->value()) return false; String valueText(property->value()->cssText()); switch (property->id()) { case CSSPropertyFontWeight: if (equalIgnoringCase(valueText, "bold")) { m_applyBold = true; return true; } break; case CSSPropertyVerticalAlign: if (equalIgnoringCase(valueText, "sub")) { m_applySubscript = true; return true; } if (equalIgnoringCase(valueText, "super")) { m_applySuperscript = true; return true; } break; case CSSPropertyFontStyle: if (equalIgnoringCase(valueText, "italic") || equalIgnoringCase(valueText, "oblique")) { m_applyItalic = true; return true; } break; case CSSPropertyColor: { RGBA32 rgba = 0; CSSParser::parseColor(rgba, valueText); Color color(rgba); m_applyFontColor = color.name(); return true; } case CSSPropertyFontFamily: m_applyFontFace = valueText; return true; case CSSPropertyFontSize: if (property->value()->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) { CSSPrimitiveValue *value = static_cast<CSSPrimitiveValue *>(property->value()); if (value->primitiveType() < CSSPrimitiveValue::CSS_PX || value->primitiveType() > CSSPrimitiveValue::CSS_PC) // Size keyword or relative unit. return false; 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"; // Huge quirk in Microsft 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. Return false. return false; } else { // Can't make sense of the number. Put no font size. return true; } } return false;}bool StyleChange::currentlyHasStyle(const Position &pos, const CSSProperty *property){ ASSERT(pos.isNotNull()); RefPtr<CSSComputedStyleDeclaration> style = pos.computedStyle(); RefPtr<CSSValue> value = style->getPropertyCSSValue(property->id(), DoNotUpdateLayout); if (!value) return false; return equalIgnoringCase(value->cssText(), property->value()->cssText());}static String& styleSpanClassString(){ DEFINE_STATIC_LOCAL(String, styleSpanClassString, ((AppleStyleSpanClass))); return styleSpanClassString;}bool isStyleSpan(const Node *node){ if (!node || !node->isHTMLElement()) return false; const HTMLElement* elem = static_cast<const HTMLElement*>(node); return elem->hasLocalName(spanAttr) && elem->getAttribute(classAttr) == styleSpanClassString();}static bool isUnstyledStyleSpan(const Node* node){ if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) return false; const HTMLElement* elem = static_cast<const HTMLElement*>(node); CSSMutableStyleDeclaration* inlineStyleDecl = elem->inlineStyleDecl(); return (!inlineStyleDecl || inlineStyleDecl->length() == 0) && elem->getAttribute(classAttr) == styleSpanClassString();}static bool isSpanWithoutAttributesOrUnstyleStyleSpan(const Node* node){ if (!node || !node->isHTMLElement() || !node->hasTagName(spanTag)) return false; const HTMLElement* elem = static_cast<const HTMLElement*>(node); NamedAttrMap* attributes = elem->attributes(true); // readonly if (attributes->length() == 0) return true; return isUnstyledStyleSpan(node);}static bool isEmptyFontTag(const Node *node){ if (!node || !node->hasTagName(fontTag)) return false; const Element *elem = static_cast<const Element *>(node); NamedAttrMap *map = elem->attributes(true); // true for read-only return (!map || map->length() == 1) && elem->getAttribute(classAttr) == styleSpanClassString();}static PassRefPtr<Element> createFontElement(Document* document){ RefPtr<Element> fontNode = createHTMLElement(document, fontTag); fontNode->setAttribute(classAttr, styleSpanClassString()); return fontNode.release();}PassRefPtr<HTMLElement> createStyleSpanElement(Document* document){ RefPtr<HTMLElement> styleElement = createHTMLElement(document, spanTag); styleElement->setAttribute(classAttr, styleSpanClassString()); return styleElement.release();}ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, EditAction editingAction, EPropertyLevel propertyLevel) : CompositeEditCommand(document) , m_style(style->makeMutable()) , m_editingAction(editingAction) , m_propertyLevel(propertyLevel) , m_start(endingSelection().start().downstream()) , m_end(endingSelection().end().upstream()) , m_useEndingSelection(true) , m_styledInlineElement(0) , m_removeOnly(false){}ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, const Position& start, const Position& end, EditAction editingAction, EPropertyLevel propertyLevel) : CompositeEditCommand(document) , m_style(style->makeMutable()) , m_editingAction(editingAction) , m_propertyLevel(propertyLevel) , m_start(start) , m_end(end) , m_useEndingSelection(false) , m_styledInlineElement(0) , m_removeOnly(false){}ApplyStyleCommand::ApplyStyleCommand(PassRefPtr<Element> element, bool removeOnly, EditAction editingAction) : CompositeEditCommand(element->document())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -