/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 ↦ |
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 | } |