forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "nsStyledElement.h"
 | |
| #include "mozAutoDocUpdate.h"
 | |
| #include "nsGkAtoms.h"
 | |
| #include "nsAttrValue.h"
 | |
| #include "nsAttrValueInlines.h"
 | |
| #include "mozilla/dom/CustomElementRegistry.h"
 | |
| #include "mozilla/dom/ElementInlines.h"
 | |
| #include "mozilla/dom/MutationEventBinding.h"
 | |
| #include "mozilla/dom/MutationObservers.h"
 | |
| #include "mozilla/InternalMutationEvent.h"
 | |
| #include "mozilla/StaticPrefs_dom.h"
 | |
| #include "nsDOMCSSDeclaration.h"
 | |
| #include "nsDOMCSSAttrDeclaration.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "mozilla/dom/Document.h"
 | |
| #include "mozilla/DeclarationBlock.h"
 | |
| #include "mozilla/css/Loader.h"
 | |
| #include "nsXULElement.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsStyleUtil.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| // Use the CC variant of this, even though this class does not define
 | |
| // a new CC participant, to make QIing to the CC interfaces faster.
 | |
| NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
 | |
|                                                    nsStyledElementBase,
 | |
|                                                    nsStyledElement)
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // nsIContent methods
 | |
| 
 | |
| bool nsStyledElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
 | |
|                                      const nsAString& aValue,
 | |
|                                      nsIPrincipal* aMaybeScriptedPrincipal,
 | |
|                                      nsAttrValue& aResult) {
 | |
|   if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
 | |
|     ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, aResult, false);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
 | |
|                                              aMaybeScriptedPrincipal, aResult);
 | |
| }
 | |
| 
 | |
| nsresult nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
 | |
|                                         const nsAttrValueOrString* aValue,
 | |
