Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/nsComputedDOMStyle.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
/* DOM object returned from element.getComputedStyle() */
8
9
#include "nsComputedDOMStyle.h"
10
11
#include "mozilla/ArrayUtils.h"
12
#include "mozilla/FloatingPoint.h"
13
#include "mozilla/FontPropertyTypes.h"
14
#include "mozilla/Preferences.h"
15
#include "mozilla/StaticPtr.h"
16
17
#include "nsError.h"
18
#include "nsIFrame.h"
19
#include "nsIFrameInlines.h"
20
#include "mozilla/ComputedStyle.h"
21
#include "nsIScrollableFrame.h"
22
#include "nsContentUtils.h"
23
#include "nsIContent.h"
24
#include "nsStyleConsts.h"
25
26
#include "nsDOMCSSRect.h"
27
#include "nsDOMCSSRGBColor.h"
28
#include "nsDOMCSSValueList.h"
29
#include "nsFlexContainerFrame.h"
30
#include "nsGridContainerFrame.h"
31
#include "nsGkAtoms.h"
32
#include "mozilla/ReflowInput.h"
33
#include "nsStyleUtil.h"
34
#include "nsStyleStructInlines.h"
35
#include "nsROCSSPrimitiveValue.h"
36
37
#include "nsPresContext.h"
38
#include "nsIDocument.h"
39
40
#include "nsCSSProps.h"
41
#include "nsCSSPseudoElements.h"
42
#include "mozilla/EffectSet.h"
43
#include "mozilla/IntegerRange.h"
44
#include "mozilla/ServoStyleSet.h"
45
#include "mozilla/RestyleManager.h"
46
#include "imgIRequest.h"
47
#include "nsLayoutUtils.h"
48
#include "nsCSSKeywords.h"
49
#include "nsStyleCoord.h"
50
#include "nsDisplayList.h"
51
#include "nsDOMCSSDeclaration.h"
52
#include "nsStyleTransformMatrix.h"
53
#include "mozilla/dom/Element.h"
54
#include "mozilla/dom/ElementInlines.h"
55
#include "prtime.h"
56
#include "nsWrapperCacheInlines.h"
57
#include "mozilla/AppUnits.h"
58
#include <algorithm>
59
#include "mozilla/ComputedStyleInlines.h"
60
61
using namespace mozilla;
62
using namespace mozilla::dom;
63
64
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
65
#define DEBUG_ComputedDOMStyle
66
#endif
67
68
/*
69
 * This is the implementation of the readonly CSSStyleDeclaration that is
70
 * returned by the getComputedStyle() function.
71
 */
72
73
already_AddRefed<nsComputedDOMStyle>
74
NS_NewComputedDOMStyle(dom::Element* aElement,
75
                       const nsAString& aPseudoElt,
76
                       nsIDocument* aDocument,
77
                       nsComputedDOMStyle::StyleType aStyleType)
78
0
{
79
0
  RefPtr<nsComputedDOMStyle> computedStyle =
80
0
    new nsComputedDOMStyle(aElement, aPseudoElt, aDocument, aStyleType);
81
0
  return computedStyle.forget();
82
0
}
83
84
static nsDOMCSSValueList*
85
GetROCSSValueList(bool aCommaDelimited)
86
0
{
87
0
  return new nsDOMCSSValueList(aCommaDelimited, true);
88
0
}
89
90
template<typename T>
91
already_AddRefed<CSSValue>
92
GetBackgroundList(T nsStyleImageLayers::Layer::* aMember,
93
                  uint32_t nsStyleImageLayers::* aCount,
94
                  const nsStyleImageLayers& aLayers,
95
                  const nsCSSKTableEntry aTable[])
96
{
97
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
98
99
  for (uint32_t i = 0, i_end = aLayers.*aCount; i < i_end; ++i) {
100
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
101
    val->SetIdent(nsCSSProps::ValueToKeywordEnum(aLayers.mLayers[i].*aMember, aTable));
102
    valueList->AppendCSSValue(val.forget());
103
  }
104
105
  return valueList.forget();
106
}
107
108
109
// Whether aDocument needs to restyle for aElement
110
static bool
111
DocumentNeedsRestyle(
112
  const nsIDocument* aDocument,
113
  Element* aElement,
114
  nsAtom* aPseudo)
115
0
{
116
0
  nsIPresShell* shell = aDocument->GetShell();
117
0
  if (!shell) {
118
0
    return true;
119
0
  }
120
0
121
0
  nsPresContext* presContext = shell->GetPresContext();
122
0
  MOZ_ASSERT(presContext);
123
0
124
0
  // Unfortunately we don't know if the sheet change affects mElement or not, so
125
0
  // just assume it will and that we need to flush normally.
126
0
  ServoStyleSet* styleSet = shell->StyleSet();
127
0
  if (styleSet->StyleSheetsHaveChanged()) {
128
0
    return true;
129
0
  }
130
0
131
0
  // Pending media query updates can definitely change style on the element. For
132
0
  // example, if you change the zoom factor and then call getComputedStyle, you
133
0
  // should be able to observe the style with the new media queries.
134
0
  //
135
0
  // TODO(emilio): Does this need to also check the user font set? (it affects
136
0
  // ch / ex units).
137
0
  if (presContext->HasPendingMediaQueryUpdates()) {
138
0
    // So gotta flush.
139
0
    return true;
140
0
  }
141
0
142
0
  // If the pseudo-element is animating, make sure to flush.
143
0
  if (aElement->MayHaveAnimations() && aPseudo) {
144
0
    if (aPseudo == nsCSSPseudoElements::before()) {
145
0
      if (EffectSet::GetEffectSet(aElement, CSSPseudoElementType::before)) {
146
0
        return true;
147
0
      }
148
0
    } else if (aPseudo == nsCSSPseudoElements::after()) {
149
0
      if (EffectSet::GetEffectSet(aElement, CSSPseudoElementType::after)) {
150
0
        return true;
151
0
      }
152
0
    }
153
0
  }
154
0
155
0
  // For Servo, we need to process the restyle-hint-invalidations first, to
156
0
  // expand LaterSiblings hint, so that we can look whether ancestors need
157
0
  // restyling.
158
0
  RestyleManager* restyleManager = presContext->RestyleManager();
159
0
  restyleManager->ProcessAllPendingAttributeAndStateInvalidations();
160
0
161
0
  if (!presContext->EffectCompositor()->HasPendingStyleUpdates() &&
162
0
      !aDocument->GetServoRestyleRoot()) {
163
0
    return false;
164
0
  }
165
0
166
0
  // Then if there is a restyle root, we check if the root is an ancestor of
167
0
  // this content. If it is not, then we don't need to restyle immediately.
168
0
  // Note this is different from Gecko: we only check if any ancestor needs
169
0
  // to restyle _itself_, not descendants, since dirty descendants can be
170
0
  // another subtree.
171
0
  return restyleManager->HasPendingRestyleAncestor(aElement);
172
0
}
173
174
/**
175
 * An object that represents the ordered set of properties that are exposed on
176
 * an nsComputedDOMStyle object and how their computed values can be obtained.
177
 */
178
struct ComputedStyleMap
179
{
180
  friend class nsComputedDOMStyle;
181
182
  struct Entry
183
  {
184
    // Create a pointer-to-member-function type.
185
    typedef already_AddRefed<CSSValue> (nsComputedDOMStyle::*ComputeMethod)();
186
187
    nsCSSPropertyID mProperty;
188
    ComputeMethod mGetter;
189
190
    bool IsLayoutFlushNeeded() const
191
0
    {
192
0
      return nsCSSProps::PropHasFlags(mProperty,
193
0
                                      CSSPropFlags::GetCSNeedsLayoutFlush);
194
0
    }
195
196
    bool IsEnabled() const
197
0
    {
198
0
      return nsCSSProps::IsEnabled(mProperty, CSSEnabledState::eForAllContent);
199
0
    }
200
  };
201
202
  // This generated file includes definition of kEntries which is typed
203
  // Entry[] and used below, so this #include has to be put here.
204
#include "nsComputedDOMStyleGenerated.cpp"
205
206
  /**
207
   * Returns the number of properties that should be exposed on an
208
   * nsComputedDOMStyle, ecxluding any disabled properties.
209
   */
210
  uint32_t Length()
211
0
  {
212
0
    Update();
213
0
    return mExposedPropertyCount;
214
0
  }
215
216
  /**
217
   * Returns the property at the given index in the list of properties
218
   * that should be exposed on an nsComputedDOMStyle, excluding any
219
   * disabled properties.
220
   */
221
  nsCSSPropertyID PropertyAt(uint32_t aIndex)
222
0
  {
223
0
    Update();
224
0
    return kEntries[EntryIndex(aIndex)].mProperty;
225
0
  }
226
227
  /**
228
   * Searches for and returns the computed style map entry for the given
229
   * property, or nullptr if the property is not exposed on nsComputedDOMStyle
230
   * or is currently disabled.
231
   */
232
  const Entry* FindEntryForProperty(nsCSSPropertyID aPropID)
233
0
  {
234
0
    Update();
235
0
    for (uint32_t i = 0; i < mExposedPropertyCount; i++) {
236
0
      const Entry* entry = &kEntries[EntryIndex(i)];
237
0
      if (entry->mProperty == aPropID) {
238
0
        return entry;
239
0
      }
240
0
    }
241
0
    return nullptr;
242
0
  }
243
244
  /**
245
   * Records that mIndexMap needs updating, due to prefs changing that could
246
   * affect the set of properties exposed on an nsComputedDOMStyle.
247
   */
248
0
  void MarkDirty() { mExposedPropertyCount = 0; }
249
250
  // The member variables are public so that we can use an initializer in
251
  // nsComputedDOMStyle::GetComputedStyleMap.  Use the member functions
252
  // above to get information from this object.
253
254
  /**
255
   * The number of properties that should be exposed on an nsComputedDOMStyle.
256
   * This will be less than eComputedStyleProperty_COUNT if some property
257
   * prefs are disabled.  A value of 0 indicates that it and mIndexMap are out
258
   * of date.
259
   */
260
  uint32_t mExposedPropertyCount;
261
262
  /**
263
   * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
264
   */
265
  uint32_t mIndexMap[ArrayLength(kEntries)];
266
267
private:
268
  /**
269
   * Returns whether mExposedPropertyCount and mIndexMap are out of date.
270
   */
271
0
  bool IsDirty() { return mExposedPropertyCount == 0; }
272
273
  /**
274
   * Updates mExposedPropertyCount and mIndexMap to take into account properties
275
   * whose prefs are currently disabled.
276
   */
277
  void Update();
278
279
  /**
280
   * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
281
   */
282
  uint32_t EntryIndex(uint32_t aIndex) const
283
0
  {
284
0
    MOZ_ASSERT(aIndex < mExposedPropertyCount);
285
0
    return mIndexMap[aIndex];
286
0
  }
287
};
288
289
constexpr ComputedStyleMap::Entry
290
ComputedStyleMap::kEntries[ArrayLength(kEntries)];
291
292
void
293
ComputedStyleMap::Update()
294
0
{
295
0
  if (!IsDirty()) {
296
0
    return;
297
0
  }
298
0
299
0
  uint32_t index = 0;
300
0
  for (uint32_t i = 0; i < ArrayLength(kEntries); i++) {
301
0
    if (kEntries[i].IsEnabled()) {
302
0
      mIndexMap[index++] = i;
303
0
    }
304
0
  }
305
0
  mExposedPropertyCount = index;
306
0
}
307
308
nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
309
                                       const nsAString& aPseudoElt,
310
                                       nsIDocument* aDocument,
311
                                       StyleType aStyleType)
312
  : mDocumentWeak(nullptr)
313
  , mOuterFrame(nullptr)
314
  , mInnerFrame(nullptr)
315
  , mPresShell(nullptr)
316
  , mStyleType(aStyleType)
317
  , mComputedStyleGeneration(0)
318
  , mExposeVisitedStyle(false)
319
  , mResolvedComputedStyle(false)
320
#ifdef DEBUG
321
  , mFlushedPendingReflows(false)
322
#endif
323
0
{
324
0
  MOZ_ASSERT(aElement);
325
0
  MOZ_ASSERT(aDocument);
326
0
  // TODO(emilio, bug 548397, https://github.com/w3c/csswg-drafts/issues/2403):
327
0
  // Should use aElement->OwnerDoc() instead.
328
0
  mDocumentWeak = do_GetWeakReference(aDocument);
329
0
  mElement = aElement;
330
0
  mPseudo = nsCSSPseudoElements::GetPseudoAtom(aPseudoElt);
331
0
}
332
333
nsComputedDOMStyle::~nsComputedDOMStyle()
334
0
{
335
0
  MOZ_ASSERT(!mResolvedComputedStyle,
336
0
             "Should have called ClearComputedStyle() during last release.");
337
0
}
338
339
NS_IMPL_CYCLE_COLLECTION_CLASS(nsComputedDOMStyle)
340
341
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle)
342
0
  tmp->ClearComputedStyle();  // remove observer before clearing mElement
343
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement)
344
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
345
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
346
347
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle)
348
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
349
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
350
351
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsComputedDOMStyle)
352
353
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
354
0
  return tmp->HasKnownLiveWrapper();
355
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
356
357
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
358
0
  return tmp->HasKnownLiveWrapper();
359
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
360
361
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
362
0
  return tmp->HasKnownLiveWrapper();
363
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
364
365
// QueryInterface implementation for nsComputedDOMStyle
366
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle)
367
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
368
0
  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
369
0
NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
370
371
372
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
373
NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
374
  nsComputedDOMStyle, ClearComputedStyle())
375
376
nsresult
377
nsComputedDOMStyle::GetPropertyValue(const nsCSSPropertyID aPropID,
378
                                     nsAString& aValue)
379
0
{
380
0
  // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
381
0
  // perf ever becomes an issue here (doubtful), we can look into changing
382
0
  // this.
383
0
  return GetPropertyValue(
384
0
    NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
385
0
    aValue);
386
0
}
387
388
nsresult
389
nsComputedDOMStyle::SetPropertyValue(const nsCSSPropertyID aPropID,
390
                                     const nsAString& aValue,
391
                                     nsIPrincipal* aSubjectPrincipal)
392
0
{
393
0
  return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
394
0
}
395
396
void
397
nsComputedDOMStyle::GetCssText(nsAString& aCssText)
398
0
{
399
0
  aCssText.Truncate();
400
0
}
401
402
void
403
nsComputedDOMStyle::SetCssText(const nsAString& aCssText,
404
                               nsIPrincipal* aSubjectPrincipal,
405
                               ErrorResult& aRv)
406
0
{
407
0
  aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
408
0
}
409
410
uint32_t
411
nsComputedDOMStyle::Length()
412
0
{
413
0
  // Make sure we have up to date style so that we can include custom
414
0
  // properties.
415
0
  UpdateCurrentStyleSources(false);
416
0
  if (!mComputedStyle) {
417
0
    return 0;
418
0
  }
419
0
420
0
  uint32_t length =
421
0
    GetComputedStyleMap()->Length() +
422
0
    Servo_GetCustomPropertiesCount(mComputedStyle);
423
0
424
0
  ClearCurrentStyleSources();
425
0
426
0
  return length;
427
0
}
428
429
css::Rule*
430
nsComputedDOMStyle::GetParentRule()
431
0
{
432
0
  return nullptr;
433
0
}
434
435
NS_IMETHODIMP
436
nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
437
                                     nsAString& aReturn)
438
0
{
439
0
  aReturn.Truncate();
440
0
441
0
  nsCSSPropertyID prop = nsCSSProps::LookupProperty(aPropertyName);
442
0
443
0
  const ComputedStyleMap::Entry* entry = nullptr;
444
0
  if (prop != eCSSPropertyExtra_variable) {
445
0
    entry = GetComputedStyleMap()->FindEntryForProperty(prop);
446
0
    if (!entry) {
447
0
      return NS_OK;
448
0
    }
449
0
  }
450
0
451
0
  const bool layoutFlushIsNeeded = entry && entry->IsLayoutFlushNeeded();
452
0
  UpdateCurrentStyleSources(layoutFlushIsNeeded);
453
0
  if (!mComputedStyle) {
454
0
    return NS_OK;
455
0
  }
456
0
457
0
  auto cleanup = mozilla::MakeScopeExit([&] {
458
0
    ClearCurrentStyleSources();
459
0
  });
460
0
461
0
  if (!entry) {
462
0
    MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
463
0
    const nsAString& name =
464
0
      Substring(aPropertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
465
0
    Servo_GetCustomPropertyValue(mComputedStyle, &name, &aReturn);
466
0
    return NS_OK;
467
0
  }
468
0
469
0
  if (nsCSSProps::PropHasFlags(prop, CSSPropFlags::IsLogical)) {
470
0
    MOZ_ASSERT(entry);
471
0
    MOZ_ASSERT(entry->mGetter == &nsComputedDOMStyle::DummyGetter);
472
0
473
0
    prop = Servo_ResolveLogicalProperty(prop, mComputedStyle);
474
0
    entry = GetComputedStyleMap()->FindEntryForProperty(prop);
475
0
476
0
    MOZ_ASSERT(layoutFlushIsNeeded == entry->IsLayoutFlushNeeded(),
477
0
               "Logical and physical property don't agree on whether layout is "
478
0
               "needed");
479
0
  }
480
0
481
0
  if (!nsCSSProps::PropHasFlags(prop, CSSPropFlags::SerializedByServo)) {
482
0
    if (RefPtr<CSSValue> value = (this->*entry->mGetter)()) {
483
0
      ErrorResult rv;
484
0
      nsString text;
485
0
      value->GetCssText(text, rv);
486
0
      aReturn.Assign(text);
487
0
      return rv.StealNSResult();
488
0
    }
489
0
    return NS_OK;
490
0
  }
491
0
492
0
  MOZ_ASSERT(entry->mGetter == &nsComputedDOMStyle::DummyGetter);
493
0
  Servo_GetPropertyValue(mComputedStyle, prop, &aReturn);
494
0
  return NS_OK;
495
0
}
496
497
/* static */
498
already_AddRefed<ComputedStyle>
499
nsComputedDOMStyle::GetComputedStyle(Element* aElement,
500
                                     nsAtom* aPseudo,
501
                                     StyleType aStyleType)
502
0
{
503
0
  if (nsIDocument* doc = aElement->GetComposedDoc()) {
504
0
    doc->FlushPendingNotifications(FlushType::Style);
505
0
  }
506
0
  return GetComputedStyleNoFlush(aElement, aPseudo, aStyleType);
507
0
}
508
509
510
/**
511
 * The following function checks whether we need to explicitly resolve the style
512
 * again, even though we have a style coming from the frame.
513
 *
514
 * This basically checks whether the style is or may be under a ::first-line or
515
 * ::first-letter frame, in which case we can't return the frame style, and we
516
 * need to resolve it. See bug 505515.
517
 */
518
static bool
519
MustReresolveStyle(const mozilla::ComputedStyle* aStyle)
520
0
{
521
0
  MOZ_ASSERT(aStyle);
522
0
523
0
  // TODO(emilio): We may want to avoid re-resolving pseudo-element styles
524
0
  // more often.
525
0
  return aStyle->HasPseudoElementData() && !aStyle->GetPseudo();
526
0
}
527
528
static inline CSSPseudoElementType
529
GetPseudoType(nsAtom* aPseudo)
530
0
{
531
0
  if (!aPseudo) {
532
0
    return CSSPseudoElementType::NotPseudo;
533
0
  }
534
0
  // FIXME(emilio, bug 1433439): The eIgnoreEnabledState thing is dubious.
535
0
  return nsCSSPseudoElements::GetPseudoType(
536
0
    aPseudo, CSSEnabledState::eIgnoreEnabledState);
537
0
}
538
539
already_AddRefed<ComputedStyle>
540
nsComputedDOMStyle::DoGetComputedStyleNoFlush(Element* aElement,
541
                                              nsAtom* aPseudo,
542
                                              nsIPresShell* aPresShell,
543
                                              StyleType aStyleType)
544
0
{
545
0
  MOZ_ASSERT(aElement, "NULL element");
546
0
547
0
  // If the content has a pres shell, we must use it.  Otherwise we'd
548
0
  // potentially mix rule trees by using the wrong pres shell's style
549
0
  // set.  Using the pres shell from the content also means that any
550
0
  // content that's actually *in* a document will get the style from the
551
0
  // correct document.
552
0
  nsIPresShell* presShell = nsContentUtils::GetPresShellForContent(aElement);
553
0
  bool inDocWithShell = true;
554
0
  if (!presShell) {
555
0
    inDocWithShell = false;
556
0
    presShell = aPresShell;
557
0
    if (!presShell) {
558
0
      return nullptr;
559
0
    }
560
0
  }
561
0
562
0
  CSSPseudoElementType pseudoType = GetPseudoType(aPseudo);
563
0
  if (aPseudo && pseudoType >= CSSPseudoElementType::Count) {
564
0
    return nullptr;
565
0
  }
566
0
567
0
  if (aElement->IsInNativeAnonymousSubtree() && !aElement->IsInComposedDoc()) {
568
0
    // Normal web content can't access NAC, but Accessibility, DevTools and
569
0
    // Editor use this same API and this may get called for anonymous content.
570
0
    // Computing the style of a pseudo-element that doesn't have a parent doesn't
571
0
    // really make sense.
572
0
    return nullptr;
573
0
  }
574
0
575
0
  // XXX the !aElement->IsHTMLElement(nsGkAtoms::area)
576
0
  // check is needed due to bug 135040 (to avoid using
577
0
  // mPrimaryFrame). Remove it once that's fixed.
578
0
  if (inDocWithShell &&
579
0
      aStyleType == eAll &&
580
0
      !aElement->IsHTMLElement(nsGkAtoms::area)) {
581
0
    nsIFrame* frame = nullptr;
582
0
    if (aPseudo == nsCSSPseudoElements::before()) {
583
0
      frame = nsLayoutUtils::GetBeforeFrame(aElement);
584
0
    } else if (aPseudo == nsCSSPseudoElements::after()) {
585
0
      frame = nsLayoutUtils::GetAfterFrame(aElement);
586
0
    } else if (!aPseudo) {
587
0
      frame = nsLayoutUtils::GetStyleFrame(aElement);
588
0
    }
589
0
    if (frame) {
590
0
      ComputedStyle* result = frame->Style();
591
0
      // Don't use the style if it was influenced by pseudo-elements, since then
592
0
      // it's not the primary style for this element / pseudo.
593
0
      if (!MustReresolveStyle(result)) {
594
0
        RefPtr<ComputedStyle> ret = result;
595
0
        return ret.forget();
596
0
      }
597
0
    }
598
0
  }
599
0
600
0
  // No frame has been created, or we have a pseudo, or we're looking
601
0
  // for the default style, so resolve the style ourselves.
602
0
  ServoStyleSet* styleSet = presShell->StyleSet();
603
0
604
0
  StyleRuleInclusion rules = aStyleType == eDefaultOnly
605
0
                             ? StyleRuleInclusion::DefaultOnly
606
0
                             : StyleRuleInclusion::All;
607
0
  RefPtr<ComputedStyle> result =
608
0
     styleSet->ResolveStyleLazily(aElement, pseudoType, rules);
609
0
  return result.forget();
610
0
}
611
612
already_AddRefed<ComputedStyle>
613
nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(Element* aElement,
614
                                                      nsAtom* aPseudo)
615
0
{
616
0
  RefPtr<ComputedStyle> style = GetComputedStyleNoFlush(aElement, aPseudo);
617
0
  if (!style) {
618
0
    return nullptr;
619
0
  }
620
0
621
0
  CSSPseudoElementType pseudoType = GetPseudoType(aPseudo);
622
0
  nsIPresShell* shell = aElement->OwnerDoc()->GetShell();
623
0
  MOZ_ASSERT(shell, "How in the world did we get a style a few lines above?");
624
0
625
0
  Element* elementOrPseudoElement =
626
0
    EffectCompositor::GetElementToRestyle(aElement, pseudoType);
627
0
  if (!elementOrPseudoElement) {
628
0
    return nullptr;
629
0
  }
630
0
631
0
  return shell->StyleSet()->
632
0
    GetBaseContextForElement(elementOrPseudoElement, style);
633
0
}
634
635
nsMargin
636
nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
637
0
{
638
0
  // We want the width/height of whatever parts 'width' or 'height' controls,
639
0
  // which can be different depending on the value of the 'box-sizing' property.
640
0
  const nsStylePosition* stylePos = StylePosition();
641
0
642
0
  nsMargin adjustment;
643
0
  if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
644
0
    adjustment = mInnerFrame->GetUsedBorderAndPadding();
645
0
  }
646
0
647
0
  return adjustment;
648
0
}
649
650
static void
651
AddImageURL(nsIURI& aURI, nsTArray<nsString>& aURLs)
652
0
{
653
0
  nsAutoCString spec;
654
0
  nsresult rv = aURI.GetSpec(spec);
655
0
  if (NS_FAILED(rv)) {
656
0
    return;
657
0
  }
658
0
659
0
  aURLs.AppendElement(NS_ConvertUTF8toUTF16(spec));
660
0
}
661
662
663
static void
664
AddImageURL(const css::URLValueData& aURL, nsTArray<nsString>& aURLs)
665
0
{
666
0
  if (aURL.IsLocalRef()) {
667
0
    return;
668
0
  }
669
0
670
0
  if (nsIURI* uri = aURL.GetURI()) {
671
0
    AddImageURL(*uri, aURLs);
672
0
  }
673
0
}
674
675
676
static void
677
AddImageURL(const nsStyleImageRequest& aRequest, nsTArray<nsString>& aURLs)
678
0
{
679
0
  if (auto* value = aRequest.GetImageValue()) {
680
0
    AddImageURL(*value, aURLs);
681
0
  }
682
0
}
683
684
static void
685
AddImageURL(const nsStyleImage& aImage, nsTArray<nsString>& aURLs)
686
0
{
687
0
  if (auto* urlValue = aImage.GetURLValue()) {
688
0
    AddImageURL(*urlValue, aURLs);
689
0
  }
690
0
}
691
692
static void
693
AddImageURL(const StyleShapeSource& aShapeSource, nsTArray<nsString>& aURLs)
694
{
695
  switch (aShapeSource.GetType()) {
696
    case StyleShapeSourceType::URL:
697
      AddImageURL(*aShapeSource.GetURL(), aURLs);
698
      break;
699
    case StyleShapeSourceType::Image:
700
      AddImageURL(*aShapeSource.GetShapeImage(), aURLs);
701
      break;
702
    default:
703
      break;
704
  }
705
}
706
707
static void
708
AddImageURLs(const nsStyleImageLayers& aLayers, nsTArray<nsString>& aURLs)
709
0
{
710
0
  for (auto i : IntegerRange(aLayers.mLayers.Length())) {
711
0
    AddImageURL(aLayers.mLayers[i].mImage, aURLs);
712
0
  }
713
0
}
714
715
// FIXME(stylo-everywhere): This should be `const ComputedStyle&`.
716
static void
717
CollectImageURLsForProperty(nsCSSPropertyID aProp,
718
                            ComputedStyle& aStyle,
719
                            nsTArray<nsString>& aURLs)
720
0
{
721
0
  if (nsCSSProps::IsShorthand(aProp)) {
722
0
    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProp, CSSEnabledState::eForAllContent) {
723
0
      CollectImageURLsForProperty(*p, aStyle, aURLs);
724
0
    }
725
0
    return;
726
0
  }
