Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set tw=78 expandtab softtabstop=2 ts=2 sw=2: */
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/. */
7 /* DOM object returned from element.getComputedStyle() */
9 #include "nsComputedDOMStyle.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/Preferences.h"
14 #include "nsError.h"
15 #include "nsDOMString.h"
16 #include "nsIDOMCSSPrimitiveValue.h"
17 #include "nsStyleContext.h"
18 #include "nsIScrollableFrame.h"
19 #include "nsContentUtils.h"
20 #include "nsIContent.h"
22 #include "nsDOMCSSRect.h"
23 #include "nsDOMCSSRGBColor.h"
24 #include "nsDOMCSSValueList.h"
25 #include "nsGkAtoms.h"
26 #include "nsHTMLReflowState.h"
27 #include "nsStyleUtil.h"
28 #include "nsStyleStructInlines.h"
29 #include "nsROCSSPrimitiveValue.h"
31 #include "nsPresContext.h"
32 #include "nsIDocument.h"
34 #include "nsCSSPseudoElements.h"
35 #include "nsStyleSet.h"
36 #include "imgIRequest.h"
37 #include "nsLayoutUtils.h"
38 #include "nsCSSKeywords.h"
39 #include "nsStyleCoord.h"
40 #include "nsDisplayList.h"
41 #include "nsDOMCSSDeclaration.h"
42 #include "nsStyleTransformMatrix.h"
43 #include "mozilla/dom/Element.h"
44 #include "prtime.h"
45 #include "nsWrapperCacheInlines.h"
46 #include "mozilla/AppUnits.h"
47 #include <algorithm>
49 using namespace mozilla;
50 using namespace mozilla::dom;
52 #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
53 #define DEBUG_ComputedDOMStyle
54 #endif
56 /*
57 * This is the implementation of the readonly CSSStyleDeclaration that is
58 * returned by the getComputedStyle() function.
59 */
61 static nsComputedDOMStyle *sCachedComputedDOMStyle;
63 already_AddRefed<nsComputedDOMStyle>
64 NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
65 nsIPresShell* aPresShell,
66 nsComputedDOMStyle::StyleType aStyleType)
67 {
68 nsRefPtr<nsComputedDOMStyle> computedStyle;
69 if (sCachedComputedDOMStyle) {
70 // There's an unused nsComputedDOMStyle cached, use it.
71 // But before we use it, re-initialize the object.
73 // Oh yeah baby, placement new!
74 computedStyle = new (sCachedComputedDOMStyle)
75 nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, aStyleType);
77 sCachedComputedDOMStyle = nullptr;
78 } else {
79 // No nsComputedDOMStyle cached, create a new one.
81 computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell,
82 aStyleType);
83 }
85 return computedStyle.forget();
86 }
88 /**
89 * An object that represents the ordered set of properties that are exposed on
90 * an nsComputedDOMStyle object and how their computed values can be obtained.
91 */
92 struct nsComputedStyleMap
93 {
94 friend class nsComputedDOMStyle;
96 struct Entry
97 {
98 // Create a pointer-to-member-function type.
99 typedef mozilla::dom::CSSValue* (nsComputedDOMStyle::*ComputeMethod)();
101 nsCSSProperty mProperty;
102 ComputeMethod mGetter;
104 bool IsLayoutFlushNeeded() const
105 {
106 return nsCSSProps::PropHasFlags(mProperty,
107 CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH);
108 }
110 bool IsEnabled() const
111 {
112 return nsCSSProps::IsEnabled(mProperty);
113 }
114 };
116 // We define this enum just to count the total number of properties that can
117 // be exposed on an nsComputedDOMStyle, including properties that may be
118 // disabled.
119 enum {
120 #define COMPUTED_STYLE_PROP(prop_, method_) \
121 eComputedStyleProperty_##prop_,
122 #include "nsComputedDOMStylePropertyList.h"
123 #undef COMPUTED_STYLE_PROP
124 eComputedStyleProperty_COUNT
125 };
127 /**
128 * Returns the number of properties that should be exposed on an
129 * nsComputedDOMStyle, ecxluding any disabled properties.
130 */
131 uint32_t Length()
132 {
133 Update();
134 return mExposedPropertyCount;
135 }
137 /**
138 * Returns the property at the given index in the list of properties
139 * that should be exposed on an nsComputedDOMStyle, excluding any
140 * disabled properties.
141 */
142 nsCSSProperty PropertyAt(uint32_t aIndex)
143 {
144 Update();
145 return kEntries[EntryIndex(aIndex)].mProperty;
146 }
148 /**
149 * Searches for and returns the computed style map entry for the given
150 * property, or nullptr if the property is not exposed on nsComputedDOMStyle
151 * or is currently disabled.
152 */
153 const Entry* FindEntryForProperty(nsCSSProperty aPropID)
154 {
155 Update();
156 for (uint32_t i = 0; i < mExposedPropertyCount; i++) {
157 const Entry* entry = &kEntries[EntryIndex(i)];
158 if (entry->mProperty == aPropID) {
159 return entry;
160 }
161 }
162 return nullptr;
163 }
165 /**
166 * Records that mIndexMap needs updating, due to prefs changing that could
167 * affect the set of properties exposed on an nsComputedDOMStyle.
168 */
169 void MarkDirty() { mExposedPropertyCount = 0; }
171 // The member variables are public so that we can use an initializer in
172 // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions
173 // above to get information from this object.
175 /**
176 * An entry for each property that can be exposed on an nsComputedDOMStyle.
177 */
178 const Entry kEntries[eComputedStyleProperty_COUNT];
180 /**
181 * The number of properties that should be exposed on an nsComputedDOMStyle.
182 * This will be less than eComputedStyleProperty_COUNT if some property
183 * prefs are disabled. A value of 0 indicates that it and mIndexMap are out
184 * of date.
185 */
186 uint32_t mExposedPropertyCount;
188 /**
189 * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
190 */
191 uint32_t mIndexMap[eComputedStyleProperty_COUNT];
193 private:
194 /**
195 * Returns whether mExposedPropertyCount and mIndexMap are out of date.
196 */
197 bool IsDirty() { return mExposedPropertyCount == 0; }
199 /**
200 * Updates mExposedPropertyCount and mIndexMap to take into account properties
201 * whose prefs are currently disabled.
202 */
203 void Update();
205 /**
206 * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
207 */
208 uint32_t EntryIndex(uint32_t aIndex) const
209 {
210 MOZ_ASSERT(aIndex < mExposedPropertyCount);
211 return mIndexMap[aIndex];
212 }
213 };
215 void
216 nsComputedStyleMap::Update()
217 {
218 if (!IsDirty()) {
219 return;
220 }
222 uint32_t index = 0;
223 for (uint32_t i = 0; i < eComputedStyleProperty_COUNT; i++) {
224 if (kEntries[i].IsEnabled()) {
225 mIndexMap[index++] = i;
226 }
227 }
228 mExposedPropertyCount = index;
229 }
231 nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
232 const nsAString& aPseudoElt,
233 nsIPresShell* aPresShell,
234 StyleType aStyleType)
235 : mDocumentWeak(nullptr), mOuterFrame(nullptr),
236 mInnerFrame(nullptr), mPresShell(nullptr),
237 mStyleType(aStyleType),
238 mExposeVisitedStyle(false)
239 {
240 MOZ_ASSERT(aElement && aPresShell);
242 mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
244 mContent = aElement;
246 if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() &&
247 aPseudoElt.First() == char16_t(':')) {
248 // deal with two-colon forms of aPseudoElt
249 nsAString::const_iterator start, end;
250 aPseudoElt.BeginReading(start);
251 aPseudoElt.EndReading(end);
252 NS_ASSERTION(start != end, "aPseudoElt is not empty!");
253 ++start;
254 bool haveTwoColons = true;
255 if (start == end || *start != char16_t(':')) {
256 --start;
257 haveTwoColons = false;
258 }
259 mPseudo = do_GetAtom(Substring(start, end));
260 MOZ_ASSERT(mPseudo);
262 // There aren't any non-CSS2 pseudo-elements with a single ':'
263 if (!haveTwoColons &&
264 (!nsCSSPseudoElements::IsPseudoElement(mPseudo) ||
265 !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo))) {
266 // XXXbz I'd really rather we threw an exception or something, but
267 // the DOM spec sucks.
268 mPseudo = nullptr;
269 }
270 }
272 MOZ_ASSERT(aPresShell->GetPresContext());
273 }
276 nsComputedDOMStyle::~nsComputedDOMStyle()
277 {
278 }
280 void
281 nsComputedDOMStyle::Shutdown()
282 {
283 // We want to de-allocate without calling the dtor since we
284 // already did that manually in doDestroyComputedDOMStyle(),
285 // so cast our cached object to something that doesn't know
286 // about our dtor.
287 delete reinterpret_cast<char*>(sCachedComputedDOMStyle);
288 sCachedComputedDOMStyle = nullptr;
289 }
292 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsComputedDOMStyle, mContent)
294 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
295 return tmp->IsBlack();
296 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
298 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
299 return tmp->IsBlack();
300 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
302 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
303 return tmp->IsBlack();
304 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
306 // QueryInterface implementation for nsComputedDOMStyle
307 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle)
308 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
309 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
312 static void doDestroyComputedDOMStyle(nsComputedDOMStyle *aComputedStyle)
313 {
314 if (!sCachedComputedDOMStyle) {
315 // The cache is empty, store aComputedStyle in the cache.
317 sCachedComputedDOMStyle = aComputedStyle;
318 sCachedComputedDOMStyle->~nsComputedDOMStyle();
319 } else {
320 // The cache is full, delete aComputedStyle
322 delete aComputedStyle;
323 }
324 }
326 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
327 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsComputedDOMStyle,
328 doDestroyComputedDOMStyle(this))
331 NS_IMETHODIMP
332 nsComputedDOMStyle::GetPropertyValue(const nsCSSProperty aPropID,
333 nsAString& aValue)
334 {
335 // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
336 // perf ever becomes an issue here (doubtful), we can look into changing
337 // this.
338 return GetPropertyValue(
339 NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
340 aValue);
341 }
343 NS_IMETHODIMP
344 nsComputedDOMStyle::SetPropertyValue(const nsCSSProperty aPropID,
345 const nsAString& aValue)
346 {
347 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
348 }
351 NS_IMETHODIMP
352 nsComputedDOMStyle::GetCssText(nsAString& aCssText)
353 {
354 aCssText.Truncate();
356 return NS_OK;
357 }
360 NS_IMETHODIMP
361 nsComputedDOMStyle::SetCssText(const nsAString& aCssText)
362 {
363 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
364 }
367 NS_IMETHODIMP
368 nsComputedDOMStyle::GetLength(uint32_t* aLength)
369 {
370 NS_PRECONDITION(aLength, "Null aLength! Prepare to die!");
372 uint32_t length = GetComputedStyleMap()->Length();
374 // Make sure we have up to date style so that we can include custom
375 // properties.
376 UpdateCurrentStyleSources(false);
377 if (mStyleContextHolder) {
378 length += StyleVariables()->mVariables.Count();
379 }
381 *aLength = length;
383 ClearCurrentStyleSources();
385 return NS_OK;
386 }
389 NS_IMETHODIMP
390 nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule)
391 {
392 *aParentRule = nullptr;
394 return NS_OK;
395 }
398 NS_IMETHODIMP
399 nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
400 nsAString& aReturn)
401 {
402 aReturn.Truncate();
404 ErrorResult error;
405 nsRefPtr<CSSValue> val = GetPropertyCSSValue(aPropertyName, error);
406 if (error.Failed()) {
407 return error.ErrorCode();
408 }
410 if (val) {
411 nsString text;
412 val->GetCssText(text, error);
413 aReturn.Assign(text);
414 return error.ErrorCode();
415 }
417 return NS_OK;
418 }
420 NS_IMETHODIMP
421 nsComputedDOMStyle::GetAuthoredPropertyValue(const nsAString& aPropertyName,
422 nsAString& aReturn)
423 {
424 // Authored style doesn't make sense to return from computed DOM style,
425 // so just return whatever GetPropertyValue() returns.
426 return GetPropertyValue(aPropertyName, aReturn);
427 }
429 /* static */
430 already_AddRefed<nsStyleContext>
431 nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
432 nsIAtom* aPseudo,
433 nsIPresShell* aPresShell,
434 StyleType aStyleType)
435 {
436 // If the content has a pres shell, we must use it. Otherwise we'd
437 // potentially mix rule trees by using the wrong pres shell's style
438 // set. Using the pres shell from the content also means that any
439 // content that's actually *in* a document will get the style from the
440 // correct document.
441 nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
442 if (!presShell) {
443 presShell = aPresShell;
444 if (!presShell)
445 return nullptr;
446 }
448 presShell->FlushPendingNotifications(Flush_Style);
450 return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
451 aStyleType);
452 }
454 /* static */
455 already_AddRefed<nsStyleContext>
456 nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
457 nsIAtom* aPseudo,
458 nsIPresShell* aPresShell,
459 StyleType aStyleType)
460 {
461 NS_ABORT_IF_FALSE(aElement, "NULL element");
462 // If the content has a pres shell, we must use it. Otherwise we'd
463 // potentially mix rule trees by using the wrong pres shell's style
464 // set. Using the pres shell from the content also means that any
465 // content that's actually *in* a document will get the style from the
466 // correct document.
467 nsIPresShell *presShell = GetPresShellForContent(aElement);
468 if (!presShell) {
469 presShell = aPresShell;
470 if (!presShell)
471 return nullptr;
472 }
474 if (!aPseudo && aStyleType == eAll) {
475 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
476 if (frame) {
477 nsStyleContext* result = frame->StyleContext();
478 // Don't use the style context if it was influenced by
479 // pseudo-elements, since then it's not the primary style
480 // for this element.
481 if (!result->HasPseudoElementData()) {
482 // this function returns an addrefed style context
483 nsRefPtr<nsStyleContext> ret = result;
484 return ret.forget();
485 }
486 }
487 }
489 // No frame has been created, or we have a pseudo, or we're looking
490 // for the default style, so resolve the style ourselves.
491 nsRefPtr<nsStyleContext> parentContext;
492 nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
493 // Don't resolve parent context for document fragments.
494 if (parent && parent->IsElement())
495 parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
496 nullptr, presShell,
497 aStyleType);
499 nsPresContext *presContext = presShell->GetPresContext();
500 if (!presContext)
501 return nullptr;
503 nsStyleSet *styleSet = presShell->StyleSet();
505 nsRefPtr<nsStyleContext> sc;
506 if (aPseudo) {
507 nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
508 if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
509 return nullptr;
510 }
511 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
512 Element* pseudoElement = frame ? frame->GetPseudoElement(type) : nullptr;
513 sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
514 pseudoElement);
515 } else {
516 sc = styleSet->ResolveStyleFor(aElement, parentContext);
517 }
519 if (aStyleType == eDefaultOnly) {
520 // We really only want the user and UA rules. Filter out the other ones.
521 nsTArray< nsCOMPtr<nsIStyleRule> > rules;
522 for (nsRuleNode* ruleNode = sc->RuleNode();
523 !ruleNode->IsRoot();
524 ruleNode = ruleNode->GetParent()) {
525 if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet ||
526 ruleNode->GetLevel() == nsStyleSet::eUserSheet) {
527 rules.AppendElement(ruleNode->GetRule());
528 }
529 }
531 // We want to build a list of user/ua rules that is in order from least to
532 // most important, so we have to reverse the list.
533 // Integer division to get "stop" is purposeful here: if length is odd, we
534 // don't have to do anything with the middle element of the array.
535 for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
536 i < stop; ++i) {
537 rules[i].swap(rules[length - i - 1]);
538 }
540 sc = styleSet->ResolveStyleForRules(parentContext, rules);
541 }
543 return sc.forget();
544 }
546 nsMargin
547 nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
548 {
549 // We want the width/height of whatever parts 'width' or 'height' controls,
550 // which can be different depending on the value of the 'box-sizing' property.
551 const nsStylePosition* stylePos = StylePosition();
553 nsMargin adjustment;
554 switch(stylePos->mBoxSizing) {
555 case NS_STYLE_BOX_SIZING_BORDER:
556 adjustment += mInnerFrame->GetUsedBorder();
557 // fall through
559 case NS_STYLE_BOX_SIZING_PADDING:
560 adjustment += mInnerFrame->GetUsedPadding();
561 }
563 return adjustment;
564 }
566 /* static */
567 nsIPresShell*
568 nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent)
569 {
570 nsIDocument* currentDoc = aContent->GetCurrentDoc();
571 if (!currentDoc)
572 return nullptr;
574 return currentDoc->GetShell();
575 }
577 // nsDOMCSSDeclaration abstract methods which should never be called
578 // on a nsComputedDOMStyle object, but must be defined to avoid
579 // compile errors.
580 css::Declaration*
581 nsComputedDOMStyle::GetCSSDeclaration(bool)
582 {
583 NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration");
584 return nullptr;
585 }
587 nsresult
588 nsComputedDOMStyle::SetCSSDeclaration(css::Declaration*)
589 {
590 NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration");
591 return NS_ERROR_FAILURE;
592 }
594 nsIDocument*
595 nsComputedDOMStyle::DocToUpdate()
596 {
597 NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate");
598 return nullptr;
599 }
601 void
602 nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
603 {
604 NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment");
605 // Just in case NS_RUNTIMEABORT ever stops killing us for some reason
606 aCSSParseEnv.mPrincipal = nullptr;
607 }
609 void
610 nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
611 {
612 MOZ_ASSERT(!mStyleContextHolder);
614 nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
615 if (!document) {
616 return;
617 }
619 document->FlushPendingLinkUpdates();
621 // Flush _before_ getting the presshell, since that could create a new
622 // presshell. Also note that we want to flush the style on the document
623 // we're computing style in, not on the document mContent is in -- the two
624 // may be different.
625 document->FlushPendingNotifications(
626 aNeedsLayoutFlush ? Flush_Layout : Flush_Style);
627 #ifdef DEBUG
628 mFlushedPendingReflows = aNeedsLayoutFlush;
629 #endif
631 mPresShell = document->GetShell();
632 if (!mPresShell || !mPresShell->GetPresContext()) {
633 return;
634 }
636 if (!mPseudo && mStyleType == eAll) {
637 mOuterFrame = mContent->GetPrimaryFrame();
638 mInnerFrame = mOuterFrame;
639 if (mOuterFrame) {
640 nsIAtom* type = mOuterFrame->GetType();
641 if (type == nsGkAtoms::tableOuterFrame) {
642 // If the frame is an outer table frame then we should get the style
643 // from the inner table frame.
644 mInnerFrame = mOuterFrame->GetFirstPrincipalChild();
645 NS_ASSERTION(mInnerFrame, "Outer table must have an inner");
646 NS_ASSERTION(!mInnerFrame->GetNextSibling(),
647 "Outer table frames should have just one child, "
648 "the inner table");
649 }
651 mStyleContextHolder = mInnerFrame->StyleContext();
652 NS_ASSERTION(mStyleContextHolder, "Frame without style context?");
653 }
654 }
656 if (!mStyleContextHolder || mStyleContextHolder->HasPseudoElementData()) {
657 #ifdef DEBUG
658 if (mStyleContextHolder) {
659 // We want to check that going through this path because of
660 // HasPseudoElementData is rare, because it slows us down a good
661 // bit. So check that we're really inside something associated
662 // with a pseudo-element that contains elements.
663 nsStyleContext *topWithPseudoElementData = mStyleContextHolder;
664 while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
665 topWithPseudoElementData = topWithPseudoElementData->GetParent();
666 }
667 nsCSSPseudoElements::Type pseudo =
668 topWithPseudoElementData->GetPseudoType();
669 nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo);
670 nsAutoString assertMsg(
671 NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements ("));
672 assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String()));
673 assertMsg.Append(NS_LITERAL_STRING(")"));
674 NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo),
675 NS_LossyConvertUTF16toASCII(assertMsg).get());
676 }
677 #endif
678 // Need to resolve a style context
679 mStyleContextHolder =
680 nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(),
681 mPseudo,
682 mPresShell,
683 mStyleType);
684 if (!mStyleContextHolder) {
685 return;
686 }
688 NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(),
689 "should not have pseudo-element data");
690 }
692 // mExposeVisitedStyle is set to true only by testing APIs that
693 // require chrome privilege.
694 NS_ABORT_IF_FALSE(!mExposeVisitedStyle ||
695 nsContentUtils::IsCallerChrome(),
696 "mExposeVisitedStyle set incorrectly");
697 if (mExposeVisitedStyle && mStyleContextHolder->RelevantLinkVisited()) {
698 nsStyleContext *styleIfVisited = mStyleContextHolder->GetStyleIfVisited();
699 if (styleIfVisited) {
700 mStyleContextHolder = styleIfVisited;
701 }
702 }
703 }
705 void
706 nsComputedDOMStyle::ClearCurrentStyleSources()
707 {
708 mOuterFrame = nullptr;
709 mInnerFrame = nullptr;
710 mPresShell = nullptr;
712 // Release the current style context for it should be re-resolved
713 // whenever a frame is not available.
714 mStyleContextHolder = nullptr;
715 }
717 already_AddRefed<CSSValue>
718 nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
719 {
720 nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName,
721 nsCSSProps::eEnabledForAllContent);
723 bool needsLayoutFlush;
724 nsComputedStyleMap::Entry::ComputeMethod getter;
726 if (prop == eCSSPropertyExtra_variable) {
727 needsLayoutFlush = false;
728 getter = nullptr;
729 } else {
730 // We don't (for now, anyway, though it may make sense to change it
731 // for all aliases, including those in nsCSSPropAliasList) want
732 // aliases to be enumerable (via GetLength and IndexedGetter), so
733 // handle them here rather than adding entries to
734 // GetQueryablePropertyMap.
735 if (prop != eCSSProperty_UNKNOWN &&
736 nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_IS_ALIAS)) {
737 const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(prop);
738 NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN,
739 "must have list of length 1");
740 prop = subprops[0];
741 }
743 const nsComputedStyleMap::Entry* propEntry =
744 GetComputedStyleMap()->FindEntryForProperty(prop);
746 if (!propEntry) {
747 #ifdef DEBUG_ComputedDOMStyle
748 NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) +
749 NS_LITERAL_CSTRING(" is not queryable!")).get());
750 #endif
752 // NOTE: For branches, we should flush here for compatibility!
753 return nullptr;
754 }
756 needsLayoutFlush = propEntry->IsLayoutFlushNeeded();
757 getter = propEntry->mGetter;
758 }
760 UpdateCurrentStyleSources(needsLayoutFlush);
761 if (!mStyleContextHolder) {
762 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
763 return nullptr;
764 }
766 nsRefPtr<CSSValue> val;
767 if (prop == eCSSPropertyExtra_variable) {
768 val = DoGetCustomProperty(aPropertyName);
769 } else {
770 // Call our pointer-to-member-function.
771 val = (this->*getter)();
772 }
774 ClearCurrentStyleSources();
776 return val.forget();
777 }
780 NS_IMETHODIMP
781 nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
782 nsAString& aReturn)
783 {
784 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
785 }
788 NS_IMETHODIMP
789 nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
790 nsAString& aReturn)
791 {
792 aReturn.Truncate();
794 return NS_OK;
795 }
798 NS_IMETHODIMP
799 nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
800 const nsAString& aValue,
801 const nsAString& aPriority)
802 {
803 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
804 }
807 NS_IMETHODIMP
808 nsComputedDOMStyle::Item(uint32_t aIndex, nsAString& aReturn)
809 {
810 return nsDOMCSSDeclaration::Item(aIndex, aReturn);
811 }
813 void
814 nsComputedDOMStyle::IndexedGetter(uint32_t aIndex, bool& aFound,
815 nsAString& aPropName)
816 {
817 nsComputedStyleMap* map = GetComputedStyleMap();
818 uint32_t length = map->Length();
820 if (aIndex < length) {
821 aFound = true;
822 CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)),
823 aPropName);
824 return;
825 }
827 // Custom properties are exposed with indexed properties just after all
828 // of the built-in properties.
829 UpdateCurrentStyleSources(false);
830 if (!mStyleContextHolder) {
831 aFound = false;
832 return;
833 }
835 const nsStyleVariables* variables = StyleVariables();
836 if (aIndex - length < variables->mVariables.Count()) {
837 aFound = true;
838 variables->mVariables.GetVariableAt(aIndex - length, aPropName);
839 } else {
840 aFound = false;
841 }
843 ClearCurrentStyleSources();
844 }
846 // Property getters...
848 CSSValue*
849 nsComputedDOMStyle::DoGetBinding()
850 {
851 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
853 const nsStyleDisplay* display = StyleDisplay();
855 if (display->mBinding) {
856 val->SetURI(display->mBinding->GetURI());
857 } else {
858 val->SetIdent(eCSSKeyword_none);
859 }
861 return val;
862 }
864 CSSValue*
865 nsComputedDOMStyle::DoGetClear()
866 {
867 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
868 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType,
869 nsCSSProps::kClearKTable));
870 return val;
871 }
873 CSSValue*
874 nsComputedDOMStyle::DoGetFloat()
875 {
876 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
877 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloats,
878 nsCSSProps::kFloatKTable));
879 return val;
880 }
882 CSSValue*
883 nsComputedDOMStyle::DoGetBottom()
884 {
885 return GetOffsetWidthFor(NS_SIDE_BOTTOM);
886 }
888 CSSValue*
889 nsComputedDOMStyle::DoGetStackSizing()
890 {
891 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
892 val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
893 eCSSKeyword_ignore);
894 return val;
895 }
897 void
898 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
899 nscolor aColor)
900 {
901 if (NS_GET_A(aColor) == 0) {
902 aValue->SetIdent(eCSSKeyword_transparent);
903 return;
904 }
906 nsROCSSPrimitiveValue *red = new nsROCSSPrimitiveValue;
907 nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue;
908 nsROCSSPrimitiveValue *blue = new nsROCSSPrimitiveValue;
909 nsROCSSPrimitiveValue *alpha = new nsROCSSPrimitiveValue;
911 uint8_t a = NS_GET_A(aColor);
912 nsDOMCSSRGBColor *rgbColor =
913 new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
915 red->SetNumber(NS_GET_R(aColor));
916 green->SetNumber(NS_GET_G(aColor));
917 blue->SetNumber(NS_GET_B(aColor));
918 alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
920 aValue->SetColor(rgbColor);
921 }
923 CSSValue*
924 nsComputedDOMStyle::DoGetColor()
925 {
926 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
927 SetToRGBAColor(val, StyleColor()->mColor);
928 return val;
929 }
931 CSSValue*
932 nsComputedDOMStyle::DoGetOpacity()
933 {
934 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
935 val->SetNumber(StyleDisplay()->mOpacity);
936 return val;
937 }
939 CSSValue*
940 nsComputedDOMStyle::DoGetColumnCount()
941 {
942 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
944 const nsStyleColumn* column = StyleColumn();
946 if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
947 val->SetIdent(eCSSKeyword_auto);
948 } else {
949 val->SetNumber(column->mColumnCount);
950 }
952 return val;
953 }
955 CSSValue*
956 nsComputedDOMStyle::DoGetColumnWidth()
957 {
958 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
960 // XXX fix the auto case. When we actually have a column frame, I think
961 // we should return the computed column width.
962 SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
963 return val;
964 }
966 CSSValue*
967 nsComputedDOMStyle::DoGetColumnGap()
968 {
969 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
971 const nsStyleColumn* column = StyleColumn();
972 if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
973 val->SetAppUnits(StyleFont()->mFont.size);
974 } else {
975 SetValueToCoord(val, StyleColumn()->mColumnGap, true);
976 }
978 return val;
979 }
981 CSSValue*
982 nsComputedDOMStyle::DoGetColumnFill()
983 {
984 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
985 val->SetIdent(
986 nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill,
987 nsCSSProps::kColumnFillKTable));
988 return val;
989 }
991 CSSValue*
992 nsComputedDOMStyle::DoGetColumnRuleWidth()
993 {
994 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
995 val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
996 return val;
997 }
999 CSSValue*
1000 nsComputedDOMStyle::DoGetColumnRuleStyle()
1001 {
1002 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1003 val->SetIdent(
1004 nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle,
1005 nsCSSProps::kBorderStyleKTable));
1006 return val;
1007 }
1009 CSSValue*
1010 nsComputedDOMStyle::DoGetColumnRuleColor()
1011 {
1012 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1014 const nsStyleColumn* column = StyleColumn();
1015 nscolor ruleColor;
1016 if (column->mColumnRuleColorIsForeground) {
1017 ruleColor = StyleColor()->mColor;
1018 } else {
1019 ruleColor = column->mColumnRuleColor;
1020 }
1022 SetToRGBAColor(val, ruleColor);
1023 return val;
1024 }
1026 CSSValue*
1027 nsComputedDOMStyle::DoGetContent()
1028 {
1029 const nsStyleContent *content = StyleContent();
1031 if (content->ContentCount() == 0) {
1032 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1033 val->SetIdent(eCSSKeyword_none);
1034 return val;
1035 }
1037 if (content->ContentCount() == 1 &&
1038 content->ContentAt(0).mType == eStyleContentType_AltContent) {
1039 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1040 val->SetIdent(eCSSKeyword__moz_alt_content);
1041 return val;
1042 }
1044 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1046 for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
1047 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1048 valueList->AppendCSSValue(val);
1050 const nsStyleContentData &data = content->ContentAt(i);
1051 switch (data.mType) {
1052 case eStyleContentType_String:
1053 {
1054 nsString str;
1055 nsStyleUtil::AppendEscapedCSSString(
1056 nsDependentString(data.mContent.mString), str);
1057 val->SetString(str);
1058 }
1059 break;
1060 case eStyleContentType_Image:
1061 {
1062 nsCOMPtr<nsIURI> uri;
1063 if (data.mContent.mImage) {
1064 data.mContent.mImage->GetURI(getter_AddRefs(uri));
1065 }
1066 val->SetURI(uri);
1067 }
1068 break;
1069 case eStyleContentType_Attr:
1070 {
1071 nsAutoString str;
1072 nsStyleUtil::AppendEscapedCSSIdent(
1073 nsDependentString(data.mContent.mString), str);
1074 val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR);
1075 }
1076 break;
1077 case eStyleContentType_Counter:
1078 case eStyleContentType_Counters:
1079 {
1080 /* FIXME: counters should really use an object */
1081 nsAutoString str;
1082 if (data.mType == eStyleContentType_Counter) {
1083 str.AppendLiteral("counter(");
1084 }
1085 else {
1086 str.AppendLiteral("counters(");
1087 }
1088 // WRITE ME
1089 nsCSSValue::Array *a = data.mContent.mCounters;
1091 nsStyleUtil::AppendEscapedCSSIdent(
1092 nsDependentString(a->Item(0).GetStringBufferValue()), str);
1093 int32_t typeItem = 1;
1094 if (data.mType == eStyleContentType_Counters) {
1095 typeItem = 2;
1096 str.AppendLiteral(", ");
1097 nsStyleUtil::AppendEscapedCSSString(
1098 nsDependentString(a->Item(1).GetStringBufferValue()), str);
1099 }
1100 NS_ABORT_IF_FALSE(eCSSUnit_None != a->Item(typeItem).GetUnit(),
1101 "'none' should be handled as enumerated value");
1102 int32_t type = a->Item(typeItem).GetIntValue();
1103 if (type != NS_STYLE_LIST_STYLE_DECIMAL) {
1104 str.AppendLiteral(", ");
1105 AppendASCIItoUTF16(
1106 nsCSSProps::ValueToKeyword(type, nsCSSProps::kListStyleKTable),
1107 str);
1108 }
1110 str.Append(char16_t(')'));
1111 val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
1112 }
1113 break;
1114 case eStyleContentType_OpenQuote:
1115 val->SetIdent(eCSSKeyword_open_quote);
1116 break;
1117 case eStyleContentType_CloseQuote:
1118 val->SetIdent(eCSSKeyword_close_quote);
1119 break;
1120 case eStyleContentType_NoOpenQuote:
1121 val->SetIdent(eCSSKeyword_no_open_quote);
1122 break;
1123 case eStyleContentType_NoCloseQuote:
1124 val->SetIdent(eCSSKeyword_no_close_quote);
1125 break;
1126 case eStyleContentType_AltContent:
1127 default:
1128 NS_NOTREACHED("unexpected type");
1129 break;
1130 }
1131 }
1133 return valueList;
1134 }
1136 CSSValue*
1137 nsComputedDOMStyle::DoGetCounterIncrement()
1138 {
1139 const nsStyleContent *content = StyleContent();
1141 if (content->CounterIncrementCount() == 0) {
1142 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1143 val->SetIdent(eCSSKeyword_none);
1144 return val;
1145 }
1147 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1149 for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
1150 nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
1151 valueList->AppendCSSValue(name);
1153 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
1154 valueList->AppendCSSValue(value);
1156 const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
1157 nsAutoString escaped;
1158 nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
1159 name->SetString(escaped);
1160 value->SetNumber(data->mValue); // XXX This should really be integer
1161 }
1163 return valueList;
1164 }
1166 /* Convert the stored representation into a list of two values and then hand
1167 * it back.
1168 */
1169 CSSValue*
1170 nsComputedDOMStyle::DoGetTransformOrigin()
1171 {
1172 /* We need to build up a list of two values. We'll call them
1173 * width and height.
1174 */
1176 /* Store things as a value list */
1177 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
1179 /* Now, get the values. */
1180 const nsStyleDisplay* display = StyleDisplay();
1182 nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
1183 SetValueToCoord(width, display->mTransformOrigin[0], false,
1184 &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1185 valueList->AppendCSSValue(width);
1187 nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
1188 SetValueToCoord(height, display->mTransformOrigin[1], false,
1189 &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1190 valueList->AppendCSSValue(height);
1192 if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
1193 display->mTransformOrigin[2].GetCoordValue() != 0) {
1194 nsROCSSPrimitiveValue* depth = new nsROCSSPrimitiveValue;
1195 SetValueToCoord(depth, display->mTransformOrigin[2], false,
1196 nullptr);
1197 valueList->AppendCSSValue(depth);
1198 }
1200 return valueList;
1201 }
1203 /* Convert the stored representation into a list of two values and then hand
1204 * it back.
1205 */
1206 CSSValue*
1207 nsComputedDOMStyle::DoGetPerspectiveOrigin()
1208 {
1209 /* We need to build up a list of two values. We'll call them
1210 * width and height.
1211 */
1213 /* Store things as a value list */
1214 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
1216 /* Now, get the values. */
1217 const nsStyleDisplay* display = StyleDisplay();
1219 nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
1220 SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
1221 &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1222 valueList->AppendCSSValue(width);
1224 nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
1225 SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
1226 &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1227 valueList->AppendCSSValue(height);
1229 return valueList;
1230 }
1232 CSSValue*
1233 nsComputedDOMStyle::DoGetPerspective()
1234 {
1235 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1236 SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
1237 return val;
1238 }
1240 CSSValue*
1241 nsComputedDOMStyle::DoGetBackfaceVisibility()
1242 {
1243 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1244 val->SetIdent(
1245 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility,
1246 nsCSSProps::kBackfaceVisibilityKTable));
1247 return val;
1248 }
1250 CSSValue*
1251 nsComputedDOMStyle::DoGetTransformStyle()
1252 {
1253 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1254 val->SetIdent(
1255 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
1256 nsCSSProps::kTransformStyleKTable));
1257 return val;
1258 }
1260 /* If the property is "none", hand back "none" wrapped in a value.
1261 * Otherwise, compute the aggregate transform matrix and hands it back in a
1262 * "matrix" wrapper.
1263 */
1264 CSSValue*
1265 nsComputedDOMStyle::DoGetTransform()
1266 {
1267 /* First, get the display data. We'll need it. */
1268 const nsStyleDisplay* display = StyleDisplay();
1270 /* If there are no transforms, then we should construct a single-element
1271 * entry and hand it back.
1272 */
1273 if (!display->mSpecifiedTransform) {
1274 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1276 /* Set it to "none." */
1277 val->SetIdent(eCSSKeyword_none);
1278 return val;
1279 }
1281 /* Otherwise, we need to compute the current value of the transform matrix,
1282 * store it in a string, and hand it back to the caller.
1283 */
1285 /* Use the inner frame for width and height. If we fail, assume zero.
1286 * TODO: There is no good way for us to represent the case where there's no
1287 * frame, which is problematic. The reason is that when we have percentage
1288 * transforms, there are a total of four stored matrix entries that influence
1289 * the transform based on the size of the element. However, this poses a
1290 * problem, because only two of these values can be explicitly referenced
1291 * using the named transforms. Until a real solution is found, we'll just
1292 * use this approach.
1293 */
1294 nsRect bounds =
1295 (mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
1296 nsRect(0, 0, 0, 0));
1298 bool dummy;
1299 gfx3DMatrix matrix =
1300 nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
1301 mStyleContextHolder,
1302 mStyleContextHolder->PresContext(),
1303 dummy,
1304 bounds,
1305 float(mozilla::AppUnitsPerCSSPixel()));
1307 return MatrixToCSSValue(matrix);
1308 }
1310 /* static */ nsROCSSPrimitiveValue*
1311 nsComputedDOMStyle::MatrixToCSSValue(gfx3DMatrix& matrix)
1312 {
1313 bool is3D = !matrix.Is2D();
1315 nsAutoString resultString(NS_LITERAL_STRING("matrix"));
1316 if (is3D) {
1317 resultString.Append(NS_LITERAL_STRING("3d"));
1318 }
1320 resultString.Append(NS_LITERAL_STRING("("));
1321 resultString.AppendFloat(matrix._11);
1322 resultString.Append(NS_LITERAL_STRING(", "));
1323 resultString.AppendFloat(matrix._12);
1324 resultString.Append(NS_LITERAL_STRING(", "));
1325 if (is3D) {
1326 resultString.AppendFloat(matrix._13);
1327 resultString.Append(NS_LITERAL_STRING(", "));
1328 resultString.AppendFloat(matrix._14);
1329 resultString.Append(NS_LITERAL_STRING(", "));
1330 }
1331 resultString.AppendFloat(matrix._21);
1332 resultString.Append(NS_LITERAL_STRING(", "));
1333 resultString.AppendFloat(matrix._22);
1334 resultString.Append(NS_LITERAL_STRING(", "));
1335 if (is3D) {
1336 resultString.AppendFloat(matrix._23);
1337 resultString.Append(NS_LITERAL_STRING(", "));
1338 resultString.AppendFloat(matrix._24);
1339 resultString.Append(NS_LITERAL_STRING(", "));
1340 resultString.AppendFloat(matrix._31);
1341 resultString.Append(NS_LITERAL_STRING(", "));
1342 resultString.AppendFloat(matrix._32);
1343 resultString.Append(NS_LITERAL_STRING(", "));
1344 resultString.AppendFloat(matrix._33);
1345 resultString.Append(NS_LITERAL_STRING(", "));
1346 resultString.AppendFloat(matrix._34);
1347 resultString.Append(NS_LITERAL_STRING(", "));
1348 }
1349 resultString.AppendFloat(matrix._41);
1350 resultString.Append(NS_LITERAL_STRING(", "));
1351 resultString.AppendFloat(matrix._42);
1352 if (is3D) {
1353 resultString.Append(NS_LITERAL_STRING(", "));
1354 resultString.AppendFloat(matrix._43);
1355 resultString.Append(NS_LITERAL_STRING(", "));
1356 resultString.AppendFloat(matrix._44);
1357 }
1358 resultString.Append(NS_LITERAL_STRING(")"));
1360 /* Create a value to hold our result. */
1361 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1363 val->SetString(resultString);
1364 return val;
1365 }
1367 CSSValue*
1368 nsComputedDOMStyle::DoGetCounterReset()
1369 {
1370 const nsStyleContent *content = StyleContent();
1372 if (content->CounterResetCount() == 0) {
1373 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1374 val->SetIdent(eCSSKeyword_none);
1375 return val;
1376 }
1378 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1380 for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
1381 nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
1382 valueList->AppendCSSValue(name);
1384 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
1385 valueList->AppendCSSValue(value);
1387 const nsStyleCounterData *data = content->GetCounterResetAt(i);
1388 nsAutoString escaped;
1389 nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
1390 name->SetString(escaped);
1391 value->SetNumber(data->mValue); // XXX This should really be integer
1392 }
1394 return valueList;
1395 }
1397 CSSValue*
1398 nsComputedDOMStyle::DoGetQuotes()
1399 {
1400 const nsStyleQuotes *quotes = StyleQuotes();
1402 if (quotes->QuotesCount() == 0) {
1403 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1404 val->SetIdent(eCSSKeyword_none);
1405 return val;
1406 }
1408 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1410 for (uint32_t i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
1411 nsROCSSPrimitiveValue* openVal = new nsROCSSPrimitiveValue;
1412 valueList->AppendCSSValue(openVal);
1414 nsROCSSPrimitiveValue* closeVal = new nsROCSSPrimitiveValue;
1415 valueList->AppendCSSValue(closeVal);
1417 nsString s;
1418 nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s);
1419 openVal->SetString(s);
1420 s.Truncate();
1421 nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s);
1422 closeVal->SetString(s);
1423 }
1425 return valueList;
1426 }
1428 CSSValue*
1429 nsComputedDOMStyle::DoGetFontFamily()
1430 {
1431 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1433 const nsStyleFont* font = StyleFont();
1435 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocumentWeak);
1436 NS_ASSERTION(doc, "document is required");
1437 nsIPresShell* presShell = doc->GetShell();
1438 NS_ASSERTION(presShell, "pres shell is required");
1439 nsPresContext *presContext = presShell->GetPresContext();
1440 NS_ASSERTION(presContext, "pres context is required");
1442 const nsString& fontName = font->mFont.name;
1443 if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) {
1444 const nsFont* defaultFont =
1445 presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
1446 font->mLanguage);
1448 int32_t lendiff = fontName.Length() - defaultFont->name.Length();
1449 if (lendiff > 0) {
1450 val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma
1451 } else {
1452 val->SetString(fontName);
1453 }
1454 } else {
1455 val->SetString(fontName);
1456 }
1458 return val;
1459 }
1461 CSSValue*
1462 nsComputedDOMStyle::DoGetFontSize()
1463 {
1464 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1466 // Note: StyleFont()->mSize is the 'computed size';
1467 // StyleFont()->mFont.size is the 'actual size'
1468 val->SetAppUnits(StyleFont()->mSize);
1469 return val;
1470 }
1472 CSSValue*
1473 nsComputedDOMStyle::DoGetFontSizeAdjust()
1474 {
1475 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1477 const nsStyleFont *font = StyleFont();
1479 if (font->mFont.sizeAdjust) {
1480 val->SetNumber(font->mFont.sizeAdjust);
1481 } else {
1482 val->SetIdent(eCSSKeyword_none);
1483 }
1485 return val;
1486 }
1488 CSSValue*
1489 nsComputedDOMStyle::DoGetOSXFontSmoothing()
1490 {
1491 if (!nsContentUtils::IsCallerChrome())
1492 return nullptr;
1494 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1495 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
1496 nsCSSProps::kFontSmoothingKTable));
1497 return val;
1498 }
1500 CSSValue*
1501 nsComputedDOMStyle::DoGetFontStretch()
1502 {
1503 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1505 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
1506 nsCSSProps::kFontStretchKTable));
1508 return val;
1509 }
1511 CSSValue*
1512 nsComputedDOMStyle::DoGetFontStyle()
1513 {
1514 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1515 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
1516 nsCSSProps::kFontStyleKTable));
1517 return val;
1518 }
1520 CSSValue*
1521 nsComputedDOMStyle::DoGetFontWeight()
1522 {
1523 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1525 const nsStyleFont* font = StyleFont();
1527 uint16_t weight = font->mFont.weight;
1528 NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight");
1529 val->SetNumber(weight);
1531 return val;
1532 }
1534 CSSValue*
1535 nsComputedDOMStyle::DoGetFontVariant()
1536 {
1537 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1538 val->SetIdent(
1539 nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.variant,
1540 nsCSSProps::kFontVariantKTable));
1541 return val;
1542 }
1544 CSSValue*
1545 nsComputedDOMStyle::DoGetFontFeatureSettings()
1546 {
1547 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1549 const nsStyleFont* font = StyleFont();
1550 if (font->mFont.fontFeatureSettings.IsEmpty()) {
1551 val->SetIdent(eCSSKeyword_normal);
1552 } else {
1553 nsAutoString result;
1554 nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings,
1555 result);
1556 val->SetString(result);
1557 }
1558 return val;
1559 }
1561 CSSValue*
1562 nsComputedDOMStyle::DoGetFontKerning()
1563 {
1564 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1565 val->SetIdent(
1566 nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning,
1567 nsCSSProps::kFontKerningKTable));
1568 return val;
1569 }
1571 CSSValue*
1572 nsComputedDOMStyle::DoGetFontLanguageOverride()
1573 {
1574 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1576 const nsStyleFont* font = StyleFont();
1577 if (font->mFont.languageOverride.IsEmpty()) {
1578 val->SetIdent(eCSSKeyword_normal);
1579 } else {
1580 nsString str;
1581 nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
1582 val->SetString(str);
1583 }
1584 return val;
1585 }
1587 CSSValue*
1588 nsComputedDOMStyle::DoGetFontSynthesis()
1589 {
1590 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1592 int32_t intValue = StyleFont()->mFont.synthesis;
1594 if (0 == intValue) {
1595 val->SetIdent(eCSSKeyword_none);
1596 } else {
1597 nsAutoString valueStr;
1599 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis,
1600 intValue, NS_FONT_SYNTHESIS_WEIGHT,
1601 NS_FONT_SYNTHESIS_STYLE, valueStr);
1602 val->SetString(valueStr);
1603 }
1605 return val;
1606 }
1608 CSSValue*
1609 nsComputedDOMStyle::DoGetFontVariantAlternates()
1610 {
1611 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1613 int32_t intValue = StyleFont()->mFont.variantAlternates;
1615 if (0 == intValue) {
1616 val->SetIdent(eCSSKeyword_normal);
1617 return val;
1618 }
1620 // first, include enumerated values
1621 nsAutoString valueStr;
1623 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates,
1624 intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
1625 NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
1626 NS_FONT_VARIANT_ALTERNATES_HISTORICAL, valueStr);
1628 // next, include functional values if present
1629 if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
1630 nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues,
1631 valueStr);
1632 }
1634 val->SetString(valueStr);
1635 return val;
1636 }
1639 CSSValue*
1640 nsComputedDOMStyle::DoGetFontVariantCaps()
1641 {
1642 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1644 int32_t intValue = StyleFont()->mFont.variantCaps;
1646 if (0 == intValue) {
1647 val->SetIdent(eCSSKeyword_normal);
1648 } else {
1649 val->SetIdent(
1650 nsCSSProps::ValueToKeywordEnum(intValue,
1651 nsCSSProps::kFontVariantCapsKTable));
1652 }
1654 return val;
1655 }
1657 CSSValue*
1658 nsComputedDOMStyle::DoGetFontVariantEastAsian()
1659 {
1660 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1662 int32_t intValue = StyleFont()->mFont.variantEastAsian;
1664 if (0 == intValue) {
1665 val->SetIdent(eCSSKeyword_normal);
1666 } else {
1667 nsAutoString valueStr;
1669 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian,
1670 intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
1671 NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr);
1672 val->SetString(valueStr);
1673 }
1675 return val;
1676 }
1678 CSSValue*
1679 nsComputedDOMStyle::DoGetFontVariantLigatures()
1680 {
1681 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1683 int32_t intValue = StyleFont()->mFont.variantLigatures;
1685 if (0 == intValue) {
1686 val->SetIdent(eCSSKeyword_normal);
1687 } else {
1688 nsAutoString valueStr;
1690 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
1691 intValue, NS_FONT_VARIANT_LIGATURES_NONE,
1692 NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
1693 val->SetString(valueStr);
1694 }
1696 return val;
1697 }
1699 CSSValue*
1700 nsComputedDOMStyle::DoGetFontVariantNumeric()
1701 {
1702 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1704 int32_t intValue = StyleFont()->mFont.variantNumeric;
1706 if (0 == intValue) {
1707 val->SetIdent(eCSSKeyword_normal);
1708 } else {
1709 nsAutoString valueStr;
1711 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric,
1712 intValue, NS_FONT_VARIANT_NUMERIC_LINING,
1713 NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr);
1714 val->SetString(valueStr);
1715 }
1717 return val;
1718 }
1720 CSSValue*
1721 nsComputedDOMStyle::DoGetFontVariantPosition()
1722 {
1723 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1725 int32_t intValue = StyleFont()->mFont.variantPosition;
1727 if (0 == intValue) {
1728 val->SetIdent(eCSSKeyword_normal);
1729 } else {
1730 val->SetIdent(
1731 nsCSSProps::ValueToKeywordEnum(intValue,
1732 nsCSSProps::kFontVariantPositionKTable));
1733 }
1735 return val;
1736 }
1738 CSSValue*
1739 nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember,
1740 uint32_t nsStyleBackground::* aCount,
1741 const KTableValue aTable[])
1742 {
1743 const nsStyleBackground* bg = StyleBackground();
1745 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
1747 for (uint32_t i = 0, i_end = bg->*aCount; i < i_end; ++i) {
1748 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1749 valueList->AppendCSSValue(val);
1750 val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
1751 aTable));
1752 }
1754 return valueList;
1755 }
1757 CSSValue*
1758 nsComputedDOMStyle::DoGetBackgroundAttachment()
1759 {
1760 return GetBackgroundList(&nsStyleBackground::Layer::mAttachment,
1761 &nsStyleBackground::mAttachmentCount,
1762 nsCSSProps::kBackgroundAttachmentKTable);
1763 }
1765 CSSValue*
1766 nsComputedDOMStyle::DoGetBackgroundClip()
1767 {
1768 return GetBackgroundList(&nsStyleBackground::Layer::mClip,
1769 &nsStyleBackground::mClipCount,
1770 nsCSSProps::kBackgroundOriginKTable);
1771 }
1773 CSSValue*
1774 nsComputedDOMStyle::DoGetBackgroundColor()
1775 {
1776 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1777 SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
1778 return val;
1779 }
1782 static void
1783 SetValueToCalc(const nsStyleCoord::Calc *aCalc, nsROCSSPrimitiveValue *aValue)
1784 {
1785 nsRefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1786 nsAutoString tmp, result;
1788 result.AppendLiteral("calc(");
1790 val->SetAppUnits(aCalc->mLength);
1791 val->GetCssText(tmp);
1792 result.Append(tmp);
1794 if (aCalc->mHasPercent) {
1795 result.AppendLiteral(" + ");
1797 val->SetPercent(aCalc->mPercent);
1798 val->GetCssText(tmp);
1799 result.Append(tmp);
1800 }
1802 result.AppendLiteral(")");
1804 aValue->SetString(result); // not really SetString
1805 }
1807 static void
1808 AppendCSSGradientLength(const nsStyleCoord& aValue,
1809 nsROCSSPrimitiveValue* aPrimitive,
1810 nsAString& aString)
1811 {
1812 nsAutoString tokenString;
1813 if (aValue.IsCalcUnit())
1814 SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
1815 else if (aValue.GetUnit() == eStyleUnit_Coord)
1816 aPrimitive->SetAppUnits(aValue.GetCoordValue());
1817 else
1818 aPrimitive->SetPercent(aValue.GetPercentValue());
1819 aPrimitive->GetCssText(tokenString);
1820 aString.Append(tokenString);
1821 }
1823 static void
1824 AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
1825 nsAString& aString,
1826 bool& aNeedSep)
1827 {
1828 float xValue = aGradient->mBgPosX.GetPercentValue();
1829 float yValue = aGradient->mBgPosY.GetPercentValue();
1831 if (yValue == 1.0f && xValue == 0.5f) {
1832 // omit "to bottom"
1833 return;
1834 }
1835 NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
1837 aString.AppendLiteral("to");
1839 if (yValue == 0.0f) {
1840 aString.AppendLiteral(" top");
1841 } else if (yValue == 1.0f) {
1842 aString.AppendLiteral(" bottom");
1843 } else if (yValue != 0.5f) { // do not write "center" keyword
1844 NS_NOTREACHED("invalid box position");
1845 }
1847 if (xValue == 0.0f) {
1848 aString.AppendLiteral(" left");
1849 } else if (xValue == 1.0f) {
1850 aString.AppendLiteral(" right");
1851 } else if (xValue != 0.5f) { // do not write "center" keyword
1852 NS_NOTREACHED("invalid box position");
1853 }
1855 aNeedSep = true;
1856 }
1858 void
1859 nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
1860 nsAString& aString)
1861 {
1862 if (!aGradient->mLegacySyntax) {
1863 aString.Truncate();
1864 } else {
1865 aString.AssignLiteral("-moz-");
1866 }
1867 if (aGradient->mRepeating) {
1868 aString.AppendLiteral("repeating-");
1869 }
1870 bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR;
1871 if (isRadial) {
1872 aString.AppendLiteral("radial-gradient(");
1873 } else {
1874 aString.AppendLiteral("linear-gradient(");
1875 }
1877 bool needSep = false;
1878 nsAutoString tokenString;
1879 nsROCSSPrimitiveValue *tmpVal = new nsROCSSPrimitiveValue;
1881 if (isRadial && !aGradient->mLegacySyntax) {
1882 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) {
1883 if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1884 aString.AppendLiteral("circle");
1885 needSep = true;
1886 }
1887 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1888 if (needSep) {
1889 aString.AppendLiteral(" ");
1890 }
1891 AppendASCIItoUTF16(nsCSSProps::
1892 ValueToKeyword(aGradient->mSize,
1893 nsCSSProps::kRadialGradientSizeKTable),
1894 aString);
1895 needSep = true;
1896 }
1897 } else {
1898 AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString);
1899 if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1900 aString.AppendLiteral(" ");
1901 AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString);
1902 }
1903 needSep = true;
1904 }
1905 }
1906 if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
1907 MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None);
1908 if (!isRadial && !aGradient->mLegacySyntax) {
1909 AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
1910 } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent ||
1911 aGradient->mBgPosX.GetPercentValue() != 0.5f ||
1912 aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent ||
1913 aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 1.0f)) {
1914 if (isRadial && !aGradient->mLegacySyntax) {
1915 if (needSep) {
1916 aString.AppendLiteral(" ");
1917 }
1918 aString.AppendLiteral("at ");
1919 needSep = false;
1920 }
1921 AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
1922 if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
1923 aString.AppendLiteral(" ");
1924 AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
1925 }
1926 needSep = true;
1927 }
1928 }
1929 if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
1930 MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
1931 if (needSep) {
1932 aString.AppendLiteral(" ");
1933 }
1934 nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString);
1935 needSep = true;
1936 }
1938 if (isRadial && aGradient->mLegacySyntax &&
1939 (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
1940 aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
1941 MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
1942 if (needSep) {
1943 aString.AppendLiteral(", ");
1944 needSep = false;
1945 }
1946 if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1947 aString.AppendLiteral("circle");
1948 needSep = true;
1949 }
1950 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1951 if (needSep) {
1952 aString.AppendLiteral(" ");
1953 }
1954 AppendASCIItoUTF16(nsCSSProps::
1955 ValueToKeyword(aGradient->mSize,
1956 nsCSSProps::kRadialGradientSizeKTable),
1957 aString);
1958 }
1959 needSep = true;
1960 }
1963 // color stops
1964 for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
1965 if (needSep) {
1966 aString.AppendLiteral(", ");
1967 }
1968 SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor);
1969 tmpVal->GetCssText(tokenString);
1970 aString.Append(tokenString);
1972 if (aGradient->mStops[i].mLocation.GetUnit() != eStyleUnit_None) {
1973 aString.AppendLiteral(" ");
1974 AppendCSSGradientLength(aGradient->mStops[i].mLocation, tmpVal, aString);
1975 }
1976 needSep = true;
1977 }
1979 delete tmpVal;
1980 aString.AppendLiteral(")");
1981 }
1983 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
1984 void
1985 nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
1986 const nsStyleSides& aCropRect,
1987 nsString& aString)
1988 {
1989 nsDOMCSSValueList* valueList = GetROCSSValueList(true);
1991 // <uri>
1992 nsROCSSPrimitiveValue *valURI = new nsROCSSPrimitiveValue;
1993 valueList->AppendCSSValue(valURI);
1994 valURI->SetURI(aURI);
1996 // <top>, <right>, <bottom>, <left>
1997 NS_FOR_CSS_SIDES(side) {
1998 nsROCSSPrimitiveValue *valSide = new nsROCSSPrimitiveValue;
1999 valueList->AppendCSSValue(valSide);
2000 SetValueToCoord(valSide, aCropRect.Get(side), false);
2001 }
2003 nsAutoString argumentString;
2004 valueList->GetCssText(argumentString);
2005 delete valueList;
2007 aString = NS_LITERAL_STRING("-moz-image-rect(") +
2008 argumentString +
2009 NS_LITERAL_STRING(")");
2010 }
2012 void
2013 nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
2014 nsROCSSPrimitiveValue* aValue)
2015 {
2016 switch (aStyleImage.GetType()) {
2017 case eStyleImageType_Image:
2018 {
2019 imgIRequest *req = aStyleImage.GetImageData();
2020 nsCOMPtr<nsIURI> uri;
2021 req->GetURI(getter_AddRefs(uri));
2023 const nsStyleSides* cropRect = aStyleImage.GetCropRect();
2024 if (cropRect) {
2025 nsAutoString imageRectString;
2026 GetImageRectString(uri, *cropRect, imageRectString);
2027 aValue->SetString(imageRectString);
2028 } else {
2029 aValue->SetURI(uri);
2030 }
2031 break;
2032 }
2033 case eStyleImageType_Gradient:
2034 {
2035 nsAutoString gradientString;
2036 GetCSSGradientString(aStyleImage.GetGradientData(),
2037 gradientString);
2038 aValue->SetString(gradientString);
2039 break;
2040 }
2041 case eStyleImageType_Element:
2042 {
2043 nsAutoString elementId;
2044 nsStyleUtil::AppendEscapedCSSIdent(
2045 nsDependentString(aStyleImage.GetElementId()), elementId);
2046 nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
2047 elementId +
2048 NS_LITERAL_STRING(")");
2049 aValue->SetString(elementString);
2050 break;
2051 }
2052 case eStyleImageType_Null:
2053 aValue->SetIdent(eCSSKeyword_none);
2054 break;
2055 default:
2056 NS_NOTREACHED("unexpected image type");
2057 break;
2058 }
2059 }
2061 CSSValue*
2062 nsComputedDOMStyle::DoGetBackgroundImage()
2063 {
2064 const nsStyleBackground* bg = StyleBackground();
2066 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2068 for (uint32_t i = 0, i_end = bg->mImageCount; i < i_end; ++i) {
2069 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2070 valueList->AppendCSSValue(val);
2072 const nsStyleImage& image = bg->mLayers[i].mImage;
2073 SetValueToStyleImage(image, val);
2074 }
2076 return valueList;
2077 }
2079 CSSValue*
2080 nsComputedDOMStyle::DoGetBackgroundInlinePolicy()
2081 {
2082 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2083 val->SetIdent(nsCSSProps::ValueToKeywordEnum(
2084 StyleBackground()->mBackgroundInlinePolicy,
2085 nsCSSProps::kBackgroundInlinePolicyKTable));
2086 return val;
2087 }
2089 CSSValue*
2090 nsComputedDOMStyle::DoGetBackgroundBlendMode()
2091 {
2092 return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
2093 &nsStyleBackground::mBlendModeCount,
2094 nsCSSProps::kBlendModeKTable);
2095 }
2097 CSSValue*
2098 nsComputedDOMStyle::DoGetBackgroundOrigin()
2099 {
2100 return GetBackgroundList(&nsStyleBackground::Layer::mOrigin,
2101 &nsStyleBackground::mOriginCount,
2102 nsCSSProps::kBackgroundOriginKTable);
2103 }
2105 CSSValue*
2106 nsComputedDOMStyle::DoGetBackgroundPosition()
2107 {
2108 const nsStyleBackground* bg = StyleBackground();
2110 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2112 for (uint32_t i = 0, i_end = bg->mPositionCount; i < i_end; ++i) {
2113 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2114 valueList->AppendCSSValue(itemList);
2116 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
2117 itemList->AppendCSSValue(valX);
2119 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
2120 itemList->AppendCSSValue(valY);
2122 const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition;
2124 if (!pos.mXPosition.mHasPercent) {
2125 NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f,
2126 "Shouldn't have mPercent!");
2127 valX->SetAppUnits(pos.mXPosition.mLength);
2128 } else if (pos.mXPosition.mLength == 0) {
2129 valX->SetPercent(pos.mXPosition.mPercent);
2130 } else {
2131 SetValueToCalc(&pos.mXPosition, valX);
2132 }
2134 if (!pos.mYPosition.mHasPercent) {
2135 NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f,
2136 "Shouldn't have mPercent!");
2137 valY->SetAppUnits(pos.mYPosition.mLength);
2138 } else if (pos.mYPosition.mLength == 0) {
2139 valY->SetPercent(pos.mYPosition.mPercent);
2140 } else {
2141 SetValueToCalc(&pos.mYPosition, valY);
2142 }
2143 }
2145 return valueList;
2146 }
2148 CSSValue*
2149 nsComputedDOMStyle::DoGetBackgroundRepeat()
2150 {
2151 const nsStyleBackground* bg = StyleBackground();
2153 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2155 for (uint32_t i = 0, i_end = bg->mRepeatCount; i < i_end; ++i) {
2156 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2157 valueList->AppendCSSValue(itemList);
2159 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
2160 itemList->AppendCSSValue(valX);
2162 const uint8_t& xRepeat = bg->mLayers[i].mRepeat.mXRepeat;
2163 const uint8_t& yRepeat = bg->mLayers[i].mRepeat.mYRepeat;
2165 bool hasContraction = true;
2166 unsigned contraction;
2167 if (xRepeat == yRepeat) {
2168 contraction = xRepeat;
2169 } else if (xRepeat == NS_STYLE_BG_REPEAT_REPEAT &&
2170 yRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT) {
2171 contraction = NS_STYLE_BG_REPEAT_REPEAT_X;
2172 } else if (xRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT &&
2173 yRepeat == NS_STYLE_BG_REPEAT_REPEAT) {
2174 contraction = NS_STYLE_BG_REPEAT_REPEAT_Y;
2175 } else {
2176 hasContraction = false;
2177 }
2179 if (hasContraction) {
2180 valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
2181 nsCSSProps::kBackgroundRepeatKTable));
2182 } else {
2183 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
2184 itemList->AppendCSSValue(valY);
2186 valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
2187 nsCSSProps::kBackgroundRepeatKTable));
2188 valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
2189 nsCSSProps::kBackgroundRepeatKTable));
2190 }
2191 }
2193 return valueList;
2194 }
2196 CSSValue*
2197 nsComputedDOMStyle::DoGetBackgroundSize()
2198 {
2199 const nsStyleBackground* bg = StyleBackground();
2201 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2203 for (uint32_t i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
2204 const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
2206 switch (size.mWidthType) {
2207 case nsStyleBackground::Size::eContain:
2208 case nsStyleBackground::Size::eCover: {
2209 NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType,
2210 "unsynced types");
2211 nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain
2212 ? eCSSKeyword_contain
2213 : eCSSKeyword_cover;
2214 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2215 valueList->AppendCSSValue(val);
2216 val->SetIdent(keyword);
2217 break;
2218 }
2219 default: {
2220 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2221 valueList->AppendCSSValue(itemList);
2223 nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
2224 itemList->AppendCSSValue(valX);
2225 nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
2226 itemList->AppendCSSValue(valY);
2228 if (size.mWidthType == nsStyleBackground::Size::eAuto) {
2229 valX->SetIdent(eCSSKeyword_auto);
2230 } else {
2231 NS_ABORT_IF_FALSE(size.mWidthType ==
2232 nsStyleBackground::Size::eLengthPercentage,
2233 "bad mWidthType");
2234 if (!size.mWidth.mHasPercent &&
2235 // negative values must have come from calc()
2236 size.mWidth.mLength >= 0) {
2237 NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f,
2238 "Shouldn't have mPercent");
2239 valX->SetAppUnits(size.mWidth.mLength);
2240 } else if (size.mWidth.mLength == 0 &&
2241 // negative values must have come from calc()
2242 size.mWidth.mPercent >= 0.0f) {
2243 valX->SetPercent(size.mWidth.mPercent);
2244 } else {
2245 SetValueToCalc(&size.mWidth, valX);
2246 }
2247 }
2249 if (size.mHeightType == nsStyleBackground::Size::eAuto) {
2250 valY->SetIdent(eCSSKeyword_auto);
2251 } else {
2252 NS_ABORT_IF_FALSE(size.mHeightType ==
2253 nsStyleBackground::Size::eLengthPercentage,
2254 "bad mHeightType");
2255 if (!size.mHeight.mHasPercent &&
2256 // negative values must have come from calc()
2257 size.mHeight.mLength >= 0) {
2258 NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f,
2259 "Shouldn't have mPercent");
2260 valY->SetAppUnits(size.mHeight.mLength);
2261 } else if (size.mHeight.mLength == 0 &&
2262 // negative values must have come from calc()
2263 size.mHeight.mPercent >= 0.0f) {
2264 valY->SetPercent(size.mHeight.mPercent);
2265 } else {
2266 SetValueToCalc(&size.mHeight, valY);
2267 }
2268 }
2269 break;
2270 }
2271 }
2272 }
2274 return valueList;
2275 }
2277 CSSValue*
2278 nsComputedDOMStyle::DoGetGridTemplateAreas()
2279 {
2280 const css::GridTemplateAreasValue* areas =
2281 StylePosition()->mGridTemplateAreas;
2282 if (!areas) {
2283 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2284 val->SetIdent(eCSSKeyword_none);
2285 return val;
2286 }
2288 MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
2289 "Unexpected empty array in GridTemplateAreasValue");
2290 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2291 for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
2292 nsAutoString str;
2293 nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
2294 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2295 val->SetString(str);
2296 valueList->AppendCSSValue(val);
2297 }
2298 return valueList;
2299 }
2301 // aLineNames must not be empty
2302 CSSValue*
2303 nsComputedDOMStyle::GetGridLineNames(const nsTArray<nsString>& aLineNames)
2304 {
2305 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2306 nsAutoString lineNamesString;
2307 uint32_t i_end = aLineNames.Length();
2308 lineNamesString.AssignLiteral("(");
2309 if (i_end > 0) {
2310 for (uint32_t i = 0;;) {
2311 nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], lineNamesString);
2312 if (++i == i_end) {
2313 break;
2314 }
2315 lineNamesString.AppendLiteral(" ");
2316 }
2317 }
2318 lineNamesString.AppendLiteral(")");
2319 val->SetString(lineNamesString);
2320 return val;
2321 }
2323 CSSValue*
2324 nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
2325 const nsStyleCoord& aMaxValue)
2326 {
2327 // FIXME bug 978212: for grid-template-columns and grid-template-rows
2328 // (not grid-auto-columns and grid-auto-rows), if we have frame,
2329 // every <track-size> should be resolved into 'px' here,
2330 // based on layout results.
2331 if (aMinValue == aMaxValue) {
2332 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2333 SetValueToCoord(val, aMinValue, true,
2334 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2335 return val;
2336 }
2338 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2339 nsAutoString argumentStr, minmaxStr;
2340 minmaxStr.AppendLiteral("minmax(");
2342 SetValueToCoord(val, aMinValue, true,
2343 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2344 val->GetCssText(argumentStr);
2345 minmaxStr.Append(argumentStr);
2347 minmaxStr.AppendLiteral(", ");
2349 SetValueToCoord(val, aMaxValue, true,
2350 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2351 val->GetCssText(argumentStr);
2352 minmaxStr.Append(argumentStr);
2354 minmaxStr.Append(char16_t(')'));
2355 val->SetString(minmaxStr);
2356 return val;
2357 }
2359 CSSValue*
2360 nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList)
2361 {
2362 if (aTrackList.mIsSubgrid) {
2363 NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
2364 aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
2365 "Unexpected sizing functions with subgrid");
2366 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2368 nsROCSSPrimitiveValue* subgridKeyword = new nsROCSSPrimitiveValue;
2369 subgridKeyword->SetIdent(eCSSKeyword_subgrid);
2370 valueList->AppendCSSValue(subgridKeyword);
2372 for (uint32_t i = 0; i < aTrackList.mLineNameLists.Length(); i++) {
2373 valueList->AppendCSSValue(GetGridLineNames(aTrackList.mLineNameLists[i]));
2374 }
2375 return valueList;
2376 }
2378 uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
2379 MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
2380 "Different number of min and max track sizing functions");
2381 // An empty <track-list> is represented as "none" in syntax.
2382 if (numSizes == 0) {
2383 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2384 val->SetIdent(eCSSKeyword_none);
2385 return val;
2386 }
2388 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2389 // Delimiting N tracks requires N+1 lines:
2390 // one before each track, plus one at the very end.
2391 MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1,
2392 "Unexpected number of line name lists");
2393 for (uint32_t i = 0;; i++) {
2394 const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
2395 if (!lineNames.IsEmpty()) {
2396 valueList->AppendCSSValue(GetGridLineNames(lineNames));
2397 }
2398 if (i == numSizes) {
2399 break;
2400 }
2401 valueList->AppendCSSValue(GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
2402 aTrackList.mMaxTrackSizingFunctions[i]));
2403 }
2405 return valueList;
2406 }
2408 CSSValue*
2409 nsComputedDOMStyle::DoGetGridAutoFlow()
2410 {
2411 nsAutoString str;
2412 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
2413 StylePosition()->mGridAutoFlow,
2414 NS_STYLE_GRID_AUTO_FLOW_NONE,
2415 NS_STYLE_GRID_AUTO_FLOW_DENSE,
2416 str);
2417 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2418 val->SetString(str);
2419 return val;
2420 }
2422 CSSValue*
2423 nsComputedDOMStyle::DoGetGridAutoColumns()
2424 {
2425 return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
2426 StylePosition()->mGridAutoColumnsMax);
2427 }
2429 CSSValue*
2430 nsComputedDOMStyle::DoGetGridAutoRows()
2431 {
2432 return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
2433 StylePosition()->mGridAutoRowsMax);
2434 }
2436 CSSValue*
2437 nsComputedDOMStyle::DoGetGridTemplateColumns()
2438 {
2439 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns);
2440 }
2442 CSSValue*
2443 nsComputedDOMStyle::DoGetGridTemplateRows()
2444 {
2445 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows);
2446 }
2448 CSSValue*
2449 nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
2450 {
2451 if (aGridLine.IsAuto()) {
2452 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2453 val->SetIdent(eCSSKeyword_auto);
2454 return val;
2455 }
2457 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2459 if (aGridLine.mHasSpan) {
2460 nsROCSSPrimitiveValue* span = new nsROCSSPrimitiveValue;
2461 span->SetIdent(eCSSKeyword_span);
2462 valueList->AppendCSSValue(span);
2463 }
2465 if (aGridLine.mInteger != 0) {
2466 nsROCSSPrimitiveValue* integer = new nsROCSSPrimitiveValue;
2467 integer->SetNumber(aGridLine.mInteger);
2468 valueList->AppendCSSValue(integer);
2469 }
2471 if (!aGridLine.mLineName.IsEmpty()) {
2472 nsROCSSPrimitiveValue* lineName = new nsROCSSPrimitiveValue;
2473 nsString escapedLineName;
2474 nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
2475 lineName->SetString(escapedLineName);
2476 valueList->AppendCSSValue(lineName);
2477 }
2479 NS_ASSERTION(valueList->Length() > 0,
2480 "Should have appended at least one value");
2481 return valueList;
2482 }
2484 CSSValue*
2485 nsComputedDOMStyle::DoGetGridAutoPosition()
2486 {
2487 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2489 valueList->AppendCSSValue(
2490 GetGridLine(StylePosition()->mGridAutoPositionColumn));
2492 nsROCSSPrimitiveValue* slash = new nsROCSSPrimitiveValue;
2493 slash->SetString(NS_LITERAL_STRING("/"));
2494 valueList->AppendCSSValue(slash);
2496 valueList->AppendCSSValue(
2497 GetGridLine(StylePosition()->mGridAutoPositionRow));
2499 return valueList;
2500 }
2502 CSSValue*
2503 nsComputedDOMStyle::DoGetGridColumnStart()
2504 {
2505 return GetGridLine(StylePosition()->mGridColumnStart);
2506 }
2508 CSSValue*
2509 nsComputedDOMStyle::DoGetGridColumnEnd()
2510 {
2511 return GetGridLine(StylePosition()->mGridColumnEnd);
2512 }
2514 CSSValue*
2515 nsComputedDOMStyle::DoGetGridRowStart()
2516 {
2517 return GetGridLine(StylePosition()->mGridRowStart);
2518 }
2520 CSSValue*
2521 nsComputedDOMStyle::DoGetGridRowEnd()
2522 {
2523 return GetGridLine(StylePosition()->mGridRowEnd);
2524 }
2526 CSSValue*
2527 nsComputedDOMStyle::DoGetPaddingTop()
2528 {
2529 return GetPaddingWidthFor(NS_SIDE_TOP);
2530 }
2532 CSSValue*
2533 nsComputedDOMStyle::DoGetPaddingBottom()
2534 {
2535 return GetPaddingWidthFor(NS_SIDE_BOTTOM);
2536 }
2538 CSSValue*
2539 nsComputedDOMStyle::DoGetPaddingLeft()
2540 {
2541 return GetPaddingWidthFor(NS_SIDE_LEFT);
2542 }
2544 CSSValue*
2545 nsComputedDOMStyle::DoGetPaddingRight()
2546 {
2547 return GetPaddingWidthFor(NS_SIDE_RIGHT);
2548 }
2550 CSSValue*
2551 nsComputedDOMStyle::DoGetBorderCollapse()
2552 {
2553 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2554 val->SetIdent(
2555 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse,
2556 nsCSSProps::kBorderCollapseKTable));
2557 return val;
2558 }
2560 CSSValue*
2561 nsComputedDOMStyle::DoGetBorderSpacing()
2562 {
2563 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2565 nsROCSSPrimitiveValue* xSpacing = new nsROCSSPrimitiveValue;
2566 valueList->AppendCSSValue(xSpacing);
2568 nsROCSSPrimitiveValue* ySpacing = new nsROCSSPrimitiveValue;
2569 valueList->AppendCSSValue(ySpacing);
2571 const nsStyleTableBorder *border = StyleTableBorder();
2572 xSpacing->SetAppUnits(border->mBorderSpacingX);
2573 ySpacing->SetAppUnits(border->mBorderSpacingY);
2575 return valueList;
2576 }
2578 CSSValue*
2579 nsComputedDOMStyle::DoGetCaptionSide()
2580 {
2581 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2582 val->SetIdent(
2583 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide,
2584 nsCSSProps::kCaptionSideKTable));
2585 return val;
2586 }
2588 CSSValue*
2589 nsComputedDOMStyle::DoGetEmptyCells()
2590 {
2591 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2592 val->SetIdent(
2593 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells,
2594 nsCSSProps::kEmptyCellsKTable));
2595 return val;
2596 }
2598 CSSValue*
2599 nsComputedDOMStyle::DoGetTableLayout()
2600 {
2601 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2602 val->SetIdent(
2603 nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy,
2604 nsCSSProps::kTableLayoutKTable));
2605 return val;
2606 }
2608 CSSValue*
2609 nsComputedDOMStyle::DoGetBorderTopStyle()
2610 {
2611 return GetBorderStyleFor(NS_SIDE_TOP);
2612 }
2614 CSSValue*
2615 nsComputedDOMStyle::DoGetBorderBottomStyle()
2616 {
2617 return GetBorderStyleFor(NS_SIDE_BOTTOM);
2618 }
2620 CSSValue*
2621 nsComputedDOMStyle::DoGetBorderLeftStyle()
2622 {
2623 return GetBorderStyleFor(NS_SIDE_LEFT);
2624 }
2626 CSSValue*
2627 nsComputedDOMStyle::DoGetBorderRightStyle()
2628 {
2629 return GetBorderStyleFor(NS_SIDE_RIGHT);
2630 }
2632 CSSValue*
2633 nsComputedDOMStyle::DoGetBorderBottomColors()
2634 {
2635 return GetBorderColorsFor(NS_SIDE_BOTTOM);
2636 }
2638 CSSValue*
2639 nsComputedDOMStyle::DoGetBorderLeftColors()
2640 {
2641 return GetBorderColorsFor(NS_SIDE_LEFT);
2642 }
2644 CSSValue*
2645 nsComputedDOMStyle::DoGetBorderRightColors()
2646 {
2647 return GetBorderColorsFor(NS_SIDE_RIGHT);
2648 }
2651 CSSValue*
2652 nsComputedDOMStyle::DoGetBorderTopColors()
2653 {
2654 return GetBorderColorsFor(NS_SIDE_TOP);
2655 }
2657 CSSValue*
2658 nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
2659 {
2660 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2661 NS_CORNER_BOTTOM_LEFT, true);
2662 }
2664 CSSValue*
2665 nsComputedDOMStyle::DoGetBorderBottomRightRadius()
2666 {
2667 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2668 NS_CORNER_BOTTOM_RIGHT, true);
2669 }
2671 CSSValue*
2672 nsComputedDOMStyle::DoGetBorderTopLeftRadius()
2673 {
2674 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2675 NS_CORNER_TOP_LEFT, true);
2676 }
2678 CSSValue*
2679 nsComputedDOMStyle::DoGetBorderTopRightRadius()
2680 {
2681 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2682 NS_CORNER_TOP_RIGHT, true);
2683 }
2685 CSSValue*
2686 nsComputedDOMStyle::DoGetBorderTopWidth()
2687 {
2688 return GetBorderWidthFor(NS_SIDE_TOP);
2689 }
2691 CSSValue*
2692 nsComputedDOMStyle::DoGetBorderBottomWidth()
2693 {
2694 return GetBorderWidthFor(NS_SIDE_BOTTOM);
2695 }
2697 CSSValue*
2698 nsComputedDOMStyle::DoGetBorderLeftWidth()
2699 {
2700 return GetBorderWidthFor(NS_SIDE_LEFT);
2701 }
2703 CSSValue*
2704 nsComputedDOMStyle::DoGetBorderRightWidth()
2705 {
2706 return GetBorderWidthFor(NS_SIDE_RIGHT);
2707 }
2709 CSSValue*
2710 nsComputedDOMStyle::DoGetBorderTopColor()
2711 {
2712 return GetBorderColorFor(NS_SIDE_TOP);
2713 }
2715 CSSValue*
2716 nsComputedDOMStyle::DoGetBorderBottomColor()
2717 {
2718 return GetBorderColorFor(NS_SIDE_BOTTOM);
2719 }
2721 CSSValue*
2722 nsComputedDOMStyle::DoGetBorderLeftColor()
2723 {
2724 return GetBorderColorFor(NS_SIDE_LEFT);
2725 }
2727 CSSValue*
2728 nsComputedDOMStyle::DoGetBorderRightColor()
2729 {
2730 return GetBorderColorFor(NS_SIDE_RIGHT);
2731 }
2733 CSSValue*
2734 nsComputedDOMStyle::DoGetMarginTopWidth()
2735 {
2736 return GetMarginWidthFor(NS_SIDE_TOP);
2737 }
2739 CSSValue*
2740 nsComputedDOMStyle::DoGetMarginBottomWidth()
2741 {
2742 return GetMarginWidthFor(NS_SIDE_BOTTOM);
2743 }
2745 CSSValue*
2746 nsComputedDOMStyle::DoGetMarginLeftWidth()
2747 {
2748 return GetMarginWidthFor(NS_SIDE_LEFT);
2749 }
2751 CSSValue*
2752 nsComputedDOMStyle::DoGetMarginRightWidth()
2753 {
2754 return GetMarginWidthFor(NS_SIDE_RIGHT);
2755 }
2757 CSSValue*
2758 nsComputedDOMStyle::DoGetMarkerOffset()
2759 {
2760 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2761 SetValueToCoord(val, StyleContent()->mMarkerOffset, false);
2762 return val;
2763 }
2765 CSSValue*
2766 nsComputedDOMStyle::DoGetOrient()
2767 {
2768 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2769 val->SetIdent(
2770 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient,
2771 nsCSSProps::kOrientKTable));
2772 return val;
2773 }
2775 CSSValue*
2776 nsComputedDOMStyle::DoGetOutlineWidth()
2777 {
2778 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2780 const nsStyleOutline* outline = StyleOutline();
2782 nscoord width;
2783 if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
2784 NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0,
2785 "unexpected width");
2786 width = 0;
2787 } else {
2788 #ifdef DEBUG
2789 bool res =
2790 #endif
2791 outline->GetOutlineWidth(width);
2792 NS_ASSERTION(res, "percent outline doesn't exist");
2793 }
2794 val->SetAppUnits(width);
2796 return val;
2797 }
2799 CSSValue*
2800 nsComputedDOMStyle::DoGetOutlineStyle()
2801 {
2802 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2803 val->SetIdent(
2804 nsCSSProps::ValueToKeywordEnum(StyleOutline()->GetOutlineStyle(),
2805 nsCSSProps::kOutlineStyleKTable));
2806 return val;
2807 }
2809 CSSValue*
2810 nsComputedDOMStyle::DoGetOutlineOffset()
2811 {
2812 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2813 val->SetAppUnits(StyleOutline()->mOutlineOffset);
2814 return val;
2815 }
2817 CSSValue*
2818 nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
2819 {
2820 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2821 NS_CORNER_BOTTOM_LEFT, false);
2822 }
2824 CSSValue*
2825 nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
2826 {
2827 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2828 NS_CORNER_BOTTOM_RIGHT, false);
2829 }
2831 CSSValue*
2832 nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
2833 {
2834 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2835 NS_CORNER_TOP_LEFT, false);
2836 }
2838 CSSValue*
2839 nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
2840 {
2841 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2842 NS_CORNER_TOP_RIGHT, false);
2843 }
2845 CSSValue*
2846 nsComputedDOMStyle::DoGetOutlineColor()
2847 {
2848 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2850 nscolor color;
2851 if (!StyleOutline()->GetOutlineColor(color))
2852 color = StyleColor()->mColor;
2854 SetToRGBAColor(val, color);
2855 return val;
2856 }
2858 CSSValue*
2859 nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
2860 uint8_t aFullCorner,
2861 bool aIsBorder) // else outline
2862 {
2863 nsStyleCoord radiusX, radiusY;
2864 if (mInnerFrame && aIsBorder) {
2865 nscoord radii[8];
2866 mInnerFrame->GetBorderRadii(radii);
2867 radiusX.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, false)]);
2868 radiusY.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, true)]);
2869 } else {
2870 radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false));
2871 radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true));
2873 if (mInnerFrame) {
2874 // We need to convert to absolute coordinates before doing the
2875 // equality check below.
2876 nscoord v;
2878 v = StyleCoordToNSCoord(radiusX,
2879 &nsComputedDOMStyle::GetFrameBorderRectWidth,
2880 0, true);
2881 radiusX.SetCoordValue(v);
2883 v = StyleCoordToNSCoord(radiusY,
2884 &nsComputedDOMStyle::GetFrameBorderRectHeight,
2885 0, true);
2886 radiusY.SetCoordValue(v);
2887 }
2888 }
2890 // for compatibility, return a single value if X and Y are equal
2891 if (radiusX == radiusY) {
2892 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2894 SetValueToCoord(val, radiusX, true);
2896 return val;
2897 }
2899 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2901 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
2902 valueList->AppendCSSValue(valX);
2904 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
2905 valueList->AppendCSSValue(valY);
2907 SetValueToCoord(valX, radiusX, true);
2908 SetValueToCoord(valY, radiusY, true);
2910 return valueList;
2911 }
2913 CSSValue*
2914 nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
2915 const nscolor& aDefaultColor,
2916 bool aIsBoxShadow)
2917 {
2918 if (!aArray) {
2919 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2920 val->SetIdent(eCSSKeyword_none);
2921 return val;
2922 }
2924 static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
2925 &nsCSSShadowItem::mXOffset,
2926 &nsCSSShadowItem::mYOffset,
2927 &nsCSSShadowItem::mRadius
2928 };
2930 static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
2931 &nsCSSShadowItem::mXOffset,
2932 &nsCSSShadowItem::mYOffset,
2933 &nsCSSShadowItem::mRadius,
2934 &nsCSSShadowItem::mSpread
2935 };
2937 nscoord nsCSSShadowItem::* const * shadowValues;
2938 uint32_t shadowValuesLength;
2939 if (aIsBoxShadow) {
2940 shadowValues = shadowValuesWithSpread;
2941 shadowValuesLength = ArrayLength(shadowValuesWithSpread);
2942 } else {
2943 shadowValues = shadowValuesNoSpread;
2944 shadowValuesLength = ArrayLength(shadowValuesNoSpread);
2945 }
2947 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2949 for (nsCSSShadowItem *item = aArray->ShadowAt(0),
2950 *item_end = item + aArray->Length();
2951 item < item_end; ++item) {
2952 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2953 valueList->AppendCSSValue(itemList);
2955 // Color is either the specified shadow color or the foreground color
2956 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2957 itemList->AppendCSSValue(val);
2958 nscolor shadowColor;
2959 if (item->mHasColor) {
2960 shadowColor = item->mColor;
2961 } else {
2962 shadowColor = aDefaultColor;
2963 }
2964 SetToRGBAColor(val, shadowColor);
2966 // Set the offsets, blur radius, and spread if available
2967 for (uint32_t i = 0; i < shadowValuesLength; ++i) {
2968 val = new nsROCSSPrimitiveValue;
2969 itemList->AppendCSSValue(val);
2970 val->SetAppUnits(item->*(shadowValues[i]));
2971 }
2973 if (item->mInset && aIsBoxShadow) {
2974 // This is an inset box-shadow
2975 val = new nsROCSSPrimitiveValue;
2976 itemList->AppendCSSValue(val);
2977 val->SetIdent(
2978 nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
2979 nsCSSProps::kBoxShadowTypeKTable));
2980 }
2981 }
2983 return valueList;
2984 }
2986 CSSValue*
2987 nsComputedDOMStyle::DoGetBoxShadow()
2988 {
2989 return GetCSSShadowArray(StyleBorder()->mBoxShadow,
2990 StyleColor()->mColor,
2991 true);
2992 }
2994 CSSValue*
2995 nsComputedDOMStyle::DoGetZIndex()
2996 {
2997 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2998 SetValueToCoord(val, StylePosition()->mZIndex, false);
2999 return val;
3000 }
3002 CSSValue*
3003 nsComputedDOMStyle::DoGetListStyleImage()
3004 {
3005 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3007 const nsStyleList* list = StyleList();
3009 if (!list->GetListStyleImage()) {
3010 val->SetIdent(eCSSKeyword_none);
3011 } else {
3012 nsCOMPtr<nsIURI> uri;
3013 if (list->GetListStyleImage()) {
3014 list->GetListStyleImage()->GetURI(getter_AddRefs(uri));
3015 }
3016 val->SetURI(uri);
3017 }
3019 return val;
3020 }
3022 CSSValue*
3023 nsComputedDOMStyle::DoGetListStylePosition()
3024 {
3025 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3026 val->SetIdent(
3027 nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition,
3028 nsCSSProps::kListStylePositionKTable));
3029 return val;
3030 }
3032 CSSValue*
3033 nsComputedDOMStyle::DoGetListStyleType()
3034 {
3035 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3036 val->SetIdent(
3037 nsCSSProps::ValueToKeywordEnum(StyleList()->mListStyleType,
3038 nsCSSProps::kListStyleKTable));
3039 return val;
3040 }
3042 CSSValue*
3043 nsComputedDOMStyle::DoGetImageRegion()
3044 {
3045 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3047 const nsStyleList* list = StyleList();
3049 if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
3050 val->SetIdent(eCSSKeyword_auto);
3051 } else {
3052 // create the cssvalues for the sides, stick them in the rect object
3053 nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
3054 nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
3055 nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3056 nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
3057 nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3058 bottomVal, leftVal);
3059 topVal->SetAppUnits(list->mImageRegion.y);
3060 rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
3061 bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
3062 leftVal->SetAppUnits(list->mImageRegion.x);
3063 val->SetRect(domRect);
3064 }
3066 return val;
3067 }
3069 CSSValue*
3070 nsComputedDOMStyle::DoGetLineHeight()
3071 {
3072 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3074 nscoord lineHeight;
3075 if (GetLineHeightCoord(lineHeight)) {
3076 val->SetAppUnits(lineHeight);
3077 } else {
3078 SetValueToCoord(val, StyleText()->mLineHeight, true,
3079 nullptr, nsCSSProps::kLineHeightKTable);
3080 }
3082 return val;
3083 }
3085 CSSValue*
3086 nsComputedDOMStyle::DoGetVerticalAlign()
3087 {
3088 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3089 SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false,
3090 &nsComputedDOMStyle::GetLineHeightCoord,
3091 nsCSSProps::kVerticalAlignKTable);
3092 return val;
3093 }
3095 CSSValue*
3096 nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
3097 const KTableValue aTable[])
3098 {
3099 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3100 val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
3101 if (!aAlignTrue) {
3102 return val;
3103 }
3105 nsROCSSPrimitiveValue* first = new nsROCSSPrimitiveValue;
3106 first->SetIdent(eCSSKeyword_true);
3108 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3109 valueList->AppendCSSValue(first);
3110 valueList->AppendCSSValue(val);
3111 return valueList;
3112 }
3114 CSSValue*
3115 nsComputedDOMStyle::DoGetTextAlign()
3116 {
3117 const nsStyleText* style = StyleText();
3118 return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
3119 nsCSSProps::kTextAlignKTable);
3120 }
3122 CSSValue*
3123 nsComputedDOMStyle::DoGetTextAlignLast()
3124 {
3125 const nsStyleText* style = StyleText();
3126 return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
3127 nsCSSProps::kTextAlignLastKTable);
3128 }
3130 CSSValue*
3131 nsComputedDOMStyle::DoGetTextCombineUpright()
3132 {
3133 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3134 uint8_t tch = StyleText()->mTextCombineUpright;
3136 if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
3137 val->SetIdent(
3138 nsCSSProps::ValueToKeywordEnum(tch,
3139 nsCSSProps::kTextCombineUprightKTable));
3140 } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
3141 val->SetString(NS_LITERAL_STRING("digits 2"));
3142 } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
3143 val->SetString(NS_LITERAL_STRING("digits 3"));
3144 } else {
3145 val->SetString(NS_LITERAL_STRING("digits 4"));
3146 }
3148 return val;
3149 }
3151 CSSValue*
3152 nsComputedDOMStyle::DoGetTextDecoration()
3153 {
3154 const nsStyleTextReset* textReset = StyleTextReset();
3156 // If decoration style or color wasn't initial value, the author knew the
3157 // text-decoration is a shorthand property in CSS 3.
3158 // Return nullptr in such cases.
3159 if (textReset->GetDecorationStyle() != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
3160 return nullptr;
3161 }
3163 nscolor color;
3164 bool isForegroundColor;
3165 textReset->GetDecorationColor(color, isForegroundColor);
3166 if (!isForegroundColor) {
3167 return nullptr;
3168 }
3170 // Otherwise, the web pages may have been written for CSS 2.1 or earlier,
3171 // i.e., text-decoration was assumed as a longhand property. In that case,
3172 // we should return computed value same as CSS 2.1 for backward compatibility.
3174 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3175 uint8_t line = textReset->mTextDecorationLine;
3176 // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
3177 // don't want these to appear in the computed style.
3178 line &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
3179 NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
3181 if (line == NS_STYLE_TEXT_DECORATION_LINE_NONE) {
3182 val->SetIdent(eCSSKeyword_none);
3183 } else {
3184 nsAutoString str;
3185 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
3186 line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
3187 NS_STYLE_TEXT_DECORATION_LINE_BLINK, str);
3188 val->SetString(str);
3189 }
3191 return val;
3192 }
3194 CSSValue*
3195 nsComputedDOMStyle::DoGetTextDecorationColor()
3196 {
3197 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3199 nscolor color;
3200 bool isForeground;
3201 StyleTextReset()->GetDecorationColor(color, isForeground);
3202 if (isForeground) {
3203 color = StyleColor()->mColor;
3204 }
3206 SetToRGBAColor(val, color);
3208 return val;
3209 }
3211 CSSValue*
3212 nsComputedDOMStyle::DoGetTextDecorationLine()
3213 {
3214 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3216 int32_t intValue = StyleTextReset()->mTextDecorationLine;
3218 if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
3219 val->SetIdent(eCSSKeyword_none);
3220 } else {
3221 nsAutoString decorationLineString;
3222 // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
3223 // don't want these to appear in the computed style.
3224 intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
3225 NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
3226 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
3227 intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
3228 NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
3229 val->SetString(decorationLineString);
3230 }
3232 return val;
3233 }
3235 CSSValue*
3236 nsComputedDOMStyle::DoGetTextDecorationStyle()
3237 {
3238 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3240 val->SetIdent(
3241 nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(),
3242 nsCSSProps::kTextDecorationStyleKTable));
3244 return val;
3245 }
3247 CSSValue*
3248 nsComputedDOMStyle::DoGetTextIndent()
3249 {
3250 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3251 SetValueToCoord(val, StyleText()->mTextIndent, false,
3252 &nsComputedDOMStyle::GetCBContentWidth);
3253 return val;
3254 }
3256 CSSValue*
3257 nsComputedDOMStyle::DoGetTextOrientation()
3258 {
3259 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3260 val->SetIdent(
3261 nsCSSProps::ValueToKeywordEnum(StyleText()->mTextOrientation,
3262 nsCSSProps::kTextOrientationKTable));
3263 return val;
3264 }
3266 CSSValue*
3267 nsComputedDOMStyle::DoGetTextOverflow()
3268 {
3269 const nsStyleTextReset *style = StyleTextReset();
3270 nsROCSSPrimitiveValue *first = new nsROCSSPrimitiveValue;
3271 const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
3272 if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3273 nsString str;
3274 nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3275 first->SetString(str);
3276 } else {
3277 first->SetIdent(
3278 nsCSSProps::ValueToKeywordEnum(side->mType,
3279 nsCSSProps::kTextOverflowKTable));
3280 }
3281 side = style->mTextOverflow.GetSecondValue();
3282 if (!side) {
3283 return first;
3284 }
3285 nsROCSSPrimitiveValue *second = new nsROCSSPrimitiveValue;
3286 if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3287 nsString str;
3288 nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3289 second->SetString(str);
3290 } else {
3291 second->SetIdent(
3292 nsCSSProps::ValueToKeywordEnum(side->mType,
3293 nsCSSProps::kTextOverflowKTable));
3294 }
3296 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
3297 valueList->AppendCSSValue(first);
3298 valueList->AppendCSSValue(second);
3299 return valueList;
3300 }
3302 CSSValue*
3303 nsComputedDOMStyle::DoGetTextShadow()
3304 {
3305 return GetCSSShadowArray(StyleText()->mTextShadow,
3306 StyleColor()->mColor,
3307 false);
3308 }
3310 CSSValue*
3311 nsComputedDOMStyle::DoGetTextTransform()
3312 {
3313 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3314 val->SetIdent(
3315 nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform,
3316 nsCSSProps::kTextTransformKTable));
3317 return val;
3318 }
3320 CSSValue*
3321 nsComputedDOMStyle::DoGetTabSize()
3322 {
3323 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3324 val->SetNumber(StyleText()->mTabSize);
3325 return val;
3326 }
3328 CSSValue*
3329 nsComputedDOMStyle::DoGetLetterSpacing()
3330 {
3331 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3332 SetValueToCoord(val, StyleText()->mLetterSpacing, false);
3333 return val;
3334 }
3336 CSSValue*
3337 nsComputedDOMStyle::DoGetWordSpacing()
3338 {
3339 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3340 val->SetAppUnits(StyleText()->mWordSpacing);
3341 return val;
3342 }
3344 CSSValue*
3345 nsComputedDOMStyle::DoGetWhiteSpace()
3346 {
3347 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3348 val->SetIdent(
3349 nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace,
3350 nsCSSProps::kWhitespaceKTable));
3351 return val;
3352 }
3354 CSSValue*
3355 nsComputedDOMStyle::DoGetWindowShadow()
3356 {
3357 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3358 val->SetIdent(
3359 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow,
3360 nsCSSProps::kWindowShadowKTable));
3361 return val;
3362 }
3364 CSSValue*
3365 nsComputedDOMStyle::DoGetWordBreak()
3366 {
3367 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3368 val->SetIdent(
3369 nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak,
3370 nsCSSProps::kWordBreakKTable));
3371 return val;
3372 }
3374 CSSValue*
3375 nsComputedDOMStyle::DoGetWordWrap()
3376 {
3377 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3378 val->SetIdent(
3379 nsCSSProps::ValueToKeywordEnum(StyleText()->mWordWrap,
3380 nsCSSProps::kWordWrapKTable));
3381 return val;
3382 }
3384 CSSValue*
3385 nsComputedDOMStyle::DoGetHyphens()
3386 {
3387 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3388 val->SetIdent(
3389 nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens,
3390 nsCSSProps::kHyphensKTable));
3391 return val;
3392 }
3394 CSSValue*
3395 nsComputedDOMStyle::DoGetTextSizeAdjust()
3396 {
3397 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3398 switch (StyleText()->mTextSizeAdjust) {
3399 default:
3400 NS_NOTREACHED("unexpected value");
3401 // fall through
3402 case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
3403 val->SetIdent(eCSSKeyword_auto);
3404 break;
3405 case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
3406 val->SetIdent(eCSSKeyword_none);
3407 break;
3408 }
3409 return val;
3410 }
3412 CSSValue*
3413 nsComputedDOMStyle::DoGetPointerEvents()
3414 {
3415 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3416 val->SetIdent(
3417 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mPointerEvents,
3418 nsCSSProps::kPointerEventsKTable));
3419 return val;
3420 }
3422 CSSValue*
3423 nsComputedDOMStyle::DoGetVisibility()
3424 {
3425 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3426 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible,
3427 nsCSSProps::kVisibilityKTable));
3428 return val;
3429 }
3431 CSSValue*
3432 nsComputedDOMStyle::DoGetWritingMode()
3433 {
3434 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3435 val->SetIdent(
3436 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode,
3437 nsCSSProps::kWritingModeKTable));
3438 return val;
3439 }
3441 CSSValue*
3442 nsComputedDOMStyle::DoGetDirection()
3443 {
3444 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3445 val->SetIdent(
3446 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection,
3447 nsCSSProps::kDirectionKTable));
3448 return val;
3449 }
3451 static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
3452 "unicode-bidi style constants not as expected");
3454 CSSValue*
3455 nsComputedDOMStyle::DoGetUnicodeBidi()
3456 {
3457 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3458 val->SetIdent(
3459 nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
3460 nsCSSProps::kUnicodeBidiKTable));
3461 return val;
3462 }
3464 CSSValue*
3465 nsComputedDOMStyle::DoGetCursor()
3466 {
3467 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
3469 const nsStyleUserInterface *ui = StyleUserInterface();
3471 for (nsCursorImage *item = ui->mCursorArray,
3472 *item_end = ui->mCursorArray + ui->mCursorArrayLength;
3473 item < item_end; ++item) {
3474 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
3475 valueList->AppendCSSValue(itemList);
3477 nsCOMPtr<nsIURI> uri;
3478 item->GetImage()->GetURI(getter_AddRefs(uri));
3480 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3481 itemList->AppendCSSValue(val);
3482 val->SetURI(uri);
3484 if (item->mHaveHotspot) {
3485 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
3486 itemList->AppendCSSValue(valX);
3487 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
3488 itemList->AppendCSSValue(valY);
3490 valX->SetNumber(item->mHotspotX);
3491 valY->SetNumber(item->mHotspotY);
3492 }
3493 }
3495 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3496 val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
3497 nsCSSProps::kCursorKTable));
3498 valueList->AppendCSSValue(val);
3499 return valueList;
3500 }
3502 CSSValue*
3503 nsComputedDOMStyle::DoGetAppearance()
3504 {
3505 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3506 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance,
3507 nsCSSProps::kAppearanceKTable));
3508 return val;
3509 }
3512 CSSValue*
3513 nsComputedDOMStyle::DoGetBoxAlign()
3514 {
3515 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3516 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign,
3517 nsCSSProps::kBoxAlignKTable));
3518 return val;
3519 }
3521 CSSValue*
3522 nsComputedDOMStyle::DoGetBoxDirection()
3523 {
3524 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3525 val->SetIdent(
3526 nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection,
3527 nsCSSProps::kBoxDirectionKTable));
3528 return val;
3529 }
3531 CSSValue*
3532 nsComputedDOMStyle::DoGetBoxFlex()
3533 {
3534 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3535 val->SetNumber(StyleXUL()->mBoxFlex);
3536 return val;
3537 }
3539 CSSValue*
3540 nsComputedDOMStyle::DoGetBoxOrdinalGroup()
3541 {
3542 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3543 val->SetNumber(StyleXUL()->mBoxOrdinal);
3544 return val;
3545 }
3547 CSSValue*
3548 nsComputedDOMStyle::DoGetBoxOrient()
3549 {
3550 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3551 val->SetIdent(
3552 nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient,
3553 nsCSSProps::kBoxOrientKTable));
3554 return val;
3555 }
3557 CSSValue*
3558 nsComputedDOMStyle::DoGetBoxPack()
3559 {
3560 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3561 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack,
3562 nsCSSProps::kBoxPackKTable));
3563 return val;
3564 }
3566 CSSValue*
3567 nsComputedDOMStyle::DoGetBoxSizing()
3568 {
3569 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3570 val->SetIdent(
3571 nsCSSProps::ValueToKeywordEnum(StylePosition()->mBoxSizing,
3572 nsCSSProps::kBoxSizingKTable));
3573 return val;
3574 }
3576 /* Border image properties */
3578 CSSValue*
3579 nsComputedDOMStyle::DoGetBorderImageSource()
3580 {
3581 const nsStyleBorder* border = StyleBorder();
3583 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3584 const nsStyleImage& image = border->mBorderImageSource;
3585 SetValueToStyleImage(image, val);
3587 return val;
3588 }
3590 CSSValue*
3591 nsComputedDOMStyle::DoGetBorderImageSlice()
3592 {
3593 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3595 const nsStyleBorder* border = StyleBorder();
3596 // Four slice numbers.
3597 NS_FOR_CSS_SIDES (side) {
3598 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3599 valueList->AppendCSSValue(val);
3600 SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
3601 }
3603 // Fill keyword.
3604 if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
3605 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3606 valueList->AppendCSSValue(val);
3607 val->SetIdent(eCSSKeyword_fill);
3608 }
3610 return valueList;
3611 }
3613 CSSValue*
3614 nsComputedDOMStyle::DoGetBorderImageWidth()
3615 {
3616 const nsStyleBorder* border = StyleBorder();
3617 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3618 NS_FOR_CSS_SIDES (side) {
3619 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3620 valueList->AppendCSSValue(val);
3621 SetValueToCoord(val, border->mBorderImageWidth.Get(side),
3622 true, nullptr);
3623 }
3625 return valueList;
3626 }
3628 CSSValue*
3629 nsComputedDOMStyle::DoGetBorderImageOutset()
3630 {
3631 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
3633 const nsStyleBorder* border = StyleBorder();
3634 // four slice numbers
3635 NS_FOR_CSS_SIDES (side) {
3636 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3637 valueList->AppendCSSValue(val);
3638 SetValueToCoord(val, border->mBorderImageOutset.Get(side),
3639 true, nullptr);
3640 }
3642 return valueList;
3643 }
3645 CSSValue*
3646 nsComputedDOMStyle::DoGetBorderImageRepeat()
3647 {
3648 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3650 const nsStyleBorder* border = StyleBorder();
3652 // horizontal repeat
3653 nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
3654 valueList->AppendCSSValue(valX);
3655 valX->SetIdent(
3656 nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
3657 nsCSSProps::kBorderImageRepeatKTable));
3659 // vertical repeat
3660 nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
3661 valueList->AppendCSSValue(valY);
3662 valY->SetIdent(
3663 nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
3664 nsCSSProps::kBorderImageRepeatKTable));
3665 return valueList;
3666 }
3668 CSSValue*
3669 nsComputedDOMStyle::DoGetAlignContent()
3670 {
3671 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3672 val->SetIdent(
3673 nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignContent,
3674 nsCSSProps::kAlignContentKTable));
3675 return val;
3676 }
3678 CSSValue*
3679 nsComputedDOMStyle::DoGetAlignItems()
3680 {
3681 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3682 val->SetIdent(
3683 nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignItems,
3684 nsCSSProps::kAlignItemsKTable));
3685 return val;
3686 }
3688 CSSValue*
3689 nsComputedDOMStyle::DoGetAlignSelf()
3690 {
3691 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3692 uint8_t computedAlignSelf = StylePosition()->mAlignSelf;
3694 if (computedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
3695 // "align-self: auto" needs to compute to parent's align-items value.
3696 nsStyleContext* parentStyleContext = mStyleContextHolder->GetParent();
3697 if (parentStyleContext) {
3698 computedAlignSelf =
3699 parentStyleContext->StylePosition()->mAlignItems;
3700 } else {
3701 // No parent --> use default.
3702 computedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
3703 }
3704 }
3706 NS_ABORT_IF_FALSE(computedAlignSelf != NS_STYLE_ALIGN_SELF_AUTO,
3707 "Should have swapped out 'auto' for something non-auto");
3708 val->SetIdent(
3709 nsCSSProps::ValueToKeywordEnum(computedAlignSelf,
3710 nsCSSProps::kAlignSelfKTable));
3711 return val;
3712 }
3714 CSSValue*
3715 nsComputedDOMStyle::DoGetFlexBasis()
3716 {
3717 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3719 // XXXdholbert We could make this more automagic and resolve percentages
3720 // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
3721 // below. Logic would go like this:
3722 // if (i'm a flex item) {
3723 // if (my flex container is horizontal) {
3724 // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
3725 // } else {
3726 // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
3727 // }
3728 // }
3730 SetValueToCoord(val, StylePosition()->mFlexBasis, true,
3731 nullptr, nsCSSProps::kWidthKTable);
3732 return val;
3733 }
3735 CSSValue*
3736 nsComputedDOMStyle::DoGetFlexDirection()
3737 {
3738 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3739 val->SetIdent(
3740 nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection,
3741 nsCSSProps::kFlexDirectionKTable));
3742 return val;
3743 }
3745 CSSValue*
3746 nsComputedDOMStyle::DoGetFlexGrow()
3747 {
3748 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3749 val->SetNumber(StylePosition()->mFlexGrow);
3750 return val;
3751 }
3753 CSSValue*
3754 nsComputedDOMStyle::DoGetFlexShrink()
3755 {
3756 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3757 val->SetNumber(StylePosition()->mFlexShrink);
3758 return val;
3759 }
3761 CSSValue*
3762 nsComputedDOMStyle::DoGetFlexWrap()
3763 {
3764 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3765 val->SetIdent(
3766 nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap,
3767 nsCSSProps::kFlexWrapKTable));
3768 return val;
3769 }
3771 CSSValue*
3772 nsComputedDOMStyle::DoGetOrder()
3773 {
3774 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3775 val->SetNumber(StylePosition()->mOrder);
3776 return val;
3777 }
3779 CSSValue*
3780 nsComputedDOMStyle::DoGetJustifyContent()
3781 {
3782 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3783 val->SetIdent(
3784 nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent,
3785 nsCSSProps::kJustifyContentKTable));
3786 return val;
3787 }
3789 CSSValue*
3790 nsComputedDOMStyle::DoGetFloatEdge()
3791 {
3792 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3793 val->SetIdent(
3794 nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
3795 nsCSSProps::kFloatEdgeKTable));
3796 return val;
3797 }
3799 CSSValue*
3800 nsComputedDOMStyle::DoGetForceBrokenImageIcon()
3801 {
3802 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3803 val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
3804 return val;
3805 }
3807 CSSValue*
3808 nsComputedDOMStyle::DoGetImageOrientation()
3809 {
3810 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3811 nsAutoString string;
3812 nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation;
3814 if (orientation.IsFromImage()) {
3815 string.AppendLiteral("from-image");
3816 } else {
3817 nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string);
3819 if (orientation.IsFlipped()) {
3820 string.AppendLiteral(" flip");
3821 }
3822 }
3824 val->SetString(string);
3825 return val;
3826 }
3828 CSSValue*
3829 nsComputedDOMStyle::DoGetIMEMode()
3830 {
3831 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3832 val->SetIdent(
3833 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode,
3834 nsCSSProps::kIMEModeKTable));
3835 return val;
3836 }
3838 CSSValue*
3839 nsComputedDOMStyle::DoGetUserFocus()
3840 {
3841 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3842 val->SetIdent(
3843 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus,
3844 nsCSSProps::kUserFocusKTable));
3845 return val;
3846 }
3848 CSSValue*
3849 nsComputedDOMStyle::DoGetUserInput()
3850 {
3851 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3852 val->SetIdent(
3853 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput,
3854 nsCSSProps::kUserInputKTable));
3855 return val;
3856 }
3858 CSSValue*
3859 nsComputedDOMStyle::DoGetUserModify()
3860 {
3861 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3862 val->SetIdent(
3863 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify,
3864 nsCSSProps::kUserModifyKTable));
3865 return val;
3866 }
3868 CSSValue*
3869 nsComputedDOMStyle::DoGetUserSelect()
3870 {
3871 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3872 val->SetIdent(
3873 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect,
3874 nsCSSProps::kUserSelectKTable));
3875 return val;
3876 }
3878 CSSValue*
3879 nsComputedDOMStyle::DoGetDisplay()
3880 {
3881 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3882 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
3883 nsCSSProps::kDisplayKTable));
3884 return val;
3885 }
3887 CSSValue*
3888 nsComputedDOMStyle::DoGetPosition()
3889 {
3890 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3891 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition,
3892 nsCSSProps::kPositionKTable));
3893 return val;
3894 }
3896 CSSValue*
3897 nsComputedDOMStyle::DoGetClip()
3898 {
3899 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3901 const nsStyleDisplay* display = StyleDisplay();
3903 if (display->mClipFlags == NS_STYLE_CLIP_AUTO) {
3904 val->SetIdent(eCSSKeyword_auto);
3905 } else {
3906 // create the cssvalues for the sides, stick them in the rect object
3907 nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
3908 nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
3909 nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3910 nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
3911 nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3912 bottomVal, leftVal);
3913 if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
3914 topVal->SetIdent(eCSSKeyword_auto);
3915 } else {
3916 topVal->SetAppUnits(display->mClip.y);
3917 }
3919 if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
3920 rightVal->SetIdent(eCSSKeyword_auto);
3921 } else {
3922 rightVal->SetAppUnits(display->mClip.width + display->mClip.x);
3923 }
3925 if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
3926 bottomVal->SetIdent(eCSSKeyword_auto);
3927 } else {
3928 bottomVal->SetAppUnits(display->mClip.height + display->mClip.y);
3929 }
3931 if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
3932 leftVal->SetIdent(eCSSKeyword_auto);
3933 } else {
3934 leftVal->SetAppUnits(display->mClip.x);
3935 }
3936 val->SetRect(domRect);
3937 }
3939 return val;
3940 }
3942 CSSValue*
3943 nsComputedDOMStyle::DoGetWillChange()
3944 {
3945 const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
3947 if (willChange.IsEmpty()) {
3948 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3949 val->SetIdent(eCSSKeyword_auto);
3950 return val;
3951 }
3953 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
3954 for (size_t i = 0; i < willChange.Length(); i++) {
3955 const nsString& willChangeIdentifier = willChange[i];
3956 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
3957 valueList->AppendCSSValue(property);
3958 property->SetString(willChangeIdentifier);
3959 }
3961 return valueList;
3962 }
3964 CSSValue*
3965 nsComputedDOMStyle::DoGetOverflow()
3966 {
3967 const nsStyleDisplay* display = StyleDisplay();
3969 if (display->mOverflowX != display->mOverflowY) {
3970 // No value to return. We can't express this combination of
3971 // values as a shorthand.
3972 return nullptr;
3973 }
3975 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3976 val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
3977 nsCSSProps::kOverflowKTable));
3978 return val;
3979 }
3981 CSSValue*
3982 nsComputedDOMStyle::DoGetOverflowX()
3983 {
3984 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3985 val->SetIdent(
3986 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX,
3987 nsCSSProps::kOverflowSubKTable));
3988 return val;
3989 }
3991 CSSValue*
3992 nsComputedDOMStyle::DoGetOverflowY()
3993 {
3994 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3995 val->SetIdent(
3996 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
3997 nsCSSProps::kOverflowSubKTable));
3998 return val;
3999 }
4001 CSSValue*
4002 nsComputedDOMStyle::DoGetOverflowClipBox()
4003 {
4004 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4005 val->SetIdent(
4006 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
4007 nsCSSProps::kOverflowClipBoxKTable));
4008 return val;
4009 }
4011 CSSValue*
4012 nsComputedDOMStyle::DoGetResize()
4013 {
4014 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4015 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
4016 nsCSSProps::kResizeKTable));
4017 return val;
4018 }
4021 CSSValue*
4022 nsComputedDOMStyle::DoGetPageBreakAfter()
4023 {
4024 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4026 const nsStyleDisplay *display = StyleDisplay();
4028 if (display->mBreakAfter) {
4029 val->SetIdent(eCSSKeyword_always);
4030 } else {
4031 val->SetIdent(eCSSKeyword_auto);
4032 }
4034 return val;
4035 }
4037 CSSValue*
4038 nsComputedDOMStyle::DoGetPageBreakBefore()
4039 {
4040 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4042 const nsStyleDisplay *display = StyleDisplay();
4044 if (display->mBreakBefore) {
4045 val->SetIdent(eCSSKeyword_always);
4046 } else {
4047 val->SetIdent(eCSSKeyword_auto);
4048 }
4050 return val;
4051 }
4053 CSSValue*
4054 nsComputedDOMStyle::DoGetPageBreakInside()
4055 {
4056 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4057 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside,
4058 nsCSSProps::kPageBreakInsideKTable));
4059 return val;
4060 }
4062 CSSValue*
4063 nsComputedDOMStyle::DoGetTouchAction()
4064 {
4065 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4067 int32_t intValue = StyleDisplay()->mTouchAction;
4069 // None and Auto and Manipulation values aren't allowed
4070 // to be in conjunction with other values.
4071 // But there are all checks in CSSParserImpl::ParseTouchAction
4072 nsAutoString valueStr;
4073 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
4074 NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
4075 valueStr);
4076 val->SetString(valueStr);
4077 return val;
4078 }
4080 CSSValue*
4081 nsComputedDOMStyle::DoGetHeight()
4082 {
4083 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4085 bool calcHeight = false;
4087 if (mInnerFrame) {
4088 calcHeight = true;
4090 const nsStyleDisplay* displayData = StyleDisplay();
4091 if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
4092 !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
4093 // An outer SVG frame should behave the same as eReplaced in this case
4094 mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
4096 calcHeight = false;
4097 }
4098 }
4100 if (calcHeight) {
4101 AssertFlushedPendingReflows();
4102 nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
4103 val->SetAppUnits(mInnerFrame->GetContentRect().height +
4104 adjustedValues.TopBottom());
4105 } else {
4106 const nsStylePosition *positionData = StylePosition();
4108 nscoord minHeight =
4109 StyleCoordToNSCoord(positionData->mMinHeight,
4110 &nsComputedDOMStyle::GetCBContentHeight, 0, true);
4112 nscoord maxHeight =
4113 StyleCoordToNSCoord(positionData->mMaxHeight,
4114 &nsComputedDOMStyle::GetCBContentHeight,
4115 nscoord_MAX, true);
4117 SetValueToCoord(val, positionData->mHeight, true, nullptr, nullptr,
4118 minHeight, maxHeight);
4119 }
4121 return val;
4122 }
4124 CSSValue*
4125 nsComputedDOMStyle::DoGetWidth()
4126 {
4127 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4129 bool calcWidth = false;
4131 if (mInnerFrame) {
4132 calcWidth = true;
4134 const nsStyleDisplay *displayData = StyleDisplay();
4135 if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
4136 !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
4137 // An outer SVG frame should behave the same as eReplaced in this case
4138 mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
4140 calcWidth = false;
4141 }
4142 }
4144 if (calcWidth) {
4145 AssertFlushedPendingReflows();
4146 nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
4147 val->SetAppUnits(mInnerFrame->GetContentRect().width +
4148 adjustedValues.LeftRight());
4149 } else {
4150 const nsStylePosition *positionData = StylePosition();
4152 nscoord minWidth =
4153 StyleCoordToNSCoord(positionData->mMinWidth,
4154 &nsComputedDOMStyle::GetCBContentWidth, 0, true);
4156 nscoord maxWidth =
4157 StyleCoordToNSCoord(positionData->mMaxWidth,
4158 &nsComputedDOMStyle::GetCBContentWidth,
4159 nscoord_MAX, true);
4161 SetValueToCoord(val, positionData->mWidth, true, nullptr,
4162 nsCSSProps::kWidthKTable, minWidth, maxWidth);
4163 }
4165 return val;
4166 }
4168 CSSValue*
4169 nsComputedDOMStyle::DoGetMaxHeight()
4170 {
4171 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4172 SetValueToCoord(val, StylePosition()->mMaxHeight, true,
4173 &nsComputedDOMStyle::GetCBContentHeight);
4174 return val;
4175 }
4177 CSSValue*
4178 nsComputedDOMStyle::DoGetMaxWidth()
4179 {
4180 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4181 SetValueToCoord(val, StylePosition()->mMaxWidth, true,
4182 &nsComputedDOMStyle::GetCBContentWidth,
4183 nsCSSProps::kWidthKTable);
4184 return val;
4185 }
4187 CSSValue*
4188 nsComputedDOMStyle::DoGetMinHeight()
4189 {
4190 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4191 SetValueToCoord(val, StylePosition()->mMinHeight, true,
4192 &nsComputedDOMStyle::GetCBContentHeight);
4193 return val;
4194 }
4196 CSSValue*
4197 nsComputedDOMStyle::DoGetMinWidth()
4198 {
4199 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4200 SetValueToCoord(val, StylePosition()->mMinWidth, true,
4201 &nsComputedDOMStyle::GetCBContentWidth,
4202 nsCSSProps::kWidthKTable);
4203 return val;
4204 }
4206 CSSValue*
4207 nsComputedDOMStyle::DoGetMixBlendMode()
4208 {
4209 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4210 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode,
4211 nsCSSProps::kBlendModeKTable));
4212 return val;
4213 }
4215 CSSValue*
4216 nsComputedDOMStyle::DoGetLeft()
4217 {
4218 return GetOffsetWidthFor(NS_SIDE_LEFT);
4219 }
4221 CSSValue*
4222 nsComputedDOMStyle::DoGetRight()
4223 {
4224 return GetOffsetWidthFor(NS_SIDE_RIGHT);
4225 }
4227 CSSValue*
4228 nsComputedDOMStyle::DoGetTop()
4229 {
4230 return GetOffsetWidthFor(NS_SIDE_TOP);
4231 }
4233 nsDOMCSSValueList*
4234 nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
4235 {
4236 nsDOMCSSValueList *valueList = new nsDOMCSSValueList(aCommaDelimited, true);
4237 NS_ASSERTION(valueList != 0, "ran out of memory");
4239 return valueList;
4240 }
4242 CSSValue*
4243 nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
4244 {
4245 const nsStyleDisplay* display = StyleDisplay();
4247 AssertFlushedPendingReflows();
4249 uint8_t position = display->mPosition;
4250 if (!mOuterFrame) {
4251 // GetRelativeOffset and GetAbsoluteOffset don't handle elements
4252 // without frames in any sensible way. GetStaticOffset, however,
4253 // is perfect for that case.
4254 position = NS_STYLE_POSITION_STATIC;
4255 }
4257 switch (position) {
4258 case NS_STYLE_POSITION_STATIC:
4259 return GetStaticOffset(aSide);
4260 case NS_STYLE_POSITION_RELATIVE:
4261 return GetRelativeOffset(aSide);
4262 case NS_STYLE_POSITION_STICKY:
4263 return GetStickyOffset(aSide);
4264 case NS_STYLE_POSITION_ABSOLUTE:
4265 case NS_STYLE_POSITION_FIXED:
4266 return GetAbsoluteOffset(aSide);
4267 default:
4268 NS_ERROR("Invalid position");
4269 return nullptr;
4270 }
4271 }
4273 CSSValue*
4274 nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
4275 {
4276 MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
4278 nsIFrame* container = mOuterFrame->GetContainingBlock();
4279 nsMargin margin = mOuterFrame->GetUsedMargin();
4280 nsMargin border = container->GetUsedBorder();
4281 nsMargin scrollbarSizes(0, 0, 0, 0);
4282 nsRect rect = mOuterFrame->GetRect();
4283 nsRect containerRect = container->GetRect();
4285 if (container->GetType() == nsGkAtoms::viewportFrame) {
4286 // For absolutely positioned frames scrollbars are taken into
4287 // account by virtue of getting a containing block that does
4288 // _not_ include the scrollbars. For fixed positioned frames,
4289 // the containing block is the viewport, which _does_ include
4290 // scrollbars. We have to do some extra work.
4291 // the first child in the default frame list is what we want
4292 nsIFrame* scrollingChild = container->GetFirstPrincipalChild();
4293 nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
4294 if (scrollFrame) {
4295 scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
4296 }
4297 }
4299 nscoord offset = 0;
4300 switch (aSide) {
4301 case NS_SIDE_TOP:
4302 offset = rect.y - margin.top - border.top - scrollbarSizes.top;
4304 break;
4305 case NS_SIDE_RIGHT:
4306 offset = containerRect.width - rect.width -
4307 rect.x - margin.right - border.right - scrollbarSizes.right;
4309 break;
4310 case NS_SIDE_BOTTOM:
4311 offset = containerRect.height - rect.height -
4312 rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
4314 break;
4315 case NS_SIDE_LEFT:
4316 offset = rect.x - margin.left - border.left - scrollbarSizes.left;
4318 break;
4319 default:
4320 NS_ERROR("Invalid side");
4321 break;
4322 }
4324 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4325 val->SetAppUnits(offset);
4326 return val;
4327 }
4329 static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
4330 NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
4331 "box side constants not as expected for NS_OPPOSITE_SIDE");
4332 #define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
4334 CSSValue*
4335 nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
4336 {
4337 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4339 const nsStylePosition* positionData = StylePosition();
4340 int32_t sign = 1;
4341 nsStyleCoord coord = positionData->mOffset.Get(aSide);
4343 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4344 coord.GetUnit() == eStyleUnit_Percent ||
4345 coord.GetUnit() == eStyleUnit_Auto ||
4346 coord.IsCalcUnit(),
4347 "Unexpected unit");
4349 if (coord.GetUnit() == eStyleUnit_Auto) {
4350 coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
4351 sign = -1;
4352 }
4353 PercentageBaseGetter baseGetter;
4354 if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
4355 baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
4356 } else {
4357 baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
4358 }
4360 val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
4361 return val;
4362 }
4364 CSSValue*
4365 nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide)
4366 {
4367 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4369 const nsStylePosition* positionData = StylePosition();
4370 nsStyleCoord coord = positionData->mOffset.Get(aSide);
4372 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4373 coord.GetUnit() == eStyleUnit_Percent ||
4374 coord.GetUnit() == eStyleUnit_Auto ||
4375 coord.IsCalcUnit(),
4376 "Unexpected unit");
4378 if (coord.GetUnit() == eStyleUnit_Auto) {
4379 val->SetIdent(eCSSKeyword_auto);
4380 return val;
4381 }
4382 PercentageBaseGetter baseGetter;
4383 if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
4384 baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
4385 } else {
4386 baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
4387 }
4389 val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
4390 return val;
4391 }
4394 CSSValue*
4395 nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
4397 {
4398 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4399 SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
4400 return val;
4401 }
4403 CSSValue*
4404 nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
4405 {
4406 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4408 if (!mInnerFrame) {
4409 SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
4410 } else {
4411 AssertFlushedPendingReflows();
4413 val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
4414 }
4416 return val;
4417 }
4419 bool
4420 nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
4421 {
4422 AssertFlushedPendingReflows();
4424 nscoord blockHeight = NS_AUTOHEIGHT;
4425 if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
4426 if (!mInnerFrame)
4427 return false;
4429 if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
4430 blockHeight = mInnerFrame->GetContentRect().height;
4431 } else {
4432 GetCBContentHeight(blockHeight);
4433 }
4434 }
4436 // lie about font size inflation since we lie about font size (since
4437 // the inflation only applies to text)
4438 aCoord = nsHTMLReflowState::CalcLineHeight(mContent, mStyleContextHolder,
4439 blockHeight, 1.0f);
4441 // CalcLineHeight uses font->mFont.size, but we want to use
4442 // font->mSize as the font size. Adjust for that. Also adjust for
4443 // the text zoom, if any.
4444 const nsStyleFont* font = StyleFont();
4445 float fCoord = float(aCoord);
4446 if (font->mAllowZoom) {
4447 fCoord /= mPresShell->GetPresContext()->TextZoom();
4448 }
4449 if (font->mFont.size != font->mSize) {
4450 fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
4451 }
4452 aCoord = NSToCoordRound(fCoord);
4454 return true;
4455 }
4457 CSSValue*
4458 nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
4459 {
4460 const nsStyleBorder *border = StyleBorder();
4462 if (border->mBorderColors) {
4463 nsBorderColors* borderColors = border->mBorderColors[aSide];
4464 if (borderColors) {
4465 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
4467 do {
4468 nsROCSSPrimitiveValue *primitive = new nsROCSSPrimitiveValue;
4470 SetToRGBAColor(primitive, borderColors->mColor);
4472 valueList->AppendCSSValue(primitive);
4473 borderColors = borderColors->mNext;
4474 } while (borderColors);
4476 return valueList;
4477 }
4478 }
4480 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4481 val->SetIdent(eCSSKeyword_none);
4482 return val;
4483 }
4485 CSSValue*
4486 nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
4487 {
4488 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4490 nscoord width;
4491 if (mInnerFrame) {
4492 AssertFlushedPendingReflows();
4493 width = mInnerFrame->GetUsedBorder().Side(aSide);
4494 } else {
4495 width = StyleBorder()->GetComputedBorderWidth(aSide);
4496 }
4497 val->SetAppUnits(width);
4499 return val;
4500 }
4502 CSSValue*
4503 nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
4504 {
4505 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4507 nscolor color;
4508 bool foreground;
4509 StyleBorder()->GetBorderColor(aSide, color, foreground);
4510 if (foreground) {
4511 color = StyleColor()->mColor;
4512 }
4514 SetToRGBAColor(val, color);
4515 return val;
4516 }
4518 CSSValue*
4519 nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
4520 {
4521 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4523 if (!mInnerFrame) {
4524 SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
4525 } else {
4526 AssertFlushedPendingReflows();
4528 // For tables, GetUsedMargin always returns an empty margin, so we
4529 // should read the margin from the outer table frame instead.
4530 val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
4531 NS_ASSERTION(mOuterFrame == mInnerFrame ||
4532 mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
4533 "Inner tables must have zero margins");
4534 }
4536 return val;
4537 }
4539 CSSValue*
4540 nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
4541 {
4542 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4543 val->SetIdent(
4544 nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
4545 nsCSSProps::kBorderStyleKTable));
4546 return val;
4547 }
4549 void
4550 nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
4551 const nsStyleCoord& aCoord,
4552 bool aClampNegativeCalc,
4553 PercentageBaseGetter aPercentageBaseGetter,
4554 const KTableValue aTable[],
4555 nscoord aMinAppUnits,
4556 nscoord aMaxAppUnits)
4557 {
4558 NS_PRECONDITION(aValue, "Must have a value to work with");
4560 switch (aCoord.GetUnit()) {
4561 case eStyleUnit_Normal:
4562 aValue->SetIdent(eCSSKeyword_normal);
4563 break;
4565 case eStyleUnit_Auto:
4566 aValue->SetIdent(eCSSKeyword_auto);
4567 break;
4569 case eStyleUnit_Percent:
4570 {
4571 nscoord percentageBase;
4572 if (aPercentageBaseGetter &&
4573 (this->*aPercentageBaseGetter)(percentageBase)) {
4574 nscoord val = NSCoordSaturatingMultiply(percentageBase,
4575 aCoord.GetPercentValue());
4576 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4577 } else {
4578 aValue->SetPercent(aCoord.GetPercentValue());
4579 }
4580 }
4581 break;
4583 case eStyleUnit_Factor:
4584 aValue->SetNumber(aCoord.GetFactorValue());
4585 break;
4587 case eStyleUnit_Coord:
4588 {
4589 nscoord val = aCoord.GetCoordValue();
4590 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4591 }
4592 break;
4594 case eStyleUnit_Integer:
4595 aValue->SetNumber(aCoord.GetIntValue());
4596 break;
4598 case eStyleUnit_Enumerated:
4599 NS_ASSERTION(aTable, "Must have table to handle this case");
4600 aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
4601 aTable));
4602 break;
4604 case eStyleUnit_None:
4605 aValue->SetIdent(eCSSKeyword_none);
4606 break;
4608 case eStyleUnit_Calc:
4609 nscoord percentageBase;
4610 if (!aCoord.CalcHasPercent()) {
4611 nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
4612 if (aClampNegativeCalc && val < 0) {
4613 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4614 "parser should have rejected value");
4615 val = 0;
4616 }
4617 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4618 } else if (aPercentageBaseGetter &&
4619 (this->*aPercentageBaseGetter)(percentageBase)) {
4620 nscoord val =
4621 nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
4622 if (aClampNegativeCalc && val < 0) {
4623 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4624 "parser should have rejected value");
4625 val = 0;
4626 }
4627 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4628 } else {
4629 nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
4630 SetValueToCalc(calc, aValue);
4631 }
4632 break;
4634 case eStyleUnit_Degree:
4635 aValue->SetDegree(aCoord.GetAngleValue());
4636 break;
4638 case eStyleUnit_Grad:
4639 aValue->SetGrad(aCoord.GetAngleValue());
4640 break;
4642 case eStyleUnit_Radian:
4643 aValue->SetRadian(aCoord.GetAngleValue());
4644 break;
4646 case eStyleUnit_Turn:
4647 aValue->SetTurn(aCoord.GetAngleValue());
4648 break;
4650 case eStyleUnit_FlexFraction: {
4651 nsAutoString tmpStr;
4652 nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
4653 tmpStr.AppendLiteral("fr");
4654 aValue->SetString(tmpStr);
4655 break;
4656 }
4658 default:
4659 NS_ERROR("Can't handle this unit");
4660 break;
4661 }
4662 }
4664 nscoord
4665 nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
4666 PercentageBaseGetter aPercentageBaseGetter,
4667 nscoord aDefaultValue,
4668 bool aClampNegativeCalc)
4669 {
4670 NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter");
4671 if (aCoord.GetUnit() == eStyleUnit_Coord) {
4672 return aCoord.GetCoordValue();
4673 }
4674 if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
4675 nscoord percentageBase;
4676 if ((this->*aPercentageBaseGetter)(percentageBase)) {
4677 nscoord result =
4678 nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
4679 if (aClampNegativeCalc && result < 0) {
4680 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4681 "parser should have rejected value");
4682 result = 0;
4683 }
4684 return result;
4685 }
4686 // Fall through to returning aDefaultValue if we have no percentage base.
4687 }
4689 return aDefaultValue;
4690 }
4692 bool
4693 nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
4694 {
4695 if (!mOuterFrame) {
4696 return false;
4697 }
4699 AssertFlushedPendingReflows();
4701 nsIFrame* container = mOuterFrame->GetContainingBlock();
4702 aWidth = container->GetContentRect().width;
4703 return true;
4704 }
4706 bool
4707 nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
4708 {
4709 if (!mOuterFrame) {
4710 return false;
4711 }
4713 AssertFlushedPendingReflows();
4715 nsIFrame* container = mOuterFrame->GetContainingBlock();
4716 aHeight = container->GetContentRect().height;
4717 return true;
4718 }
4720 bool
4721 nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth)
4722 {
4723 if (!mOuterFrame) {
4724 return false;
4725 }
4727 AssertFlushedPendingReflows();
4729 nsIScrollableFrame* scrollableFrame =
4730 nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4731 nsLayoutUtils::SCROLLABLE_SAME_DOC |
4732 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4734 if (!scrollableFrame) {
4735 return false;
4736 }
4737 aWidth =
4738 scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width;
4739 return true;
4740 }
4742 bool
4743 nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight)
4744 {
4745 if (!mOuterFrame) {
4746 return false;
4747 }
4749 AssertFlushedPendingReflows();
4751 nsIScrollableFrame* scrollableFrame =
4752 nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4753 nsLayoutUtils::SCROLLABLE_SAME_DOC |
4754 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4756 if (!scrollableFrame) {
4757 return false;
4758 }
4759 aHeight =
4760 scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height;
4761 return true;
4762 }
4764 bool
4765 nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
4766 {
4767 if (!mInnerFrame) {
4768 return false;
4769 }
4771 AssertFlushedPendingReflows();
4773 aWidth = mInnerFrame->GetSize().width;
4774 return true;
4775 }
4777 bool
4778 nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
4779 {
4780 if (!mInnerFrame) {
4781 return false;
4782 }
4784 AssertFlushedPendingReflows();
4786 aHeight = mInnerFrame->GetSize().height;
4787 return true;
4788 }
4790 bool
4791 nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
4792 {
4793 // We need a frame to work with.
4794 if (!mInnerFrame) {
4795 return false;
4796 }
4798 AssertFlushedPendingReflows();
4800 aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
4801 return true;
4802 }
4804 bool
4805 nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
4806 {
4807 // We need a frame to work with.
4808 if (!mInnerFrame) {
4809 return false;
4810 }
4812 AssertFlushedPendingReflows();
4814 aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
4815 return true;
4816 }
4818 CSSValue*
4819 nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
4820 {
4821 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4823 const nsStyleSVG* svg = StyleSVG();
4824 const nsStyleSVGPaint* paint = nullptr;
4826 if (aFill)
4827 paint = &svg->mFill;
4828 else
4829 paint = &svg->mStroke;
4831 nsAutoString paintString;
4833 switch (paint->mType) {
4834 case eStyleSVGPaintType_None:
4835 {
4836 val->SetIdent(eCSSKeyword_none);
4837 break;
4838 }
4839 case eStyleSVGPaintType_Color:
4840 {
4841 SetToRGBAColor(val, paint->mPaint.mColor);
4842 break;
4843 }
4844 case eStyleSVGPaintType_Server:
4845 {
4846 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
4847 valueList->AppendCSSValue(val);
4849 nsROCSSPrimitiveValue* fallback = new nsROCSSPrimitiveValue;
4850 valueList->AppendCSSValue(fallback);
4852 val->SetURI(paint->mPaint.mPaintServer);
4853 SetToRGBAColor(fallback, paint->mFallbackColor);
4854 return valueList;
4855 }
4856 case eStyleSVGPaintType_ContextFill:
4857 {
4858 val->SetIdent(eCSSKeyword_context_fill);
4859 break;
4860 }
4861 case eStyleSVGPaintType_ContextStroke:
4862 {
4863 val->SetIdent(eCSSKeyword_context_stroke);
4864 break;
4865 }
4866 }
4868 return val;
4869 }
4871 CSSValue*
4872 nsComputedDOMStyle::DoGetFill()
4873 {
4874 return GetSVGPaintFor(true);
4875 }
4877 CSSValue*
4878 nsComputedDOMStyle::DoGetStroke()
4879 {
4880 return GetSVGPaintFor(false);
4881 }
4883 CSSValue*
4884 nsComputedDOMStyle::DoGetMarkerEnd()
4885 {
4886 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4888 const nsStyleSVG* svg = StyleSVG();
4890 if (svg->mMarkerEnd)
4891 val->SetURI(svg->mMarkerEnd);
4892 else
4893 val->SetIdent(eCSSKeyword_none);
4895 return val;
4896 }
4898 CSSValue*
4899 nsComputedDOMStyle::DoGetMarkerMid()
4900 {
4901 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4903 const nsStyleSVG* svg = StyleSVG();
4905 if (svg->mMarkerMid)
4906 val->SetURI(svg->mMarkerMid);
4907 else
4908 val->SetIdent(eCSSKeyword_none);
4910 return val;
4911 }
4913 CSSValue*
4914 nsComputedDOMStyle::DoGetMarkerStart()
4915 {
4916 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4918 const nsStyleSVG* svg = StyleSVG();
4920 if (svg->mMarkerStart)
4921 val->SetURI(svg->mMarkerStart);
4922 else
4923 val->SetIdent(eCSSKeyword_none);
4925 return val;
4926 }
4928 CSSValue*
4929 nsComputedDOMStyle::DoGetStrokeDasharray()
4930 {
4931 const nsStyleSVG* svg = StyleSVG();
4933 if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) {
4934 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4935 val->SetIdent(eCSSKeyword_none);
4936 return val;
4937 }
4939 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
4941 for (uint32_t i = 0; i < svg->mStrokeDasharrayLength; i++) {
4942 nsROCSSPrimitiveValue* dash = new nsROCSSPrimitiveValue;
4943 valueList->AppendCSSValue(dash);
4945 SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
4946 }
4948 return valueList;
4949 }
4951 CSSValue*
4952 nsComputedDOMStyle::DoGetStrokeDashoffset()
4953 {
4954 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4955 SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
4956 return val;
4957 }
4959 CSSValue*
4960 nsComputedDOMStyle::DoGetStrokeWidth()
4961 {
4962 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4963 SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
4964 return val;
4965 }
4967 CSSValue*
4968 nsComputedDOMStyle::DoGetVectorEffect()
4969 {
4970 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4971 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect,
4972 nsCSSProps::kVectorEffectKTable));
4973 return val;
4974 }
4976 CSSValue*
4977 nsComputedDOMStyle::DoGetFillOpacity()
4978 {
4979 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4980 val->SetNumber(StyleSVG()->mFillOpacity);
4981 return val;
4982 }
4984 CSSValue*
4985 nsComputedDOMStyle::DoGetFloodOpacity()
4986 {
4987 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4988 val->SetNumber(StyleSVGReset()->mFloodOpacity);
4989 return val;
4990 }
4992 CSSValue*
4993 nsComputedDOMStyle::DoGetStopOpacity()
4994 {
4995 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4996 val->SetNumber(StyleSVGReset()->mStopOpacity);
4997 return val;
4998 }
5000 CSSValue*
5001 nsComputedDOMStyle::DoGetStrokeMiterlimit()
5002 {
5003 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5004 val->SetNumber(StyleSVG()->mStrokeMiterlimit);
5005 return val;
5006 }
5008 CSSValue*
5009 nsComputedDOMStyle::DoGetStrokeOpacity()
5010 {
5011 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5012 val->SetNumber(StyleSVG()->mStrokeOpacity);
5013 return val;
5014 }
5016 CSSValue*
5017 nsComputedDOMStyle::DoGetClipRule()
5018 {
5019 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5020 val->SetIdent(nsCSSProps::ValueToKeywordEnum(
5021 StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
5022 return val;
5023 }
5025 CSSValue*
5026 nsComputedDOMStyle::DoGetFillRule()
5027 {
5028 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5029 val->SetIdent(nsCSSProps::ValueToKeywordEnum(
5030 StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
5031 return val;
5032 }
5034 CSSValue*
5035 nsComputedDOMStyle::DoGetStrokeLinecap()
5036 {
5037 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5038 val->SetIdent(
5039 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap,
5040 nsCSSProps::kStrokeLinecapKTable));
5041 return val;
5042 }
5044 CSSValue*
5045 nsComputedDOMStyle::DoGetStrokeLinejoin()
5046 {
5047 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5048 val->SetIdent(
5049 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin,
5050 nsCSSProps::kStrokeLinejoinKTable));
5051 return val;
5052 }
5054 CSSValue*
5055 nsComputedDOMStyle::DoGetTextAnchor()
5056 {
5057 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5058 val->SetIdent(
5059 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor,
5060 nsCSSProps::kTextAnchorKTable));
5061 return val;
5062 }
5064 CSSValue*
5065 nsComputedDOMStyle::DoGetColorInterpolation()
5066 {
5067 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5068 val->SetIdent(
5069 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation,
5070 nsCSSProps::kColorInterpolationKTable));
5071 return val;
5072 }
5074 CSSValue*
5075 nsComputedDOMStyle::DoGetColorInterpolationFilters()
5076 {
5077 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5078 val->SetIdent(
5079 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters,
5080 nsCSSProps::kColorInterpolationKTable));
5081 return val;
5082 }
5084 CSSValue*
5085 nsComputedDOMStyle::DoGetDominantBaseline()
5086 {
5087 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5088 val->SetIdent(
5089 nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline,
5090 nsCSSProps::kDominantBaselineKTable));
5091 return val;
5092 }
5094 CSSValue*
5095 nsComputedDOMStyle::DoGetImageRendering()
5096 {
5097 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5098 val->SetIdent(
5099 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mImageRendering,
5100 nsCSSProps::kImageRenderingKTable));
5101 return val;
5102 }
5104 CSSValue*
5105 nsComputedDOMStyle::DoGetShapeRendering()
5106 {
5107 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5108 val->SetIdent(
5109 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering,
5110 nsCSSProps::kShapeRenderingKTable));
5111 return val;
5112 }
5114 CSSValue*
5115 nsComputedDOMStyle::DoGetTextRendering()
5116 {
5117 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5118 val->SetIdent(
5119 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextRendering,
5120 nsCSSProps::kTextRenderingKTable));
5121 return val;
5122 }
5124 CSSValue*
5125 nsComputedDOMStyle::DoGetFloodColor()
5126 {
5127 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5128 SetToRGBAColor(val, StyleSVGReset()->mFloodColor);
5129 return val;
5130 }
5132 CSSValue*
5133 nsComputedDOMStyle::DoGetLightingColor()
5134 {
5135 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5136 SetToRGBAColor(val, StyleSVGReset()->mLightingColor);
5137 return val;
5138 }
5140 CSSValue*
5141 nsComputedDOMStyle::DoGetStopColor()
5142 {
5143 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5144 SetToRGBAColor(val, StyleSVGReset()->mStopColor);
5145 return val;
5146 }
5148 CSSValue*
5149 nsComputedDOMStyle::DoGetClipPath()
5150 {
5151 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5153 const nsStyleSVGReset* svg = StyleSVGReset();
5155 if (svg->mClipPath)
5156 val->SetURI(svg->mClipPath);
5157 else
5158 val->SetIdent(eCSSKeyword_none);
5160 return val;
5161 }
5163 void
5164 nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
5165 const nsStyleCoord& aCoord)
5166 {
5167 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
5168 bool clampNegativeCalc = true;
5169 SetValueToCoord(value, aCoord, clampNegativeCalc);
5170 value->GetCssText(aCssText);
5171 delete value;
5172 }
5174 CSSValue*
5175 nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
5176 const nsStyleFilter& aStyleFilter)
5177 {
5178 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
5179 // Handle url().
5180 if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
5181 value->SetURI(aStyleFilter.GetURL());
5182 return value;
5183 }
5185 // Filter function name and opening parenthesis.
5186 nsAutoString filterFunctionString;
5187 AppendASCIItoUTF16(
5188 nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
5189 nsCSSProps::kFilterFunctionKTable),
5190 filterFunctionString);
5191 filterFunctionString.AppendLiteral("(");
5193 nsAutoString argumentString;
5194 if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
5195 // Handle drop-shadow()
5196 nsRefPtr<CSSValue> shadowValue =
5197 GetCSSShadowArray(aStyleFilter.GetDropShadow(),
5198 StyleColor()->mColor,
5199 false);
5200 ErrorResult dummy;
5201 shadowValue->GetCssText(argumentString, dummy);
5202 } else {
5203 // Filter function argument.
5204 SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter());
5205 }
5206 filterFunctionString.Append(argumentString);
5208 // Filter function closing parenthesis.
5209 filterFunctionString.AppendLiteral(")");
5211 value->SetString(filterFunctionString);
5212 return value;
5213 }
5215 CSSValue*
5216 nsComputedDOMStyle::DoGetFilter()
5217 {
5218 const nsTArray<nsStyleFilter>& filters = StyleSVGReset()->mFilters;
5220 if (filters.IsEmpty()) {
5221 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
5222 value->SetIdent(eCSSKeyword_none);
5223 return value;
5224 }
5226 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
5227 for(uint32_t i = 0; i < filters.Length(); i++) {
5228 CSSValue* value = CreatePrimitiveValueForStyleFilter(filters[i]);
5229 valueList->AppendCSSValue(value);
5230 }
5231 return valueList;
5232 }
5234 CSSValue*
5235 nsComputedDOMStyle::DoGetMask()
5236 {
5237 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5239 const nsStyleSVGReset* svg = StyleSVGReset();
5241 if (svg->mMask)
5242 val->SetURI(svg->mMask);
5243 else
5244 val->SetIdent(eCSSKeyword_none);
5246 return val;
5247 }
5249 CSSValue*
5250 nsComputedDOMStyle::DoGetMaskType()
5251 {
5252 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5253 val->SetIdent(
5254 nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType,
5255 nsCSSProps::kMaskTypeKTable));
5256 return val;
5257 }
5259 CSSValue*
5260 nsComputedDOMStyle::DoGetPaintOrder()
5261 {
5262 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5263 nsAutoString string;
5264 uint8_t paintOrder = StyleSVG()->mPaintOrder;
5265 nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
5266 val->SetString(string);
5267 return val;
5268 }
5270 CSSValue*
5271 nsComputedDOMStyle::DoGetTransitionDelay()
5272 {
5273 const nsStyleDisplay* display = StyleDisplay();
5275 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5277 NS_ABORT_IF_FALSE(display->mTransitionDelayCount > 0,
5278 "first item must be explicit");
5279 uint32_t i = 0;
5280 do {
5281 const nsTransition *transition = &display->mTransitions[i];
5282 nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
5283 valueList->AppendCSSValue(delay);
5284 delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
5285 } while (++i < display->mTransitionDelayCount);
5287 return valueList;
5288 }
5290 CSSValue*
5291 nsComputedDOMStyle::DoGetTransitionDuration()
5292 {
5293 const nsStyleDisplay* display = StyleDisplay();
5295 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5297 NS_ABORT_IF_FALSE(display->mTransitionDurationCount > 0,
5298 "first item must be explicit");
5299 uint32_t i = 0;
5300 do {
5301 const nsTransition *transition = &display->mTransitions[i];
5302 nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
5303 valueList->AppendCSSValue(duration);
5305 duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
5306 } while (++i < display->mTransitionDurationCount);
5308 return valueList;
5309 }
5311 CSSValue*
5312 nsComputedDOMStyle::DoGetTransitionProperty()
5313 {
5314 const nsStyleDisplay* display = StyleDisplay();
5316 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5318 NS_ABORT_IF_FALSE(display->mTransitionPropertyCount > 0,
5319 "first item must be explicit");
5320 uint32_t i = 0;
5321 do {
5322 const nsTransition *transition = &display->mTransitions[i];
5323 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
5324 valueList->AppendCSSValue(property);
5325 nsCSSProperty cssprop = transition->GetProperty();
5326 if (cssprop == eCSSPropertyExtra_all_properties)
5327 property->SetIdent(eCSSKeyword_all);
5328 else if (cssprop == eCSSPropertyExtra_no_properties)
5329 property->SetIdent(eCSSKeyword_none);
5330 else if (cssprop == eCSSProperty_UNKNOWN)
5331 {
5332 nsAutoString escaped;
5333 nsStyleUtil::AppendEscapedCSSIdent(
5334 nsDependentAtomString(transition->GetUnknownProperty()), escaped);
5335 property->SetString(escaped); // really want SetIdent
5336 }
5337 else
5338 property->SetString(nsCSSProps::GetStringValue(cssprop));
5339 } while (++i < display->mTransitionPropertyCount);
5341 return valueList;
5342 }
5344 void
5345 nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
5346 const nsTimingFunction& aTimingFunction)
5347 {
5348 nsROCSSPrimitiveValue* timingFunction = new nsROCSSPrimitiveValue;
5349 aValueList->AppendCSSValue(timingFunction);
5351 nsAutoString tmp;
5353 if (aTimingFunction.mType == nsTimingFunction::Function) {
5354 // set the value from the cubic-bezier control points
5355 // (We could try to regenerate the keywords if we want.)
5356 tmp.AppendLiteral("cubic-bezier(");
5357 tmp.AppendFloat(aTimingFunction.mFunc.mX1);
5358 tmp.AppendLiteral(", ");
5359 tmp.AppendFloat(aTimingFunction.mFunc.mY1);
5360 tmp.AppendLiteral(", ");
5361 tmp.AppendFloat(aTimingFunction.mFunc.mX2);
5362 tmp.AppendLiteral(", ");
5363 tmp.AppendFloat(aTimingFunction.mFunc.mY2);
5364 tmp.AppendLiteral(")");
5365 } else {
5366 tmp.AppendLiteral("steps(");
5367 tmp.AppendInt(aTimingFunction.mSteps);
5368 if (aTimingFunction.mType == nsTimingFunction::StepStart) {
5369 tmp.AppendLiteral(", start)");
5370 } else {
5371 tmp.AppendLiteral(", end)");
5372 }
5373 }
5374 timingFunction->SetString(tmp);
5375 }
5377 CSSValue*
5378 nsComputedDOMStyle::DoGetTransitionTimingFunction()
5379 {
5380 const nsStyleDisplay* display = StyleDisplay();
5382 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5384 NS_ABORT_IF_FALSE(display->mTransitionTimingFunctionCount > 0,
5385 "first item must be explicit");
5386 uint32_t i = 0;
5387 do {
5388 AppendTimingFunction(valueList,
5389 display->mTransitions[i].GetTimingFunction());
5390 } while (++i < display->mTransitionTimingFunctionCount);
5392 return valueList;
5393 }
5395 CSSValue*
5396 nsComputedDOMStyle::DoGetAnimationName()
5397 {
5398 const nsStyleDisplay* display = StyleDisplay();
5400 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5402 NS_ABORT_IF_FALSE(display->mAnimationNameCount > 0,
5403 "first item must be explicit");
5404 uint32_t i = 0;
5405 do {
5406 const nsAnimation *animation = &display->mAnimations[i];
5407 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
5408 valueList->AppendCSSValue(property);
5410 const nsString& name = animation->GetName();
5411 if (name.IsEmpty()) {
5412 property->SetIdent(eCSSKeyword_none);
5413 } else {
5414 nsAutoString escaped;
5415 nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
5416 property->SetString(escaped); // really want SetIdent
5417 }
5418 } while (++i < display->mAnimationNameCount);
5420 return valueList;
5421 }
5423 CSSValue*
5424 nsComputedDOMStyle::DoGetAnimationDelay()
5425 {
5426 const nsStyleDisplay* display = StyleDisplay();
5428 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5430 NS_ABORT_IF_FALSE(display->mAnimationDelayCount > 0,
5431 "first item must be explicit");
5432 uint32_t i = 0;
5433 do {
5434 const nsAnimation *animation = &display->mAnimations[i];
5435 nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
5436 valueList->AppendCSSValue(delay);
5437 delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
5438 } while (++i < display->mAnimationDelayCount);
5440 return valueList;
5441 }
5443 CSSValue*
5444 nsComputedDOMStyle::DoGetAnimationDuration()
5445 {
5446 const nsStyleDisplay* display = StyleDisplay();
5448 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5450 NS_ABORT_IF_FALSE(display->mAnimationDurationCount > 0,
5451 "first item must be explicit");
5452 uint32_t i = 0;
5453 do {
5454 const nsAnimation *animation = &display->mAnimations[i];
5455 nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
5456 valueList->AppendCSSValue(duration);
5458 duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
5459 } while (++i < display->mAnimationDurationCount);
5461 return valueList;
5462 }
5464 CSSValue*
5465 nsComputedDOMStyle::DoGetAnimationTimingFunction()
5466 {
5467 const nsStyleDisplay* display = StyleDisplay();
5469 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5471 NS_ABORT_IF_FALSE(display->mAnimationTimingFunctionCount > 0,
5472 "first item must be explicit");
5473 uint32_t i = 0;
5474 do {
5475 AppendTimingFunction(valueList,
5476 display->mAnimations[i].GetTimingFunction());
5477 } while (++i < display->mAnimationTimingFunctionCount);
5479 return valueList;
5480 }
5482 CSSValue*
5483 nsComputedDOMStyle::DoGetAnimationDirection()
5484 {
5485 const nsStyleDisplay* display = StyleDisplay();
5487 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5489 NS_ABORT_IF_FALSE(display->mAnimationDirectionCount > 0,
5490 "first item must be explicit");
5491 uint32_t i = 0;
5492 do {
5493 const nsAnimation *animation = &display->mAnimations[i];
5494 nsROCSSPrimitiveValue* direction = new nsROCSSPrimitiveValue;
5495 valueList->AppendCSSValue(direction);
5496 direction->SetIdent(
5497 nsCSSProps::ValueToKeywordEnum(animation->GetDirection(),
5498 nsCSSProps::kAnimationDirectionKTable));
5499 } while (++i < display->mAnimationDirectionCount);
5501 return valueList;
5502 }
5504 CSSValue*
5505 nsComputedDOMStyle::DoGetAnimationFillMode()
5506 {
5507 const nsStyleDisplay* display = StyleDisplay();
5509 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5511 NS_ABORT_IF_FALSE(display->mAnimationFillModeCount > 0,
5512 "first item must be explicit");
5513 uint32_t i = 0;
5514 do {
5515 const nsAnimation *animation = &display->mAnimations[i];
5516 nsROCSSPrimitiveValue* fillMode = new nsROCSSPrimitiveValue;
5517 valueList->AppendCSSValue(fillMode);
5518 fillMode->SetIdent(
5519 nsCSSProps::ValueToKeywordEnum(animation->GetFillMode(),
5520 nsCSSProps::kAnimationFillModeKTable));
5521 } while (++i < display->mAnimationFillModeCount);
5523 return valueList;
5524 }
5526 CSSValue*
5527 nsComputedDOMStyle::DoGetAnimationIterationCount()
5528 {
5529 const nsStyleDisplay* display = StyleDisplay();
5531 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5533 NS_ABORT_IF_FALSE(display->mAnimationIterationCountCount > 0,
5534 "first item must be explicit");
5535 uint32_t i = 0;
5536 do {
5537 const nsAnimation *animation = &display->mAnimations[i];
5538 nsROCSSPrimitiveValue* iterationCount = new nsROCSSPrimitiveValue;
5539 valueList->AppendCSSValue(iterationCount);
5541 float f = animation->GetIterationCount();
5542 /* Need a nasty hack here to work around an optimizer bug in gcc
5543 4.2 on Mac, which somehow gets confused when directly comparing
5544 a float to the return value of NS_IEEEPositiveInfinity when
5545 building 32-bit builds. */
5546 #ifdef XP_MACOSX
5547 volatile
5548 #endif
5549 float inf = NS_IEEEPositiveInfinity();
5550 if (f == inf) {
5551 iterationCount->SetIdent(eCSSKeyword_infinite);
5552 } else {
5553 iterationCount->SetNumber(f);
5554 }
5555 } while (++i < display->mAnimationIterationCountCount);
5557 return valueList;
5558 }
5560 CSSValue*
5561 nsComputedDOMStyle::DoGetAnimationPlayState()
5562 {
5563 const nsStyleDisplay* display = StyleDisplay();
5565 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5567 NS_ABORT_IF_FALSE(display->mAnimationPlayStateCount > 0,
5568 "first item must be explicit");
5569 uint32_t i = 0;
5570 do {
5571 const nsAnimation *animation = &display->mAnimations[i];
5572 nsROCSSPrimitiveValue* playState = new nsROCSSPrimitiveValue;
5573 valueList->AppendCSSValue(playState);
5574 playState->SetIdent(
5575 nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
5576 nsCSSProps::kAnimationPlayStateKTable));
5577 } while (++i < display->mAnimationPlayStateCount);
5579 return valueList;
5580 }
5582 static void
5583 MarkComputedStyleMapDirty(const char* aPref, void* aData)
5584 {
5585 static_cast<nsComputedStyleMap*>(aData)->MarkDirty();
5586 }
5588 CSSValue*
5589 nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
5590 {
5591 MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
5593 const nsStyleVariables* variables = StyleVariables();
5595 nsString variableValue;
5596 const nsAString& name = Substring(aPropertyName,
5597 CSS_CUSTOM_NAME_PREFIX_LENGTH);
5598 if (!variables->mVariables.Get(name, variableValue)) {
5599 return nullptr;
5600 }
5602 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5603 val->SetString(variableValue);
5605 return val;
5606 }
5608 /* static */ nsComputedStyleMap*
5609 nsComputedDOMStyle::GetComputedStyleMap()
5610 {
5611 static nsComputedStyleMap map = {
5612 {
5613 #define COMPUTED_STYLE_PROP(prop_, method_) \
5614 { eCSSProperty_##prop_, &nsComputedDOMStyle::DoGet##method_ },
5615 #include "nsComputedDOMStylePropertyList.h"
5616 #undef COMPUTED_STYLE_PROP
5617 }
5618 };
5619 return ↦
5620 }
5622 /* static */ void
5623 nsComputedDOMStyle::RegisterPrefChangeCallbacks()
5624 {
5625 // Note that this will register callbacks for all properties with prefs, not
5626 // just those that are implemented on computed style objects, as it's not
5627 // easy to grab specific property data from nsCSSPropList.h based on the
5628 // entries iterated in nsComputedDOMStylePropertyList.h.
5629 nsComputedStyleMap* data = GetComputedStyleMap();
5630 #define REGISTER_CALLBACK(pref_) \
5631 if (pref_[0]) { \
5632 Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data); \
5633 }
5634 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
5635 kwtable_, stylestruct_, stylestructoffset_, animtype_) \
5636 REGISTER_CALLBACK(pref_)
5637 #include "nsCSSPropList.h"
5638 #undef CSS_PROP
5639 #undef REGISTER_CALLBACK
5640 }
5642 /* static */ void
5643 nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
5644 {
5645 nsComputedStyleMap* data = GetComputedStyleMap();
5646 #define UNREGISTER_CALLBACK(pref_) \
5647 if (pref_[0]) { \
5648 Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data); \
5649 }
5650 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
5651 kwtable_, stylestruct_, stylestructoffset_, animtype_) \
5652 UNREGISTER_CALLBACK(pref_)
5653 #include "nsCSSPropList.h"
5654 #undef CSS_PROP
5655 #undef UNREGISTER_CALLBACK
5656 }