|                                         bool aNotify) {
 | |
|   if (aNamespaceID == kNameSpaceID_None) {
 | |
|     if (aName == nsGkAtoms::style) {
 | |
|       if (aValue) {
 | |
|         SetMayHaveStyle();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
 | |
|                                             aNotify);
 | |
| }
 | |
| 
 | |
| void nsStyledElement::InlineStyleDeclarationWillChange(
 | |
|     MutationClosureData& aData) {
 | |
|   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
 | |
|   MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel() > 0,
 | |
|              "Should be inside document update!");
 | |
|   bool modification = false;
 | |
|   if (MayHaveStyle()) {
 | |
|     bool needsOldValue = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
 | |
|                          nsContentUtils::HasMutationListeners(
 | |
|                              this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
 | |
| 
 | |
|     if (!needsOldValue) {
 | |
|       CustomElementDefinition* definition = GetCustomElementDefinition();
 | |
|       if (definition &&
 | |
|           definition->IsInObservedAttributeList(nsGkAtoms::style)) {
 | |
|         needsOldValue = true;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (needsOldValue) {
 | |
|       nsAutoString oldValueStr;
 | |
|       modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style, oldValueStr);
 | |
|       if (modification) {
 | |
|         aData.mOldValue.emplace();
 | |
|         aData.mOldValue->SetTo(oldValueStr);
 | |
|       }
 | |
|     } else {
 | |
|       modification = HasAttr(kNameSpaceID_None, nsGkAtoms::style);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   aData.mModType =
 | |
|       modification ? static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION)
 | |
|                    : static_cast<uint8_t>(MutationEvent_Binding::ADDITION);
 | |
|   MutationObservers::NotifyAttributeWillChange(
 | |
|       this, kNameSpaceID_None, nsGkAtoms::style, aData.mModType);
 | |
| 
 | |
|   // XXXsmaug In order to make attribute handling more consistent, consider to
 | |
|   //         call BeforeSetAttr and pass kCallAfterSetAttr to
 | |
|   //         SetAttrAndNotify in SetInlineStyleDeclaration.
 | |
|   //         Handling of mozAutoDocUpdate may require changes in that case.
 | |
| }
 | |
| 
 | |
| nsresult nsStyledElement::SetInlineStyleDeclaration(
 | |
|     DeclarationBlock& aDeclaration, MutationClosureData& aData) {
 | |
|   MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel(),
 | |
|              "Should be inside document update!");
 | |
| 
 | |
|   bool hasListeners = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
 | |
|                       nsContentUtils::HasMutationListeners(
 | |
|                           this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
 | |
| 
 | |
|   nsAttrValue attrValue(do_AddRef(&aDeclaration), nullptr);
 | |
|   SetMayHaveStyle();
 | |
| 
 | |
|   Document* document = GetComposedDoc();
 | |
|   mozAutoDocUpdate updateBatch(document, true);
 | |
|   return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
 | |
|                           aData.mOldValue.ptrOr(nullptr), attrValue, nullptr,
 | |
|                           aData.mModType, hasListeners, true,
 | |
|                           kDontCallAfterSetAttr, document, updateBatch);
 | |
| }
 | |
| 
 | |
| // ---------------------------------------------------------------
 | |
| // Others and helpers
 | |
| 
 | |
| nsICSSDeclaration* nsStyledElement::Style() {
 | |
|   Element::nsDOMSlots* slots = DOMSlots();
 | |
| 
 | |
|   if (!slots->mStyle) {
 | |
|     // Just in case...
 | |
|     ReparseStyleAttribute(/* aForceInDataDoc */ true);
 | |
| 
 | |
|     slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
 | |
|     SetMayHaveStyle();
 | |
|   }
 | |
| 
 | |
|   return slots->mStyle;
 | |
| }
 | |
| 
 | |
| nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) {
 | |
|   if (!MayHaveStyle()) {
 | |
|     return NS_OK;
 | |
|   }
 | |
|   const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
 | |
|   if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
 | |
|     nsAttrValue attrValue;
 | |
|     nsAutoString stringValue;
 | |
|     oldVal->ToString(stringValue);
 | |
|     ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
 | |
|     // Don't bother going through SetInlineStyleDeclaration; we don't
 | |
|     // want to fire off mutation events or document notifications anyway
 | |
|     bool oldValueSet;
 | |
|     nsresult rv =
 | |
|         mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsICSSDeclaration* nsStyledElement::GetExistingStyle() {
 | |
|   Element::nsDOMSlots* slots = GetExistingDOMSlots();
 | |
|   if (!slots) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   return slots->mStyle;
 | |
| }
 | |
| 
 | |
| void nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
 | |
|                                           nsIPrincipal* aMaybeScriptedPrincipal,
 | |
|                                           nsAttrValue& aResult,
 | |
|                                           bool aForceInDataDoc) {
 | |
|   Document* doc = OwnerDoc();
 | |
|   bool isNativeAnon = IsInNativeAnonymousSubtree();
 | |
| 
 | |
|   if (!isNativeAnon &&
 | |
|       !nsStyleUtil::CSPAllowsInlineStyle(this, doc, aMaybeScriptedPrincipal, 0,
 | |
|                                          0, aValue, nullptr))
 | |
|     return;
 | |
| 
 | |
|   if (aForceInDataDoc || !doc->IsLoadedAsData() || GetExistingStyle() ||
 | |
|       doc->IsStaticDocument()) {
 | |
|     bool isCSS = true;  // assume CSS until proven otherwise
 | |
| 
 | |
|     if (!isNativeAnon) {  // native anonymous content always assumes CSS
 | |
|       nsAutoString styleType;
 | |
|       doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
 | |
|       if (!styleType.IsEmpty()) {
 | |
|         static const char textCssStr[] = "text/css";
 | |
|         isCSS =
 | |
|             (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (isCSS &&
 | |
|         aResult.ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, this)) {
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   aResult.SetTo(aValue);
 | |
| }
 | 
