Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/nsDOMCSSDeclaration.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
/* base class for DOM objects for element.style and cssStyleRule.style */
8
9
#include "nsDOMCSSDeclaration.h"
10
11
#include "mozilla/DeclarationBlock.h"
12
#include "mozilla/StyleSheetInlines.h"
13
#include "mozilla/css/Rule.h"
14
#include "mozilla/dom/CSS2PropertiesBinding.h"
15
#include "mozilla/dom/MutationEventBinding.h"
16
#include "nsCSSProps.h"
17
#include "nsCOMPtr.h"
18
#include "mozAutoDocUpdate.h"
19
#include "nsIURI.h"
20
#include "mozilla/dom/BindingUtils.h"
21
#include "nsQueryObject.h"
22
#include "mozilla/layers/ScrollLinkedEffectDetector.h"
23
24
using namespace mozilla;
25
26
0
nsDOMCSSDeclaration::~nsDOMCSSDeclaration() = default;
27
28
/* virtual */ JSObject*
29
nsDOMCSSDeclaration::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
30
0
{
31
0
  return dom::CSS2Properties_Binding::Wrap(aCx, this, aGivenProto);
32
0
}
33
34
NS_IMPL_QUERY_INTERFACE(nsDOMCSSDeclaration,
35
                        nsICSSDeclaration)
36
37
nsresult
38
nsDOMCSSDeclaration::GetPropertyValue(const nsCSSPropertyID aPropID,
39
                                      nsAString& aValue)
40
0
{
41
0
  MOZ_ASSERT(aPropID != eCSSProperty_UNKNOWN,
42
0
             "Should never pass eCSSProperty_UNKNOWN around");
43
0
44
0
  aValue.Truncate();
45
0
  if (DeclarationBlock* decl =
46
0
        GetOrCreateCSSDeclaration(eOperation_Read, nullptr)) {
47
0
    decl->GetPropertyValueByID(aPropID, aValue);
48
0
  }
49
0
  return NS_OK;
50
0
}
51
52
nsresult
53
nsDOMCSSDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
54
                                      const nsAString& aValue,
55
                                      nsIPrincipal* aSubjectPrincipal)
56
0
{
57
0
  switch (aPropID) {
58
0
    case eCSSProperty_background_position:
59
0
    case eCSSProperty_background_position_x:
60
0
    case eCSSProperty_background_position_y:
61
0
    case eCSSProperty_transform:
62
0
    case eCSSProperty_top:
63
0
    case eCSSProperty_left:
64
0
    case eCSSProperty_bottom:
65
0
    case eCSSProperty_right:
66
0
    case eCSSProperty_margin:
67
0
    case eCSSProperty_margin_top:
68
0
    case eCSSProperty_margin_left:
69
0
    case eCSSProperty_margin_bottom:
70
0
    case eCSSProperty_margin_right:
71
0
    case eCSSProperty_margin_inline_start:
72
0
    case eCSSProperty_margin_inline_end:
73
0
    case eCSSProperty_margin_block_start:
74
0
    case eCSSProperty_margin_block_end:
75
0
      mozilla::layers::ScrollLinkedEffectDetector::PositioningPropertyMutated();
76
0
      break;
77
0
    default:
78
0
      break;
79
0
  }
80
0
81
0
  if (aValue.IsEmpty()) {
82
0
    // If the new value of the property is an empty string we remove the
83
0
    // property.
84
0
    return RemovePropertyInternal(aPropID);
85
0
  }
86
0
87
0
  return ParsePropertyValue(aPropID, aValue, false, aSubjectPrincipal);
88
0
}
89
90
91
void
92
nsDOMCSSDeclaration::GetCssText(nsAString& aCssText)
93
0
{
94
0
  DeclarationBlock* decl = GetOrCreateCSSDeclaration(eOperation_Read, nullptr);
95
0
  aCssText.Truncate();
96
0
97
0
  if (decl) {
98
0
    decl->ToString(aCssText);
99
0
  }
100
0
}
101
102
void
103
nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText,
104
                                nsIPrincipal* aSubjectPrincipal,
105
                                ErrorResult& aRv)
