gecko-dev/layout/style/nsComputedDOMStyle.cpp

4736 lines
143 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set tw=78 expandtab softtabstop=2 ts=2 sw=2: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
* Boris Zbarsky <bzbarsky@mit.edu>
* Christopher A. Aillon <christopher@aillon.com>
* Mats Palmgren <matspal@gmail.com>
* Christian Biesinger <cbiesinger@web.de>
* Michael Ventnor <m.ventnor@gmail.com>
* Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* DOM object returned from element.getComputedStyle() */
#include "mozilla/Util.h"
#include "nsComputedDOMStyle.h"
#include "nsDOMError.h"
#include "nsDOMString.h"
#include "nsIDOMCSS2Properties.h"
#include "nsIDOMElement.h"
#include "nsIDOMCSSPrimitiveValue.h"
#include "nsStyleContext.h"
#include "nsIScrollableFrame.h"
#include "nsContentUtils.h"
#include "prprf.h"
#include "nsCSSProps.h"
#include "nsCSSKeywords.h"
#include "nsDOMCSSRect.h"
#include "nsGkAtoms.h"
#include "nsHTMLReflowState.h"
#include "nsThemeConstants.h"
#include "nsStyleUtil.h"
#include "nsStyleStructInlines.h"
#include "nsPresContext.h"
#include "nsIDocument.h"
#include "nsCSSPseudoElements.h"
#include "nsStyleSet.h"
#include "imgIRequest.h"
#include "nsLayoutUtils.h"
#include "nsFrameManager.h"
#include "prlog.h"
#include "nsCSSKeywords.h"
#include "nsStyleCoord.h"
#include "nsDisplayList.h"
#include "nsDOMCSSDeclaration.h"
#include "mozilla/dom/Element.h"
#include "nsGenericElement.h"
#include "CSSCalc.h"
using namespace mozilla;
using namespace mozilla::dom;
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
#define DEBUG_ComputedDOMStyle
#endif
/*
* This is the implementation of the readonly CSSStyleDeclaration that is
* returned by the getComputedStyle() function.
*/
static nsComputedDOMStyle *sCachedComputedDOMStyle;
nsresult
NS_NewComputedDOMStyle(nsIDOMElement *aElement, const nsAString &aPseudoElt,
nsIPresShell *aPresShell,
nsComputedDOMStyle **aComputedStyle)
{
nsRefPtr<nsComputedDOMStyle> computedStyle;
if (sCachedComputedDOMStyle) {
// There's an unused nsComputedDOMStyle cached, use it.
// But before we use it, re-initialize the object.
// Oh yeah baby, placement new!
computedStyle = new (sCachedComputedDOMStyle) nsComputedDOMStyle();
sCachedComputedDOMStyle = nsnull;
} else {
// No nsComputedDOMStyle cached, create a new one.
computedStyle = new nsComputedDOMStyle();
NS_ENSURE_TRUE(computedStyle, NS_ERROR_OUT_OF_MEMORY);
}
nsresult rv = computedStyle->Init(aElement, aPseudoElt, aPresShell);
NS_ENSURE_SUCCESS(rv, rv);
*aComputedStyle = nsnull;
computedStyle.swap(*aComputedStyle);
return NS_OK;
}
static nsIFrame*
GetContainingBlockFor(nsIFrame* aFrame) {
if (!aFrame) {
return nsnull;
}
return aFrame->GetContainingBlock();
}
nsComputedDOMStyle::nsComputedDOMStyle()
: mDocumentWeak(nsnull), mOuterFrame(nsnull),
mInnerFrame(nsnull), mPresShell(nsnull),
mExposeVisitedStyle(false)
{
}
nsComputedDOMStyle::~nsComputedDOMStyle()
{
}
void
nsComputedDOMStyle::Shutdown()
{
// We want to de-allocate without calling the dtor since we
// already did that manually in doDestroyComputedDOMStyle(),
// so cast our cached object to something that doesn't know
// about our dtor.
delete reinterpret_cast<char*>(sCachedComputedDOMStyle);
sCachedComputedDOMStyle = nsnull;
}
// If nsComputedDOMStyle is changed so that any additional fields are
// traversed by the cycle collector (for instance, if wrapper cache
// handling is changed) then CAN_SKIP must be updated.
NS_IMPL_CYCLE_COLLECTION_1(nsComputedDOMStyle, mContent)
// nsComputedDOMStyle has only one cycle collected field, so if
// mContent is going to be skipped, the style isn't part of a garbage
// cycle.
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
return !tmp->mContent || nsGenericElement::CanSkip(tmp->mContent, true);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
return !tmp->mContent || nsGenericElement::CanSkipInCC(tmp->mContent);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
// CanSkipThis returns false to avoid problems with incomplete unlinking.
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
// QueryInterface implementation for nsComputedDOMStyle
NS_INTERFACE_MAP_BEGIN(nsComputedDOMStyle)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsComputedDOMStyle)
NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
static void doDestroyComputedDOMStyle(nsComputedDOMStyle *aComputedStyle)
{
if (!sCachedComputedDOMStyle) {
// The cache is empty, store aComputedStyle in the cache.
sCachedComputedDOMStyle = aComputedStyle;
sCachedComputedDOMStyle->~nsComputedDOMStyle();
} else {
// The cache is full, delete aComputedStyle
delete aComputedStyle;
}
}
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsComputedDOMStyle,
doDestroyComputedDOMStyle(this))
NS_IMETHODIMP
nsComputedDOMStyle::Init(nsIDOMElement *aElement,
const nsAString& aPseudoElt,
nsIPresShell *aPresShell)
{
NS_ENSURE_ARG_POINTER(aElement);
NS_ENSURE_ARG_POINTER(aPresShell);
mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
mContent = do_QueryInterface(aElement);
if (!mContent) {
// This should not happen, all our elements support nsIContent!
return NS_ERROR_FAILURE;
}
if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() &&
aPseudoElt.First() == PRUnichar(':')) {
// deal with two-colon forms of aPseudoElt
nsAString::const_iterator start, end;
aPseudoElt.BeginReading(start);
aPseudoElt.EndReading(end);
NS_ASSERTION(start != end, "aPseudoElt is not empty!");
++start;
bool haveTwoColons = true;
if (start == end || *start != PRUnichar(':')) {
--start;
haveTwoColons = false;
}
mPseudo = do_GetAtom(Substring(start, end));
NS_ENSURE_TRUE(mPseudo, NS_ERROR_OUT_OF_MEMORY);
// There aren't any non-CSS2 pseudo-elements with a single ':'
if (!haveTwoColons &&
!nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo)) {
// XXXbz I'd really rather we threw an exception or something, but
// the DOM spec sucks.
mPseudo = nsnull;
}
}
nsPresContext *presCtx = aPresShell->GetPresContext();
NS_ENSURE_TRUE(presCtx, NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetPropertyValue(const nsCSSProperty aPropID,
nsAString& aValue)
{
// This is mostly to avoid code duplication with GetPropertyCSSValue(); if
// perf ever becomes an issue here (doubtful), we can look into changing
// this.
return GetPropertyValue(
NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
aValue);
}
NS_IMETHODIMP
nsComputedDOMStyle::SetPropertyValue(const nsCSSProperty aPropID,
const nsAString& aValue)
{
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetCssText(nsAString& aCssText)
{
aCssText.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::SetCssText(const nsAString& aCssText)
{
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetLength(PRUint32* aLength)
{
NS_PRECONDITION(aLength, "Null aLength! Prepare to die!");
(void)GetQueryablePropertyMap(aLength);
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule)
{
*aParentRule = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
nsAString& aReturn)
{
nsCOMPtr<nsIDOMCSSValue> val;
aReturn.Truncate();
nsresult rv = GetPropertyCSSValue(aPropertyName, getter_AddRefs(val));
NS_ENSURE_SUCCESS(rv, rv);
if (val) {
rv = val->GetCssText(aReturn);
}
return rv;
}
/* static */
already_AddRefed<nsStyleContext>
nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell)
{
// If the content has a pres shell, we must use it. Otherwise we'd
// potentially mix rule trees by using the wrong pres shell's style
// set. Using the pres shell from the content also means that any
// content that's actually *in* a document will get the style from the
// correct document.
nsIPresShell *presShell = GetPresShellForContent(aElement);
if (!presShell) {
presShell = aPresShell;
if (!presShell)
return nsnull;
}
presShell->FlushPendingNotifications(Flush_Style);
return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell);
}
/* static */
already_AddRefed<nsStyleContext>
nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell)
{
NS_ABORT_IF_FALSE(aElement, "NULL element");
// If the content has a pres shell, we must use it. Otherwise we'd
// potentially mix rule trees by using the wrong pres shell's style
// set. Using the pres shell from the content also means that any
// content that's actually *in* a document will get the style from the
// correct document.
nsIPresShell *presShell = GetPresShellForContent(aElement);
if (!presShell) {
presShell = aPresShell;
if (!presShell)
return nsnull;
}
if (!aPseudo) {
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
nsStyleContext* result =
nsLayoutUtils::GetStyleFrame(frame)->GetStyleContext();
// Don't use the style context if it was influenced by
// pseudo-elements, since then it's not the primary style
// for this element.
if (!result->HasPseudoElementData()) {
// this function returns an addrefed style context
result->AddRef();
return result;
}
}
}
// No frame has been created or we have a pseudo, so resolve the
// style ourselves
nsRefPtr<nsStyleContext> parentContext;
nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
// Don't resolve parent context for document fragments.
if (parent && parent->IsElement())
parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
nsnull, presShell);
nsPresContext *presContext = presShell->GetPresContext();
if (!presContext)
return nsnull;
nsStyleSet *styleSet = presShell->StyleSet();
if (aPseudo) {
nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
return nsnull;
}
return styleSet->ResolvePseudoElementStyle(aElement, type, parentContext);
}
return styleSet->ResolveStyleFor(aElement, parentContext);
}
/* static */
nsIPresShell*
nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent)
{
nsIDocument* currentDoc = aContent->GetCurrentDoc();
if (!currentDoc)
return nsnull;
return currentDoc->GetShell();
}
// nsDOMCSSDeclaration abstract methods which should never be called
// on a nsComputedDOMStyle object, but must be defined to avoid
// compile errors.
css::Declaration*
nsComputedDOMStyle::GetCSSDeclaration(bool)
{
NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration");
return nsnull;
}
nsresult
nsComputedDOMStyle::SetCSSDeclaration(css::Declaration*)
{
NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration");
return NS_ERROR_FAILURE;
}
nsIDocument*
nsComputedDOMStyle::DocToUpdate()
{
NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate");
return nsnull;
}
void
nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
{
NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment");
// Just in case NS_RUNTIMEABORT ever stops killing us for some reason
aCSSParseEnv.mPrincipal = nsnull;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName,
nsIDOMCSSValue** aReturn)
{
NS_ASSERTION(!mStyleContextHolder, "bad state");
*aReturn = nsnull;
nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
document->FlushPendingLinkUpdates();
nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName);
const ComputedStyleMapEntry* propEntry = nsnull;
{
PRUint32 length = 0;
const ComputedStyleMapEntry* propMap = GetQueryablePropertyMap(&length);
for (PRUint32 i = 0; i < length; ++i) {
if (prop == propMap[i].mProperty) {
propEntry = &propMap[i];
break;
}
}
}
if (!propEntry) {
#ifdef DEBUG_ComputedDOMStyle
NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) +
NS_LITERAL_CSTRING(" is not queryable!")).get());
#endif
// NOTE: For branches, we should flush here for compatibility!
return NS_OK;
}
// Flush _before_ getting the presshell, since that could create a new
// presshell. Also note that we want to flush the style on the document
// we're computing style in, not on the document mContent is in -- the two
// may be different.
document->FlushPendingNotifications(
propEntry->mNeedsLayoutFlush ? Flush_Layout : Flush_Style);
#ifdef DEBUG
mFlushedPendingReflows = propEntry->mNeedsLayoutFlush;
#endif
mPresShell = document->GetShell();
NS_ENSURE_TRUE(mPresShell && mPresShell->GetPresContext(),
NS_ERROR_NOT_AVAILABLE);
if (!mPseudo) {
mOuterFrame = mContent->GetPrimaryFrame();
mInnerFrame = mOuterFrame;
if (mOuterFrame) {
nsIAtom* type = mOuterFrame->GetType();
if (type == nsGkAtoms::tableOuterFrame) {
// If the frame is an outer table frame then we should get the style
// from the inner table frame.
mInnerFrame = mOuterFrame->GetFirstPrincipalChild();
NS_ASSERTION(mInnerFrame, "Outer table must have an inner");
NS_ASSERTION(!mInnerFrame->GetNextSibling(),
"Outer table frames should have just one child, "
"the inner table");
}
mStyleContextHolder = mInnerFrame->GetStyleContext();
NS_ASSERTION(mStyleContextHolder, "Frame without style context?");
}
}
if (!mStyleContextHolder || mStyleContextHolder->HasPseudoElementData()) {
#ifdef DEBUG
if (mStyleContextHolder) {
// We want to check that going through this path because of
// HasPseudoElementData is rare, because it slows us down a good
// bit. So check that we're really inside something associated
// with a pseudo-element that contains elements.
nsStyleContext *topWithPseudoElementData = mStyleContextHolder;
while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
topWithPseudoElementData = topWithPseudoElementData->GetParent();
}
NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(
topWithPseudoElementData->GetPseudo()),
"we should be in a pseudo-element that is expected to "
"contain elements");
}
#endif
// Need to resolve a style context
mStyleContextHolder =
nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(),
mPseudo,
mPresShell);
NS_ENSURE_TRUE(mStyleContextHolder, NS_ERROR_OUT_OF_MEMORY);
NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(),
"should not have pseudo-element data");
}
// mExposeVisitedStyle is set to true only by testing APIs that
// require UniversalXPConnect.
NS_ABORT_IF_FALSE(!mExposeVisitedStyle ||
nsContentUtils::CallerHasUniversalXPConnect(),
"mExposeVisitedStyle set incorrectly");
if (mExposeVisitedStyle && mStyleContextHolder->RelevantLinkVisited()) {
nsStyleContext *styleIfVisited = mStyleContextHolder->GetStyleIfVisited();
if (styleIfVisited) {
mStyleContextHolder = styleIfVisited;
}
}
// Call our pointer-to-member-function.
*aReturn = (this->*(propEntry->mGetter))();
NS_IF_ADDREF(*aReturn); // property getter gives us an object with refcount of 0
mOuterFrame = nsnull;
mInnerFrame = nsnull;
mPresShell = nsnull;
// Release the current style context for it should be re-resolved
// whenever a frame is not available.
mStyleContextHolder = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
nsAString& aReturn)
{
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
}
NS_IMETHODIMP
nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
nsAString& aReturn)
{
aReturn.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
const nsAString& aValue,
const nsAString& aPriority)
{
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
}
NS_IMETHODIMP
nsComputedDOMStyle::Item(PRUint32 aIndex, nsAString& aReturn)
{
aReturn.Truncate();
PRUint32 length = 0;
const ComputedStyleMapEntry* propMap = GetQueryablePropertyMap(&length);
if (aIndex < length) {
CopyASCIItoUTF16(nsCSSProps::GetStringValue(propMap[aIndex].mProperty),
aReturn);
}
return NS_OK;
}
// Property getters...
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBinding()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleDisplay* display = GetStyleDisplay();
if (display->mBinding) {
val->SetURI(display->mBinding->GetURI());
} else {
val->SetIdent(eCSSKeyword_none);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetClear()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mBreakType,
nsCSSProps::kClearKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetCssFloat()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mFloats,
nsCSSProps::kFloatKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBottom()
{
return GetOffsetWidthFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStackSizing()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(GetStyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
eCSSKeyword_ignore);
return val;
}
void
nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
nscolor aColor)
{
if (NS_GET_A(aColor) == 0) {
aValue->SetIdent(eCSSKeyword_transparent);
return;
}
nsROCSSPrimitiveValue *red = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *green = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *blue = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *alpha = GetROCSSPrimitiveValue();
PRUint8 a = NS_GET_A(aColor);
nsDOMCSSRGBColor *rgbColor =
new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
red->SetNumber(NS_GET_R(aColor));
green->SetNumber(NS_GET_G(aColor));
blue->SetNumber(NS_GET_B(aColor));
alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
aValue->SetColor(rgbColor);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetToRGBAColor(val, GetStyleColor()->mColor);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOpacity()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleDisplay()->mOpacity);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnCount()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleColumn* column = GetStyleColumn();
if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
val->SetIdent(eCSSKeyword_auto);
} else {
val->SetNumber(column->mColumnCount);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnWidth()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
// XXX fix the auto case. When we actually have a column frame, I think
// we should return the computed column width.
SetValueToCoord(val, GetStyleColumn()->mColumnWidth, true);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnGap()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleColumn* column = GetStyleColumn();
if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
val->SetAppUnits(GetStyleFont()->mFont.size);
} else {
SetValueToCoord(val, GetStyleColumn()->mColumnGap, true);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnFill()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleColumn()->mColumnFill,
nsCSSProps::kColumnFillKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnRuleWidth()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetAppUnits(GetStyleColumn()->GetComputedColumnRuleWidth());
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnRuleStyle()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleColumn()->mColumnRuleStyle,
nsCSSProps::kBorderStyleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColumnRuleColor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleColumn* column = GetStyleColumn();
nscolor ruleColor;
if (column->mColumnRuleColorIsForeground) {
ruleColor = GetStyleColor()->mColor;
} else {
ruleColor = column->mColumnRuleColor;
}
SetToRGBAColor(val, ruleColor);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetContent()
{
const nsStyleContent *content = GetStyleContent();
if (content->ContentCount() == 0) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
if (content->ContentCount() == 1 &&
content->ContentAt(0).mType == eStyleContentType_AltContent) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword__moz_alt_content);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
for (PRUint32 i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
const nsStyleContentData &data = content->ContentAt(i);
switch (data.mType) {
case eStyleContentType_String:
{
nsString str;
nsStyleUtil::AppendEscapedCSSString(
nsDependentString(data.mContent.mString), str);
val->SetString(str);
}
break;
case eStyleContentType_Image:
{
nsCOMPtr<nsIURI> uri;
if (data.mContent.mImage) {
data.mContent.mImage->GetURI(getter_AddRefs(uri));
}
val->SetURI(uri);
}
break;
case eStyleContentType_Attr:
{
nsAutoString str;
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(data.mContent.mString), str);
val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR);
}
break;
case eStyleContentType_Counter:
case eStyleContentType_Counters:
{
/* FIXME: counters should really use an object */
nsAutoString str;
if (data.mType == eStyleContentType_Counter) {
str.AppendLiteral("counter(");
}
else {
str.AppendLiteral("counters(");
}
// WRITE ME
nsCSSValue::Array *a = data.mContent.mCounters;
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(a->Item(0).GetStringBufferValue()), str);
PRInt32 typeItem = 1;
if (data.mType == eStyleContentType_Counters) {
typeItem = 2;
str.AppendLiteral(", ");
nsStyleUtil::AppendEscapedCSSString(
nsDependentString(a->Item(1).GetStringBufferValue()), str);
}
NS_ABORT_IF_FALSE(eCSSUnit_None != a->Item(typeItem).GetUnit(),
"'none' should be handled as enumerated value");
PRInt32 type = a->Item(typeItem).GetIntValue();
if (type != NS_STYLE_LIST_STYLE_DECIMAL) {
str.AppendLiteral(", ");
AppendASCIItoUTF16(
nsCSSProps::ValueToKeyword(type, nsCSSProps::kListStyleKTable),
str);
}
str.Append(PRUnichar(')'));
val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
}
break;
case eStyleContentType_OpenQuote:
val->SetIdent(eCSSKeyword_open_quote);
break;
case eStyleContentType_CloseQuote:
val->SetIdent(eCSSKeyword_close_quote);
break;
case eStyleContentType_NoOpenQuote:
val->SetIdent(eCSSKeyword_no_open_quote);
break;
case eStyleContentType_NoCloseQuote:
val->SetIdent(eCSSKeyword_no_close_quote);
break;
case eStyleContentType_AltContent:
default:
NS_NOTREACHED("unexpected type");
break;
}
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetCounterIncrement()
{
const nsStyleContent *content = GetStyleContent();
if (content->CounterIncrementCount() == 0) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
for (PRUint32 i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(name);
nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(value);
const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
nsAutoString escaped;
nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
name->SetString(escaped);
value->SetNumber(data->mValue); // XXX This should really be integer
}
return valueList;
}
/* Convert the stored representation into a list of two values and then hand
* it back.
*/
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTransformOrigin()
{
/* We need to build up a list of two values. We'll call them
* width and height.
*/
/* Store things as a value list */
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
/* Now, get the values. */
const nsStyleDisplay* display = GetStyleDisplay();
nsROCSSPrimitiveValue* width = GetROCSSPrimitiveValue();
SetValueToCoord(width, display->mTransformOrigin[0], false,
&nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
valueList->AppendCSSValue(width);
nsROCSSPrimitiveValue* height = GetROCSSPrimitiveValue();
SetValueToCoord(height, display->mTransformOrigin[1], false,
&nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
valueList->AppendCSSValue(height);
if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
display->mTransformOrigin[2].GetCoordValue() != 0) {
nsROCSSPrimitiveValue* depth = GetROCSSPrimitiveValue();
SetValueToCoord(depth, display->mTransformOrigin[2], false,
nsnull);
valueList->AppendCSSValue(depth);
}
return valueList;
}
/* Convert the stored representation into a list of two values and then hand
* it back.
*/
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozPerspectiveOrigin()
{
/* We need to build up a list of two values. We'll call them
* width and height.
*/
/* Store things as a value list */
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
/* Now, get the values. */
const nsStyleDisplay* display = GetStyleDisplay();
nsROCSSPrimitiveValue* width = GetROCSSPrimitiveValue();
SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
&nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
valueList->AppendCSSValue(width);
nsROCSSPrimitiveValue* height = GetROCSSPrimitiveValue();
SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
&nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
valueList->AppendCSSValue(height);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozPerspective()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
if (GetStyleDisplay()->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
GetStyleDisplay()->mChildPerspective.GetCoordValue() == 0.0) {
val->SetIdent(eCSSKeyword_none);
} else {
SetValueToCoord(val, GetStyleDisplay()->mChildPerspective, false);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozBackfaceVisibility()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mBackfaceVisibility,
nsCSSProps::kBackfaceVisibilityKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTransformStyle()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mTransformStyle,
nsCSSProps::kTransformStyleKTable));
return val;
}
/* If the property is "none", hand back "none" wrapped in a value.
* Otherwise, compute the aggregate transform matrix and hands it back in a
* "matrix" wrapper.
*/
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTransform()
{
/* First, get the display data. We'll need it. */
const nsStyleDisplay* display = GetStyleDisplay();
/* If the "no transforms" flag is set, then we should construct a
* single-element entry and hand it back.
*/
if (!display->HasTransform()) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
/* Set it to "none." */
val->SetIdent(eCSSKeyword_none);
return val;
}
/* Otherwise, we need to compute the current value of the transform matrix,
* store it in a string, and hand it back to the caller.
*/
/* Use the inner frame for width and height. If we fail, assume zero.
* TODO: There is no good way for us to represent the case where there's no
* frame, which is problematic. The reason is that when we have percentage
* transforms, there are a total of four stored matrix entries that influence
* the transform based on the size of the element. However, this poses a
* problem, because only two of these values can be explicitly referenced
* using the named transforms. Until a real solution is found, we'll just
* use this approach.
*/
nsRect bounds =
(mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
nsRect(0, 0, 0, 0));
bool dummy;
gfx3DMatrix matrix =
nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform,
mStyleContextHolder,
mStyleContextHolder->PresContext(),
dummy,
bounds,
float(nsDeviceContext::AppUnitsPerCSSPixel()));
bool is3D = !matrix.Is2D();
nsAutoString resultString(NS_LITERAL_STRING("matrix"));
if (is3D) {
resultString.Append(NS_LITERAL_STRING("3d"));
}
resultString.Append(NS_LITERAL_STRING("("));
resultString.AppendFloat(matrix._11);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._12);
resultString.Append(NS_LITERAL_STRING(", "));
if (is3D) {
resultString.AppendFloat(matrix._13);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._14);
resultString.Append(NS_LITERAL_STRING(", "));
}
resultString.AppendFloat(matrix._21);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._22);
resultString.Append(NS_LITERAL_STRING(", "));
if (is3D) {
resultString.AppendFloat(matrix._23);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._24);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._31);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._32);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._33);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._34);
resultString.Append(NS_LITERAL_STRING(", "));
}
resultString.AppendFloat(matrix._41);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._42);
if (is3D) {
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._43);
resultString.Append(NS_LITERAL_STRING(", "));
resultString.AppendFloat(matrix._44);
}
resultString.Append(NS_LITERAL_STRING(")"));
/* Create a value to hold our result. */
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetString(resultString);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetCounterReset()
{
const nsStyleContent *content = GetStyleContent();
if (content->CounterResetCount() == 0) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
for (PRUint32 i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(name);
nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(value);
const nsStyleCounterData *data = content->GetCounterResetAt(i);
nsAutoString escaped;
nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
name->SetString(escaped);
value->SetNumber(data->mValue); // XXX This should really be integer
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetQuotes()
{
const nsStyleQuotes *quotes = GetStyleQuotes();
if (quotes->QuotesCount() == 0) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
for (PRUint32 i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
nsROCSSPrimitiveValue* openVal = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(openVal);
nsROCSSPrimitiveValue* closeVal = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(closeVal);
nsString s;
nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s);
openVal->SetString(s);
s.Truncate();
nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s);
closeVal->SetString(s);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontFamily()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleFont* font = GetStyleFont();
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocumentWeak);
NS_ASSERTION(doc, "document is required");
nsIPresShell* presShell = doc->GetShell();
NS_ASSERTION(presShell, "pres shell is required");
nsPresContext *presContext = presShell->GetPresContext();
NS_ASSERTION(presContext, "pres context is required");
const nsString& fontName = font->mFont.name;
if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) {
const nsFont* defaultFont =
presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
font->mLanguage);
PRInt32 lendiff = fontName.Length() - defaultFont->name.Length();
if (lendiff > 0) {
val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma
} else {
val->SetString(fontName);
}
} else {
val->SetString(fontName);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontSize()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
// Note: GetStyleFont()->mSize is the 'computed size';
// GetStyleFont()->mFont.size is the 'actual size'
val->SetAppUnits(GetStyleFont()->mSize);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontSizeAdjust()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleFont *font = GetStyleFont();
if (font->mFont.sizeAdjust) {
val->SetNumber(font->mFont.sizeAdjust);
} else {
val->SetIdent(eCSSKeyword_none);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontStretch()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleFont()->mFont.stretch,
nsCSSProps::kFontStretchKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontStyle()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleFont()->mFont.style,
nsCSSProps::kFontStyleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontWeight()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleFont* font = GetStyleFont();
PRUint16 weight = font->mFont.weight;
if (weight % 100 == 0) {
val->SetNumber(font->mFont.weight);
} else if (weight % 100 > 50) {
// FIXME: This doesn't represent the full range of computed values,
// but at least it's legal CSS.
val->SetIdent(eCSSKeyword_lighter);
} else {
// FIXME: This doesn't represent the full range of computed values,
// but at least it's legal CSS.
val->SetIdent(eCSSKeyword_bolder);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFontVariant()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleFont()->mFont.variant,
nsCSSProps::kFontVariantKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozFontFeatureSettings()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleFont* font = GetStyleFont();
if (font->mFont.featureSettings.IsEmpty()) {
val->SetIdent(eCSSKeyword_normal);
} else {
nsString str;
nsStyleUtil::AppendEscapedCSSString(font->mFont.featureSettings, str);
val->SetString(str);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozFontLanguageOverride()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleFont* font = GetStyleFont();
if (font->mFont.languageOverride.IsEmpty()) {
val->SetIdent(eCSSKeyword_normal);
} else {
nsString str;
nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
val->SetString(str);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetBackgroundList(PRUint8 nsStyleBackground::Layer::* aMember,
PRUint32 nsStyleBackground::* aCount,
const PRInt32 aTable[])
{
const nsStyleBackground* bg = GetStyleBackground();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (PRUint32 i = 0, i_end = bg->*aCount; i < i_end; ++i) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
aTable));
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundAttachment()
{
return GetBackgroundList(&nsStyleBackground::Layer::mAttachment,
&nsStyleBackground::mAttachmentCount,
nsCSSProps::kBackgroundAttachmentKTable);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundClip()
{
return GetBackgroundList(&nsStyleBackground::Layer::mClip,
&nsStyleBackground::mClipCount,
nsCSSProps::kBackgroundOriginKTable);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundColor()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
SetToRGBAColor(val, GetStyleBackground()->mBackgroundColor);
return val;
}
static void
SetValueToCalc(const nsStyleCoord::Calc *aCalc, nsROCSSPrimitiveValue *aValue)
{
nsRefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue();
nsAutoString tmp, result;
result.AppendLiteral("-moz-calc(");
val->SetAppUnits(aCalc->mLength);
val->GetCssText(tmp);
result.Append(tmp);
if (aCalc->mHasPercent) {
result.AppendLiteral(" + ");
val->SetPercent(aCalc->mPercent);
val->GetCssText(tmp);
result.Append(tmp);
}
result.AppendLiteral(")");
aValue->SetString(result); // not really SetString
}
static void
AppendCSSGradientLength(const nsStyleCoord& aValue,
nsROCSSPrimitiveValue* aPrimitive,
nsAString& aString)
{
nsAutoString tokenString;
if (aValue.IsCalcUnit())
SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
else if (aValue.GetUnit() == eStyleUnit_Coord)
aPrimitive->SetAppUnits(aValue.GetCoordValue());
else
aPrimitive->SetPercent(aValue.GetPercentValue());
aPrimitive->GetCssText(tokenString);
aString.Append(tokenString);
}
static void
AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
nsAString& aString,
bool& aNeedSep)
{
float xValue = aGradient->mBgPosX.GetPercentValue();
float yValue = aGradient->mBgPosY.GetPercentValue();
if (yValue == 1.0f && xValue == 0.5f) {
// omit "to bottom"
return;
}
NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
aString.AppendLiteral("to");
if (yValue == 0.0f) {
aString.AppendLiteral(" top");
} else if (yValue == 1.0f) {
aString.AppendLiteral(" bottom");
} else if (yValue != 0.5f) { // do not write "center" keyword
NS_NOTREACHED("invalid box position");
}
if (xValue == 0.0f) {
aString.AppendLiteral(" left");
} else if (xValue == 1.0f) {
aString.AppendLiteral(" right");
} else if (xValue != 0.5f) { // do not write "center" keyword
NS_NOTREACHED("invalid box position");
}
aNeedSep = true;
}
void
nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
nsAString& aString)
{
if (aGradient->mRepeating) {
if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR)
aString.AssignLiteral("-moz-repeating-linear-gradient(");
else
aString.AssignLiteral("-moz-repeating-radial-gradient(");
} else {
if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR)
aString.AssignLiteral("-moz-linear-gradient(");
else
aString.AssignLiteral("-moz-radial-gradient(");
}
bool needSep = false;
nsAutoString tokenString;
nsROCSSPrimitiveValue *tmpVal = GetROCSSPrimitiveValue();
if (aGradient->mToCorner) {
AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
} else {
if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
needSep = true;
}
if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
if (needSep) {
aString.AppendLiteral(" ");
}
AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
needSep = true;
}
}
if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
if (needSep) {
aString.AppendLiteral(" ");
}
tmpVal->SetNumber(aGradient->mAngle.GetAngleValue());
tmpVal->GetCssText(tokenString);
aString.Append(tokenString);
switch (aGradient->mAngle.GetUnit()) {
case eStyleUnit_Degree: aString.AppendLiteral("deg"); break;
case eStyleUnit_Grad: aString.AppendLiteral("grad"); break;
case eStyleUnit_Radian: aString.AppendLiteral("rad"); break;
case eStyleUnit_Turn: aString.AppendLiteral("turn"); break;
default: NS_NOTREACHED("unrecognized angle unit");
}
needSep = true;
}
if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR) {
if (needSep) {
aString.AppendLiteral(", ");
}
AppendASCIItoUTF16(nsCSSProps::
ValueToKeyword(aGradient->mShape,
nsCSSProps::kRadialGradientShapeKTable),
aString);
if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
aString.AppendLiteral(" ");
AppendASCIItoUTF16(nsCSSProps::
ValueToKeyword(aGradient->mSize,
nsCSSProps::kRadialGradientSizeKTable),
aString);
}
needSep = true;
}
// color stops
for (PRUint32 i = 0; i < aGradient->mStops.Length(); ++i) {
if (needSep) {
aString.AppendLiteral(", ");
}
SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor);
tmpVal->GetCssText(tokenString);
aString.Append(tokenString);
if (aGradient->mStops[i].mLocation.GetUnit() != eStyleUnit_None) {
aString.AppendLiteral(" ");
AppendCSSGradientLength(aGradient->mStops[i].mLocation, tmpVal, aString);
}
needSep = true;
}
delete tmpVal;
aString.AppendLiteral(")");
}
// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
void
nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
const nsStyleSides& aCropRect,
nsString& aString)
{
nsDOMCSSValueList* valueList = GetROCSSValueList(true);
// <uri>
nsROCSSPrimitiveValue *valURI = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valURI);
valURI->SetURI(aURI);
// <top>, <right>, <bottom>, <left>
NS_FOR_CSS_SIDES(side) {
nsROCSSPrimitiveValue *valSide = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valSide);
SetValueToCoord(valSide, aCropRect.Get(side), false);
}
nsAutoString argumentString;
valueList->GetCssText(argumentString);
delete valueList;
aString = NS_LITERAL_STRING("-moz-image-rect(") +
argumentString +
NS_LITERAL_STRING(")");
}
void
nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
nsROCSSPrimitiveValue* aValue)
{
switch (aStyleImage.GetType()) {
case eStyleImageType_Image:
{
imgIRequest *req = aStyleImage.GetImageData();
nsCOMPtr<nsIURI> uri;
req->GetURI(getter_AddRefs(uri));
const nsStyleSides* cropRect = aStyleImage.GetCropRect();
if (cropRect) {
nsAutoString imageRectString;
GetImageRectString(uri, *cropRect, imageRectString);
aValue->SetString(imageRectString);
} else {
aValue->SetURI(uri);
}
break;
}
case eStyleImageType_Gradient:
{
nsAutoString gradientString;
GetCSSGradientString(aStyleImage.GetGradientData(),
gradientString);
aValue->SetString(gradientString);
break;
}
case eStyleImageType_Element:
{
nsAutoString elementId;
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentString(aStyleImage.GetElementId()), elementId);
nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
elementId +
NS_LITERAL_STRING(")");
aValue->SetString(elementString);
break;
}
case eStyleImageType_Null:
aValue->SetIdent(eCSSKeyword_none);
break;
default:
NS_NOTREACHED("unexpected image type");
break;
}
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundImage()
{
const nsStyleBackground* bg = GetStyleBackground();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (PRUint32 i = 0, i_end = bg->mImageCount; i < i_end; ++i) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
const nsStyleImage& image = bg->mLayers[i].mImage;
SetValueToStyleImage(image, val);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundInlinePolicy()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(
GetStyleBackground()->mBackgroundInlinePolicy,
nsCSSProps::kBackgroundInlinePolicyKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundOrigin()
{
return GetBackgroundList(&nsStyleBackground::Layer::mOrigin,
&nsStyleBackground::mOriginCount,
nsCSSProps::kBackgroundOriginKTable);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundPosition()
{
const nsStyleBackground* bg = GetStyleBackground();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (PRUint32 i = 0, i_end = bg->mPositionCount; i < i_end; ++i) {
nsDOMCSSValueList *itemList = GetROCSSValueList(false);
valueList->AppendCSSValue(itemList);
nsROCSSPrimitiveValue *valX = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valX);
nsROCSSPrimitiveValue *valY = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valY);
const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition;
if (!pos.mXPosition.mHasPercent) {
NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f,
"Shouldn't have mPercent!");
valX->SetAppUnits(pos.mXPosition.mLength);
} else if (pos.mXPosition.mLength == 0) {
valX->SetPercent(pos.mXPosition.mPercent);
} else {
SetValueToCalc(&pos.mXPosition, valX);
}
if (!pos.mYPosition.mHasPercent) {
NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f,
"Shouldn't have mPercent!");
valY->SetAppUnits(pos.mYPosition.mLength);
} else if (pos.mYPosition.mLength == 0) {
valY->SetPercent(pos.mYPosition.mPercent);
} else {
SetValueToCalc(&pos.mYPosition, valY);
}
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBackgroundRepeat()
{
return GetBackgroundList(&nsStyleBackground::Layer::mRepeat,
&nsStyleBackground::mRepeatCount,
nsCSSProps::kBackgroundRepeatKTable);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozBackgroundSize()
{
const nsStyleBackground* bg = GetStyleBackground();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (PRUint32 i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
switch (size.mWidthType) {
case nsStyleBackground::Size::eContain:
case nsStyleBackground::Size::eCover: {
NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType,
"unsynced types");
nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain
? eCSSKeyword_contain
: eCSSKeyword_cover;
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
val->SetIdent(keyword);
break;
}
default: {
nsDOMCSSValueList *itemList = GetROCSSValueList(false);
valueList->AppendCSSValue(itemList);
nsROCSSPrimitiveValue* valX = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valX);
nsROCSSPrimitiveValue* valY = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valY);
if (size.mWidthType == nsStyleBackground::Size::eAuto) {
valX->SetIdent(eCSSKeyword_auto);
} else {
NS_ABORT_IF_FALSE(size.mWidthType ==
nsStyleBackground::Size::eLengthPercentage,
"bad mWidthType");
if (!size.mWidth.mHasPercent &&
// negative values must have come from calc()
size.mWidth.mLength >= 0) {
NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f,
"Shouldn't have mPercent");
valX->SetAppUnits(size.mWidth.mLength);
} else if (size.mWidth.mLength == 0 &&
// negative values must have come from calc()
size.mWidth.mPercent >= 0.0f) {
valX->SetPercent(size.mWidth.mPercent);
} else {
SetValueToCalc(&size.mWidth, valX);
}
}
if (size.mHeightType == nsStyleBackground::Size::eAuto) {
valY->SetIdent(eCSSKeyword_auto);
} else {
NS_ABORT_IF_FALSE(size.mHeightType ==
nsStyleBackground::Size::eLengthPercentage,
"bad mHeightType");
if (!size.mHeight.mHasPercent &&
// negative values must have come from calc()
size.mHeight.mLength >= 0) {
NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f,
"Shouldn't have mPercent");
valY->SetAppUnits(size.mHeight.mLength);
} else if (size.mHeight.mLength == 0 &&
// negative values must have come from calc()
size.mHeight.mPercent >= 0.0f) {
valY->SetPercent(size.mHeight.mPercent);
} else {
SetValueToCalc(&size.mHeight, valY);
}
}
break;
}
}
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPadding()
{
// return null per spec.
return nsnull;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPaddingTop()
{
return GetPaddingWidthFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPaddingBottom()
{
return GetPaddingWidthFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPaddingLeft()
{
return GetPaddingWidthFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPaddingRight()
{
return GetPaddingWidthFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderCollapse()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTableBorder()->mBorderCollapse,
nsCSSProps::kBorderCollapseKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderSpacing()
{
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
nsROCSSPrimitiveValue* xSpacing = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(xSpacing);
nsROCSSPrimitiveValue* ySpacing = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(ySpacing);
const nsStyleTableBorder *border = GetStyleTableBorder();
xSpacing->SetAppUnits(border->mBorderSpacingX);
ySpacing->SetAppUnits(border->mBorderSpacingY);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetCaptionSide()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTableBorder()->mCaptionSide,
nsCSSProps::kCaptionSideKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetEmptyCells()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTableBorder()->mEmptyCells,
nsCSSProps::kEmptyCellsKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTableLayout()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTable()->mLayoutStrategy,
nsCSSProps::kTableLayoutKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderStyle()
{
// return null per spec.
return nsnull;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopStyle()
{
return GetBorderStyleFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomStyle()
{
return GetBorderStyleFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderLeftStyle()
{
return GetBorderStyleFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderRightStyle()
{
return GetBorderStyleFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomColors()
{
return GetBorderColorsFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderLeftColors()
{
return GetBorderColorsFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderRightColors()
{
return GetBorderColorsFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopColors()
{
return GetBorderColorsFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
{
return GetEllipseRadii(GetStyleBorder()->mBorderRadius,
NS_CORNER_BOTTOM_LEFT, true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomRightRadius()
{
return GetEllipseRadii(GetStyleBorder()->mBorderRadius,
NS_CORNER_BOTTOM_RIGHT, true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopLeftRadius()
{
return GetEllipseRadii(GetStyleBorder()->mBorderRadius,
NS_CORNER_TOP_LEFT, true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopRightRadius()
{
return GetEllipseRadii(GetStyleBorder()->mBorderRadius,
NS_CORNER_TOP_RIGHT, true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderWidth()
{
// return null per spec.
return nsnull;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopWidth()
{
return GetBorderWidthFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomWidth()
{
return GetBorderWidthFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderLeftWidth()
{
return GetBorderWidthFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderRightWidth()
{
return GetBorderWidthFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderTopColor()
{
return GetBorderColorFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderBottomColor()
{
return GetBorderColorFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderLeftColor()
{
return GetBorderColorFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderRightColor()
{
return GetBorderColorFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarginWidth()
{
// return null per spec.
return nsnull;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarginTopWidth()
{
return GetMarginWidthFor(NS_SIDE_TOP);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarginBottomWidth()
{
return GetMarginWidthFor(NS_SIDE_BOTTOM);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarginLeftWidth()
{
return GetMarginWidthFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarginRightWidth()
{
return GetMarginWidthFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarkerOffset()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleContent()->mMarkerOffset, false);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOrient()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mOrient,
nsCSSProps::kOrientKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutline()
{
// return null per spec.
return nsnull;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineWidth()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleOutline* outline = GetStyleOutline();
nscoord width;
if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0,
"unexpected width");
width = 0;
} else {
#ifdef DEBUG
bool res =
#endif
outline->GetOutlineWidth(width);
NS_ASSERTION(res, "percent outline doesn't exist");
}
val->SetAppUnits(width);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineStyle()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleOutline()->GetOutlineStyle(),
nsCSSProps::kOutlineStyleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineOffset()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetAppUnits(GetStyleOutline()->mOutlineOffset);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
{
return GetEllipseRadii(GetStyleOutline()->mOutlineRadius,
NS_CORNER_BOTTOM_LEFT, false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
{
return GetEllipseRadii(GetStyleOutline()->mOutlineRadius,
NS_CORNER_BOTTOM_RIGHT, false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
{
return GetEllipseRadii(GetStyleOutline()->mOutlineRadius,
NS_CORNER_TOP_LEFT, false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
{
return GetEllipseRadii(GetStyleOutline()->mOutlineRadius,
NS_CORNER_TOP_RIGHT, false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOutlineColor()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
nscolor color;
if (!GetStyleOutline()->GetOutlineColor(color))
color = GetStyleColor()->mColor;
SetToRGBAColor(val, color);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
PRUint8 aFullCorner,
bool aIsBorder) // else outline
{
nsStyleCoord radiusX, radiusY;
if (mInnerFrame && aIsBorder) {
nscoord radii[8];
mInnerFrame->GetBorderRadii(radii);
radiusX.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, false)]);
radiusY.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, true)]);
} else {
radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false));
radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true));
if (mInnerFrame) {
// We need to convert to absolute coordinates before doing the
// equality check below.
nscoord v;
v = StyleCoordToNSCoord(radiusX,
&nsComputedDOMStyle::GetFrameBorderRectWidth,
0, true);
radiusX.SetCoordValue(v);
v = StyleCoordToNSCoord(radiusY,
&nsComputedDOMStyle::GetFrameBorderRectHeight,
0, true);
radiusY.SetCoordValue(v);
}
}
// for compatibility, return a single value if X and Y are equal
if (radiusX == radiusY) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, radiusX, true);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
nsROCSSPrimitiveValue *valX = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valX);
nsROCSSPrimitiveValue *valY = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valY);
SetValueToCoord(valX, radiusX, true);
SetValueToCoord(valY, radiusY, true);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
const nscolor& aDefaultColor,
bool aIsBoxShadow)
{
if (!aArray) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
&nsCSSShadowItem::mXOffset,
&nsCSSShadowItem::mYOffset,
&nsCSSShadowItem::mRadius
};
static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
&nsCSSShadowItem::mXOffset,
&nsCSSShadowItem::mYOffset,
&nsCSSShadowItem::mRadius,
&nsCSSShadowItem::mSpread
};
nscoord nsCSSShadowItem::* const * shadowValues;
PRUint32 shadowValuesLength;
if (aIsBoxShadow) {
shadowValues = shadowValuesWithSpread;
shadowValuesLength = ArrayLength(shadowValuesWithSpread);
} else {
shadowValues = shadowValuesNoSpread;
shadowValuesLength = ArrayLength(shadowValuesNoSpread);
}
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (nsCSSShadowItem *item = aArray->ShadowAt(0),
*item_end = item + aArray->Length();
item < item_end; ++item) {
nsDOMCSSValueList *itemList = GetROCSSValueList(false);
valueList->AppendCSSValue(itemList);
// Color is either the specified shadow color or the foreground color
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(val);
nscolor shadowColor;
if (item->mHasColor) {
shadowColor = item->mColor;
} else {
shadowColor = aDefaultColor;
}
SetToRGBAColor(val, shadowColor);
// Set the offsets, blur radius, and spread if available
for (PRUint32 i = 0; i < shadowValuesLength; ++i) {
val = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(val);
val->SetAppUnits(item->*(shadowValues[i]));
}
if (item->mInset && aIsBoxShadow) {
// This is an inset box-shadow
val = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(val);
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
nsCSSProps::kBoxShadowTypeKTable));
}
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxShadow()
{
return GetCSSShadowArray(GetStyleBorder()->mBoxShadow,
GetStyleColor()->mColor,
true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetZIndex()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mZIndex, false);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetListStyleImage()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleList* list = GetStyleList();
if (!list->GetListStyleImage()) {
val->SetIdent(eCSSKeyword_none);
} else {
nsCOMPtr<nsIURI> uri;
if (list->GetListStyleImage()) {
list->GetListStyleImage()->GetURI(getter_AddRefs(uri));
}
val->SetURI(uri);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetListStylePosition()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleList()->mListStylePosition,
nsCSSProps::kListStylePositionKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetListStyleType()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleList()->mListStyleType,
nsCSSProps::kListStyleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetImageRegion()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleList* list = GetStyleList();
if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
val->SetIdent(eCSSKeyword_auto);
} else {
// create the cssvalues for the sides, stick them in the rect object
nsROCSSPrimitiveValue *topVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *rightVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *bottomVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *leftVal = GetROCSSPrimitiveValue();
nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
bottomVal, leftVal);
topVal->SetAppUnits(list->mImageRegion.y);
rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
leftVal->SetAppUnits(list->mImageRegion.x);
val->SetRect(domRect);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetLineHeight()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
nscoord lineHeight;
if (GetLineHeightCoord(lineHeight)) {
val->SetAppUnits(lineHeight);
} else {
SetValueToCoord(val, GetStyleText()->mLineHeight, true,
nsnull, nsCSSProps::kLineHeightKTable);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetVerticalAlign()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleTextReset()->mVerticalAlign, false,
&nsComputedDOMStyle::GetLineHeightCoord,
nsCSSProps::kVerticalAlignKTable);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextAlign()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mTextAlign,
nsCSSProps::kTextAlignKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextAlignLast()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mTextAlignLast,
nsCSSProps::kTextAlignLastKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTextBlink()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTextReset()->mTextBlink,
nsCSSProps::kTextBlinkKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextDecoration()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleTextReset* textReset = GetStyleTextReset();
// If decoration style or color wasn't initial value, the author knew the
// text-decoration is a shorthand property in CSS 3.
// Return NULL in such cases.
if (textReset->GetDecorationStyle() != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
return nsnull;
}
nscolor color;
bool isForegroundColor;
textReset->GetDecorationColor(color, isForegroundColor);
if (!isForegroundColor) {
return nsnull;
}
// Otherwise, the web pages may have been written for CSS 2.1 or earlier,
// i.e., text-decoration was assumed as a longhand property. In that case,
// we should return computed value same as CSS 2.1 for backward compatibility.
PRUint8 line = textReset->mTextDecorationLine;
// Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
// don't want these to appear in the computed style.
line &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
PRUint8 blink = textReset->mTextBlink;
if (blink == NS_STYLE_TEXT_BLINK_NONE &&
line == NS_STYLE_TEXT_DECORATION_LINE_NONE) {
val->SetIdent(eCSSKeyword_none);
} else {
nsAutoString str;
if (line != NS_STYLE_TEXT_DECORATION_LINE_NONE) {
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, str);
}
if (blink != NS_STYLE_TEXT_BLINK_NONE) {
if (!str.IsEmpty()) {
str.Append(PRUnichar(' '));
}
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_blink, blink,
NS_STYLE_TEXT_BLINK_BLINK, NS_STYLE_TEXT_BLINK_BLINK, str);
}
val->SetString(str);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTextDecorationColor()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
nscolor color;
bool isForeground;
GetStyleTextReset()->GetDecorationColor(color, isForeground);
if (isForeground) {
color = GetStyleColor()->mColor;
}
SetToRGBAColor(val, color);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTextDecorationLine()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
PRInt32 intValue = GetStyleTextReset()->mTextDecorationLine;
if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
val->SetIdent(eCSSKeyword_none);
} else {
nsAutoString decorationLineString;
// Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
// don't want these to appear in the computed style.
intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationLineString);
val->SetString(decorationLineString);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTextDecorationStyle()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleTextReset()->GetDecorationStyle(),
nsCSSProps::kTextDecorationStyleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextIndent()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleText()->mTextIndent, false,
&nsComputedDOMStyle::GetCBContentWidth);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextOverflow()
{
const nsStyleTextReset *style = GetStyleTextReset();
nsROCSSPrimitiveValue *first = GetROCSSPrimitiveValue();
const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
nsString str;
nsStyleUtil::AppendEscapedCSSString(side->mString, str);
first->SetString(str);
} else {
first->SetIdent(
nsCSSProps::ValueToKeywordEnum(side->mType,
nsCSSProps::kTextOverflowKTable));
}
side = style->mTextOverflow.GetSecondValue();
if (!side) {
return first;
}
nsROCSSPrimitiveValue *second = GetROCSSPrimitiveValue();
if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
nsString str;
nsStyleUtil::AppendEscapedCSSString(side->mString, str);
second->SetString(str);
} else {
second->SetIdent(
nsCSSProps::ValueToKeywordEnum(side->mType,
nsCSSProps::kTextOverflowKTable));
}
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
valueList->AppendCSSValue(first);
valueList->AppendCSSValue(second);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextShadow()
{
return GetCSSShadowArray(GetStyleText()->mTextShadow,
GetStyleColor()->mColor,
false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextTransform()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mTextTransform,
nsCSSProps::kTextTransformKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTabSize()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleText()->mTabSize);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetLetterSpacing()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleText()->mLetterSpacing, false);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetWordSpacing()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetAppUnits(GetStyleText()->mWordSpacing);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetWhiteSpace()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mWhiteSpace,
nsCSSProps::kWhitespaceKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetWindowShadow()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUIReset()->mWindowShadow,
nsCSSProps::kWindowShadowKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetWordWrap()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mWordWrap,
nsCSSProps::kWordwrapKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetHyphens()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mHyphens,
nsCSSProps::kHyphensKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextSizeAdjust()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
switch (GetStyleText()->mTextSizeAdjust) {
default:
NS_NOTREACHED("unexpected value");
// fall through
case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
val->SetIdent(eCSSKeyword_auto);
break;
case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
val->SetIdent(eCSSKeyword_none);
break;
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPointerEvents()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleVisibility()->mPointerEvents,
nsCSSProps::kPointerEventsKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetVisibility()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleVisibility()->mVisible,
nsCSSProps::kVisibilityKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetDirection()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleVisibility()->mDirection,
nsCSSProps::kDirectionKTable));
return val;
}
MOZ_STATIC_ASSERT(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
"unicode-bidi style constants not as expected");
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetUnicodeBidi()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
PRInt32 intValue = GetStyleTextReset()->mUnicodeBidi;
if (NS_STYLE_UNICODE_BIDI_NORMAL == intValue) {
val->SetIdent(eCSSKeyword_normal);
} else {
nsAutoString unicodeBidiString;
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_unicode_bidi, intValue,
NS_STYLE_UNICODE_BIDI_EMBED,
NS_STYLE_UNICODE_BIDI_PLAINTEXT,
unicodeBidiString);
val->SetString(unicodeBidiString);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetCursor()
{
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
const nsStyleUserInterface *ui = GetStyleUserInterface();
for (nsCursorImage *item = ui->mCursorArray,
*item_end = ui->mCursorArray + ui->mCursorArrayLength;
item < item_end; ++item) {
nsDOMCSSValueList *itemList = GetROCSSValueList(false);
valueList->AppendCSSValue(itemList);
nsCOMPtr<nsIURI> uri;
item->GetImage()->GetURI(getter_AddRefs(uri));
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(val);
val->SetURI(uri);
if (item->mHaveHotspot) {
nsROCSSPrimitiveValue *valX = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valX);
nsROCSSPrimitiveValue *valY = GetROCSSPrimitiveValue();
itemList->AppendCSSValue(valY);
valX->SetNumber(item->mHotspotX);
valY->SetNumber(item->mHotspotY);
}
}
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
nsCSSProps::kCursorKTable));
valueList->AppendCSSValue(val);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAppearance()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mAppearance,
nsCSSProps::kAppearanceKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxAlign()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleXUL()->mBoxAlign,
nsCSSProps::kBoxAlignKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxDirection()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleXUL()->mBoxDirection,
nsCSSProps::kBoxDirectionKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxFlex()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleXUL()->mBoxFlex);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxOrdinalGroup()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleXUL()->mBoxOrdinal);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxOrient()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleXUL()->mBoxOrient,
nsCSSProps::kBoxOrientKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxPack()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleXUL()->mBoxPack,
nsCSSProps::kBoxPackKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBoxSizing()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStylePosition()->mBoxSizing,
nsCSSProps::kBoxSizingKTable));
return val;
}
/* Border image properties */
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderImageSource()
{
const nsStyleBorder* border = GetStyleBorder();
imgIRequest* imgSrc = border->GetBorderImage();
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
if (imgSrc) {
nsCOMPtr<nsIURI> uri;
imgSrc->GetURI(getter_AddRefs(uri));
val->SetURI(uri);
} else {
val->SetIdent(eCSSKeyword_none);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderImageSlice()
{
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
const nsStyleBorder* border = GetStyleBorder();
// Four slice numbers.
NS_FOR_CSS_SIDES (side) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
SetValueToCoord(val, border->mBorderImageSlice.Get(side), nsnull, nsnull);
}
// Fill keyword.
if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
val->SetIdent(eCSSKeyword_fill);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderImageWidth()
{
const nsStyleBorder* border = GetStyleBorder();
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
NS_FOR_CSS_SIDES (side) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
SetValueToCoord(val, border->mBorderImageWidth.Get(side),
nsnull, nsnull);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderImageOutset()
{
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
const nsStyleBorder* border = GetStyleBorder();
// four slice numbers
NS_FOR_CSS_SIDES (side) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(val);
SetValueToCoord(val, border->mBorderImageOutset.Get(side),
nsnull, nsnull);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetBorderImageRepeat()
{
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
const nsStyleBorder* border = GetStyleBorder();
// horizontal repeat
nsROCSSPrimitiveValue* valX = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valX);
valX->SetIdent(
nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
nsCSSProps::kBorderImageRepeatKTable));
// vertical repeat
nsROCSSPrimitiveValue* valY = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(valY);
valY->SetIdent(
nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
nsCSSProps::kBorderImageRepeatKTable));
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFloatEdge()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleBorder()->mFloatEdge,
nsCSSProps::kFloatEdgeKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetForceBrokenImageIcon()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleUIReset()->mForceBrokenImageIcon);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetIMEMode()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUIReset()->mIMEMode,
nsCSSProps::kIMEModeKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetUserFocus()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUserInterface()->mUserFocus,
nsCSSProps::kUserFocusKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetUserInput()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUserInterface()->mUserInput,
nsCSSProps::kUserInputKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetUserModify()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUserInterface()->mUserModify,
nsCSSProps::kUserModifyKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetUserSelect()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleUIReset()->mUserSelect,
nsCSSProps::kUserSelectKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetDisplay()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mDisplay,
nsCSSProps::kDisplayKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPosition()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mPosition,
nsCSSProps::kPositionKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetClip()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleDisplay* display = GetStyleDisplay();
if (display->mClipFlags == NS_STYLE_CLIP_AUTO) {
val->SetIdent(eCSSKeyword_auto);
} else {
// create the cssvalues for the sides, stick them in the rect object
nsROCSSPrimitiveValue *topVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *rightVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *bottomVal = GetROCSSPrimitiveValue();
nsROCSSPrimitiveValue *leftVal = GetROCSSPrimitiveValue();
nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
bottomVal, leftVal);
if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
topVal->SetIdent(eCSSKeyword_auto);
} else {
topVal->SetAppUnits(display->mClip.y);
}
if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
rightVal->SetIdent(eCSSKeyword_auto);
} else {
rightVal->SetAppUnits(display->mClip.width + display->mClip.x);
}
if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
bottomVal->SetIdent(eCSSKeyword_auto);
} else {
bottomVal->SetAppUnits(display->mClip.height + display->mClip.y);
}
if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
leftVal->SetIdent(eCSSKeyword_auto);
} else {
leftVal->SetAppUnits(display->mClip.x);
}
val->SetRect(domRect);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOverflow()
{
const nsStyleDisplay* display = GetStyleDisplay();
if (display->mOverflowX != display->mOverflowY) {
// No value to return. We can't express this combination of
// values as a shorthand.
return nsnull;
}
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
nsCSSProps::kOverflowKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOverflowX()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mOverflowX,
nsCSSProps::kOverflowSubKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetOverflowY()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mOverflowY,
nsCSSProps::kOverflowSubKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetResize()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mResize,
nsCSSProps::kResizeKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPageBreakAfter()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleDisplay *display = GetStyleDisplay();
if (display->mBreakAfter) {
val->SetIdent(eCSSKeyword_always);
} else {
val->SetIdent(eCSSKeyword_auto);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetPageBreakBefore()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStyleDisplay *display = GetStyleDisplay();
if (display->mBreakBefore) {
val->SetIdent(eCSSKeyword_always);
} else {
val->SetIdent(eCSSKeyword_auto);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetHeight()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
bool calcHeight = false;
if (mInnerFrame) {
calcHeight = true;
const nsStyleDisplay* displayData = GetStyleDisplay();
if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
!(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced))) {
calcHeight = false;
}
}
if (calcHeight) {
AssertFlushedPendingReflows();
val->SetAppUnits(mInnerFrame->GetContentRect().height);
} else {
const nsStylePosition *positionData = GetStylePosition();
nscoord minHeight =
StyleCoordToNSCoord(positionData->mMinHeight,
&nsComputedDOMStyle::GetCBContentHeight, 0, true);
nscoord maxHeight =
StyleCoordToNSCoord(positionData->mMaxHeight,
&nsComputedDOMStyle::GetCBContentHeight,
nscoord_MAX, true);
SetValueToCoord(val, positionData->mHeight, true, nsnull, nsnull,
minHeight, maxHeight);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetWidth()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
bool calcWidth = false;
if (mInnerFrame) {
calcWidth = true;
const nsStyleDisplay *displayData = GetStyleDisplay();
if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
!(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced))) {
calcWidth = false;
}
}
if (calcWidth) {
AssertFlushedPendingReflows();
val->SetAppUnits(mInnerFrame->GetContentRect().width);
} else {
const nsStylePosition *positionData = GetStylePosition();
nscoord minWidth =
StyleCoordToNSCoord(positionData->mMinWidth,
&nsComputedDOMStyle::GetCBContentWidth, 0, true);
nscoord maxWidth =
StyleCoordToNSCoord(positionData->mMaxWidth,
&nsComputedDOMStyle::GetCBContentWidth,
nscoord_MAX, true);
SetValueToCoord(val, positionData->mWidth, true, nsnull,
nsCSSProps::kWidthKTable, minWidth, maxWidth);
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMaxHeight()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mMaxHeight, true,
&nsComputedDOMStyle::GetCBContentHeight);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMaxWidth()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mMaxWidth, true,
&nsComputedDOMStyle::GetCBContentWidth,
nsCSSProps::kWidthKTable);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMinHeight()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mMinHeight, true,
&nsComputedDOMStyle::GetCBContentHeight);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMinWidth()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mMinWidth, true,
&nsComputedDOMStyle::GetCBContentWidth,
nsCSSProps::kWidthKTable);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetLeft()
{
return GetOffsetWidthFor(NS_SIDE_LEFT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetRight()
{
return GetOffsetWidthFor(NS_SIDE_RIGHT);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTop()
{
return GetOffsetWidthFor(NS_SIDE_TOP);
}
nsROCSSPrimitiveValue*
nsComputedDOMStyle::GetROCSSPrimitiveValue()
{
nsROCSSPrimitiveValue *primitiveValue = new nsROCSSPrimitiveValue();
NS_ASSERTION(primitiveValue != 0, "ran out of memory");
return primitiveValue;
}
nsDOMCSSValueList*
nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
{
nsDOMCSSValueList *valueList = new nsDOMCSSValueList(aCommaDelimited,
true);
NS_ASSERTION(valueList != 0, "ran out of memory");
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
{
const nsStyleDisplay* display = GetStyleDisplay();
2000-05-17 06:26:23 +00:00
AssertFlushedPendingReflows();
PRUint8 position = display->mPosition;
if (!mOuterFrame) {
// GetRelativeOffset and GetAbsoluteOffset don't handle elements
// without frames in any sensible way. GetStaticOffset, however,
// is perfect for that case.
position = NS_STYLE_POSITION_STATIC;
}
switch (position) {
case NS_STYLE_POSITION_STATIC:
return GetStaticOffset(aSide);
case NS_STYLE_POSITION_RELATIVE:
return GetRelativeOffset(aSide);
case NS_STYLE_POSITION_ABSOLUTE:
case NS_STYLE_POSITION_FIXED:
return GetAbsoluteOffset(aSide);
default:
NS_ERROR("Invalid position");
return nsnull;
}
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
nsIFrame* container = GetContainingBlockFor(mOuterFrame);
if (container) {
nsMargin margin = mOuterFrame->GetUsedMargin();
nsMargin border = container->GetUsedBorder();
nsMargin scrollbarSizes(0, 0, 0, 0);
nsRect rect = mOuterFrame->GetRect();
nsRect containerRect = container->GetRect();
if (container->GetType() == nsGkAtoms::viewportFrame) {
// For absolutely positioned frames scrollbars are taken into
// account by virtue of getting a containing block that does
// _not_ include the scrollbars. For fixed positioned frames,
// the containing block is the viewport, which _does_ include
// scrollbars. We have to do some extra work.
// the first child in the default frame list is what we want
nsIFrame* scrollingChild = container->GetFirstPrincipalChild();
nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
if (scrollFrame) {
scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
}
}
nscoord offset = 0;
switch (aSide) {
case NS_SIDE_TOP:
offset = rect.y - margin.top - border.top - scrollbarSizes.top;
break;
case NS_SIDE_RIGHT:
offset = containerRect.width - rect.width -
rect.x - margin.right - border.right - scrollbarSizes.right;
break;
case NS_SIDE_BOTTOM:
offset = containerRect.height - rect.height -
rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
break;
case NS_SIDE_LEFT:
offset = rect.x - margin.left - border.left - scrollbarSizes.left;
break;
default:
NS_ERROR("Invalid side");
break;
}
val->SetAppUnits(offset);
} else {
// XXX no frame. This property makes no sense
val->SetAppUnits(0);
}
return val;
}
MOZ_STATIC_ASSERT(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
"box side constants not as expected for NS_OPPOSITE_SIDE");
#define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
nsIDOMCSSValue*
nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
const nsStylePosition* positionData = GetStylePosition();
PRInt32 sign = 1;
nsStyleCoord coord = positionData->mOffset.Get(aSide);
NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
coord.GetUnit() == eStyleUnit_Percent ||
coord.GetUnit() == eStyleUnit_Auto ||
coord.IsCalcUnit(),
"Unexpected unit");
if (coord.GetUnit() == eStyleUnit_Auto) {
coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
sign = -1;
}
PercentageBaseGetter baseGetter;
if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
} else {
baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
}
val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStylePosition()->mOffset.Get(aSide), false);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
if (!mInnerFrame) {
SetValueToCoord(val, GetStylePadding()->mPadding.Get(aSide), true);
} else {
AssertFlushedPendingReflows();
val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
}
return val;
}
bool
nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
{
AssertFlushedPendingReflows();
nscoord blockHeight = NS_AUTOHEIGHT;
if (GetStyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
if (!mInnerFrame)
return false;
if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
blockHeight = mInnerFrame->GetContentRect().height;
} else {
GetCBContentHeight(blockHeight);
}
}
// lie about font size inflation since we lie about font size (since
// the inflation only applies to text)
aCoord = nsHTMLReflowState::CalcLineHeight(mStyleContextHolder,
blockHeight, 1.0f);
// CalcLineHeight uses font->mFont.size, but we want to use
// font->mSize as the font size. Adjust for that. Also adjust for
// the text zoom, if any.
const nsStyleFont* font = GetStyleFont();
aCoord = NSToCoordRound((float(aCoord) *
(float(font->mSize) / float(font->mFont.size))) /
mPresShell->GetPresContext()->TextZoom());
return true;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
{
const nsStyleBorder *border = GetStyleBorder();
if (border->mBorderColors) {
nsBorderColors* borderColors = border->mBorderColors[aSide];
if (borderColors) {
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
do {
nsROCSSPrimitiveValue *primitive = GetROCSSPrimitiveValue();
SetToRGBAColor(primitive, borderColors->mColor);
valueList->AppendCSSValue(primitive);
borderColors = borderColors->mNext;
} while (borderColors);
return valueList;
}
}
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
nscoord width;
if (mInnerFrame) {
AssertFlushedPendingReflows();
width = mInnerFrame->GetUsedBorder().Side(aSide);
} else {
width = GetStyleBorder()->GetActualBorderWidth(aSide);
}
val->SetAppUnits(width);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
nscolor color;
bool foreground;
GetStyleBorder()->GetBorderColor(aSide, color, foreground);
if (foreground) {
color = GetStyleColor()->mColor;
}
SetToRGBAColor(val, color);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
if (!mInnerFrame) {
SetValueToCoord(val, GetStyleMargin()->mMargin.Get(aSide), false);
} else {
AssertFlushedPendingReflows();
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out without taking their margins into the account, which meant that their width was always equal to the available width. This breaks horizontal positioning of absolutely positioned kids of a table frame. The main purpose of this patch is to apply the margins of tables to their outer frame, instead of the inner frame. This means that the inner table frame will always have a zero margin, which means that a lot of the stuff which used to rely on the fact that table margins are applied to the inner frame need to change. In particular, in order to get the computed margins of a table, we used to query the inner table frame, and this patch corrects that. Also, when shrink wrapping tables, we used to not take the margins of the inner table frame into account, which is fixed by this patch too. nsBlockReflowState:: ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the margin values from the outer frame too. Also, as part of this patch, we start to respect the CSS2.1 margin model for captions on all sides. This means that in particular, the top/bottom margins on the top-outside and bottom-outside captions will not be collapsed with the top/bottom margins of the table, and that the margins of the caption element contribute to the width and height of the outer table frame. The 427129-table-caption reftest has been modified to match this new behavior. Another side effect of this bug is fixing bug 87277, and the reftests for that bug are marked as passing in this patch.
2011-05-31 23:02:56 +00:00
// For tables, GetUsedMargin always returns an empty margin, so we
// should read the margin from the outer table frame instead.
val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
NS_ASSERTION(mOuterFrame == mInnerFrame ||
mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
"Inner tables must have zero margins");
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleBorder()->GetBorderStyle(aSide),
nsCSSProps::kBorderStyleKTable));
return val;
}
void
nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
const nsStyleCoord& aCoord,
bool aClampNegativeCalc,
PercentageBaseGetter aPercentageBaseGetter,
const PRInt32 aTable[],
nscoord aMinAppUnits,
nscoord aMaxAppUnits)
{
NS_PRECONDITION(aValue, "Must have a value to work with");
switch (aCoord.GetUnit()) {
case eStyleUnit_Normal:
aValue->SetIdent(eCSSKeyword_normal);
break;
case eStyleUnit_Auto:
aValue->SetIdent(eCSSKeyword_auto);
break;
case eStyleUnit_Percent:
{
nscoord percentageBase;
if (aPercentageBaseGetter &&
(this->*aPercentageBaseGetter)(percentageBase)) {
nscoord val = NSCoordSaturatingMultiply(percentageBase,
aCoord.GetPercentValue());
aValue->SetAppUnits(NS_MAX(aMinAppUnits, NS_MIN(val, aMaxAppUnits)));
} else {
aValue->SetPercent(aCoord.GetPercentValue());
}
}
break;
case eStyleUnit_Factor:
aValue->SetNumber(aCoord.GetFactorValue());
break;
case eStyleUnit_Coord:
{
nscoord val = aCoord.GetCoordValue();
aValue->SetAppUnits(NS_MAX(aMinAppUnits, NS_MIN(val, aMaxAppUnits)));
}
break;
case eStyleUnit_Integer:
aValue->SetNumber(aCoord.GetIntValue());
break;
case eStyleUnit_Enumerated:
NS_ASSERTION(aTable, "Must have table to handle this case");
aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
aTable));
break;
case eStyleUnit_None:
aValue->SetIdent(eCSSKeyword_none);
break;
case eStyleUnit_Calc:
nscoord percentageBase;
if (!aCoord.CalcHasPercent()) {
nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
if (aClampNegativeCalc && val < 0) {
NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
"parser should have rejected value");
val = 0;
}
aValue->SetAppUnits(NS_MAX(aMinAppUnits, NS_MIN(val, aMaxAppUnits)));
} else if (aPercentageBaseGetter &&
(this->*aPercentageBaseGetter)(percentageBase)) {
nscoord val =
nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
if (aClampNegativeCalc && val < 0) {
NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
"parser should have rejected value");
val = 0;
}
aValue->SetAppUnits(NS_MAX(aMinAppUnits, NS_MIN(val, aMaxAppUnits)));
} else {
nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
SetValueToCalc(calc, aValue);
}
break;
default:
NS_ERROR("Can't handle this unit");
break;
}
}
nscoord
nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
PercentageBaseGetter aPercentageBaseGetter,
nscoord aDefaultValue,
bool aClampNegativeCalc)
{
NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter");
if (aCoord.GetUnit() == eStyleUnit_Coord) {
return aCoord.GetCoordValue();
}
if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
nscoord percentageBase;
if ((this->*aPercentageBaseGetter)(percentageBase)) {
nscoord result =
nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
if (aClampNegativeCalc && result < 0) {
NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
"parser should have rejected value");
result = 0;
}
return result;
}
// Fall through to returning aDefaultValue if we have no percentage base.
}
return aDefaultValue;
}
bool
nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
{
if (!mOuterFrame) {
return false;
}
nsIFrame* container = GetContainingBlockFor(mOuterFrame);
if (!container) {
return false;
}
AssertFlushedPendingReflows();
aWidth = container->GetContentRect().width;
return true;
}
bool
nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
{
if (!mOuterFrame) {
return false;
}
nsIFrame* container = GetContainingBlockFor(mOuterFrame);
if (!container) {
return false;
}
AssertFlushedPendingReflows();
aHeight = container->GetContentRect().height;
return true;
}
bool
nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
{
if (!mInnerFrame) {
return false;
}
AssertFlushedPendingReflows();
aWidth = mInnerFrame->GetSize().width;
return true;
}
bool
nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
{
if (!mInnerFrame) {
return false;
}
AssertFlushedPendingReflows();
aHeight = mInnerFrame->GetSize().height;
return true;
}
bool
nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
{
// We need a frame to work with.
if (!mInnerFrame) {
return false;
}
AssertFlushedPendingReflows();
aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
return true;
}
bool
nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
{
// We need a frame to work with.
if (!mInnerFrame) {
return false;
}
AssertFlushedPendingReflows();
aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
return true;
}
nsIDOMCSSValue*
nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVG* svg = GetStyleSVG();
const nsStyleSVGPaint* paint = nsnull;
if (aFill)
paint = &svg->mFill;
else
paint = &svg->mStroke;
nsAutoString paintString;
switch (paint->mType) {
case eStyleSVGPaintType_None:
{
val->SetIdent(eCSSKeyword_none);
break;
}
case eStyleSVGPaintType_Color:
{
SetToRGBAColor(val, paint->mPaint.mColor);
break;
}
case eStyleSVGPaintType_Server:
{
nsDOMCSSValueList *valueList = GetROCSSValueList(false);
valueList->AppendCSSValue(val);
nsROCSSPrimitiveValue* fallback = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(fallback);
val->SetURI(paint->mPaint.mPaintServer);
SetToRGBAColor(fallback, paint->mFallbackColor);
return valueList;
}
}
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFill()
{
return GetSVGPaintFor(true);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStroke()
{
return GetSVGPaintFor(false);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarkerEnd()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVG* svg = GetStyleSVG();
if (svg->mMarkerEnd)
val->SetURI(svg->mMarkerEnd);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarkerMid()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVG* svg = GetStyleSVG();
if (svg->mMarkerMid)
val->SetURI(svg->mMarkerMid);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMarkerStart()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVG* svg = GetStyleSVG();
if (svg->mMarkerStart)
val->SetURI(svg->mMarkerStart);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeDasharray()
{
const nsStyleSVG* svg = GetStyleSVG();
if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(eCSSKeyword_none);
return val;
}
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
for (PRUint32 i = 0; i < svg->mStrokeDasharrayLength; i++) {
nsROCSSPrimitiveValue* dash = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(dash);
SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
}
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeDashoffset()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleSVG()->mStrokeDashoffset, false);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeWidth()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
SetValueToCoord(val, GetStyleSVG()->mStrokeWidth, true);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFillOpacity()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleSVG()->mFillOpacity);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFloodOpacity()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleSVGReset()->mFloodOpacity);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStopOpacity()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleSVGReset()->mStopOpacity);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeMiterlimit()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleSVG()->mStrokeMiterlimit);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeOpacity()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetNumber(GetStyleSVG()->mStrokeOpacity);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetClipRule()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(
GetStyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFillRule()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsCSSProps::ValueToKeywordEnum(
GetStyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeLinecap()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mStrokeLinecap,
nsCSSProps::kStrokeLinecapKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStrokeLinejoin()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mStrokeLinejoin,
nsCSSProps::kStrokeLinejoinKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextAnchor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mTextAnchor,
nsCSSProps::kTextAnchorKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColorInterpolation()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mColorInterpolation,
nsCSSProps::kColorInterpolationKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetColorInterpolationFilters()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mColorInterpolationFilters,
nsCSSProps::kColorInterpolationKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetDominantBaseline()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVGReset()->mDominantBaseline,
nsCSSProps::kDominantBaselineKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetImageRendering()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mImageRendering,
nsCSSProps::kImageRenderingKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetShapeRendering()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mShapeRendering,
nsCSSProps::kShapeRenderingKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextRendering()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleSVG()->mTextRendering,
nsCSSProps::kTextRenderingKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFloodColor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetToRGBAColor(val, GetStyleSVGReset()->mFloodColor);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetLightingColor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetToRGBAColor(val, GetStyleSVGReset()->mLightingColor);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetStopColor()
{
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
SetToRGBAColor(val, GetStyleSVGReset()->mStopColor);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetClipPath()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVGReset* svg = GetStyleSVGReset();
if (svg->mClipPath)
val->SetURI(svg->mClipPath);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetFilter()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVGReset* svg = GetStyleSVGReset();
if (svg->mFilter)
val->SetURI(svg->mFilter);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMask()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
const nsStyleSVGReset* svg = GetStyleSVGReset();
if (svg->mMask)
val->SetURI(svg->mMask);
else
val->SetIdent(eCSSKeyword_none);
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTransitionDelay()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mTransitionDelayCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsTransition *transition = &display->mTransitions[i];
nsROCSSPrimitiveValue* delay = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(delay);
delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
} while (++i < display->mTransitionDelayCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTransitionDuration()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mTransitionDurationCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsTransition *transition = &display->mTransitions[i];
nsROCSSPrimitiveValue* duration = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(duration);
duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
} while (++i < display->mTransitionDurationCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTransitionProperty()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mTransitionPropertyCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsTransition *transition = &display->mTransitions[i];
nsROCSSPrimitiveValue* property = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(property);
nsCSSProperty cssprop = transition->GetProperty();
if (cssprop == eCSSPropertyExtra_all_properties)
property->SetIdent(eCSSKeyword_all);
else if (cssprop == eCSSPropertyExtra_no_properties)
property->SetIdent(eCSSKeyword_none);
else if (cssprop == eCSSProperty_UNKNOWN)
{
nsAutoString escaped;
nsStyleUtil::AppendEscapedCSSIdent(
nsDependentAtomString(transition->GetUnknownProperty()), escaped);
property->SetString(escaped); // really want SetIdent
}
else
property->SetString(nsCSSProps::GetStringValue(cssprop));
} while (++i < display->mTransitionPropertyCount);
return valueList;
}
void
nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
const nsTimingFunction& aTimingFunction)
{
nsROCSSPrimitiveValue* timingFunction = GetROCSSPrimitiveValue();
aValueList->AppendCSSValue(timingFunction);
nsAutoString tmp;
if (aTimingFunction.mType == nsTimingFunction::Function) {
// set the value from the cubic-bezier control points
// (We could try to regenerate the keywords if we want.)
tmp.AppendLiteral("cubic-bezier(");
tmp.AppendFloat(aTimingFunction.mFunc.mX1);
tmp.AppendLiteral(", ");
tmp.AppendFloat(aTimingFunction.mFunc.mY1);
tmp.AppendLiteral(", ");
tmp.AppendFloat(aTimingFunction.mFunc.mX2);
tmp.AppendLiteral(", ");
tmp.AppendFloat(aTimingFunction.mFunc.mY2);
tmp.AppendLiteral(")");
} else {
tmp.AppendLiteral("steps(");
tmp.AppendInt(aTimingFunction.mSteps);
if (aTimingFunction.mType == nsTimingFunction::StepStart) {
tmp.AppendLiteral(", start)");
} else {
tmp.AppendLiteral(", end)");
}
}
timingFunction->SetString(tmp);
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTransitionTimingFunction()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mTransitionTimingFunctionCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
AppendTimingFunction(valueList,
display->mTransitions[i].GetTimingFunction());
} while (++i < display->mTransitionTimingFunctionCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationName()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationNameCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* property = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(property);
const nsString& name = animation->GetName();
if (name.IsEmpty()) {
property->SetIdent(eCSSKeyword_none);
} else {
nsAutoString escaped;
nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
property->SetString(escaped); // really want SetIdent
}
} while (++i < display->mAnimationNameCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationDelay()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationDelayCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* delay = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(delay);
delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
} while (++i < display->mAnimationDelayCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationDuration()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationDurationCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* duration = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(duration);
duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
} while (++i < display->mAnimationDurationCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationTimingFunction()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationTimingFunctionCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
AppendTimingFunction(valueList,
display->mAnimations[i].GetTimingFunction());
} while (++i < display->mAnimationTimingFunctionCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationDirection()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationDirectionCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* direction = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(direction);
direction->SetIdent(
nsCSSProps::ValueToKeywordEnum(animation->GetDirection(),
nsCSSProps::kAnimationDirectionKTable));
} while (++i < display->mAnimationDirectionCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationFillMode()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationFillModeCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* fillMode = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(fillMode);
fillMode->SetIdent(
nsCSSProps::ValueToKeywordEnum(animation->GetFillMode(),
nsCSSProps::kAnimationFillModeKTable));
} while (++i < display->mAnimationFillModeCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationIterationCount()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationIterationCountCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* iterationCount = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(iterationCount);
float f = animation->GetIterationCount();
/* Need a nasty hack here to work around an optimizer bug in gcc
4.2 on Mac, which somehow gets confused when directly comparing
a float to the return value of NS_IEEEPositiveInfinity when
building 32-bit builds. */
#ifdef XP_MACOSX
volatile
#endif
float inf = NS_IEEEPositiveInfinity();
if (f == inf) {
iterationCount->SetIdent(eCSSKeyword_infinite);
} else {
iterationCount->SetNumber(f);
}
} while (++i < display->mAnimationIterationCountCount);
return valueList;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetAnimationPlayState()
{
const nsStyleDisplay* display = GetStyleDisplay();
nsDOMCSSValueList *valueList = GetROCSSValueList(true);
NS_ABORT_IF_FALSE(display->mAnimationPlayStateCount > 0,
"first item must be explicit");
PRUint32 i = 0;
do {
const nsAnimation *animation = &display->mAnimations[i];
nsROCSSPrimitiveValue* playState = GetROCSSPrimitiveValue();
valueList->AppendCSSValue(playState);
playState->SetIdent(
nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
nsCSSProps::kAnimationPlayStateKTable));
} while (++i < display->mAnimationPlayStateCount);
return valueList;
}
#define COMPUTED_STYLE_MAP_ENTRY(_prop, _method) \
{ eCSSProperty_##_prop, &nsComputedDOMStyle::DoGet##_method, false }
#define COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_prop, _method) \
{ eCSSProperty_##_prop, &nsComputedDOMStyle::DoGet##_method, true }
const nsComputedDOMStyle::ComputedStyleMapEntry*
nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
{
/* ******************************************************************* *\
* Properties below are listed in alphabetical order. *
* Please keep them that way. *
* *
* Properties commented out with // are not yet implemented *
* Properties commented out with //// are shorthands and not queryable *
\* ******************************************************************* */
static const ComputedStyleMapEntry map[] = {
/* ***************************** *\
* Implementations of CSS styles *
\* ***************************** */
//// COMPUTED_STYLE_MAP_ENTRY(background, Background),
COMPUTED_STYLE_MAP_ENTRY(background_attachment, BackgroundAttachment),
COMPUTED_STYLE_MAP_ENTRY(background_clip, BackgroundClip),
COMPUTED_STYLE_MAP_ENTRY(background_color, BackgroundColor),
COMPUTED_STYLE_MAP_ENTRY(background_image, BackgroundImage),
COMPUTED_STYLE_MAP_ENTRY(background_origin, BackgroundOrigin),
COMPUTED_STYLE_MAP_ENTRY(background_position, BackgroundPosition),
COMPUTED_STYLE_MAP_ENTRY(background_repeat, BackgroundRepeat),
COMPUTED_STYLE_MAP_ENTRY(background_size, MozBackgroundSize),
//// COMPUTED_STYLE_MAP_ENTRY(border, Border),
//// COMPUTED_STYLE_MAP_ENTRY(border_bottom, BorderBottom),
COMPUTED_STYLE_MAP_ENTRY(border_bottom_color, BorderBottomColor),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_bottom_left_radius, BorderBottomLeftRadius),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_bottom_right_radius,BorderBottomRightRadius),
COMPUTED_STYLE_MAP_ENTRY(border_bottom_style, BorderBottomStyle),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_bottom_width, BorderBottomWidth),
COMPUTED_STYLE_MAP_ENTRY(border_collapse, BorderCollapse),
//// COMPUTED_STYLE_MAP_ENTRY(border_color, BorderColor),
//// COMPUTED_STYLE_MAP_ENTRY(border_left, BorderLeft),
COMPUTED_STYLE_MAP_ENTRY(border_left_color, BorderLeftColor),
COMPUTED_STYLE_MAP_ENTRY(border_left_style, BorderLeftStyle),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_left_width, BorderLeftWidth),
//// COMPUTED_STYLE_MAP_ENTRY(border_right, BorderRight),
COMPUTED_STYLE_MAP_ENTRY(border_right_color, BorderRightColor),
COMPUTED_STYLE_MAP_ENTRY(border_right_style, BorderRightStyle),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_right_width, BorderRightWidth),
COMPUTED_STYLE_MAP_ENTRY(border_spacing, BorderSpacing),
//// COMPUTED_STYLE_MAP_ENTRY(border_style, BorderStyle),
//// COMPUTED_STYLE_MAP_ENTRY(border_top, BorderTop),
COMPUTED_STYLE_MAP_ENTRY(border_top_color, BorderTopColor),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_top_left_radius, BorderTopLeftRadius),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_top_right_radius, BorderTopRightRadius),
COMPUTED_STYLE_MAP_ENTRY(border_top_style, BorderTopStyle),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(border_top_width, BorderTopWidth),
//// COMPUTED_STYLE_MAP_ENTRY(border_width, BorderWidth),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(bottom, Bottom),
COMPUTED_STYLE_MAP_ENTRY(box_shadow, BoxShadow),
COMPUTED_STYLE_MAP_ENTRY(caption_side, CaptionSide),
COMPUTED_STYLE_MAP_ENTRY(clear, Clear),
COMPUTED_STYLE_MAP_ENTRY(clip, Clip),
COMPUTED_STYLE_MAP_ENTRY(color, Color),
COMPUTED_STYLE_MAP_ENTRY(content, Content),
COMPUTED_STYLE_MAP_ENTRY(counter_increment, CounterIncrement),
COMPUTED_STYLE_MAP_ENTRY(counter_reset, CounterReset),
COMPUTED_STYLE_MAP_ENTRY(cursor, Cursor),
COMPUTED_STYLE_MAP_ENTRY(direction, Direction),
COMPUTED_STYLE_MAP_ENTRY(display, Display),
COMPUTED_STYLE_MAP_ENTRY(empty_cells, EmptyCells),
COMPUTED_STYLE_MAP_ENTRY(float, CssFloat),
//// COMPUTED_STYLE_MAP_ENTRY(font, Font),
COMPUTED_STYLE_MAP_ENTRY(font_family, FontFamily),
COMPUTED_STYLE_MAP_ENTRY(font_size, FontSize),
COMPUTED_STYLE_MAP_ENTRY(font_size_adjust, FontSizeAdjust),
COMPUTED_STYLE_MAP_ENTRY(font_stretch, FontStretch),
COMPUTED_STYLE_MAP_ENTRY(font_style, FontStyle),
COMPUTED_STYLE_MAP_ENTRY(font_variant, FontVariant),
COMPUTED_STYLE_MAP_ENTRY(font_weight, FontWeight),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(height, Height),
COMPUTED_STYLE_MAP_ENTRY(ime_mode, IMEMode),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(left, Left),
COMPUTED_STYLE_MAP_ENTRY(letter_spacing, LetterSpacing),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(line_height, LineHeight),
//// COMPUTED_STYLE_MAP_ENTRY(list_style, ListStyle),
COMPUTED_STYLE_MAP_ENTRY(list_style_image, ListStyleImage),
COMPUTED_STYLE_MAP_ENTRY(list_style_position, ListStylePosition),
COMPUTED_STYLE_MAP_ENTRY(list_style_type, ListStyleType),
//// COMPUTED_STYLE_MAP_ENTRY(margin, Margin),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(margin_bottom, MarginBottomWidth),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(margin_left, MarginLeftWidth),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(margin_right, MarginRightWidth),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(margin_top, MarginTopWidth),
COMPUTED_STYLE_MAP_ENTRY(marker_offset, MarkerOffset),
// COMPUTED_STYLE_MAP_ENTRY(marks, Marks),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(max_height, MaxHeight),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(max_width, MaxWidth),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(min_height, MinHeight),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(min_width, MinWidth),
COMPUTED_STYLE_MAP_ENTRY(opacity, Opacity),
// COMPUTED_STYLE_MAP_ENTRY(orphans, Orphans),
//// COMPUTED_STYLE_MAP_ENTRY(outline, Outline),
COMPUTED_STYLE_MAP_ENTRY(outline_color, OutlineColor),
COMPUTED_STYLE_MAP_ENTRY(outline_offset, OutlineOffset),
COMPUTED_STYLE_MAP_ENTRY(outline_style, OutlineStyle),
COMPUTED_STYLE_MAP_ENTRY(outline_width, OutlineWidth),
COMPUTED_STYLE_MAP_ENTRY(overflow, Overflow),
COMPUTED_STYLE_MAP_ENTRY(overflow_x, OverflowX),
COMPUTED_STYLE_MAP_ENTRY(overflow_y, OverflowY),
//// COMPUTED_STYLE_MAP_ENTRY(padding, Padding),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(padding_bottom, PaddingBottom),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(padding_left, PaddingLeft),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(padding_right, PaddingRight),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(padding_top, PaddingTop),
// COMPUTED_STYLE_MAP_ENTRY(page, Page),
COMPUTED_STYLE_MAP_ENTRY(page_break_after, PageBreakAfter),
COMPUTED_STYLE_MAP_ENTRY(page_break_before, PageBreakBefore),
// COMPUTED_STYLE_MAP_ENTRY(page_break_inside, PageBreakInside),
COMPUTED_STYLE_MAP_ENTRY(pointer_events, PointerEvents),
COMPUTED_STYLE_MAP_ENTRY(position, Position),
COMPUTED_STYLE_MAP_ENTRY(quotes, Quotes),
COMPUTED_STYLE_MAP_ENTRY(resize, Resize),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(right, Right),
//// COMPUTED_STYLE_MAP_ENTRY(size, Size),
COMPUTED_STYLE_MAP_ENTRY(table_layout, TableLayout),
COMPUTED_STYLE_MAP_ENTRY(text_align, TextAlign),
COMPUTED_STYLE_MAP_ENTRY(text_decoration, TextDecoration),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(text_indent, TextIndent),
COMPUTED_STYLE_MAP_ENTRY(text_overflow, TextOverflow),
COMPUTED_STYLE_MAP_ENTRY(text_shadow, TextShadow),
COMPUTED_STYLE_MAP_ENTRY(text_transform, TextTransform),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(top, Top),
COMPUTED_STYLE_MAP_ENTRY(unicode_bidi, UnicodeBidi),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(vertical_align, VerticalAlign),
COMPUTED_STYLE_MAP_ENTRY(visibility, Visibility),
COMPUTED_STYLE_MAP_ENTRY(white_space, WhiteSpace),
// COMPUTED_STYLE_MAP_ENTRY(widows, Widows),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(width, Width),
COMPUTED_STYLE_MAP_ENTRY(word_spacing, WordSpacing),
COMPUTED_STYLE_MAP_ENTRY(word_wrap, WordWrap),
COMPUTED_STYLE_MAP_ENTRY(z_index, ZIndex),
/* ******************************* *\
* Implementations of -moz- styles *
\* ******************************* */
COMPUTED_STYLE_MAP_ENTRY(animation_delay, AnimationDelay),
COMPUTED_STYLE_MAP_ENTRY(animation_direction, AnimationDirection),
COMPUTED_STYLE_MAP_ENTRY(animation_duration, AnimationDuration),
COMPUTED_STYLE_MAP_ENTRY(animation_fill_mode, AnimationFillMode),
COMPUTED_STYLE_MAP_ENTRY(animation_iteration_count, AnimationIterationCount),
COMPUTED_STYLE_MAP_ENTRY(animation_name, AnimationName),
COMPUTED_STYLE_MAP_ENTRY(animation_play_state, AnimationPlayState),
COMPUTED_STYLE_MAP_ENTRY(animation_timing_function, AnimationTimingFunction),
COMPUTED_STYLE_MAP_ENTRY(appearance, Appearance),
COMPUTED_STYLE_MAP_ENTRY(backface_visibility, MozBackfaceVisibility),
COMPUTED_STYLE_MAP_ENTRY(_moz_background_inline_policy, BackgroundInlinePolicy),
COMPUTED_STYLE_MAP_ENTRY(binding, Binding),
COMPUTED_STYLE_MAP_ENTRY(border_bottom_colors, BorderBottomColors),
//// COMPUTED_STYLE_MAP_ENTRY(border_image, BorderImage),
COMPUTED_STYLE_MAP_ENTRY(border_image_outset, BorderImageOutset),
COMPUTED_STYLE_MAP_ENTRY(border_image_repeat, BorderImageRepeat),
COMPUTED_STYLE_MAP_ENTRY(border_image_slice, BorderImageSlice),
COMPUTED_STYLE_MAP_ENTRY(border_image_source, BorderImageSource),
COMPUTED_STYLE_MAP_ENTRY(border_image_width, BorderImageWidth),
COMPUTED_STYLE_MAP_ENTRY(border_left_colors, BorderLeftColors),
COMPUTED_STYLE_MAP_ENTRY(border_right_colors, BorderRightColors),
COMPUTED_STYLE_MAP_ENTRY(border_top_colors, BorderTopColors),
COMPUTED_STYLE_MAP_ENTRY(box_align, BoxAlign),
COMPUTED_STYLE_MAP_ENTRY(box_direction, BoxDirection),
COMPUTED_STYLE_MAP_ENTRY(box_flex, BoxFlex),
COMPUTED_STYLE_MAP_ENTRY(box_ordinal_group, BoxOrdinalGroup),
COMPUTED_STYLE_MAP_ENTRY(box_orient, BoxOrient),
COMPUTED_STYLE_MAP_ENTRY(box_pack, BoxPack),
COMPUTED_STYLE_MAP_ENTRY(box_sizing, BoxSizing),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_count, ColumnCount),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_fill, ColumnFill),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_gap, ColumnGap),
//// COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule, ColumnRule),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_color, ColumnRuleColor),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_style, ColumnRuleStyle),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_rule_width, ColumnRuleWidth),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_width, ColumnWidth),
COMPUTED_STYLE_MAP_ENTRY(float_edge, FloatEdge),
COMPUTED_STYLE_MAP_ENTRY(font_feature_settings, MozFontFeatureSettings),
COMPUTED_STYLE_MAP_ENTRY(font_language_override, MozFontLanguageOverride),
COMPUTED_STYLE_MAP_ENTRY(force_broken_image_icon, ForceBrokenImageIcon),
COMPUTED_STYLE_MAP_ENTRY(hyphens, Hyphens),
COMPUTED_STYLE_MAP_ENTRY(image_region, ImageRegion),
COMPUTED_STYLE_MAP_ENTRY(orient, Orient),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_bottomLeft, OutlineRadiusBottomLeft),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_topLeft, OutlineRadiusTopLeft),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_topRight, OutlineRadiusTopRight),
COMPUTED_STYLE_MAP_ENTRY(perspective, MozPerspective),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(perspective_origin, MozPerspectiveOrigin),
COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing),
COMPUTED_STYLE_MAP_ENTRY(_moz_tab_size, MozTabSize),
COMPUTED_STYLE_MAP_ENTRY(text_align_last, TextAlignLast),
COMPUTED_STYLE_MAP_ENTRY(text_blink, MozTextBlink),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_color, MozTextDecorationColor),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_line, MozTextDecorationLine),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_style, MozTextDecorationStyle),
COMPUTED_STYLE_MAP_ENTRY(text_size_adjust, TextSizeAdjust),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_transform, MozTransform),
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_transform_origin, MozTransformOrigin),
COMPUTED_STYLE_MAP_ENTRY(transform_style, MozTransformStyle),
COMPUTED_STYLE_MAP_ENTRY(transition_delay, TransitionDelay),
COMPUTED_STYLE_MAP_ENTRY(transition_duration, TransitionDuration),
COMPUTED_STYLE_MAP_ENTRY(transition_property, TransitionProperty),
COMPUTED_STYLE_MAP_ENTRY(transition_timing_function, TransitionTimingFunction),
COMPUTED_STYLE_MAP_ENTRY(user_focus, UserFocus),
COMPUTED_STYLE_MAP_ENTRY(user_input, UserInput),
COMPUTED_STYLE_MAP_ENTRY(user_modify, UserModify),
COMPUTED_STYLE_MAP_ENTRY(user_select, UserSelect),
COMPUTED_STYLE_MAP_ENTRY(_moz_window_shadow, WindowShadow),
/* ***************************** *\
* Implementations of SVG styles *
\* ***************************** */
COMPUTED_STYLE_MAP_ENTRY(clip_path, ClipPath),
COMPUTED_STYLE_MAP_ENTRY(clip_rule, ClipRule),
COMPUTED_STYLE_MAP_ENTRY(color_interpolation, ColorInterpolation),
COMPUTED_STYLE_MAP_ENTRY(color_interpolation_filters, ColorInterpolationFilters),
COMPUTED_STYLE_MAP_ENTRY(dominant_baseline, DominantBaseline),
COMPUTED_STYLE_MAP_ENTRY(fill, Fill),
COMPUTED_STYLE_MAP_ENTRY(fill_opacity, FillOpacity),
COMPUTED_STYLE_MAP_ENTRY(fill_rule, FillRule),
COMPUTED_STYLE_MAP_ENTRY(filter, Filter),
COMPUTED_STYLE_MAP_ENTRY(flood_color, FloodColor),
COMPUTED_STYLE_MAP_ENTRY(flood_opacity, FloodOpacity),
COMPUTED_STYLE_MAP_ENTRY(image_rendering, ImageRendering),
COMPUTED_STYLE_MAP_ENTRY(lighting_color, LightingColor),
COMPUTED_STYLE_MAP_ENTRY(marker_end, MarkerEnd),
COMPUTED_STYLE_MAP_ENTRY(marker_mid, MarkerMid),
COMPUTED_STYLE_MAP_ENTRY(marker_start, MarkerStart),
COMPUTED_STYLE_MAP_ENTRY(mask, Mask),
COMPUTED_STYLE_MAP_ENTRY(shape_rendering, ShapeRendering),
COMPUTED_STYLE_MAP_ENTRY(stop_color, StopColor),
COMPUTED_STYLE_MAP_ENTRY(stop_opacity, StopOpacity),
COMPUTED_STYLE_MAP_ENTRY(stroke, Stroke),
COMPUTED_STYLE_MAP_ENTRY(stroke_dasharray, StrokeDasharray),
COMPUTED_STYLE_MAP_ENTRY(stroke_dashoffset, StrokeDashoffset),
COMPUTED_STYLE_MAP_ENTRY(stroke_linecap, StrokeLinecap),
COMPUTED_STYLE_MAP_ENTRY(stroke_linejoin, StrokeLinejoin),
COMPUTED_STYLE_MAP_ENTRY(stroke_miterlimit, StrokeMiterlimit),
COMPUTED_STYLE_MAP_ENTRY(stroke_opacity, StrokeOpacity),
COMPUTED_STYLE_MAP_ENTRY(stroke_width, StrokeWidth),
COMPUTED_STYLE_MAP_ENTRY(text_anchor, TextAnchor),
COMPUTED_STYLE_MAP_ENTRY(text_rendering, TextRendering)
};
*aLength = ArrayLength(map);
return map;
}