727
0
728
0
  switch (aProp) {
729
0
    case eCSSProperty_cursor:
730
0
      for (auto& image : aStyle.StyleUI()->mCursorImages) {
731
0
        AddImageURL(*image.mImage, aURLs);
732
0
      }
733
0
      break;
734
0
    case eCSSProperty_background_image:
735
0
      AddImageURLs(aStyle.StyleBackground()->mImage, aURLs);
736
0
      break;
737
0
    case eCSSProperty_mask_clip:
738
0
      AddImageURLs(aStyle.StyleSVGReset()->mMask, aURLs);
739
0
      break;
740
0
    case eCSSProperty_list_style_image:
741
0
      if (nsStyleImageRequest* image = aStyle.StyleList()->mListStyleImage) {
742
0
        AddImageURL(*image, aURLs);
743
0
      }
744
0
      break;
745
0
    case eCSSProperty_border_image_source:
746
0
      AddImageURL(aStyle.StyleBorder()->mBorderImageSource, aURLs);
747
0
      break;
748
0
    case eCSSProperty_clip_path:
749
0
      AddImageURL(aStyle.StyleSVGReset()->mClipPath, aURLs);
750
0
      break;
751
0
    case eCSSProperty_shape_outside:
752
0
      AddImageURL(aStyle.StyleDisplay()->mShapeOutside, aURLs);
753
0
      break;
754
0
    default:
755
0
      break;
756
0
  }
757
0
}
758
759
void
760
nsComputedDOMStyle::GetCSSImageURLs(const nsAString& aPropertyName,
761
                                    nsTArray<nsString>& aImageURLs,
762
                                    mozilla::ErrorResult& aRv)
763
0
{
764
0
  nsCSSPropertyID prop = nsCSSProps::LookupProperty(aPropertyName);
765
0
  if (prop == eCSSProperty_UNKNOWN) {
766
0
    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
767
0
    return;
768
0
  }
769
0
770
0
  UpdateCurrentStyleSources(false);
771
0
772
0
  if (!mComputedStyle) {
773
0
    return;
774
0
  }
775
0
776
0
  CollectImageURLsForProperty(prop, *mComputedStyle, aImageURLs);
777
0
  ClearCurrentStyleSources();
778
0
}
779
780
// nsDOMCSSDeclaration abstract methods which should never be called
781
// on a nsComputedDOMStyle object, but must be defined to avoid
782
// compile errors.
783
DeclarationBlock*
784
nsComputedDOMStyle::GetOrCreateCSSDeclaration(Operation aOperation,
785
                                              DeclarationBlock** aCreated)
786
0
{
787
0
  MOZ_CRASH("called nsComputedDOMStyle::GetCSSDeclaration");
788
0
}
789
790
nsresult
791
nsComputedDOMStyle::SetCSSDeclaration(DeclarationBlock*,
792
                                      MutationClosureData*)
793
0
{
794
0
  MOZ_CRASH("called nsComputedDOMStyle::SetCSSDeclaration");
795
0
}
796
797
nsIDocument*
798
nsComputedDOMStyle::DocToUpdate()
799
0
{
800
0
  MOZ_CRASH("called nsComputedDOMStyle::DocToUpdate");
801
0
}
802
803
nsDOMCSSDeclaration::ParsingEnvironment
804
nsComputedDOMStyle::GetParsingEnvironment(
805
  nsIPrincipal* aSubjectPrincipal) const
806
0
{
807
0
  MOZ_CRASH("called nsComputedDOMStyle::GetParsingEnvironment");
808
0
}
809
810
void
811
nsComputedDOMStyle::ClearComputedStyle()
812
0
{
813
0
  if (mResolvedComputedStyle) {
814
0
    mResolvedComputedStyle = false;
815
0
    mElement->RemoveMutationObserver(this);
816
0
  }
817
0
  mComputedStyle = nullptr;
818
0
}
819
820
void
821
nsComputedDOMStyle::SetResolvedComputedStyle(RefPtr<ComputedStyle>&& aContext,
822
                                            uint64_t aGeneration)
823
0
{
824
0
  if (!mResolvedComputedStyle) {
825
0
    mResolvedComputedStyle = true;
826
0
    mElement->AddMutationObserver(this);
827
0
  }
828
0
  mComputedStyle = aContext;
829
0
  mComputedStyleGeneration = aGeneration;
830
0
}
831
832
void
833
nsComputedDOMStyle::SetFrameComputedStyle(mozilla::ComputedStyle* aStyle,
834
                                         uint64_t aGeneration)
835
0
{
836
0
  ClearComputedStyle();
837
0
  mComputedStyle = aStyle;
838
0
  mComputedStyleGeneration = aGeneration;
839
0
}
840
841
bool
842
nsComputedDOMStyle::NeedsToFlush(nsIDocument* aDocument) const
843
0
{
844
0
  // If mElement is not in the same document, we could do some checks to know if
845
0
  // there are some pending restyles can be ignored across documents (since we
846
0
  // will use the caller document's style), but it can be complicated and should
847
0
  // be an edge case, so we just don't bother to do the optimization in this
848
0
  // case.
849
0
  //
850
0
  // FIXME(emilio): This is likely to want GetComposedDoc() instead of
851
0
  // OwnerDoc().
852
0
  if (aDocument != mElement->OwnerDoc()) {
853
0
    return true;
854
0
  }
855
0
  if (DocumentNeedsRestyle(aDocument, mElement, mPseudo)) {
856
0
    return true;
857
0
  }
858
0
  // If parent document is there, also needs to check if there is some change
859
0
  // that needs to flush this document (e.g. size change for iframe).
860
0
  while (nsIDocument* parentDocument = aDocument->GetParentDocument()) {
861
0
    Element* element = parentDocument->FindContentForSubDocument(aDocument);
862
0
    if (DocumentNeedsRestyle(parentDocument, element, nullptr)) {
863
0
      return true;
864
0
    }
865
0
    aDocument = parentDocument;
866
0
  }
867
0
868
0
  return false;
869
0
}
870
871
void
872
nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
873
0
{
874
0
  nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
875
0
  if (!document) {
876
0
    ClearComputedStyle();
877
0
    return;
878
0
  }
879
0
880
0
  // TODO(emilio): We may want to handle a few special-cases here:
881
0
  //
882
0
  //  * https://github.com/w3c/csswg-drafts/issues/1964
883
0
  //  * https://github.com/w3c/csswg-drafts/issues/1548
884
0
885
0
  // If the property we are computing relies on layout, then we must flush.
886
0
  const bool needsToFlush = aNeedsLayoutFlush || NeedsToFlush(document);
887
0
  if (needsToFlush) {
888
0
    // Flush _before_ getting the presshell, since that could create a new
889
0
    // presshell.  Also note that we want to flush the style on the document
890
0
    // we're computing style in, not on the document mElement is in -- the two
891
0
    // may be different.
892
0
    document->FlushPendingNotifications(
893
0
      aNeedsLayoutFlush ? FlushType::Layout : FlushType::Style);
894
0
  }
895
0
896
#ifdef DEBUG
897
  mFlushedPendingReflows = aNeedsLayoutFlush;
898
#endif
899
900
0
  nsCOMPtr<nsIPresShell> presShellForContent =
901
0
    nsContentUtils::GetPresShellForContent(mElement);
902
0
  if (presShellForContent && presShellForContent->GetDocument() != document) {
903
0
    presShellForContent->GetDocument()->FlushPendingNotifications(FlushType::Style);
904
0
    if (presShellForContent->IsDestroying()) {
905
0
      presShellForContent = nullptr;
906
0
    }
907
0
  }
908
0
909
0
  mPresShell = document->GetShell();
910
0
  if (!mPresShell || !mPresShell->GetPresContext()) {
911
0
    ClearComputedStyle();
912
0
    return;
913
0
  }
914
0
915
0
  // We need to use GetUndisplayedRestyleGeneration instead of
916
0
  // GetRestyleGeneration, because the caching of mComputedStyle is an
917
0
  // optimization that is useful only for displayed elements.
918
0
  // For undisplayed elements we need to take into account any DOM changes that
919
0
  // might cause a restyle, because Servo will not increase the generation for
920
0
  // undisplayed elements.
921
0
  // As for Gecko, GetUndisplayedRestyleGeneration is effectively equal to
922
0
  // GetRestyleGeneration, since the generation is incremented whenever we
923
0
  // process restyles.
924
0
  uint64_t currentGeneration =
925
0
    mPresShell->GetPresContext()->GetUndisplayedRestyleGeneration();
926
0
927
0
  if (mComputedStyle) {
928
0
    // We can't rely on the undisplayed restyle generation if mElement is
929
0
    // out-of-document, since that generation is not incremented for DOM changes
930
0
    // on out-of-document elements.
931
0
    //
932
0
    // So we always need to update the style to ensure it it up-to-date.
933
0
    if (mComputedStyleGeneration == currentGeneration &&
934
0
        mElement->IsInComposedDoc()) {
935
0
      // Our cached style is still valid.
936
0
      return;
937
0
    }
938
0
    // We've processed some restyles, so the cached style might be out of date.
939
0
    mComputedStyle = nullptr;
940
0
  }
941
0
942
0
  // XXX the !mElement->IsHTMLElement(nsGkAtoms::area)
943
0
  // check is needed due to bug 135040 (to avoid using
944
0
  // mPrimaryFrame). Remove it once that's fixed.
945
0
  if (mStyleType == eAll && !mElement->IsHTMLElement(nsGkAtoms::area)) {
946
0
    mOuterFrame = nullptr;
947
0
948
0
    if (!mPseudo) {
949
0
      mOuterFrame = mElement->GetPrimaryFrame();
950
0
    } else if (mPseudo == nsCSSPseudoElements::before() ||
951
0
               mPseudo == nsCSSPseudoElements::after()) {
952
0
      nsAtom* property = mPseudo == nsCSSPseudoElements::before()
953
0
                            ? nsGkAtoms::beforePseudoProperty
954
0
                            : nsGkAtoms::afterPseudoProperty;
955
0
956
0
      auto* pseudo = static_cast<Element*>(mElement->GetProperty(property));
957
0
      mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr;
958
0
    }
959
0
960
0
    mInnerFrame = mOuterFrame;
961
0
    if (mOuterFrame) {
962
0
      LayoutFrameType type = mOuterFrame->Type();
963
0
      if (type == LayoutFrameType::TableWrapper) {
964
0
        // If the frame is a table wrapper frame then we should get the style
965
0
        // from the inner table frame.
966
0
        mInnerFrame = mOuterFrame->PrincipalChildList().FirstChild();
967
0
        NS_ASSERTION(mInnerFrame, "table wrapper must have an inner");
968
0
        NS_ASSERTION(!mInnerFrame->GetNextSibling(),
969
0
                     "table wrapper frames should have just one child, "
970
0
                     "the inner table");
971
0
      }
972
0
973
0
      SetFrameComputedStyle(mInnerFrame->Style(), currentGeneration);
974
0
      NS_ASSERTION(mComputedStyle, "Frame without style?");
975
0
    }
976
0
  }
977
0
978
0
  if (!mComputedStyle || MustReresolveStyle(mComputedStyle)) {
979
0
    // Need to resolve a style.
980
0
    RefPtr<ComputedStyle> resolvedComputedStyle =
981
0
      DoGetComputedStyleNoFlush(
982
0
          mElement,
983
0
          mPseudo,
984
0
          presShellForContent ? presShellForContent.get() : mPresShell,
985
0
          mStyleType);
986
0
    if (!resolvedComputedStyle) {
987
0
      ClearComputedStyle();
988
0
      return;
989
0
    }
990
0
991
0
    // No need to re-get the generation, even though GetComputedStyle
992
0
    // will flush, since we flushed style at the top of this function.
993
0
    // We don't need to check this if we only flushed the parent.
994
0
    NS_ASSERTION(!needsToFlush ||
995
0
                 currentGeneration ==
996
0
                     mPresShell->GetPresContext()->GetUndisplayedRestyleGeneration(),
997
0
                   "why should we have flushed style again?");
998
0
999
0
    SetResolvedComputedStyle(std::move(resolvedComputedStyle), currentGeneration);
1000
0
    NS_ASSERTION(mPseudo || !mComputedStyle->HasPseudoElementData(),
1001
0
                 "should not have pseudo-element data");
1002
0
  }
1003
0
1004
0
  // mExposeVisitedStyle is set to true only by testing APIs that
1005
0
  // require chrome privilege.
1006
0
  MOZ_ASSERT(!mExposeVisitedStyle || nsContentUtils::IsCallerChrome(),
1007
0
             "mExposeVisitedStyle set incorrectly");
1008
0
  if (mExposeVisitedStyle && mComputedStyle->RelevantLinkVisited()) {
1009
0
    if (ComputedStyle* styleIfVisited = mComputedStyle->GetStyleIfVisited()) {
1010
0
      mComputedStyle = styleIfVisited;
1011
0
    }
1012
0
  }
1013
0
}
1014
1015
void
1016
nsComputedDOMStyle::ClearCurrentStyleSources()
1017
0
{
1018
0
  // Release the current style if we got it off the frame.
1019
0
  //
1020
0
  // For a style we resolved, keep it around so that we can re-use it next time
1021
0
  // this object is queried, but not if it-s a re-resolved style because we were
1022
0
  // inside a pseudo-element.
1023
0
  if (!mResolvedComputedStyle || mOuterFrame) {
1024
0
    ClearComputedStyle();
1025
0
  }
1026
0
1027
0
  mOuterFrame = nullptr;
1028
0
  mInnerFrame = nullptr;
1029
0
  mPresShell = nullptr;
1030
0
}
1031
1032
NS_IMETHODIMP
1033
nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
1034
                                   nsAString& aReturn)
1035
0
{
1036
0
  return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
1037
0
}
1038
1039
1040
void
1041
nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
1042
                                        nsAString& aReturn)
1043
0
{
1044
0
  aReturn.Truncate();
1045
0
}
1046
1047
NS_IMETHODIMP
1048
nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
1049
                                const nsAString& aValue,
1050
                                const nsAString& aPriority,
1051
                                nsIPrincipal* aSubjectPrincipal)
1052
0
{
1053
0
  return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
1054
0
}
1055
1056
void
1057
nsComputedDOMStyle::IndexedGetter(uint32_t   aIndex,
1058
                                  bool&      aFound,
1059
                                  nsAString& aPropName)
1060
0
{
1061
0
  ComputedStyleMap* map = GetComputedStyleMap();
1062
0
  uint32_t length = map->Length();
1063
0
1064
0
  if (aIndex < length) {
1065
0
    aFound = true;
1066
0
    CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)),
1067
0
                     aPropName);
1068
0
    return;
1069
0
  }
1070
0
1071
0
  // Custom properties are exposed with indexed properties just after all
1072
0
  // of the built-in properties.
1073
0
  UpdateCurrentStyleSources(false);
1074
0
  if (!mComputedStyle) {
1075
0
    aFound = false;
1076
0
    return;
1077
0
  }
1078
0
1079
0
  uint32_t count =
1080
0
    Servo_GetCustomPropertiesCount(mComputedStyle);
1081
0
1082
0
  const uint32_t index = aIndex - length;
1083
0
  if (index < count) {
1084
0
    aFound = true;
1085
0
    nsString varName;
1086
0
    Servo_GetCustomPropertyNameAt(mComputedStyle, index, &varName);
1087
0
    aPropName.AssignLiteral("--");
1088
0
    aPropName.Append(varName);
1089
0
  } else {
1090
0
    aFound = false;
1091
0
  }
1092
0
1093
0
  ClearCurrentStyleSources();
1094
0
}
1095
1096
// Property getters...
1097
1098
already_AddRefed<CSSValue>
1099
nsComputedDOMStyle::DoGetBinding()
1100
0
{
1101
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1102
0
1103
0
  const nsStyleDisplay* display = StyleDisplay();
1104
0
1105
0
  if (display->mBinding && display->mBinding->GetURI()) {
1106
0
    val->SetURI(display->mBinding->GetURI());
1107
0
  } else {
1108
0
    val->SetIdent(eCSSKeyword_none);
1109
0
  }
1110
0
1111
0
  return val.forget();
1112
0
}
1113
1114
already_AddRefed<CSSValue>
1115
nsComputedDOMStyle::DoGetBottom()
1116
0
{
1117
0
  return GetOffsetWidthFor(eSideBottom);
1118
0
}
1119
1120
void
1121
nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
1122
                                   nscolor aColor)
1123
0
{
1124
0
  nsROCSSPrimitiveValue *red   = new nsROCSSPrimitiveValue;
1125
0
  nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue;
1126
0
  nsROCSSPrimitiveValue *blue  = new nsROCSSPrimitiveValue;
1127
0
  nsROCSSPrimitiveValue *alpha  = new nsROCSSPrimitiveValue;
1128
0
1129
0
  uint8_t a = NS_GET_A(aColor);
1130
0
  nsDOMCSSRGBColor *rgbColor =
1131
0
    new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
1132
0
1133
0
  red->SetNumber(NS_GET_R(aColor));
1134
0
  green->SetNumber(NS_GET_G(aColor));
1135
0
  blue->SetNumber(NS_GET_B(aColor));
1136
0
  alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
1137
0
1138
0
  aValue->SetColor(rgbColor);
1139
0
}
1140
1141
void
1142
nsComputedDOMStyle::SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
1143
                                             const StyleComplexColor& aColor)
1144
0
{
1145
0
  SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
1146
0
}
1147
1148
void
1149
nsComputedDOMStyle::SetValueForWidgetColor(nsROCSSPrimitiveValue* aValue,
1150
                                           const StyleComplexColor& aColor,
1151
                                           StyleAppearance aWidgetType)
1152
0
{
1153
0
  if (!aColor.IsAuto()) {
1154
0
    SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
1155
0
    return;
1156
0
  }
1157
0
  nsPresContext* presContext = mPresShell->GetPresContext();
1158
0
  MOZ_ASSERT(presContext);
1159
0
  if (nsContentUtils::ShouldResistFingerprinting(presContext->GetDocShell())) {
1160
0
    // Return transparent when resisting fingerprinting.
1161
0
    SetToRGBAColor(aValue, NS_RGBA(0, 0, 0, 0));
1162
0
    return;
1163
0
  }
1164
0
  if (nsITheme* theme = presContext->GetTheme()) {
1165
0
    nscolor color = theme->GetWidgetAutoColor(mComputedStyle, aWidgetType);
1166
0
    SetToRGBAColor(aValue, color);
1167
0
  } else {
1168
0
    // If we don't have theme, we don't know what value it should be,
1169
0
    // just give it a transparent fallback.
1170
0
    SetToRGBAColor(aValue, NS_RGBA(0, 0, 0, 0));
1171
0
  }
1172
0
}
1173
1174
already_AddRefed<CSSValue>
1175
nsComputedDOMStyle::DoGetColor()
1176
0
{
1177
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1178
0
  SetToRGBAColor(val, StyleColor()->mColor);
1179
0
  return val.forget();
1180
0
}
1181
1182
already_AddRefed<CSSValue>
1183
nsComputedDOMStyle::DoGetColumnCount()
1184
0
{
1185
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1186
0
1187
0
  const nsStyleColumn* column = StyleColumn();
1188
0
1189
0
  if (column->mColumnCount == nsStyleColumn::kColumnCountAuto) {
1190
0
    val->SetIdent(eCSSKeyword_auto);
1191
0
  } else {
1192
0
    val->SetNumber(column->mColumnCount);
1193
0
  }
1194
0
1195
0
  return val.forget();
1196
0
}
1197
1198
already_AddRefed<CSSValue>
1199
nsComputedDOMStyle::DoGetColumnWidth()
1200
0
{
1201
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1202
0
1203
0
  // XXX fix the auto case. When we actually have a column frame, I think
1204
0
  // we should return the computed column width.
1205
0
  SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
1206
0
  return val.forget();
1207
0
}
1208
1209
already_AddRefed<CSSValue>
1210
nsComputedDOMStyle::DoGetColumnRuleWidth()
1211
0
{
1212
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1213
0
  val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
1214
0
  return val.forget();
1215
0
}
1216
1217
/* Convert the stored representation into a list of two values and then hand
1218
 * it back.
1219
 */
1220
already_AddRefed<CSSValue>
1221
nsComputedDOMStyle::DoGetTransformOrigin()
1222
0
{
1223
0
  /* We need to build up a list of two values.  We'll call them
1224
0
   * width and height.
1225
0
   */
1226
0
1227
0
  /* Store things as a value list */
1228
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
1229
0
1230
0
  /* Now, get the values. */
1231
0
  const nsStyleDisplay* display = StyleDisplay();
1232
0
1233
0
  RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
1234
0
  SetValueToCoord(width, display->mTransformOrigin[0], false,
1235
0
                  &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1236
0
  valueList->AppendCSSValue(width.forget());
1237
0
1238
0
  RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
1239
0
  SetValueToCoord(height, display->mTransformOrigin[1], false,
1240
0
                  &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1241
0
  valueList->AppendCSSValue(height.forget());
1242
0
1243
0
  if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
1244
0
      display->mTransformOrigin[2].GetCoordValue() != 0) {
1245
0
    RefPtr<nsROCSSPrimitiveValue> depth = new nsROCSSPrimitiveValue;
1246
0
    SetValueToCoord(depth, display->mTransformOrigin[2], false,
1247
0
                    nullptr);
1248
0
    valueList->AppendCSSValue(depth.forget());
1249
0
  }
1250
0
1251
0
  return valueList.forget();
1252
0
}
1253
1254
/* Convert the stored representation into a list of two values and then hand
1255
 * it back.
1256
 */
1257
already_AddRefed<CSSValue>
1258
nsComputedDOMStyle::DoGetPerspectiveOrigin()
1259
0
{
1260
0
  /* We need to build up a list of two values.  We'll call them
1261
0
   * width and height.
1262
0
   */
1263
0
1264
0
  /* Store things as a value list */
1265
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
1266
0
1267
0
  /* Now, get the values. */
1268
0
  const nsStyleDisplay* display = StyleDisplay();
1269
0
1270
0
  RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
1271
0
  SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
1272
0
                  &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1273
0
  valueList->AppendCSSValue(width.forget());
1274
0
1275
0
  RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
1276
0
  SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
1277
0
                  &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1278
0
  valueList->AppendCSSValue(height.forget());
1279
0
1280
0
  return valueList.forget();
1281
0
}
1282
1283
already_AddRefed<CSSValue>
1284
nsComputedDOMStyle::DoGetPerspective()
1285
0
{
1286
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1287
0
  SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
1288
0
  return val.forget();
1289
0
}
1290
1291
already_AddRefed<CSSValue>
1292
nsComputedDOMStyle::DoGetTransformStyle()
1293
0
{
1294
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1295
0
  val->SetIdent(
1296
0
      nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
1297
0
                                     nsCSSProps::kTransformStyleKTable));
1298
0
  return val.forget();
1299
0
}
1300
1301
already_AddRefed<CSSValue>
1302
nsComputedDOMStyle::DoGetTransform()
1303
0
{
1304
0
  const nsStyleDisplay* display = StyleDisplay();
1305
0
  return GetTransformValue(display->mSpecifiedTransform);
1306
0
}
1307
1308
static already_AddRefed<CSSValue>
1309
ReadIndividualTransformValue(nsCSSValueSharedList* aList,
1310
                             const std::function<void(const nsCSSValue::Array*,
1311
                                                      nsString&)>& aCallback)