106
0
{
107
0
  // We don't need to *do* anything with the old declaration, but we need
108
0
  // to ensure that it exists, or else SetCSSDeclaration may crash.
109
0
  RefPtr<DeclarationBlock> created;
110
0
  DeclarationBlock* olddecl =
111
0
    GetOrCreateCSSDeclaration(eOperation_Modify, getter_AddRefs(created));
112
0
  if (!olddecl) {
113
0
    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
114
0
    return;
115
0
  }
116
0
117
0
  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
118
0
  // Attribute setting code, which leads in turn to BeginUpdate.  We
119
0
  // need to start the update now so that the old rule doesn't get used
120
0
  // between when we mutate the declaration and when we set the new
121
0
  // rule (see stack in bug 209575).
122
0
  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
123
0
  DeclarationBlockMutationClosure closure = {};
124
0
  MutationClosureData closureData;
125
0
  GetPropertyChangeClosure(&closure, &closureData);
126
0
127
0
  ParsingEnvironment servoEnv =
128
0
    GetParsingEnvironment(aSubjectPrincipal);
129
0
  if (!servoEnv.mUrlExtraData) {
130
0
    if (created) {
131
0
      // In case we can't set a new declaration, but one was
132
0
      // created for the old one, we need to set the old declaration to
133
0
      // get right style attribute handling.
134
0
      SetCSSDeclaration(olddecl, &closureData);
135
0
    }
136
0
    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
137
0
    return;
138
0
  }
139
0
140
0
  // Need to special case closure calling here, since parsing css text
141
0
  // doesn't modify any existing declaration and that is why the callback isn't
142
0
  // called implicitly.
143
0
  if (closureData.mClosure) {
144
0
    closureData.mClosure(&closureData);
145
0
  }
146
0
147
0
  RefPtr<DeclarationBlock> newdecl =
148
0
    DeclarationBlock::FromCssText(aCssText, servoEnv.mUrlExtraData,
149
0
                                  servoEnv.mCompatMode, servoEnv.mLoader);
150
0
151
0
  aRv = SetCSSDeclaration(newdecl, &closureData);
152
0
}
153
154
uint32_t
155
nsDOMCSSDeclaration::Length()
156
0
{
157
0
  DeclarationBlock* decl = GetOrCreateCSSDeclaration(eOperation_Read, nullptr);
158
0
159
0
  if (decl) {
160
0
    return decl->Count();
161
0
  }
162
0
163
0
  return 0;
164
0
}
165
166
void
167
nsDOMCSSDeclaration::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName)
168
0
{
169
0
  DeclarationBlock* decl = GetOrCreateCSSDeclaration(eOperation_Read, nullptr);
170
0
  aFound = decl && decl->GetNthProperty(aIndex, aPropName);
171
0
}
172
173
NS_IMETHODIMP
174
nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
175
                                      nsAString& aReturn)
176
0
{
177
0
  aReturn.Truncate();
178
0
  if (DeclarationBlock* decl =
179
0
        GetOrCreateCSSDeclaration(eOperation_Read, nullptr)) {
180
0
    decl->GetPropertyValue(aPropertyName, aReturn);
181
0
  }
182
0
  return NS_OK;
183
0
}
184
185
void
186
nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName,
187
                                         nsAString& aPriority)
188
0
{
189
0
  DeclarationBlock* decl = GetOrCreateCSSDeclaration(eOperation_Read, nullptr);
190
0
191
0
  aPriority.Truncate();
192
0
  if (decl && decl->GetPropertyIsImportant(aPropertyName)) {
193
0
    aPriority.AssignLiteral("important");
194
0
  }
195
0
}
196
197
NS_IMETHODIMP
198
nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName,
199
                                 const nsAString& aValue,
200
                                 const nsAString& aPriority,
201
                                 nsIPrincipal* aSubjectPrincipal)
202
0
{
203
0
  if (aValue.IsEmpty()) {
204
0
    // If the new value of the property is an empty string we remove the
205
0
    // property.
206
0
    // XXX this ignores the priority string, should it?
207
0
    return RemovePropertyInternal(aPropertyName);
208
0
  }
209
0
210
0
  // In the common (and fast) cases we can use the property id
211
0
  nsCSSPropertyID propID = nsCSSProps::LookupProperty(aPropertyName);
212
0
  if (propID == eCSSProperty_UNKNOWN) {
213
0
    return NS_OK;
214
0
  }
215
0
216
0
  bool important;
217
0
  if (aPriority.IsEmpty()) {
218
0
    important = false;
219
0
  } else if (aPriority.EqualsLiteral("important")) {
220
0
    important = true;
221
0
  } else {
222
0
    // XXX silent failure?
223
0
    return NS_OK;
224
0
  }
225
0
226
0
  if (propID == eCSSPropertyExtra_variable) {
227
0
    return ParseCustomPropertyValue(aPropertyName, aValue, important,
228
0
                                    aSubjectPrincipal);
229
0
  }
230
0
  return ParsePropertyValue(propID, aValue, important, aSubjectPrincipal);
231
0
}
232
233
NS_IMETHODIMP
234
nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
235
                                    nsAString& aReturn)
