michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set tw=78 expandtab softtabstop=2 ts=2 sw=2: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* DOM object returned from element.getComputedStyle() */ michael@0: michael@0: #include "nsComputedDOMStyle.h" michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include "nsError.h" michael@0: #include "nsDOMString.h" michael@0: #include "nsIDOMCSSPrimitiveValue.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsIContent.h" michael@0: michael@0: #include "nsDOMCSSRect.h" michael@0: #include "nsDOMCSSRGBColor.h" michael@0: #include "nsDOMCSSValueList.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsHTMLReflowState.h" michael@0: #include "nsStyleUtil.h" michael@0: #include "nsStyleStructInlines.h" michael@0: #include "nsROCSSPrimitiveValue.h" michael@0: michael@0: #include "nsPresContext.h" michael@0: #include "nsIDocument.h" michael@0: michael@0: #include "nsCSSPseudoElements.h" michael@0: #include "nsStyleSet.h" michael@0: #include "imgIRequest.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsCSSKeywords.h" michael@0: #include "nsStyleCoord.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsDOMCSSDeclaration.h" michael@0: #include "nsStyleTransformMatrix.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "prtime.h" michael@0: #include "nsWrapperCacheInlines.h" michael@0: #include "mozilla/AppUnits.h" michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon) michael@0: #define DEBUG_ComputedDOMStyle michael@0: #endif michael@0: michael@0: /* michael@0: * This is the implementation of the readonly CSSStyleDeclaration that is michael@0: * returned by the getComputedStyle() function. michael@0: */ michael@0: michael@0: static nsComputedDOMStyle *sCachedComputedDOMStyle; michael@0: michael@0: already_AddRefed michael@0: NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt, michael@0: nsIPresShell* aPresShell, michael@0: nsComputedDOMStyle::StyleType aStyleType) michael@0: { michael@0: nsRefPtr computedStyle; michael@0: if (sCachedComputedDOMStyle) { michael@0: // There's an unused nsComputedDOMStyle cached, use it. michael@0: // But before we use it, re-initialize the object. michael@0: michael@0: // Oh yeah baby, placement new! michael@0: computedStyle = new (sCachedComputedDOMStyle) michael@0: nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, aStyleType); michael@0: michael@0: sCachedComputedDOMStyle = nullptr; michael@0: } else { michael@0: // No nsComputedDOMStyle cached, create a new one. michael@0: michael@0: computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, michael@0: aStyleType); michael@0: } michael@0: michael@0: return computedStyle.forget(); michael@0: } michael@0: michael@0: /** michael@0: * An object that represents the ordered set of properties that are exposed on michael@0: * an nsComputedDOMStyle object and how their computed values can be obtained. michael@0: */ michael@0: struct nsComputedStyleMap michael@0: { michael@0: friend class nsComputedDOMStyle; michael@0: michael@0: struct Entry michael@0: { michael@0: // Create a pointer-to-member-function type. michael@0: typedef mozilla::dom::CSSValue* (nsComputedDOMStyle::*ComputeMethod)(); michael@0: michael@0: nsCSSProperty mProperty; michael@0: ComputeMethod mGetter; michael@0: michael@0: bool IsLayoutFlushNeeded() const michael@0: { michael@0: return nsCSSProps::PropHasFlags(mProperty, michael@0: CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH); michael@0: } michael@0: michael@0: bool IsEnabled() const michael@0: { michael@0: return nsCSSProps::IsEnabled(mProperty); michael@0: } michael@0: }; michael@0: michael@0: // We define this enum just to count the total number of properties that can michael@0: // be exposed on an nsComputedDOMStyle, including properties that may be michael@0: // disabled. michael@0: enum { michael@0: #define COMPUTED_STYLE_PROP(prop_, method_) \ michael@0: eComputedStyleProperty_##prop_, michael@0: #include "nsComputedDOMStylePropertyList.h" michael@0: #undef COMPUTED_STYLE_PROP michael@0: eComputedStyleProperty_COUNT michael@0: }; michael@0: michael@0: /** michael@0: * Returns the number of properties that should be exposed on an michael@0: * nsComputedDOMStyle, ecxluding any disabled properties. michael@0: */ michael@0: uint32_t Length() michael@0: { michael@0: Update(); michael@0: return mExposedPropertyCount; michael@0: } michael@0: michael@0: /** michael@0: * Returns the property at the given index in the list of properties michael@0: * that should be exposed on an nsComputedDOMStyle, excluding any michael@0: * disabled properties. michael@0: */ michael@0: nsCSSProperty PropertyAt(uint32_t aIndex) michael@0: { michael@0: Update(); michael@0: return kEntries[EntryIndex(aIndex)].mProperty; michael@0: } michael@0: michael@0: /** michael@0: * Searches for and returns the computed style map entry for the given michael@0: * property, or nullptr if the property is not exposed on nsComputedDOMStyle michael@0: * or is currently disabled. michael@0: */ michael@0: const Entry* FindEntryForProperty(nsCSSProperty aPropID) michael@0: { michael@0: Update(); michael@0: for (uint32_t i = 0; i < mExposedPropertyCount; i++) { michael@0: const Entry* entry = &kEntries[EntryIndex(i)]; michael@0: if (entry->mProperty == aPropID) { michael@0: return entry; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: /** michael@0: * Records that mIndexMap needs updating, due to prefs changing that could michael@0: * affect the set of properties exposed on an nsComputedDOMStyle. michael@0: */ michael@0: void MarkDirty() { mExposedPropertyCount = 0; } michael@0: michael@0: // The member variables are public so that we can use an initializer in michael@0: // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions michael@0: // above to get information from this object. michael@0: michael@0: /** michael@0: * An entry for each property that can be exposed on an nsComputedDOMStyle. michael@0: */ michael@0: const Entry kEntries[eComputedStyleProperty_COUNT]; michael@0: michael@0: /** michael@0: * The number of properties that should be exposed on an nsComputedDOMStyle. michael@0: * This will be less than eComputedStyleProperty_COUNT if some property michael@0: * prefs are disabled. A value of 0 indicates that it and mIndexMap are out michael@0: * of date. michael@0: */ michael@0: uint32_t mExposedPropertyCount; michael@0: michael@0: /** michael@0: * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries. michael@0: */ michael@0: uint32_t mIndexMap[eComputedStyleProperty_COUNT]; michael@0: michael@0: private: michael@0: /** michael@0: * Returns whether mExposedPropertyCount and mIndexMap are out of date. michael@0: */ michael@0: bool IsDirty() { return mExposedPropertyCount == 0; } michael@0: michael@0: /** michael@0: * Updates mExposedPropertyCount and mIndexMap to take into account properties michael@0: * whose prefs are currently disabled. michael@0: */ michael@0: void Update(); michael@0: michael@0: /** michael@0: * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries. michael@0: */ michael@0: uint32_t EntryIndex(uint32_t aIndex) const michael@0: { michael@0: MOZ_ASSERT(aIndex < mExposedPropertyCount); michael@0: return mIndexMap[aIndex]; michael@0: } michael@0: }; michael@0: michael@0: void michael@0: nsComputedStyleMap::Update() michael@0: { michael@0: if (!IsDirty()) { michael@0: return; michael@0: } michael@0: michael@0: uint32_t index = 0; michael@0: for (uint32_t i = 0; i < eComputedStyleProperty_COUNT; i++) { michael@0: if (kEntries[i].IsEnabled()) { michael@0: mIndexMap[index++] = i; michael@0: } michael@0: } michael@0: mExposedPropertyCount = index; michael@0: } michael@0: michael@0: nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement, michael@0: const nsAString& aPseudoElt, michael@0: nsIPresShell* aPresShell, michael@0: StyleType aStyleType) michael@0: : mDocumentWeak(nullptr), mOuterFrame(nullptr), michael@0: mInnerFrame(nullptr), mPresShell(nullptr), michael@0: mStyleType(aStyleType), michael@0: mExposeVisitedStyle(false) michael@0: { michael@0: MOZ_ASSERT(aElement && aPresShell); michael@0: michael@0: mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument()); michael@0: michael@0: mContent = aElement; michael@0: michael@0: if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() && michael@0: aPseudoElt.First() == char16_t(':')) { michael@0: // deal with two-colon forms of aPseudoElt michael@0: nsAString::const_iterator start, end; michael@0: aPseudoElt.BeginReading(start); michael@0: aPseudoElt.EndReading(end); michael@0: NS_ASSERTION(start != end, "aPseudoElt is not empty!"); michael@0: ++start; michael@0: bool haveTwoColons = true; michael@0: if (start == end || *start != char16_t(':')) { michael@0: --start; michael@0: haveTwoColons = false; michael@0: } michael@0: mPseudo = do_GetAtom(Substring(start, end)); michael@0: MOZ_ASSERT(mPseudo); michael@0: michael@0: // There aren't any non-CSS2 pseudo-elements with a single ':' michael@0: if (!haveTwoColons && michael@0: (!nsCSSPseudoElements::IsPseudoElement(mPseudo) || michael@0: !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo))) { michael@0: // XXXbz I'd really rather we threw an exception or something, but michael@0: // the DOM spec sucks. michael@0: mPseudo = nullptr; michael@0: } michael@0: } michael@0: michael@0: MOZ_ASSERT(aPresShell->GetPresContext()); michael@0: } michael@0: michael@0: michael@0: nsComputedDOMStyle::~nsComputedDOMStyle() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::Shutdown() michael@0: { michael@0: // We want to de-allocate without calling the dtor since we michael@0: // already did that manually in doDestroyComputedDOMStyle(), michael@0: // so cast our cached object to something that doesn't know michael@0: // about our dtor. michael@0: delete reinterpret_cast(sCachedComputedDOMStyle); michael@0: sCachedComputedDOMStyle = nullptr; michael@0: } michael@0: michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsComputedDOMStyle, mContent) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle) michael@0: return tmp->IsBlack(); michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle) michael@0: return tmp->IsBlack(); michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle) michael@0: return tmp->IsBlack(); michael@0: NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END michael@0: michael@0: // QueryInterface implementation for nsComputedDOMStyle michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration) michael@0: michael@0: michael@0: static void doDestroyComputedDOMStyle(nsComputedDOMStyle *aComputedStyle) michael@0: { michael@0: if (!sCachedComputedDOMStyle) { michael@0: // The cache is empty, store aComputedStyle in the cache. michael@0: michael@0: sCachedComputedDOMStyle = aComputedStyle; michael@0: sCachedComputedDOMStyle->~nsComputedDOMStyle(); michael@0: } else { michael@0: // The cache is full, delete aComputedStyle michael@0: michael@0: delete aComputedStyle; michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsComputedDOMStyle, michael@0: doDestroyComputedDOMStyle(this)) michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetPropertyValue(const nsCSSProperty aPropID, michael@0: nsAString& aValue) michael@0: { michael@0: // This is mostly to avoid code duplication with GetPropertyCSSValue(); if michael@0: // perf ever becomes an issue here (doubtful), we can look into changing michael@0: // this. michael@0: return GetPropertyValue( michael@0: NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)), michael@0: aValue); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::SetPropertyValue(const nsCSSProperty aPropID, michael@0: const nsAString& aValue) michael@0: { michael@0: return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetCssText(nsAString& aCssText) michael@0: { michael@0: aCssText.Truncate(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::SetCssText(const nsAString& aCssText) michael@0: { michael@0: return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetLength(uint32_t* aLength) michael@0: { michael@0: NS_PRECONDITION(aLength, "Null aLength! Prepare to die!"); michael@0: michael@0: uint32_t length = GetComputedStyleMap()->Length(); michael@0: michael@0: // Make sure we have up to date style so that we can include custom michael@0: // properties. michael@0: UpdateCurrentStyleSources(false); michael@0: if (mStyleContextHolder) { michael@0: length += StyleVariables()->mVariables.Count(); michael@0: } michael@0: michael@0: *aLength = length; michael@0: michael@0: ClearCurrentStyleSources(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule) michael@0: { michael@0: *aParentRule = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName, michael@0: nsAString& aReturn) michael@0: { michael@0: aReturn.Truncate(); michael@0: michael@0: ErrorResult error; michael@0: nsRefPtr val = GetPropertyCSSValue(aPropertyName, error); michael@0: if (error.Failed()) { michael@0: return error.ErrorCode(); michael@0: } michael@0: michael@0: if (val) { michael@0: nsString text; michael@0: val->GetCssText(text, error); michael@0: aReturn.Assign(text); michael@0: return error.ErrorCode(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetAuthoredPropertyValue(const nsAString& aPropertyName, michael@0: nsAString& aReturn) michael@0: { michael@0: // Authored style doesn't make sense to return from computed DOM style, michael@0: // so just return whatever GetPropertyValue() returns. michael@0: return GetPropertyValue(aPropertyName, aReturn); michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: nsComputedDOMStyle::GetStyleContextForElement(Element* aElement, michael@0: nsIAtom* aPseudo, michael@0: nsIPresShell* aPresShell, michael@0: StyleType aStyleType) michael@0: { michael@0: // If the content has a pres shell, we must use it. Otherwise we'd michael@0: // potentially mix rule trees by using the wrong pres shell's style michael@0: // set. Using the pres shell from the content also means that any michael@0: // content that's actually *in* a document will get the style from the michael@0: // correct document. michael@0: nsCOMPtr presShell = GetPresShellForContent(aElement); michael@0: if (!presShell) { michael@0: presShell = aPresShell; michael@0: if (!presShell) michael@0: return nullptr; michael@0: } michael@0: michael@0: presShell->FlushPendingNotifications(Flush_Style); michael@0: michael@0: return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell, michael@0: aStyleType); michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement, michael@0: nsIAtom* aPseudo, michael@0: nsIPresShell* aPresShell, michael@0: StyleType aStyleType) michael@0: { michael@0: NS_ABORT_IF_FALSE(aElement, "NULL element"); michael@0: // If the content has a pres shell, we must use it. Otherwise we'd michael@0: // potentially mix rule trees by using the wrong pres shell's style michael@0: // set. Using the pres shell from the content also means that any michael@0: // content that's actually *in* a document will get the style from the michael@0: // correct document. michael@0: nsIPresShell *presShell = GetPresShellForContent(aElement); michael@0: if (!presShell) { michael@0: presShell = aPresShell; michael@0: if (!presShell) michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!aPseudo && aStyleType == eAll) { michael@0: nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement); michael@0: if (frame) { michael@0: nsStyleContext* result = frame->StyleContext(); michael@0: // Don't use the style context if it was influenced by michael@0: // pseudo-elements, since then it's not the primary style michael@0: // for this element. michael@0: if (!result->HasPseudoElementData()) { michael@0: // this function returns an addrefed style context michael@0: nsRefPtr ret = result; michael@0: return ret.forget(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // No frame has been created, or we have a pseudo, or we're looking michael@0: // for the default style, so resolve the style ourselves. michael@0: nsRefPtr parentContext; michael@0: nsIContent* parent = aPseudo ? aElement : aElement->GetParent(); michael@0: // Don't resolve parent context for document fragments. michael@0: if (parent && parent->IsElement()) michael@0: parentContext = GetStyleContextForElementNoFlush(parent->AsElement(), michael@0: nullptr, presShell, michael@0: aStyleType); michael@0: michael@0: nsPresContext *presContext = presShell->GetPresContext(); michael@0: if (!presContext) michael@0: return nullptr; michael@0: michael@0: nsStyleSet *styleSet = presShell->StyleSet(); michael@0: michael@0: nsRefPtr sc; michael@0: if (aPseudo) { michael@0: nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo); michael@0: if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) { michael@0: return nullptr; michael@0: } michael@0: nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement); michael@0: Element* pseudoElement = frame ? frame->GetPseudoElement(type) : nullptr; michael@0: sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext, michael@0: pseudoElement); michael@0: } else { michael@0: sc = styleSet->ResolveStyleFor(aElement, parentContext); michael@0: } michael@0: michael@0: if (aStyleType == eDefaultOnly) { michael@0: // We really only want the user and UA rules. Filter out the other ones. michael@0: nsTArray< nsCOMPtr > rules; michael@0: for (nsRuleNode* ruleNode = sc->RuleNode(); michael@0: !ruleNode->IsRoot(); michael@0: ruleNode = ruleNode->GetParent()) { michael@0: if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet || michael@0: ruleNode->GetLevel() == nsStyleSet::eUserSheet) { michael@0: rules.AppendElement(ruleNode->GetRule()); michael@0: } michael@0: } michael@0: michael@0: // We want to build a list of user/ua rules that is in order from least to michael@0: // most important, so we have to reverse the list. michael@0: // Integer division to get "stop" is purposeful here: if length is odd, we michael@0: // don't have to do anything with the middle element of the array. michael@0: for (uint32_t i = 0, length = rules.Length(), stop = length / 2; michael@0: i < stop; ++i) { michael@0: rules[i].swap(rules[length - i - 1]); michael@0: } michael@0: michael@0: sc = styleSet->ResolveStyleForRules(parentContext, rules); michael@0: } michael@0: michael@0: return sc.forget(); michael@0: } michael@0: michael@0: nsMargin michael@0: nsComputedDOMStyle::GetAdjustedValuesForBoxSizing() michael@0: { michael@0: // We want the width/height of whatever parts 'width' or 'height' controls, michael@0: // which can be different depending on the value of the 'box-sizing' property. michael@0: const nsStylePosition* stylePos = StylePosition(); michael@0: michael@0: nsMargin adjustment; michael@0: switch(stylePos->mBoxSizing) { michael@0: case NS_STYLE_BOX_SIZING_BORDER: michael@0: adjustment += mInnerFrame->GetUsedBorder(); michael@0: // fall through michael@0: michael@0: case NS_STYLE_BOX_SIZING_PADDING: michael@0: adjustment += mInnerFrame->GetUsedPadding(); michael@0: } michael@0: michael@0: return adjustment; michael@0: } michael@0: michael@0: /* static */ michael@0: nsIPresShell* michael@0: nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent) michael@0: { michael@0: nsIDocument* currentDoc = aContent->GetCurrentDoc(); michael@0: if (!currentDoc) michael@0: return nullptr; michael@0: michael@0: return currentDoc->GetShell(); michael@0: } michael@0: michael@0: // nsDOMCSSDeclaration abstract methods which should never be called michael@0: // on a nsComputedDOMStyle object, but must be defined to avoid michael@0: // compile errors. michael@0: css::Declaration* michael@0: nsComputedDOMStyle::GetCSSDeclaration(bool) michael@0: { michael@0: NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration"); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsComputedDOMStyle::SetCSSDeclaration(css::Declaration*) michael@0: { michael@0: NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsIDocument* michael@0: nsComputedDOMStyle::DocToUpdate() michael@0: { michael@0: NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate"); michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) michael@0: { michael@0: NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment"); michael@0: // Just in case NS_RUNTIMEABORT ever stops killing us for some reason michael@0: aCSSParseEnv.mPrincipal = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) michael@0: { michael@0: MOZ_ASSERT(!mStyleContextHolder); michael@0: michael@0: nsCOMPtr document = do_QueryReferent(mDocumentWeak); michael@0: if (!document) { michael@0: return; michael@0: } michael@0: michael@0: document->FlushPendingLinkUpdates(); michael@0: michael@0: // Flush _before_ getting the presshell, since that could create a new michael@0: // presshell. Also note that we want to flush the style on the document michael@0: // we're computing style in, not on the document mContent is in -- the two michael@0: // may be different. michael@0: document->FlushPendingNotifications( michael@0: aNeedsLayoutFlush ? Flush_Layout : Flush_Style); michael@0: #ifdef DEBUG michael@0: mFlushedPendingReflows = aNeedsLayoutFlush; michael@0: #endif michael@0: michael@0: mPresShell = document->GetShell(); michael@0: if (!mPresShell || !mPresShell->GetPresContext()) { michael@0: return; michael@0: } michael@0: michael@0: if (!mPseudo && mStyleType == eAll) { michael@0: mOuterFrame = mContent->GetPrimaryFrame(); michael@0: mInnerFrame = mOuterFrame; michael@0: if (mOuterFrame) { michael@0: nsIAtom* type = mOuterFrame->GetType(); michael@0: if (type == nsGkAtoms::tableOuterFrame) { michael@0: // If the frame is an outer table frame then we should get the style michael@0: // from the inner table frame. michael@0: mInnerFrame = mOuterFrame->GetFirstPrincipalChild(); michael@0: NS_ASSERTION(mInnerFrame, "Outer table must have an inner"); michael@0: NS_ASSERTION(!mInnerFrame->GetNextSibling(), michael@0: "Outer table frames should have just one child, " michael@0: "the inner table"); michael@0: } michael@0: michael@0: mStyleContextHolder = mInnerFrame->StyleContext(); michael@0: NS_ASSERTION(mStyleContextHolder, "Frame without style context?"); michael@0: } michael@0: } michael@0: michael@0: if (!mStyleContextHolder || mStyleContextHolder->HasPseudoElementData()) { michael@0: #ifdef DEBUG michael@0: if (mStyleContextHolder) { michael@0: // We want to check that going through this path because of michael@0: // HasPseudoElementData is rare, because it slows us down a good michael@0: // bit. So check that we're really inside something associated michael@0: // with a pseudo-element that contains elements. michael@0: nsStyleContext *topWithPseudoElementData = mStyleContextHolder; michael@0: while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) { michael@0: topWithPseudoElementData = topWithPseudoElementData->GetParent(); michael@0: } michael@0: nsCSSPseudoElements::Type pseudo = michael@0: topWithPseudoElementData->GetPseudoType(); michael@0: nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo); michael@0: nsAutoString assertMsg( michael@0: NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements (")); michael@0: assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String())); michael@0: assertMsg.Append(NS_LITERAL_STRING(")")); michael@0: NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo), michael@0: NS_LossyConvertUTF16toASCII(assertMsg).get()); michael@0: } michael@0: #endif michael@0: // Need to resolve a style context michael@0: mStyleContextHolder = michael@0: nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(), michael@0: mPseudo, michael@0: mPresShell, michael@0: mStyleType); michael@0: if (!mStyleContextHolder) { michael@0: return; michael@0: } michael@0: michael@0: NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(), michael@0: "should not have pseudo-element data"); michael@0: } michael@0: michael@0: // mExposeVisitedStyle is set to true only by testing APIs that michael@0: // require chrome privilege. michael@0: NS_ABORT_IF_FALSE(!mExposeVisitedStyle || michael@0: nsContentUtils::IsCallerChrome(), michael@0: "mExposeVisitedStyle set incorrectly"); michael@0: if (mExposeVisitedStyle && mStyleContextHolder->RelevantLinkVisited()) { michael@0: nsStyleContext *styleIfVisited = mStyleContextHolder->GetStyleIfVisited(); michael@0: if (styleIfVisited) { michael@0: mStyleContextHolder = styleIfVisited; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::ClearCurrentStyleSources() michael@0: { michael@0: mOuterFrame = nullptr; michael@0: mInnerFrame = nullptr; michael@0: mPresShell = nullptr; michael@0: michael@0: // Release the current style context for it should be re-resolved michael@0: // whenever a frame is not available. michael@0: mStyleContextHolder = nullptr; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv) michael@0: { michael@0: nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName, michael@0: nsCSSProps::eEnabledForAllContent); michael@0: michael@0: bool needsLayoutFlush; michael@0: nsComputedStyleMap::Entry::ComputeMethod getter; michael@0: michael@0: if (prop == eCSSPropertyExtra_variable) { michael@0: needsLayoutFlush = false; michael@0: getter = nullptr; michael@0: } else { michael@0: // We don't (for now, anyway, though it may make sense to change it michael@0: // for all aliases, including those in nsCSSPropAliasList) want michael@0: // aliases to be enumerable (via GetLength and IndexedGetter), so michael@0: // handle them here rather than adding entries to michael@0: // GetQueryablePropertyMap. michael@0: if (prop != eCSSProperty_UNKNOWN && michael@0: nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_IS_ALIAS)) { michael@0: const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(prop); michael@0: NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN, michael@0: "must have list of length 1"); michael@0: prop = subprops[0]; michael@0: } michael@0: michael@0: const nsComputedStyleMap::Entry* propEntry = michael@0: GetComputedStyleMap()->FindEntryForProperty(prop); michael@0: michael@0: if (!propEntry) { michael@0: #ifdef DEBUG_ComputedDOMStyle michael@0: NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) + michael@0: NS_LITERAL_CSTRING(" is not queryable!")).get()); michael@0: #endif michael@0: michael@0: // NOTE: For branches, we should flush here for compatibility! michael@0: return nullptr; michael@0: } michael@0: michael@0: needsLayoutFlush = propEntry->IsLayoutFlushNeeded(); michael@0: getter = propEntry->mGetter; michael@0: } michael@0: michael@0: UpdateCurrentStyleSources(needsLayoutFlush); michael@0: if (!mStyleContextHolder) { michael@0: aRv.Throw(NS_ERROR_NOT_AVAILABLE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr val; michael@0: if (prop == eCSSPropertyExtra_variable) { michael@0: val = DoGetCustomProperty(aPropertyName); michael@0: } else { michael@0: // Call our pointer-to-member-function. michael@0: val = (this->*getter)(); michael@0: } michael@0: michael@0: ClearCurrentStyleSources(); michael@0: michael@0: return val.forget(); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName, michael@0: nsAString& aReturn) michael@0: { michael@0: return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName, michael@0: nsAString& aReturn) michael@0: { michael@0: aReturn.Truncate(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName, michael@0: const nsAString& aValue, michael@0: const nsAString& aPriority) michael@0: { michael@0: return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsComputedDOMStyle::Item(uint32_t aIndex, nsAString& aReturn) michael@0: { michael@0: return nsDOMCSSDeclaration::Item(aIndex, aReturn); michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::IndexedGetter(uint32_t aIndex, bool& aFound, michael@0: nsAString& aPropName) michael@0: { michael@0: nsComputedStyleMap* map = GetComputedStyleMap(); michael@0: uint32_t length = map->Length(); michael@0: michael@0: if (aIndex < length) { michael@0: aFound = true; michael@0: CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)), michael@0: aPropName); michael@0: return; michael@0: } michael@0: michael@0: // Custom properties are exposed with indexed properties just after all michael@0: // of the built-in properties. michael@0: UpdateCurrentStyleSources(false); michael@0: if (!mStyleContextHolder) { michael@0: aFound = false; michael@0: return; michael@0: } michael@0: michael@0: const nsStyleVariables* variables = StyleVariables(); michael@0: if (aIndex - length < variables->mVariables.Count()) { michael@0: aFound = true; michael@0: variables->mVariables.GetVariableAt(aIndex - length, aPropName); michael@0: } else { michael@0: aFound = false; michael@0: } michael@0: michael@0: ClearCurrentStyleSources(); michael@0: } michael@0: michael@0: // Property getters... michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBinding() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: if (display->mBinding) { michael@0: val->SetURI(display->mBinding->GetURI()); michael@0: } else { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetClear() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType, michael@0: nsCSSProps::kClearKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFloat() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloats, michael@0: nsCSSProps::kFloatKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBottom() michael@0: { michael@0: return GetOffsetWidthFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStackSizing() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit : michael@0: eCSSKeyword_ignore); michael@0: return val; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue, michael@0: nscolor aColor) michael@0: { michael@0: if (NS_GET_A(aColor) == 0) { michael@0: aValue->SetIdent(eCSSKeyword_transparent); michael@0: return; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue *red = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *blue = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *alpha = new nsROCSSPrimitiveValue; michael@0: michael@0: uint8_t a = NS_GET_A(aColor); michael@0: nsDOMCSSRGBColor *rgbColor = michael@0: new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255); michael@0: michael@0: red->SetNumber(NS_GET_R(aColor)); michael@0: green->SetNumber(NS_GET_G(aColor)); michael@0: blue->SetNumber(NS_GET_B(aColor)); michael@0: alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a)); michael@0: michael@0: aValue->SetColor(rgbColor); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetToRGBAColor(val, StyleColor()->mColor); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOpacity() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleDisplay()->mOpacity); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnCount() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleColumn* column = StyleColumn(); michael@0: michael@0: if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: val->SetNumber(column->mColumnCount); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnWidth() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: // XXX fix the auto case. When we actually have a column frame, I think michael@0: // we should return the computed column width. michael@0: SetValueToCoord(val, StyleColumn()->mColumnWidth, true); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnGap() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleColumn* column = StyleColumn(); michael@0: if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) { michael@0: val->SetAppUnits(StyleFont()->mFont.size); michael@0: } else { michael@0: SetValueToCoord(val, StyleColumn()->mColumnGap, true); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnFill() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill, michael@0: nsCSSProps::kColumnFillKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnRuleWidth() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth()); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnRuleStyle() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle, michael@0: nsCSSProps::kBorderStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColumnRuleColor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleColumn* column = StyleColumn(); michael@0: nscolor ruleColor; michael@0: if (column->mColumnRuleColorIsForeground) { michael@0: ruleColor = StyleColor()->mColor; michael@0: } else { michael@0: ruleColor = column->mColumnRuleColor; michael@0: } michael@0: michael@0: SetToRGBAColor(val, ruleColor); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetContent() michael@0: { michael@0: const nsStyleContent *content = StyleContent(); michael@0: michael@0: if (content->ContentCount() == 0) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: if (content->ContentCount() == 1 && michael@0: content->ContentAt(0).mType == eStyleContentType_AltContent) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword__moz_alt_content); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: michael@0: const nsStyleContentData &data = content->ContentAt(i); michael@0: switch (data.mType) { michael@0: case eStyleContentType_String: michael@0: { michael@0: nsString str; michael@0: nsStyleUtil::AppendEscapedCSSString( michael@0: nsDependentString(data.mContent.mString), str); michael@0: val->SetString(str); michael@0: } michael@0: break; michael@0: case eStyleContentType_Image: michael@0: { michael@0: nsCOMPtr uri; michael@0: if (data.mContent.mImage) { michael@0: data.mContent.mImage->GetURI(getter_AddRefs(uri)); michael@0: } michael@0: val->SetURI(uri); michael@0: } michael@0: break; michael@0: case eStyleContentType_Attr: michael@0: { michael@0: nsAutoString str; michael@0: nsStyleUtil::AppendEscapedCSSIdent( michael@0: nsDependentString(data.mContent.mString), str); michael@0: val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR); michael@0: } michael@0: break; michael@0: case eStyleContentType_Counter: michael@0: case eStyleContentType_Counters: michael@0: { michael@0: /* FIXME: counters should really use an object */ michael@0: nsAutoString str; michael@0: if (data.mType == eStyleContentType_Counter) { michael@0: str.AppendLiteral("counter("); michael@0: } michael@0: else { michael@0: str.AppendLiteral("counters("); michael@0: } michael@0: // WRITE ME michael@0: nsCSSValue::Array *a = data.mContent.mCounters; michael@0: michael@0: nsStyleUtil::AppendEscapedCSSIdent( michael@0: nsDependentString(a->Item(0).GetStringBufferValue()), str); michael@0: int32_t typeItem = 1; michael@0: if (data.mType == eStyleContentType_Counters) { michael@0: typeItem = 2; michael@0: str.AppendLiteral(", "); michael@0: nsStyleUtil::AppendEscapedCSSString( michael@0: nsDependentString(a->Item(1).GetStringBufferValue()), str); michael@0: } michael@0: NS_ABORT_IF_FALSE(eCSSUnit_None != a->Item(typeItem).GetUnit(), michael@0: "'none' should be handled as enumerated value"); michael@0: int32_t type = a->Item(typeItem).GetIntValue(); michael@0: if (type != NS_STYLE_LIST_STYLE_DECIMAL) { michael@0: str.AppendLiteral(", "); michael@0: AppendASCIItoUTF16( michael@0: nsCSSProps::ValueToKeyword(type, nsCSSProps::kListStyleKTable), michael@0: str); michael@0: } michael@0: michael@0: str.Append(char16_t(')')); michael@0: val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER); michael@0: } michael@0: break; michael@0: case eStyleContentType_OpenQuote: michael@0: val->SetIdent(eCSSKeyword_open_quote); michael@0: break; michael@0: case eStyleContentType_CloseQuote: michael@0: val->SetIdent(eCSSKeyword_close_quote); michael@0: break; michael@0: case eStyleContentType_NoOpenQuote: michael@0: val->SetIdent(eCSSKeyword_no_open_quote); michael@0: break; michael@0: case eStyleContentType_NoCloseQuote: michael@0: val->SetIdent(eCSSKeyword_no_close_quote); michael@0: break; michael@0: case eStyleContentType_AltContent: michael@0: default: michael@0: NS_NOTREACHED("unexpected type"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetCounterIncrement() michael@0: { michael@0: const nsStyleContent *content = StyleContent(); michael@0: michael@0: if (content->CounterIncrementCount() == 0) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(name); michael@0: michael@0: nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(value); michael@0: michael@0: const nsStyleCounterData *data = content->GetCounterIncrementAt(i); michael@0: nsAutoString escaped; michael@0: nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped); michael@0: name->SetString(escaped); michael@0: value->SetNumber(data->mValue); // XXX This should really be integer michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: /* Convert the stored representation into a list of two values and then hand michael@0: * it back. michael@0: */ michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransformOrigin() michael@0: { michael@0: /* We need to build up a list of two values. We'll call them michael@0: * width and height. michael@0: */ michael@0: michael@0: /* Store things as a value list */ michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: /* Now, get the values. */ michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(width, display->mTransformOrigin[0], false, michael@0: &nsComputedDOMStyle::GetFrameBoundsWidthForTransform); michael@0: valueList->AppendCSSValue(width); michael@0: michael@0: nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(height, display->mTransformOrigin[1], false, michael@0: &nsComputedDOMStyle::GetFrameBoundsHeightForTransform); michael@0: valueList->AppendCSSValue(height); michael@0: michael@0: if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord || michael@0: display->mTransformOrigin[2].GetCoordValue() != 0) { michael@0: nsROCSSPrimitiveValue* depth = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(depth, display->mTransformOrigin[2], false, michael@0: nullptr); michael@0: valueList->AppendCSSValue(depth); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: /* Convert the stored representation into a list of two values and then hand michael@0: * it back. michael@0: */ michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPerspectiveOrigin() michael@0: { michael@0: /* We need to build up a list of two values. We'll call them michael@0: * width and height. michael@0: */ michael@0: michael@0: /* Store things as a value list */ michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: /* Now, get the values. */ michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(width, display->mPerspectiveOrigin[0], false, michael@0: &nsComputedDOMStyle::GetFrameBoundsWidthForTransform); michael@0: valueList->AppendCSSValue(width); michael@0: michael@0: nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(height, display->mPerspectiveOrigin[1], false, michael@0: &nsComputedDOMStyle::GetFrameBoundsHeightForTransform); michael@0: valueList->AppendCSSValue(height); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPerspective() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleDisplay()->mChildPerspective, false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackfaceVisibility() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility, michael@0: nsCSSProps::kBackfaceVisibilityKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransformStyle() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle, michael@0: nsCSSProps::kTransformStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: /* If the property is "none", hand back "none" wrapped in a value. michael@0: * Otherwise, compute the aggregate transform matrix and hands it back in a michael@0: * "matrix" wrapper. michael@0: */ michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransform() michael@0: { michael@0: /* First, get the display data. We'll need it. */ michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: /* If there are no transforms, then we should construct a single-element michael@0: * entry and hand it back. michael@0: */ michael@0: if (!display->mSpecifiedTransform) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: /* Set it to "none." */ michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: /* Otherwise, we need to compute the current value of the transform matrix, michael@0: * store it in a string, and hand it back to the caller. michael@0: */ michael@0: michael@0: /* Use the inner frame for width and height. If we fail, assume zero. michael@0: * TODO: There is no good way for us to represent the case where there's no michael@0: * frame, which is problematic. The reason is that when we have percentage michael@0: * transforms, there are a total of four stored matrix entries that influence michael@0: * the transform based on the size of the element. However, this poses a michael@0: * problem, because only two of these values can be explicitly referenced michael@0: * using the named transforms. Until a real solution is found, we'll just michael@0: * use this approach. michael@0: */ michael@0: nsRect bounds = michael@0: (mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) : michael@0: nsRect(0, 0, 0, 0)); michael@0: michael@0: bool dummy; michael@0: gfx3DMatrix matrix = michael@0: nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead, michael@0: mStyleContextHolder, michael@0: mStyleContextHolder->PresContext(), michael@0: dummy, michael@0: bounds, michael@0: float(mozilla::AppUnitsPerCSSPixel())); michael@0: michael@0: return MatrixToCSSValue(matrix); michael@0: } michael@0: michael@0: /* static */ nsROCSSPrimitiveValue* michael@0: nsComputedDOMStyle::MatrixToCSSValue(gfx3DMatrix& matrix) michael@0: { michael@0: bool is3D = !matrix.Is2D(); michael@0: michael@0: nsAutoString resultString(NS_LITERAL_STRING("matrix")); michael@0: if (is3D) { michael@0: resultString.Append(NS_LITERAL_STRING("3d")); michael@0: } michael@0: michael@0: resultString.Append(NS_LITERAL_STRING("(")); michael@0: resultString.AppendFloat(matrix._11); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._12); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: if (is3D) { michael@0: resultString.AppendFloat(matrix._13); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._14); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: } michael@0: resultString.AppendFloat(matrix._21); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._22); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: if (is3D) { michael@0: resultString.AppendFloat(matrix._23); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._24); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._31); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._32); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._33); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._34); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: } michael@0: resultString.AppendFloat(matrix._41); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._42); michael@0: if (is3D) { michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._43); michael@0: resultString.Append(NS_LITERAL_STRING(", ")); michael@0: resultString.AppendFloat(matrix._44); michael@0: } michael@0: resultString.Append(NS_LITERAL_STRING(")")); michael@0: michael@0: /* Create a value to hold our result. */ michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: val->SetString(resultString); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetCounterReset() michael@0: { michael@0: const nsStyleContent *content = StyleContent(); michael@0: michael@0: if (content->CounterResetCount() == 0) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(name); michael@0: michael@0: nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(value); michael@0: michael@0: const nsStyleCounterData *data = content->GetCounterResetAt(i); michael@0: nsAutoString escaped; michael@0: nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped); michael@0: name->SetString(escaped); michael@0: value->SetNumber(data->mValue); // XXX This should really be integer michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetQuotes() michael@0: { michael@0: const nsStyleQuotes *quotes = StyleQuotes(); michael@0: michael@0: if (quotes->QuotesCount() == 0) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: for (uint32_t i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue* openVal = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(openVal); michael@0: michael@0: nsROCSSPrimitiveValue* closeVal = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(closeVal); michael@0: michael@0: nsString s; michael@0: nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s); michael@0: openVal->SetString(s); michael@0: s.Truncate(); michael@0: nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s); michael@0: closeVal->SetString(s); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontFamily() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleFont* font = StyleFont(); michael@0: michael@0: nsCOMPtr doc = do_QueryReferent(mDocumentWeak); michael@0: NS_ASSERTION(doc, "document is required"); michael@0: nsIPresShell* presShell = doc->GetShell(); michael@0: NS_ASSERTION(presShell, "pres shell is required"); michael@0: nsPresContext *presContext = presShell->GetPresContext(); michael@0: NS_ASSERTION(presContext, "pres context is required"); michael@0: michael@0: const nsString& fontName = font->mFont.name; michael@0: if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) { michael@0: const nsFont* defaultFont = michael@0: presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID, michael@0: font->mLanguage); michael@0: michael@0: int32_t lendiff = fontName.Length() - defaultFont->name.Length(); michael@0: if (lendiff > 0) { michael@0: val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma michael@0: } else { michael@0: val->SetString(fontName); michael@0: } michael@0: } else { michael@0: val->SetString(fontName); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontSize() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: // Note: StyleFont()->mSize is the 'computed size'; michael@0: // StyleFont()->mFont.size is the 'actual size' michael@0: val->SetAppUnits(StyleFont()->mSize); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontSizeAdjust() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleFont *font = StyleFont(); michael@0: michael@0: if (font->mFont.sizeAdjust) { michael@0: val->SetNumber(font->mFont.sizeAdjust); michael@0: } else { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOSXFontSmoothing() michael@0: { michael@0: if (!nsContentUtils::IsCallerChrome()) michael@0: return nullptr; michael@0: michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing, michael@0: nsCSSProps::kFontSmoothingKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontStretch() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch, michael@0: nsCSSProps::kFontStretchKTable)); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontStyle() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style, michael@0: nsCSSProps::kFontStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontWeight() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleFont* font = StyleFont(); michael@0: michael@0: uint16_t weight = font->mFont.weight; michael@0: NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight"); michael@0: val->SetNumber(weight); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariant() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.variant, michael@0: nsCSSProps::kFontVariantKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontFeatureSettings() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleFont* font = StyleFont(); michael@0: if (font->mFont.fontFeatureSettings.IsEmpty()) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: nsAutoString result; michael@0: nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings, michael@0: result); michael@0: val->SetString(result); michael@0: } michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontKerning() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning, michael@0: nsCSSProps::kFontKerningKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontLanguageOverride() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleFont* font = StyleFont(); michael@0: if (font->mFont.languageOverride.IsEmpty()) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: nsString str; michael@0: nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str); michael@0: val->SetString(str); michael@0: } michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontSynthesis() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.synthesis; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } else { michael@0: nsAutoString valueStr; michael@0: michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis, michael@0: intValue, NS_FONT_SYNTHESIS_WEIGHT, michael@0: NS_FONT_SYNTHESIS_STYLE, valueStr); michael@0: val->SetString(valueStr); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantAlternates() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantAlternates; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: return val; michael@0: } michael@0: michael@0: // first, include enumerated values michael@0: nsAutoString valueStr; michael@0: michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates, michael@0: intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK, michael@0: NS_FONT_VARIANT_ALTERNATES_HISTORICAL, michael@0: NS_FONT_VARIANT_ALTERNATES_HISTORICAL, valueStr); michael@0: michael@0: // next, include functional values if present michael@0: if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) { michael@0: nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues, michael@0: valueStr); michael@0: } michael@0: michael@0: val->SetString(valueStr); michael@0: return val; michael@0: } michael@0: michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantCaps() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantCaps; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(intValue, michael@0: nsCSSProps::kFontVariantCapsKTable)); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantEastAsian() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantEastAsian; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: nsAutoString valueStr; michael@0: michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian, michael@0: intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78, michael@0: NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr); michael@0: val->SetString(valueStr); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantLigatures() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantLigatures; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: nsAutoString valueStr; michael@0: michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures, michael@0: intValue, NS_FONT_VARIANT_LIGATURES_NONE, michael@0: NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr); michael@0: val->SetString(valueStr); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantNumeric() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantNumeric; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: nsAutoString valueStr; michael@0: michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric, michael@0: intValue, NS_FONT_VARIANT_NUMERIC_LINING, michael@0: NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr); michael@0: val->SetString(valueStr); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFontVariantPosition() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleFont()->mFont.variantPosition; michael@0: michael@0: if (0 == intValue) { michael@0: val->SetIdent(eCSSKeyword_normal); michael@0: } else { michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(intValue, michael@0: nsCSSProps::kFontVariantPositionKTable)); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember, michael@0: uint32_t nsStyleBackground::* aCount, michael@0: const KTableValue aTable[]) michael@0: { michael@0: const nsStyleBackground* bg = StyleBackground(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0, i_end = bg->*aCount; i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember, michael@0: aTable)); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundAttachment() michael@0: { michael@0: return GetBackgroundList(&nsStyleBackground::Layer::mAttachment, michael@0: &nsStyleBackground::mAttachmentCount, michael@0: nsCSSProps::kBackgroundAttachmentKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundClip() michael@0: { michael@0: return GetBackgroundList(&nsStyleBackground::Layer::mClip, michael@0: &nsStyleBackground::mClipCount, michael@0: nsCSSProps::kBackgroundOriginKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundColor() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetToRGBAColor(val, StyleBackground()->mBackgroundColor); michael@0: return val; michael@0: } michael@0: michael@0: michael@0: static void michael@0: SetValueToCalc(const nsStyleCoord::Calc *aCalc, nsROCSSPrimitiveValue *aValue) michael@0: { michael@0: nsRefPtr val = new nsROCSSPrimitiveValue; michael@0: nsAutoString tmp, result; michael@0: michael@0: result.AppendLiteral("calc("); michael@0: michael@0: val->SetAppUnits(aCalc->mLength); michael@0: val->GetCssText(tmp); michael@0: result.Append(tmp); michael@0: michael@0: if (aCalc->mHasPercent) { michael@0: result.AppendLiteral(" + "); michael@0: michael@0: val->SetPercent(aCalc->mPercent); michael@0: val->GetCssText(tmp); michael@0: result.Append(tmp); michael@0: } michael@0: michael@0: result.AppendLiteral(")"); michael@0: michael@0: aValue->SetString(result); // not really SetString michael@0: } michael@0: michael@0: static void michael@0: AppendCSSGradientLength(const nsStyleCoord& aValue, michael@0: nsROCSSPrimitiveValue* aPrimitive, michael@0: nsAString& aString) michael@0: { michael@0: nsAutoString tokenString; michael@0: if (aValue.IsCalcUnit()) michael@0: SetValueToCalc(aValue.GetCalcValue(), aPrimitive); michael@0: else if (aValue.GetUnit() == eStyleUnit_Coord) michael@0: aPrimitive->SetAppUnits(aValue.GetCoordValue()); michael@0: else michael@0: aPrimitive->SetPercent(aValue.GetPercentValue()); michael@0: aPrimitive->GetCssText(tokenString); michael@0: aString.Append(tokenString); michael@0: } michael@0: michael@0: static void michael@0: AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient, michael@0: nsAString& aString, michael@0: bool& aNeedSep) michael@0: { michael@0: float xValue = aGradient->mBgPosX.GetPercentValue(); michael@0: float yValue = aGradient->mBgPosY.GetPercentValue(); michael@0: michael@0: if (yValue == 1.0f && xValue == 0.5f) { michael@0: // omit "to bottom" michael@0: return; michael@0: } michael@0: NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position"); michael@0: michael@0: aString.AppendLiteral("to"); michael@0: michael@0: if (yValue == 0.0f) { michael@0: aString.AppendLiteral(" top"); michael@0: } else if (yValue == 1.0f) { michael@0: aString.AppendLiteral(" bottom"); michael@0: } else if (yValue != 0.5f) { // do not write "center" keyword michael@0: NS_NOTREACHED("invalid box position"); michael@0: } michael@0: michael@0: if (xValue == 0.0f) { michael@0: aString.AppendLiteral(" left"); michael@0: } else if (xValue == 1.0f) { michael@0: aString.AppendLiteral(" right"); michael@0: } else if (xValue != 0.5f) { // do not write "center" keyword michael@0: NS_NOTREACHED("invalid box position"); michael@0: } michael@0: michael@0: aNeedSep = true; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient, michael@0: nsAString& aString) michael@0: { michael@0: if (!aGradient->mLegacySyntax) { michael@0: aString.Truncate(); michael@0: } else { michael@0: aString.AssignLiteral("-moz-"); michael@0: } michael@0: if (aGradient->mRepeating) { michael@0: aString.AppendLiteral("repeating-"); michael@0: } michael@0: bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR; michael@0: if (isRadial) { michael@0: aString.AppendLiteral("radial-gradient("); michael@0: } else { michael@0: aString.AppendLiteral("linear-gradient("); michael@0: } michael@0: michael@0: bool needSep = false; michael@0: nsAutoString tokenString; michael@0: nsROCSSPrimitiveValue *tmpVal = new nsROCSSPrimitiveValue; michael@0: michael@0: if (isRadial && !aGradient->mLegacySyntax) { michael@0: if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) { michael@0: if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) { michael@0: aString.AppendLiteral("circle"); michael@0: needSep = true; michael@0: } michael@0: if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) { michael@0: if (needSep) { michael@0: aString.AppendLiteral(" "); michael@0: } michael@0: AppendASCIItoUTF16(nsCSSProps:: michael@0: ValueToKeyword(aGradient->mSize, michael@0: nsCSSProps::kRadialGradientSizeKTable), michael@0: aString); michael@0: needSep = true; michael@0: } michael@0: } else { michael@0: AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString); michael@0: if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) { michael@0: aString.AppendLiteral(" "); michael@0: AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString); michael@0: } michael@0: needSep = true; michael@0: } michael@0: } michael@0: if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) { michael@0: MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None); michael@0: if (!isRadial && !aGradient->mLegacySyntax) { michael@0: AppendCSSGradientToBoxPosition(aGradient, aString, needSep); michael@0: } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent || michael@0: aGradient->mBgPosX.GetPercentValue() != 0.5f || michael@0: aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent || michael@0: aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 1.0f)) { michael@0: if (isRadial && !aGradient->mLegacySyntax) { michael@0: if (needSep) { michael@0: aString.AppendLiteral(" "); michael@0: } michael@0: aString.AppendLiteral("at "); michael@0: needSep = false; michael@0: } michael@0: AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString); michael@0: if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) { michael@0: aString.AppendLiteral(" "); michael@0: AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString); michael@0: } michael@0: needSep = true; michael@0: } michael@0: } michael@0: if (aGradient->mAngle.GetUnit() != eStyleUnit_None) { michael@0: MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax); michael@0: if (needSep) { michael@0: aString.AppendLiteral(" "); michael@0: } michael@0: nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString); michael@0: needSep = true; michael@0: } michael@0: michael@0: if (isRadial && aGradient->mLegacySyntax && michael@0: (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR || michael@0: aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) { michael@0: MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE); michael@0: if (needSep) { michael@0: aString.AppendLiteral(", "); michael@0: needSep = false; michael@0: } michael@0: if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) { michael@0: aString.AppendLiteral("circle"); michael@0: needSep = true; michael@0: } michael@0: if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) { michael@0: if (needSep) { michael@0: aString.AppendLiteral(" "); michael@0: } michael@0: AppendASCIItoUTF16(nsCSSProps:: michael@0: ValueToKeyword(aGradient->mSize, michael@0: nsCSSProps::kRadialGradientSizeKTable), michael@0: aString); michael@0: } michael@0: needSep = true; michael@0: } michael@0: michael@0: michael@0: // color stops michael@0: for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) { michael@0: if (needSep) { michael@0: aString.AppendLiteral(", "); michael@0: } michael@0: SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor); michael@0: tmpVal->GetCssText(tokenString); michael@0: aString.Append(tokenString); michael@0: michael@0: if (aGradient->mStops[i].mLocation.GetUnit() != eStyleUnit_None) { michael@0: aString.AppendLiteral(" "); michael@0: AppendCSSGradientLength(aGradient->mStops[i].mLocation, tmpVal, aString); michael@0: } michael@0: needSep = true; michael@0: } michael@0: michael@0: delete tmpVal; michael@0: aString.AppendLiteral(")"); michael@0: } michael@0: michael@0: // -moz-image-rect(, , , , ) michael@0: void michael@0: nsComputedDOMStyle::GetImageRectString(nsIURI* aURI, michael@0: const nsStyleSides& aCropRect, michael@0: nsString& aString) michael@0: { michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(true); michael@0: michael@0: // michael@0: nsROCSSPrimitiveValue *valURI = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valURI); michael@0: valURI->SetURI(aURI); michael@0: michael@0: // , , , michael@0: NS_FOR_CSS_SIDES(side) { michael@0: nsROCSSPrimitiveValue *valSide = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valSide); michael@0: SetValueToCoord(valSide, aCropRect.Get(side), false); michael@0: } michael@0: michael@0: nsAutoString argumentString; michael@0: valueList->GetCssText(argumentString); michael@0: delete valueList; michael@0: michael@0: aString = NS_LITERAL_STRING("-moz-image-rect(") + michael@0: argumentString + michael@0: NS_LITERAL_STRING(")"); michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage, michael@0: nsROCSSPrimitiveValue* aValue) michael@0: { michael@0: switch (aStyleImage.GetType()) { michael@0: case eStyleImageType_Image: michael@0: { michael@0: imgIRequest *req = aStyleImage.GetImageData(); michael@0: nsCOMPtr uri; michael@0: req->GetURI(getter_AddRefs(uri)); michael@0: michael@0: const nsStyleSides* cropRect = aStyleImage.GetCropRect(); michael@0: if (cropRect) { michael@0: nsAutoString imageRectString; michael@0: GetImageRectString(uri, *cropRect, imageRectString); michael@0: aValue->SetString(imageRectString); michael@0: } else { michael@0: aValue->SetURI(uri); michael@0: } michael@0: break; michael@0: } michael@0: case eStyleImageType_Gradient: michael@0: { michael@0: nsAutoString gradientString; michael@0: GetCSSGradientString(aStyleImage.GetGradientData(), michael@0: gradientString); michael@0: aValue->SetString(gradientString); michael@0: break; michael@0: } michael@0: case eStyleImageType_Element: michael@0: { michael@0: nsAutoString elementId; michael@0: nsStyleUtil::AppendEscapedCSSIdent( michael@0: nsDependentString(aStyleImage.GetElementId()), elementId); michael@0: nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") + michael@0: elementId + michael@0: NS_LITERAL_STRING(")"); michael@0: aValue->SetString(elementString); michael@0: break; michael@0: } michael@0: case eStyleImageType_Null: michael@0: aValue->SetIdent(eCSSKeyword_none); michael@0: break; michael@0: default: michael@0: NS_NOTREACHED("unexpected image type"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundImage() michael@0: { michael@0: const nsStyleBackground* bg = StyleBackground(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0, i_end = bg->mImageCount; i < i_end; ++i) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: michael@0: const nsStyleImage& image = bg->mLayers[i].mImage; michael@0: SetValueToStyleImage(image, val); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundInlinePolicy() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum( michael@0: StyleBackground()->mBackgroundInlinePolicy, michael@0: nsCSSProps::kBackgroundInlinePolicyKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundBlendMode() michael@0: { michael@0: return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode, michael@0: &nsStyleBackground::mBlendModeCount, michael@0: nsCSSProps::kBlendModeKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundOrigin() michael@0: { michael@0: return GetBackgroundList(&nsStyleBackground::Layer::mOrigin, michael@0: &nsStyleBackground::mOriginCount, michael@0: nsCSSProps::kBackgroundOriginKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundPosition() michael@0: { michael@0: const nsStyleBackground* bg = StyleBackground(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0, i_end = bg->mPositionCount; i < i_end; ++i) { michael@0: nsDOMCSSValueList *itemList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(itemList); michael@0: michael@0: nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valX); michael@0: michael@0: nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valY); michael@0: michael@0: const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition; michael@0: michael@0: if (!pos.mXPosition.mHasPercent) { michael@0: NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f, michael@0: "Shouldn't have mPercent!"); michael@0: valX->SetAppUnits(pos.mXPosition.mLength); michael@0: } else if (pos.mXPosition.mLength == 0) { michael@0: valX->SetPercent(pos.mXPosition.mPercent); michael@0: } else { michael@0: SetValueToCalc(&pos.mXPosition, valX); michael@0: } michael@0: michael@0: if (!pos.mYPosition.mHasPercent) { michael@0: NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f, michael@0: "Shouldn't have mPercent!"); michael@0: valY->SetAppUnits(pos.mYPosition.mLength); michael@0: } else if (pos.mYPosition.mLength == 0) { michael@0: valY->SetPercent(pos.mYPosition.mPercent); michael@0: } else { michael@0: SetValueToCalc(&pos.mYPosition, valY); michael@0: } michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundRepeat() michael@0: { michael@0: const nsStyleBackground* bg = StyleBackground(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0, i_end = bg->mRepeatCount; i < i_end; ++i) { michael@0: nsDOMCSSValueList *itemList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(itemList); michael@0: michael@0: nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valX); michael@0: michael@0: const uint8_t& xRepeat = bg->mLayers[i].mRepeat.mXRepeat; michael@0: const uint8_t& yRepeat = bg->mLayers[i].mRepeat.mYRepeat; michael@0: michael@0: bool hasContraction = true; michael@0: unsigned contraction; michael@0: if (xRepeat == yRepeat) { michael@0: contraction = xRepeat; michael@0: } else if (xRepeat == NS_STYLE_BG_REPEAT_REPEAT && michael@0: yRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT) { michael@0: contraction = NS_STYLE_BG_REPEAT_REPEAT_X; michael@0: } else if (xRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT && michael@0: yRepeat == NS_STYLE_BG_REPEAT_REPEAT) { michael@0: contraction = NS_STYLE_BG_REPEAT_REPEAT_Y; michael@0: } else { michael@0: hasContraction = false; michael@0: } michael@0: michael@0: if (hasContraction) { michael@0: valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction, michael@0: nsCSSProps::kBackgroundRepeatKTable)); michael@0: } else { michael@0: nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valY); michael@0: michael@0: valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat, michael@0: nsCSSProps::kBackgroundRepeatKTable)); michael@0: valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat, michael@0: nsCSSProps::kBackgroundRepeatKTable)); michael@0: } michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBackgroundSize() michael@0: { michael@0: const nsStyleBackground* bg = StyleBackground(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0, i_end = bg->mSizeCount; i < i_end; ++i) { michael@0: const nsStyleBackground::Size &size = bg->mLayers[i].mSize; michael@0: michael@0: switch (size.mWidthType) { michael@0: case nsStyleBackground::Size::eContain: michael@0: case nsStyleBackground::Size::eCover: { michael@0: NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType, michael@0: "unsynced types"); michael@0: nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain michael@0: ? eCSSKeyword_contain michael@0: : eCSSKeyword_cover; michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: val->SetIdent(keyword); michael@0: break; michael@0: } michael@0: default: { michael@0: nsDOMCSSValueList *itemList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(itemList); michael@0: michael@0: nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valX); michael@0: nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valY); michael@0: michael@0: if (size.mWidthType == nsStyleBackground::Size::eAuto) { michael@0: valX->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: NS_ABORT_IF_FALSE(size.mWidthType == michael@0: nsStyleBackground::Size::eLengthPercentage, michael@0: "bad mWidthType"); michael@0: if (!size.mWidth.mHasPercent && michael@0: // negative values must have come from calc() michael@0: size.mWidth.mLength >= 0) { michael@0: NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f, michael@0: "Shouldn't have mPercent"); michael@0: valX->SetAppUnits(size.mWidth.mLength); michael@0: } else if (size.mWidth.mLength == 0 && michael@0: // negative values must have come from calc() michael@0: size.mWidth.mPercent >= 0.0f) { michael@0: valX->SetPercent(size.mWidth.mPercent); michael@0: } else { michael@0: SetValueToCalc(&size.mWidth, valX); michael@0: } michael@0: } michael@0: michael@0: if (size.mHeightType == nsStyleBackground::Size::eAuto) { michael@0: valY->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: NS_ABORT_IF_FALSE(size.mHeightType == michael@0: nsStyleBackground::Size::eLengthPercentage, michael@0: "bad mHeightType"); michael@0: if (!size.mHeight.mHasPercent && michael@0: // negative values must have come from calc() michael@0: size.mHeight.mLength >= 0) { michael@0: NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f, michael@0: "Shouldn't have mPercent"); michael@0: valY->SetAppUnits(size.mHeight.mLength); michael@0: } else if (size.mHeight.mLength == 0 && michael@0: // negative values must have come from calc() michael@0: size.mHeight.mPercent >= 0.0f) { michael@0: valY->SetPercent(size.mHeight.mPercent); michael@0: } else { michael@0: SetValueToCalc(&size.mHeight, valY); michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridTemplateAreas() michael@0: { michael@0: const css::GridTemplateAreasValue* areas = michael@0: StylePosition()->mGridTemplateAreas; michael@0: if (!areas) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: MOZ_ASSERT(!areas->mTemplates.IsEmpty(), michael@0: "Unexpected empty array in GridTemplateAreasValue"); michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) { michael@0: nsAutoString str; michael@0: nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str); michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetString(str); michael@0: valueList->AppendCSSValue(val); michael@0: } michael@0: return valueList; michael@0: } michael@0: michael@0: // aLineNames must not be empty michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetGridLineNames(const nsTArray& aLineNames) michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: nsAutoString lineNamesString; michael@0: uint32_t i_end = aLineNames.Length(); michael@0: lineNamesString.AssignLiteral("("); michael@0: if (i_end > 0) { michael@0: for (uint32_t i = 0;;) { michael@0: nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], lineNamesString); michael@0: if (++i == i_end) { michael@0: break; michael@0: } michael@0: lineNamesString.AppendLiteral(" "); michael@0: } michael@0: } michael@0: lineNamesString.AppendLiteral(")"); michael@0: val->SetString(lineNamesString); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue, michael@0: const nsStyleCoord& aMaxValue) michael@0: { michael@0: // FIXME bug 978212: for grid-template-columns and grid-template-rows michael@0: // (not grid-auto-columns and grid-auto-rows), if we have frame, michael@0: // every should be resolved into 'px' here, michael@0: // based on layout results. michael@0: if (aMinValue == aMaxValue) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, aMinValue, true, michael@0: nullptr, nsCSSProps::kGridTrackBreadthKTable); michael@0: return val; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: nsAutoString argumentStr, minmaxStr; michael@0: minmaxStr.AppendLiteral("minmax("); michael@0: michael@0: SetValueToCoord(val, aMinValue, true, michael@0: nullptr, nsCSSProps::kGridTrackBreadthKTable); michael@0: val->GetCssText(argumentStr); michael@0: minmaxStr.Append(argumentStr); michael@0: michael@0: minmaxStr.AppendLiteral(", "); michael@0: michael@0: SetValueToCoord(val, aMaxValue, true, michael@0: nullptr, nsCSSProps::kGridTrackBreadthKTable); michael@0: val->GetCssText(argumentStr); michael@0: minmaxStr.Append(argumentStr); michael@0: michael@0: minmaxStr.Append(char16_t(')')); michael@0: val->SetString(minmaxStr); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList) michael@0: { michael@0: if (aTrackList.mIsSubgrid) { michael@0: NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() && michael@0: aTrackList.mMaxTrackSizingFunctions.IsEmpty(), michael@0: "Unexpected sizing functions with subgrid"); michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: nsROCSSPrimitiveValue* subgridKeyword = new nsROCSSPrimitiveValue; michael@0: subgridKeyword->SetIdent(eCSSKeyword_subgrid); michael@0: valueList->AppendCSSValue(subgridKeyword); michael@0: michael@0: for (uint32_t i = 0; i < aTrackList.mLineNameLists.Length(); i++) { michael@0: valueList->AppendCSSValue(GetGridLineNames(aTrackList.mLineNameLists[i])); michael@0: } michael@0: return valueList; michael@0: } michael@0: michael@0: uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length(); michael@0: MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes, michael@0: "Different number of min and max track sizing functions"); michael@0: // An empty is represented as "none" in syntax. michael@0: if (numSizes == 0) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: // Delimiting N tracks requires N+1 lines: michael@0: // one before each track, plus one at the very end. michael@0: MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1, michael@0: "Unexpected number of line name lists"); michael@0: for (uint32_t i = 0;; i++) { michael@0: const nsTArray& lineNames = aTrackList.mLineNameLists[i]; michael@0: if (!lineNames.IsEmpty()) { michael@0: valueList->AppendCSSValue(GetGridLineNames(lineNames)); michael@0: } michael@0: if (i == numSizes) { michael@0: break; michael@0: } michael@0: valueList->AppendCSSValue(GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i], michael@0: aTrackList.mMaxTrackSizingFunctions[i])); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridAutoFlow() michael@0: { michael@0: nsAutoString str; michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow, michael@0: StylePosition()->mGridAutoFlow, michael@0: NS_STYLE_GRID_AUTO_FLOW_NONE, michael@0: NS_STYLE_GRID_AUTO_FLOW_DENSE, michael@0: str); michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetString(str); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridAutoColumns() michael@0: { michael@0: return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin, michael@0: StylePosition()->mGridAutoColumnsMax); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridAutoRows() michael@0: { michael@0: return GetGridTrackSize(StylePosition()->mGridAutoRowsMin, michael@0: StylePosition()->mGridAutoRowsMax); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridTemplateColumns() michael@0: { michael@0: return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridTemplateRows() michael@0: { michael@0: return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine) michael@0: { michael@0: if (aGridLine.IsAuto()) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: if (aGridLine.mHasSpan) { michael@0: nsROCSSPrimitiveValue* span = new nsROCSSPrimitiveValue; michael@0: span->SetIdent(eCSSKeyword_span); michael@0: valueList->AppendCSSValue(span); michael@0: } michael@0: michael@0: if (aGridLine.mInteger != 0) { michael@0: nsROCSSPrimitiveValue* integer = new nsROCSSPrimitiveValue; michael@0: integer->SetNumber(aGridLine.mInteger); michael@0: valueList->AppendCSSValue(integer); michael@0: } michael@0: michael@0: if (!aGridLine.mLineName.IsEmpty()) { michael@0: nsROCSSPrimitiveValue* lineName = new nsROCSSPrimitiveValue; michael@0: nsString escapedLineName; michael@0: nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName); michael@0: lineName->SetString(escapedLineName); michael@0: valueList->AppendCSSValue(lineName); michael@0: } michael@0: michael@0: NS_ASSERTION(valueList->Length() > 0, michael@0: "Should have appended at least one value"); michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridAutoPosition() michael@0: { michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: valueList->AppendCSSValue( michael@0: GetGridLine(StylePosition()->mGridAutoPositionColumn)); michael@0: michael@0: nsROCSSPrimitiveValue* slash = new nsROCSSPrimitiveValue; michael@0: slash->SetString(NS_LITERAL_STRING("/")); michael@0: valueList->AppendCSSValue(slash); michael@0: michael@0: valueList->AppendCSSValue( michael@0: GetGridLine(StylePosition()->mGridAutoPositionRow)); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridColumnStart() michael@0: { michael@0: return GetGridLine(StylePosition()->mGridColumnStart); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridColumnEnd() michael@0: { michael@0: return GetGridLine(StylePosition()->mGridColumnEnd); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridRowStart() michael@0: { michael@0: return GetGridLine(StylePosition()->mGridRowStart); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetGridRowEnd() michael@0: { michael@0: return GetGridLine(StylePosition()->mGridRowEnd); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPaddingTop() michael@0: { michael@0: return GetPaddingWidthFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPaddingBottom() michael@0: { michael@0: return GetPaddingWidthFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPaddingLeft() michael@0: { michael@0: return GetPaddingWidthFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPaddingRight() michael@0: { michael@0: return GetPaddingWidthFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderCollapse() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse, michael@0: nsCSSProps::kBorderCollapseKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderSpacing() michael@0: { michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: nsROCSSPrimitiveValue* xSpacing = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(xSpacing); michael@0: michael@0: nsROCSSPrimitiveValue* ySpacing = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(ySpacing); michael@0: michael@0: const nsStyleTableBorder *border = StyleTableBorder(); michael@0: xSpacing->SetAppUnits(border->mBorderSpacingX); michael@0: ySpacing->SetAppUnits(border->mBorderSpacingY); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetCaptionSide() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide, michael@0: nsCSSProps::kCaptionSideKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetEmptyCells() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells, michael@0: nsCSSProps::kEmptyCellsKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTableLayout() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy, michael@0: nsCSSProps::kTableLayoutKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopStyle() michael@0: { michael@0: return GetBorderStyleFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomStyle() michael@0: { michael@0: return GetBorderStyleFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderLeftStyle() michael@0: { michael@0: return GetBorderStyleFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderRightStyle() michael@0: { michael@0: return GetBorderStyleFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomColors() michael@0: { michael@0: return GetBorderColorsFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderLeftColors() michael@0: { michael@0: return GetBorderColorsFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderRightColors() michael@0: { michael@0: return GetBorderColorsFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopColors() michael@0: { michael@0: return GetBorderColorsFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomLeftRadius() michael@0: { michael@0: return GetEllipseRadii(StyleBorder()->mBorderRadius, michael@0: NS_CORNER_BOTTOM_LEFT, true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomRightRadius() michael@0: { michael@0: return GetEllipseRadii(StyleBorder()->mBorderRadius, michael@0: NS_CORNER_BOTTOM_RIGHT, true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopLeftRadius() michael@0: { michael@0: return GetEllipseRadii(StyleBorder()->mBorderRadius, michael@0: NS_CORNER_TOP_LEFT, true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopRightRadius() michael@0: { michael@0: return GetEllipseRadii(StyleBorder()->mBorderRadius, michael@0: NS_CORNER_TOP_RIGHT, true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopWidth() michael@0: { michael@0: return GetBorderWidthFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomWidth() michael@0: { michael@0: return GetBorderWidthFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderLeftWidth() michael@0: { michael@0: return GetBorderWidthFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderRightWidth() michael@0: { michael@0: return GetBorderWidthFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderTopColor() michael@0: { michael@0: return GetBorderColorFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderBottomColor() michael@0: { michael@0: return GetBorderColorFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderLeftColor() michael@0: { michael@0: return GetBorderColorFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderRightColor() michael@0: { michael@0: return GetBorderColorFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarginTopWidth() michael@0: { michael@0: return GetMarginWidthFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarginBottomWidth() michael@0: { michael@0: return GetMarginWidthFor(NS_SIDE_BOTTOM); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarginLeftWidth() michael@0: { michael@0: return GetMarginWidthFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarginRightWidth() michael@0: { michael@0: return GetMarginWidthFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarkerOffset() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleContent()->mMarkerOffset, false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOrient() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient, michael@0: nsCSSProps::kOrientKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineWidth() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleOutline* outline = StyleOutline(); michael@0: michael@0: nscoord width; michael@0: if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) { michael@0: NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0, michael@0: "unexpected width"); michael@0: width = 0; michael@0: } else { michael@0: #ifdef DEBUG michael@0: bool res = michael@0: #endif michael@0: outline->GetOutlineWidth(width); michael@0: NS_ASSERTION(res, "percent outline doesn't exist"); michael@0: } michael@0: val->SetAppUnits(width); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineStyle() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleOutline()->GetOutlineStyle(), michael@0: nsCSSProps::kOutlineStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineOffset() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetAppUnits(StyleOutline()->mOutlineOffset); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft() michael@0: { michael@0: return GetEllipseRadii(StyleOutline()->mOutlineRadius, michael@0: NS_CORNER_BOTTOM_LEFT, false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineRadiusBottomRight() michael@0: { michael@0: return GetEllipseRadii(StyleOutline()->mOutlineRadius, michael@0: NS_CORNER_BOTTOM_RIGHT, false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineRadiusTopLeft() michael@0: { michael@0: return GetEllipseRadii(StyleOutline()->mOutlineRadius, michael@0: NS_CORNER_TOP_LEFT, false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineRadiusTopRight() michael@0: { michael@0: return GetEllipseRadii(StyleOutline()->mOutlineRadius, michael@0: NS_CORNER_TOP_RIGHT, false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOutlineColor() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: nscolor color; michael@0: if (!StyleOutline()->GetOutlineColor(color)) michael@0: color = StyleColor()->mColor; michael@0: michael@0: SetToRGBAColor(val, color); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius, michael@0: uint8_t aFullCorner, michael@0: bool aIsBorder) // else outline michael@0: { michael@0: nsStyleCoord radiusX, radiusY; michael@0: if (mInnerFrame && aIsBorder) { michael@0: nscoord radii[8]; michael@0: mInnerFrame->GetBorderRadii(radii); michael@0: radiusX.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, false)]); michael@0: radiusY.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, true)]); michael@0: } else { michael@0: radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false)); michael@0: radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true)); michael@0: michael@0: if (mInnerFrame) { michael@0: // We need to convert to absolute coordinates before doing the michael@0: // equality check below. michael@0: nscoord v; michael@0: michael@0: v = StyleCoordToNSCoord(radiusX, michael@0: &nsComputedDOMStyle::GetFrameBorderRectWidth, michael@0: 0, true); michael@0: radiusX.SetCoordValue(v); michael@0: michael@0: v = StyleCoordToNSCoord(radiusY, michael@0: &nsComputedDOMStyle::GetFrameBorderRectHeight, michael@0: 0, true); michael@0: radiusY.SetCoordValue(v); michael@0: } michael@0: } michael@0: michael@0: // for compatibility, return a single value if X and Y are equal michael@0: if (radiusX == radiusY) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: SetValueToCoord(val, radiusX, true); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valX); michael@0: michael@0: nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valY); michael@0: michael@0: SetValueToCoord(valX, radiusX, true); michael@0: SetValueToCoord(valY, radiusY, true); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray, michael@0: const nscolor& aDefaultColor, michael@0: bool aIsBoxShadow) michael@0: { michael@0: if (!aArray) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = { michael@0: &nsCSSShadowItem::mXOffset, michael@0: &nsCSSShadowItem::mYOffset, michael@0: &nsCSSShadowItem::mRadius michael@0: }; michael@0: michael@0: static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = { michael@0: &nsCSSShadowItem::mXOffset, michael@0: &nsCSSShadowItem::mYOffset, michael@0: &nsCSSShadowItem::mRadius, michael@0: &nsCSSShadowItem::mSpread michael@0: }; michael@0: michael@0: nscoord nsCSSShadowItem::* const * shadowValues; michael@0: uint32_t shadowValuesLength; michael@0: if (aIsBoxShadow) { michael@0: shadowValues = shadowValuesWithSpread; michael@0: shadowValuesLength = ArrayLength(shadowValuesWithSpread); michael@0: } else { michael@0: shadowValues = shadowValuesNoSpread; michael@0: shadowValuesLength = ArrayLength(shadowValuesNoSpread); michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (nsCSSShadowItem *item = aArray->ShadowAt(0), michael@0: *item_end = item + aArray->Length(); michael@0: item < item_end; ++item) { michael@0: nsDOMCSSValueList *itemList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(itemList); michael@0: michael@0: // Color is either the specified shadow color or the foreground color michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(val); michael@0: nscolor shadowColor; michael@0: if (item->mHasColor) { michael@0: shadowColor = item->mColor; michael@0: } else { michael@0: shadowColor = aDefaultColor; michael@0: } michael@0: SetToRGBAColor(val, shadowColor); michael@0: michael@0: // Set the offsets, blur radius, and spread if available michael@0: for (uint32_t i = 0; i < shadowValuesLength; ++i) { michael@0: val = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(val); michael@0: val->SetAppUnits(item->*(shadowValues[i])); michael@0: } michael@0: michael@0: if (item->mInset && aIsBoxShadow) { michael@0: // This is an inset box-shadow michael@0: val = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(val); michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET, michael@0: nsCSSProps::kBoxShadowTypeKTable)); michael@0: } michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxShadow() michael@0: { michael@0: return GetCSSShadowArray(StyleBorder()->mBoxShadow, michael@0: StyleColor()->mColor, michael@0: true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetZIndex() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mZIndex, false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetListStyleImage() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleList* list = StyleList(); michael@0: michael@0: if (!list->GetListStyleImage()) { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } else { michael@0: nsCOMPtr uri; michael@0: if (list->GetListStyleImage()) { michael@0: list->GetListStyleImage()->GetURI(getter_AddRefs(uri)); michael@0: } michael@0: val->SetURI(uri); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetListStylePosition() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition, michael@0: nsCSSProps::kListStylePositionKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetListStyleType() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleList()->mListStyleType, michael@0: nsCSSProps::kListStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetImageRegion() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleList* list = StyleList(); michael@0: michael@0: if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: // create the cssvalues for the sides, stick them in the rect object michael@0: nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue; michael@0: nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal, michael@0: bottomVal, leftVal); michael@0: topVal->SetAppUnits(list->mImageRegion.y); michael@0: rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x); michael@0: bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y); michael@0: leftVal->SetAppUnits(list->mImageRegion.x); michael@0: val->SetRect(domRect); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetLineHeight() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: nscoord lineHeight; michael@0: if (GetLineHeightCoord(lineHeight)) { michael@0: val->SetAppUnits(lineHeight); michael@0: } else { michael@0: SetValueToCoord(val, StyleText()->mLineHeight, true, michael@0: nullptr, nsCSSProps::kLineHeightKTable); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetVerticalAlign() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false, michael@0: &nsComputedDOMStyle::GetLineHeightCoord, michael@0: nsCSSProps::kVerticalAlignKTable); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue, michael@0: const KTableValue aTable[]) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable)); michael@0: if (!aAlignTrue) { michael@0: return val; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue* first = new nsROCSSPrimitiveValue; michael@0: first->SetIdent(eCSSKeyword_true); michael@0: michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(first); michael@0: valueList->AppendCSSValue(val); michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextAlign() michael@0: { michael@0: const nsStyleText* style = StyleText(); michael@0: return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue, michael@0: nsCSSProps::kTextAlignKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextAlignLast() michael@0: { michael@0: const nsStyleText* style = StyleText(); michael@0: return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue, michael@0: nsCSSProps::kTextAlignLastKTable); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextCombineUpright() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: uint8_t tch = StyleText()->mTextCombineUpright; michael@0: michael@0: if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) { michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(tch, michael@0: nsCSSProps::kTextCombineUprightKTable)); michael@0: } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) { michael@0: val->SetString(NS_LITERAL_STRING("digits 2")); michael@0: } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) { michael@0: val->SetString(NS_LITERAL_STRING("digits 3")); michael@0: } else { michael@0: val->SetString(NS_LITERAL_STRING("digits 4")); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextDecoration() michael@0: { michael@0: const nsStyleTextReset* textReset = StyleTextReset(); michael@0: michael@0: // If decoration style or color wasn't initial value, the author knew the michael@0: // text-decoration is a shorthand property in CSS 3. michael@0: // Return nullptr in such cases. michael@0: if (textReset->GetDecorationStyle() != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nscolor color; michael@0: bool isForegroundColor; michael@0: textReset->GetDecorationColor(color, isForegroundColor); michael@0: if (!isForegroundColor) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Otherwise, the web pages may have been written for CSS 2.1 or earlier, michael@0: // i.e., text-decoration was assumed as a longhand property. In that case, michael@0: // we should return computed value same as CSS 2.1 for backward compatibility. michael@0: michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: uint8_t line = textReset->mTextDecorationLine; michael@0: // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we michael@0: // don't want these to appear in the computed style. michael@0: line &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS | michael@0: NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL); michael@0: michael@0: if (line == NS_STYLE_TEXT_DECORATION_LINE_NONE) { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } else { michael@0: nsAutoString str; michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line, michael@0: line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, michael@0: NS_STYLE_TEXT_DECORATION_LINE_BLINK, str); michael@0: val->SetString(str); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextDecorationColor() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: nscolor color; michael@0: bool isForeground; michael@0: StyleTextReset()->GetDecorationColor(color, isForeground); michael@0: if (isForeground) { michael@0: color = StyleColor()->mColor; michael@0: } michael@0: michael@0: SetToRGBAColor(val, color); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextDecorationLine() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleTextReset()->mTextDecorationLine; michael@0: michael@0: if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: } else { michael@0: nsAutoString decorationLineString; michael@0: // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we michael@0: // don't want these to appear in the computed style. michael@0: intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS | michael@0: NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL); michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line, michael@0: intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, michael@0: NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString); michael@0: val->SetString(decorationLineString); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextDecorationStyle() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(), michael@0: nsCSSProps::kTextDecorationStyleKTable)); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextIndent() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleText()->mTextIndent, false, michael@0: &nsComputedDOMStyle::GetCBContentWidth); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextOrientation() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mTextOrientation, michael@0: nsCSSProps::kTextOrientationKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextOverflow() michael@0: { michael@0: const nsStyleTextReset *style = StyleTextReset(); michael@0: nsROCSSPrimitiveValue *first = new nsROCSSPrimitiveValue; michael@0: const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue(); michael@0: if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) { michael@0: nsString str; michael@0: nsStyleUtil::AppendEscapedCSSString(side->mString, str); michael@0: first->SetString(str); michael@0: } else { michael@0: first->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(side->mType, michael@0: nsCSSProps::kTextOverflowKTable)); michael@0: } michael@0: side = style->mTextOverflow.GetSecondValue(); michael@0: if (!side) { michael@0: return first; michael@0: } michael@0: nsROCSSPrimitiveValue *second = new nsROCSSPrimitiveValue; michael@0: if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) { michael@0: nsString str; michael@0: nsStyleUtil::AppendEscapedCSSString(side->mString, str); michael@0: second->SetString(str); michael@0: } else { michael@0: second->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(side->mType, michael@0: nsCSSProps::kTextOverflowKTable)); michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(first); michael@0: valueList->AppendCSSValue(second); michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextShadow() michael@0: { michael@0: return GetCSSShadowArray(StyleText()->mTextShadow, michael@0: StyleColor()->mColor, michael@0: false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextTransform() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform, michael@0: nsCSSProps::kTextTransformKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTabSize() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleText()->mTabSize); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetLetterSpacing() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleText()->mLetterSpacing, false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWordSpacing() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetAppUnits(StyleText()->mWordSpacing); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWhiteSpace() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace, michael@0: nsCSSProps::kWhitespaceKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWindowShadow() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow, michael@0: nsCSSProps::kWindowShadowKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWordBreak() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak, michael@0: nsCSSProps::kWordBreakKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWordWrap() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mWordWrap, michael@0: nsCSSProps::kWordWrapKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetHyphens() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens, michael@0: nsCSSProps::kHyphensKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextSizeAdjust() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: switch (StyleText()->mTextSizeAdjust) { michael@0: default: michael@0: NS_NOTREACHED("unexpected value"); michael@0: // fall through michael@0: case NS_STYLE_TEXT_SIZE_ADJUST_AUTO: michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: break; michael@0: case NS_STYLE_TEXT_SIZE_ADJUST_NONE: michael@0: val->SetIdent(eCSSKeyword_none); michael@0: break; michael@0: } michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPointerEvents() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mPointerEvents, michael@0: nsCSSProps::kPointerEventsKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetVisibility() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible, michael@0: nsCSSProps::kVisibilityKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWritingMode() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode, michael@0: nsCSSProps::kWritingModeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetDirection() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection, michael@0: nsCSSProps::kDirectionKTable)); michael@0: return val; michael@0: } michael@0: michael@0: static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0, michael@0: "unicode-bidi style constants not as expected"); michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetUnicodeBidi() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi, michael@0: nsCSSProps::kUnicodeBidiKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetCursor() michael@0: { michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: const nsStyleUserInterface *ui = StyleUserInterface(); michael@0: michael@0: for (nsCursorImage *item = ui->mCursorArray, michael@0: *item_end = ui->mCursorArray + ui->mCursorArrayLength; michael@0: item < item_end; ++item) { michael@0: nsDOMCSSValueList *itemList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(itemList); michael@0: michael@0: nsCOMPtr uri; michael@0: item->GetImage()->GetURI(getter_AddRefs(uri)); michael@0: michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(val); michael@0: val->SetURI(uri); michael@0: michael@0: if (item->mHaveHotspot) { michael@0: nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valX); michael@0: nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue; michael@0: itemList->AppendCSSValue(valY); michael@0: michael@0: valX->SetNumber(item->mHotspotX); michael@0: valY->SetNumber(item->mHotspotY); michael@0: } michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor, michael@0: nsCSSProps::kCursorKTable)); michael@0: valueList->AppendCSSValue(val); michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAppearance() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance, michael@0: nsCSSProps::kAppearanceKTable)); michael@0: return val; michael@0: } michael@0: michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxAlign() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign, michael@0: nsCSSProps::kBoxAlignKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxDirection() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection, michael@0: nsCSSProps::kBoxDirectionKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxFlex() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleXUL()->mBoxFlex); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxOrdinalGroup() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleXUL()->mBoxOrdinal); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxOrient() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient, michael@0: nsCSSProps::kBoxOrientKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxPack() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack, michael@0: nsCSSProps::kBoxPackKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBoxSizing() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mBoxSizing, michael@0: nsCSSProps::kBoxSizingKTable)); michael@0: return val; michael@0: } michael@0: michael@0: /* Border image properties */ michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderImageSource() michael@0: { michael@0: const nsStyleBorder* border = StyleBorder(); michael@0: michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: const nsStyleImage& image = border->mBorderImageSource; michael@0: SetValueToStyleImage(image, val); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderImageSlice() michael@0: { michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: const nsStyleBorder* border = StyleBorder(); michael@0: // Four slice numbers. michael@0: NS_FOR_CSS_SIDES (side) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr); michael@0: } michael@0: michael@0: // Fill keyword. michael@0: if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: val->SetIdent(eCSSKeyword_fill); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderImageWidth() michael@0: { michael@0: const nsStyleBorder* border = StyleBorder(); michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: NS_FOR_CSS_SIDES (side) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: SetValueToCoord(val, border->mBorderImageWidth.Get(side), michael@0: true, nullptr); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderImageOutset() michael@0: { michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: const nsStyleBorder* border = StyleBorder(); michael@0: // four slice numbers michael@0: NS_FOR_CSS_SIDES (side) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(val); michael@0: SetValueToCoord(val, border->mBorderImageOutset.Get(side), michael@0: true, nullptr); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetBorderImageRepeat() michael@0: { michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: michael@0: const nsStyleBorder* border = StyleBorder(); michael@0: michael@0: // horizontal repeat michael@0: nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valX); michael@0: valX->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH, michael@0: nsCSSProps::kBorderImageRepeatKTable)); michael@0: michael@0: // vertical repeat michael@0: nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(valY); michael@0: valY->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV, michael@0: nsCSSProps::kBorderImageRepeatKTable)); michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAlignContent() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignContent, michael@0: nsCSSProps::kAlignContentKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAlignItems() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignItems, michael@0: nsCSSProps::kAlignItemsKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAlignSelf() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: uint8_t computedAlignSelf = StylePosition()->mAlignSelf; michael@0: michael@0: if (computedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) { michael@0: // "align-self: auto" needs to compute to parent's align-items value. michael@0: nsStyleContext* parentStyleContext = mStyleContextHolder->GetParent(); michael@0: if (parentStyleContext) { michael@0: computedAlignSelf = michael@0: parentStyleContext->StylePosition()->mAlignItems; michael@0: } else { michael@0: // No parent --> use default. michael@0: computedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE; michael@0: } michael@0: } michael@0: michael@0: NS_ABORT_IF_FALSE(computedAlignSelf != NS_STYLE_ALIGN_SELF_AUTO, michael@0: "Should have swapped out 'auto' for something non-auto"); michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(computedAlignSelf, michael@0: nsCSSProps::kAlignSelfKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFlexBasis() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: // XXXdholbert We could make this more automagic and resolve percentages michael@0: // if we wanted, by passing in a PercentageBaseGetter instead of nullptr michael@0: // below. Logic would go like this: michael@0: // if (i'm a flex item) { michael@0: // if (my flex container is horizontal) { michael@0: // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth; michael@0: // } else { michael@0: // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight; michael@0: // } michael@0: // } michael@0: michael@0: SetValueToCoord(val, StylePosition()->mFlexBasis, true, michael@0: nullptr, nsCSSProps::kWidthKTable); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFlexDirection() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection, michael@0: nsCSSProps::kFlexDirectionKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFlexGrow() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StylePosition()->mFlexGrow); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFlexShrink() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StylePosition()->mFlexShrink); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFlexWrap() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap, michael@0: nsCSSProps::kFlexWrapKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOrder() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StylePosition()->mOrder); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetJustifyContent() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent, michael@0: nsCSSProps::kJustifyContentKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFloatEdge() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge, michael@0: nsCSSProps::kFloatEdgeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetForceBrokenImageIcon() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleUIReset()->mForceBrokenImageIcon); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetImageOrientation() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: nsAutoString string; michael@0: nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation; michael@0: michael@0: if (orientation.IsFromImage()) { michael@0: string.AppendLiteral("from-image"); michael@0: } else { michael@0: nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string); michael@0: michael@0: if (orientation.IsFlipped()) { michael@0: string.AppendLiteral(" flip"); michael@0: } michael@0: } michael@0: michael@0: val->SetString(string); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetIMEMode() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode, michael@0: nsCSSProps::kIMEModeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetUserFocus() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus, michael@0: nsCSSProps::kUserFocusKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetUserInput() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput, michael@0: nsCSSProps::kUserInputKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetUserModify() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify, michael@0: nsCSSProps::kUserModifyKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetUserSelect() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect, michael@0: nsCSSProps::kUserSelectKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetDisplay() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay, michael@0: nsCSSProps::kDisplayKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPosition() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition, michael@0: nsCSSProps::kPositionKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetClip() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: if (display->mClipFlags == NS_STYLE_CLIP_AUTO) { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: // create the cssvalues for the sides, stick them in the rect object michael@0: nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue; michael@0: nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue; michael@0: nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal, michael@0: bottomVal, leftVal); michael@0: if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) { michael@0: topVal->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: topVal->SetAppUnits(display->mClip.y); michael@0: } michael@0: michael@0: if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) { michael@0: rightVal->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: rightVal->SetAppUnits(display->mClip.width + display->mClip.x); michael@0: } michael@0: michael@0: if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) { michael@0: bottomVal->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: bottomVal->SetAppUnits(display->mClip.height + display->mClip.y); michael@0: } michael@0: michael@0: if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) { michael@0: leftVal->SetIdent(eCSSKeyword_auto); michael@0: } else { michael@0: leftVal->SetAppUnits(display->mClip.x); michael@0: } michael@0: val->SetRect(domRect); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWillChange() michael@0: { michael@0: const nsTArray& willChange = StyleDisplay()->mWillChange; michael@0: michael@0: if (willChange.IsEmpty()) { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: for (size_t i = 0; i < willChange.Length(); i++) { michael@0: const nsString& willChangeIdentifier = willChange[i]; michael@0: nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(property); michael@0: property->SetString(willChangeIdentifier); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOverflow() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: if (display->mOverflowX != display->mOverflowY) { michael@0: // No value to return. We can't express this combination of michael@0: // values as a shorthand. michael@0: return nullptr; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX, michael@0: nsCSSProps::kOverflowKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOverflowX() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX, michael@0: nsCSSProps::kOverflowSubKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOverflowY() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY, michael@0: nsCSSProps::kOverflowSubKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetOverflowClipBox() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox, michael@0: nsCSSProps::kOverflowClipBoxKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetResize() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize, michael@0: nsCSSProps::kResizeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPageBreakAfter() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleDisplay *display = StyleDisplay(); michael@0: michael@0: if (display->mBreakAfter) { michael@0: val->SetIdent(eCSSKeyword_always); michael@0: } else { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPageBreakBefore() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleDisplay *display = StyleDisplay(); michael@0: michael@0: if (display->mBreakBefore) { michael@0: val->SetIdent(eCSSKeyword_always); michael@0: } else { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPageBreakInside() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside, michael@0: nsCSSProps::kPageBreakInsideKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTouchAction() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: int32_t intValue = StyleDisplay()->mTouchAction; michael@0: michael@0: // None and Auto and Manipulation values aren't allowed michael@0: // to be in conjunction with other values. michael@0: // But there are all checks in CSSParserImpl::ParseTouchAction michael@0: nsAutoString valueStr; michael@0: nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue, michael@0: NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION, michael@0: valueStr); michael@0: val->SetString(valueStr); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetHeight() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: bool calcHeight = false; michael@0: michael@0: if (mInnerFrame) { michael@0: calcHeight = true; michael@0: michael@0: const nsStyleDisplay* displayData = StyleDisplay(); michael@0: if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE && michael@0: !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) && michael@0: // An outer SVG frame should behave the same as eReplaced in this case michael@0: mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) { michael@0: michael@0: calcHeight = false; michael@0: } michael@0: } michael@0: michael@0: if (calcHeight) { michael@0: AssertFlushedPendingReflows(); michael@0: nsMargin adjustedValues = GetAdjustedValuesForBoxSizing(); michael@0: val->SetAppUnits(mInnerFrame->GetContentRect().height + michael@0: adjustedValues.TopBottom()); michael@0: } else { michael@0: const nsStylePosition *positionData = StylePosition(); michael@0: michael@0: nscoord minHeight = michael@0: StyleCoordToNSCoord(positionData->mMinHeight, michael@0: &nsComputedDOMStyle::GetCBContentHeight, 0, true); michael@0: michael@0: nscoord maxHeight = michael@0: StyleCoordToNSCoord(positionData->mMaxHeight, michael@0: &nsComputedDOMStyle::GetCBContentHeight, michael@0: nscoord_MAX, true); michael@0: michael@0: SetValueToCoord(val, positionData->mHeight, true, nullptr, nullptr, michael@0: minHeight, maxHeight); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetWidth() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: bool calcWidth = false; michael@0: michael@0: if (mInnerFrame) { michael@0: calcWidth = true; michael@0: michael@0: const nsStyleDisplay *displayData = StyleDisplay(); michael@0: if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE && michael@0: !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) && michael@0: // An outer SVG frame should behave the same as eReplaced in this case michael@0: mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) { michael@0: michael@0: calcWidth = false; michael@0: } michael@0: } michael@0: michael@0: if (calcWidth) { michael@0: AssertFlushedPendingReflows(); michael@0: nsMargin adjustedValues = GetAdjustedValuesForBoxSizing(); michael@0: val->SetAppUnits(mInnerFrame->GetContentRect().width + michael@0: adjustedValues.LeftRight()); michael@0: } else { michael@0: const nsStylePosition *positionData = StylePosition(); michael@0: michael@0: nscoord minWidth = michael@0: StyleCoordToNSCoord(positionData->mMinWidth, michael@0: &nsComputedDOMStyle::GetCBContentWidth, 0, true); michael@0: michael@0: nscoord maxWidth = michael@0: StyleCoordToNSCoord(positionData->mMaxWidth, michael@0: &nsComputedDOMStyle::GetCBContentWidth, michael@0: nscoord_MAX, true); michael@0: michael@0: SetValueToCoord(val, positionData->mWidth, true, nullptr, michael@0: nsCSSProps::kWidthKTable, minWidth, maxWidth); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMaxHeight() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mMaxHeight, true, michael@0: &nsComputedDOMStyle::GetCBContentHeight); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMaxWidth() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mMaxWidth, true, michael@0: &nsComputedDOMStyle::GetCBContentWidth, michael@0: nsCSSProps::kWidthKTable); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMinHeight() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mMinHeight, true, michael@0: &nsComputedDOMStyle::GetCBContentHeight); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMinWidth() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mMinWidth, true, michael@0: &nsComputedDOMStyle::GetCBContentWidth, michael@0: nsCSSProps::kWidthKTable); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMixBlendMode() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode, michael@0: nsCSSProps::kBlendModeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetLeft() michael@0: { michael@0: return GetOffsetWidthFor(NS_SIDE_LEFT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetRight() michael@0: { michael@0: return GetOffsetWidthFor(NS_SIDE_RIGHT); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTop() michael@0: { michael@0: return GetOffsetWidthFor(NS_SIDE_TOP); michael@0: } michael@0: michael@0: nsDOMCSSValueList* michael@0: nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited) michael@0: { michael@0: nsDOMCSSValueList *valueList = new nsDOMCSSValueList(aCommaDelimited, true); michael@0: NS_ASSERTION(valueList != 0, "ran out of memory"); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide) michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: uint8_t position = display->mPosition; michael@0: if (!mOuterFrame) { michael@0: // GetRelativeOffset and GetAbsoluteOffset don't handle elements michael@0: // without frames in any sensible way. GetStaticOffset, however, michael@0: // is perfect for that case. michael@0: position = NS_STYLE_POSITION_STATIC; michael@0: } michael@0: michael@0: switch (position) { michael@0: case NS_STYLE_POSITION_STATIC: michael@0: return GetStaticOffset(aSide); michael@0: case NS_STYLE_POSITION_RELATIVE: michael@0: return GetRelativeOffset(aSide); michael@0: case NS_STYLE_POSITION_STICKY: michael@0: return GetStickyOffset(aSide); michael@0: case NS_STYLE_POSITION_ABSOLUTE: michael@0: case NS_STYLE_POSITION_FIXED: michael@0: return GetAbsoluteOffset(aSide); michael@0: default: michael@0: NS_ERROR("Invalid position"); michael@0: return nullptr; michael@0: } michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide) michael@0: { michael@0: MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()"); michael@0: michael@0: nsIFrame* container = mOuterFrame->GetContainingBlock(); michael@0: nsMargin margin = mOuterFrame->GetUsedMargin(); michael@0: nsMargin border = container->GetUsedBorder(); michael@0: nsMargin scrollbarSizes(0, 0, 0, 0); michael@0: nsRect rect = mOuterFrame->GetRect(); michael@0: nsRect containerRect = container->GetRect(); michael@0: michael@0: if (container->GetType() == nsGkAtoms::viewportFrame) { michael@0: // For absolutely positioned frames scrollbars are taken into michael@0: // account by virtue of getting a containing block that does michael@0: // _not_ include the scrollbars. For fixed positioned frames, michael@0: // the containing block is the viewport, which _does_ include michael@0: // scrollbars. We have to do some extra work. michael@0: // the first child in the default frame list is what we want michael@0: nsIFrame* scrollingChild = container->GetFirstPrincipalChild(); michael@0: nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild); michael@0: if (scrollFrame) { michael@0: scrollbarSizes = scrollFrame->GetActualScrollbarSizes(); michael@0: } michael@0: } michael@0: michael@0: nscoord offset = 0; michael@0: switch (aSide) { michael@0: case NS_SIDE_TOP: michael@0: offset = rect.y - margin.top - border.top - scrollbarSizes.top; michael@0: michael@0: break; michael@0: case NS_SIDE_RIGHT: michael@0: offset = containerRect.width - rect.width - michael@0: rect.x - margin.right - border.right - scrollbarSizes.right; michael@0: michael@0: break; michael@0: case NS_SIDE_BOTTOM: michael@0: offset = containerRect.height - rect.height - michael@0: rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom; michael@0: michael@0: break; michael@0: case NS_SIDE_LEFT: michael@0: offset = rect.x - margin.left - border.left - scrollbarSizes.left; michael@0: michael@0: break; michael@0: default: michael@0: NS_ERROR("Invalid side"); michael@0: break; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetAppUnits(offset); michael@0: return val; michael@0: } michael@0: michael@0: static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 && michael@0: NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3, michael@0: "box side constants not as expected for NS_OPPOSITE_SIDE"); michael@0: #define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3) michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStylePosition* positionData = StylePosition(); michael@0: int32_t sign = 1; michael@0: nsStyleCoord coord = positionData->mOffset.Get(aSide); michael@0: michael@0: NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord || michael@0: coord.GetUnit() == eStyleUnit_Percent || michael@0: coord.GetUnit() == eStyleUnit_Auto || michael@0: coord.IsCalcUnit(), michael@0: "Unexpected unit"); michael@0: michael@0: if (coord.GetUnit() == eStyleUnit_Auto) { michael@0: coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide)); michael@0: sign = -1; michael@0: } michael@0: PercentageBaseGetter baseGetter; michael@0: if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) { michael@0: baseGetter = &nsComputedDOMStyle::GetCBContentWidth; michael@0: } else { michael@0: baseGetter = &nsComputedDOMStyle::GetCBContentHeight; michael@0: } michael@0: michael@0: val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStylePosition* positionData = StylePosition(); michael@0: nsStyleCoord coord = positionData->mOffset.Get(aSide); michael@0: michael@0: NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord || michael@0: coord.GetUnit() == eStyleUnit_Percent || michael@0: coord.GetUnit() == eStyleUnit_Auto || michael@0: coord.IsCalcUnit(), michael@0: "Unexpected unit"); michael@0: michael@0: if (coord.GetUnit() == eStyleUnit_Auto) { michael@0: val->SetIdent(eCSSKeyword_auto); michael@0: return val; michael@0: } michael@0: PercentageBaseGetter baseGetter; michael@0: if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) { michael@0: baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth; michael@0: } else { michael@0: baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight; michael@0: } michael@0: michael@0: val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false)); michael@0: return val; michael@0: } michael@0: michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide) michael@0: michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: if (!mInnerFrame) { michael@0: SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true); michael@0: } else { michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide)); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord) michael@0: { michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: nscoord blockHeight = NS_AUTOHEIGHT; michael@0: if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) { michael@0: if (!mInnerFrame) michael@0: return false; michael@0: michael@0: if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) { michael@0: blockHeight = mInnerFrame->GetContentRect().height; michael@0: } else { michael@0: GetCBContentHeight(blockHeight); michael@0: } michael@0: } michael@0: michael@0: // lie about font size inflation since we lie about font size (since michael@0: // the inflation only applies to text) michael@0: aCoord = nsHTMLReflowState::CalcLineHeight(mContent, mStyleContextHolder, michael@0: blockHeight, 1.0f); michael@0: michael@0: // CalcLineHeight uses font->mFont.size, but we want to use michael@0: // font->mSize as the font size. Adjust for that. Also adjust for michael@0: // the text zoom, if any. michael@0: const nsStyleFont* font = StyleFont(); michael@0: float fCoord = float(aCoord); michael@0: if (font->mAllowZoom) { michael@0: fCoord /= mPresShell->GetPresContext()->TextZoom(); michael@0: } michael@0: if (font->mFont.size != font->mSize) { michael@0: fCoord = fCoord * (float(font->mSize) / float(font->mFont.size)); michael@0: } michael@0: aCoord = NSToCoordRound(fCoord); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide) michael@0: { michael@0: const nsStyleBorder *border = StyleBorder(); michael@0: michael@0: if (border->mBorderColors) { michael@0: nsBorderColors* borderColors = border->mBorderColors[aSide]; michael@0: if (borderColors) { michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: michael@0: do { michael@0: nsROCSSPrimitiveValue *primitive = new nsROCSSPrimitiveValue; michael@0: michael@0: SetToRGBAColor(primitive, borderColors->mColor); michael@0: michael@0: valueList->AppendCSSValue(primitive); michael@0: borderColors = borderColors->mNext; michael@0: } while (borderColors); michael@0: michael@0: return valueList; michael@0: } michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: nscoord width; michael@0: if (mInnerFrame) { michael@0: AssertFlushedPendingReflows(); michael@0: width = mInnerFrame->GetUsedBorder().Side(aSide); michael@0: } else { michael@0: width = StyleBorder()->GetComputedBorderWidth(aSide); michael@0: } michael@0: val->SetAppUnits(width); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: nscolor color; michael@0: bool foreground; michael@0: StyleBorder()->GetBorderColor(aSide, color, foreground); michael@0: if (foreground) { michael@0: color = StyleColor()->mColor; michael@0: } michael@0: michael@0: SetToRGBAColor(val, color); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: if (!mInnerFrame) { michael@0: SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false); michael@0: } else { michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: // For tables, GetUsedMargin always returns an empty margin, so we michael@0: // should read the margin from the outer table frame instead. michael@0: val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide)); michael@0: NS_ASSERTION(mOuterFrame == mInnerFrame || michael@0: mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0), michael@0: "Inner tables must have zero margins"); michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide), michael@0: nsCSSProps::kBorderStyleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue, michael@0: const nsStyleCoord& aCoord, michael@0: bool aClampNegativeCalc, michael@0: PercentageBaseGetter aPercentageBaseGetter, michael@0: const KTableValue aTable[], michael@0: nscoord aMinAppUnits, michael@0: nscoord aMaxAppUnits) michael@0: { michael@0: NS_PRECONDITION(aValue, "Must have a value to work with"); michael@0: michael@0: switch (aCoord.GetUnit()) { michael@0: case eStyleUnit_Normal: michael@0: aValue->SetIdent(eCSSKeyword_normal); michael@0: break; michael@0: michael@0: case eStyleUnit_Auto: michael@0: aValue->SetIdent(eCSSKeyword_auto); michael@0: break; michael@0: michael@0: case eStyleUnit_Percent: michael@0: { michael@0: nscoord percentageBase; michael@0: if (aPercentageBaseGetter && michael@0: (this->*aPercentageBaseGetter)(percentageBase)) { michael@0: nscoord val = NSCoordSaturatingMultiply(percentageBase, michael@0: aCoord.GetPercentValue()); michael@0: aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits))); michael@0: } else { michael@0: aValue->SetPercent(aCoord.GetPercentValue()); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case eStyleUnit_Factor: michael@0: aValue->SetNumber(aCoord.GetFactorValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_Coord: michael@0: { michael@0: nscoord val = aCoord.GetCoordValue(); michael@0: aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits))); michael@0: } michael@0: break; michael@0: michael@0: case eStyleUnit_Integer: michael@0: aValue->SetNumber(aCoord.GetIntValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_Enumerated: michael@0: NS_ASSERTION(aTable, "Must have table to handle this case"); michael@0: aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(), michael@0: aTable)); michael@0: break; michael@0: michael@0: case eStyleUnit_None: michael@0: aValue->SetIdent(eCSSKeyword_none); michael@0: break; michael@0: michael@0: case eStyleUnit_Calc: michael@0: nscoord percentageBase; michael@0: if (!aCoord.CalcHasPercent()) { michael@0: nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0); michael@0: if (aClampNegativeCalc && val < 0) { michael@0: NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(), michael@0: "parser should have rejected value"); michael@0: val = 0; michael@0: } michael@0: aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits))); michael@0: } else if (aPercentageBaseGetter && michael@0: (this->*aPercentageBaseGetter)(percentageBase)) { michael@0: nscoord val = michael@0: nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase); michael@0: if (aClampNegativeCalc && val < 0) { michael@0: NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(), michael@0: "parser should have rejected value"); michael@0: val = 0; michael@0: } michael@0: aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits))); michael@0: } else { michael@0: nsStyleCoord::Calc *calc = aCoord.GetCalcValue(); michael@0: SetValueToCalc(calc, aValue); michael@0: } michael@0: break; michael@0: michael@0: case eStyleUnit_Degree: michael@0: aValue->SetDegree(aCoord.GetAngleValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_Grad: michael@0: aValue->SetGrad(aCoord.GetAngleValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_Radian: michael@0: aValue->SetRadian(aCoord.GetAngleValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_Turn: michael@0: aValue->SetTurn(aCoord.GetAngleValue()); michael@0: break; michael@0: michael@0: case eStyleUnit_FlexFraction: { michael@0: nsAutoString tmpStr; michael@0: nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr); michael@0: tmpStr.AppendLiteral("fr"); michael@0: aValue->SetString(tmpStr); michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: NS_ERROR("Can't handle this unit"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: nscoord michael@0: nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord, michael@0: PercentageBaseGetter aPercentageBaseGetter, michael@0: nscoord aDefaultValue, michael@0: bool aClampNegativeCalc) michael@0: { michael@0: NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter"); michael@0: if (aCoord.GetUnit() == eStyleUnit_Coord) { michael@0: return aCoord.GetCoordValue(); michael@0: } michael@0: if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) { michael@0: nscoord percentageBase; michael@0: if ((this->*aPercentageBaseGetter)(percentageBase)) { michael@0: nscoord result = michael@0: nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase); michael@0: if (aClampNegativeCalc && result < 0) { michael@0: NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(), michael@0: "parser should have rejected value"); michael@0: result = 0; michael@0: } michael@0: return result; michael@0: } michael@0: // Fall through to returning aDefaultValue if we have no percentage base. michael@0: } michael@0: michael@0: return aDefaultValue; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth) michael@0: { michael@0: if (!mOuterFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: nsIFrame* container = mOuterFrame->GetContainingBlock(); michael@0: aWidth = container->GetContentRect().width; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight) michael@0: { michael@0: if (!mOuterFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: nsIFrame* container = mOuterFrame->GetContainingBlock(); michael@0: aHeight = container->GetContentRect().height; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth) michael@0: { michael@0: if (!mOuterFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: nsIScrollableFrame* scrollableFrame = michael@0: nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(), michael@0: nsLayoutUtils::SCROLLABLE_SAME_DOC | michael@0: nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN); michael@0: michael@0: if (!scrollableFrame) { michael@0: return false; michael@0: } michael@0: aWidth = michael@0: scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight) michael@0: { michael@0: if (!mOuterFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: nsIScrollableFrame* scrollableFrame = michael@0: nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(), michael@0: nsLayoutUtils::SCROLLABLE_SAME_DOC | michael@0: nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN); michael@0: michael@0: if (!scrollableFrame) { michael@0: return false; michael@0: } michael@0: aHeight = michael@0: scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth) michael@0: { michael@0: if (!mInnerFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: aWidth = mInnerFrame->GetSize().width; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight) michael@0: { michael@0: if (!mInnerFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: aHeight = mInnerFrame->GetSize().height; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth) michael@0: { michael@0: // We need a frame to work with. michael@0: if (!mInnerFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight) michael@0: { michael@0: // We need a frame to work with. michael@0: if (!mInnerFrame) { michael@0: return false; michael@0: } michael@0: michael@0: AssertFlushedPendingReflows(); michael@0: michael@0: aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height; michael@0: return true; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::GetSVGPaintFor(bool aFill) michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVG* svg = StyleSVG(); michael@0: const nsStyleSVGPaint* paint = nullptr; michael@0: michael@0: if (aFill) michael@0: paint = &svg->mFill; michael@0: else michael@0: paint = &svg->mStroke; michael@0: michael@0: nsAutoString paintString; michael@0: michael@0: switch (paint->mType) { michael@0: case eStyleSVGPaintType_None: michael@0: { michael@0: val->SetIdent(eCSSKeyword_none); michael@0: break; michael@0: } michael@0: case eStyleSVGPaintType_Color: michael@0: { michael@0: SetToRGBAColor(val, paint->mPaint.mColor); michael@0: break; michael@0: } michael@0: case eStyleSVGPaintType_Server: michael@0: { michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(false); michael@0: valueList->AppendCSSValue(val); michael@0: michael@0: nsROCSSPrimitiveValue* fallback = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(fallback); michael@0: michael@0: val->SetURI(paint->mPaint.mPaintServer); michael@0: SetToRGBAColor(fallback, paint->mFallbackColor); michael@0: return valueList; michael@0: } michael@0: case eStyleSVGPaintType_ContextFill: michael@0: { michael@0: val->SetIdent(eCSSKeyword_context_fill); michael@0: break; michael@0: } michael@0: case eStyleSVGPaintType_ContextStroke: michael@0: { michael@0: val->SetIdent(eCSSKeyword_context_stroke); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFill() michael@0: { michael@0: return GetSVGPaintFor(true); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStroke() michael@0: { michael@0: return GetSVGPaintFor(false); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarkerEnd() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVG* svg = StyleSVG(); michael@0: michael@0: if (svg->mMarkerEnd) michael@0: val->SetURI(svg->mMarkerEnd); michael@0: else michael@0: val->SetIdent(eCSSKeyword_none); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarkerMid() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVG* svg = StyleSVG(); michael@0: michael@0: if (svg->mMarkerMid) michael@0: val->SetURI(svg->mMarkerMid); michael@0: else michael@0: val->SetIdent(eCSSKeyword_none); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMarkerStart() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVG* svg = StyleSVG(); michael@0: michael@0: if (svg->mMarkerStart) michael@0: val->SetURI(svg->mMarkerStart); michael@0: else michael@0: val->SetIdent(eCSSKeyword_none); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeDasharray() michael@0: { michael@0: const nsStyleSVG* svg = StyleSVG(); michael@0: michael@0: if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(eCSSKeyword_none); michael@0: return val; michael@0: } michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: for (uint32_t i = 0; i < svg->mStrokeDasharrayLength; i++) { michael@0: nsROCSSPrimitiveValue* dash = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(dash); michael@0: michael@0: SetValueToCoord(dash, svg->mStrokeDasharray[i], true); michael@0: } michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeDashoffset() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeWidth() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: SetValueToCoord(val, StyleSVG()->mStrokeWidth, true); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetVectorEffect() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect, michael@0: nsCSSProps::kVectorEffectKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFillOpacity() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleSVG()->mFillOpacity); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFloodOpacity() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleSVGReset()->mFloodOpacity); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStopOpacity() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleSVGReset()->mStopOpacity); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeMiterlimit() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleSVG()->mStrokeMiterlimit); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeOpacity() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetNumber(StyleSVG()->mStrokeOpacity); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetClipRule() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum( michael@0: StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFillRule() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent(nsCSSProps::ValueToKeywordEnum( michael@0: StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeLinecap() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap, michael@0: nsCSSProps::kStrokeLinecapKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStrokeLinejoin() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin, michael@0: nsCSSProps::kStrokeLinejoinKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextAnchor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor, michael@0: nsCSSProps::kTextAnchorKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColorInterpolation() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation, michael@0: nsCSSProps::kColorInterpolationKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetColorInterpolationFilters() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters, michael@0: nsCSSProps::kColorInterpolationKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetDominantBaseline() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline, michael@0: nsCSSProps::kDominantBaselineKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetImageRendering() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mImageRendering, michael@0: nsCSSProps::kImageRenderingKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetShapeRendering() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering, michael@0: nsCSSProps::kShapeRenderingKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTextRendering() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextRendering, michael@0: nsCSSProps::kTextRenderingKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFloodColor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetToRGBAColor(val, StyleSVGReset()->mFloodColor); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetLightingColor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetToRGBAColor(val, StyleSVGReset()->mLightingColor); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetStopColor() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: SetToRGBAColor(val, StyleSVGReset()->mStopColor); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetClipPath() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVGReset* svg = StyleSVGReset(); michael@0: michael@0: if (svg->mClipPath) michael@0: val->SetURI(svg->mClipPath); michael@0: else michael@0: val->SetIdent(eCSSKeyword_none); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText, michael@0: const nsStyleCoord& aCoord) michael@0: { michael@0: nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue; michael@0: bool clampNegativeCalc = true; michael@0: SetValueToCoord(value, aCoord, clampNegativeCalc); michael@0: value->GetCssText(aCssText); michael@0: delete value; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter( michael@0: const nsStyleFilter& aStyleFilter) michael@0: { michael@0: nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue; michael@0: // Handle url(). michael@0: if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) { michael@0: value->SetURI(aStyleFilter.GetURL()); michael@0: return value; michael@0: } michael@0: michael@0: // Filter function name and opening parenthesis. michael@0: nsAutoString filterFunctionString; michael@0: AppendASCIItoUTF16( michael@0: nsCSSProps::ValueToKeyword(aStyleFilter.GetType(), michael@0: nsCSSProps::kFilterFunctionKTable), michael@0: filterFunctionString); michael@0: filterFunctionString.AppendLiteral("("); michael@0: michael@0: nsAutoString argumentString; michael@0: if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) { michael@0: // Handle drop-shadow() michael@0: nsRefPtr shadowValue = michael@0: GetCSSShadowArray(aStyleFilter.GetDropShadow(), michael@0: StyleColor()->mColor, michael@0: false); michael@0: ErrorResult dummy; michael@0: shadowValue->GetCssText(argumentString, dummy); michael@0: } else { michael@0: // Filter function argument. michael@0: SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter()); michael@0: } michael@0: filterFunctionString.Append(argumentString); michael@0: michael@0: // Filter function closing parenthesis. michael@0: filterFunctionString.AppendLiteral(")"); michael@0: michael@0: value->SetString(filterFunctionString); michael@0: return value; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetFilter() michael@0: { michael@0: const nsTArray& filters = StyleSVGReset()->mFilters; michael@0: michael@0: if (filters.IsEmpty()) { michael@0: nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue; michael@0: value->SetIdent(eCSSKeyword_none); michael@0: return value; michael@0: } michael@0: michael@0: nsDOMCSSValueList* valueList = GetROCSSValueList(false); michael@0: for(uint32_t i = 0; i < filters.Length(); i++) { michael@0: CSSValue* value = CreatePrimitiveValueForStyleFilter(filters[i]); michael@0: valueList->AppendCSSValue(value); michael@0: } michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMask() michael@0: { michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: michael@0: const nsStyleSVGReset* svg = StyleSVGReset(); michael@0: michael@0: if (svg->mMask) michael@0: val->SetURI(svg->mMask); michael@0: else michael@0: val->SetIdent(eCSSKeyword_none); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetMaskType() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: val->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType, michael@0: nsCSSProps::kMaskTypeKTable)); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetPaintOrder() michael@0: { michael@0: nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue; michael@0: nsAutoString string; michael@0: uint8_t paintOrder = StyleSVG()->mPaintOrder; michael@0: nsStyleUtil::AppendPaintOrderValue(paintOrder, string); michael@0: val->SetString(string); michael@0: return val; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransitionDelay() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mTransitionDelayCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsTransition *transition = &display->mTransitions[i]; michael@0: nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(delay); michael@0: delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC); michael@0: } while (++i < display->mTransitionDelayCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransitionDuration() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mTransitionDurationCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsTransition *transition = &display->mTransitions[i]; michael@0: nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(duration); michael@0: michael@0: duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC); michael@0: } while (++i < display->mTransitionDurationCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransitionProperty() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mTransitionPropertyCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsTransition *transition = &display->mTransitions[i]; michael@0: nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(property); michael@0: nsCSSProperty cssprop = transition->GetProperty(); michael@0: if (cssprop == eCSSPropertyExtra_all_properties) michael@0: property->SetIdent(eCSSKeyword_all); michael@0: else if (cssprop == eCSSPropertyExtra_no_properties) michael@0: property->SetIdent(eCSSKeyword_none); michael@0: else if (cssprop == eCSSProperty_UNKNOWN) michael@0: { michael@0: nsAutoString escaped; michael@0: nsStyleUtil::AppendEscapedCSSIdent( michael@0: nsDependentAtomString(transition->GetUnknownProperty()), escaped); michael@0: property->SetString(escaped); // really want SetIdent michael@0: } michael@0: else michael@0: property->SetString(nsCSSProps::GetStringValue(cssprop)); michael@0: } while (++i < display->mTransitionPropertyCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: void michael@0: nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList, michael@0: const nsTimingFunction& aTimingFunction) michael@0: { michael@0: nsROCSSPrimitiveValue* timingFunction = new nsROCSSPrimitiveValue; michael@0: aValueList->AppendCSSValue(timingFunction); michael@0: michael@0: nsAutoString tmp; michael@0: michael@0: if (aTimingFunction.mType == nsTimingFunction::Function) { michael@0: // set the value from the cubic-bezier control points michael@0: // (We could try to regenerate the keywords if we want.) michael@0: tmp.AppendLiteral("cubic-bezier("); michael@0: tmp.AppendFloat(aTimingFunction.mFunc.mX1); michael@0: tmp.AppendLiteral(", "); michael@0: tmp.AppendFloat(aTimingFunction.mFunc.mY1); michael@0: tmp.AppendLiteral(", "); michael@0: tmp.AppendFloat(aTimingFunction.mFunc.mX2); michael@0: tmp.AppendLiteral(", "); michael@0: tmp.AppendFloat(aTimingFunction.mFunc.mY2); michael@0: tmp.AppendLiteral(")"); michael@0: } else { michael@0: tmp.AppendLiteral("steps("); michael@0: tmp.AppendInt(aTimingFunction.mSteps); michael@0: if (aTimingFunction.mType == nsTimingFunction::StepStart) { michael@0: tmp.AppendLiteral(", start)"); michael@0: } else { michael@0: tmp.AppendLiteral(", end)"); michael@0: } michael@0: } michael@0: timingFunction->SetString(tmp); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetTransitionTimingFunction() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mTransitionTimingFunctionCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: AppendTimingFunction(valueList, michael@0: display->mTransitions[i].GetTimingFunction()); michael@0: } while (++i < display->mTransitionTimingFunctionCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationName() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationNameCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(property); michael@0: michael@0: const nsString& name = animation->GetName(); michael@0: if (name.IsEmpty()) { michael@0: property->SetIdent(eCSSKeyword_none); michael@0: } else { michael@0: nsAutoString escaped; michael@0: nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped); michael@0: property->SetString(escaped); // really want SetIdent michael@0: } michael@0: } while (++i < display->mAnimationNameCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationDelay() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationDelayCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(delay); michael@0: delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC); michael@0: } while (++i < display->mAnimationDelayCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationDuration() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationDurationCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(duration); michael@0: michael@0: duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC); michael@0: } while (++i < display->mAnimationDurationCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationTimingFunction() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationTimingFunctionCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: AppendTimingFunction(valueList, michael@0: display->mAnimations[i].GetTimingFunction()); michael@0: } while (++i < display->mAnimationTimingFunctionCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationDirection() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationDirectionCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* direction = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(direction); michael@0: direction->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(animation->GetDirection(), michael@0: nsCSSProps::kAnimationDirectionKTable)); michael@0: } while (++i < display->mAnimationDirectionCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationFillMode() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationFillModeCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* fillMode = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(fillMode); michael@0: fillMode->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(animation->GetFillMode(), michael@0: nsCSSProps::kAnimationFillModeKTable)); michael@0: } while (++i < display->mAnimationFillModeCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationIterationCount() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationIterationCountCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* iterationCount = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(iterationCount); michael@0: michael@0: float f = animation->GetIterationCount(); michael@0: /* Need a nasty hack here to work around an optimizer bug in gcc michael@0: 4.2 on Mac, which somehow gets confused when directly comparing michael@0: a float to the return value of NS_IEEEPositiveInfinity when michael@0: building 32-bit builds. */ michael@0: #ifdef XP_MACOSX michael@0: volatile michael@0: #endif michael@0: float inf = NS_IEEEPositiveInfinity(); michael@0: if (f == inf) { michael@0: iterationCount->SetIdent(eCSSKeyword_infinite); michael@0: } else { michael@0: iterationCount->SetNumber(f); michael@0: } michael@0: } while (++i < display->mAnimationIterationCountCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetAnimationPlayState() michael@0: { michael@0: const nsStyleDisplay* display = StyleDisplay(); michael@0: michael@0: nsDOMCSSValueList *valueList = GetROCSSValueList(true); michael@0: michael@0: NS_ABORT_IF_FALSE(display->mAnimationPlayStateCount > 0, michael@0: "first item must be explicit"); michael@0: uint32_t i = 0; michael@0: do { michael@0: const nsAnimation *animation = &display->mAnimations[i]; michael@0: nsROCSSPrimitiveValue* playState = new nsROCSSPrimitiveValue; michael@0: valueList->AppendCSSValue(playState); michael@0: playState->SetIdent( michael@0: nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(), michael@0: nsCSSProps::kAnimationPlayStateKTable)); michael@0: } while (++i < display->mAnimationPlayStateCount); michael@0: michael@0: return valueList; michael@0: } michael@0: michael@0: static void michael@0: MarkComputedStyleMapDirty(const char* aPref, void* aData) michael@0: { michael@0: static_cast(aData)->MarkDirty(); michael@0: } michael@0: michael@0: CSSValue* michael@0: nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName) michael@0: { michael@0: MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName)); michael@0: michael@0: const nsStyleVariables* variables = StyleVariables(); michael@0: michael@0: nsString variableValue; michael@0: const nsAString& name = Substring(aPropertyName, michael@0: CSS_CUSTOM_NAME_PREFIX_LENGTH); michael@0: if (!variables->mVariables.Get(name, variableValue)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; michael@0: val->SetString(variableValue); michael@0: michael@0: return val; michael@0: } michael@0: michael@0: /* static */ nsComputedStyleMap* michael@0: nsComputedDOMStyle::GetComputedStyleMap() michael@0: { michael@0: static nsComputedStyleMap map = { michael@0: { michael@0: #define COMPUTED_STYLE_PROP(prop_, method_) \ michael@0: { eCSSProperty_##prop_, &nsComputedDOMStyle::DoGet##method_ }, michael@0: #include "nsComputedDOMStylePropertyList.h" michael@0: #undef COMPUTED_STYLE_PROP michael@0: } michael@0: }; michael@0: return ↦ michael@0: } michael@0: michael@0: /* static */ void michael@0: nsComputedDOMStyle::RegisterPrefChangeCallbacks() michael@0: { michael@0: // Note that this will register callbacks for all properties with prefs, not michael@0: // just those that are implemented on computed style objects, as it's not michael@0: // easy to grab specific property data from nsCSSPropList.h based on the michael@0: // entries iterated in nsComputedDOMStylePropertyList.h. michael@0: nsComputedStyleMap* data = GetComputedStyleMap(); michael@0: #define REGISTER_CALLBACK(pref_) \ michael@0: if (pref_[0]) { \ michael@0: Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data); \ michael@0: } michael@0: #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \ michael@0: kwtable_, stylestruct_, stylestructoffset_, animtype_) \ michael@0: REGISTER_CALLBACK(pref_) michael@0: #include "nsCSSPropList.h" michael@0: #undef CSS_PROP michael@0: #undef REGISTER_CALLBACK michael@0: } michael@0: michael@0: /* static */ void michael@0: nsComputedDOMStyle::UnregisterPrefChangeCallbacks() michael@0: { michael@0: nsComputedStyleMap* data = GetComputedStyleMap(); michael@0: #define UNREGISTER_CALLBACK(pref_) \ michael@0: if (pref_[0]) { \ michael@0: Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data); \ michael@0: } michael@0: #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \ michael@0: kwtable_, stylestruct_, stylestructoffset_, animtype_) \ michael@0: UNREGISTER_CALLBACK(pref_) michael@0: #include "nsCSSPropList.h" michael@0: #undef CSS_PROP michael@0: #undef UNREGISTER_CALLBACK michael@0: }