1312
0
{
1313
0
  if (!aList) {
1314
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1315
0
    val->SetIdent(eCSSKeyword_none);
1316
0
    return val.forget();
1317
0
  }
1318
0
1319
0
  nsAutoString result;
1320
0
  const nsCSSValue::Array* data = aList->mHead->mValue.GetArrayValue();
1321
0
  aCallback(data, result);
1322
0
1323
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1324
0
  val->SetString(result);
1325
0
  return val.forget();
1326
0
}
1327
1328
already_AddRefed<CSSValue>
1329
nsComputedDOMStyle::DoGetTranslate()
1330
0
{
1331
0
  typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
1332
0
1333
0
  RefPtr<nsComputedDOMStyle> self(this);
1334
0
  return ReadIndividualTransformValue(StyleDisplay()->mSpecifiedTranslate,
1335
0
    [self](const nsCSSValue::Array* aData, nsString& aResult) {
1336
0
      TransformReferenceBox refBox(self->mInnerFrame, nsSize(0, 0));
1337
0
1338
0
      // Even though the spec doesn't say to resolve percentage values, Blink
1339
0
      // and Edge do and so until that is clarified we do as well:
1340
0
      //
1341
0
      // https://github.com/w3c/csswg-drafts/issues/2124
1342
0
      switch (nsStyleTransformMatrix::TransformFunctionOf(aData)) {
1343
0
        /* translate : <length-percentage> */
1344
0
        case eCSSKeyword_translatex: {
1345
0
          MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
1346
0
          float tx = ProcessTranslatePart(aData->Item(1),
1347
0
                                          &refBox,
1348
0
                                          &TransformReferenceBox::Width);
1349
0
          aResult.AppendFloat(tx);
1350
0
          aResult.AppendLiteral("px");
1351
0
          break;
1352
0
        }
1353
0
        /* translate : <length-percentage> <length-percentage> */
1354
0
        case eCSSKeyword_translate: {
1355
0
          MOZ_ASSERT(aData->Count() == 3, "Invalid array!");
1356
0
          float tx = ProcessTranslatePart(aData->Item(1),
1357
0
                                          &refBox,
1358
0
                                          &TransformReferenceBox::Width);
1359
0
          aResult.AppendFloat(tx);
1360
0
          aResult.AppendLiteral("px");
1361
0
1362
0
          float ty = ProcessTranslatePart(aData->Item(2),
1363
0
                                          &refBox,
1364
0
                                          &TransformReferenceBox::Height);
1365
0
          if (ty != 0) {
1366
0
            aResult.AppendLiteral(" ");
1367
0
            aResult.AppendFloat(ty);
1368
0
            aResult.AppendLiteral("px");
1369
0
          }
1370
0
          break;
1371
0
        }
1372
0
        /* translate : <length-percentage> <length-percentage> <length>*/
1373
0
        case eCSSKeyword_translate3d: {
1374
0
          MOZ_ASSERT(aData->Count() == 4, "Invalid array!");
1375
0
          float tx = ProcessTranslatePart(aData->Item(1),
1376
0
                                          &refBox,
1377
0
                                          &TransformReferenceBox::Width);
1378
0
          aResult.AppendFloat(tx);
1379
0
          aResult.AppendLiteral("px");
1380
0
1381
0
          float ty = ProcessTranslatePart(aData->Item(2),
1382
0
                                          &refBox,
1383
0
                                          &TransformReferenceBox::Height);
1384
0
1385
0
          float tz = ProcessTranslatePart(aData->Item(3),
1386
0
                                          &refBox,
1387
0
                                          nullptr);
1388
0
          if (ty != 0. || tz != 0.) {
1389
0
            aResult.AppendLiteral(" ");
1390
0
            aResult.AppendFloat(ty);
1391
0
            aResult.AppendLiteral("px");
1392
0
          }
1393
0
          if (tz != 0.) {
1394
0
            aResult.AppendLiteral(" ");
1395
0
            aResult.AppendFloat(tz);
1396
0
            aResult.AppendLiteral("px");
1397
0
          }
1398
0
1399
0
          break;
1400
0
        }
1401
0
        default:
1402
0
          MOZ_ASSERT_UNREACHABLE("Unexpected CSS keyword.");
1403
0
      }
1404
0
    });
1405
0
}
1406
1407
already_AddRefed<CSSValue>
1408
nsComputedDOMStyle::DoGetScale()
1409
0
{
1410
0
  return ReadIndividualTransformValue(StyleDisplay()->mSpecifiedScale,
1411
0
    [](const nsCSSValue::Array* aData, nsString& aResult) {
1412
0
      switch (nsStyleTransformMatrix::TransformFunctionOf(aData)) {
1413
0
        /* scale : <number> */
1414
0
        case eCSSKeyword_scalex:
1415
0
          MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
1416
0
          aResult.AppendFloat(aData->Item(1).GetFloatValue());
1417
0
          break;
1418
0
        /* scale : <number> <number>*/
1419
0
        case eCSSKeyword_scale: {
1420
0
          MOZ_ASSERT(aData->Count() == 3, "Invalid array!");
1421
0
          aResult.AppendFloat(aData->Item(1).GetFloatValue());
1422
0
1423
0
          float sy = aData->Item(2).GetFloatValue();
1424
0
          if (sy != 1.) {
1425
0
            aResult.AppendLiteral(" ");
1426
0
            aResult.AppendFloat(sy);
1427
0
          }
1428
0
          break;
1429
0
        }
1430
0
        /* scale : <number> <number> <number> */
1431
0
        case eCSSKeyword_scale3d: {
1432
0
          MOZ_ASSERT(aData->Count() == 4, "Invalid array!");
1433
0
          aResult.AppendFloat(aData->Item(1).GetFloatValue());
1434
0
1435
0
          float sy = aData->Item(2).GetFloatValue();
1436
0
          float sz = aData->Item(3).GetFloatValue();
1437
0
1438
0
          if (sy != 1. || sz != 1.) {
1439
0
            aResult.AppendLiteral(" ");
1440
0
            aResult.AppendFloat(sy);
1441
0
          }
1442
0
          if (sz != 1.) {
1443
0
            aResult.AppendLiteral(" ");
1444
0
            aResult.AppendFloat(sz);
1445
0
          }
1446
0
          break;
1447
0
        }
1448
0
        default:
1449
0
          MOZ_ASSERT_UNREACHABLE("Unexpected CSS keyword.");
1450
0
      }
1451
0
    });
1452
0
}
1453
1454
already_AddRefed<CSSValue>
1455
nsComputedDOMStyle::DoGetRotate()
1456
0
{
1457
0
  return ReadIndividualTransformValue(StyleDisplay()->mSpecifiedRotate,
1458
0
    [](const nsCSSValue::Array* aData, nsString& aResult) {
1459
0
1460
0
      switch (nsStyleTransformMatrix::TransformFunctionOf(aData)) {
1461
0
        /* rotate : <angle> */
1462
0
        case eCSSKeyword_rotate: {
1463
0
          MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
1464
0
          float theta = aData->Item(1).GetAngleValueInDegrees();
1465
0
          aResult.AppendFloat(theta);
1466
0
          aResult.AppendLiteral("deg");
1467
0
          break;
1468
0
        }
1469
0
        /* rotate : <number> <number> <number> <angle> */
1470
0
        case eCSSKeyword_rotate3d: {
1471
0
          MOZ_ASSERT(aData->Count() == 5, "Invalid array!");
1472
0
          float rx = aData->Item(1).GetFloatValue();
1473
0
          float ry = aData->Item(2).GetFloatValue();
1474
0
          float rz = aData->Item(3).GetFloatValue();
1475
0
          if (rx != 0. || ry != 0. || rz != 1.) {
1476
0
            aResult.AppendFloat(rx);
1477
0
            aResult.AppendLiteral(" ");
1478
0
            aResult.AppendFloat(ry);
1479
0
            aResult.AppendLiteral(" ");
1480
0
            aResult.AppendFloat(rz);
1481
0
            aResult.AppendLiteral(" ");
1482
0
          }
1483
0
          float theta = aData->Item(4).GetAngleValueInDegrees();
1484
0
          aResult.AppendFloat(theta);
1485
0
          aResult.AppendLiteral("deg");
1486
0
          break;
1487
0
        }
1488
0
        default:
1489
0
          MOZ_ASSERT_UNREACHABLE("Unexpected CSS keyword.");
1490
0
      }
1491
0
    });
1492
0
}
1493
1494
/* static */ already_AddRefed<nsROCSSPrimitiveValue>
1495
nsComputedDOMStyle::MatrixToCSSValue(const mozilla::gfx::Matrix4x4& matrix)
1496
0
{
1497
0
  bool is3D = !matrix.Is2D();
1498
0
1499
0
  nsAutoString resultString(NS_LITERAL_STRING("matrix"));
1500
0
  if (is3D) {
1501
0
    resultString.AppendLiteral("3d");
1502
0
  }
1503
0
1504
0
  resultString.Append('(');
1505
0
  resultString.AppendFloat(matrix._11);
1506
0
  resultString.AppendLiteral(", ");
1507
0
  resultString.AppendFloat(matrix._12);
1508
0
  resultString.AppendLiteral(", ");
1509
0
  if (is3D) {
1510
0
    resultString.AppendFloat(matrix._13);
1511
0
    resultString.AppendLiteral(", ");
1512
0
    resultString.AppendFloat(matrix._14);
1513
0
    resultString.AppendLiteral(", ");
1514
0
  }
1515
0
  resultString.AppendFloat(matrix._21);
1516
0
  resultString.AppendLiteral(", ");
1517
0
  resultString.AppendFloat(matrix._22);
1518
0
  resultString.AppendLiteral(", ");
1519
0
  if (is3D) {
1520
0
    resultString.AppendFloat(matrix._23);
1521
0
    resultString.AppendLiteral(", ");
1522
0
    resultString.AppendFloat(matrix._24);
1523
0
    resultString.AppendLiteral(", ");
1524
0
    resultString.AppendFloat(matrix._31);
1525
0
    resultString.AppendLiteral(", ");
1526
0
    resultString.AppendFloat(matrix._32);
1527
0
    resultString.AppendLiteral(", ");
1528
0
    resultString.AppendFloat(matrix._33);
1529
0
    resultString.AppendLiteral(", ");
1530
0
    resultString.AppendFloat(matrix._34);
1531
0
    resultString.AppendLiteral(", ");
1532
0
  }
1533
0
  resultString.AppendFloat(matrix._41);
1534
0
  resultString.AppendLiteral(", ");
1535
0
  resultString.AppendFloat(matrix._42);
1536
0
  if (is3D) {
1537
0
    resultString.AppendLiteral(", ");
1538
0
    resultString.AppendFloat(matrix._43);
1539
0
    resultString.AppendLiteral(", ");
1540
0
    resultString.AppendFloat(matrix._44);
1541
0
  }
1542
0
  resultString.Append(')');
1543
0
1544
0
  /* Create a value to hold our result. */
1545
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1546
0
1547
0
  val->SetString(resultString);
1548
0
  return val.forget();
1549
0
}
1550
1551
already_AddRefed<CSSValue>
1552
nsComputedDOMStyle::DoGetQuotes()
1553
0
{
1554
0
  const auto& quotePairs = StyleList()->GetQuotePairs();
1555
0
1556
0
  if (quotePairs.IsEmpty()) {
1557
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1558
0
    val->SetIdent(eCSSKeyword_none);
1559
0
    return val.forget();
1560
0
  }
1561
0
1562
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
1563
0
1564
0
  for (const auto& quotePair : quotePairs) {
1565
0
    RefPtr<nsROCSSPrimitiveValue> openVal = new nsROCSSPrimitiveValue;
1566
0
    RefPtr<nsROCSSPrimitiveValue> closeVal = new nsROCSSPrimitiveValue;
1567
0
1568
0
    nsAutoString s;
1569
0
    nsStyleUtil::AppendEscapedCSSString(quotePair.first, s);
1570
0
    openVal->SetString(s);
1571
0
    s.Truncate();
1572
0
    nsStyleUtil::AppendEscapedCSSString(quotePair.second, s);
1573
0
    closeVal->SetString(s);
1574
0
1575
0
    valueList->AppendCSSValue(openVal.forget());
1576
0
    valueList->AppendCSSValue(closeVal.forget());
1577
0
  }
1578
0
1579
0
  return valueList.forget();
1580
0
}
1581
1582
already_AddRefed<CSSValue>
1583
nsComputedDOMStyle::DoGetOsxFontSmoothing()
1584
0
{
1585
0
  if (nsContentUtils::ShouldResistFingerprinting(
1586
0
        mPresShell->GetPresContext()->GetDocShell()))
1587
0
    return nullptr;
1588
0
1589
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1590
0
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
1591
0
                                               nsCSSProps::kFontSmoothingKTable));
1592
0
  return val.forget();
1593
0
}
1594
1595
// return a value *only* for valid longhand values from CSS 2.1, either
1596
// normal or small-caps only
1597
already_AddRefed<CSSValue>
1598
nsComputedDOMStyle::DoGetFontVariant()
1599
0
{
1600
0
  const nsFont& f = StyleFont()->mFont;
1601
0
1602
0
  // if any of the other font-variant subproperties other than
1603
0
  // font-variant-caps are not normal then can't calculate a computed value
1604
0
  if (f.variantAlternates || f.variantEastAsian || f.variantLigatures ||
1605
0
      f.variantNumeric || f.variantPosition) {
1606
0
    return nullptr;
1607
0
  }
1608
0
1609
0
  nsCSSKeyword keyword;
1610
0
  switch (f.variantCaps) {
1611
0
    case 0:
1612
0
      keyword = eCSSKeyword_normal;
1613
0
      break;
1614
0
    case NS_FONT_VARIANT_CAPS_SMALLCAPS:
1615
0
      keyword = eCSSKeyword_small_caps;
1616
0
      break;
1617
0
    default:
1618
0
      return nullptr;
1619
0
  }
1620
0
1621
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1622
0
  val->SetIdent(keyword);
1623
0
  return val.forget();
1624
0
}
1625
1626
static void
1627
SetValueToCalc(const nsStyleCoord::CalcValue* aCalc,
1628
               nsROCSSPrimitiveValue*         aValue)
1629
0
{
1630
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1631
0
  nsAutoString tmp, result;
1632
0
1633
0
  result.AppendLiteral("calc(");
1634
0
1635
0
  val->SetAppUnits(aCalc->mLength);
1636
0
  val->GetCssText(tmp);
1637
0
  result.Append(tmp);
1638
0
1639
0
  if (aCalc->mHasPercent) {
1640
0
    result.AppendLiteral(" + ");
1641
0
1642
0
    val->SetPercent(aCalc->mPercent);
1643
0
    val->GetCssText(tmp);
1644
0
    result.Append(tmp);
1645
0
  }
1646
0
1647
0
  result.Append(')');
1648
0
1649
0
  aValue->SetString(result); // not really SetString
1650
0
}
1651
1652
static void
1653
AppendCSSGradientLength(const nsStyleCoord&    aValue,
1654
                        nsROCSSPrimitiveValue* aPrimitive,
1655
                        nsAString&             aString)
1656
0
{
1657
0
  nsAutoString tokenString;
1658
0
  if (aValue.IsCalcUnit())
1659
0
    SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
1660
0
  else if (aValue.GetUnit() == eStyleUnit_Coord)
1661
0
    aPrimitive->SetAppUnits(aValue.GetCoordValue());
1662
0
  else
1663
0
    aPrimitive->SetPercent(aValue.GetPercentValue());
1664
0
  aPrimitive->GetCssText(tokenString);
1665
0
  aString.Append(tokenString);
1666
0
}
1667
1668
static void
1669
AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
1670
                               nsAString&             aString,
1671
                               bool&                  aNeedSep)
1672
0
{
1673
0
  // This function only supports box position keywords. Make sure we're not
1674
0
  // calling it with inputs that would have coordinates that aren't
1675
0
  // representable with box-position keywords.
1676
0
  MOZ_ASSERT(aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR &&
1677
0
             !(aGradient->mLegacySyntax && aGradient->mMozLegacySyntax),
1678
0
             "Only call me for linear-gradient and -webkit-linear-gradient");
1679
0
1680
0
  float xValue = aGradient->mBgPosX.GetPercentValue();
1681
0
  float yValue = aGradient->mBgPosY.GetPercentValue();
1682
0
1683
0
  if (xValue == 0.5f &&
1684
0
      yValue == (aGradient->mLegacySyntax ? 0.0f : 1.0f)) {
1685
0
    // omit "to bottom" in modern syntax, "top" in legacy syntax
1686
0
    return;
1687
0
  }
1688
0
  NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
1689
0
1690
0
  if (!aGradient->mLegacySyntax) {
1691
0
    // Modern syntax explicitly includes the word "to". Old syntax does not
1692
0
    // (and is implicitly "from" the given position instead).
1693
0
    aString.AppendLiteral("to ");
1694
0
  }
1695
0
1696
0
  if (xValue == 0.0f) {
1697
0
    aString.AppendLiteral("left");
1698
0
  } else if (xValue == 1.0f) {
1699
0
    aString.AppendLiteral("right");
1700
0
  } else if (xValue != 0.5f) { // do not write "center" keyword
1701
0
    MOZ_ASSERT_UNREACHABLE("invalid box position");
1702
0
  }
1703
0
1704
0
  if (xValue != 0.5f && yValue != 0.5f) {
1705
0
    // We're appending both an x-keyword and a y-keyword.
1706
0
    // Add a space between them here.
1707
0
    aString.AppendLiteral(" ");
1708
0
  }
1709
0
1710
0
  if (yValue == 0.0f) {
1711
0
    aString.AppendLiteral("top");
1712
0
  } else if (yValue == 1.0f) {
1713
0
    aString.AppendLiteral("bottom");
1714
0
  } else if (yValue != 0.5f) { // do not write "center" keyword
1715
0
    MOZ_ASSERT_UNREACHABLE("invalid box position");
1716
0
  }
1717
0
1718
0
1719
0
  aNeedSep = true;
1720
0
}
1721
1722
void
1723
nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
1724
                                         nsAString& aString)
1725
0
{
1726
0
  if (!aGradient->mLegacySyntax) {
1727
0
    aString.Truncate();
1728
0
  } else {
1729
0
    if (aGradient->mMozLegacySyntax) {
1730
0
      aString.AssignLiteral("-moz-");
1731
0
    } else {
1732
0
      aString.AssignLiteral("-webkit-");
1733
0
    }
1734
0
  }
1735
0
  if (aGradient->mRepeating) {
1736
0
    aString.AppendLiteral("repeating-");
1737
0
  }
1738
0
  bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR;
1739
0
  if (isRadial) {
1740
0
    aString.AppendLiteral("radial-gradient(");
1741
0
  } else {
1742
0
    aString.AppendLiteral("linear-gradient(");
1743
0
  }
1744
0
1745
0
  bool needSep = false;
1746
0
  nsAutoString tokenString;
1747
0
  RefPtr<nsROCSSPrimitiveValue> tmpVal = new nsROCSSPrimitiveValue;
1748
0
1749
0
  if (isRadial && !aGradient->mLegacySyntax) {
1750
0
    if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) {
1751
0
      if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1752
0
        aString.AppendLiteral("circle");
1753
0
        needSep = true;
1754
0
      }
1755
0
      if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1756
0
        if (needSep) {
1757
0
          aString.Append(' ');
1758
0
        }
1759
0
        AppendASCIItoUTF16(nsCSSProps::
1760
0
                           ValueToKeyword(aGradient->mSize,
1761
0
                                          nsCSSProps::kRadialGradientSizeKTable),
1762
0
                           aString);
1763
0
        needSep = true;
1764
0
      }
1765
0
    } else {
1766
0
      AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString);
1767
0
      if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1768
0
        aString.Append(' ');
1769
0
        AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString);
1770
0
      }
1771
0
      needSep = true;
1772
0
    }
1773
0
  }
1774
0
  if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
1775
0
    MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None);
1776
0
    if (!isRadial &&
1777
0
        !(aGradient->mLegacySyntax && aGradient->mMozLegacySyntax)) {
1778
0
      // linear-gradient() or -webkit-linear-gradient()
1779
0
      AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
1780
0
    } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent ||
1781
0
               aGradient->mBgPosX.GetPercentValue() != 0.5f ||
1782
0
               aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent ||
1783
0
               aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 0.0f)) {
1784
0
      // [-vendor-]radial-gradient or -moz-linear-gradient, with
1785
0
      // non-default box position, which we output here.
1786
0
      if (isRadial && !aGradient->mLegacySyntax) {
1787
0
        if (needSep) {
1788
0
          aString.Append(' ');
1789
0
        }
1790
0
        aString.AppendLiteral("at ");
1791
0
        needSep = false;
1792
0
      }
1793
0
      AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
1794
0
      if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
1795
0
        aString.Append(' ');
1796
0
        AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
1797
0
      }
1798
0
      needSep = true;
1799
0
    }
1800
0
  }
1801
0
  if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
1802
0
    MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
1803
0
    if (needSep) {
1804
0
      aString.Append(' ');
1805
0
    }
1806
0
    nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString);
1807
0
    needSep = true;
1808
0
  }
1809
0
1810
0
  if (isRadial && aGradient->mLegacySyntax &&
1811
0
      (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
1812
0
       aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
1813
0
    MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
1814
0
    if (needSep) {
1815
0
      aString.AppendLiteral(", ");
1816
0
      needSep = false;
1817
0
    }
1818
0
    if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1819
0
      aString.AppendLiteral("circle");
1820
0
      needSep = true;
1821
0
    }
1822
0
    if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1823
0
      if (needSep) {
1824
0
        aString.Append(' ');
1825
0
      }
1826
0
      AppendASCIItoUTF16(nsCSSProps::
1827
0
                         ValueToKeyword(aGradient->mSize,
1828
0
                                        nsCSSProps::kRadialGradientSizeKTable),
1829
0
                         aString);
1830
0
    }
1831
0
    needSep = true;
1832
0
  }
1833
0
1834
0
1835
0
  // color stops
1836
0
  for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
1837
0
    if (needSep) {
1838
0
      aString.AppendLiteral(", ");
1839
0
    }
1840
0
1841
0
    const auto& stop = aGradient->mStops[i];
1842
0
    if (!stop.mIsInterpolationHint) {
1843
0
      SetValueFromComplexColor(tmpVal, stop.mColor);
1844
0
      tmpVal->GetCssText(tokenString);
1845
0
      aString.Append(tokenString);
1846
0
    }
1847
0
1848
0
    if (stop.mLocation.GetUnit() != eStyleUnit_None) {
1849
0
      if (!stop.mIsInterpolationHint) {
1850
0
        aString.Append(' ');
1851
0
      }
1852
0
      AppendCSSGradientLength(stop.mLocation, tmpVal, aString);
1853
0
    }
1854
0
    needSep = true;
1855
0
  }
1856
0
1857
0
  aString.Append(')');
1858
0
}
1859
1860
// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
1861
void
1862
nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
1863
                                       const nsStyleSides& aCropRect,
1864
                                       nsString& aString)
1865
0
{
1866
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1867
0
1868
0
  // <uri>
1869
0
  RefPtr<nsROCSSPrimitiveValue> valURI = new nsROCSSPrimitiveValue;
1870
0
  valURI->SetURI(aURI);
1871
0
  valueList->AppendCSSValue(valURI.forget());
1872
0
1873
0
  // <top>, <right>, <bottom>, <left>
1874
0
  NS_FOR_CSS_SIDES(side) {
1875
0
    RefPtr<nsROCSSPrimitiveValue> valSide = new nsROCSSPrimitiveValue;
1876
0
    SetValueToCoord(valSide, aCropRect.Get(side), false);
1877
0
    valueList->AppendCSSValue(valSide.forget());
1878
0
  }
1879
0
1880
0
  nsAutoString argumentString;
1881
0
  valueList->GetCssText(argumentString);
1882
0
1883
0
  aString = NS_LITERAL_STRING("-moz-image-rect(") +
1884
0
            argumentString +
1885
0
            NS_LITERAL_STRING(")");
1886
0
}
1887
1888
void
1889
nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
1890
                                         nsROCSSPrimitiveValue* aValue)
1891
0
{
1892
0
  switch (aStyleImage.GetType()) {
1893
0
    case eStyleImageType_Image:
1894
0
    {
1895
0
      nsCOMPtr<nsIURI> uri = aStyleImage.GetImageURI();
1896
0
      if (!uri) {
1897
0
        aValue->SetIdent(eCSSKeyword_none);
1898
0
        break;
1899
0
      }
1900
0
1901
0
      const UniquePtr<nsStyleSides>& cropRect = aStyleImage.GetCropRect();
1902
0
      if (cropRect) {
1903
0
        nsAutoString imageRectString;
1904
0
        GetImageRectString(uri, *cropRect, imageRectString);
1905
0
        aValue->SetString(imageRectString);
1906
0
      } else {
1907
0
        aValue->SetURI(uri);
1908
0
      }
1909
0
      break;
1910
0
    }
1911
0
    case eStyleImageType_Gradient:
1912
0
    {
1913
0
      nsAutoString gradientString;
1914
0
      GetCSSGradientString(aStyleImage.GetGradientData(),
1915
0
                           gradientString);
1916
0
      aValue->SetString(gradientString);
1917
0
      break;
1918
0
    }
1919
0
    case eStyleImageType_Element:
1920
0
    {
1921
0
      nsAutoString elementId;
1922
0
      nsStyleUtil::AppendEscapedCSSIdent(
1923
0
        nsDependentAtomString(aStyleImage.GetElementId()),
1924
0
                              elementId);
1925
0
      nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
1926
0
                                   elementId +
1927
0
                                   NS_LITERAL_STRING(")");
1928
0
      aValue->SetString(elementString);
1929
0
      break;
1930
0
    }
1931
0
    case eStyleImageType_Null:
1932
0
      aValue->SetIdent(eCSSKeyword_none);
1933
0
      break;
1934
0
    case eStyleImageType_URL:
1935
0
      SetValueToURLValue(aStyleImage.GetURLValue(), aValue);
1936
0
      break;
1937
0
    default:
1938
0
      MOZ_ASSERT_UNREACHABLE("unexpected image type");
1939
0
      break;
1940
0
  }
1941
0
}
1942
1943
already_AddRefed<CSSValue>
1944
nsComputedDOMStyle::DoGetImageLayerImage(const nsStyleImageLayers& aLayers)
1945
0
{
1946
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1947
0
1948
0
  for (uint32_t i = 0, i_end = aLayers.mImageCount; i < i_end; ++i) {
1949
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1950
0
1951
0
    SetValueToStyleImage(aLayers.mLayers[i].mImage, val);
1952
0
    valueList->AppendCSSValue(val.forget());
1953
0
  }
1954
0
1955
0
  return valueList.forget();
1956
0
}
1957
1958
already_AddRefed<CSSValue>
1959
nsComputedDOMStyle::DoGetImageLayerPosition(const nsStyleImageLayers& aLayers)
1960
0
{
1961
0
  if (aLayers.mPositionXCount != aLayers.mPositionYCount) {
1962
0
    // No value to return.  We can't express this combination of
1963
0
    // values as a shorthand.
1964
0
    return nullptr;
1965
0
  }
1966
0
1967
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1968
0
  for (uint32_t i = 0, i_end = aLayers.mPositionXCount; i < i_end; ++i) {
1969
0
    RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
1970
0
1971
0
    SetValueToPosition(aLayers.mLayers[i].mPosition, itemList);
1972
0
    valueList->AppendCSSValue(itemList.forget());
1973
0
  }
1974
0
1975
0
  return valueList.forget();
1976
0
}
1977
1978
already_AddRefed<CSSValue>
1979
nsComputedDOMStyle::DoGetImageLayerPositionX(const nsStyleImageLayers& aLayers)
1980
0
{
1981
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1982
0
  for (uint32_t i = 0, i_end = aLayers.mPositionXCount; i < i_end; ++i) {
1983
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1984
0
    SetValueToPositionCoord(aLayers.mLayers[i].mPosition.mXPosition, val);
1985
0
    valueList->AppendCSSValue(val.forget());
1986
0
  }
1987
0
1988
0
  return valueList.forget();
1989
0
}
1990
1991
already_AddRefed<CSSValue>
1992
nsComputedDOMStyle::DoGetImageLayerPositionY(const nsStyleImageLayers& aLayers)
1993
0
{
1994
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1995
0
  for (uint32_t i = 0, i_end = aLayers.mPositionYCount; i < i_end; ++i) {
1996
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1997
0
    SetValueToPositionCoord(aLayers.mLayers[i].mPosition.mYPosition, val);
1998
0
    valueList->AppendCSSValue(val.forget());
1999
0
  }
2000
0
2001
0
  return valueList.forget();
2002
0
}
2003
2004
already_AddRefed<CSSValue>
2005
nsComputedDOMStyle::DoGetImageLayerRepeat(const nsStyleImageLayers& aLayers)
2006
0
{
2007
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
2008
0
2009
0
  for (uint32_t i = 0, i_end = aLayers.mRepeatCount; i < i_end; ++i) {
2010
0
    RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
2011
0
    RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
2012
0
2013
0
    const StyleImageLayerRepeat xRepeat = aLayers.mLayers[i].mRepeat.mXRepeat;
2014
0
    const StyleImageLayerRepeat yRepeat = aLayers.mLayers[i].mRepeat.mYRepeat;
2015
0
2016
0
    bool hasContraction = true;
2017
0
    unsigned contraction;
2018
0
    if (xRepeat == yRepeat) {
2019
0
      contraction = uint8_t(xRepeat);
2020
0
    } else if (xRepeat == StyleImageLayerRepeat::Repeat &&
2021
0
               yRepeat == StyleImageLayerRepeat::NoRepeat) {
2022
0
      contraction = uint8_t(StyleImageLayerRepeat::RepeatX);
2023
0
    } else if (xRepeat == StyleImageLayerRepeat::NoRepeat &&
2024
0
               yRepeat == StyleImageLayerRepeat::Repeat) {
2025
0
      contraction = uint8_t(StyleImageLayerRepeat::RepeatY);
2026
0
    } else {
2027
0
      hasContraction = false;
2028
0
    }
2029
0
2030
0
    RefPtr<nsROCSSPrimitiveValue> valY;
2031
0
    if (hasContraction) {
2032
0
      valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
2033
0
                                         nsCSSProps::kImageLayerRepeatKTable));
2034
0
    } else {
2035
0
      valY = new nsROCSSPrimitiveValue;
2036
0
2037
0
      valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
2038
0
                                          nsCSSProps::kImageLayerRepeatKTable));
2039
0
      valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
2040
0
                                          nsCSSProps::kImageLayerRepeatKTable));
2041
0
    }
2042
0
    itemList->AppendCSSValue(valX.forget());
2043
0
    if (valY) {
2044
0
      itemList->AppendCSSValue(valY.forget());
2045
0
    }
2046
0
    valueList->AppendCSSValue(itemList.forget());
2047
0
  }
2048
0
2049
0
  return valueList.forget();