236
0
{
237
0
  nsresult rv = GetPropertyValue(aPropertyName, aReturn);
238
0
  NS_ENSURE_SUCCESS(rv, rv);
239
0
  return RemovePropertyInternal(aPropertyName);
240
0
}
241
242
/* static */ nsDOMCSSDeclaration::ParsingEnvironment
243
nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule)
244
0
{
245
0
  StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
246
0
  if (!sheet) {
247
0
    return { nullptr, eCompatibility_FullStandards, nullptr };
248
0
  }
249
0
250
0
  if (nsIDocument* document = sheet->GetAssociatedDocument()) {
251
0
    return {
252
0
      sheet->URLData(),
253
0
      document->GetCompatibilityMode(),
254
0
      document->CSSLoader(),
255
0
    };
256
0
  }
257
0
258
0
  return {
259
0
    sheet->URLData(),
260
0
    eCompatibility_FullStandards,
261
0
    nullptr,
262
0
  };
263
0
}
264
265
template<typename Func>
266
nsresult
267
nsDOMCSSDeclaration::ModifyDeclaration(nsIPrincipal* aSubjectPrincipal,
268
                                       MutationClosureData* aClosureData,
269
                                       Func aFunc)
270
0
{
271
0
  RefPtr<DeclarationBlock> created;
272
0
  DeclarationBlock* olddecl =
273
0
    GetOrCreateCSSDeclaration(eOperation_Modify, getter_AddRefs(created));
274
0
  if (!olddecl) {
275
0
    return NS_ERROR_NOT_AVAILABLE;
276
0
  }
277
0
278
0
  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
279
0
  // Attribute setting code, which leads in turn to BeginUpdate.  We
280
0
  // need to start the update now so that the old rule doesn't get used
281
0
  // between when we mutate the declaration and when we set the new
282
0
  // rule (see stack in bug 209575).
283
0
  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
284
0
  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
285
0
286
0
  bool changed;
287
0
  ParsingEnvironment servoEnv =
288
0
    GetParsingEnvironment(aSubjectPrincipal);
289
0
  if (!servoEnv.mUrlExtraData) {
290
0
    if (created) {
291
0
      // In case we can't set a new declaration, but one was
292
0
      // created for the old one, we need to set the old declaration to
293
0
      // get right style attribute handling.
294
0
      SetCSSDeclaration(olddecl, aClosureData);
295
0
    }
296
0
    return NS_ERROR_NOT_AVAILABLE;
297
0
  }
298
0
299
0
  changed = aFunc(decl, servoEnv);
300
0
301
0
  if (!changed) {
302
0
    if (created) {
303
0
      // See comment above about setting old declaration.
304
0
      SetCSSDeclaration(olddecl, aClosureData);
305
0
    }
306
0
    // Parsing failed -- but we don't throw an exception for that.
307
0
    return NS_OK;
308
0
  }
309
0
310
0
  return SetCSSDeclaration(decl, aClosureData);
311
0
}
Unexecuted instantiation: Unified_cpp_layout_style3.cpp:nsresult nsDOMCSSDeclaration::ModifyDeclaration<nsDOMCSSDeclaration::ParsePropertyValue(nsCSSPropertyID, nsTSubstring<char16_t> const&, bool, nsIPrincipal*)::$_7>(nsIPrincipal*, mozilla::MutationClosureData*, nsDOMCSSDeclaration::ParsePropertyValue(nsCSSPropertyID, nsTSubstring<char16_t> const&, bool, nsIPrincipal*)::$_7)
Unexecuted instantiation: Unified_cpp_layout_style3.cpp:nsresult nsDOMCSSDeclaration::ModifyDeclaration<nsDOMCSSDeclaration::ParseCustomPropertyValue(nsTSubstring<char16_t> const&, nsTSubstring<char16_t> const&, bool, nsIPrincipal*)::$_8>(nsIPrincipal*, mozilla::MutationClosureData*, nsDOMCSSDeclaration::ParseCustomPropertyValue(nsTSubstring<char16_t> const&, nsTSubstring<char16_t> const&, bool, nsIPrincipal*)::$_8)
312
313
nsresult
314
nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
315
                                        const nsAString& aPropValue,
