Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsStyledElement.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsStyledElement.h"
8
#include "mozAutoDocUpdate.h"
9
#include "nsGkAtoms.h"
10
#include "nsAttrValue.h"
11
#include "nsAttrValueInlines.h"
12
#include "mozilla/dom/ElementInlines.h"
13
#include "mozilla/dom/MutationEventBinding.h"
14
#include "mozilla/InternalMutationEvent.h"
15
#include "mozilla/StaticPrefs.h"
16
#include "nsDOMCSSDeclaration.h"
17
#include "nsDOMCSSAttrDeclaration.h"
18
#include "nsServiceManagerUtils.h"
19
#include "nsIDocument.h"
20
#include "mozilla/DeclarationBlock.h"
21
#include "mozilla/css/Loader.h"
22
#include "nsXULElement.h"
23
#include "nsContentUtils.h"
24
#include "nsStyleUtil.h"
25
26
using namespace mozilla;
27
using namespace mozilla::dom;
28
29
// Use the CC variant of this, even though this class does not define
30
// a new CC participant, to make QIing to the CC interfaces faster.
31
NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
32
                                                   nsStyledElementBase,
33
                                                   nsStyledElement)
34
35
//----------------------------------------------------------------------
36
// nsIContent methods
37
38
bool
39
nsStyledElement::ParseAttribute(int32_t aNamespaceID,
40
                                nsAtom* aAttribute,
41
                                const nsAString& aValue,
42
                                nsIPrincipal* aMaybeScriptedPrincipal,
43
                                nsAttrValue& aResult)
44
0
{
45
0
  if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
46
0
    ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, aResult, false);
47
0
    return true;
48
0
  }
49
0
50
0
  return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
51
0
                                             aMaybeScriptedPrincipal, aResult);
52
0
}
53
54
nsresult
55
nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
56
                               const nsAttrValueOrString* aValue, bool aNotify)
57
0
{
58
0
  if (aNamespaceID == kNameSpaceID_None) {
59
0
    if (aName == nsGkAtoms::style) {
60
0
      if (aValue) {
61
0
        SetMayHaveStyle();
62
0
      }
63
0
    }
64
0
  }
65
0
66
0
  return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
67
0
                                            aNotify);
68
0
}
69
70
void
71
nsStyledElement::InlineStyleDeclarationWillChange(MutationClosureData& aData)
72
0
{
73
0
  MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel() > 0,
74
0
             "Should be inside document update!");
75
0
  bool modification = false;
76
0
  if (MayHaveStyle()) {
77
0
    bool needsOldValue =
78
0
      !StaticPrefs::dom_mutation_events_cssom_disabled() &&
79
0
      nsContentUtils::HasMutationListeners(this,
80
0
                                           NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
81
0
                                           this);
82
0
83
0
    if (!needsOldValue) {
84
0
      CustomElementDefinition* definition = GetCustomElementDefinition();
85
0
      if (definition && definition->IsInObservedAttributeList(nsGkAtoms::style)) {
86
0
        needsOldValue = true;
87
0
      }
88
0
    }
89
0
90
0
    if (needsOldValue) {
91
0
      nsAutoString oldValueStr;
92
0
      modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
93
0
                             oldValueStr);
94
0
      if (modification) {
95
0
        aData.mOldValue.emplace();
96
0
        aData.mOldValue->SetTo(oldValueStr);
97
0
      }
98
0
    } else {
99
0
      modification = HasAttr(kNameSpaceID_None, nsGkAtoms::style);
100
0
    }
101
0
  }
102
0
103
0
  aData.mModType = modification ?
104
0
    static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION) :
105
0
    static_cast<uint8_t>(MutationEvent_Binding::ADDITION);
106
0
  nsNodeUtils::AttributeWillChange(this, kNameSpaceID_None,
107
0
                                   nsGkAtoms::style,
108
0
                                   aData.mModType, nullptr);
109
0
110
0
  //XXXsmaug In order to make attribute handling more consistent, consider to
111
0
  //         call BeforeSetAttr and pass kCallAfterSetAttr to
112
0
  //         SetAttrAndNotify in SetInlineStyleDeclaration.
113
0
  //         Handling of mozAutoDocUpdate may require changes in that case.
114
0
}
115
116
nsresult
117
nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock& aDeclaration,
118
                                           MutationClosureData& aData)
119
0
{
120
0
  MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel(),
121
0
             "Should be inside document update!");