2050
0
}
2051
2052
already_AddRefed<CSSValue>
2053
nsComputedDOMStyle::DoGetImageLayerSize(const nsStyleImageLayers& aLayers)
2054
0
{
2055
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
2056
0
2057
0
  for (uint32_t i = 0, i_end = aLayers.mSizeCount; i < i_end; ++i) {
2058
0
    const nsStyleImageLayers::Size &size = aLayers.mLayers[i].mSize;
2059
0
2060
0
    switch (size.mWidthType) {
2061
0
      case nsStyleImageLayers::Size::eContain:
2062
0
      case nsStyleImageLayers::Size::eCover: {
2063
0
        MOZ_ASSERT(size.mWidthType == size.mHeightType,
2064
0
                   "unsynced types");
2065
0
        nsCSSKeyword keyword = size.mWidthType == nsStyleImageLayers::Size::eContain
2066
0
                             ? eCSSKeyword_contain
2067
0
                             : eCSSKeyword_cover;
2068
0
        RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2069
0
        val->SetIdent(keyword);
2070
0
        valueList->AppendCSSValue(val.forget());
2071
0
        break;
2072
0
      }
2073
0
      default: {
2074
0
        RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
2075
0
2076
0
        RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
2077
0
        RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
2078
0
2079
0
        if (size.mWidthType == nsStyleImageLayers::Size::eAuto) {
2080
0
          valX->SetIdent(eCSSKeyword_auto);
2081
0
        } else {
2082
0
          MOZ_ASSERT(size.mWidthType ==
2083
0
                       nsStyleImageLayers::Size::eLengthPercentage,
2084
0
                     "bad mWidthType");
2085
0
          if (!size.mWidth.mHasPercent &&
2086
0
              // negative values must have come from calc()
2087
0
              size.mWidth.mLength >= 0) {
2088
0
            MOZ_ASSERT(size.mWidth.mPercent == 0.0f,
2089
0
                       "Shouldn't have mPercent");
2090
0
            valX->SetAppUnits(size.mWidth.mLength);
2091
0
          } else if (size.mWidth.mLength == 0 &&
2092
0
                     // negative values must have come from calc()
2093
0
                     size.mWidth.mPercent >= 0.0f) {
2094
0
            valX->SetPercent(size.mWidth.mPercent);
2095
0
          } else {
2096
0
            SetValueToCalc(&size.mWidth, valX);
2097
0
          }
2098
0
        }
2099
0
2100
0
        if (size.mHeightType == nsStyleImageLayers::Size::eAuto) {
2101
0
          valY->SetIdent(eCSSKeyword_auto);
2102
0
        } else {
2103
0
          MOZ_ASSERT(size.mHeightType ==
2104
0
                       nsStyleImageLayers::Size::eLengthPercentage,
2105
0
                     "bad mHeightType");
2106
0
          if (!size.mHeight.mHasPercent &&
2107
0
              // negative values must have come from calc()
2108
0
              size.mHeight.mLength >= 0) {
2109
0
            MOZ_ASSERT(size.mHeight.mPercent == 0.0f,
2110
0
                       "Shouldn't have mPercent");
2111
0
            valY->SetAppUnits(size.mHeight.mLength);
2112
0
          } else if (size.mHeight.mLength == 0 &&
2113
0
                     // negative values must have come from calc()
2114
0
                     size.mHeight.mPercent >= 0.0f) {
2115
0
            valY->SetPercent(size.mHeight.mPercent);
2116
0
          } else {
2117
0
            SetValueToCalc(&size.mHeight, valY);
2118
0
          }
2119
0
        }
2120
0
        itemList->AppendCSSValue(valX.forget());
2121
0
        itemList->AppendCSSValue(valY.forget());
2122
0
        valueList->AppendCSSValue(itemList.forget());
2123
0
        break;
2124
0
      }
2125
0
    }
2126
0
  }
2127
0
2128
0
  return valueList.forget();
2129
0
}
2130
2131
already_AddRefed<CSSValue>
2132
nsComputedDOMStyle::DoGetBackgroundImage()
2133
0
{
2134
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2135
0
  return DoGetImageLayerImage(layers);
2136
0
}
2137
2138
void
2139
nsComputedDOMStyle::SetValueToPositionCoord(
2140
    const Position::Coord& aCoord,
2141
    nsROCSSPrimitiveValue* aValue)
2142
0
{
2143
0
  if (!aCoord.mHasPercent) {
2144
0
    MOZ_ASSERT(aCoord.mPercent == 0.0f,
2145
0
               "Shouldn't have mPercent!");
2146
0
    aValue->SetAppUnits(aCoord.mLength);
2147
0
  } else if (aCoord.mLength == 0) {
2148
0
    aValue->SetPercent(aCoord.mPercent);
2149
0
  } else {
2150
0
    SetValueToCalc(&aCoord, aValue);
2151
0
  }
2152
0
}
2153
2154
void
2155
nsComputedDOMStyle::SetValueToPosition(
2156
    const Position& aPosition,
2157
    nsDOMCSSValueList* aValueList)
2158
0
{
2159
0
  RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
2160
0
  SetValueToPositionCoord(aPosition.mXPosition, valX);
2161
0
  aValueList->AppendCSSValue(valX.forget());
2162
0
2163
0
  RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
2164
0
  SetValueToPositionCoord(aPosition.mYPosition, valY);
2165
0
  aValueList->AppendCSSValue(valY.forget());
2166
0
}
2167
2168
2169
void
2170
nsComputedDOMStyle::SetValueToURLValue(const css::URLValueData* aURL,
2171
                                       nsROCSSPrimitiveValue* aValue)
2172
0
{
2173
0
  if (!aURL) {
2174
0
    aValue->SetIdent(eCSSKeyword_none);
2175
0
    return;
2176
0
  }
2177
0
2178
0
  // If we have a usable nsIURI in the URLValueData, and the url() wasn't
2179
0
  // a fragment-only URL, serialize the nsIURI.
2180
0
  if (!aURL->IsLocalRef()) {
2181
0
    if (nsIURI* uri = aURL->GetURI()) {
2182
0
      aValue->SetURI(uri);
2183
0
      return;
2184
0
    }
2185
0
  }
2186
0
2187
0
  // Otherwise, serialize the specified URL value.
2188
0
  nsAutoString source;
2189
0
  aURL->GetSourceString(source);
2190
0
2191
0
  nsAutoString url;
2192
0
  url.AppendLiteral(u"url(");
2193
0
  nsStyleUtil::AppendEscapedCSSString(source, url, '"');
2194
0
  url.Append(')');
2195
0
  aValue->SetString(url);
2196
0
}
2197
2198
already_AddRefed<CSSValue>
2199
nsComputedDOMStyle::DoGetBackgroundPosition()
2200
0
{
2201
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2202
0
  return DoGetImageLayerPosition(layers);
2203
0
}
2204
2205
already_AddRefed<CSSValue>
2206
nsComputedDOMStyle::DoGetBackgroundPositionX()
2207
0
{
2208
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2209
0
  return DoGetImageLayerPositionX(layers);
2210
0
}
2211
2212
already_AddRefed<CSSValue>
2213
nsComputedDOMStyle::DoGetBackgroundPositionY()
2214
0
{
2215
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2216
0
  return DoGetImageLayerPositionY(layers);
2217
0
}
2218
2219
already_AddRefed<CSSValue>
2220
nsComputedDOMStyle::DoGetBackgroundRepeat()
2221
0
{
2222
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2223
0
  return DoGetImageLayerRepeat(layers);
2224
0
}
2225
2226
already_AddRefed<CSSValue>
2227
nsComputedDOMStyle::DoGetBackgroundSize()
2228
0
{
2229
0
  const nsStyleImageLayers& layers = StyleBackground()->mImage;
2230
0
  return DoGetImageLayerSize(layers);
2231
0
}
2232
2233
already_AddRefed<CSSValue>
2234
nsComputedDOMStyle::DoGetGridTemplateAreas()
2235
0
{
2236
0
  const css::GridTemplateAreasValue* areas =
2237
0
    StylePosition()->mGridTemplateAreas;
2238
0
  if (!areas) {
2239
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2240
0
    val->SetIdent(eCSSKeyword_none);
2241
0
    return val.forget();
2242
0
  }
2243
0
2244
0
  MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
2245
0
             "Unexpected empty array in GridTemplateAreasValue");
2246
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2247
0
  for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
2248
0
    nsAutoString str;
2249
0
    nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
2250
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2251
0
    val->SetString(str);
2252
0
    valueList->AppendCSSValue(val.forget());
2253
0
  }
2254
0
  return valueList.forget();
2255
0
}
2256
2257
void
2258
nsComputedDOMStyle::AppendGridLineNames(nsString& aResult,
2259
                                        const nsTArray<nsString>& aLineNames)
2260
0
{
2261
0
  uint32_t numLines = aLineNames.Length();
2262
0
  if (numLines == 0) {
2263
0
    return;
2264
0
  }
2265
0
  for (uint32_t i = 0;;) {
2266
0
    nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], aResult);
2267
0
    if (++i == numLines) {
2268
0
      break;
2269
0
    }
2270
0
    aResult.Append(' ');
2271
0
  }
2272
0
}
2273
2274
void
2275
nsComputedDOMStyle::AppendGridLineNames(nsDOMCSSValueList* aValueList,
2276
                                        const nsTArray<nsString>& aLineNames,
2277
                                        bool aSuppressEmptyList)
2278
0
{
2279
0
  if (aLineNames.IsEmpty() && aSuppressEmptyList) {
2280
0
    return;
2281
0
  }
2282
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2283
0
  nsAutoString lineNamesString;
2284
0
  lineNamesString.Assign('[');
2285
0
  AppendGridLineNames(lineNamesString, aLineNames);
2286
0
  lineNamesString.Append(']');
2287
0
  val->SetString(lineNamesString);
2288
0
  aValueList->AppendCSSValue(val.forget());
2289
0
}
2290
2291
void
2292
nsComputedDOMStyle::AppendGridLineNames(nsDOMCSSValueList* aValueList,
2293
                                        const nsTArray<nsString>& aLineNames1,
2294
                                        const nsTArray<nsString>& aLineNames2)
2295
0
{
2296
0
  if (aLineNames1.IsEmpty() && aLineNames2.IsEmpty()) {
2297
0
    return;
2298
0
  }
2299
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2300
0
  nsAutoString lineNamesString;
2301
0
  lineNamesString.Assign('[');
2302
0
  if (!aLineNames1.IsEmpty()) {
2303
0
    AppendGridLineNames(lineNamesString, aLineNames1);
2304
0
  }
2305
0
  if (!aLineNames2.IsEmpty()) {
2306
0
    if (!aLineNames1.IsEmpty()) {
2307
0
      lineNamesString.Append(' ');
2308
0
    }
2309
0
    AppendGridLineNames(lineNamesString, aLineNames2);
2310
0
  }
2311
0
  lineNamesString.Append(']');
2312
0
  val->SetString(lineNamesString);
2313
0
  aValueList->AppendCSSValue(val.forget());
2314
0
}
2315
2316
already_AddRefed<CSSValue>
2317
nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
2318
                                     const nsStyleCoord& aMaxValue)
2319
0
{
2320
0
  if (aMinValue.GetUnit() == eStyleUnit_None) {
2321
0
    // A fit-content() function.
2322
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2323
0
    nsAutoString argumentStr, fitContentStr;
2324
0
    fitContentStr.AppendLiteral("fit-content(");
2325
0
    MOZ_ASSERT(aMaxValue.IsCoordPercentCalcUnit(),
2326
0
               "unexpected unit for fit-content() argument value");
2327
0
    SetValueToCoord(val, aMaxValue, true);
2328
0
    val->GetCssText(argumentStr);
2329
0
    fitContentStr.Append(argumentStr);
2330
0
    fitContentStr.Append(char16_t(')'));
2331
0
    val->SetString(fitContentStr);
2332
0
    return val.forget();
2333
0
  }
2334
0
2335
0
  if (aMinValue == aMaxValue) {
2336
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2337
0
    SetValueToCoord(val, aMinValue, true,
2338
0
                    nullptr, nsCSSProps::kGridTrackBreadthKTable);
2339
0
    return val.forget();
2340
0
  }
2341
0
2342
0
  // minmax(auto, <flex>) is equivalent to (and is our internal representation
2343
0
  // of) <flex>, and both compute to <flex>
2344
0
  if (aMinValue.GetUnit() == eStyleUnit_Auto &&
2345
0
      aMaxValue.GetUnit() == eStyleUnit_FlexFraction) {
2346
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2347
0
    SetValueToCoord(val, aMaxValue, true);
2348
0
    return val.forget();
2349
0
  }
2350
0
2351
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2352
0
  nsAutoString argumentStr, minmaxStr;
2353
0
  minmaxStr.AppendLiteral("minmax(");
2354
0
2355
0
  SetValueToCoord(val, aMinValue, true,
2356
0
                  nullptr, nsCSSProps::kGridTrackBreadthKTable);
2357
0
  val->GetCssText(argumentStr);
2358
0
  minmaxStr.Append(argumentStr);
2359
0
2360
0
  minmaxStr.AppendLiteral(", ");
2361
0
2362
0
  SetValueToCoord(val, aMaxValue, true,
2363
0
                  nullptr, nsCSSProps::kGridTrackBreadthKTable);
2364
0
  val->GetCssText(argumentStr);
2365
0
  minmaxStr.Append(argumentStr);
2366
0
2367
0
  minmaxStr.Append(char16_t(')'));
2368
0
  val->SetString(minmaxStr);
2369
0
  return val.forget();
2370
0
}
2371
2372
already_AddRefed<CSSValue>
2373
nsComputedDOMStyle::GetGridTemplateColumnsRows(
2374
  const nsStyleGridTemplate&   aTrackList,
2375
  const ComputedGridTrackInfo* aTrackInfo)
2376
0
{
2377
0
  if (aTrackList.mIsSubgrid) {
2378
0
    // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311)
2379
0
    NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
2380
0
                 aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
2381
0
                 "Unexpected sizing functions with subgrid");
2382
0
    RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2383
0
2384
0
    RefPtr<nsROCSSPrimitiveValue> subgridKeyword = new nsROCSSPrimitiveValue;
2385
0
    subgridKeyword->SetIdent(eCSSKeyword_subgrid);
2386
0
    valueList->AppendCSSValue(subgridKeyword.forget());
2387
0
2388
0
    for (uint32_t i = 0, len = aTrackList.mLineNameLists.Length(); ; ++i) {
2389
0
      if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
2390
0
        MOZ_ASSERT(aTrackList.mIsAutoFill, "subgrid can only have 'auto-fill'");
2391
0
        MOZ_ASSERT(aTrackList.mRepeatAutoLineNameListAfter.IsEmpty(),
2392
0
                   "mRepeatAutoLineNameListAfter isn't used for subgrid");
2393
0
        RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
2394
0
        start->SetString(NS_LITERAL_STRING("repeat(auto-fill,"));
2395
0
        valueList->AppendCSSValue(start.forget());
2396
0
        AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore,
2397
0
                            /*aSuppressEmptyList*/ false);
2398
0
        RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
2399
0
        end->SetString(NS_LITERAL_STRING(")"));
2400
0
        valueList->AppendCSSValue(end.forget());
2401
0
      }
2402
0
      if (i == len) {
2403
0
        break;
2404
0
      }
2405
0
      AppendGridLineNames(valueList, aTrackList.mLineNameLists[i],
2406
0
                          /*aSuppressEmptyList*/ false);
2407
0
    }
2408
0
    return valueList.forget();
2409
0
  }
2410
0
2411
0
  uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
2412
0
  MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
2413
0
             "Different number of min and max track sizing functions");
2414
0
  if (aTrackInfo) {
2415
0
    DebugOnly<bool> isAutoFill =
2416
0
      aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill;
2417
0
    DebugOnly<bool> isAutoFit =
2418
0
      aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill;
2419
0
    DebugOnly<uint32_t> numExplicitTracks = aTrackInfo->mNumExplicitTracks;
2420
0
    MOZ_ASSERT(numExplicitTracks == numSizes ||
2421
0
               (isAutoFill && numExplicitTracks >= numSizes) ||
2422
0
               (isAutoFit && numExplicitTracks + 1 >= numSizes),
2423
0
               "expected all explicit tracks (or possibly one less, if there's "
2424
0
               "an 'auto-fit' track, since that can collapse away)");
2425
0
    numSizes = aTrackInfo->mSizes.Length();
2426
0
  }
2427
0
2428
0
  // An empty <track-list> without repeats is represented as "none" in syntax.
2429
0
  if (numSizes == 0 && !aTrackList.HasRepeatAuto()) {
2430
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2431
0
    val->SetIdent(eCSSKeyword_none);
2432
0
    return val.forget();
2433
0
  }
2434
0
2435
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2436
0
  if (aTrackInfo) {
2437
0
    // We've done layout on the grid and have resolved the sizes of its tracks,
2438
0
    // so we'll return those sizes here.  The grid spec says we MAY use
2439
0
    // repeat(<positive-integer>, Npx) here for consecutive tracks with the same
2440
0
    // size, but that doesn't seem worth doing since even for repeat(auto-*)
2441
0
    // the resolved size might differ for the repeated tracks.
2442
0
    const nsTArray<nscoord>& trackSizes = aTrackInfo->mSizes;
2443
0
    const uint32_t numExplicitTracks = aTrackInfo->mNumExplicitTracks;
2444
0
    const uint32_t numLeadingImplicitTracks = aTrackInfo->mNumLeadingImplicitTracks;
2445
0
    MOZ_ASSERT(numSizes >= numLeadingImplicitTracks + numExplicitTracks);
2446
0
2447
0
    // Add any leading implicit tracks.
2448
0
    for (uint32_t i = 0; i < numLeadingImplicitTracks; ++i) {
2449
0
      RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2450
0
      val->SetAppUnits(trackSizes[i]);
2451
0
      valueList->AppendCSSValue(val.forget());
2452
0
    }
2453
0
2454
0
    // Then add any explicit tracks and removed auto-fit tracks.
2455
0
    if (numExplicitTracks || aTrackList.HasRepeatAuto()) {
2456
0
      int32_t endOfRepeat = 0;  // first index after any repeat() tracks
2457
0
      int32_t offsetToLastRepeat = 0;
2458
0
      if (aTrackList.HasRepeatAuto()) {
2459
0
        // offsetToLastRepeat is -1 if all repeat(auto-fit) tracks are empty
2460
0
        offsetToLastRepeat = numExplicitTracks + 1 - aTrackList.mLineNameLists.Length();
2461
0
        endOfRepeat = aTrackList.mRepeatAutoIndex + offsetToLastRepeat + 1;
2462
0
      }
2463
0
2464
0
      uint32_t repeatIndex = 0;
2465
0
      uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
2466
0
      enum LinePlacement { LinesPrecede, LinesFollow, LinesBetween };
2467
0
      auto AppendRemovedAutoFits = [this, aTrackInfo, &valueList, aTrackList,
2468
0
                                    &repeatIndex,
2469
0
                                    numRepeatTracks](LinePlacement aPlacement)
2470
0
      {
2471
0
        // Add in removed auto-fit tracks and lines here, if necessary
2472
0
        bool atLeastOneTrackReported = false;
2473
0
        while (repeatIndex < numRepeatTracks &&
2474
0
             aTrackInfo->mRemovedRepeatTracks[repeatIndex]) {
2475
0
          if ((aPlacement == LinesPrecede) ||
2476
0
              ((aPlacement == LinesBetween) && atLeastOneTrackReported)) {
2477
0
            // Precede it with the lines between repeats.
2478
0
            AppendGridLineNames(valueList,
2479
0
                                aTrackList.mRepeatAutoLineNameListAfter,
2480
0
                                aTrackList.mRepeatAutoLineNameListBefore);
2481
0
          }
2482
0
2483
0
          // Removed 'auto-fit' tracks are reported as 0px.
2484
0
          RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2485
0
          val->SetAppUnits(0);
2486
0
          valueList->AppendCSSValue(val.forget());
2487
0
          atLeastOneTrackReported = true;
2488
0
2489
0
          if (aPlacement == LinesFollow) {
2490
0
            // Follow it with the lines between repeats.
2491
0
            AppendGridLineNames(valueList,
2492
0
                                aTrackList.mRepeatAutoLineNameListAfter,
2493
0
                                aTrackList.mRepeatAutoLineNameListBefore);
2494
0
          }
2495
0
          repeatIndex++;
2496
0
        }
2497
0
        repeatIndex++;
2498
0
      };
2499
0
2500
0
      for (int32_t i = 0;; i++) {
2501
0
        if (aTrackList.HasRepeatAuto()) {
2502
0
          if (i == aTrackList.mRepeatAutoIndex) {
2503
0
            const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
2504
0
            if (i == endOfRepeat) {
2505
0
              // All auto-fit tracks are empty, but we report them anyway.
2506
0
              AppendGridLineNames(valueList, lineNames,
2507
0
                                  aTrackList.mRepeatAutoLineNameListBefore);
2508
0
2509
0
              AppendRemovedAutoFits(LinesBetween);
2510
0
2511
0
              AppendGridLineNames(valueList,
2512
0
                                  aTrackList.mRepeatAutoLineNameListAfter,
2513
0
                                  aTrackList.mLineNameLists[i + 1]);
2514
0
            } else {
2515
0
              AppendGridLineNames(valueList, lineNames,
2516
0
                                  aTrackList.mRepeatAutoLineNameListBefore);
2517
0
              AppendRemovedAutoFits(LinesFollow);
2518
0
            }
2519
0
          } else if (i == endOfRepeat) {
2520
0
            // Before appending the last line, finish off any removed auto-fits.
2521
0
            AppendRemovedAutoFits(LinesPrecede);
2522
0
2523
0
            const nsTArray<nsString>& lineNames =
2524
0
              aTrackList.mLineNameLists[aTrackList.mRepeatAutoIndex + 1];
2525
0
            AppendGridLineNames(valueList,
2526
0
                                aTrackList.mRepeatAutoLineNameListAfter,
2527
0
                                lineNames);
2528
0
          } else if (i > aTrackList.mRepeatAutoIndex && i < endOfRepeat) {
2529
0
            AppendGridLineNames(valueList,
2530
0
                                aTrackList.mRepeatAutoLineNameListAfter,
2531
0
                                aTrackList.mRepeatAutoLineNameListBefore);
2532
0
            AppendRemovedAutoFits(LinesFollow);
2533
0
          } else {
2534
0
            uint32_t j = i > endOfRepeat ? i - offsetToLastRepeat : i;
2535
0
            const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[j];
2536
0
            AppendGridLineNames(valueList, lineNames);
2537
0
          }
2538
0
        } else {
2539
0
          const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
2540
0
          AppendGridLineNames(valueList, lineNames);
2541
0
        }
2542
0
        if (uint32_t(i) == numExplicitTracks) {
2543
0
          break;
2544
0
        }
2545
0
        RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2546
0
        val->SetAppUnits(trackSizes[i + numLeadingImplicitTracks]);
2547
0
        valueList->AppendCSSValue(val.forget());
2548
0
      }
2549
0
    }
2550
0
2551
0
    // Add any trailing implicit tracks.
2552
0
    for (uint32_t i = numLeadingImplicitTracks + numExplicitTracks;
2553
0
         i < numSizes; ++i) {
2554
0
      RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2555
0
      val->SetAppUnits(trackSizes[i]);
2556
0
      valueList->AppendCSSValue(val.forget());
2557
0
    }
2558
0
  } else {
2559
0
    // We don't have a frame.  So, we'll just return a serialization of
2560
0
    // the tracks from the style (without resolved sizes).
2561
0
    for (uint32_t i = 0;; i++) {
2562
0
      const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
2563
0
      if (!lineNames.IsEmpty()) {
2564
0
        AppendGridLineNames(valueList, lineNames);
2565
0
      }
2566
0
      if (i == numSizes) {
2567
0
        break;
2568
0
      }
2569
0
      if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
2570
0
        RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
2571
0
        start->SetString(aTrackList.mIsAutoFill ? NS_LITERAL_STRING("repeat(auto-fill,")
2572
0
                                                : NS_LITERAL_STRING("repeat(auto-fit,"));
2573
0
        valueList->AppendCSSValue(start.forget());
2574
0
        if (!aTrackList.mRepeatAutoLineNameListBefore.IsEmpty()) {
2575
0
          AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore);
2576
0
        }
2577
0
2578
0
        valueList->AppendCSSValue(
2579
0
          GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
2580
0
                           aTrackList.mMaxTrackSizingFunctions[i]));
2581
0
        if (!aTrackList.mRepeatAutoLineNameListAfter.IsEmpty()) {
2582
0
          AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListAfter);
2583
0
        }
2584
0
        RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
2585
0
        end->SetString(NS_LITERAL_STRING(")"));
2586
0
        valueList->AppendCSSValue(end.forget());
2587
0
      } else {
2588
0
        valueList->AppendCSSValue(
2589
0
          GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
2590
0
                           aTrackList.mMaxTrackSizingFunctions[i]));
2591
0
      }
2592
0
    }
2593
0
  }
2594
0
2595
0
  return valueList.forget();
2596
0
}
2597
2598
already_AddRefed<CSSValue>
2599
nsComputedDOMStyle::DoGetGridAutoFlow()
2600
0
{
2601
0
  nsAutoString str;
2602
0
  nsStyleUtil::AppendBitmaskCSSValue(nsCSSProps::kGridAutoFlowKTable,
2603
0
                                     StylePosition()->mGridAutoFlow,
2604
0
                                     NS_STYLE_GRID_AUTO_FLOW_ROW,
2605
0
                                     NS_STYLE_GRID_AUTO_FLOW_DENSE,
2606
0
                                     str);
2607
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2608
0
  val->SetString(str);
2609
0
  return val.forget();
2610
0
}
2611
2612
already_AddRefed<CSSValue>
2613
nsComputedDOMStyle::DoGetGridAutoColumns()
2614
0
{
2615
0
  return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
2616
0
                          StylePosition()->mGridAutoColumnsMax);
2617
0
}
2618
2619
already_AddRefed<CSSValue>
2620
nsComputedDOMStyle::DoGetGridAutoRows()
2621
0
{
2622
0
  return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
2623
0
                          StylePosition()->mGridAutoRowsMax);
2624
0
}
2625
2626
already_AddRefed<CSSValue>
2627
nsComputedDOMStyle::DoGetGridTemplateColumns()
2628
0
{
2629
0
  const ComputedGridTrackInfo* info = nullptr;
2630
0
2631
0
  nsGridContainerFrame* gridFrame =
2632
0
    nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame);
2633
0
2634
0
  if (gridFrame) {
2635
0
    info = gridFrame->GetComputedTemplateColumns();
2636
0
  }
2637
0
2638
0
  return GetGridTemplateColumnsRows(
2639
0
    StylePosition()->GridTemplateColumns(), info);
2640
0
}
2641
2642
already_AddRefed<CSSValue>
2643
nsComputedDOMStyle::DoGetGridTemplateRows()
2644
0
{
2645
0
  const ComputedGridTrackInfo* info = nullptr;
2646
0
2647
0
  nsGridContainerFrame* gridFrame =
2648
0
    nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame);
2649
0
2650
0
  if (gridFrame) {
2651
0
    info = gridFrame->GetComputedTemplateRows();
2652
0
  }
2653
0
2654
0
  return GetGridTemplateColumnsRows(
2655
0
    StylePosition()->GridTemplateRows(), info);