316
                                        bool aIsImportant,
317
                                        nsIPrincipal* aSubjectPrincipal)
318
0
{
319
0
  DeclarationBlockMutationClosure closure = {};
320
0
  MutationClosureData closureData;
321
0
  GetPropertyChangeClosure(&closure, &closureData);
322
0
323
0
  return ModifyDeclaration(
324
0
    aSubjectPrincipal,
325
0
    &closureData,
326
0
    [&](DeclarationBlock* decl, ParsingEnvironment& env) {
327
0
      NS_ConvertUTF16toUTF8 value(aPropValue);
328
0
      return Servo_DeclarationBlock_SetPropertyById(
329
0
        decl->Raw(), aPropID, &value, aIsImportant, env.mUrlExtraData,
330
0
        ParsingMode::Default, env.mCompatMode, env.mLoader, closure);
331
0
    });
332
0
}
333
334
nsresult
335
nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
336
                                              const nsAString& aPropValue,
337
                                              bool aIsImportant,
338
                                              nsIPrincipal* aSubjectPrincipal)
339
0
{
340
0
  MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
341
0
342
0
  DeclarationBlockMutationClosure closure = {};
343
0
  MutationClosureData closureData;
344
0
  GetPropertyChangeClosure(&closure, &closureData);
345
0
346
0
  return ModifyDeclaration(
347
0
    aSubjectPrincipal,
348
0
    &closureData,
349
0
    [&](DeclarationBlock* decl, ParsingEnvironment& env) {
350
0
      NS_ConvertUTF16toUTF8 property(aPropertyName);
351
0
      NS_ConvertUTF16toUTF8 value(aPropValue);
352
0
      return Servo_DeclarationBlock_SetProperty(
353
0
        decl->Raw(), &property, &value, aIsImportant, env.mUrlExtraData,
354
0
        ParsingMode::Default, env.mCompatMode, env.mLoader, closure);
355
0
    });
356
0
}
357
358
nsresult
359
nsDOMCSSDeclaration::RemovePropertyInternal(nsCSSPropertyID aPropID)
360
0
{
361
0
  DeclarationBlock* olddecl =
362
0
    GetOrCreateCSSDeclaration(eOperation_RemoveProperty, nullptr);
363
0
  if (!olddecl) {
364
0
    return NS_OK; // no decl, so nothing to remove
365
0
  }
366
0
367
0
  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
368
0
  // Attribute setting code, which leads in turn to BeginUpdate.  We
369
0
  // need to start the update now so that the old rule doesn't get used
370
0
  // between when we mutate the declaration and when we set the new
371
0
  // rule (see stack in bug 209575).
372
0
  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
373
0
374
0
  DeclarationBlockMutationClosure closure = {};
375
0
  MutationClosureData closureData;
376
0
  GetPropertyChangeClosure(&closure, &closureData);
377
0
378
0
  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
379
0
  if (!decl->RemovePropertyByID(aPropID, closure)) {
380
0
    return NS_OK;
381
0
  }
382
0
  return SetCSSDeclaration(decl, &closureData);
383
0
}
384
385
nsresult
386
nsDOMCSSDeclaration::RemovePropertyInternal(const nsAString& aPropertyName)
387
0
{
388
0
  DeclarationBlock* olddecl =
389
0
    GetOrCreateCSSDeclaration(eOperation_RemoveProperty, nullptr);
390
0
  if (!olddecl) {
391
0
    return NS_OK; // no decl, so nothing to remove
392
0
  }
393
0
394
0
  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
395
0
  // Attribute setting code, which leads in turn to BeginUpdate.  We
396
0
  // need to start the update now so that the old rule doesn't get used
397
0
  // between when we mutate the declaration and when we set the new
398
0
  // rule (see stack in bug 209575).
399
0
  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
400
0
401
0
  DeclarationBlockMutationClosure closure = {};
402
0
  MutationClosureData closureData;
403
0
  GetPropertyChangeClosure(&closure, &closureData);
404
0
405
0
  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
406
0
  if (!decl->RemoveProperty(aPropertyName, closure)) {
407
0
    return NS_OK;
408
0
  }
409
0
  return SetCSSDeclaration(decl, &closureData);
410
0
}