1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsStyledElement.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,265 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsStyledElement.h" 1.11 +#include "nsGkAtoms.h" 1.12 +#include "nsAttrValue.h" 1.13 +#include "nsAttrValueInlines.h" 1.14 +#include "mozilla/dom/ElementInlines.h" 1.15 +#include "mozilla/InternalMutationEvent.h" 1.16 +#include "nsDOMCSSDeclaration.h" 1.17 +#include "nsDOMCSSAttrDeclaration.h" 1.18 +#include "nsServiceManagerUtils.h" 1.19 +#include "nsIDocument.h" 1.20 +#include "mozilla/css/StyleRule.h" 1.21 +#include "nsCSSParser.h" 1.22 +#include "mozilla/css/Loader.h" 1.23 +#include "nsIDOMMutationEvent.h" 1.24 +#include "nsXULElement.h" 1.25 +#include "nsContentUtils.h" 1.26 +#include "nsStyleUtil.h" 1.27 + 1.28 +using namespace mozilla; 1.29 +using namespace mozilla::dom; 1.30 + 1.31 +//---------------------------------------------------------------------- 1.32 +// nsIContent methods 1.33 + 1.34 +nsIAtom* 1.35 +nsStyledElementNotElementCSSInlineStyle::GetClassAttributeName() const 1.36 +{ 1.37 + return nsGkAtoms::_class; 1.38 +} 1.39 + 1.40 +nsIAtom* 1.41 +nsStyledElementNotElementCSSInlineStyle::GetIDAttributeName() const 1.42 +{ 1.43 + return nsGkAtoms::id; 1.44 +} 1.45 + 1.46 +nsIAtom* 1.47 +nsStyledElementNotElementCSSInlineStyle::DoGetID() const 1.48 +{ 1.49 + NS_ASSERTION(HasID(), "Unexpected call"); 1.50 + 1.51 + // The nullcheck here is needed because Element::UnsetAttr calls 1.52 + // out to various code between removing the attribute and we get a chance to 1.53 + // ClearHasID(). 1.54 + 1.55 + const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::id); 1.56 + 1.57 + return attr ? attr->GetAtomValue() : nullptr; 1.58 +} 1.59 + 1.60 +const nsAttrValue* 1.61 +nsStyledElementNotElementCSSInlineStyle::DoGetClasses() const 1.62 +{ 1.63 + NS_ASSERTION(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call"); 1.64 + return mAttrsAndChildren.GetAttr(nsGkAtoms::_class); 1.65 +} 1.66 + 1.67 +bool 1.68 +nsStyledElementNotElementCSSInlineStyle::ParseAttribute(int32_t aNamespaceID, 1.69 + nsIAtom* aAttribute, 1.70 + const nsAString& aValue, 1.71 + nsAttrValue& aResult) 1.72 +{ 1.73 + if (aNamespaceID == kNameSpaceID_None) { 1.74 + if (aAttribute == nsGkAtoms::style) { 1.75 + SetMayHaveStyle(); 1.76 + ParseStyleAttribute(aValue, aResult, false); 1.77 + return true; 1.78 + } 1.79 + if (aAttribute == nsGkAtoms::_class) { 1.80 + SetFlags(NODE_MAY_HAVE_CLASS); 1.81 + aResult.ParseAtomArray(aValue); 1.82 + return true; 1.83 + } 1.84 + if (aAttribute == nsGkAtoms::id) { 1.85 + // Store id as an atom. id="" means that the element has no id, 1.86 + // not that it has an emptystring as the id. 1.87 + RemoveFromIdTable(); 1.88 + if (aValue.IsEmpty()) { 1.89 + ClearHasID(); 1.90 + return false; 1.91 + } 1.92 + aResult.ParseAtom(aValue); 1.93 + SetHasID(); 1.94 + AddToIdTable(aResult.GetAtomValue()); 1.95 + return true; 1.96 + } 1.97 + } 1.98 + 1.99 + return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue, 1.100 + aResult); 1.101 +} 1.102 + 1.103 +nsresult 1.104 +nsStyledElementNotElementCSSInlineStyle::UnsetAttr(int32_t aNameSpaceID, 1.105 + nsIAtom* aAttribute, 1.106 + bool aNotify) 1.107 +{ 1.108 + nsAutoScriptBlocker scriptBlocker; 1.109 + if (aAttribute == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) { 1.110 + // Have to do this before clearing flag. See RemoveFromIdTable 1.111 + RemoveFromIdTable(); 1.112 + } 1.113 + 1.114 + return Element::UnsetAttr(aNameSpaceID, aAttribute, aNotify); 1.115 +} 1.116 + 1.117 +nsresult 1.118 +nsStyledElementNotElementCSSInlineStyle::AfterSetAttr(int32_t aNamespaceID, 1.119 + nsIAtom* aAttribute, 1.120 + const nsAttrValue* aValue, 1.121 + bool aNotify) 1.122 +{ 1.123 + if (aNamespaceID == kNameSpaceID_None && !aValue && 1.124 + aAttribute == nsGkAtoms::id) { 1.125 + // The id has been removed when calling UnsetAttr but we kept it because 1.126 + // the id is used for some layout stuff between UnsetAttr and AfterSetAttr. 1.127 + // Now. the id is really removed so it would not be safe to keep this flag. 1.128 + ClearHasID(); 1.129 + } 1.130 + 1.131 + return Element::AfterSetAttr(aNamespaceID, aAttribute, aValue, aNotify); 1.132 +} 1.133 + 1.134 +nsresult 1.135 +nsStyledElementNotElementCSSInlineStyle::SetInlineStyleRule(css::StyleRule* aStyleRule, 1.136 + const nsAString* aSerialized, 1.137 + bool aNotify) 1.138 +{ 1.139 + SetMayHaveStyle(); 1.140 + bool modification = false; 1.141 + nsAttrValue oldValue; 1.142 + 1.143 + bool hasListeners = aNotify && 1.144 + nsContentUtils::HasMutationListeners(this, 1.145 + NS_EVENT_BITS_MUTATION_ATTRMODIFIED, 1.146 + this); 1.147 + 1.148 + // There's no point in comparing the stylerule pointers since we're always 1.149 + // getting a new stylerule here. And we can't compare the stringvalues of 1.150 + // the old and the new rules since both will point to the same declaration 1.151 + // and thus will be the same. 1.152 + if (hasListeners) { 1.153 + // save the old attribute so we can set up the mutation event properly 1.154 + // XXXbz if the old rule points to the same declaration as the new one, 1.155 + // this is getting the new attr value, not the old one.... 1.156 + nsAutoString oldValueStr; 1.157 + modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style, 1.158 + oldValueStr); 1.159 + if (modification) { 1.160 + oldValue.SetTo(oldValueStr); 1.161 + } 1.162 + } 1.163 + else if (aNotify && IsInDoc()) { 1.164 + modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style); 1.165 + } 1.166 + 1.167 + nsAttrValue attrValue(aStyleRule, aSerialized); 1.168 + 1.169 + // XXXbz do we ever end up with ADDITION here? I doubt it. 1.170 + uint8_t modType = modification ? 1.171 + static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) : 1.172 + static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION); 1.173 + 1.174 + return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr, 1.175 + oldValue, attrValue, modType, hasListeners, 1.176 + aNotify, kDontCallAfterSetAttr); 1.177 +} 1.178 + 1.179 +css::StyleRule* 1.180 +nsStyledElementNotElementCSSInlineStyle::GetInlineStyleRule() 1.181 +{ 1.182 + if (!MayHaveStyle()) { 1.183 + return nullptr; 1.184 + } 1.185 + const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style); 1.186 + 1.187 + if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) { 1.188 + return attrVal->GetCSSStyleRuleValue(); 1.189 + } 1.190 + 1.191 + return nullptr; 1.192 +} 1.193 + 1.194 +// --------------------------------------------------------------- 1.195 +// Others and helpers 1.196 + 1.197 +nsICSSDeclaration* 1.198 +nsStyledElementNotElementCSSInlineStyle::Style() 1.199 +{ 1.200 + Element::nsDOMSlots *slots = DOMSlots(); 1.201 + 1.202 + if (!slots->mStyle) { 1.203 + // Just in case... 1.204 + ReparseStyleAttribute(true); 1.205 + 1.206 + slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false); 1.207 + SetMayHaveStyle(); 1.208 + } 1.209 + 1.210 + return slots->mStyle; 1.211 +} 1.212 + 1.213 +nsresult 1.214 +nsStyledElementNotElementCSSInlineStyle::ReparseStyleAttribute(bool aForceInDataDoc) 1.215 +{ 1.216 + if (!MayHaveStyle()) { 1.217 + return NS_OK; 1.218 + } 1.219 + const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style); 1.220 + 1.221 + if (oldVal && oldVal->Type() != nsAttrValue::eCSSStyleRule) { 1.222 + nsAttrValue attrValue; 1.223 + nsAutoString stringValue; 1.224 + oldVal->ToString(stringValue); 1.225 + ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc); 1.226 + // Don't bother going through SetInlineStyleRule, we don't want to fire off 1.227 + // mutation events or document notifications anyway 1.228 + nsresult rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, attrValue); 1.229 + NS_ENSURE_SUCCESS(rv, rv); 1.230 + } 1.231 + 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +void 1.236 +nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aValue, 1.237 + nsAttrValue& aResult, 1.238 + bool aForceInDataDoc) 1.239 +{ 1.240 + nsIDocument* doc = OwnerDoc(); 1.241 + 1.242 + if (!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(), 1.243 + doc->GetDocumentURI(), 0, aValue, 1.244 + nullptr)) 1.245 + return; 1.246 + 1.247 + if (aForceInDataDoc || 1.248 + !doc->IsLoadedAsData() || 1.249 + doc->IsStaticDocument()) { 1.250 + bool isCSS = true; // assume CSS until proven otherwise 1.251 + 1.252 + if (!IsInNativeAnonymousSubtree()) { // native anonymous content 1.253 + // always assumes CSS 1.254 + nsAutoString styleType; 1.255 + doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType); 1.256 + if (!styleType.IsEmpty()) { 1.257 + static const char textCssStr[] = "text/css"; 1.258 + isCSS = (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1)); 1.259 + } 1.260 + } 1.261 + 1.262 + if (isCSS && aResult.ParseStyleAttribute(aValue, this)) { 1.263 + return; 1.264 + } 1.265 + } 1.266 + 1.267 + aResult.SetTo(aValue); 1.268 +}