2656
0
}
2657
2658
already_AddRefed<CSSValue>
2659
nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
2660
0
{
2661
0
  if (aGridLine.IsAuto()) {
2662
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2663
0
    val->SetIdent(eCSSKeyword_auto);
2664
0
    return val.forget();
2665
0
  }
2666
0
2667
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2668
0
2669
0
  if (aGridLine.mHasSpan) {
2670
0
    RefPtr<nsROCSSPrimitiveValue> span = new nsROCSSPrimitiveValue;
2671
0
    span->SetIdent(eCSSKeyword_span);
2672
0
    valueList->AppendCSSValue(span.forget());
2673
0
  }
2674
0
2675
0
  if (aGridLine.mInteger != 0) {
2676
0
    RefPtr<nsROCSSPrimitiveValue> integer = new nsROCSSPrimitiveValue;
2677
0
    integer->SetNumber(aGridLine.mInteger);
2678
0
    valueList->AppendCSSValue(integer.forget());
2679
0
  }
2680
0
2681
0
  if (!aGridLine.mLineName.IsEmpty()) {
2682
0
    RefPtr<nsROCSSPrimitiveValue> lineName = new nsROCSSPrimitiveValue;
2683
0
    nsString escapedLineName;
2684
0
    nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
2685
0
    lineName->SetString(escapedLineName);
2686
0
    valueList->AppendCSSValue(lineName.forget());
2687
0
  }
2688
0
2689
0
  NS_ASSERTION(valueList->Length() > 0,
2690
0
               "Should have appended at least one value");
2691
0
  return valueList.forget();
2692
0
}
2693
2694
already_AddRefed<CSSValue>
2695
nsComputedDOMStyle::DoGetGridColumnStart()
2696
0
{
2697
0
  return GetGridLine(StylePosition()->mGridColumnStart);
2698
0
}
2699
2700
already_AddRefed<CSSValue>
2701
nsComputedDOMStyle::DoGetGridColumnEnd()
2702
0
{
2703
0
  return GetGridLine(StylePosition()->mGridColumnEnd);
2704
0
}
2705
2706
already_AddRefed<CSSValue>
2707
nsComputedDOMStyle::DoGetGridRowStart()
2708
0
{
2709
0
  return GetGridLine(StylePosition()->mGridRowStart);
2710
0
}
2711
2712
already_AddRefed<CSSValue>
2713
nsComputedDOMStyle::DoGetGridRowEnd()
2714
0
{
2715
0
  return GetGridLine(StylePosition()->mGridRowEnd);
2716
0
}
2717
2718
already_AddRefed<CSSValue>
2719
nsComputedDOMStyle::DoGetColumnGap()
2720
0
{
2721
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2722
0
  const auto& columnGap = StylePosition()->mColumnGap;
2723
0
  if (columnGap.GetUnit() == eStyleUnit_Normal) {
2724
0
    val->SetIdent(eCSSKeyword_normal);
2725
0
  } else {
2726
0
    SetValueToCoord(val, columnGap, true);
2727
0
  }
2728
0
  return val.forget();
2729
0
}
2730
2731
already_AddRefed<CSSValue>
2732
nsComputedDOMStyle::DoGetRowGap()
2733
0
{
2734
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2735
0
  const auto& rowGap = StylePosition()->mRowGap;
2736
0
  if (rowGap.GetUnit() == eStyleUnit_Normal) {
2737
0
    val->SetIdent(eCSSKeyword_normal);
2738
0
  } else {
2739
0
    SetValueToCoord(val, rowGap, true);
2740
0
  }
2741
0
  return val.forget();
2742
0
}
2743
2744
already_AddRefed<CSSValue>
2745
nsComputedDOMStyle::DoGetPaddingTop()
2746
0
{
2747
0
  return GetPaddingWidthFor(eSideTop);
2748
0
}
2749
2750
already_AddRefed<CSSValue>
2751
nsComputedDOMStyle::DoGetPaddingBottom()
2752
0
{
2753
0
  return GetPaddingWidthFor(eSideBottom);
2754
0
}
2755
2756
already_AddRefed<CSSValue>
2757
nsComputedDOMStyle::DoGetPaddingLeft()
2758
0
{
2759
0
  return GetPaddingWidthFor(eSideLeft);
2760
0
}
2761
2762
already_AddRefed<CSSValue>
2763
nsComputedDOMStyle::DoGetPaddingRight()
2764
0
{
2765
0
  return GetPaddingWidthFor(eSideRight);
2766
0
}
2767
2768
already_AddRefed<CSSValue>
2769
nsComputedDOMStyle::DoGetBorderSpacing()
2770
0
{
2771
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2772
0
2773
0
  RefPtr<nsROCSSPrimitiveValue> xSpacing = new nsROCSSPrimitiveValue;
2774
0
  RefPtr<nsROCSSPrimitiveValue> ySpacing = new nsROCSSPrimitiveValue;
2775
0
2776
0
  const nsStyleTableBorder *border = StyleTableBorder();
2777
0
  xSpacing->SetAppUnits(border->mBorderSpacingCol);
2778
0
  ySpacing->SetAppUnits(border->mBorderSpacingRow);
2779
0
2780
0
  valueList->AppendCSSValue(xSpacing.forget());
2781
0
  valueList->AppendCSSValue(ySpacing.forget());
2782
0
2783
0
  return valueList.forget();
2784
0
}
2785
2786
already_AddRefed<CSSValue>
2787
nsComputedDOMStyle::DoGetBorderTopStyle()
2788
0
{
2789
0
  return GetBorderStyleFor(eSideTop);
2790
0
}
2791
2792
already_AddRefed<CSSValue>
2793
nsComputedDOMStyle::DoGetBorderBottomStyle()
2794
0
{
2795
0
  return GetBorderStyleFor(eSideBottom);
2796
0
}
2797
2798
already_AddRefed<CSSValue>
2799
nsComputedDOMStyle::DoGetBorderLeftStyle()
2800
0
{
2801
0
  return GetBorderStyleFor(eSideLeft);
2802
0
}
2803
2804
already_AddRefed<CSSValue>
2805
nsComputedDOMStyle::DoGetBorderRightStyle()
2806
0
{
2807
0
  return GetBorderStyleFor(eSideRight);
2808
0
}
2809
2810
already_AddRefed<CSSValue>
2811
nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
2812
0
{
2813
0
  return GetEllipseRadii(StyleBorder()->mBorderRadius,
2814
0
                         eCornerBottomLeft);
2815
0
}
2816
2817
already_AddRefed<CSSValue>
2818
nsComputedDOMStyle::DoGetBorderBottomRightRadius()
2819
0
{
2820
0
  return GetEllipseRadii(StyleBorder()->mBorderRadius,
2821
0
                         eCornerBottomRight);
2822
0
}
2823
2824
already_AddRefed<CSSValue>
2825
nsComputedDOMStyle::DoGetBorderTopLeftRadius()
2826
0
{
2827
0
  return GetEllipseRadii(StyleBorder()->mBorderRadius,
2828
0
                         eCornerTopLeft);
2829
0
}
2830
2831
already_AddRefed<CSSValue>
2832
nsComputedDOMStyle::DoGetBorderTopRightRadius()
2833
0
{
2834
0
  return GetEllipseRadii(StyleBorder()->mBorderRadius,
2835
0
                         eCornerTopRight);
2836
0
}
2837
2838
already_AddRefed<CSSValue>
2839
nsComputedDOMStyle::DoGetBorderTopWidth()
2840
0
{
2841
0
  return GetBorderWidthFor(eSideTop);
2842
0
}
2843
2844
already_AddRefed<CSSValue>
2845
nsComputedDOMStyle::DoGetBorderBottomWidth()
2846
0
{
2847
0
  return GetBorderWidthFor(eSideBottom);
2848
0
}
2849
2850
already_AddRefed<CSSValue>
2851
nsComputedDOMStyle::DoGetBorderLeftWidth()
2852
0
{
2853
0
  return GetBorderWidthFor(eSideLeft);
2854
0
}
2855
2856
already_AddRefed<CSSValue>
2857
nsComputedDOMStyle::DoGetBorderRightWidth()
2858
0
{
2859
0
  return GetBorderWidthFor(eSideRight);
2860
0
}
2861
2862
already_AddRefed<CSSValue>
2863
nsComputedDOMStyle::DoGetMarginTopWidth()
2864
0
{
2865
0
  return GetMarginWidthFor(eSideTop);
2866
0
}
2867
2868
already_AddRefed<CSSValue>
2869
nsComputedDOMStyle::DoGetMarginBottomWidth()
2870
0
{
2871
0
  return GetMarginWidthFor(eSideBottom);
2872
0
}
2873
2874
already_AddRefed<CSSValue>
2875
nsComputedDOMStyle::DoGetMarginLeftWidth()
2876
0
{
2877
0
  return GetMarginWidthFor(eSideLeft);
2878
0
}
2879
2880
already_AddRefed<CSSValue>
2881
nsComputedDOMStyle::DoGetMarginRightWidth()
2882
0
{
2883
0
  return GetMarginWidthFor(eSideRight);
2884
0
}
2885
2886
already_AddRefed<CSSValue>
2887
nsComputedDOMStyle::DoGetOverscrollBehaviorX()
2888
0
{
2889
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2890
0
  val->SetIdent(
2891
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverscrollBehaviorX,
2892
0
                                   nsCSSProps::kOverscrollBehaviorKTable));
2893
0
  return val.forget();
2894
0
}
2895
2896
already_AddRefed<CSSValue>
2897
nsComputedDOMStyle::DoGetOverscrollBehaviorY()
2898
0
{
2899
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2900
0
  val->SetIdent(
2901
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverscrollBehaviorY,
2902
0
                                   nsCSSProps::kOverscrollBehaviorKTable));
2903
0
  return val.forget();
2904
0
}
2905
2906
already_AddRefed<CSSValue>
2907
nsComputedDOMStyle::DoGetScrollSnapTypeX()
2908
0
{
2909
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2910
0
  val->SetIdent(
2911
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeX,
2912
0
                                   nsCSSProps::kScrollSnapTypeKTable));
2913
0
  return val.forget();
2914
0
}
2915
2916
already_AddRefed<CSSValue>
2917
nsComputedDOMStyle::DoGetScrollSnapTypeY()
2918
0
{
2919
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2920
0
  val->SetIdent(
2921
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeY,
2922
0
                                   nsCSSProps::kScrollSnapTypeKTable));
2923
0
  return val.forget();
2924
0
}
2925
2926
already_AddRefed<CSSValue>
2927
nsComputedDOMStyle::GetScrollSnapPoints(const nsStyleCoord& aCoord)
2928
0
{
2929
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2930
0
  if (aCoord.GetUnit() == eStyleUnit_None) {
2931
0
    val->SetIdent(eCSSKeyword_none);
2932
0
  } else {
2933
0
    nsAutoString argumentString;
2934
0
    SetCssTextToCoord(argumentString, aCoord, true);
2935
0
    nsAutoString tmp;
2936
0
    tmp.AppendLiteral("repeat(");
2937
0
    tmp.Append(argumentString);
2938
0
    tmp.Append(')');
2939
0
    val->SetString(tmp);
2940
0
  }
2941
0
  return val.forget();
2942
0
}
2943
2944
already_AddRefed<CSSValue>
2945
nsComputedDOMStyle::DoGetScrollSnapPointsX()
2946
0
{
2947
0
  return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsX);
2948
0
}
2949
2950
already_AddRefed<CSSValue>
2951
nsComputedDOMStyle::DoGetScrollSnapPointsY()
2952
0
{
2953
0
  return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsY);
2954
0
}
2955
2956
already_AddRefed<CSSValue>
2957
nsComputedDOMStyle::DoGetScrollSnapDestination()
2958
0
{
2959
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
2960
0
  SetValueToPosition(StyleDisplay()->mScrollSnapDestination, valueList);
2961
0
  return valueList.forget();
2962
0
}
2963
2964
already_AddRefed<CSSValue>
2965
nsComputedDOMStyle::DoGetScrollSnapCoordinate()
2966
0
{
2967
0
  const nsStyleDisplay* sd = StyleDisplay();
2968
0
  if (sd->mScrollSnapCoordinate.IsEmpty()) {
2969
0
    // Having no snap coordinates is interpreted as "none"
2970
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2971
0
    val->SetIdent(eCSSKeyword_none);
2972
0
    return val.forget();
2973
0
  } else {
2974
0
    RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
2975
0
    for (size_t i = 0, i_end = sd->mScrollSnapCoordinate.Length(); i < i_end; ++i) {
2976
0
      RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
2977
0
      SetValueToPosition(sd->mScrollSnapCoordinate[i], itemList);
2978
0
      valueList->AppendCSSValue(itemList.forget());
2979
0
    }
2980
0
    return valueList.forget();
2981
0
  }
2982
0
}
2983
2984
already_AddRefed<CSSValue>
2985
nsComputedDOMStyle::DoGetScrollbarColor()
2986
0
{
2987
0
  const nsStyleUI* ui = StyleUI();
2988
0
  RefPtr<nsDOMCSSValueList> list = GetROCSSValueList(false);
2989
0
  auto put = [this, &list](const StyleComplexColor& color,
2990
0
                           StyleAppearance type) {
2991
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
2992
0
    SetValueForWidgetColor(val, color, type);
2993
0
    list->AppendCSSValue(val.forget());
2994
0
  };
2995
0
  put(ui->mScrollbarFaceColor, StyleAppearance::ScrollbarthumbVertical);
2996
0
  put(ui->mScrollbarTrackColor, StyleAppearance::ScrollbarVertical);
2997
0
  return list.forget();
2998
0
}
2999
3000
already_AddRefed<CSSValue>
3001
nsComputedDOMStyle::DoGetOutlineWidth()
3002
0
{
3003
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3004
0
3005
0
  const nsStyleOutline* outline = StyleOutline();
3006
0
3007
0
  nscoord width;
3008
0
  if (outline->mOutlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
3009
0
    NS_ASSERTION(outline->GetOutlineWidth() == 0, "unexpected width");
3010
0
    width = 0;
3011
0
  } else {
3012
0
    width = outline->GetOutlineWidth();
3013
0
  }
3014
0
  val->SetAppUnits(width);
3015
0
3016
0
  return val.forget();
3017
0
}
3018
3019
already_AddRefed<CSSValue>
3020
nsComputedDOMStyle::DoGetOutlineStyle()
3021
0
{
3022
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3023
0
  val->SetIdent(
3024
0
    nsCSSProps::ValueToKeywordEnum(StyleOutline()->mOutlineStyle,
3025
0
                                   nsCSSProps::kOutlineStyleKTable));
3026
0
  return val.forget();
3027
0
}
3028
3029
already_AddRefed<CSSValue>
3030
nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
3031
0
{
3032
0
  return GetEllipseRadii(StyleOutline()->mOutlineRadius,
3033
0
                         eCornerBottomLeft);
3034
0
}
3035
3036
already_AddRefed<CSSValue>
3037
nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
3038
0
{
3039
0
  return GetEllipseRadii(StyleOutline()->mOutlineRadius,
3040
0
                         eCornerBottomRight);
3041
0
}
3042
3043
already_AddRefed<CSSValue>
3044
nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
3045
0
{
3046
0
  return GetEllipseRadii(StyleOutline()->mOutlineRadius,
3047
0
                         eCornerTopLeft);
3048
0
}
3049
3050
already_AddRefed<CSSValue>
3051
nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
3052
0
{
3053
0
  return GetEllipseRadii(StyleOutline()->mOutlineRadius,
3054
0
                         eCornerTopRight);
3055
0
}
3056
3057
already_AddRefed<CSSValue>
3058
nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
3059
                                    Corner aFullCorner)
3060
0
{
3061
0
  nsStyleCoord radiusX = aRadius.Get(FullToHalfCorner(aFullCorner, false));
3062
0
  nsStyleCoord radiusY = aRadius.Get(FullToHalfCorner(aFullCorner, true));
3063
0
3064
0
  // for compatibility, return a single value if X and Y are equal
3065
0
  if (radiusX == radiusY) {
3066
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3067
0
    SetValueToCoord(val, radiusX, true);
3068
0
    return val.forget();
3069
0
  }
3070
0
3071
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3072
0
3073
0
  RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
3074
0
  RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
3075
0
3076
0
  SetValueToCoord(valX, radiusX, true);
3077
0
  SetValueToCoord(valY, radiusY, true);
3078
0
3079
0
  valueList->AppendCSSValue(valX.forget());
3080
0
  valueList->AppendCSSValue(valY.forget());
3081
0
3082
0
  return valueList.forget();
3083
0
}
3084
3085
already_AddRefed<CSSValue>
3086
nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
3087
                                      bool aIsBoxShadow)
3088
0
{
3089
0
  if (!aArray) {
3090
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3091
0
    val->SetIdent(eCSSKeyword_none);
3092
0
    return val.forget();
3093
0
  }
3094
0
3095
0
  static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
3096
0
    &nsCSSShadowItem::mXOffset,
3097
0
    &nsCSSShadowItem::mYOffset,
3098
0
    &nsCSSShadowItem::mRadius
3099
0
  };
3100
0
3101
0
  static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
3102
0
    &nsCSSShadowItem::mXOffset,
3103
0
    &nsCSSShadowItem::mYOffset,
3104
0
    &nsCSSShadowItem::mRadius,
3105
0
    &nsCSSShadowItem::mSpread
3106
0
  };
3107
0
3108
0
  nscoord nsCSSShadowItem::* const * shadowValues;
3109
0
  uint32_t shadowValuesLength;
3110
0
  if (aIsBoxShadow) {
3111
0
    shadowValues = shadowValuesWithSpread;
3112
0
    shadowValuesLength = ArrayLength(shadowValuesWithSpread);
3113
0
  } else {
3114
0
    shadowValues = shadowValuesNoSpread;
3115
0
    shadowValuesLength = ArrayLength(shadowValuesNoSpread);
3116
0
  }
3117
0
3118
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
3119
0
3120
0
  for (nsCSSShadowItem *item = aArray->ShadowAt(0),
3121
0
                   *item_end = item + aArray->Length();
3122
0
       item < item_end; ++item) {
3123
0
    RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
3124
0
3125
0
    // Color is either the specified shadow color or the foreground color
3126
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3127
0
    SetValueFromComplexColor(val, item->mColor);
3128
0
    itemList->AppendCSSValue(val.forget());
3129
0
3130
0
    // Set the offsets, blur radius, and spread if available
3131
0
    for (uint32_t i = 0; i < shadowValuesLength; ++i) {
3132
0
      val = new nsROCSSPrimitiveValue;
3133
0
      val->SetAppUnits(item->*(shadowValues[i]));
3134
0
      itemList->AppendCSSValue(val.forget());
3135
0
    }
3136
0
3137
0
    if (item->mInset && aIsBoxShadow) {
3138
0
      // This is an inset box-shadow
3139
0
      val = new nsROCSSPrimitiveValue;
3140
0
      val->SetIdent(
3141
0
        nsCSSProps::ValueToKeywordEnum(
3142
0
            uint8_t(StyleBoxShadowType::Inset),
3143
0
            nsCSSProps::kBoxShadowTypeKTable));
3144
0
      itemList->AppendCSSValue(val.forget());
3145
0
    }
3146
0
    valueList->AppendCSSValue(itemList.forget());
3147
0
  }
3148
0
3149
0
  return valueList.forget();
3150
0
}
3151
3152
already_AddRefed<CSSValue>
3153
nsComputedDOMStyle::DoGetBoxShadow()
3154
0
{
3155
0
  return GetCSSShadowArray(StyleEffects()->mBoxShadow, true);
3156
0
}
3157
3158
already_AddRefed<CSSValue>
3159
nsComputedDOMStyle::DoGetZIndex()
3160
0
{
3161
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3162
0
  SetValueToCoord(val, StylePosition()->mZIndex, false);
3163
0
  return val.forget();
3164
0
}
3165
3166
already_AddRefed<CSSValue>
3167
nsComputedDOMStyle::DoGetImageRegion()
3168
0
{
3169
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3170
0
3171
0
  const nsStyleList* list = StyleList();
3172
0
3173
0
  if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
3174
0
    val->SetIdent(eCSSKeyword_auto);
3175
0
  } else {
3176
0
    // create the cssvalues for the sides, stick them in the rect object
3177
0
    nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
3178
0
    nsROCSSPrimitiveValue *rightVal  = new nsROCSSPrimitiveValue;
3179
0
    nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3180
0
    nsROCSSPrimitiveValue *leftVal   = new nsROCSSPrimitiveValue;
3181
0
    nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3182
0
                                              bottomVal, leftVal);
3183
0
    topVal->SetAppUnits(list->mImageRegion.y);
3184
0
    rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
3185
0
    bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
3186
0
    leftVal->SetAppUnits(list->mImageRegion.x);
3187
0
    val->SetRect(domRect);
3188
0
  }
3189
0
3190
0
  return val.forget();
3191
0
}
3192
3193
already_AddRefed<CSSValue>
3194
nsComputedDOMStyle::DoGetInitialLetter()
3195
0
{
3196
0
  const nsStyleTextReset* textReset = StyleTextReset();
3197
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3198
0
  if (textReset->mInitialLetterSink == 0) {
3199
0
    val->SetIdent(eCSSKeyword_normal);
3200
0
    return val.forget();
3201
0
  } else {
3202
0
    RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3203
0
    val->SetNumber(textReset->mInitialLetterSize);
3204
0
    valueList->AppendCSSValue(val.forget());
3205
0
    RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
3206
0
    second->SetNumber(textReset->mInitialLetterSink);
3207
0
    valueList->AppendCSSValue(second.forget());
3208
0
    return valueList.forget();
3209
0
  }
3210
0
}
3211
3212
already_AddRefed<CSSValue>
3213
nsComputedDOMStyle::DoGetLineHeight()
3214
0
{
3215
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3216
0
3217
0
  nscoord lineHeight;
3218
0
  if (GetLineHeightCoord(lineHeight)) {
3219
0
    val->SetAppUnits(lineHeight);
3220
0
  } else {
3221
0
    SetValueToCoord(val, StyleText()->mLineHeight, true,
3222
0
                    nullptr, nsCSSProps::kLineHeightKTable);
3223
0
  }
3224
0
3225
0
  return val.forget();
3226
0
}
3227
3228
already_AddRefed<CSSValue>
3229
nsComputedDOMStyle::DoGetVerticalAlign()
3230
0
{
3231
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3232
0
  SetValueToCoord(val, StyleDisplay()->mVerticalAlign, false,
3233
0
                  nullptr, nsCSSProps::kVerticalAlignKTable);
3234
0
  return val.forget();
3235
0
}
3236
3237
already_AddRefed<CSSValue>
3238
nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
3239
                                         const KTableEntry aTable[])
3240
0
{
3241
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3242
0
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
3243
0
  if (!aAlignTrue) {
3244
0
    return val.forget();
3245
0
  }
3246
0
3247
0
  RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
3248
0
  first->SetIdent(eCSSKeyword_unsafe);
3249
0
3250
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3251
0
  valueList->AppendCSSValue(first.forget());
3252
0
  valueList->AppendCSSValue(val.forget());
3253
0
  return valueList.forget();
3254
0
}
3255
3256
already_AddRefed<CSSValue>
3257
nsComputedDOMStyle::DoGetTextAlign()
3258
0
{
3259
0
  const nsStyleText* style = StyleText();
3260
0
  return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
3261
0
                              nsCSSProps::kTextAlignKTable);
3262
0
}
3263
3264
already_AddRefed<CSSValue>
3265
nsComputedDOMStyle::DoGetTextDecoration()
3266
0
{
3267
0
  const nsStyleTextReset* textReset = StyleTextReset();
3268
0
3269
0
  bool isInitialStyle =
3270
0
    textReset->mTextDecorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
3271
0
  StyleComplexColor color = textReset->mTextDecorationColor;
3272
0
3273
0
  if (isInitialStyle && color.IsCurrentColor()) {
3274
0
    return DoGetTextDecorationLine();
3275
0
  }
3276
0
3277
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3278
0
3279
0
  valueList->AppendCSSValue(DoGetTextDecorationLine());
3280
0
  if (!isInitialStyle) {
3281
0
    valueList->AppendCSSValue(DoGetTextDecorationStyle());
3282
0
  }
3283
0
  if (!color.IsCurrentColor()) {
3284
0
    valueList->AppendCSSValue(DoGetTextDecorationColor());
3285
0
  }
3286
0
3287
0
  return valueList.forget();
3288
0
}
3289
3290
already_AddRefed<CSSValue>
3291
nsComputedDOMStyle::DoGetTextDecorationColor()
3292
0
{
3293
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3294
0
  SetValueFromComplexColor(val, StyleTextReset()->mTextDecorationColor);
3295
0
  return val.forget();
3296
0
}
3297
3298
already_AddRefed<CSSValue>
3299
nsComputedDOMStyle::DoGetTextDecorationLine()
3300
0
{
3301
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3302
0
3303
0
  int32_t intValue = StyleTextReset()->mTextDecorationLine;
3304
0
3305
0
  if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
3306
0
    val->SetIdent(eCSSKeyword_none);
3307
0
  } else {
3308
0
    nsAutoString decorationLineString;
3309
0
    // Clear the OVERRIDE_ALL bits -- we don't want these to appear in
3310
0
    // the computed style.
3311
0
    intValue &= ~NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
3312
0
    nsStyleUtil::AppendBitmaskCSSValue(nsCSSProps::kTextDecorationLineKTable,
3313
0
                                       intValue,
3314
0
                                       NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
3315
0
                                       NS_STYLE_TEXT_DECORATION_LINE_BLINK,
3316
0
                                       decorationLineString);
3317
0
    val->SetString(decorationLineString);
3318
0
  }
3319
0
3320
0
  return val.forget();
3321
0
}
3322
3323
already_AddRefed<CSSValue>
3324
nsComputedDOMStyle::DoGetTextDecorationStyle()
3325
0
{
3326
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3327
0
3328
0
  val->SetIdent(
3329
0
    nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mTextDecorationStyle,
3330
0
                                   nsCSSProps::kTextDecorationStyleKTable));
3331
0
3332
0
  return val.forget();
3333
0
}
3334
3335
already_AddRefed<CSSValue>
3336
nsComputedDOMStyle::DoGetTextEmphasisPosition()
3337
0
{
3338
0
  auto position = StyleText()->mTextEmphasisPosition;
3339
0
3340
0
  MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) !=
3341
0
             !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER));
3342
0
  RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
3343
0
  first->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) ?
3344
0
                  eCSSKeyword_over : eCSSKeyword_under);
3345
0
3346
0
  MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) !=
3347
0
             !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT));
3348
0
  RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
3349
0
  second->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) ?
3350
0
                   eCSSKeyword_left : eCSSKeyword_right);
3351
0
3352
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3353
0
  valueList->AppendCSSValue(first.forget());
3354
0
  valueList->AppendCSSValue(second.forget());
3355
0
  return valueList.forget();
3356
0
}
3357
3358
already_AddRefed<CSSValue>
3359
nsComputedDOMStyle::DoGetTextEmphasisStyle()
3360
0
{
3361
0
  auto style = StyleText()->mTextEmphasisStyle;
3362
0
  if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_NONE) {
3363
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3364
0
    val->SetIdent(eCSSKeyword_none);
3365
0
    return val.forget();
3366
0
  }
3367
0
  if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_STRING) {
3368
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3369
0
    nsAutoString tmp;
3370
0
    nsStyleUtil::AppendEscapedCSSString(
3371
0
      StyleText()->mTextEmphasisStyleString, tmp);
3372
0
    val->SetString(tmp);
3373
0
    return val.forget();
3374
0
  }
3375
0
3376
0
  RefPtr<nsROCSSPrimitiveValue> fillVal = new nsROCSSPrimitiveValue;