122
0
123
0
  bool hasListeners =
124
0
    !StaticPrefs::dom_mutation_events_cssom_disabled() &&
125
0
    nsContentUtils::HasMutationListeners(this,
126
0
                                         NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
127
0
                                         this);
128
0
129
0
  nsAttrValue attrValue(do_AddRef(&aDeclaration), nullptr);
130
0
  SetMayHaveStyle();
131
0
132
0
  nsIDocument* document = GetComposedDoc();
133
0
  mozAutoDocUpdate updateBatch(document, true);
134
0
  return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
135
0
                          aData.mOldValue.isSome() ?
136
0
                            aData.mOldValue.ptr() : nullptr,
137
0
                          attrValue, nullptr, aData.mModType,
138
0
                          hasListeners, true, kDontCallAfterSetAttr,
139
0
                          document, updateBatch);
140
0
}
141
142
// ---------------------------------------------------------------
143
// Others and helpers
144
145
nsICSSDeclaration*
146
nsStyledElement::Style()
147
0
{
148
0
  Element::nsDOMSlots *slots = DOMSlots();
149
0
150
0
  if (!slots->mStyle) {
151
0
    // Just in case...
152
0
    ReparseStyleAttribute(true, false);
153
0
154
0
    slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
155
0
    SetMayHaveStyle();
156
0
  }
157
0
158
0
  return slots->mStyle;
159
0
}
160
161
nsresult
162
nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc, bool aForceIfAlreadyParsed)
163
0
{
164
0
  if (!MayHaveStyle()) {
165
0
    return NS_OK;
166
0
  }
167
0
  const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
168
0
  if (oldVal && (aForceIfAlreadyParsed || oldVal->Type() != nsAttrValue::eCSSDeclaration)) {
169
0
    nsAttrValue attrValue;
170
0
    nsAutoString stringValue;
171
0
    oldVal->ToString(stringValue);
172
0
    ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
173
0
    // Don't bother going through SetInlineStyleDeclaration; we don't
174
0
    // want to fire off mutation events or document notifications anyway
175
0
    bool oldValueSet;
176
0
    nsresult rv = mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue,
177
0
                                        &oldValueSet);
178
0
    NS_ENSURE_SUCCESS(rv, rv);
179
0
  }
180
0
181
0
  return NS_OK;
182
0
}
183
184
void
185
nsStyledElement::NodeInfoChanged(nsIDocument* aOldDoc)
186
0
{
187
0
  nsStyledElementBase::NodeInfoChanged(aOldDoc);
188
0
}
189
190
nsICSSDeclaration*
191
nsStyledElement::GetExistingStyle()
192
0
{
193
0
  Element::nsDOMSlots* slots = GetExistingDOMSlots();
194
0
  if (!slots) {
195
0
    return nullptr;
196
0
  }
197
0
198
0
  return slots->mStyle;
199
0
}
200
201
void
202
nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
203
                                     nsIPrincipal* aMaybeScriptedPrincipal,
204
                                     nsAttrValue& aResult,
205
                                     bool aForceInDataDoc)
206
0
{
207
0
  nsIDocument* doc = OwnerDoc();
208
0
  bool isNativeAnon = IsInNativeAnonymousSubtree();
209
0
210
0
  if (!isNativeAnon &&
211
0
      !nsStyleUtil::CSPAllowsInlineStyle(this, NodePrincipal(),
212
0
                                         aMaybeScriptedPrincipal,
213
0
                                         doc->GetDocumentURI(), 0, 0, aValue,
214
0
                                         nullptr))
215
0
    return;
216
0
217
0
  if (aForceInDataDoc ||
218
0
      !doc->IsLoadedAsData() ||
219
0
      GetExistingStyle() ||
220
0
      doc->IsStaticDocument()) {
221
0
    bool isCSS = true; // assume CSS until proven otherwise
222
0
223
0
    if (!isNativeAnon) {  // native anonymous content always assumes CSS
224
0
      nsAutoString styleType;
225
0
      doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
226
0
      if (!styleType.IsEmpty()) {
227
0
        static const char textCssStr[] = "text/css";
228
0
        isCSS = (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
229
0
      }
230
0
    }
231
0
232
0
    if (isCSS && aResult.ParseStyleAttribute(aValue, aMaybeScriptedPrincipal,
233
0
                                             this)) {
234
0
      return;
235
0
    }
236
0
  }
237
0
238
0
  aResult.SetTo(aValue);
239
0
}