3377
0
  if ((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
3378
0
      NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED) {
3379
0
    fillVal->SetIdent(eCSSKeyword_filled);
3380
0
  } else {
3381
0
    MOZ_ASSERT((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
3382
0
               NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN);
3383
0
    fillVal->SetIdent(eCSSKeyword_open);
3384
0
  }
3385
0
3386
0
  RefPtr<nsROCSSPrimitiveValue> shapeVal = new nsROCSSPrimitiveValue;
3387
0
  shapeVal->SetIdent(nsCSSProps::ValueToKeywordEnum(
3388
0
    style & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK,
3389
0
    nsCSSProps::kTextEmphasisStyleShapeKTable));
3390
0
3391
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3392
0
  valueList->AppendCSSValue(fillVal.forget());
3393
0
  valueList->AppendCSSValue(shapeVal.forget());
3394
0
  return valueList.forget();
3395
0
}
3396
3397
already_AddRefed<CSSValue>
3398
nsComputedDOMStyle::DoGetTextOverflow()
3399
0
{
3400
0
  const nsStyleTextReset *style = StyleTextReset();
3401
0
  RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
3402
0
  const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
3403
0
  if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3404
0
    nsAutoString str;
3405
0
    nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3406
0
    first->SetString(str);
3407
0
  } else {
3408
0
    first->SetIdent(
3409
0
      nsCSSProps::ValueToKeywordEnum(side->mType,
3410
0
                                     nsCSSProps::kTextOverflowKTable));
3411
0
  }
3412
0
  side = style->mTextOverflow.GetSecondValue();
3413
0
  if (!side) {
3414
0
    return first.forget();
3415
0
  }
3416
0
  RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
3417
0
  if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3418
0
    nsAutoString str;
3419
0
    nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3420
0
    second->SetString(str);
3421
0
  } else {
3422
0
    second->SetIdent(
3423
0
      nsCSSProps::ValueToKeywordEnum(side->mType,
3424
0
                                     nsCSSProps::kTextOverflowKTable));
3425
0
  }
3426
0
3427
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3428
0
  valueList->AppendCSSValue(first.forget());
3429
0
  valueList->AppendCSSValue(second.forget());
3430
0
  return valueList.forget();
3431
0
}
3432
3433
already_AddRefed<CSSValue>
3434
nsComputedDOMStyle::DoGetTextShadow()
3435
0
{
3436
0
  return GetCSSShadowArray(StyleText()->mTextShadow, false);
3437
0
}
3438
3439
already_AddRefed<CSSValue>
3440
nsComputedDOMStyle::DoGetTabSize()
3441
0
{
3442
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3443
0
  SetValueToCoord(val, StyleText()->mTabSize, true);
3444
0
  return val.forget();
3445
0
}
3446
3447
already_AddRefed<CSSValue>
3448
nsComputedDOMStyle::DoGetLetterSpacing()
3449
0
{
3450
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3451
0
  SetValueToCoord(val, StyleText()->mLetterSpacing, false);
3452
0
  return val.forget();
3453
0
}
3454
3455
already_AddRefed<CSSValue>
3456
nsComputedDOMStyle::DoGetWordSpacing()
3457
0
{
3458
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3459
0
  SetValueToCoord(val, StyleText()->mWordSpacing, false);
3460
0
  return val.forget();
3461
0
}
3462
3463
already_AddRefed<CSSValue>
3464
nsComputedDOMStyle::DoGetWebkitTextStrokeWidth()
3465
0
{
3466
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3467
0
  val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth);
3468
0
  return val.forget();
3469
0
}
3470
3471
static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
3472
              "unicode-bidi style constants not as expected");
3473
3474
already_AddRefed<CSSValue>
3475
nsComputedDOMStyle::DoGetCaretColor()
3476
0
{
3477
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3478
0
  SetValueFromComplexColor(val, StyleUI()->mCaretColor);
3479
0
  return val.forget();
3480
0
}
3481
3482
already_AddRefed<CSSValue>
3483
nsComputedDOMStyle::DoGetCursor()
3484
0
{
3485
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
3486
0
3487
0
  const nsStyleUI *ui = StyleUI();
3488
0
3489
0
  for (const nsCursorImage& item : ui->mCursorImages) {
3490
0
    RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
3491
0
3492
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3493
0
    SetValueToURLValue(item.mImage->GetImageValue(), val);
3494
0
    itemList->AppendCSSValue(val.forget());
3495
0
3496
0
    if (item.mHaveHotspot) {
3497
0
      RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
3498
0
      RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
3499
0
3500
0
      valX->SetNumber(item.mHotspotX);
3501
0
      valY->SetNumber(item.mHotspotY);
3502
0
3503
0
      itemList->AppendCSSValue(valX.forget());
3504
0
      itemList->AppendCSSValue(valY.forget());
3505
0
    }
3506
0
    valueList->AppendCSSValue(itemList.forget());
3507
0
  }
3508
0
3509
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3510
0
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
3511
0
                                               nsCSSProps::kCursorKTable));
3512
0
  valueList->AppendCSSValue(val.forget());
3513
0
  return valueList.forget();
3514
0
}
3515
3516
3517
already_AddRefed<CSSValue>
3518
nsComputedDOMStyle::DoGetBoxFlex()
3519
0
{
3520
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3521
0
  val->SetNumber(StyleXUL()->mBoxFlex);
3522
0
  return val.forget();
3523
0
}
3524
3525
/* Border image properties */
3526
3527
already_AddRefed<CSSValue>
3528
nsComputedDOMStyle::DoGetBorderImageSource()
3529
0
{
3530
0
  const nsStyleBorder* border = StyleBorder();
3531
0
3532
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3533
0
  const nsStyleImage& image = border->mBorderImageSource;
3534
0
  SetValueToStyleImage(image, val);
3535
0
3536
0
  return val.forget();
3537
0
}
3538
3539
void
3540
nsComputedDOMStyle::AppendFourSideCoordValues(nsDOMCSSValueList* aList,
3541
                                              const nsStyleSides& aValues)
3542
0
{
3543
0
  const nsStyleCoord& top = aValues.Get(eSideTop);
3544
0
  const nsStyleCoord& right = aValues.Get(eSideRight);
3545
0
  const nsStyleCoord& bottom = aValues.Get(eSideBottom);
3546
0
  const nsStyleCoord& left = aValues.Get(eSideLeft);
3547
0
3548
0
  auto appendValue = [this, aList](const nsStyleCoord& value) {
3549
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3550
0
    SetValueToCoord(val, value, true);
3551
0
    aList->AppendCSSValue(val.forget());
3552
0
  };
3553
0
  appendValue(top);
3554
0
  if (top != right || top != bottom || top != left) {
3555
0
    appendValue(right);
3556
0
    if (top != bottom || right != left) {
3557
0
      appendValue(bottom);
3558
0
      if (right != left) {
3559
0
        appendValue(left);
3560
0
      }
3561
0
    }
3562
0
  }
3563
0
}
3564
3565
already_AddRefed<CSSValue>
3566
nsComputedDOMStyle::DoGetBorderImageSlice()
3567
0
{
3568
0
  const nsStyleBorder* border = StyleBorder();
3569
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3570
0
  AppendFourSideCoordValues(valueList, border->mBorderImageSlice);
3571
0
3572
0
  // Fill keyword.
3573
0
  if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
3574
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3575
0
    val->SetIdent(eCSSKeyword_fill);
3576
0
    valueList->AppendCSSValue(val.forget());
3577
0
  }
3578
0
3579
0
  return valueList.forget();
3580
0
}
3581
3582
already_AddRefed<CSSValue>
3583
nsComputedDOMStyle::DoGetBorderImageWidth()
3584
0
{
3585
0
  const nsStyleBorder* border = StyleBorder();
3586
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3587
0
  AppendFourSideCoordValues(valueList, border->mBorderImageWidth);
3588
0
  return valueList.forget();
3589
0
}
3590
3591
already_AddRefed<CSSValue>
3592
nsComputedDOMStyle::DoGetBorderImageOutset()
3593
0
{
3594
0
  const nsStyleBorder* border = StyleBorder();
3595
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3596
0
  AppendFourSideCoordValues(valueList, border->mBorderImageOutset);
3597
0
  return valueList.forget();
3598
0
}
3599
3600
already_AddRefed<CSSValue>
3601
nsComputedDOMStyle::DoGetBorderImageRepeat()
3602
0
{
3603
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3604
0
3605
0
  const nsStyleBorder* border = StyleBorder();
3606
0
3607
0
  // horizontal repeat
3608
0
  RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
3609
0
  valX->SetIdent(
3610
0
    nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
3611
0
                                   nsCSSProps::kBorderImageRepeatKTable));
3612
0
  valueList->AppendCSSValue(valX.forget());
3613
0
3614
0
  // vertical repeat
3615
0
  RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
3616
0
  valY->SetIdent(
3617
0
    nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
3618
0
                                   nsCSSProps::kBorderImageRepeatKTable));
3619
0
  valueList->AppendCSSValue(valY.forget());
3620
0
  return valueList.forget();
3621
0
}
3622
3623
already_AddRefed<CSSValue>
3624
nsComputedDOMStyle::DoGetFlexBasis()
3625
0
{
3626
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3627
0
3628
0
  // XXXdholbert We could make this more automagic and resolve percentages
3629
0
  // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
3630
0
  // below.  Logic would go like this:
3631
0
  //   if (i'm a flex item) {
3632
0
  //     if (my flex container is horizontal) {
3633
0
  //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
3634
0
  //     } else {
3635
0
  //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
3636
0
  //     }
3637
0
  //   }
3638
0
3639
0
  SetValueToCoord(val, StylePosition()->mFlexBasis, true,
3640
0
                  nullptr, nsCSSProps::kFlexBasisKTable);
3641
0
  return val.forget();
3642
0
}
3643
3644
already_AddRefed<CSSValue>
3645
nsComputedDOMStyle::DoGetFlexGrow()
3646
0
{
3647
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3648
0
  val->SetNumber(StylePosition()->mFlexGrow);
3649
0
  return val.forget();
3650
0
}
3651
3652
already_AddRefed<CSSValue>
3653
nsComputedDOMStyle::DoGetFlexShrink()
3654
0
{
3655
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3656
0
  val->SetNumber(StylePosition()->mFlexShrink);
3657
0
  return val.forget();
3658
0
}
3659
3660
already_AddRefed<CSSValue>
3661
nsComputedDOMStyle::DoGetAlignContent()
3662
0
{
3663
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3664
0
  nsAutoString str;
3665
0
  auto align = StylePosition()->mAlignContent;
3666
0
  nsCSSValue::AppendAlignJustifyValueToString(align & NS_STYLE_ALIGN_ALL_BITS, str);
3667
0
  auto fallback = align >> NS_STYLE_ALIGN_ALL_SHIFT;
3668
0
  if (fallback) {
3669
0
    str.Append(' ');
3670
0
    nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
3671
0
  }
3672
0
  val->SetString(str);
3673
0
  return val.forget();
3674
0
}
3675
3676
already_AddRefed<CSSValue>
3677
nsComputedDOMStyle::DoGetAlignItems()
3678
0
{
3679
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3680
0
  nsAutoString str;
3681
0
  auto align = StylePosition()->mAlignItems;
3682
0
  nsCSSValue::AppendAlignJustifyValueToString(align, str);
3683
0
  val->SetString(str);
3684
0
  return val.forget();
3685
0
}
3686
3687
already_AddRefed<CSSValue>
3688
nsComputedDOMStyle::DoGetAlignSelf()
3689
0
{
3690
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3691
0
  nsAutoString str;
3692
0
  auto align = StylePosition()->mAlignSelf;
3693
0
  nsCSSValue::AppendAlignJustifyValueToString(align, str);
3694
0
  val->SetString(str);
3695
0
  return val.forget();
3696
0
}
3697
3698
already_AddRefed<CSSValue>
3699
nsComputedDOMStyle::DoGetJustifyContent()
3700
0
{
3701
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3702
0
  nsAutoString str;
3703
0
  auto justify = StylePosition()->mJustifyContent;
3704
0
  nsCSSValue::AppendAlignJustifyValueToString(justify & NS_STYLE_JUSTIFY_ALL_BITS, str);
3705
0
  auto fallback = justify >> NS_STYLE_JUSTIFY_ALL_SHIFT;
3706
0
  if (fallback) {
3707
0
    MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(fallback & ~NS_STYLE_JUSTIFY_FLAG_BITS,
3708
0
                                              nsCSSProps::kAlignSelfPosition)
3709
0
               != eCSSKeyword_UNKNOWN, "unknown fallback value");
3710
0
    str.Append(' ');
3711
0
    nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
3712
0
  }
3713
0
  val->SetString(str);
3714
0
  return val.forget();
3715
0
}
3716
3717
already_AddRefed<CSSValue>
3718
nsComputedDOMStyle::DoGetJustifyItems()
3719
0
{
3720
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3721
0
  nsAutoString str;
3722
0
  auto justify = StylePosition()->mJustifyItems;
3723
0
  nsCSSValue::AppendAlignJustifyValueToString(justify, str);
3724
0
  val->SetString(str);
3725
0
  return val.forget();
3726
0
}
3727
3728
already_AddRefed<CSSValue>
3729
nsComputedDOMStyle::DoGetJustifySelf()
3730
0
{
3731
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3732
0
  nsAutoString str;
3733
0
  auto justify = StylePosition()->mJustifySelf;
3734
0
  nsCSSValue::AppendAlignJustifyValueToString(justify, str);
3735
0
  val->SetString(str);
3736
0
  return val.forget();
3737
0
}
3738
3739
already_AddRefed<CSSValue>
3740
nsComputedDOMStyle::DoGetForceBrokenImageIcon()
3741
0
{
3742
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3743
0
  val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
3744
0
  return val.forget();
3745
0
}
3746
3747
already_AddRefed<CSSValue>
3748
nsComputedDOMStyle::DoGetDisplay()
3749
0
{
3750
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3751
0
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
3752
0
                                               nsCSSProps::kDisplayKTable));
3753
0
  return val.forget();
3754
0
}
3755
3756
already_AddRefed<CSSValue>
3757
nsComputedDOMStyle::DoGetContain()
3758
0
{
3759
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3760
0
3761
0
  int32_t mask = StyleDisplay()->mContain;
3762
0
3763
0
  if (mask == 0) {
3764
0
    val->SetIdent(eCSSKeyword_none);
3765
0
  } else if (mask & NS_STYLE_CONTAIN_STRICT) {
3766
0
    NS_ASSERTION(mask == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
3767
0
                 "contain: strict should imply contain: size layout style paint");
3768
0
    val->SetIdent(eCSSKeyword_strict);
3769
0
  } else if (mask & NS_STYLE_CONTAIN_CONTENT) {
3770
0
    NS_ASSERTION(mask == (NS_STYLE_CONTAIN_CONTENT | NS_STYLE_CONTAIN_CONTENT_BITS),
3771
0
                 "contain: content should imply contain: layout style paint");
3772
0
    val->SetIdent(eCSSKeyword_content);
3773
0
  }  else {
3774
0
    nsAutoString valueStr;
3775
0
    nsStyleUtil::AppendBitmaskCSSValue(nsCSSProps::kContainKTable,
3776
0
                                       mask,
3777
0
                                       NS_STYLE_CONTAIN_SIZE, NS_STYLE_CONTAIN_PAINT,
3778
0
                                       valueStr);
3779
0
    val->SetString(valueStr);
3780
0
  }
3781
0
3782
0
  return val.forget();
3783
0
}
3784
3785
already_AddRefed<CSSValue>
3786
nsComputedDOMStyle::DoGetClip()
3787
0
{
3788
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3789
0
3790
0
  const nsStyleEffects* effects = StyleEffects();
3791
0
3792
0
  if (effects->mClipFlags == NS_STYLE_CLIP_AUTO) {
3793
0
    val->SetIdent(eCSSKeyword_auto);
3794
0
  } else {
3795
0
    // create the cssvalues for the sides, stick them in the rect object
3796
0
    nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
3797
0
    nsROCSSPrimitiveValue *rightVal  = new nsROCSSPrimitiveValue;
3798
0
    nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3799
0
    nsROCSSPrimitiveValue *leftVal   = new nsROCSSPrimitiveValue;
3800
0
    nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3801
0
                                              bottomVal, leftVal);
3802
0
    if (effects->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
3803
0
      topVal->SetIdent(eCSSKeyword_auto);
3804
0
    } else {
3805
0
      topVal->SetAppUnits(effects->mClip.y);
3806
0
    }
3807
0
3808
0
    if (effects->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
3809
0
      rightVal->SetIdent(eCSSKeyword_auto);
3810
0
    } else {
3811
0
      rightVal->SetAppUnits(effects->mClip.width + effects->mClip.x);
3812
0
    }
3813
0
3814
0
    if (effects->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
3815
0
      bottomVal->SetIdent(eCSSKeyword_auto);
3816
0
    } else {
3817
0
      bottomVal->SetAppUnits(effects->mClip.height + effects->mClip.y);
3818
0
    }
3819
0
3820
0
    if (effects->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
3821
0
      leftVal->SetIdent(eCSSKeyword_auto);
3822
0
    } else {
3823
0
      leftVal->SetAppUnits(effects->mClip.x);
3824
0
    }
3825
0
    val->SetRect(domRect);
3826
0
  }
3827
0
3828
0
  return val.forget();
3829
0
}
3830
3831
already_AddRefed<CSSValue>
3832
nsComputedDOMStyle::DoGetWillChange()
3833
0
{
3834
0
  const nsTArray<RefPtr<nsAtom>>& willChange = StyleDisplay()->mWillChange;
3835
0
3836
0
  if (willChange.IsEmpty()) {
3837
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3838
0
    val->SetIdent(eCSSKeyword_auto);
3839
0
    return val.forget();
3840
0
  }
3841
0
3842
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
3843
0
  for (const nsAtom* ident : willChange) {
3844
0
    RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
3845
0
    property->SetString(nsDependentAtomString(ident));
3846
0
    valueList->AppendCSSValue(property.forget());
3847
0
  }
3848
0
3849
0
  return valueList.forget();
3850
0
}
3851
3852
already_AddRefed<CSSValue>
3853
nsComputedDOMStyle::DoGetOverflow()
3854
0
{
3855
0
  const nsStyleDisplay* display = StyleDisplay();
3856
0
3857
0
  RefPtr<nsROCSSPrimitiveValue> overflowX = new nsROCSSPrimitiveValue;
3858
0
  overflowX->SetIdent(
3859
0
    nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
3860
0
                                   nsCSSProps::kOverflowKTable));
3861
0
  if (display->mOverflowX == display->mOverflowY) {
3862
0
    return overflowX.forget();
3863
0
  }
3864
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
3865
0
  valueList->AppendCSSValue(overflowX.forget());
3866
0
3867
0
  RefPtr<nsROCSSPrimitiveValue> overflowY= new nsROCSSPrimitiveValue;
3868
0
  overflowY->SetIdent(
3869
0
    nsCSSProps::ValueToKeywordEnum(display->mOverflowY,
3870
0
                                   nsCSSProps::kOverflowKTable));
3871
0
  valueList->AppendCSSValue(overflowY.forget());
3872
0
  return valueList.forget();
3873
0
}
3874
3875
already_AddRefed<CSSValue>
3876
nsComputedDOMStyle::DoGetOverflowY()
3877
0
{
3878
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3879
0
  val->SetIdent(
3880
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
3881
0
                                   nsCSSProps::kOverflowSubKTable));
3882
0
  return val.forget();
3883
0
}
3884
3885
already_AddRefed<CSSValue>
3886
nsComputedDOMStyle::DoGetOverflowClipBoxBlock()
3887
0
{
3888
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3889
0
  val->SetIdent(
3890
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxBlock,
3891
0
                                   nsCSSProps::kOverflowClipBoxKTable));
3892
0
  return val.forget();
3893
0
}
3894
3895
already_AddRefed<CSSValue>
3896
nsComputedDOMStyle::DoGetOverflowClipBoxInline()
3897
0
{
3898
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3899
0
  val->SetIdent(
3900
0
    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBoxInline,
3901
0
                                   nsCSSProps::kOverflowClipBoxKTable));
3902
0
  return val.forget();
3903
0
}
3904
3905
3906
already_AddRefed<CSSValue>
3907
nsComputedDOMStyle::DoGetTouchAction()
3908
0
{
3909
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3910
0
3911
0
  int32_t intValue = StyleDisplay()->mTouchAction;
3912
0
3913
0
  // None and Auto and Manipulation values aren't allowed
3914
0
  // to be in conjunction with other values.
3915
0
  // But there are all checks in CSSParserImpl::ParseTouchAction
3916
0
  nsAutoString valueStr;
3917
0
  nsStyleUtil::AppendBitmaskCSSValue(nsCSSProps::kTouchActionKTable,
3918
0
                                     intValue,
3919
0
                                     NS_STYLE_TOUCH_ACTION_NONE,
3920
0
                                     NS_STYLE_TOUCH_ACTION_MANIPULATION,
3921
0
                                     valueStr);
3922
0
  val->SetString(valueStr);
3923
0
  return val.forget();
3924
0
}
3925
3926
already_AddRefed<CSSValue>
3927
nsComputedDOMStyle::DoGetHeight()
3928
0
{
3929
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3930
0
3931
0
  bool calcHeight = false;
3932
0
3933
0
  if (mInnerFrame) {
3934
0
    calcHeight = true;
3935
0
3936
0
    const nsStyleDisplay* displayData = StyleDisplay();
3937
0
    if (displayData->mDisplay == mozilla::StyleDisplay::Inline &&
3938
0
        !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
3939
0
        // An outer SVG frame should behave the same as eReplaced in this case
3940
0
        !mInnerFrame->IsSVGOuterSVGFrame()) {
3941
0
3942
0
      calcHeight = false;
3943
0
    }
3944
0
  }
3945
0
3946
0
  if (calcHeight) {
3947
0
    AssertFlushedPendingReflows();
3948
0
    nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
3949
0
    val->SetAppUnits(mInnerFrame->GetContentRect().height +
3950
0
      adjustedValues.TopBottom());
3951
0
  } else {
3952
0
    const nsStylePosition *positionData = StylePosition();
3953
0
3954
0
    nscoord minHeight =
3955
0
      StyleCoordToNSCoord(positionData->mMinHeight,
3956
0
                          &nsComputedDOMStyle::GetCBContentHeight, 0, true);
3957
0
3958
0
    nscoord maxHeight =
3959
0
      StyleCoordToNSCoord(positionData->mMaxHeight,
3960
0
                          &nsComputedDOMStyle::GetCBContentHeight,
3961
0
                          nscoord_MAX, true);
3962
0
3963
0
    SetValueToCoord(val, positionData->mHeight, true, nullptr,
3964
0
                    nsCSSProps::kWidthKTable, minHeight, maxHeight);
3965
0
  }
3966
0
3967
0
  return val.forget();
3968
0
}
3969
3970
already_AddRefed<CSSValue>
3971
nsComputedDOMStyle::DoGetWidth()
3972
0
{
3973
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
3974
0
3975
0
  bool calcWidth = false;
3976
0
3977
0
  if (mInnerFrame) {
3978
0
    calcWidth = true;
3979
0
3980
0
    const nsStyleDisplay *displayData = StyleDisplay();
3981
0
    if (displayData->mDisplay == mozilla::StyleDisplay::Inline &&
3982
0
        !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
3983
0
        // An outer SVG frame should behave the same as eReplaced in this case
3984
0
        !mInnerFrame->IsSVGOuterSVGFrame()) {
3985
0
3986
0
      calcWidth = false;
3987
0
    }
3988
0
  }
3989
0
3990
0
  if (calcWidth) {
3991
0
    AssertFlushedPendingReflows();
3992
0
    nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
3993
0
    val->SetAppUnits(mInnerFrame->GetContentRect().width +
3994
0
      adjustedValues.LeftRight());
3995
0
  } else {
3996
0
    const nsStylePosition *positionData = StylePosition();
3997
0
3998
0
    nscoord minWidth =
3999
0
      StyleCoordToNSCoord(positionData->mMinWidth,
4000
0
                          &nsComputedDOMStyle::GetCBContentWidth, 0, true);
4001
0
4002
0
    nscoord maxWidth =
4003
0
      StyleCoordToNSCoord(positionData->mMaxWidth,
4004
0
                          &nsComputedDOMStyle::GetCBContentWidth,
4005
0
                          nscoord_MAX, true);
4006
0
4007
0
    SetValueToCoord(val, positionData->mWidth, true, nullptr,
4008
0
                    nsCSSProps::kWidthKTable, minWidth, maxWidth);
4009
0
  }
4010
0
4011
0
  return val.forget();
4012
0
}
4013
4014
already_AddRefed<CSSValue>
4015
nsComputedDOMStyle::DoGetMaxHeight()
4016
0
{
4017
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4018
0
  SetValueToCoord(val, StylePosition()->mMaxHeight, true,
4019
0
                  nullptr, nsCSSProps::kWidthKTable);
4020
0
  return val.forget();
4021
0
}
4022
4023
already_AddRefed<CSSValue>
4024
nsComputedDOMStyle::DoGetMaxWidth()
4025
0
{
4026
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4027
0
  SetValueToCoord(val, StylePosition()->mMaxWidth, true,
4028
0
                  nullptr, nsCSSProps::kWidthKTable);
4029
0
  return val.forget();
4030
0
}
4031
4032
/**
4033
 * This function indicates whether we should return "auto" as the
4034
 * getComputedStyle() result for the (default) "min-width: auto" and
4035
 * "min-height: auto" CSS values.
4036
 *
4037
 * As of this writing, the CSS Sizing draft spec says this "auto" value
4038
 * *always* computes to itself.  However, for now, we only make it compute to
4039
 * itself for grid and flex items (the containers where "auto" has special
4040
 * significance), because those are the only areas where the CSSWG has actually
4041
 * resolved on this "computes-to-itself" behavior. For elements in other sorts
4042
 * of containers, this function returns false, which will make us resolve
4043
 * "auto" to 0.
4044
 */
4045
bool
4046
nsComputedDOMStyle::ShouldHonorMinSizeAutoInAxis(PhysicalAxis aAxis)
4047
0
{
4048
0
  return mOuterFrame && mOuterFrame->IsFlexOrGridItem();
4049
0
}
4050
4051
already_AddRefed<CSSValue>
4052
nsComputedDOMStyle::DoGetMinHeight()
4053
0
{
4054
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4055
0
  nsStyleCoord minHeight = StylePosition()->mMinHeight;
4056
0
4057
0
  if (eStyleUnit_Auto == minHeight.GetUnit() &&
4058
0
      !ShouldHonorMinSizeAutoInAxis(eAxisVertical)) {
4059
0
    minHeight.SetCoordValue(0);
4060
0
  }
4061
0
4062
0
  SetValueToCoord(val, minHeight, true, nullptr, nsCSSProps::kWidthKTable);
4063
0
  return val.forget();
4064
0
}
4065
4066
already_AddRefed<CSSValue>
4067
nsComputedDOMStyle::DoGetMinWidth()
4068
0
{
4069
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4070
0
4071
0
  nsStyleCoord minWidth = StylePosition()->mMinWidth;
4072
0
4073
0
  if (eStyleUnit_Auto == minWidth.GetUnit() &&
4074
0
      !ShouldHonorMinSizeAutoInAxis(eAxisHorizontal)) {
4075
0
    minWidth.SetCoordValue(0);
4076
0
  }
4077
0
4078
0
  SetValueToCoord(val, minWidth, true, nullptr, nsCSSProps::kWidthKTable);
4079
0
  return val.forget();
4080
0
}
4081
4082
already_AddRefed<CSSValue>
4083
nsComputedDOMStyle::DoGetObjectPosition()
4084
0
{
4085
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
4086
0
  SetValueToPosition(StylePosition()->mObjectPosition, valueList);
4087
0
  return valueList.forget();
4088
0
}
4089
4090
already_AddRefed<CSSValue>
4091
nsComputedDOMStyle::DoGetLeft()
4092
0
{
4093
0
  return GetOffsetWidthFor(eSideLeft);
4094
0
}
4095
4096
already_AddRefed<CSSValue>
4097
nsComputedDOMStyle::DoGetRight()
4098
0
{
4099
0
  return GetOffsetWidthFor(eSideRight);
4100
0
}
4101
4102
already_AddRefed<CSSValue>
4103
nsComputedDOMStyle::DoGetTop()
4104
0
{
4105
0
  return GetOffsetWidthFor(eSideTop);
4106
0
}
4107
4108
already_AddRefed<CSSValue>
4109
nsComputedDOMStyle::GetOffsetWidthFor(mozilla::Side aSide)
4110
0
{
4111
0
  const nsStyleDisplay* display = StyleDisplay();
4112
0
4113
0
  AssertFlushedPendingReflows();
4114
0
4115
0
  uint8_t position = display->mPosition;
4116
0
  if (!mOuterFrame) {
4117
0
    // GetRelativeOffset and GetAbsoluteOffset don't handle elements
4118
0
    // without frames in any sensible way.  GetStaticOffset, however,
4119
0
    // is perfect for that case.
4120
0
    position = NS_STYLE_POSITION_STATIC;
4121
0
  }
4122
0
4123
0
  switch (position) {
4124
0
    case NS_STYLE_POSITION_STATIC:
4125
0
      return GetStaticOffset(aSide);
4126
0
    case NS_STYLE_POSITION_RELATIVE:
4127
0
      return GetRelativeOffset(aSide);
4128
0
    case NS_STYLE_POSITION_STICKY:
4129
0
      return GetStickyOffset(aSide);
4130
0
    case NS_STYLE_POSITION_ABSOLUTE:
4131
0
    case NS_STYLE_POSITION_FIXED:
4132
0
      return GetAbsoluteOffset(aSide);
4133
0
    default:
4134
0
      NS_ERROR("Invalid position");
4135
0
      return nullptr;
4136
0
  }
4137
0
}
4138
4139
already_AddRefed<CSSValue>
4140
nsComputedDOMStyle::GetAbsoluteOffset(mozilla::Side aSide)
4141
0
{
4142
0
  MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
4143
0
4144
0
  nsIFrame* container = mOuterFrame->GetContainingBlock();
4145
0
  nsMargin margin = mOuterFrame->GetUsedMargin();
4146
0
  nsMargin border = container->GetUsedBorder();
4147
0
  nsMargin scrollbarSizes(0, 0, 0, 0);
4148
0
  nsRect rect = mOuterFrame->GetRect();
4149
0
  nsRect containerRect = container->GetRect();
4150
0
4151
0
  if (container->IsViewportFrame()) {
4152
0
    // For absolutely positioned frames scrollbars are taken into
4153
0
    // account by virtue of getting a containing block that does
4154
0
    // _not_ include the scrollbars.  For fixed positioned frames,
4155
0
    // the containing block is the viewport, which _does_ include
4156
0
    // scrollbars.  We have to do some extra work.
4157
0
    // the first child in the default frame list is what we want
4158
0
    nsIFrame* scrollingChild = container->PrincipalChildList().FirstChild();
4159
0
    nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
4160
0
    if (scrollFrame) {
4161
0
      scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
4162
0
    }
4163
0
  } else if (container->IsGridContainerFrame() &&
4164
0
             (mOuterFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
4165
0
    containerRect = nsGridContainerFrame::GridItemCB(mOuterFrame);
4166
0
    rect.MoveBy(-containerRect.x, -containerRect.y);
4167
0
  }
4168
0
4169
0
  nscoord offset = 0;
4170
0
  switch (aSide) {
4171
0
    case eSideTop:
4172
0
      offset = rect.y - margin.top - border.top - scrollbarSizes.top;
4173
0
4174
0
      break;
4175
0
    case eSideRight:
4176
0
      offset = containerRect.width - rect.width -
4177
0
        rect.x - margin.right - border.right - scrollbarSizes.right;
4178
0
4179
0
      break;
4180
0
    case eSideBottom:
4181
0
      offset = containerRect.height - rect.height -
4182
0
        rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
4183
0
4184
0
      break;
4185
0
    case eSideLeft:
4186
0
      offset = rect.x - margin.left - border.left - scrollbarSizes.left;
4187
0
4188
0
      break;
4189
0
    default:
4190
0
      NS_ERROR("Invalid side");
4191
0
      break;
4192
0
  }
4193
0
4194
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4195
0
  val->SetAppUnits(offset);
4196
0
  return val.forget();
4197
0
}
4198
4199
static_assert(eSideTop == 0 && eSideRight == 1 &&
4200
              eSideBottom == 2 && eSideLeft == 3,
4201
              "box side constants not as expected for NS_OPPOSITE_SIDE");
4202
0
#define NS_OPPOSITE_SIDE(s_) mozilla::Side(((s_) + 2) & 3)
4203
4204
already_AddRefed<CSSValue>
4205
nsComputedDOMStyle::GetRelativeOffset(mozilla::Side aSide)
4206
0
{
4207
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4208
0
4209
0
  const nsStylePosition* positionData = StylePosition();
4210
0
  int32_t sign = 1;
4211
0
  nsStyleCoord coord = positionData->mOffset.Get(aSide);
4212
0
4213
0
  NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4214
0
               coord.GetUnit() == eStyleUnit_Percent ||
4215
0
               coord.GetUnit() == eStyleUnit_Auto ||
4216
0
               coord.IsCalcUnit(),
4217
0
               "Unexpected unit");
4218
0
4219
0
  if (coord.GetUnit() == eStyleUnit_Auto) {
4220
0
    coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
4221
0
    sign = -1;
4222
0
  }
4223
0
  PercentageBaseGetter baseGetter;
4224
0
  if (aSide == eSideLeft || aSide == eSideRight) {
4225
0
    baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
4226
0
  } else {
4227
0
    baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
4228
0
  }
4229
0
4230
0
  val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
4231
0
  return val.forget();
4232
0
}
4233
4234
already_AddRefed<CSSValue>
4235
nsComputedDOMStyle::GetStickyOffset(mozilla::Side aSide)
4236
0
{
4237
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4238
0
4239
0
  const nsStylePosition* positionData = StylePosition();
4240
0
  nsStyleCoord coord = positionData->mOffset.Get(aSide);
4241
0
4242
0
  NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4243
0
               coord.GetUnit() == eStyleUnit_Percent ||
4244
0
               coord.GetUnit() == eStyleUnit_Auto ||
4245
0
               coord.IsCalcUnit(),
4246
0
               "Unexpected unit");
4247
0
4248
0
  if (coord.GetUnit() == eStyleUnit_Auto) {
4249
0
    val->SetIdent(eCSSKeyword_auto);
4250
0
    return val.forget();
4251
0
  }
4252
0
  PercentageBaseGetter baseGetter;
4253
0
  if (aSide == eSideLeft || aSide == eSideRight) {
4254
0
    baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
4255
0
  } else {
4256
0
    baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
4257
0
  }
4258
0
4259
0
  val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
4260
0
  return val.forget();
4261
0
}
4262
4263
4264
already_AddRefed<CSSValue>
4265
nsComputedDOMStyle::GetStaticOffset(mozilla::Side aSide)
4266
0
{
4267
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4268
0
  SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
4269
0
  return val.forget();
4270
0
}
4271
4272
already_AddRefed<CSSValue>
4273
nsComputedDOMStyle::GetPaddingWidthFor(mozilla::Side aSide)
4274
0
{
4275
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4276
0
4277
0
  if (!mInnerFrame) {
4278
0
    SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
4279
0
  } else {
4280
0
    AssertFlushedPendingReflows();
4281
0
4282
0
    val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
4283
0
  }
4284
0
4285
0
  return val.forget();
4286
0
}
4287
4288
bool
4289
nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
4290
0
{
4291
0
  AssertFlushedPendingReflows();
4292
0
4293
0
  nscoord blockHeight = NS_AUTOHEIGHT;
4294
0
  if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
4295
0
    if (!mInnerFrame)
4296
0
      return false;
4297
0
4298
0
    if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
4299
0
      blockHeight = mInnerFrame->GetContentRect().height;
4300
0
    } else {
4301
0
      GetCBContentHeight(blockHeight);
4302
0
    }
4303
0
  }
4304
0
4305
0
  nsPresContext* presContext = mPresShell->GetPresContext();
4306
0
4307
0
  // lie about font size inflation since we lie about font size (since
4308
0
  // the inflation only applies to text)
4309
0
  aCoord = ReflowInput::CalcLineHeight(mElement,
4310
0
                                       mComputedStyle,
4311
0
                                       presContext,
4312
0
                                       blockHeight, 1.0f);
4313
0
4314
0
  // CalcLineHeight uses font->mFont.size, but we want to use
4315
0
  // font->mSize as the font size.  Adjust for that.  Also adjust for
4316
0
  // the text zoom, if any.
4317
0
  const nsStyleFont* font = StyleFont();
4318
0
  float fCoord = float(aCoord);
4319
0
  if (font->mAllowZoom) {
4320
0
    fCoord /= presContext->EffectiveTextZoom();
4321
0
  }
4322
0
  if (font->mFont.size != font->mSize) {
4323
0
    fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
4324
0
  }
4325
0
  aCoord = NSToCoordRound(fCoord);
4326
0
4327
0
  return true;
4328
0
}
4329
4330
already_AddRefed<CSSValue>
4331
nsComputedDOMStyle::GetBorderWidthFor(mozilla::Side aSide)
4332
0
{
4333
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4334
0
4335
0
  nscoord width;
4336
0
  if (mInnerFrame) {
4337
0
    AssertFlushedPendingReflows();
4338
0
    width = mInnerFrame->GetUsedBorder().Side(aSide);
4339
0
  } else {
4340
0
    width = StyleBorder()->GetComputedBorderWidth(aSide);
4341
0
  }
4342
0
  val->SetAppUnits(width);
4343
0
4344
0
  return val.forget();
4345
0
}
4346
4347
already_AddRefed<CSSValue>
4348
nsComputedDOMStyle::GetBorderColorFor(mozilla::Side aSide)
4349
0
{
4350
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4351
0
  SetValueFromComplexColor(val, StyleBorder()->BorderColorFor(aSide));
4352
0
  return val.forget();
4353
0
}
4354
4355
already_AddRefed<CSSValue>
4356
nsComputedDOMStyle::GetMarginWidthFor(mozilla::Side aSide)
4357
0
{
4358
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4359
0
4360
0
  if (!mInnerFrame) {
4361
0
    SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
4362
0
  } else {
4363
0
    AssertFlushedPendingReflows();
4364
0
4365
0
    // For tables, GetUsedMargin always returns an empty margin, so we
4366
0
    // should read the margin from the table wrapper frame instead.
4367
0
    val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
4368
0
    NS_ASSERTION(mOuterFrame == mInnerFrame ||
4369
0
                 mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
4370
0
                 "Inner tables must have zero margins");
4371
0
  }
4372
0
4373
0
  return val.forget();
4374
0
}
4375
4376
already_AddRefed<CSSValue>
4377
nsComputedDOMStyle::GetBorderStyleFor(mozilla::Side aSide)
4378
0
{
4379
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4380
0
  val->SetIdent(
4381
0
    nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
4382
0
                                   nsCSSProps::kBorderStyleKTable));
4383
0
  return val.forget();
4384
0
}
4385
4386
void
4387
nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
4388
                                    const nsStyleCoord& aCoord,
4389
                                    bool aClampNegativeCalc,
4390
                                    PercentageBaseGetter aPercentageBaseGetter,
4391
                                    const KTableEntry aTable[],
4392
                                    nscoord aMinAppUnits,
4393
                                    nscoord aMaxAppUnits)
4394
0
{
4395
0
  MOZ_ASSERT(aValue, "Must have a value to work with");
4396
0
4397
0
  switch (aCoord.GetUnit()) {
4398
0
    case eStyleUnit_Normal:
4399
0
      aValue->SetIdent(eCSSKeyword_normal);
4400
0
      break;
4401
0
4402
0
    case eStyleUnit_Auto:
4403
0
      aValue->SetIdent(eCSSKeyword_auto);
4404
0
      break;
4405
0
4406
0
    case eStyleUnit_Percent:
4407
0
      {
4408
0
        nscoord percentageBase;
4409
0
        if (aPercentageBaseGetter &&
4410
0
            (this->*aPercentageBaseGetter)(percentageBase)) {
4411
0
          nscoord val = NSCoordSaturatingMultiply(percentageBase,
4412
0
                                                  aCoord.GetPercentValue());
4413
0
          aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4414
0
        } else {
4415
0
          aValue->SetPercent(aCoord.GetPercentValue());
4416
0
        }
4417
0
      }
4418
0
      break;
4419
0
4420
0
    case eStyleUnit_Factor:
4421
0
      aValue->SetNumber(aCoord.GetFactorValue());
4422
0
      break;
4423
0
4424
0
    case eStyleUnit_Coord:
4425
0
      {
4426
0
        nscoord val = aCoord.GetCoordValue();
4427
0
        aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4428
0
      }
4429
0
      break;
4430
0
4431
0
    case eStyleUnit_Integer:
4432
0
      aValue->SetNumber(aCoord.GetIntValue());
4433
0
      break;
4434
0
4435
0
    case eStyleUnit_Enumerated:
4436
0
      NS_ASSERTION(aTable, "Must have table to handle this case");
4437
0
      aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
4438
0
                                                      aTable));
4439
0
      break;
4440
0
4441
0
    case eStyleUnit_None:
4442
0
      aValue->SetIdent(eCSSKeyword_none);
4443
0
      break;
4444
0
4445
0
    case eStyleUnit_Calc:
4446
0
      nscoord percentageBase;
4447
0
      if (!aCoord.CalcHasPercent()) {
4448
0
        nscoord val = aCoord.ComputeCoordPercentCalc(0);
4449
0
        if (aClampNegativeCalc && val < 0) {
4450
0
          MOZ_ASSERT(aCoord.IsCalcUnit(),
4451
0
                     "parser should have rejected value");
4452
0
          val = 0;
4453
0
        }
4454
0
        aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4455
0
      } else if (aPercentageBaseGetter &&
4456
0
                 (this->*aPercentageBaseGetter)(percentageBase)) {
4457
0
        nscoord val = aCoord.ComputeCoordPercentCalc(percentageBase);
4458
0
        if (aClampNegativeCalc && val < 0) {
4459
0
          MOZ_ASSERT(aCoord.IsCalcUnit(),
4460
0
                     "parser should have rejected value");
4461
0
          val = 0;
4462
0
        }
4463
0
        aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4464
0
      } else {
4465
0
        nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
4466
0
        SetValueToCalc(calc, aValue);
4467
0
      }
4468
0
      break;
4469
0
4470
0
    case eStyleUnit_Degree:
4471
0
      aValue->SetDegree(aCoord.GetAngleValue());
4472
0
      break;
4473
0
4474
0
    case eStyleUnit_Grad:
4475
0
      aValue->SetGrad(aCoord.GetAngleValue());
4476
0
      break;
4477
0
4478
0
    case eStyleUnit_Radian:
4479
0
      aValue->SetRadian(aCoord.GetAngleValue());
4480
0
      break;
4481
0
4482
0
    case eStyleUnit_Turn:
4483
0
      aValue->SetTurn(aCoord.GetAngleValue());
4484
0
      break;
4485
0
4486
0
    case eStyleUnit_FlexFraction: {
4487
0
      nsAutoString tmpStr;
4488
0
      nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
4489
0
      tmpStr.AppendLiteral("fr");
4490
0
      aValue->SetString(tmpStr);
4491
0
      break;
4492
0
    }
4493
0
4494
0
    default:
4495
0
      NS_ERROR("Can't handle this unit");
4496
0
      break;
4497
0
  }
4498
0
}
4499
4500
nscoord
4501
nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
4502
                                        PercentageBaseGetter aPercentageBaseGetter,
4503
                                        nscoord aDefaultValue,
4504
                                        bool aClampNegativeCalc)
4505
0
{
4506
0
  MOZ_ASSERT(aPercentageBaseGetter, "Must have a percentage base getter");
4507
0
  if (aCoord.GetUnit() == eStyleUnit_Coord) {
4508
0
    return aCoord.GetCoordValue();
4509
0
  }
4510
0
  if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
4511
0
    nscoord percentageBase;
4512
0
    if ((this->*aPercentageBaseGetter)(percentageBase)) {
4513
0
      nscoord result = aCoord.ComputeCoordPercentCalc(percentageBase);
4514
0
      if (aClampNegativeCalc && result < 0) {
4515
0
        // It's expected that we can get a negative value here with calc().
4516
0
        // We can also get a negative value with a percentage value if
4517
0
        // percentageBase is negative; this isn't expected, but can happen
4518
0
        // when large length values overflow.
4519
0
        NS_WARNING_ASSERTION(
4520
0
          percentageBase >= 0,
4521
0
          "percentage base value overflowed to become negative for a property "
4522
0
          "that disallows negative values");
4523
0
        MOZ_ASSERT(aCoord.IsCalcUnit() ||
4524
0
                   (aCoord.HasPercent() && percentageBase < 0),
4525
0
                   "parser should have rejected value");
4526
0
        result = 0;
4527
0
      }
4528
0
      return result;
4529
0
    }
4530
0
    // Fall through to returning aDefaultValue if we have no percentage base.
4531
0
  }
4532
0
4533
0
  return aDefaultValue;
4534
0
}
4535
4536
bool
4537
nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
4538
0
{
4539
0
  if (!mOuterFrame) {
4540
0
    return false;
4541
0
  }
4542
0
4543
0
  AssertFlushedPendingReflows();
4544
0
4545
0
  nsIFrame* container = mOuterFrame->GetContainingBlock();
4546
0
  aWidth = container->GetContentRect().width;
4547
0
  return true;
4548
0
}
4549
4550
bool
4551
nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
4552
0
{
4553
0
  if (!mOuterFrame) {
4554
0
    return false;
4555
0
  }
4556
0
4557
0
  AssertFlushedPendingReflows();
4558
0
4559
0
  nsIFrame* container = mOuterFrame->GetContainingBlock();
4560
0
  aHeight = container->GetContentRect().height;
4561
0
  return true;
4562
0
}
4563
4564
bool
4565
nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth)
4566
0
{
4567
0
  if (!mOuterFrame) {
4568
0
    return false;
4569
0
  }
4570
0
4571
0
  AssertFlushedPendingReflows();
4572
0
4573
0
  nsIScrollableFrame* scrollableFrame =
4574
0
    nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4575
0
      nsLayoutUtils::SCROLLABLE_SAME_DOC |
4576
0
      nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4577
0
4578
0
  if (!scrollableFrame) {
4579
0
    return false;
4580
0
  }
4581
0
  aWidth =
4582
0
    scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width;
4583
0
  return true;
4584
0
}
4585
4586
bool
4587
nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight)
4588
0
{
4589
0
  if (!mOuterFrame) {
4590
0
    return false;
4591
0
  }
4592
0
4593
0
  AssertFlushedPendingReflows();
4594
0
4595
0
  nsIScrollableFrame* scrollableFrame =
4596
0
    nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4597
0
      nsLayoutUtils::SCROLLABLE_SAME_DOC |
4598
0
      nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4599
0
4600
0
  if (!scrollableFrame) {
4601
0
    return false;
4602
0
  }
4603
0
  aHeight =
4604
0
    scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height;
4605
0
  return true;
4606
0
}
4607
4608
bool
4609
nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
4610
0
{
4611
0
  if (!mInnerFrame) {
4612
0
    return false;
4613
0
  }
4614
0
4615
0
  AssertFlushedPendingReflows();
4616
0
4617
0
  aWidth = mInnerFrame->GetSize().width;
4618
0
  return true;
4619
0
}
4620
4621
bool
4622
nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
4623
0
{
4624
0
  if (!mInnerFrame) {
4625
0
    return false;
4626
0
  }
4627
0
4628
0
  AssertFlushedPendingReflows();
4629
0
4630
0
  aHeight = mInnerFrame->GetSize().height;
4631
0
  return true;
4632
0
}
4633
4634
bool
4635
nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
4636
0
{
4637
0
  // We need a frame to work with.
4638
0
  if (!mInnerFrame) {
4639
0
    return false;
4640
0
  }
4641
0
4642
0
  AssertFlushedPendingReflows();
4643
0
4644
0
  aWidth = nsStyleTransformMatrix::TransformReferenceBox(mInnerFrame).Width();
4645
0
  return true;
4646
0
}
4647
4648
bool
4649
nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
4650
0
{
4651
0
  // We need a frame to work with.
4652
0
  if (!mInnerFrame) {
4653
0
    return false;
4654
0
  }
4655
0
4656
0
  AssertFlushedPendingReflows();
4657
0
4658
0
  aHeight = nsStyleTransformMatrix::TransformReferenceBox(mInnerFrame).Height();
4659
0
  return true;
4660
0
}
4661
4662
already_AddRefed<CSSValue>
4663
nsComputedDOMStyle::GetFallbackValue(const nsStyleSVGPaint* aPaint)
4664
0
{
4665
0
  RefPtr<nsROCSSPrimitiveValue> fallback = new nsROCSSPrimitiveValue;
4666
0
  if (aPaint->GetFallbackType() == eStyleSVGFallbackType_Color) {
4667
0
    SetToRGBAColor(fallback, aPaint->GetFallbackColor(mComputedStyle));
4668
0
  } else {
4669
0
    fallback->SetIdent(eCSSKeyword_none);
4670
0
  }
4671
0
  return fallback.forget();
4672
0
}
4673
4674
already_AddRefed<CSSValue>
4675
nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
4676
0
{
4677
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4678
0
4679
0
  const nsStyleSVG* svg = StyleSVG();
4680
0
  const nsStyleSVGPaint* paint = aFill ? &svg->mFill : &svg->mStroke;
4681
0
4682
0
  nsAutoString paintString;
4683
0
4684
0
  switch (paint->Type()) {
4685
0
    case eStyleSVGPaintType_None:
4686
0
      val->SetIdent(eCSSKeyword_none);
4687
0
      break;
4688
0
    case eStyleSVGPaintType_Color:
4689
0
      SetToRGBAColor(val, paint->GetColor(mComputedStyle));
4690
0
      break;
4691
0
    case eStyleSVGPaintType_Server: {
4692
0
      SetValueToURLValue(paint->GetPaintServer(), val);
4693
0
      if (paint->GetFallbackType() != eStyleSVGFallbackType_NotSet) {
4694
0
        RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
4695
0
        RefPtr<CSSValue> fallback = GetFallbackValue(paint);
4696
0
        valueList->AppendCSSValue(val.forget());
4697
0
        valueList->AppendCSSValue(fallback.forget());
4698
0
        return valueList.forget();
4699
0
      }
4700
0
      break;
4701
0
    }
4702
0
    case eStyleSVGPaintType_ContextFill:
4703
0
    case eStyleSVGPaintType_ContextStroke: {
4704
0
      val->SetIdent(paint->Type() == eStyleSVGPaintType_ContextFill ?
4705
0
                    eCSSKeyword_context_fill : eCSSKeyword_context_stroke);
4706
0
      if (paint->GetFallbackType() != eStyleSVGFallbackType_NotSet) {
4707
0
        RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
4708
0
        RefPtr<CSSValue> fallback = GetFallbackValue(paint);
4709
0
        valueList->AppendCSSValue(val.forget());
4710
0
        valueList->AppendCSSValue(fallback.forget());
4711
0
        return valueList.forget();
4712
0
      }
4713
0
      break;
4714
0
    }
4715
0
  }
4716
0
4717
0
  return val.forget();
4718
0
}
4719
4720
/* If the property is "none", hand back "none" wrapped in a value.
4721
 * Otherwise, compute the aggregate transform matrix and hands it back in a
4722
 * "matrix" wrapper.
4723
 */
4724
already_AddRefed<CSSValue>
4725
nsComputedDOMStyle::GetTransformValue(nsCSSValueSharedList* aSpecifiedTransform)
4726
0
{
4727
0
  /* If there are no transforms, then we should construct a single-element
4728
0
   * entry and hand it back.
4729
0
   */
4730
0
  if (!aSpecifiedTransform) {
4731
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4732
0
4733
0
    /* Set it to "none." */
4734
0
    val->SetIdent(eCSSKeyword_none);
4735
0
    return val.forget();
4736
0
  }
4737
0
4738
0
  /* Otherwise, we need to compute the current value of the transform matrix,
4739
0
   * store it in a string, and hand it back to the caller.
4740
0
   */
4741
0
4742
0
  /* Use the inner frame for the reference box.  If we don't have an inner
4743
0
   * frame we use empty dimensions to allow us to continue (and percentage
4744
0
   * values in the transform will simply give broken results).
4745
0
   * TODO: There is no good way for us to represent the case where there's no
4746
0
   * frame, which is problematic.  The reason is that when we have percentage
4747
0
   * transforms, there are a total of four stored matrix entries that influence
4748
0
   * the transform based on the size of the element.  However, this poses a
4749
0
   * problem, because only two of these values can be explicitly referenced
4750
0
   * using the named transforms.  Until a real solution is found, we'll just
4751
0
   * use this approach.
4752
0
   */
4753
0
  nsStyleTransformMatrix::TransformReferenceBox refBox(mInnerFrame,
4754
0
                                                       nsSize(0, 0));
4755
0
4756
0
   bool dummyBool;
4757
0
   gfx::Matrix4x4 matrix =
4758
0
     nsStyleTransformMatrix::ReadTransforms(aSpecifiedTransform->mHead,
4759
0
                                            refBox,
4760
0
                                            float(mozilla::AppUnitsPerCSSPixel()),
4761
0
                                            &dummyBool);
4762
0
4763
0
  return MatrixToCSSValue(matrix);
4764
0
}
4765
4766
already_AddRefed<CSSValue>
4767
nsComputedDOMStyle::DoGetFill()
4768
0
{
4769
0
  return GetSVGPaintFor(true);
4770
0
}
4771
4772
already_AddRefed<CSSValue>
4773
nsComputedDOMStyle::DoGetStroke()
4774
0
{
4775
0
  return GetSVGPaintFor(false);
4776
0
}
4777
4778
already_AddRefed<CSSValue>
4779
nsComputedDOMStyle::DoGetMarkerEnd()
4780
0
{
4781
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4782
0
  SetValueToURLValue(StyleSVG()->mMarkerEnd, val);
4783
0
4784
0
  return val.forget();
4785
0
}
4786
4787
already_AddRefed<CSSValue>
4788
nsComputedDOMStyle::DoGetMarkerMid()
4789
0
{
4790
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4791
0
  SetValueToURLValue(StyleSVG()->mMarkerMid, val);
4792
0
4793
0
  return val.forget();
4794
0
}
4795
4796
already_AddRefed<CSSValue>
4797
nsComputedDOMStyle::DoGetMarkerStart()
4798
0
{
4799
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4800
0
  SetValueToURLValue(StyleSVG()->mMarkerStart, val);
4801
0
4802
0
  return val.forget();
4803
0
}
4804
4805
already_AddRefed<CSSValue>
4806
nsComputedDOMStyle::DoGetStrokeDasharray()
4807
0
{
4808
0
  const nsStyleSVG* svg = StyleSVG();
4809
0
4810
0
  if (svg->mStrokeDasharray.IsEmpty()) {
4811
0
    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4812
0
    val->SetIdent(eCSSKeyword_none);
4813
0
    return val.forget();
4814
0
  }
4815
0
4816
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
4817
0
4818
0
  for (uint32_t i = 0; i < svg->mStrokeDasharray.Length(); i++) {
4819
0
    RefPtr<nsROCSSPrimitiveValue> dash = new nsROCSSPrimitiveValue;
4820
0
    SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
4821
0
    valueList->AppendCSSValue(dash.forget());
4822
0
  }
4823
0
4824
0
  return valueList.forget();
4825
0
}
4826
4827
already_AddRefed<CSSValue>
4828
nsComputedDOMStyle::DoGetStrokeDashoffset()
4829
0
{
4830
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4831
0
  SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
4832
0
  return val.forget();
4833
0
}
4834
4835
already_AddRefed<CSSValue>
4836
nsComputedDOMStyle::DoGetStrokeWidth()
4837
0
{
4838
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4839
0
  SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
4840
0
  return val.forget();
4841
0
}
4842
4843
already_AddRefed<CSSValue>
4844
nsComputedDOMStyle::DoGetFillOpacity()
4845
0
{
4846
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4847
0
  val->SetNumber(StyleSVG()->mFillOpacity);
4848
0
  return val.forget();
4849
0
}
4850
4851
already_AddRefed<CSSValue>
4852
nsComputedDOMStyle::DoGetStrokeMiterlimit()
4853
0
{
4854
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4855
0
  val->SetNumber(StyleSVG()->mStrokeMiterlimit);
4856
0
  return val.forget();
4857
0
}
4858
4859
already_AddRefed<CSSValue>
4860
nsComputedDOMStyle::DoGetStrokeOpacity()
4861
0
{
4862
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
4863
0
  val->SetNumber(StyleSVG()->mStrokeOpacity);
4864
0
  return val.forget();
4865
0
}
4866
4867
void
4868
nsComputedDOMStyle::BoxValuesToString(nsAString& aString,
4869
                                      const nsTArray<nsStyleCoord>& aBoxValues,
4870
                                      bool aClampNegativeCalc)
4871
0
{
4872
0
  MOZ_ASSERT(aBoxValues.Length() == 4, "wrong number of box values");
4873
0
  nsAutoString value1, value2, value3, value4;
4874
0
  SetCssTextToCoord(value1, aBoxValues[0], aClampNegativeCalc);
4875
0
  SetCssTextToCoord(value2, aBoxValues[1], aClampNegativeCalc);
4876
0
  SetCssTextToCoord(value3, aBoxValues[2], aClampNegativeCalc);
4877
0
  SetCssTextToCoord(value4, aBoxValues[3], aClampNegativeCalc);
4878
0
4879
0
  // nsROCSSPrimitiveValue do not have binary comparison operators.
4880
0
  // Compare string results instead.
4881
0
  aString.Append(value1);
4882
0
  if (value1 != value2 || value1 != value3 || value1 != value4) {
4883
0
    aString.Append(' ');
4884
0
    aString.Append(value2);
4885
0
    if (value1 != value3 || value2 != value4) {
4886
0
      aString.Append(' ');
4887
0
      aString.Append(value3);
4888
0
      if (value2 != value4) {
4889
0
        aString.Append(' ');
4890
0
        aString.Append(value4);
4891
0
      }
4892
0
    }
4893
0
  }
4894
0
}
4895
4896
void
4897
nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
4898
                                            const nsStyleCorners& aCorners)
4899
0
{
4900
0
  nsTArray<nsStyleCoord> horizontal, vertical;
4901
0
  nsAutoString horizontalString, verticalString;
4902
0
  NS_FOR_CSS_FULL_CORNERS(corner) {
4903
0
    horizontal.AppendElement(
4904
0
      aCorners.Get(FullToHalfCorner(corner, false)));
4905
0
    vertical.AppendElement(
4906
0
      aCorners.Get(FullToHalfCorner(corner, true)));
4907
0
  }
4908
0
  BoxValuesToString(horizontalString, horizontal, true);
4909
0
  BoxValuesToString(verticalString, vertical, true);
4910
0
  aCssText.Append(horizontalString);
4911
0
  if (horizontalString == verticalString) {
4912
0
    return;
4913
0
  }
4914
0
  aCssText.AppendLiteral(" / ");
4915
0
  aCssText.Append(verticalString);
4916
0
}
4917
4918
already_AddRefed<CSSValue>
4919
nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
4920
  const UniquePtr<StyleBasicShape>& aStyleBasicShape)
4921
0
{
4922
0
  MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
4923
0
4924
0
  StyleBasicShapeType type = aStyleBasicShape->GetShapeType();
4925
0
  // Shape function name and opening parenthesis.
4926
0
  nsAutoString shapeFunctionString;
4927
0
  AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
4928
0
                       aStyleBasicShape->GetShapeTypeName()),
4929
0
                     shapeFunctionString);
4930
0
  shapeFunctionString.Append('(');
4931
0
  switch (type) {
4932
0
    case StyleBasicShapeType::Polygon: {
4933
0
      bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
4934
0
        StyleFillRule::Evenodd;
4935
0
      if (hasEvenOdd) {
4936
0
        shapeFunctionString.AppendLiteral("evenodd");
4937
0
      }
4938
0
      for (size_t i = 0;
4939
0
           i < aStyleBasicShape->Coordinates().Length(); i += 2) {
4940
0
        nsAutoString coordString;
4941
0
        if (i > 0 || hasEvenOdd) {
4942
0
          shapeFunctionString.AppendLiteral(", ");
4943
0
        }
4944
0
        SetCssTextToCoord(coordString,
4945
0
                          aStyleBasicShape->Coordinates()[i],
4946
0
                          false);
4947
0
        shapeFunctionString.Append(coordString);
4948
0
        shapeFunctionString.Append(' ');
4949
0
        SetCssTextToCoord(coordString,
4950
0
                          aStyleBasicShape->Coordinates()[i + 1],
4951
0
                          false);
4952
0
        shapeFunctionString.Append(coordString);
4953
0
      }
4954
0
      break;
4955
0
    }
4956
0
    case StyleBasicShapeType::Circle:
4957
0
    case StyleBasicShapeType::Ellipse: {
4958
0
      const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
4959
0
      MOZ_ASSERT(radii.Length() ==
4960
0
                 (type == StyleBasicShapeType::Circle ? 1 : 2),
4961
0
                 "wrong number of radii");
4962
0
      for (size_t i = 0; i < radii.Length(); ++i) {
4963
0
        nsAutoString radius;
4964
0
        RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
4965
0
        bool clampNegativeCalc = true;
4966
0
        SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
4967
0
                        nsCSSProps::kShapeRadiusKTable);
4968
0
        value->GetCssText(radius);
4969
0
        shapeFunctionString.Append(radius);
4970
0
        shapeFunctionString.Append(' ');
4971
0
      }
4972
0
      shapeFunctionString.AppendLiteral("at ");
4973
0
4974
0
      RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
4975
0
      nsAutoString positionString;
4976
0
      SetValueToPosition(aStyleBasicShape->GetPosition(), position);
4977
0
      position->GetCssText(positionString);
4978
0
      shapeFunctionString.Append(positionString);
4979
0
      break;
4980
0
    }
4981
0
    case StyleBasicShapeType::Inset: {
4982
0
      BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates(), false);
4983
0
      if (aStyleBasicShape->HasRadius()) {
4984
0
        shapeFunctionString.AppendLiteral(" round ");
4985
0
        nsAutoString radiiString;
4986
0
        BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
4987
0
        shapeFunctionString.Append(radiiString);
4988
0
      }
4989
0
      break;
4990
0
    }
4991
0
    default:
4992
0
      MOZ_ASSERT_UNREACHABLE("unexpected type");
4993
0
  }
4994
0
  shapeFunctionString.Append(')');
4995
0
  RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
4996
0
  functionValue->SetString(shapeFunctionString);
4997
0
  return functionValue.forget();
4998
0
}
4999
5000
template<typename ReferenceBox>
5001
already_AddRefed<CSSValue>
5002
nsComputedDOMStyle::CreatePrimitiveValueForShapeSource(
5003
  const UniquePtr<StyleBasicShape>& aStyleBasicShape,
5004
  ReferenceBox aReferenceBox,
5005
  const KTableEntry aBoxKeywordTable[])
5006
{
5007
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
5008
  if (aStyleBasicShape) {
5009
    valueList->AppendCSSValue(
5010
      CreatePrimitiveValueForBasicShape(aStyleBasicShape));
5011
  }
5012
5013
  if (aReferenceBox == ReferenceBox::NoBox) {
5014
    return valueList.forget();
5015
  }
5016
5017
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
5018
  val->SetIdent(nsCSSProps::ValueToKeywordEnum(aReferenceBox, aBoxKeywordTable));
5019
  valueList->AppendCSSValue(val.forget());
5020
5021
  return valueList.forget();
5022
}
5023
5024
void
5025
nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
5026
                                      const nsStyleCoord& aCoord,
5027
                                      bool aClampNegativeCalc)
5028
0
{
5029
0
  RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
5030
0
  SetValueToCoord(value, aCoord, aClampNegativeCalc);
5031
0
  value->GetCssText(aCssText);
5032
0
}
5033
5034
already_AddRefed<CSSValue>
5035
nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
5036
  const nsStyleFilter& aStyleFilter)
5037
0
{
5038
0
  RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
5039
0
  // Handle url().
5040
0
  if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
5041
0
    MOZ_ASSERT(aStyleFilter.GetURL() &&
5042
0
               aStyleFilter.GetURL()->GetURI());
5043
0
    SetValueToURLValue(aStyleFilter.GetURL(), value);
5044
0
    return value.forget();
5045
0
  }
5046
0
5047
0
  // Filter function name and opening parenthesis.
5048
0
  nsAutoString filterFunctionString;
5049
0
  AppendASCIItoUTF16(
5050
0
    nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
5051
0
                               nsCSSProps::kFilterFunctionKTable),
5052
0
                               filterFunctionString);
5053
0
  filterFunctionString.Append('(');
5054
0
5055
0
  nsAutoString argumentString;
5056
0
  if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
5057
0
    // Handle drop-shadow()
5058
0
    RefPtr<CSSValue> shadowValue =
5059
0
      GetCSSShadowArray(aStyleFilter.GetDropShadow(), false);
5060
0
    ErrorResult dummy;
5061
0
    shadowValue->GetCssText(argumentString, dummy);
5062
0
  } else {
5063
0
    // Filter function argument.
5064
0
    SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter(), true);
5065
0
  }
5066
0
  filterFunctionString.Append(argumentString);
5067
0
5068
0
  // Filter function closing parenthesis.
5069
0
  filterFunctionString.Append(')');
5070
0
5071
0
  value->SetString(filterFunctionString);
5072
0
  return value.forget();
5073
0
}
5074
5075
already_AddRefed<CSSValue>
5076
nsComputedDOMStyle::DoGetFilter()
5077
0
{
5078
0
  const nsTArray<nsStyleFilter>& filters = StyleEffects()->mFilters;
5079
0
5080
0
  if (filters.IsEmpty()) {
5081
0
    RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
5082
0
    value->SetIdent(eCSSKeyword_none);
5083
0
    return value.forget();
5084
0
  }
5085
0
5086
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
5087
0
  for(uint32_t i = 0; i < filters.Length(); i++) {
5088
0
    RefPtr<CSSValue> value = CreatePrimitiveValueForStyleFilter(filters[i]);
5089
0
    valueList->AppendCSSValue(value.forget());
5090
0
  }
5091
0
  return valueList.forget();
5092
0
}
5093
5094
already_AddRefed<CSSValue>
5095
nsComputedDOMStyle::DoGetMask()
5096
0
{
5097
0
  const nsStyleSVGReset* svg = StyleSVGReset();
5098
0
  const nsStyleImageLayers::Layer& firstLayer = svg->mMask.mLayers[0];
5099
0
5100
0
  // Mask is now a shorthand, but it used to be a longhand, so that we
5101
0
  // need to support computed style for the cases where it used to be
5102
0
  // a longhand.
5103
0
  if (svg->mMask.mImageCount > 1 ||
5104
0
      firstLayer.mClip != StyleGeometryBox::BorderBox ||
5105
0
      firstLayer.mOrigin != StyleGeometryBox::BorderBox ||
5106
0
      firstLayer.mComposite != NS_STYLE_MASK_COMPOSITE_ADD ||
5107
0
      firstLayer.mMaskMode != NS_STYLE_MASK_MODE_MATCH_SOURCE ||
5108
0
      !nsStyleImageLayers::IsInitialPositionForLayerType(
5109
0
        firstLayer.mPosition, nsStyleImageLayers::LayerType::Mask) ||
5110
0
      !firstLayer.mRepeat.IsInitialValue() ||
5111
0
      !firstLayer.mSize.IsInitialValue() ||
5112
0
      !(firstLayer.mImage.GetType() == eStyleImageType_Null ||
5113
0
        firstLayer.mImage.GetType() == eStyleImageType_Image ||
5114
0
        firstLayer.mImage.GetType() == eStyleImageType_URL)) {
5115
0
    return nullptr;
5116
0
  }
5117
0
5118
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
5119
0
5120
0
  SetValueToURLValue(firstLayer.mImage.GetURLValue(), val);
5121
0
5122
0
  return val.forget();
5123
0
}
5124
5125
already_AddRefed<CSSValue>
5126
nsComputedDOMStyle::DoGetMaskImage()
5127
0
{
5128
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5129
0
  return DoGetImageLayerImage(layers);
5130
0
}
5131
5132
already_AddRefed<CSSValue>
5133
nsComputedDOMStyle::DoGetMaskPosition()
5134
0
{
5135
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5136
0
  return DoGetImageLayerPosition(layers);
5137
0
}
5138
5139
already_AddRefed<CSSValue>
5140
nsComputedDOMStyle::DoGetMaskPositionX()
5141
0
{
5142
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5143
0
  return DoGetImageLayerPositionX(layers);
5144
0
}
5145
5146
already_AddRefed<CSSValue>
5147
nsComputedDOMStyle::DoGetMaskPositionY()
5148
0
{
5149
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5150
0
  return DoGetImageLayerPositionY(layers);
5151
0
}
5152
5153
already_AddRefed<CSSValue>
5154
nsComputedDOMStyle::DoGetMaskRepeat()
5155
0
{
5156
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5157
0
  return DoGetImageLayerRepeat(layers);
5158
0
}
5159
5160
already_AddRefed<CSSValue>
5161
nsComputedDOMStyle::DoGetMaskSize()
5162
0
{
5163
0
  const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
5164
0
  return DoGetImageLayerSize(layers);
5165
0
}
5166
5167
already_AddRefed<CSSValue>
5168
nsComputedDOMStyle::DoGetPaintOrder()
5169
0
{
5170
0
  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
5171
0
  nsAutoString string;
5172
0
  uint8_t paintOrder = StyleSVG()->mPaintOrder;
5173
0
  nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
5174
0
  val->SetString(string);
5175
0
  return val.forget();
5176
0
}
5177
5178
already_AddRefed<CSSValue>
5179
nsComputedDOMStyle::DoGetTransitionDelay()
5180
0
{
5181
0
  const nsStyleDisplay* display = StyleDisplay();
5182
0
5183
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5184
0
5185
0
  MOZ_ASSERT(display->mTransitionDelayCount > 0,
5186
0
             "first item must be explicit");
5187
0
  uint32_t i = 0;
5188
0
  do {
5189
0
    const StyleTransition *transition = &display->mTransitions[i];
5190
0
    RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
5191
0
    delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
5192
0
    valueList->AppendCSSValue(delay.forget());
5193
0
  } while (++i < display->mTransitionDelayCount);
5194
0
5195
0
  return valueList.forget();
5196
0
}
5197
5198
already_AddRefed<CSSValue>
5199
nsComputedDOMStyle::DoGetTransitionDuration()
5200
0
{
5201
0
  const nsStyleDisplay* display = StyleDisplay();
5202
0
5203
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5204
0
5205
0
  MOZ_ASSERT(display->mTransitionDurationCount > 0,
5206
0
             "first item must be explicit");
5207
0
  uint32_t i = 0;
5208
0
  do {
5209
0
    const StyleTransition *transition = &display->mTransitions[i];
5210
0
    RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
5211
0
5212
0
    duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
5213
0
    valueList->AppendCSSValue(duration.forget());
5214
0
  } while (++i < display->mTransitionDurationCount);
5215
0
5216
0
  return valueList.forget();
5217
0
}
5218
5219
already_AddRefed<CSSValue>
5220
nsComputedDOMStyle::DoGetTransitionProperty()
5221
0
{
5222
0
  const nsStyleDisplay* display = StyleDisplay();
5223
0
5224
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5225
0
5226
0
  MOZ_ASSERT(display->mTransitionPropertyCount > 0,
5227
0
             "first item must be explicit");
5228
0
  uint32_t i = 0;
5229
0
  do {
5230
0
    const StyleTransition *transition = &display->mTransitions[i];
5231
0
    RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
5232
0
    nsCSSPropertyID cssprop = transition->GetProperty();
5233
0
    if (cssprop == eCSSPropertyExtra_all_properties)
5234
0
      property->SetIdent(eCSSKeyword_all);
5235
0
    else if (cssprop == eCSSPropertyExtra_no_properties)
5236
0
      property->SetIdent(eCSSKeyword_none);
5237
0
    else if (cssprop == eCSSProperty_UNKNOWN ||
5238
0
             cssprop == eCSSPropertyExtra_variable)
5239
0
    {
5240
0
      nsAutoString escaped;
5241
0
      nsStyleUtil::AppendEscapedCSSIdent(
5242
0
        nsDependentAtomString(transition->GetUnknownProperty()), escaped);
5243
0
      property->SetString(escaped); // really want SetIdent
5244
0
    }
5245
0
    else
5246
0
      property->SetString(nsCSSProps::GetStringValue(cssprop));
5247
0
5248
0
    valueList->AppendCSSValue(property.forget());
5249
0
  } while (++i < display->mTransitionPropertyCount);
5250
0
5251
0
  return valueList.forget();
5252
0
}
5253
5254
void
5255
nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
5256
                                         const nsTimingFunction& aTimingFunction)
5257
0
{
5258
0
  RefPtr<nsROCSSPrimitiveValue> timingFunction = new nsROCSSPrimitiveValue;
5259
0
5260
0
  nsAutoString tmp;
5261
0
  switch (aTimingFunction.mType) {
5262
0
    case nsTimingFunction::Type::CubicBezier:
5263
0
      nsStyleUtil::AppendCubicBezierTimingFunction(aTimingFunction.mFunc.mX1,
5264
0
                                                   aTimingFunction.mFunc.mY1,
5265
0
                                                   aTimingFunction.mFunc.mX2,
5266
0
                                                   aTimingFunction.mFunc.mY2,
5267
0
                                                   tmp);
5268
0
      break;
5269
0
    case nsTimingFunction::Type::StepStart:
5270
0
    case nsTimingFunction::Type::StepEnd:
5271
0
      nsStyleUtil::AppendStepsTimingFunction(aTimingFunction.mType,
5272
0
                                             aTimingFunction.mStepsOrFrames,
5273
0
                                             tmp);
5274
0
      break;
5275
0
    case nsTimingFunction::Type::Frames:
5276
0
      nsStyleUtil::AppendFramesTimingFunction(aTimingFunction.mStepsOrFrames,
5277
0
                                              tmp);
5278
0
      break;
5279
0
    default:
5280
0
      nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
5281
0
                                                          tmp);
5282
0
      break;
5283
0
  }
5284
0
  timingFunction->SetString(tmp);
5285
0
  aValueList->AppendCSSValue(timingFunction.forget());
5286
0
}
5287
5288
already_AddRefed<CSSValue>
5289
nsComputedDOMStyle::DoGetTransitionTimingFunction()
5290
0
{
5291
0
  const nsStyleDisplay* display = StyleDisplay();
5292
0
5293
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5294
0
5295
0
  MOZ_ASSERT(display->mTransitionTimingFunctionCount > 0,
5296
0
             "first item must be explicit");
5297
0
  uint32_t i = 0;
5298
0
  do {
5299
0
    AppendTimingFunction(valueList,
5300
0
                         display->mTransitions[i].GetTimingFunction());
5301
0
  } while (++i < display->mTransitionTimingFunctionCount);
5302
0
5303
0
  return valueList.forget();
5304
0
}
5305
5306
already_AddRefed<CSSValue>
5307
nsComputedDOMStyle::DoGetAnimationName()
5308
0
{
5309
0
  const nsStyleDisplay* display = StyleDisplay();
5310
0
5311
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5312
0
5313
0
  MOZ_ASSERT(display->mAnimationNameCount > 0,
5314
0
             "first item must be explicit");
5315
0
  uint32_t i = 0;
5316
0
  do {
5317
0
    const StyleAnimation *animation = &display->mAnimations[i];
5318
0
    RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
5319
0
5320
0
    nsAtom* name = animation->GetName();
5321
0
    if (name == nsGkAtoms::_empty) {
5322
0
      property->SetIdent(eCSSKeyword_none);
5323
0
    } else {
5324
0
      nsDependentAtomString nameStr(name);
5325
0
      nsAutoString escaped;
5326
0
      nsStyleUtil::AppendEscapedCSSIdent(nameStr, escaped);
5327
0
      property->SetString(escaped); // really want SetIdent
5328
0
    }
5329
0
    valueList->AppendCSSValue(property.forget());
5330
0
  } while (++i < display->mAnimationNameCount);
5331
0
5332
0
  return valueList.forget();
5333
0
}
5334
5335
already_AddRefed<CSSValue>
5336
nsComputedDOMStyle::DoGetAnimationDelay()
5337
0
{
5338
0
  const nsStyleDisplay* display = StyleDisplay();
5339
0
5340
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5341
0
5342
0
  MOZ_ASSERT(display->mAnimationDelayCount > 0,
5343
0
             "first item must be explicit");
5344
0
  uint32_t i = 0;
5345
0
  do {
5346
0
    const StyleAnimation *animation = &display->mAnimations[i];
5347
0
    RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
5348
0
    delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
5349
0
    valueList->AppendCSSValue(delay.forget());
5350
0
  } while (++i < display->mAnimationDelayCount);
5351
0
5352
0
  return valueList.forget();
5353
0
}
5354
5355
already_AddRefed<CSSValue>
5356
nsComputedDOMStyle::DoGetAnimationDuration()
5357
0
{
5358
0
  const nsStyleDisplay* display = StyleDisplay();
5359
0
5360
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5361
0
5362
0
  MOZ_ASSERT(display->mAnimationDurationCount > 0,
5363
0
             "first item must be explicit");
5364
0
  uint32_t i = 0;
5365
0
  do {
5366
0
    const StyleAnimation *animation = &display->mAnimations[i];
5367
0
    RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
5368
0
5369
0
    duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
5370
0
    valueList->AppendCSSValue(duration.forget());
5371
0
  } while (++i < display->mAnimationDurationCount);
5372
0
5373
0
  return valueList.forget();
5374
0
}
5375
5376
already_AddRefed<CSSValue>
5377
nsComputedDOMStyle::DoGetAnimationTimingFunction()
5378
0
{
5379
0
  const nsStyleDisplay* display = StyleDisplay();
5380
0
5381
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5382
0
5383
0
  MOZ_ASSERT(display->mAnimationTimingFunctionCount > 0,
5384
0
             "first item must be explicit");
5385
0
  uint32_t i = 0;
5386
0
  do {
5387
0
    AppendTimingFunction(valueList,
5388
0
                         display->mAnimations[i].GetTimingFunction());
5389
0
  } while (++i < display->mAnimationTimingFunctionCount);
5390
0
5391
0
  return valueList.forget();
5392
0
}
5393
5394
already_AddRefed<CSSValue>
5395
nsComputedDOMStyle::DoGetAnimationIterationCount()
5396
0
{
5397
0
  const nsStyleDisplay* display = StyleDisplay();
5398
0
5399
0
  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
5400
0
5401
0
  MOZ_ASSERT(display->mAnimationIterationCountCount > 0,
5402
0
             "first item must be explicit");
5403
0
  uint32_t i = 0;
5404
0
  do {
5405
0
    const StyleAnimation *animation = &display->mAnimations[i];
5406
0
    RefPtr<nsROCSSPrimitiveValue> iterationCount = new nsROCSSPrimitiveValue;
5407
0
5408
0
    float f = animation->GetIterationCount();
5409
0
    if (f == PositiveInfinity<float>()) {
5410
0
      iterationCount->SetIdent(eCSSKeyword_infinite);
5411
0
    } else {
5412
0
      iterationCount->SetNumber(f);
5413
0
    }
5414
0
    valueList->AppendCSSValue(iterationCount.forget());
5415
0
  } while (++i < display->mAnimationIterationCountCount);
5416
0
5417
0
  return valueList.forget();
5418
0
}
5419
5420
already_AddRefed<CSSValue>
5421
nsComputedDOMStyle::DummyGetter()
5422
0
{
5423
0
  MOZ_CRASH("DummyGetter is not supposed to be invoked");
5424
0
}
5425
5426
static void
5427
MarkComputedStyleMapDirty(const char* aPref, ComputedStyleMap* aData)
5428
0
{
5429
0
  aData->MarkDirty();
5430
0
}
5431
5432
void
5433
nsComputedDOMStyle::ParentChainChanged(nsIContent* aContent)
5434
0
{
5435
0
  NS_ASSERTION(mElement == aContent, "didn't we register mElement?");
5436
0
  NS_ASSERTION(mResolvedComputedStyle,
5437
0
               "should have only registered an observer when "
5438
0
               "mResolvedComputedStyle is true");
5439
0
5440
0
  ClearComputedStyle();
5441
0
}
5442
5443
/* static */ ComputedStyleMap*
5444
nsComputedDOMStyle::GetComputedStyleMap()
5445
3
{
5446
3
  static ComputedStyleMap map{};
5447
3
  return &map;
5448
3
}
5449
5450
static StaticAutoPtr<nsTArray<const char*>> gCallbackPrefs;
5451
5452
/* static */ void
5453
nsComputedDOMStyle::RegisterPrefChangeCallbacks()
5454
3
{
5455
3
  // Note that this will register callbacks for all properties with prefs, not
5456
3
  // just those that are implemented on computed style objects, as it's not
5457
3
  // easy to grab specific property data from ServoCSSPropList.h based on the
5458
3
  // entries iterated in nsComputedDOMStylePropertyList.h.
5459
3
5460
3
  AutoTArray<const char*, 64> prefs;
5461
3
  for (const auto* p = nsCSSProps::kPropertyPrefTable;
5462
405
       p->mPropID != eCSSProperty_UNKNOWN; p++) {
5463
402
    // Many properties are controlled by the same preference, so de-duplicate
5464
402
    // them before adding observers.
5465
402
    //
5466
402
    // Note: This is done by pointer comparison, which works because the mPref
5467
402
    // members are string literals from the same same translation unit, and are
5468
402
    // therefore de-duplicated by the compiler. On the off chance that we wind
5469
402
    // up with some duplicates with different pointers, though, it's not a bit
5470
402
    // deal.
5471
402
    if (!prefs.ContainsSorted(p->mPref)) {
5472
96
      prefs.InsertElementSorted(p->mPref);
5473
96
    }
5474
402
  }
5475
3
  prefs.AppendElement(nullptr);
5476
3
5477
3
  MOZ_ASSERT(!gCallbackPrefs);
5478
3
  gCallbackPrefs = new nsTArray<const char*>(std::move(prefs));
5479
3
5480
3
  Preferences::RegisterCallbacks(MarkComputedStyleMapDirty,
5481
3
                                 gCallbackPrefs->Elements(),
5482
3
                                 GetComputedStyleMap());
5483
3
}
5484
5485
/* static */ void
5486
nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
5487
0
{
5488
0
  if (!gCallbackPrefs) {
5489
0
    return;
5490
0
  }
5491
0
5492
0
  Preferences::UnregisterCallbacks(MarkComputedStyleMapDirty,
5493
0
                                   gCallbackPrefs->Elements(),
5494
0
                                   GetComputedStyleMap());
5495
0
  gCallbackPrefs = nullptr;
5496
0
}