pjs/layout/style/nsCSSParser.cpp

4117 строки
125 KiB
C++
Исходник Обычный вид История

1998-04-14 00:24:54 +04:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsICSSParser.h"
#include "nsCSSProps.h"
#include "nsCSSKeywords.h"
#include "nsCSSScanner.h"
#include "nsICSSLoader.h"
1998-04-14 00:24:54 +04:00
#include "nsICSSStyleRule.h"
#include "nsICSSImportRule.h"
#include "nsICSSMediaRule.h"
#include "nsICSSCharsetRule.h"
#include "nsICSSNameSpaceRule.h"
1998-04-14 00:24:54 +04:00
#include "nsIUnicharInputStream.h"
#include "nsIStyleSet.h"
#include "nsICSSStyleSheet.h"
#include "nsICSSDeclaration.h"
#include "nsStyleConsts.h"
#include "nsIURL.h"
#ifdef NECKO
#include "nsIIOService.h"
#include "nsIURI.h"
#include "nsIServiceManager.h"
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
#endif // NECKO
#include "nsIURLGroup.h"
1998-04-14 00:24:54 +04:00
#include "nsString.h"
#include "nsIAtom.h"
#include "nsVoidArray.h"
#include "nsISupportsArray.h"
1998-04-14 00:24:54 +04:00
#include "nsColor.h"
#include "nsStyleConsts.h"
1998-12-11 05:50:43 +03:00
#include "nsCSSAtoms.h"
#include "nsINameSpaceManager.h"
#include "nsINameSpace.h"
1998-04-14 00:24:54 +04:00
// XXX TODO:
// - rework aErrorCode stuff: switch over to nsresult
1999-02-10 11:37:52 +03:00
// verify ! is followed by important and nothing else
1998-04-14 00:24:54 +04:00
static NS_DEFINE_IID(kICSSParserIID, NS_ICSS_PARSER_IID);
static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID);
static NS_DEFINE_IID(kIStyleSheetIID, NS_ISTYLE_SHEET_IID);
1999-02-10 11:37:52 +03:00
#define KEYWORD_BUFFER_SIZE 100 // big enough for any keyword
1998-04-14 00:24:54 +04:00
// e.g. "P B, H1 B { ... }" has a selector list with two elements,
// each of which has two selectors.
struct SelectorList {
1998-12-11 05:50:43 +03:00
SelectorList(void);
~SelectorList(void);
1998-04-14 00:24:54 +04:00
1998-12-11 05:50:43 +03:00
void AddSelector(const nsCSSSelector& aSelector);
1998-04-14 00:24:54 +04:00
#ifdef NS_DEBUG
1998-12-11 05:50:43 +03:00
void Dump(void);
1998-04-14 00:24:54 +04:00
#endif
1999-02-27 10:15:59 +03:00
nsCSSSelector* mSelectors;
nsAutoString mSourceString;
PRInt32 mWeight;
SelectorList* mNext;
1998-04-14 00:24:54 +04:00
};
1998-12-11 05:50:43 +03:00
SelectorList::SelectorList(void)
: mSelectors(nsnull),
mNext(nsnull)
1998-04-14 00:24:54 +04:00
{
}
SelectorList::~SelectorList()
{
1998-12-11 05:50:43 +03:00
nsCSSSelector* sel = mSelectors;
while (nsnull != sel) {
nsCSSSelector* dead = sel;
sel = sel->mNext;
delete dead;
}
if (nsnull != mNext) {
delete mNext;
1998-04-14 00:24:54 +04:00
}
}
1998-12-11 05:50:43 +03:00
void SelectorList::AddSelector(const nsCSSSelector& aSelector)
{ // prepend to list
nsCSSSelector* newSel = new nsCSSSelector(aSelector);
1999-02-10 11:37:52 +03:00
if (nsnull != newSel) {
newSel->mNext = mSelectors;
mSelectors = newSel;
}
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
1998-04-14 00:24:54 +04:00
#ifdef NS_DEBUG
void SelectorList::Dump()
{
}
#endif
//----------------------------------------------------------------------
// Your basic top-down recursive descent style parser
class CSSParserImpl : public nsICSSParser {
public:
CSSParserImpl();
virtual ~CSSParserImpl();
1998-04-14 00:24:54 +04:00
NS_DECL_ISUPPORTS
NS_IMETHOD Init(nsICSSStyleSheet* aSheet);
NS_IMETHOD GetInfoMask(PRUint32& aResult);
1998-11-26 04:34:53 +03:00
NS_IMETHOD SetStyleSheet(nsICSSStyleSheet* aSheet);
1998-04-14 00:24:54 +04:00
1998-12-21 08:58:58 +03:00
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
1998-12-11 05:50:43 +03:00
NS_IMETHOD SetChildLoader(nsICSSLoader* aChildLoader);
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
1998-11-26 04:34:53 +03:00
nsIURL* aInputURL,
nsICSSStyleSheet*& aResult);
1998-04-14 00:24:54 +04:00
NS_IMETHOD ParseDeclarations(const nsString& aDeclaration,
nsIURL* aBaseURL,
nsIStyleRule*& aResult);
1998-09-30 03:50:09 +04:00
NS_IMETHOD ParseAndAppendDeclaration(const nsString& aBuffer,
nsIURL* aBaseURL,
nsICSSDeclaration* aDeclaration,
PRInt32* aHint);
1998-04-14 00:24:54 +04:00
protected:
1998-10-27 02:22:40 +03:00
PRBool GetToken(PRInt32& aErrorCode, PRBool aSkipWS);
PRBool GetURLToken(PRInt32& aErrorCode, PRBool aSkipWS);
1998-04-14 00:24:54 +04:00
void UngetToken();
PRBool ExpectSymbol(PRInt32& aErrorCode, PRUnichar aSymbol, PRBool aSkipWS);
1998-10-27 02:22:40 +03:00
PRBool ExpectEndProperty(PRInt32& aErrorCode, PRBool aSkipWS);
nsString* NextIdent(PRInt32& aErrorCode);
void SkipUntil(PRInt32& aErrorCode, PRUnichar aStopSymbol);
void SkipRuleSet(PRInt32& aErrorCode);
PRBool SkipAtRule(PRInt32& aErrorCode);
1998-10-27 02:22:40 +03:00
PRBool SkipDeclaration(PRInt32& aErrorCode, PRBool aCheckForBraces);
PRBool PushGroup(nsICSSGroupRule* aRule);
void PopGroup(void);
void AppendRule(nsICSSRule* aRule);
1998-10-27 02:22:40 +03:00
PRBool ParseRuleSet(PRInt32& aErrorCode);
PRBool ParseAtRule(PRInt32& aErrorCode);
PRBool ParseCharsetRule(PRInt32& aErrorCode);
1998-10-27 02:22:40 +03:00
PRBool ParseImportRule(PRInt32& aErrorCode);
PRBool GatherMedia(PRInt32& aErrorCode, nsString& aMedia, nsISupportsArray* aMediaAtoms);
1998-11-26 08:16:22 +03:00
PRBool ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia);
PRBool ParseMediaRule(PRInt32& aErrorCode);
PRBool ParseNameSpaceRule(PRInt32& aErrorCode);
PRBool ProcessNameSpace(PRInt32& aErrorCode, const nsString& aPrefix,
const nsString& aURLSpec);
PRBool ParseFontFaceRule(PRInt32& aErrorCode);
PRBool ParsePageRule(PRInt32& aErrorCode);
1998-10-27 02:22:40 +03:00
1998-12-11 05:50:43 +03:00
PRBool ParseSelectorList(PRInt32& aErrorCode, SelectorList*& aListHead);
PRBool ParseSelectorGroup(PRInt32& aErrorCode, SelectorList*& aListHead);
PRBool ParseSelector(PRInt32& aErrorCode, nsCSSSelector& aSelectorResult, nsString& aSource);
1998-10-27 02:22:40 +03:00
nsICSSDeclaration* ParseDeclarationBlock(PRInt32& aErrorCode,
PRBool aCheckForBraces);
1998-10-27 02:22:40 +03:00
PRBool ParseDeclaration(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration,
1998-09-30 03:50:09 +04:00
PRBool aCheckForBraces,
1998-10-27 02:22:40 +03:00
PRInt32& aChangeHint);
PRBool ParseProperty(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
PRInt32 aPropID, PRInt32& aChangeHint);
PRBool ParseProperty(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
PRInt32 aPropID);
1999-02-10 11:37:52 +03:00
PRBool ParseSingleValueProperty(PRInt32& aErrorCode, nsCSSValue& aValue,
PRInt32 aPropID);
1998-04-14 00:24:54 +04:00
// Property specific parsing routines
1999-02-10 11:37:52 +03:00
PRBool ParseAzimuth(PRInt32& aErrorCode, nsCSSValue& aValue);
1998-10-27 02:22:40 +03:00
PRBool ParseBackground(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
1999-02-10 11:37:52 +03:00
PRBool ParseBackgroundFilter(PRInt32& aErrorCode, nsCSSValue& aValue);
PRBool ParseForegroundFilter(PRInt32& aErrorCode, nsCSSValue& aValue);
1998-10-27 02:22:40 +03:00
PRBool ParseBackgroundPosition(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseBorder(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseBorderColor(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseBorderSpacing(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseBorderSide(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
1999-02-10 11:37:52 +03:00
const PRInt32 aPropIDs[]);
1998-10-27 02:22:40 +03:00
PRBool ParseBorderStyle(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseBorderWidth(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseClip(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseContent(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseCounterData(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
PRInt32 aPropID);
PRBool ParseCue(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseCursor(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseFont(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
1999-02-10 11:37:52 +03:00
PRBool ParseFamily(PRInt32& aErrorCode, nsCSSValue& aValue);
1998-10-27 02:22:40 +03:00
PRBool ParseListStyle(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseMargin(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
1999-02-10 11:37:52 +03:00
PRBool ParseMarks(PRInt32& aErrorCode, nsCSSValue& aValue);
1998-10-27 02:22:40 +03:00
PRBool ParseOutline(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParsePadding(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParsePause(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParsePlayDuring(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseQuotes(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
PRBool ParseSize(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
1999-02-10 11:37:52 +03:00
PRBool ParseTextDecoration(PRInt32& aErrorCode, nsCSSValue& aValue);
1998-10-27 02:22:40 +03:00
PRBool ParseTextShadow(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration);
1998-04-14 00:24:54 +04:00
// Reused utility parsing routines
1998-10-27 02:22:40 +03:00
PRBool ParseBoxProperties(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
const PRInt32 aPropIDs[]);
1999-02-10 11:37:52 +03:00
PRInt32 ParseChoice(PRInt32& aErrorCode, nsCSSValue aValues[],
1998-10-27 02:22:40 +03:00
const PRInt32 aPropIDs[], PRInt32 aNumIDs);
PRBool ParseColor(PRInt32& aErrorCode, nsCSSValue& aValue);
PRBool ParseColorComponent(PRInt32& aErrorCode, PRUint8& aComponent,
1998-04-14 00:24:54 +04:00
char aStop);
1998-10-27 02:22:40 +03:00
PRBool ParseEnum(PRInt32& aErrorCode, nsCSSValue& aValue, const PRInt32 aKeywordTable[]);
PRInt32 SearchKeywordTable(PRInt32 aID, const PRInt32 aTable[]);
PRBool ParseVariant(PRInt32& aErrorCode, nsCSSValue& aValue,
PRInt32 aVariantMask,
1999-02-10 11:37:52 +03:00
const PRInt32 aKeywordTable[]);
PRBool ParsePositiveVariant(PRInt32& aErrorCode, nsCSSValue& aValue,
PRInt32 aVariantMask,
const PRInt32 aKeywordTable[]);
1998-10-27 02:22:40 +03:00
PRBool ParseCounter(PRInt32& aErrorCode, nsCSSValue& aValue);
PRBool ParseAttr(PRInt32& aErrorCode, nsCSSValue& aValue);
PRBool ParseURL(PRInt32& aErrorCode, nsCSSValue& aValue);
PRBool TranslateDimension(nsCSSValue& aValue, PRInt32 aVariantMask,
1999-02-10 11:37:52 +03:00
float aNumber, const nsString& aUnit);
1998-04-14 00:24:54 +04:00
// Current token. The value is valid after calling GetToken
nsCSSToken mToken;
// After an UngetToken is done this flag is true. The next call to
// GetToken clears the flag.
PRBool mHavePushBack;
nsCSSScanner* mScanner;
nsIURL* mURL;
nsICSSStyleSheet* mSheet;
PRInt32 mChildSheetCount;
nsICSSLoader* mChildLoader; // not ref counted, it owns us
1998-04-14 00:24:54 +04:00
enum nsCSSSection {
eCSSSection_Charset,
eCSSSection_Import,
eCSSSection_NameSpace,
eCSSSection_General
};
nsCSSSection mSection;
PRBool mNavQuirkMode;
1998-12-21 08:58:58 +03:00
PRBool mCaseSensitive;
nsINameSpace* mNameSpace;
nsISupportsArray* mGroupStack;
1998-04-14 00:24:54 +04:00
};
NS_HTML nsresult
NS_NewCSSParser(nsICSSParser** aInstancePtrResult)
{
CSSParserImpl *it = new CSSParserImpl();
if (it == nsnull) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kICSSParserIID, (void **) aInstancePtrResult);
}
CSSParserImpl::CSSParserImpl()
: mToken(),
mHavePushBack(PR_FALSE),
mScanner(nsnull),
mURL(nsnull),
mSheet(nsnull),
mChildSheetCount(0),
mChildLoader(nsnull),
mSection(eCSSSection_Charset),
mNavQuirkMode(PR_TRUE),
mCaseSensitive(PR_FALSE),
mNameSpace(nsnull),
mGroupStack(nsnull)
1998-04-14 00:24:54 +04:00
{
NS_INIT_REFCNT();
1998-12-11 05:50:43 +03:00
nsCSSAtoms::AddrefAtoms();
1998-04-14 00:24:54 +04:00
}
NS_IMETHODIMP
CSSParserImpl::Init(nsICSSStyleSheet* aSheet)
1998-04-14 00:24:54 +04:00
{
NS_IF_RELEASE(mGroupStack);
NS_IF_RELEASE(mNameSpace);
NS_IF_RELEASE(mSheet);
mSheet = aSheet;
if (mSheet) {
NS_ADDREF(aSheet);
mSheet->StyleSheetCount(mChildSheetCount);
mSheet->GetNameSpace(mNameSpace);
}
return NS_OK;
1998-04-14 00:24:54 +04:00
}
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
CSSParserImpl::~CSSParserImpl()
{
NS_IF_RELEASE(mGroupStack);
NS_IF_RELEASE(mNameSpace);
1998-04-14 00:24:54 +04:00
NS_IF_RELEASE(mSheet);
1998-12-11 05:50:43 +03:00
nsCSSAtoms::ReleaseAtoms();
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
CSSParserImpl::GetInfoMask(PRUint32& aResult)
1998-04-14 00:24:54 +04:00
{
aResult = NS_CSS_GETINFO_CSS1 | NS_CSS_GETINFO_CSSP;
return NS_OK;
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
1998-11-26 04:34:53 +03:00
CSSParserImpl::SetStyleSheet(nsICSSStyleSheet* aSheet)
1998-04-14 00:24:54 +04:00
{
NS_PRECONDITION(nsnull != aSheet, "null ptr");
if (nsnull == aSheet) {
return NS_ERROR_NULL_POINTER;
}
1998-11-26 04:34:53 +03:00
if (aSheet != mSheet) {
// Switch to using the new sheet
NS_IF_RELEASE(mGroupStack);
NS_IF_RELEASE(mNameSpace);
1998-11-26 04:34:53 +03:00
NS_IF_RELEASE(mSheet);
mSheet = aSheet;
NS_ADDREF(mSheet);
mSheet->StyleSheetCount(mChildSheetCount);
mSheet->GetNameSpace(mNameSpace);
1998-04-14 00:24:54 +04:00
}
return NS_OK;
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
1998-12-21 08:58:58 +03:00
CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive)
1998-12-11 05:50:43 +03:00
{
1998-12-21 08:58:58 +03:00
mCaseSensitive = aCaseSensitive;
1998-12-11 05:50:43 +03:00
return NS_OK;
}
NS_IMETHODIMP
CSSParserImpl::SetChildLoader(nsICSSLoader* aChildLoader)
{
mChildLoader = aChildLoader; // not ref counted, it owns us
return NS_OK;
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
1998-10-27 02:22:40 +03:00
nsIURL* aInputURL,
1998-11-26 04:34:53 +03:00
nsICSSStyleSheet*& aResult)
1998-04-14 00:24:54 +04:00
{
NS_ASSERTION(nsnull != aInputURL, "need base URL");
if (! mSheet) {
1998-04-14 00:24:54 +04:00
NS_NewCSSStyleSheet(&mSheet, aInputURL);
mChildSheetCount = 0;
1998-04-14 00:24:54 +04:00
}
if (! mSheet) {
return NS_ERROR_OUT_OF_MEMORY;
}
1998-04-14 00:24:54 +04:00
PRInt32 errorCode = NS_OK;
1998-04-14 00:24:54 +04:00
mScanner = new nsCSSScanner();
1999-02-10 11:37:52 +03:00
if (nsnull == mScanner) {
return NS_ERROR_OUT_OF_MEMORY;
}
1998-04-14 00:24:54 +04:00
mScanner->Init(aInput);
mURL = aInputURL;
NS_IF_ADDREF(aInputURL);
PRInt32 ruleCount = 0;
mSheet->StyleRuleCount(ruleCount);
if (0 < ruleCount) {
nsICSSRule* lastRule = nsnull;
mSheet->GetStyleRuleAt(ruleCount - 1, lastRule);
if (lastRule) {
PRInt32 type;
lastRule->GetType(type);
switch (type) {
case nsICSSRule::CHARSET_RULE:
case nsICSSRule::IMPORT_RULE:
mSection = eCSSSection_Import;
break;
case nsICSSRule::NAMESPACE_RULE:
mSection = eCSSSection_NameSpace;
break;
default:
mSection = eCSSSection_General;
break;
}
NS_RELEASE(lastRule);
}
}
else {
mSection = eCSSSection_Charset; // sheet is empty, any rules are fair
}
1998-04-14 00:24:54 +04:00
nsCSSToken* tk = &mToken;
for (;;) {
// Get next non-whitespace token
1998-10-27 02:22:40 +03:00
if (!GetToken(errorCode, PR_TRUE)) {
1998-04-14 00:24:54 +04:00
break;
}
if (eCSSToken_HTMLComment == tk->mType) {
continue; // legal here only
}
1998-04-14 00:24:54 +04:00
if (eCSSToken_AtKeyword == tk->mType) {
1998-10-27 02:22:40 +03:00
ParseAtRule(errorCode);
1998-04-14 00:24:54 +04:00
continue;
}
UngetToken();
if (ParseRuleSet(errorCode)) {
mSection = eCSSSection_General;
}
1998-04-14 00:24:54 +04:00
}
delete mScanner;
mScanner = nsnull;
NS_IF_RELEASE(mURL);
1998-11-26 04:34:53 +03:00
aResult = mSheet;
NS_ADDREF(aResult);
return NS_OK;
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
CSSParserImpl::ParseDeclarations(const nsString& aDeclaration,
nsIURL* aBaseURL,
nsIStyleRule*& aResult)
{
NS_ASSERTION(nsnull != aBaseURL, "need base URL");
nsString* str = new nsString(aDeclaration);
if (nsnull == str) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsIUnicharInputStream* input = nsnull;
nsresult rv = NS_NewStringUnicharInputStream(&input, str);
if (NS_OK != rv) {
1999-02-10 11:37:52 +03:00
delete str;
return rv;
}
mScanner = new nsCSSScanner();
1999-02-10 11:37:52 +03:00
if (nsnull == mScanner) {
NS_RELEASE(input);
return NS_ERROR_OUT_OF_MEMORY;
}
mScanner->Init(input);
NS_RELEASE(input);
mURL = aBaseURL;
NS_IF_ADDREF(mURL);
mSection = eCSSSection_General;
PRInt32 errorCode = NS_OK;
1998-10-27 02:22:40 +03:00
nsICSSDeclaration* declaration = ParseDeclarationBlock(errorCode, PR_FALSE);
if (nsnull != declaration) {
// Create a style rule for the delcaration
nsICSSStyleRule* rule = nsnull;
NS_NewCSSStyleRule(&rule, nsCSSSelector());
rule->SetDeclaration(declaration);
aResult = rule;
NS_RELEASE(declaration);
}
else {
aResult = nsnull;
}
delete mScanner;
mScanner = nsnull;
NS_IF_RELEASE(mURL);
return NS_OK;
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
NS_IMETHODIMP
1998-09-30 03:50:09 +04:00
CSSParserImpl::ParseAndAppendDeclaration(const nsString& aBuffer,
nsIURL* aBaseURL,
nsICSSDeclaration* aDeclaration,
PRInt32* aHint)
{
NS_ASSERTION(nsnull != aBaseURL, "need base URL");
nsString* str = new nsString(aBuffer);
if (nsnull == str) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsIUnicharInputStream* input = nsnull;
nsresult rv = NS_NewStringUnicharInputStream(&input, str);
if (NS_OK != rv) {
1999-02-10 11:37:52 +03:00
delete str;
return rv;
}
mScanner = new nsCSSScanner();
1999-02-10 11:37:52 +03:00
if (nsnull == mScanner) {
NS_RELEASE(input);
return NS_ERROR_OUT_OF_MEMORY;
}
mScanner->Init(input);
NS_RELEASE(input);
mURL = aBaseURL;
NS_IF_ADDREF(mURL);
mSection = eCSSSection_General;
PRInt32 errorCode = NS_OK;
1998-10-27 02:22:40 +03:00
PRInt32 hint = NS_STYLE_HINT_UNKNOWN;
ParseDeclaration(errorCode, aDeclaration, PR_FALSE, hint);
1998-10-28 05:04:06 +03:00
if (nsnull != aHint) {
1998-10-27 02:22:40 +03:00
*aHint = hint;
}
delete mScanner;
mScanner = nsnull;
NS_IF_RELEASE(mURL);
return NS_OK;
}
1998-04-14 00:24:54 +04:00
//----------------------------------------------------------------------
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::GetToken(PRInt32& aErrorCode, PRBool aSkipWS)
1998-04-14 00:24:54 +04:00
{
for (;;) {
if (!mHavePushBack) {
1998-10-27 02:22:40 +03:00
if (!mScanner->Next(aErrorCode, mToken)) {
break;
}
}
mHavePushBack = PR_FALSE;
if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) {
continue;
}
return PR_TRUE;
}
return PR_FALSE;
}
PRBool CSSParserImpl::GetURLToken(PRInt32& aErrorCode, PRBool aSkipWS)
{
for (;;) {
if (! mHavePushBack) {
if (! mScanner->NextURL(aErrorCode, mToken)) {
1998-04-14 00:24:54 +04:00
break;
}
}
mHavePushBack = PR_FALSE;
if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) {
continue;
}
return PR_TRUE;
}
return PR_FALSE;
}
void CSSParserImpl::UngetToken()
{
NS_PRECONDITION(mHavePushBack == PR_FALSE, "double pushback");
mHavePushBack = PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ExpectSymbol(PRInt32& aErrorCode,
PRUnichar aSymbol,
1998-04-14 00:24:54 +04:00
PRBool aSkipWS)
{
if (!GetToken(aErrorCode, aSkipWS)) {
return PR_FALSE;
}
if (mToken.IsSymbol(aSymbol)) {
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
UngetToken();
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ExpectEndProperty(PRInt32& aErrorCode, PRBool aSkipWS)
{
if (!GetToken(aErrorCode, aSkipWS)) {
1999-02-10 11:37:52 +03:00
return PR_TRUE; // properties may end with eof
1998-10-27 02:22:40 +03:00
}
if ((eCSSToken_Symbol == mToken.mType) &&
1999-02-10 11:37:52 +03:00
((';' == mToken.mSymbol) || ('!' == mToken.mSymbol) || ('}' == mToken.mSymbol))) {
// XXX need to verify that ! is only followed by "important [;|}]
// XXX this requires a multi-token pushback buffer
1998-10-27 02:22:40 +03:00
UngetToken();
return PR_TRUE;
}
UngetToken();
return PR_FALSE;
}
nsString* CSSParserImpl::NextIdent(PRInt32& aErrorCode)
1998-04-14 00:24:54 +04:00
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return nsnull;
}
if (eCSSToken_Ident != mToken.mType) {
UngetToken();
return nsnull;
}
return &mToken.mIdent;
}
PRBool CSSParserImpl::SkipAtRule(PRInt32& aErrorCode)
1998-04-14 00:24:54 +04:00
{
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
if (eCSSToken_Symbol == mToken.mType) {
PRUnichar symbol = mToken.mSymbol;
1998-04-14 00:24:54 +04:00
if (symbol == ';') {
break;
}
if (symbol == '{') {
SkipUntil(aErrorCode, '}');
break;
} else if (symbol == '(') {
SkipUntil(aErrorCode, ')');
} else if (symbol == '[') {
SkipUntil(aErrorCode, ']');
}
}
}
return PR_TRUE;
}
// XXX @media type {, types } '{' rules '}'
// XXX @font-face
// XXX @page { :left | :right } '{' declarations '}'
PRBool CSSParserImpl::ParseAtRule(PRInt32& aErrorCode)
{
if ((mSection <= eCSSSection_Charset) &&
(mToken.mIdent.EqualsIgnoreCase("charset"))) {
if (ParseCharsetRule(aErrorCode)) {
mSection = eCSSSection_Import; // only one charset allowed
return PR_TRUE;
}
}
if ((mSection <= eCSSSection_Import) &&
mToken.mIdent.EqualsIgnoreCase("import")) {
if (ParseImportRule(aErrorCode)) {
mSection = eCSSSection_Import;
return PR_TRUE;
}
}
if ((mSection <= eCSSSection_NameSpace) &&
mToken.mIdent.EqualsIgnoreCase("namespace")) {
if (ParseNameSpaceRule(aErrorCode)) {
mSection = eCSSSection_NameSpace;
return PR_TRUE;
}
}
if (mToken.mIdent.EqualsIgnoreCase("media")) {
if (ParseMediaRule(aErrorCode)) {
mSection = eCSSSection_General;
return PR_TRUE;
}
}
if (mToken.mIdent.EqualsIgnoreCase("font-face")) {
if (ParseFontFaceRule(aErrorCode)) {
mSection = eCSSSection_General;
return PR_TRUE;
}
}
if (mToken.mIdent.EqualsIgnoreCase("page")) {
if (ParsePageRule(aErrorCode)) {
mSection = eCSSSection_General;
return PR_TRUE;
}
}
// Skip over unsupported at rule, don't advance section
return SkipAtRule(aErrorCode);
}
PRBool CSSParserImpl::ParseCharsetRule(PRInt32& aErrorCode)
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
// XXX not yet implemented
return PR_FALSE;
}
PRBool CSSParserImpl::GatherMedia(PRInt32& aErrorCode, nsString& aMedia,
nsISupportsArray* aMediaAtoms)
1999-01-23 10:08:11 +03:00
{
1998-11-26 08:16:22 +03:00
PRBool first = PR_TRUE;
PRBool expectIdent = PR_TRUE;
1998-11-26 08:16:22 +03:00
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Symbol == mToken.mType) {
PRUnichar symbol = mToken.mSymbol;
if ((';' == symbol) || ('{' == symbol)) {
1998-11-26 08:16:22 +03:00
UngetToken();
return PR_TRUE;
} else if (',' != symbol) {
UngetToken();
break;
} else if (expectIdent) {
UngetToken();
break;
}
else {
expectIdent = PR_TRUE;
1998-11-26 08:16:22 +03:00
}
}
else if (eCSSToken_Ident == mToken.mType) {
if (expectIdent) {
if (! first) {
aMedia.Append(',');
}
mToken.mIdent.ToLowerCase(); // case insensitive from CSS - must be lower cased
if (aMediaAtoms) {
nsIAtom* medium = NS_NewAtom(mToken.mIdent);
aMediaAtoms->AppendElement(medium);
NS_RELEASE(medium);
}
aMedia.Append(mToken.mIdent);
first = PR_FALSE;
expectIdent = PR_FALSE;
}
else {
UngetToken();
break;
1998-11-26 08:16:22 +03:00
}
}
else {
UngetToken();
1998-11-26 08:16:22 +03:00
break;
}
}
aMedia.Truncate();
if (aMediaAtoms) {
aMediaAtoms->Clear();
}
1998-11-26 08:16:22 +03:00
return PR_FALSE;
}
// Parse a CSS2 import rule: "@import STRING | URL [medium [, mdeium]]"
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseImportRule(PRInt32& aErrorCode)
1998-04-14 00:24:54 +04:00
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
1998-11-26 08:16:22 +03:00
nsAutoString url;
nsAutoString media;
1998-10-27 02:22:40 +03:00
if (eCSSToken_String == mToken.mType) {
1998-11-26 08:16:22 +03:00
url = mToken.mIdent;
if (GatherMedia(aErrorCode, media, nsnull)) {
1998-11-26 08:16:22 +03:00
if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
ProcessImport(aErrorCode, url, media);
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
}
}
else if ((eCSSToken_Function == mToken.mType) &&
(mToken.mIdent.EqualsIgnoreCase("url"))) {
1998-10-27 02:22:40 +03:00
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (GetURLToken(aErrorCode, PR_TRUE)) {
if ((eCSSToken_String == mToken.mType) || (eCSSToken_URL == mToken.mType)) {
1998-11-26 08:16:22 +03:00
url = mToken.mIdent;
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
if (GatherMedia(aErrorCode, media, nsnull)) {
1998-11-26 08:16:22 +03:00
if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
ProcessImport(aErrorCode, url, media);
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
}
}
}
}
}
// don't advance section, simply ignore invalid @import
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
1998-11-26 08:16:22 +03:00
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
1998-04-14 00:24:54 +04:00
{
1998-11-26 08:16:22 +03:00
PRBool result = PR_FALSE;
nsICSSImportRule* rule = nsnull;
NS_NewCSSImportRule(&rule, aURLSpec, aMedia);
if (rule) {
AppendRule(rule);
NS_RELEASE(rule);
}
if (mChildLoader) {
// XXX probably need a way to encode unicode junk for the part of
// the url that follows a "?"
nsIURL* url;
nsIURLGroup* urlGroup = nsnull;
mURL->GetURLGroup(&urlGroup);
if (urlGroup) {
aErrorCode = urlGroup->CreateURL(&url, mURL, aURLSpec, nsnull);
NS_RELEASE(urlGroup);
1998-04-14 00:24:54 +04:00
}
else {
#ifndef NECKO
aErrorCode = NS_NewURL(&url, aURLSpec, mURL);
#else
nsresult rv;
NS_WITH_SERVICE(nsIIOService, service, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return PR_FALSE;
nsIURI *uri = nsnull, *baseUri = nsnull;
rv = mURL->QueryInterface(nsIURI::GetIID(), (void**)&baseUri);
if (NS_FAILED(rv)) return PR_FALSE;
const char *uriStr = aURLSpec.GetBuffer();
rv = service->NewURI(uriStr, baseUri, &uri);
NS_RELEASE(baseUri);
if (NS_FAILED(rv)) return PR_FALSE;
rv = uri->QueryInterface(nsIURL::GetIID(), (void**)&url);
NS_RELEASE(uri);
#endif // NECKO
}
1998-04-14 00:24:54 +04:00
if (NS_FAILED(aErrorCode)) {
// import url is bad
// XXX log this somewhere for easier web page debugging
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
if (NS_COMFALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
mChildLoader->LoadChildSheet(mSheet, url, aMedia, kNameSpaceID_Unknown, mChildSheetCount++);
1998-04-14 00:24:54 +04:00
}
NS_RELEASE(url);
1998-04-14 00:24:54 +04:00
}
1998-11-26 08:16:22 +03:00
return result;
1998-04-14 00:24:54 +04:00
}
// Parse a CSS2 media rule: "@media medium [, mdeium] { ... }"
PRBool CSSParserImpl::ParseMediaRule(PRInt32& aErrorCode)
{
nsAutoString mediaStr;
nsISupportsArray* media = nsnull;
NS_NewISupportsArray(&media);
if (media) {
if (GatherMedia(aErrorCode, mediaStr, media)) {
if ((0 < mediaStr.Length()) &&
ExpectSymbol(aErrorCode, '{', PR_TRUE)) {
// push media rule on stack, loop over children
nsICSSMediaRule* rule = nsnull;
NS_NewCSSMediaRule(&rule);
if (rule) {
if (PushGroup(rule)) {
nsCSSSection holdSection = mSection;
mSection = eCSSSection_General;
for (;;) {
// Get next non-whitespace token
if (! GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (mToken.IsSymbol('}')) { // done!
UngetToken();
break;
}
if (eCSSToken_AtKeyword == mToken.mType) {
SkipAtRule(aErrorCode); // @media cannot contain @rules
continue;
}
UngetToken();
ParseRuleSet(aErrorCode);
}
PopGroup();
if (ExpectSymbol(aErrorCode, '}', PR_TRUE)) {
rule->SetMedia(media);
AppendRule(rule);
NS_RELEASE(rule);
NS_RELEASE(media);
return PR_TRUE;
}
mSection = holdSection;
}
NS_RELEASE(rule);
}
else { // failed to create rule, backup and skip block
UngetToken();
}
}
}
NS_RELEASE(media);
}
return PR_FALSE;
}
// Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
PRBool CSSParserImpl::ParseNameSpaceRule(PRInt32& aErrorCode)
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
nsAutoString prefix;
nsAutoString url;
if (eCSSToken_Ident == mToken.mType) {
prefix = mToken.mIdent;
if (! GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
}
if (eCSSToken_String == mToken.mType) {
url = mToken.mIdent;
if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
ProcessNameSpace(aErrorCode, prefix, url);
return PR_TRUE;
}
}
else if ((eCSSToken_Function == mToken.mType) &&
(mToken.mIdent.EqualsIgnoreCase("url"))) {
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (GetURLToken(aErrorCode, PR_TRUE)) {
if ((eCSSToken_String == mToken.mType) || (eCSSToken_URL == mToken.mType)) {
url = mToken.mIdent;
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
if (ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
ProcessNameSpace(aErrorCode, prefix, url);
return PR_TRUE;
}
}
}
}
}
}
return PR_FALSE;
}
PRBool CSSParserImpl::ProcessNameSpace(PRInt32& aErrorCode, const nsString& aPrefix,
const nsString& aURLSpec)
{
PRBool result = PR_FALSE;
nsICSSNameSpaceRule* rule = nsnull;
nsIAtom* prefix = nsnull;
if (0 < aPrefix.Length()) {
prefix = NS_NewAtom(aPrefix);
}
NS_NewCSSNameSpaceRule(&rule, prefix, aURLSpec);
if (rule) {
AppendRule(rule);
NS_RELEASE(rule);
NS_IF_RELEASE(mNameSpace);
mSheet->GetNameSpace(mNameSpace);
}
NS_IF_RELEASE(prefix);
return result;
}
PRBool CSSParserImpl::ParseFontFaceRule(PRInt32& aErrorCode)
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
// XXX not yet implemented
return PR_FALSE;
}
PRBool CSSParserImpl::ParsePageRule(PRInt32& aErrorCode)
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
// XXX not yet implemented
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
void CSSParserImpl::SkipUntil(PRInt32& aErrorCode, PRUnichar aStopSymbol)
1998-04-14 00:24:54 +04:00
{
nsCSSToken* tk = &mToken;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Symbol == tk->mType) {
PRUnichar symbol = tk->mSymbol;
if (symbol == aStopSymbol) {
break;
} else if ('{' == symbol) {
SkipUntil(aErrorCode, '}');
} else if ('[' == symbol) {
SkipUntil(aErrorCode, ']');
} else if ('(' == symbol) {
SkipUntil(aErrorCode, ')');
}
}
}
}
PRBool
1998-10-27 02:22:40 +03:00
CSSParserImpl::SkipDeclaration(PRInt32& aErrorCode, PRBool aCheckForBraces)
1998-04-14 00:24:54 +04:00
{
nsCSSToken* tk = &mToken;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
if (eCSSToken_Symbol == tk->mType) {
PRUnichar symbol = tk->mSymbol;
if (';' == symbol) {
break;
}
if (aCheckForBraces) {
if ('}' == symbol) {
UngetToken();
break;
}
1998-04-14 00:24:54 +04:00
}
if ('{' == symbol) {
SkipUntil(aErrorCode, '}');
} else if ('(' == symbol) {
SkipUntil(aErrorCode, ')');
} else if ('[' == symbol) {
SkipUntil(aErrorCode, ']');
}
}
}
return PR_TRUE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
void CSSParserImpl::SkipRuleSet(PRInt32& aErrorCode)
1998-04-14 00:24:54 +04:00
{
nsCSSToken* tk = &mToken;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Symbol == tk->mType) {
PRUnichar symbol = tk->mSymbol;
if ('{' == symbol) {
SkipUntil(aErrorCode, '}');
break;
}
if ('(' == symbol) {
SkipUntil(aErrorCode, ')');
} else if ('[' == symbol) {
SkipUntil(aErrorCode, ']');
}
}
}
}
PRBool CSSParserImpl::PushGroup(nsICSSGroupRule* aRule)
{
if (! mGroupStack) {
NS_NewISupportsArray(&mGroupStack);
}
if (mGroupStack) {
mGroupStack->AppendElement(aRule);
return PR_TRUE;
}
return PR_FALSE;
}
void CSSParserImpl::PopGroup(void)
{
if (mGroupStack) {
PRUint32 count;
mGroupStack->Count(&count);
if (0 < count) {
mGroupStack->RemoveElementAt(count - 1);
}
}
}
void CSSParserImpl::AppendRule(nsICSSRule* aRule)
{
PRUint32 count = 0;
if (mGroupStack) {
mGroupStack->Count(&count);
}
if (0 < count) {
nsICSSGroupRule* group = (nsICSSGroupRule*)mGroupStack->ElementAt(count - 1);
group->AppendStyleRule(aRule);
NS_RELEASE(group);
}
else {
mSheet->AppendStyleRule(aRule);
}
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseRuleSet(PRInt32& aErrorCode)
1998-04-14 00:24:54 +04:00
{
// First get the list of selectors for the rule
1998-12-11 05:50:43 +03:00
SelectorList* slist = nsnull;
if (! ParseSelectorList(aErrorCode, slist)) {
1998-04-14 00:24:54 +04:00
SkipRuleSet(aErrorCode);
return PR_FALSE;
}
1998-12-11 05:50:43 +03:00
NS_ASSERTION(nsnull != slist, "null selector list");
1998-04-14 00:24:54 +04:00
// Next parse the declaration block
nsICSSDeclaration* declaration = ParseDeclarationBlock(aErrorCode, PR_TRUE);
1998-04-14 00:24:54 +04:00
if (nsnull == declaration) {
// XXX skip something here
1998-12-11 05:50:43 +03:00
delete slist;
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
#if 0
slist->Dump();
fputs("{\n", stdout);
declaration->List();
fputs("}\n", stdout);
#endif
// Translate the selector list and declaration block into style data
SelectorList* list = slist;
while (nsnull != list) {
1998-12-11 05:50:43 +03:00
nsICSSStyleRule* rule = nsnull;
NS_NewCSSStyleRule(&rule, *(list->mSelectors));
1998-05-19 01:07:54 +04:00
if (nsnull != rule) {
1998-12-11 05:50:43 +03:00
if (nsnull != list->mSelectors->mNext) { // hand off other selectors to new rule
nsCSSSelector* ruleFirst = rule->FirstSelector();
ruleFirst->mNext = list->mSelectors->mNext;
list->mSelectors->mNext = nsnull;
1998-04-14 00:24:54 +04:00
}
rule->SetDeclaration(declaration);
1999-02-27 10:15:59 +03:00
rule->SetWeight(list->mWeight);
rule->SetSourceSelectorText(list->mSourceString); // capture the original input (need this for namespace prefixes)
1998-04-14 00:24:54 +04:00
// rule->List();
AppendRule(rule);
1998-04-14 00:24:54 +04:00
NS_RELEASE(rule);
}
list = list->mNext;
}
// Release temporary storage
1998-12-11 05:50:43 +03:00
delete slist;
1998-04-14 00:24:54 +04:00
NS_RELEASE(declaration);
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseSelectorList(PRInt32& aErrorCode,
1998-12-11 05:50:43 +03:00
SelectorList*& aListHead)
1998-04-14 00:24:54 +04:00
{
1998-12-11 05:50:43 +03:00
SelectorList* list = nsnull;
if (! ParseSelectorGroup(aErrorCode, list)) {
1998-04-14 00:24:54 +04:00
// must have at least one selector group
1998-12-11 05:50:43 +03:00
aListHead = nsnull;
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1998-12-11 05:50:43 +03:00
NS_ASSERTION(nsnull != list, "no selector list");
aListHead = list;
1998-04-14 00:24:54 +04:00
// After that there must either be a "," or a "{"
nsCSSToken* tk = &mToken;
for (;;) {
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_TRUE)) {
break;
1998-04-14 00:24:54 +04:00
}
if (eCSSToken_Symbol != tk->mType) {
UngetToken();
1998-12-11 05:50:43 +03:00
break;
1998-04-14 00:24:54 +04:00
}
if (',' == tk->mSymbol) {
1998-12-11 05:50:43 +03:00
SelectorList* newList = nsnull;
1998-04-14 00:24:54 +04:00
// Another selector group must follow
1998-12-11 05:50:43 +03:00
if (! ParseSelectorGroup(aErrorCode, newList)) {
break;
1998-04-14 00:24:54 +04:00
}
// add new list to the end of the selector list
1998-12-11 05:50:43 +03:00
list->mNext = newList;
list = newList;
1998-04-14 00:24:54 +04:00
continue;
} else if ('{' == tk->mSymbol) {
UngetToken();
1998-12-11 05:50:43 +03:00
return PR_TRUE;
1998-04-14 00:24:54 +04:00
} else {
UngetToken();
1998-12-11 05:50:43 +03:00
break;
1998-04-14 00:24:54 +04:00
}
}
1998-12-11 05:50:43 +03:00
delete aListHead;
aListHead = nsnull;
return PR_FALSE;
}
static PRBool IsPseudoClass(const nsIAtom* aAtom)
{
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
1999-02-27 10:15:59 +03:00
(nsCSSAtoms::disabledPseudo == aAtom) ||
(nsCSSAtoms::dragOverPseudo == aAtom) ||
(nsCSSAtoms::dragPseudo == aAtom) ||
1999-02-27 10:15:59 +03:00
(nsCSSAtoms::enabledPseudo == aAtom) ||
1998-12-11 05:50:43 +03:00
(nsCSSAtoms::firstChildPseudo == aAtom) ||
(nsCSSAtoms::focusPseudo == aAtom) ||
(nsCSSAtoms::hoverPseudo == aAtom) ||
(nsCSSAtoms::langPseudo == aAtom) ||
(nsCSSAtoms::linkPseudo == aAtom) ||
(nsCSSAtoms::outOfDatePseudo == aAtom) ||
1999-02-27 10:15:59 +03:00
(nsCSSAtoms::selectedPseudo == aAtom) ||
1998-12-11 05:50:43 +03:00
(nsCSSAtoms::visitedPseudo == aAtom));
}
static PRBool IsSinglePseudoClass(const nsCSSSelector& aSelector)
{
return PRBool((aSelector.mNameSpace == kNameSpaceID_Unknown) &&
(aSelector.mTag == nsnull) &&
(aSelector.mID == nsnull) &&
(aSelector.mClassList == nsnull) &&
(aSelector.mAttrList == nsnull) &&
(aSelector.mPseudoClassList != nsnull) &&
(aSelector.mPseudoClassList->mNext == nsnull));
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseSelectorGroup(PRInt32& aErrorCode,
1998-12-11 05:50:43 +03:00
SelectorList*& aList)
1998-04-14 00:24:54 +04:00
{
nsAutoString sourceBuffer;
1998-12-11 05:50:43 +03:00
SelectorList* list = nsnull;
1999-02-27 10:15:59 +03:00
PRUnichar combinator = PRUnichar(0);
PRInt32 weight = 0;
PRBool havePseudoElement = PR_FALSE;
1998-04-14 00:24:54 +04:00
for (;;) {
1998-12-11 05:50:43 +03:00
nsCSSSelector selector;
if (! ParseSelector(aErrorCode, selector, sourceBuffer)) {
1998-04-14 00:24:54 +04:00
break;
}
1998-12-11 05:50:43 +03:00
if (nsnull == list) {
list = new SelectorList();
1999-02-10 11:37:52 +03:00
if (nsnull == list) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
1998-12-11 05:50:43 +03:00
}
sourceBuffer.Append(PRUnichar(' '));
1998-12-11 05:50:43 +03:00
list->AddSelector(selector);
nsCSSSelector* listSel = list->mSelectors;
// pull out pseudo elements here
nsAtomList* prevList = nsnull;
nsAtomList* pseudoClassList = listSel->mPseudoClassList;
while (nsnull != pseudoClassList) {
if (! IsPseudoClass(pseudoClassList->mAtom)) {
1999-02-27 10:15:59 +03:00
havePseudoElement = PR_TRUE;
1998-12-11 05:50:43 +03:00
if (IsSinglePseudoClass(*listSel)) { // convert to pseudo element selector
nsIAtom* pseudoElement = pseudoClassList->mAtom; // steal ref count
pseudoClassList->mAtom = nsnull;
listSel->Reset();
1999-04-16 01:22:41 +04:00
if (listSel->mNext) {// more to the selector
listSel->mOperator = PRUnichar('>');
nsCSSSelector empty;
list->AddSelector(empty); // leave a blank (universal) selector in the middle
listSel = list->mSelectors; // use the new one for the pseudo
}
1998-12-11 05:50:43 +03:00
listSel->mTag = pseudoElement;
}
else { // append new pseudo element selector
selector.Reset();
selector.mTag = pseudoClassList->mAtom; // steal ref count
list->AddSelector(selector);
pseudoClassList->mAtom = nsnull;
1999-02-27 10:15:59 +03:00
listSel->mOperator = PRUnichar('>');
1998-12-11 05:50:43 +03:00
if (nsnull == prevList) { // delete list entry
listSel->mPseudoClassList = pseudoClassList->mNext;
}
else {
prevList->mNext = pseudoClassList->mNext;
}
pseudoClassList->mNext = nsnull;
delete pseudoClassList;
1999-02-27 10:15:59 +03:00
weight += listSel->CalcWeight(); // capture weight from remainder
1998-12-11 05:50:43 +03:00
}
break; // only one pseudo element per selector
}
prevList = pseudoClassList;
pseudoClassList = pseudoClassList->mNext;
}
1999-02-27 10:15:59 +03:00
combinator = PRUnichar(0);
if (GetToken(aErrorCode, PR_TRUE)) {
if ((eCSSToken_Symbol == mToken.mType) &&
(('+' == mToken.mSymbol) || ('>' == mToken.mSymbol))) {
combinator = mToken.mSymbol;
list->mSelectors->SetOperator(combinator);
sourceBuffer.Append(combinator);
sourceBuffer.Append(PRUnichar(' '));
}
else {
UngetToken(); // give it back to selector
}
}
if (havePseudoElement) {
break;
}
else {
weight += selector.CalcWeight();
}
}
if (PRUnichar(0) != combinator) { // no dangling combinators
if (list) {
delete list;
}
list = nsnull;
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
aList = list;
if (nsnull != list) {
sourceBuffer.Truncate(sourceBuffer.Length() - 1); // kill trailing space
list->mSourceString = sourceBuffer;
1999-02-27 10:15:59 +03:00
list->mWeight = weight;
}
1998-12-11 05:50:43 +03:00
return PRBool(nsnull != aList);
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
#define SEL_MASK_NSPACE 0x01
#define SEL_MASK_ELEM 0x02
#define SEL_MASK_ID 0x04
#define SEL_MASK_CLASS 0x08
#define SEL_MASK_ATTRIB 0x10
#define SEL_MASK_PCLASS 0x20
#define SEL_MASK_PELEM 0x40
1998-05-19 01:07:54 +04:00
1998-04-14 00:24:54 +04:00
/**
1998-12-11 05:50:43 +03:00
* This is the format for selectors:
* operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
1998-04-14 00:24:54 +04:00
*/
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
nsCSSSelector& aSelector,
nsString& aSource)
1998-04-14 00:24:54 +04:00
{
1998-12-11 05:50:43 +03:00
PRInt32 dataMask = 0;
nsAutoString buffer;
1998-04-14 00:24:54 +04:00
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_TRUE)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
mToken.AppendToString(aSource);
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { // was namespace
mToken.AppendToString(aSource);
dataMask |= SEL_MASK_NSPACE;
aSelector.SetNameSpace(kNameSpaceID_Unknown); // namespace wildcard
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // element name
dataMask |= SEL_MASK_ELEM;
if (mCaseSensitive) {
aSelector.SetTag(mToken.mIdent);
}
else {
mToken.mIdent.ToLowerCase(buffer);
aSelector.SetTag(buffer);
}
}
else if (mToken.IsSymbol('*')) { // universal selector
dataMask |= SEL_MASK_ELEM;
// don't set tag
}
else {
UngetToken();
return PR_FALSE;
}
}
else { // was universal element selector
aSelector.SetNameSpace(kNameSpaceID_Unknown); // wildcard
if (mNameSpace) { // look for default namespace
nsINameSpace* defaultNameSpace = nsnull;
mNameSpace->FindNameSpace(nsnull, defaultNameSpace);
if (defaultNameSpace) {
PRInt32 defaultID;
defaultNameSpace->GetNameSpaceID(defaultID);
aSelector.SetNameSpace(defaultID);
NS_RELEASE(defaultNameSpace);
}
}
dataMask |= SEL_MASK_ELEM;
// don't set any tag in the selector
}
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
}
else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name
mToken.AppendToString(aSource);
buffer = mToken.mIdent; // hang on to ident
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { // was namespace
mToken.AppendToString(aSource);
dataMask |= SEL_MASK_NSPACE;
PRInt32 nameSpaceID = kNameSpaceID_Unknown;
if (mNameSpace) {
nsIAtom* prefix;
if (mCaseSensitive) {
prefix = NS_NewAtom(buffer);
}
else {
buffer.ToLowerCase();
prefix = NS_NewAtom(buffer);
}
mNameSpace->FindNameSpaceID(prefix, nameSpaceID);
NS_IF_RELEASE(prefix);
} // else, no delcared namespaces
if (kNameSpaceID_Unknown == nameSpaceID) { // unknown prefix, dump it
return PR_FALSE;
}
aSelector.SetNameSpace(nameSpaceID);
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // element name
dataMask |= SEL_MASK_ELEM;
if (mCaseSensitive) {
aSelector.SetTag(mToken.mIdent);
}
else {
mToken.mIdent.ToLowerCase(buffer);
aSelector.SetTag(buffer);
}
}
else if (mToken.IsSymbol('*')) { // universal selector
dataMask |= SEL_MASK_ELEM;
// don't set tag
}
else {
UngetToken();
return PR_FALSE;
}
}
else { // was element name
aSelector.SetNameSpace(kNameSpaceID_Unknown); // wildcard
if (mNameSpace) { // look for default namespace
nsINameSpace* defaultNameSpace = nsnull;
mNameSpace->FindNameSpace(nsnull, defaultNameSpace);
if (defaultNameSpace) {
PRInt32 defaultID;
defaultNameSpace->GetNameSpaceID(defaultID);
aSelector.SetNameSpace(defaultID);
NS_RELEASE(defaultNameSpace);
}
}
if (mCaseSensitive) {
aSelector.SetTag(buffer);
}
else {
buffer.ToLowerCase();
aSelector.SetTag(buffer);
}
dataMask |= SEL_MASK_ELEM;
}
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
return PR_TRUE;
}
}
else if (mToken.IsSymbol('|')) { // No namespace
mToken.AppendToString(aSource);
dataMask |= SEL_MASK_NSPACE;
aSelector.SetNameSpace(kNameSpaceID_None); // explicit NO namespace
// get mandatory tag
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // element name
dataMask |= SEL_MASK_ELEM;
1998-12-21 08:58:58 +03:00
if (mCaseSensitive) {
1998-12-11 05:50:43 +03:00
aSelector.SetTag(mToken.mIdent);
}
else {
1999-02-12 09:19:07 +03:00
mToken.mIdent.ToLowerCase(buffer);
1998-12-11 05:50:43 +03:00
aSelector.SetTag(buffer);
}
}
else if (mToken.IsSymbol('*')) { // universal selector
dataMask |= SEL_MASK_ELEM;
// don't set tag
}
else {
UngetToken();
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
}
1998-12-11 05:50:43 +03:00
for (;;) {
if (eCSSToken_ID == mToken.mType) { // #id
if ((0 == (dataMask & SEL_MASK_ID)) && // only one ID
(0 < mToken.mIdent.Length()) &&
(nsString::IsAlpha(mToken.mIdent.CharAt(0)))) { // verify is legal ID
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
dataMask |= SEL_MASK_ID;
aSelector.SetID(mToken.mIdent);
}
else {
UngetToken();
return PR_FALSE;
}
1998-05-19 01:07:54 +04:00
}
else if (mToken.IsSymbol('.')) { // .class
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_FALSE)) { // get ident
return PR_FALSE;
}
if (eCSSToken_Ident != mToken.mType) { // malformed selector (XXX what about leading digits?)
UngetToken();
return PR_FALSE;
}
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
dataMask |= SEL_MASK_CLASS;
aSelector.AddClass(mToken.mIdent); // class always case sensitive
1998-05-19 01:07:54 +04:00
}
else if (mToken.IsSymbol(':')) { // :pseudo
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
return PR_FALSE;
}
if (eCSSToken_Ident != mToken.mType) { // malformed selector
UngetToken();
return PR_FALSE;
}
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
buffer.Truncate();
buffer.Append(':');
buffer.Append(mToken.mIdent);
1999-02-12 09:19:07 +03:00
buffer.ToLowerCase();
1998-12-11 05:50:43 +03:00
nsIAtom* pseudo = NS_NewAtom(buffer);
if (IsPseudoClass(pseudo)) {
// XXX parse lang pseudo class
dataMask |= SEL_MASK_PCLASS;
aSelector.AddPseudoClass(pseudo);
}
else {
if (0 == (dataMask & SEL_MASK_PELEM)) {
dataMask |= SEL_MASK_PELEM;
aSelector.AddPseudoClass(pseudo); // store it here, it gets pulled later
// ensure selector ends here, must be followed by EOF, space, '{' or ','
if (GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
if ((eCSSToken_WhiteSpace == mToken.mType) ||
(mToken.IsSymbol('{') || mToken.IsSymbol(','))) {
UngetToken();
return PR_TRUE;
}
UngetToken();
return PR_FALSE;
}
1998-12-11 05:50:43 +03:00
}
else { // multiple pseudo elements, not legal
UngetToken();
NS_RELEASE(pseudo);
return PR_FALSE;
}
}
NS_RELEASE(pseudo);
1998-05-19 01:07:54 +04:00
}
else if (mToken.IsSymbol('[')) { // attribute
mToken.AppendToString(aSource);
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
1998-12-11 05:50:43 +03:00
return PR_FALSE;
}
mToken.AppendToString(aSource);
PRInt32 nameSpaceID = kNameSpaceID_None;
nsAutoString attr;
if (mToken.IsSymbol('*')) { // wildcard namespace
nameSpaceID = kNameSpaceID_Unknown;
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) {
mToken.AppendToString(aSource);
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent;
}
else {
UngetToken();
return PR_FALSE;
}
}
else {
return PR_FALSE;
}
}
else if (mToken.IsSymbol('|')) { // NO namespace
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent;
}
else {
UngetToken();
return PR_FALSE;
}
}
else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace
attr = mToken.mIdent; // hang on to it
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { // was a namespace
mToken.AppendToString(aSource);
nameSpaceID = kNameSpaceID_Unknown;
if (mNameSpace) {
nsIAtom* prefix;
if (mCaseSensitive) {
prefix = NS_NewAtom(attr);
}
else {
attr.ToLowerCase();
prefix = NS_NewAtom(attr);
}
mNameSpace->FindNameSpaceID(prefix, nameSpaceID);
NS_IF_RELEASE(prefix);
} // else, no delcared namespaces
if (kNameSpaceID_Unknown == nameSpaceID) { // unknown prefix, dump it
return PR_FALSE;
}
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent;
}
else {
UngetToken();
return PR_FALSE;
}
}
}
else { // malformed
1998-12-11 05:50:43 +03:00
UngetToken();
return PR_FALSE;
}
1998-12-21 08:58:58 +03:00
if (! mCaseSensitive) {
1999-02-12 09:19:07 +03:00
attr.ToLowerCase();
1998-12-11 05:50:43 +03:00
}
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
1998-12-11 05:50:43 +03:00
return PR_FALSE;
}
if (eCSSToken_Symbol == mToken.mType) {
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
PRUint8 func;
if (']' == mToken.mSymbol) {
dataMask |= SEL_MASK_ATTRIB;
aSelector.AddAttribute(nameSpaceID, attr);
1998-12-11 05:50:43 +03:00
func = NS_ATTR_FUNC_SET;
}
else if ('=' == mToken.mSymbol) {
func = NS_ATTR_FUNC_EQUALS;
}
else if ('~' == mToken.mSymbol) {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (mToken.IsSymbol('=')) {
1998-12-11 05:50:43 +03:00
func = NS_ATTR_FUNC_INCLUDES;
}
else {
UngetToken();
return PR_FALSE;
}
}
else if ('|' == mToken.mSymbol) {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
return PR_FALSE;
}
mToken.AppendToString(aSource);
if (mToken.IsSymbol('=')) {
1998-12-11 05:50:43 +03:00
func = NS_ATTR_FUNC_DASHMATCH;
}
else {
UngetToken();
return PR_FALSE;
}
}
else {
UngetToken(); // bad function
return PR_FALSE;
}
if (NS_ATTR_FUNC_SET != func) { // get value
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
1998-12-11 05:50:43 +03:00
return PR_FALSE;
}
if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) {
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
nsAutoString value(mToken.mIdent);
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
1998-12-11 05:50:43 +03:00
return PR_FALSE;
}
if (mToken.IsSymbol(']')) {
mToken.AppendToString(aSource);
1998-12-11 05:50:43 +03:00
dataMask |= SEL_MASK_ATTRIB;
aSelector.AddAttribute(nameSpaceID, attr, func, value, mCaseSensitive);
1998-12-11 05:50:43 +03:00
}
else {
UngetToken();
return PR_FALSE;
}
}
else {
UngetToken();
return PR_FALSE;
}
}
}
else {
UngetToken(); // bad dog, no biscut!
return PR_FALSE;
}
1998-05-19 01:07:54 +04:00
}
1998-12-11 05:50:43 +03:00
else { // not a selector token, we're done
break;
1998-05-19 01:07:54 +04:00
}
1998-12-11 05:50:43 +03:00
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
return PR_TRUE;
1998-05-19 01:07:54 +04:00
}
1998-04-14 00:24:54 +04:00
}
1998-12-11 05:50:43 +03:00
UngetToken();
return PRBool(0 != dataMask);
1998-04-14 00:24:54 +04:00
}
nsICSSDeclaration*
1998-10-27 02:22:40 +03:00
CSSParserImpl::ParseDeclarationBlock(PRInt32& aErrorCode,
PRBool aCheckForBraces)
1998-04-14 00:24:54 +04:00
{
if (aCheckForBraces) {
if (!ExpectSymbol(aErrorCode, '{', PR_TRUE)) {
return nsnull;
}
1998-04-14 00:24:54 +04:00
}
nsICSSDeclaration* declaration = nsnull;
if (NS_OK == NS_NewCSSDeclaration(&declaration)) {
PRInt32 count = 0;
1998-04-14 00:24:54 +04:00
for (;;) {
1998-09-30 03:50:09 +04:00
PRInt32 hint;
1998-10-27 02:22:40 +03:00
if (ParseDeclaration(aErrorCode, declaration, aCheckForBraces, hint)) {
count++; // count declarations
}
else {
if (!SkipDeclaration(aErrorCode, aCheckForBraces)) {
1998-04-14 00:24:54 +04:00
break;
}
if (aCheckForBraces) {
if (ExpectSymbol(aErrorCode, '}', PR_TRUE)) {
break;
}
}
1998-04-14 00:24:54 +04:00
// Since the skipped declaration didn't end the block we parse
// the next declaration.
}
}
if (0 == count) { // didn't get any XXX is this ok with the DOM?
NS_RELEASE(declaration);
}
1998-04-14 00:24:54 +04:00
}
return declaration;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseColor(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
char cbuf[KEYWORD_BUFFER_SIZE];
1998-04-14 00:24:54 +04:00
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
nsCSSToken* tk = &mToken;
1998-10-27 02:22:40 +03:00
nscolor rgba;
1998-04-14 00:24:54 +04:00
switch (tk->mType) {
1998-10-27 02:22:40 +03:00
case eCSSToken_ID:
// #xxyyzz
tk->mIdent.ToCString(cbuf, sizeof(cbuf));
if (NS_HexToRGB(cbuf, &rgba)) {
aValue.SetColorValue(rgba);
return PR_TRUE;
}
break;
1998-04-14 00:24:54 +04:00
1998-10-27 02:22:40 +03:00
case eCSSToken_Ident:
1998-04-14 00:24:54 +04:00
tk->mIdent.ToCString(cbuf, sizeof(cbuf));
1998-10-27 02:22:40 +03:00
if (NS_ColorNameToRGB(cbuf, &rgba)) {
aValue.SetStringValue(tk->mIdent, eCSSUnit_String);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
break;
case eCSSToken_Function:
if (mToken.mIdent.EqualsIgnoreCase("rgb")) {
// rgb ( component , component , component )
PRUint8 r, g, b;
if (ExpectSymbol(aErrorCode, '(', PR_FALSE) &&
ParseColorComponent(aErrorCode, r, ',') &&
ParseColorComponent(aErrorCode, g, ',') &&
ParseColorComponent(aErrorCode, b, ')')) {
nscolor rgba = NS_RGB(r,g,b);
aValue.SetColorValue(rgba);
return PR_TRUE;
}
return PR_FALSE; // already pushed back
1998-04-14 00:24:54 +04:00
}
break;
1998-10-27 02:22:40 +03:00
default:
break;
1998-04-14 00:24:54 +04:00
}
// It's not a color
UngetToken();
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseColorComponent(PRInt32& aErrorCode,
PRUint8& aComponent,
1998-04-14 00:24:54 +04:00
char aStop)
{
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
float value;
nsCSSToken* tk = &mToken;
switch (tk->mType) {
case eCSSToken_Number:
value = tk->mNumber;
break;
case eCSSToken_Percentage:
value = tk->mNumber * 255.0f;
break;
default:
UngetToken();
return PR_FALSE;
}
if (ExpectSymbol(aErrorCode, aStop, PR_TRUE)) {
if (value < 0.0f) value = 0.0f;
if (value > 255.0f) value = 255.0f;
1998-10-27 02:22:40 +03:00
aComponent = (PRUint8) value;
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
return PR_FALSE;
}
//----------------------------------------------------------------------
PRBool
1998-10-27 02:22:40 +03:00
CSSParserImpl::ParseDeclaration(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration,
1998-09-30 03:50:09 +04:00
PRBool aCheckForBraces,
1998-10-27 02:22:40 +03:00
PRInt32& aChangeHint)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
aChangeHint = NS_STYLE_HINT_UNKNOWN;
1998-09-30 03:50:09 +04:00
1998-04-14 00:24:54 +04:00
// Get property name
nsCSSToken* tk = &mToken;
char propertyName[100];
1998-04-14 00:24:54 +04:00
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
if (eCSSToken_Ident == tk->mType) {
tk->mIdent.ToCString(propertyName, sizeof(propertyName));
// grab the ident before the ExpectSymbol trashes the token
1998-04-14 00:24:54 +04:00
if (!ExpectSymbol(aErrorCode, ':', PR_TRUE)) {
return PR_FALSE;
}
break;
}
if (tk->IsSymbol(';')) {
1998-04-14 00:24:54 +04:00
// dangling semicolons are skipped
continue;
}
// Not a declaration...
UngetToken();
return PR_FALSE;
}
// Map property name to it's ID and then parse the property
1998-10-27 02:22:40 +03:00
PRInt32 propID = nsCSSProps::LookupName(propertyName);
if (0 > propID) { // unknown property
return PR_FALSE;
}
if (! ParseProperty(aErrorCode, aDeclaration, propID, aChangeHint)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
// See if the declaration is followed by a "!important" declaration
PRBool isImportant = PR_FALSE;
if (!GetToken(aErrorCode, PR_TRUE)) {
if (aCheckForBraces) {
// Premature eof is not ok when proper termination is mandated
return PR_FALSE;
}
return PR_TRUE;
}
else {
if (eCSSToken_Symbol == tk->mType) {
if ('!' == tk->mSymbol) {
// Look for important ident
if (!GetToken(aErrorCode, PR_TRUE)) {
// Premature eof is not ok
return PR_FALSE;
}
if ((eCSSToken_Ident != tk->mType) ||
!tk->mIdent.EqualsIgnoreCase("important")) {
UngetToken();
return PR_FALSE;
}
isImportant = PR_TRUE;
}
else {
// Not a !important declaration
UngetToken();
}
}
else {
// Not a !important declaration
UngetToken();
}
}
1998-06-26 09:51:55 +04:00
if (PR_TRUE == isImportant) {
1998-11-06 03:52:30 +03:00
aDeclaration->SetValueImportant(propID);
1998-06-26 09:51:55 +04:00
}
1998-04-14 00:24:54 +04:00
// Make sure valid property declaration is terminated with either a
// semicolon or a right-curly-brace (when aCheckForBraces is true).
// When aCheckForBraces is false, proper termination is either
// semicolon or EOF.
1998-04-14 00:24:54 +04:00
if (!GetToken(aErrorCode, PR_TRUE)) {
if (aCheckForBraces) {
// Premature eof is not ok
return PR_FALSE;
}
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
if (eCSSToken_Symbol == tk->mType) {
if (';' == tk->mSymbol) {
return PR_TRUE;
}
if (!aCheckForBraces) {
// If we didn't hit eof and we didn't see a semicolon then the
// declaration is not properly terminated.
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
if ('}' == tk->mSymbol) {
UngetToken();
return PR_TRUE;
}
}
return PR_FALSE;
}
// Flags for ParseVariant method
1998-10-27 02:22:40 +03:00
#define VARIANT_KEYWORD 0x000001 // K
#define VARIANT_LENGTH 0x000002 // L
#define VARIANT_PERCENT 0x000004 // P
#define VARIANT_COLOR 0x000008 // C
#define VARIANT_URL 0x000010 // U
#define VARIANT_NUMBER 0x000020 // N
#define VARIANT_INTEGER 0x000040 // I
#define VARIANT_ANGLE 0x000080 // G
#define VARIANT_FREQUENCY 0x000100 // F
#define VARIANT_TIME 0x000200 // T
#define VARIANT_STRING 0x000400 // S
#define VARIANT_COUNTER 0x000800 //
#define VARIANT_ATTR 0x001000 //
#define VARIANT_IDENTIFIER 0x002000 // D
#define VARIANT_AUTO 0x010000 // A
#define VARIANT_INHERIT 0x020000 // H
#define VARIANT_NONE 0x040000 // O
#define VARIANT_NORMAL 0x080000 // M
1998-04-14 00:24:54 +04:00
// Common combinations of variants
1998-10-27 02:22:40 +03:00
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
#define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)
#define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
#define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)
#define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)
1998-10-27 02:22:40 +03:00
#define VARIANT_AHUK (VARIANT_AH | VARIANT_URL | VARIANT_KEYWORD)
#define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)
1998-10-27 02:22:40 +03:00
#define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
1998-05-27 03:16:55 +04:00
#define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)
1998-10-27 02:22:40 +03:00
#define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)
#define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)
#define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
1998-04-30 23:57:36 +04:00
#define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)
1998-10-27 02:22:40 +03:00
#define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)
#define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)
#define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
1998-10-27 02:22:40 +03:00
#define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
#define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
#define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)
#define VARIANT_HMKI (VARIANT_HMK | VARIANT_INTEGER)
#define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)
#define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)
#define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
#define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
#define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
1998-10-27 02:22:40 +03:00
#define VARIANT_HOK (VARIANT_HK | VARIANT_NONE)
#define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)
#define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
#define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
static const PRInt32 kBorderTopIDs[] = {
PROP_BORDER_TOP_WIDTH,
PROP_BORDER_TOP_STYLE,
PROP_BORDER_TOP_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
static const PRInt32 kBorderRightIDs[] = {
PROP_BORDER_RIGHT_WIDTH,
PROP_BORDER_RIGHT_STYLE,
PROP_BORDER_RIGHT_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
static const PRInt32 kBorderBottomIDs[] = {
PROP_BORDER_BOTTOM_WIDTH,
PROP_BORDER_BOTTOM_STYLE,
PROP_BORDER_BOTTOM_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
static const PRInt32 kBorderLeftIDs[] = {
PROP_BORDER_LEFT_WIDTH,
PROP_BORDER_LEFT_STYLE,
PROP_BORDER_LEFT_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
PRInt32 CSSParserImpl::SearchKeywordTable(PRInt32 aKeywordID, const PRInt32 aKeywordTable[])
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
PRInt32 index = 0;
while (0 <= aKeywordTable[index]) {
if (aKeywordID == aKeywordTable[index++]) {
return index;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
index++;
1998-04-14 00:24:54 +04:00
}
return -1;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseEnum(PRInt32& aErrorCode, nsCSSValue& aValue,
const PRInt32 aKeywordTable[])
1998-04-14 00:24:54 +04:00
{
nsString* ident = NextIdent(aErrorCode);
if (nsnull == ident) {
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
char cbuf[KEYWORD_BUFFER_SIZE];
1998-04-14 00:24:54 +04:00
ident->ToCString(cbuf, sizeof(cbuf));
1998-10-27 02:22:40 +03:00
PRInt32 keyword = nsCSSKeywords::LookupName(cbuf);
if (0 <= keyword) {
PRInt32 index = SearchKeywordTable(keyword, aKeywordTable);
if (0 < index) {
aValue.SetIntValue(aKeywordTable[index], eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
}
// Put the unknown identifier back and return
UngetToken();
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::TranslateDimension(nsCSSValue& aValue,
PRInt32 aVariantMask,
float aNumber,
1999-02-10 11:37:52 +03:00
const nsString& aUnit)
1998-04-14 00:24:54 +04:00
{
nsCSSUnit units;
1998-10-27 02:22:40 +03:00
PRInt32 type = 0;
if (0 != aUnit.Length()) {
char cbuf[KEYWORD_BUFFER_SIZE];
aUnit.ToCString(cbuf, sizeof(cbuf));
1998-04-14 00:24:54 +04:00
PRInt32 id = nsCSSKeywords::LookupName(cbuf);
switch (id) {
1998-10-27 02:22:40 +03:00
case KEYWORD_EM: units = eCSSUnit_EM; type = VARIANT_LENGTH; break;
case KEYWORD_EX: units = eCSSUnit_XHeight; type = VARIANT_LENGTH; break;
case KEYWORD_PX: units = eCSSUnit_Pixel; type = VARIANT_LENGTH; break;
case KEYWORD_IN: units = eCSSUnit_Inch; type = VARIANT_LENGTH; break;
case KEYWORD_CM: units = eCSSUnit_Centimeter; type = VARIANT_LENGTH; break;
case KEYWORD_MM: units = eCSSUnit_Millimeter; type = VARIANT_LENGTH; break;
case KEYWORD_PT: units = eCSSUnit_Point; type = VARIANT_LENGTH; break;
case KEYWORD_PC: units = eCSSUnit_Pica; type = VARIANT_LENGTH; break;
case KEYWORD_DEG: units = eCSSUnit_Degree; type = VARIANT_ANGLE; break;
case KEYWORD_GRAD: units = eCSSUnit_Grad; type = VARIANT_ANGLE; break;
case KEYWORD_RAD: units = eCSSUnit_Radian; type = VARIANT_ANGLE; break;
case KEYWORD_HZ: units = eCSSUnit_Hertz; type = VARIANT_FREQUENCY; break;
case KEYWORD_KHZ: units = eCSSUnit_Kilohertz; type = VARIANT_FREQUENCY; break;
case KEYWORD_S: units = eCSSUnit_Seconds; type = VARIANT_TIME; break;
case KEYWORD_MS: units = eCSSUnit_Milliseconds; type = VARIANT_TIME; break;
default:
// unknown unit
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
} else {
// Must be a zero number...
1998-10-27 02:22:40 +03:00
NS_ASSERTION(0 == aNumber, "numbers without units must be 0");
if ((VARIANT_LENGTH & aVariantMask) != 0) {
units = eCSSUnit_Point;
type = VARIANT_LENGTH;
}
else if ((VARIANT_ANGLE & aVariantMask) != 0) {
units = eCSSUnit_Degree;
type = VARIANT_ANGLE;
}
else if ((VARIANT_FREQUENCY & aVariantMask) != 0) {
units = eCSSUnit_Hertz;
type = VARIANT_FREQUENCY;
}
else if ((VARIANT_TIME & aVariantMask) != 0) {
units = eCSSUnit_Seconds;
type = VARIANT_TIME;
}
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
if ((type & aVariantMask) != 0) {
aValue.SetFloatValue(aNumber, units);
return PR_TRUE;
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParsePositiveVariant(PRInt32& aErrorCode,
1999-02-10 11:37:52 +03:00
nsCSSValue& aValue,
PRInt32 aVariantMask,
1999-02-10 11:37:52 +03:00
const PRInt32 aKeywordTable[])
{
1999-02-10 11:37:52 +03:00
if (ParseVariant(aErrorCode, aValue, aVariantMask, aKeywordTable)) {
if (eCSSUnit_Number == aValue.GetUnit() ||
aValue.IsLengthUnit()){
if (aValue.GetFloatValue() < 0) {
return PR_FALSE;
}
}
1999-02-10 11:37:52 +03:00
else if(aValue.GetUnit() == eCSSUnit_Percent) {
if (aValue.GetPercentValue() < 0) {
return PR_FALSE;
}
}
return PR_TRUE;
}
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseVariant(PRInt32& aErrorCode, nsCSSValue& aValue,
PRInt32 aVariantMask,
1999-02-10 11:37:52 +03:00
const PRInt32 aKeywordTable[])
1998-10-27 02:22:40 +03:00
{
1998-04-14 00:24:54 +04:00
if (!GetToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
nsCSSToken* tk = &mToken;
if (((aVariantMask & (VARIANT_AHK | VARIANT_NORMAL | VARIANT_NONE)) != 0) &&
1998-04-14 00:24:54 +04:00
(eCSSToken_Ident == tk->mType)) {
1998-10-27 02:22:40 +03:00
char cbuf[KEYWORD_BUFFER_SIZE];
1998-04-14 00:24:54 +04:00
tk->mIdent.ToCString(cbuf, sizeof(cbuf));
1998-10-27 02:22:40 +03:00
PRInt32 keyword = nsCSSKeywords::LookupName(cbuf);
if (0 <= keyword) { // known keyword
if ((aVariantMask & VARIANT_AUTO) != 0) {
if (KEYWORD_AUTO == keyword) {
aValue.SetAutoValue();
1998-04-30 23:57:36 +04:00
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
if ((aVariantMask & VARIANT_INHERIT) != 0) {
if (KEYWORD_INHERIT == keyword) {
aValue.SetInheritValue();
1998-04-30 23:57:36 +04:00
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
if ((aVariantMask & VARIANT_NONE) != 0) {
if (KEYWORD_NONE == keyword) {
aValue.SetNoneValue();
1998-04-30 23:57:36 +04:00
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
if ((aVariantMask & VARIANT_NORMAL) != 0) {
if (KEYWORD_NORMAL == keyword) {
aValue.SetNormalValue();
1998-04-30 23:57:36 +04:00
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
if ((aVariantMask & VARIANT_KEYWORD) != 0) {
PRInt32 index = SearchKeywordTable(keyword, aKeywordTable);
if (0 < index) {
aValue.SetIntValue(aKeywordTable[index], eCSSUnit_Enumerated);
1998-04-30 23:57:36 +04:00
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
}
}
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & (VARIANT_LENGTH | VARIANT_ANGLE | VARIANT_FREQUENCY | VARIANT_TIME)) != 0) &&
tk->IsDimension()) {
1999-02-10 11:37:52 +03:00
return TranslateDimension(aValue, aVariantMask, tk->mNumber, tk->mIdent);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & VARIANT_PERCENT) != 0) &&
1998-04-14 00:24:54 +04:00
(eCSSToken_Percentage == tk->mType)) {
1998-10-27 02:22:40 +03:00
aValue.SetPercentValue(tk->mNumber);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & VARIANT_NUMBER) != 0) &&
1998-04-14 00:24:54 +04:00
(eCSSToken_Number == tk->mType)) {
1998-10-27 02:22:40 +03:00
aValue.SetFloatValue(tk->mNumber, eCSSUnit_Number);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & VARIANT_INTEGER) != 0) &&
1998-04-14 00:24:54 +04:00
(eCSSToken_Number == tk->mType) && tk->mIntegerValid) {
1998-10-27 02:22:40 +03:00
aValue.SetIntValue(tk->mInteger, eCSSUnit_Integer);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
if (PR_TRUE == mNavQuirkMode) { // NONSTANDARD: Nav interprets unitless numbers as px
if (((aVariantMask & VARIANT_LENGTH) != 0) &&
(eCSSToken_Number == tk->mType)) {
aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel);
return PR_TRUE;
}
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & VARIANT_URL) != 0) &&
(eCSSToken_Function == tk->mType) &&
tk->mIdent.EqualsIgnoreCase("url")) {
if (ParseURL(aErrorCode, aValue)) {
return PR_TRUE;
1998-05-12 03:28:47 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
if ((aVariantMask & VARIANT_COLOR) != 0) {
if ((eCSSToken_ID == tk->mType) ||
(eCSSToken_Ident == tk->mType) ||
((eCSSToken_Function == tk->mType) &&
(tk->mIdent.EqualsIgnoreCase("rgb")))) {
1998-04-14 00:24:54 +04:00
// Put token back so that parse color can get it
UngetToken();
1998-10-27 02:22:40 +03:00
if (ParseColor(aErrorCode, aValue)) {
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
return PR_FALSE;
}
}
1998-10-27 02:22:40 +03:00
if (((aVariantMask & VARIANT_STRING) != 0) &&
(eCSSToken_String == tk->mType)) {
nsAutoString buffer;
buffer.Append(tk->mSymbol);
buffer.Append(tk->mIdent);
buffer.Append(tk->mSymbol);
aValue.SetStringValue(buffer, eCSSUnit_String);
return PR_TRUE;
}
if (((aVariantMask & VARIANT_IDENTIFIER) != 0) &&
(eCSSToken_Ident == tk->mType)) {
aValue.SetStringValue(tk->mIdent, eCSSUnit_String);
return PR_TRUE;
}
if (((aVariantMask & VARIANT_COUNTER) != 0) &&
(eCSSToken_Function == tk->mType) &&
(tk->mIdent.EqualsIgnoreCase("counter") ||
tk->mIdent.EqualsIgnoreCase("counters"))) {
if (ParseCounter(aErrorCode, aValue)) {
return PR_TRUE;
}
return PR_FALSE;
}
if (((aVariantMask & VARIANT_ATTR) != 0) &&
(eCSSToken_Function == tk->mType) &&
tk->mIdent.EqualsIgnoreCase("attr")) {
if (ParseAttr(aErrorCode, aValue)) {
return PR_TRUE;
}
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
UngetToken();
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseCounter(PRInt32& aErrorCode, nsCSSValue& aValue)
{
nsCSSUnit unit = (mToken.mIdent.EqualsIgnoreCase("counter") ?
eCSSUnit_Counter : eCSSUnit_Counters);
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (GetToken(aErrorCode, PR_TRUE)) {
if (eCSSToken_Ident == mToken.mType) {
nsAutoString counter;
counter.Append(mToken.mIdent);
if (eCSSUnit_Counters == unit) {
// get mandatory string
if (! ExpectSymbol(aErrorCode, ',', PR_TRUE)) {
return PR_FALSE;
}
if (GetToken(aErrorCode, PR_TRUE) && (eCSSToken_String == mToken.mType)) {
counter.Append(',');
counter.Append(mToken.mSymbol); // quote too
counter.Append(mToken.mIdent);
counter.Append(mToken.mSymbol); // quote too
}
else {
UngetToken();
return PR_FALSE;
}
}
// get optional type
if (ExpectSymbol(aErrorCode, ',', PR_TRUE)) {
if (GetToken(aErrorCode, PR_TRUE) && (eCSSToken_Ident == mToken.mType)) {
char cbuf[KEYWORD_BUFFER_SIZE];
mToken.mIdent.ToCString(cbuf, sizeof(cbuf));
PRInt32 keyword = nsCSSKeywords::LookupName(cbuf);
if ((0 <= keyword) &&
(0 < SearchKeywordTable(keyword, nsCSSProps::kListStyleKTable))) {
counter.Append(',');
counter.Append(mToken.mIdent);
}
else {
return PR_FALSE;
}
}
else {
UngetToken();
return PR_FALSE;
}
}
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
aValue.SetStringValue(counter, unit);
return PR_TRUE;
}
}
else {
UngetToken();
}
}
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseAttr(PRInt32& aErrorCode, nsCSSValue& aValue)
{
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (GetToken(aErrorCode, PR_TRUE)) {
nsAutoString attr;
if (eCSSToken_Ident == mToken.mType) { // attr name or namespace
nsAutoString holdIdent(mToken.mIdent);
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { // namespace
PRInt32 nameSpaceID = kNameSpaceID_Unknown;
if (mNameSpace) {
nsIAtom* prefix;
if (mCaseSensitive) {
prefix = NS_NewAtom(holdIdent);
}
else {
holdIdent.ToLowerCase();
prefix = NS_NewAtom(holdIdent);
}
mNameSpace->FindNameSpaceID(prefix, nameSpaceID);
NS_IF_RELEASE(prefix);
} // else, no delcared namespaces
if (kNameSpaceID_Unknown == nameSpaceID) { // unknown prefix, dump it
return PR_FALSE;
}
attr.Append(nameSpaceID, 10);
attr.Append('|');
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
if (eCSSToken_Ident == mToken.mType) {
attr.Append(mToken.mIdent);
}
else {
UngetToken();
return PR_FALSE;
}
}
else { // no namespace
attr = holdIdent;
}
}
else if (mToken.IsSymbol('*')) { // namespace wildcard
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) {
attr.Append(kNameSpaceID_Unknown, 10);
attr.Append('|');
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
if (eCSSToken_Ident == mToken.mType) {
attr.Append(mToken.mIdent);
}
else {
UngetToken();
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
}
else {
return PR_FALSE;
}
}
else if (mToken.IsSymbol('|')) { // explicit NO namespace
if (! GetToken(aErrorCode, PR_FALSE)) {
return PR_FALSE;
}
if (eCSSToken_Ident == mToken.mType) {
1998-10-27 02:22:40 +03:00
attr.Append(mToken.mIdent);
}
else {
UngetToken();
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
}
else {
UngetToken();
return PR_FALSE;
}
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
aValue.SetStringValue(attr, eCSSUnit_Attr);
return PR_TRUE;
1998-10-27 02:22:40 +03:00
}
}
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseURL(PRInt32& aErrorCode, nsCSSValue& aValue)
{
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (! GetURLToken(aErrorCode, PR_TRUE)) {
return PR_FALSE;
}
nsCSSToken* tk = &mToken;
if ((eCSSToken_String == tk->mType) || (eCSSToken_URL == tk->mType)) {
// Translate url into an absolute url if the url is relative to
// the style sheet.
// XXX editors won't like this - too bad for now
nsAutoString absURL;
if (nsnull != mURL) {
nsString baseURL;
nsresult rv;
#ifndef NECKO
rv = NS_MakeAbsoluteURL(mURL, baseURL, tk->mIdent, absURL);
#else
NS_WITH_SERVICE(nsIIOService, service, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return PR_FALSE;
nsIURI *baseUri = nsnull;
rv = mURL->QueryInterface(nsIURI::GetIID(), (void**)&baseUri);
if (NS_FAILED(rv)) return PR_FALSE;
char *absUrlStr = nsnull;
const char *urlSpec = (tk->mIdent).GetBuffer();
rv = service->MakeAbsolute(urlSpec, baseUri, &absUrlStr);
NS_RELEASE(baseUri);
absURL = absUrlStr;
delete [] absUrlStr;
#endif // NECKO
if (NS_FAILED(rv)) {
absURL = tk->mIdent;
}
}
else {
1998-10-27 02:22:40 +03:00
absURL = tk->mIdent;
}
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
aValue.SetStringValue(absURL, eCSSUnit_URL);
return PR_TRUE;
}
}
}
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
PRInt32 CSSParserImpl::ParseChoice(PRInt32& aErrorCode, nsCSSValue aValues[],
1998-10-27 02:22:40 +03:00
const PRInt32 aPropIDs[], PRInt32 aNumIDs)
1998-04-14 00:24:54 +04:00
{
PRInt32 found = 0;
1999-02-10 11:37:52 +03:00
PRInt32 loop;
1998-10-27 02:22:40 +03:00
for (loop = 0; loop < aNumIDs; loop++) {
1998-04-14 00:24:54 +04:00
// Try each property parser in order
1998-10-27 02:22:40 +03:00
PRInt32 hadFound = found;
1999-02-10 11:37:52 +03:00
PRInt32 index;
1998-10-27 02:22:40 +03:00
for (index = 0; index < aNumIDs; index++) {
PRInt32 bit = 1 << index;
1998-04-14 00:24:54 +04:00
if ((found & bit) == 0) {
1999-02-10 11:37:52 +03:00
if (ParseSingleValueProperty(aErrorCode, aValues[index], aPropIDs[index])) {
1998-04-14 00:24:54 +04:00
found |= bit;
}
}
}
1998-10-27 02:22:40 +03:00
if (found == hadFound) { // found nothing new
break;
}
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if (0 < found) {
if (1 == found) { // only first property
if (eCSSUnit_Inherit == aValues[0].GetUnit()) { // one inherit, all inherit
for (loop = 1; loop < aNumIDs; loop++) {
aValues[loop].SetInheritValue();
}
found = ((1 << aNumIDs) - 1);
}
}
else { // more than one value, verify no inherits
for (loop = 0; loop < aNumIDs; loop++) {
if (eCSSUnit_Inherit == aValues[loop].GetUnit()) {
found = -1;
break;
}
}
}
}
1998-04-14 00:24:54 +04:00
return found;
}
/**
* Parse a "box" property. Box properties have 1 to 4 values. When less
* than 4 values are provided a standard mapping is used to replicate
1999-02-10 11:37:52 +03:00
* existing values.
1998-04-14 00:24:54 +04:00
*/
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBoxProperties(PRInt32& aErrorCode,
1998-04-14 00:24:54 +04:00
nsICSSDeclaration* aDeclaration,
1998-10-27 02:22:40 +03:00
const PRInt32 aPropIDs[])
1998-04-14 00:24:54 +04:00
{
// Get up to four values for the property
1999-02-10 11:37:52 +03:00
nsCSSValue values[4];
1998-04-14 00:24:54 +04:00
PRInt32 count = 0;
1999-02-10 11:37:52 +03:00
PRInt32 index;
1998-10-27 02:22:40 +03:00
for (index = 0; index < 4; index++) {
1999-02-10 11:37:52 +03:00
if (! ParseSingleValueProperty(aErrorCode, values[index], aPropIDs[index])) {
1998-04-14 00:24:54 +04:00
break;
}
count++;
}
1999-02-10 11:37:52 +03:00
if ((count == 0) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if (1 < count) { // verify no more than single inherit
for (index = 0; index < 4; index++) {
if (eCSSUnit_Inherit == values[index].GetUnit()) {
return PR_FALSE;
}
}
}
1998-04-14 00:24:54 +04:00
// Provide missing values by replicating some of the values found
switch (count) {
case 1: // Make right == top
1999-02-10 11:37:52 +03:00
values[1] = values[0];
1998-04-14 00:24:54 +04:00
case 2: // Make bottom == top
1999-02-10 11:37:52 +03:00
values[2] = values[0];
1998-04-14 00:24:54 +04:00
case 3: // Make left == right
1999-02-10 11:37:52 +03:00
values[3] = values[1];
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
for (index = 0; index < 4; index++) {
aDeclaration->AppendValue(aPropIDs[index], values[index]);
}
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseProperty(PRInt32& aErrorCode,
1998-09-30 03:50:09 +04:00
nsICSSDeclaration* aDeclaration,
1998-10-27 02:22:40 +03:00
PRInt32 aPropID,
PRInt32& aChangeHint)
1998-04-14 00:24:54 +04:00
{
// Strip out properties we use internally. These properties are used
// by compound property parsing routines (e.g. "background-position").
1998-10-27 02:22:40 +03:00
switch (aPropID) {
case PROP_BACKGROUND_X_POSITION:
case PROP_BACKGROUND_Y_POSITION:
case PROP_BORDER_X_SPACING:
case PROP_BORDER_Y_SPACING:
case PROP_CLIP_BOTTOM:
case PROP_CLIP_LEFT:
case PROP_CLIP_RIGHT:
case PROP_CLIP_TOP:
// The user can't use these
return PR_FALSE;
default:
break;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
if (aChangeHint < nsCSSProps::kHintTable[aPropID]) {
aChangeHint = nsCSSProps::kHintTable[aPropID];
}
1998-09-30 03:50:09 +04:00
1998-10-27 02:22:40 +03:00
return ParseProperty(aErrorCode, aDeclaration, aPropID);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseProperty(PRInt32& aErrorCode,
1998-04-14 00:24:54 +04:00
nsICSSDeclaration* aDeclaration,
1998-10-27 02:22:40 +03:00
PRInt32 aPropID)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
switch (aPropID) { // handle shorthand or multiple properties
1998-04-14 00:24:54 +04:00
case PROP_BACKGROUND:
return ParseBackground(aErrorCode, aDeclaration);
case PROP_BACKGROUND_POSITION:
1998-10-27 02:22:40 +03:00
return ParseBackgroundPosition(aErrorCode, aDeclaration);
1998-04-14 00:24:54 +04:00
case PROP_BORDER:
return ParseBorder(aErrorCode, aDeclaration);
case PROP_BORDER_COLOR:
return ParseBorderColor(aErrorCode, aDeclaration);
1998-10-27 02:22:40 +03:00
case PROP_BORDER_SPACING:
return ParseBorderSpacing(aErrorCode, aDeclaration);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_STYLE:
return ParseBorderStyle(aErrorCode, aDeclaration);
case PROP_BORDER_BOTTOM:
1999-02-10 11:37:52 +03:00
return ParseBorderSide(aErrorCode, aDeclaration, kBorderBottomIDs);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_LEFT:
1999-02-10 11:37:52 +03:00
return ParseBorderSide(aErrorCode, aDeclaration, kBorderLeftIDs);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_RIGHT:
1999-02-10 11:37:52 +03:00
return ParseBorderSide(aErrorCode, aDeclaration, kBorderRightIDs);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_TOP:
1999-02-10 11:37:52 +03:00
return ParseBorderSide(aErrorCode, aDeclaration, kBorderTopIDs);
case PROP_BORDER_WIDTH:
return ParseBorderWidth(aErrorCode, aDeclaration);
case PROP_CLIP:
return ParseClip(aErrorCode, aDeclaration);
case PROP_CONTENT:
return ParseContent(aErrorCode, aDeclaration);
case PROP_COUNTER_INCREMENT:
case PROP_COUNTER_RESET:
return ParseCounterData(aErrorCode, aDeclaration, aPropID);
case PROP_CUE:
return ParseCue(aErrorCode, aDeclaration);
case PROP_CURSOR:
return ParseCursor(aErrorCode, aDeclaration);
case PROP_FONT:
return ParseFont(aErrorCode, aDeclaration);
case PROP_LIST_STYLE:
return ParseListStyle(aErrorCode, aDeclaration);
case PROP_MARGIN:
return ParseMargin(aErrorCode, aDeclaration);
case PROP_OUTLINE:
return ParseOutline(aErrorCode, aDeclaration);
case PROP_PADDING:
return ParsePadding(aErrorCode, aDeclaration);
case PROP_PAUSE:
return ParsePause(aErrorCode, aDeclaration);
case PROP_PLAY_DURING:
return ParsePlayDuring(aErrorCode, aDeclaration);
case PROP_QUOTES:
return ParseQuotes(aErrorCode, aDeclaration);
case PROP_SIZE:
return ParseSize(aErrorCode, aDeclaration);
case PROP_TEXT_SHADOW:
return ParseTextShadow(aErrorCode, aDeclaration);
default: // must be single property
{
nsCSSValue value;
if (ParseSingleValueProperty(aErrorCode, value, aPropID)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(aPropID, value);
return PR_TRUE;
}
}
}
}
return PR_FALSE;
}
// Bits used in determining which background position info we have
1999-03-28 08:29:57 +04:00
#define BG_CENTER 0x01
#define BG_TOP 0x02
#define BG_BOTTOM 0x04
#define BG_LEFT 0x08
#define BG_RIGHT 0x10
#define BG_CENTER1 0x20
#define BG_CENTER2 0x40
1999-02-10 11:37:52 +03:00
// Note: Don't change this table unless you update
// parseBackgroundPosition!
static const PRInt32 kBackgroundXYPositionKTable[] = {
KEYWORD_CENTER, BG_CENTER,
KEYWORD_TOP, BG_TOP,
KEYWORD_BOTTOM, BG_BOTTOM,
KEYWORD_LEFT, BG_LEFT,
KEYWORD_RIGHT, BG_RIGHT,
-1,
};
PRBool CSSParserImpl::ParseSingleValueProperty(PRInt32& aErrorCode,
nsCSSValue& aValue,
PRInt32 aPropID)
{
switch (aPropID) {
case PROP_BACKGROUND:
case PROP_BACKGROUND_POSITION:
case PROP_BORDER:
case PROP_BORDER_COLOR:
case PROP_BORDER_SPACING:
case PROP_BORDER_STYLE:
case PROP_BORDER_BOTTOM:
case PROP_BORDER_LEFT:
case PROP_BORDER_RIGHT:
case PROP_BORDER_TOP:
case PROP_BORDER_WIDTH:
case PROP_CLIP:
case PROP_CONTENT:
case PROP_COUNTER_INCREMENT:
case PROP_COUNTER_RESET:
case PROP_CUE:
case PROP_CURSOR:
case PROP_FONT:
case PROP_LIST_STYLE:
case PROP_MARGIN:
case PROP_OUTLINE:
case PROP_PADDING:
case PROP_PAUSE:
case PROP_QUOTES:
case PROP_SIZE:
case PROP_TEXT_SHADOW:
NS_ERROR("not a single value property");
return PR_FALSE;
case PROP_AZIMUTH:
return ParseAzimuth(aErrorCode, aValue);
case PROP_BACKGROUND_ATTACHMENT:
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kBackgroundAttachmentKTable);
case PROP_BACKGROUND_COLOR:
return ParseVariant(aErrorCode, aValue, VARIANT_HCK,
nsCSSProps::kBackgroundColorKTable);
case PROP_BACKGROUND_FILTER: // XXX
return ParseBackgroundFilter(aErrorCode, aValue);
case PROP_BACKGROUND_IMAGE:
return ParseVariant(aErrorCode, aValue, VARIANT_HUO, nsnull);
case PROP_BACKGROUND_REPEAT:
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kBackgroundRepeatKTable);
case PROP_BACKGROUND_X_POSITION:
case PROP_BACKGROUND_Y_POSITION:
return ParseVariant(aErrorCode, aValue, VARIANT_HKLP,
kBackgroundXYPositionKTable);
case PROP_BORDER_COLLAPSE:
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kBorderCollapseKTable);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_BOTTOM_COLOR:
case PROP_BORDER_LEFT_COLOR:
case PROP_BORDER_RIGHT_COLOR:
case PROP_BORDER_TOP_COLOR:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HCK,
nsCSSProps::kBorderColorKTable);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_BOTTOM_STYLE:
case PROP_BORDER_LEFT_STYLE:
case PROP_BORDER_RIGHT_STYLE:
case PROP_BORDER_TOP_STYLE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kBorderStyleKTable);
1998-04-14 00:24:54 +04:00
case PROP_BORDER_BOTTOM_WIDTH:
case PROP_BORDER_LEFT_WIDTH:
case PROP_BORDER_RIGHT_WIDTH:
case PROP_BORDER_TOP_WIDTH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HKL,
nsCSSProps::kBorderWidthKTable);
1999-04-03 07:15:01 +04:00
case PROP__MOZ_BORDER_RADIUS:
return ParseVariant(aErrorCode, aValue, VARIANT_HLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_BOTTOM:
case PROP_TOP:
case PROP_LEFT:
case PROP_RIGHT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_HEIGHT:
case PROP_WIDTH:
1999-02-10 11:37:52 +03:00
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_AHLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_CAPTION_SIDE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kCaptionSideKTable);
1998-04-14 00:24:54 +04:00
case PROP_CLEAR:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kClearKTable);
1998-04-14 00:24:54 +04:00
case PROP_COLOR:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HC, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_CUE_AFTER:
case PROP_CUE_BEFORE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HUO, nsnull);
case PROP_DIRECTION:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kDirectionKTable);
1998-04-14 00:24:54 +04:00
case PROP_DISPLAY:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kDisplayKTable);
1998-10-27 02:22:40 +03:00
case PROP_ELEVATION:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK | VARIANT_ANGLE,
nsCSSProps::kElevationKTable);
1998-10-27 02:22:40 +03:00
case PROP_EMPTY_CELLS:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kEmptyCellsKTable);
1998-04-14 00:24:54 +04:00
case PROP_FILTER:
1999-02-10 11:37:52 +03:00
return ParseForegroundFilter(aErrorCode, aValue);
1998-04-14 00:24:54 +04:00
case PROP_FLOAT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kFloatKTable);
1998-04-14 00:24:54 +04:00
case PROP_FONT_FAMILY:
1999-02-10 11:37:52 +03:00
return ParseFamily(aErrorCode, aValue);
1998-04-14 00:24:54 +04:00
case PROP_FONT_SIZE:
1999-02-10 11:37:52 +03:00
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_HKLP,
nsCSSProps::kFontSizeKTable);
1998-10-27 02:22:40 +03:00
case PROP_FONT_SIZE_ADJUST:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HON,
nsnull);
1998-10-27 02:22:40 +03:00
case PROP_FONT_STRETCH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK,
nsCSSProps::kFontStretchKTable);
1998-04-14 00:24:54 +04:00
case PROP_FONT_STYLE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK,
nsCSSProps::kFontStyleKTable);
1998-04-14 00:24:54 +04:00
case PROP_FONT_VARIANT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK,
nsCSSProps::kFontVariantKTable);
1998-04-14 00:24:54 +04:00
case PROP_FONT_WEIGHT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMKI,
nsCSSProps::kFontWeightKTable);
1998-10-27 02:22:40 +03:00
case PROP_LETTER_SPACING:
case PROP_WORD_SPACING:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HL | VARIANT_NORMAL, nsnull);
1998-04-14 00:24:54 +04:00
case PROP_LINE_HEIGHT:
1999-02-10 11:37:52 +03:00
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_HLPN | VARIANT_NORMAL, nsnull);
1998-04-14 00:24:54 +04:00
case PROP_LIST_STYLE_IMAGE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HUO, nsnull);
1998-04-14 00:24:54 +04:00
case PROP_LIST_STYLE_POSITION:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK, nsCSSProps::kListStylePositionKTable);
1998-04-14 00:24:54 +04:00
case PROP_LIST_STYLE_TYPE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK, nsCSSProps::kListStyleKTable);
1998-04-14 00:24:54 +04:00
case PROP_MARGIN_BOTTOM:
case PROP_MARGIN_LEFT:
case PROP_MARGIN_RIGHT:
case PROP_MARGIN_TOP:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_MARKER_OFFSET:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHL, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_MARKS:
1999-02-10 11:37:52 +03:00
return ParseMarks(aErrorCode, aValue);
1998-10-27 02:22:40 +03:00
case PROP_MAX_HEIGHT:
case PROP_MAX_WIDTH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HLPO, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_MIN_HEIGHT:
case PROP_MIN_WIDTH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_OPACITY:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HPN, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_ORPHANS:
case PROP_WIDOWS:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HI, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_OUTLINE_COLOR:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HCK,
nsCSSProps::kOutlineColorKTable);
1998-10-27 02:22:40 +03:00
case PROP_OUTLINE_STYLE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kBorderStyleKTable);
1998-10-27 02:22:40 +03:00
case PROP_OUTLINE_WIDTH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HKL,
nsCSSProps::kBorderWidthKTable);
1998-10-27 02:22:40 +03:00
case PROP_OVERFLOW:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHK,
nsCSSProps::kOverflowKTable);
1998-04-14 00:24:54 +04:00
case PROP_PADDING_BOTTOM:
case PROP_PADDING_LEFT:
case PROP_PADDING_RIGHT:
case PROP_PADDING_TOP:
1999-02-10 11:37:52 +03:00
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_HLP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_PAGE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AUTO | VARIANT_IDENTIFIER, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_PAGE_BREAK_AFTER:
case PROP_PAGE_BREAK_BEFORE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHK,
nsCSSProps::kPageBreakKTable);
1998-10-27 02:22:40 +03:00
case PROP_PAGE_BREAK_INSIDE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHK,
nsCSSProps::kPageBreakInsideKTable);
1998-10-27 02:22:40 +03:00
case PROP_PAUSE_AFTER:
case PROP_PAUSE_BEFORE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HTP, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_PITCH:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HKF, nsCSSProps::kPitchKTable);
1998-10-27 02:22:40 +03:00
case PROP_PITCH_RANGE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HN, nsnull);
1998-04-14 00:24:54 +04:00
case PROP_POSITION:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK, nsCSSProps::kPositionKTable);
1998-10-27 02:22:40 +03:00
case PROP_RICHNESS:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HN, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_SPEAK:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK | VARIANT_NONE,
nsCSSProps::kSpeakKTable);
1998-10-27 02:22:40 +03:00
case PROP_SPEAK_HEADER:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kSpeakHeaderKTable);
1998-10-27 02:22:40 +03:00
case PROP_SPEAK_NUMERAL:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kSpeakNumeralKTable);
1998-10-27 02:22:40 +03:00
case PROP_SPEAK_PUNCTUATION:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kSpeakPunctuationKTable);
1998-10-27 02:22:40 +03:00
case PROP_SPEECH_RATE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HN | VARIANT_KEYWORD,
nsCSSProps::kSpeechRateKTable);
1998-10-27 02:22:40 +03:00
case PROP_STRESS:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HN, nsnull);
1998-10-27 02:22:40 +03:00
case PROP_TABLE_LAYOUT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHK,
nsCSSProps::kTableLayoutKTable);
1998-04-14 00:24:54 +04:00
case PROP_TEXT_ALIGN:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK | VARIANT_STRING,
nsCSSProps::kTextAlignKTable);
1998-04-14 00:24:54 +04:00
case PROP_TEXT_DECORATION:
1999-02-10 11:37:52 +03:00
return ParseTextDecoration(aErrorCode, aValue);
1998-04-14 00:24:54 +04:00
case PROP_TEXT_INDENT:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HLP, nsnull);
1998-04-14 00:24:54 +04:00
case PROP_TEXT_TRANSFORM:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
nsCSSProps::kTextTransformKTable);
1998-10-27 02:22:40 +03:00
case PROP_UNICODE_BIDI:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK,
nsCSSProps::kUnicodeBidiKTable);
1998-04-14 00:24:54 +04:00
case PROP_VERTICAL_ALIGN:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HKLP,
nsCSSProps::kVerticalAlignKTable);
1998-04-14 00:24:54 +04:00
case PROP_VISIBILITY:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
nsCSSProps::kVisibilityKTable);
1998-10-27 02:22:40 +03:00
case PROP_VOICE_FAMILY:
1999-02-10 11:37:52 +03:00
return ParseFamily(aErrorCode, aValue);
1998-10-27 02:22:40 +03:00
case PROP_VOLUME:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HPN | VARIANT_KEYWORD,
nsCSSProps::kVolumeKTable);
1998-04-14 00:24:54 +04:00
case PROP_WHITE_SPACE:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_HMK,
nsCSSProps::kWhitespaceKTable);
1998-04-14 00:24:54 +04:00
case PROP_Z_INDEX:
1999-02-10 11:37:52 +03:00
return ParseVariant(aErrorCode, aValue, VARIANT_AHI, nsnull);
1998-04-14 00:24:54 +04:00
}
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseAzimuth(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
if (ParseVariant(aErrorCode, aValue, VARIANT_HK | VARIANT_ANGLE,
nsCSSProps::kAzimuthKTable)) {
if (eCSSUnit_Enumerated == aValue.GetUnit()) {
PRInt32 intValue = aValue.GetIntValue();
1998-10-27 02:22:40 +03:00
if ((NS_STYLE_AZIMUTH_LEFT_SIDE <= intValue) &&
(intValue <= NS_STYLE_AZIMUTH_BEHIND)) { // look for optional modifier
nsCSSValue modifier;
if (ParseEnum(aErrorCode, modifier, nsCSSProps::kAzimuthKTable)) {
PRInt32 enumValue = modifier.GetIntValue();
if (((intValue == NS_STYLE_AZIMUTH_BEHIND) &&
(NS_STYLE_AZIMUTH_LEFT_SIDE <= enumValue) && (enumValue <= NS_STYLE_AZIMUTH_RIGHT_SIDE)) ||
((enumValue == NS_STYLE_AZIMUTH_BEHIND) &&
(NS_STYLE_AZIMUTH_LEFT_SIDE <= intValue) && (intValue <= NS_STYLE_AZIMUTH_RIGHT_SIDE))) {
1999-02-10 11:37:52 +03:00
aValue.SetIntValue(intValue | enumValue, eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
return PR_TRUE;
}
// Put the unknown identifier back and return
UngetToken();
return PR_FALSE;
}
}
}
return PR_TRUE;
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseBackground(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 6;
static const PRInt32 kBackgroundIDs[numProps] = {
1998-10-27 02:22:40 +03:00
PROP_BACKGROUND_COLOR,
PROP_BACKGROUND_IMAGE,
PROP_BACKGROUND_REPEAT,
PROP_BACKGROUND_ATTACHMENT,
1999-02-10 11:37:52 +03:00
PROP_BACKGROUND_X_POSITION,
PROP_BACKGROUND_Y_POSITION
1998-10-27 02:22:40 +03:00
// PROP_BACKGROUND_FILTER
1998-04-14 00:24:54 +04:00
};
1999-02-10 11:37:52 +03:00
nsCSSValue values[numProps];
PRInt32 found = ParseChoice(aErrorCode, values, kBackgroundIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if (0 != (found & 0x30)) { // found one or more position values, validate them
if (0 == (found & 0x20)) { // x value only
if (eCSSUnit_Enumerated == values[4].GetUnit()) {
switch (values[4].GetIntValue()) {
case BG_CENTER:
values[4].SetIntValue(50, eCSSUnit_Enumerated);
values[5].SetIntValue(50, eCSSUnit_Enumerated);
break;
case BG_TOP:
values[4].SetIntValue(50, eCSSUnit_Enumerated);
values[5].SetIntValue(0, eCSSUnit_Enumerated);
break;
case BG_BOTTOM:
values[4].SetIntValue(50, eCSSUnit_Enumerated);
values[5].SetIntValue(100, eCSSUnit_Enumerated);
break;
case BG_LEFT:
values[4].SetIntValue(0, eCSSUnit_Enumerated);
values[5].SetIntValue(50, eCSSUnit_Enumerated);
break;
case BG_RIGHT:
values[4].SetIntValue(100, eCSSUnit_Enumerated);
values[5].SetIntValue(50, eCSSUnit_Enumerated);
break;
}
}
else if (eCSSUnit_Inherit == values[4].GetUnit()) {
values[5].SetInheritValue();
}
else {
values[5].SetPercentValue(50.0f);
}
}
else { // both x & y values
nsCSSUnit xUnit = values[4].GetUnit();
nsCSSUnit yUnit = values[5].GetUnit();
if (eCSSUnit_Enumerated == xUnit) { // if one is enumerated, both must be
if (eCSSUnit_Enumerated == yUnit) {
PRInt32 xValue = values[4].GetIntValue();
PRInt32 yValue = values[5].GetIntValue();
if (0 != (xValue & (BG_LEFT | BG_CENTER | BG_RIGHT))) { // x is really an x value
if (0 != (yValue & (BG_LEFT | BG_RIGHT))) { // y is also an x value
return PR_FALSE;
}
}
else { // x is a y value
if (0 != (yValue & (BG_TOP | BG_BOTTOM))) { // y is also a y value
return PR_FALSE;
}
PRInt32 holdXValue = xValue;
xValue = yValue;
yValue = holdXValue;
}
switch (xValue) {
case BG_LEFT:
values[4].SetIntValue(0, eCSSUnit_Enumerated);
break;
case BG_CENTER:
values[4].SetIntValue(50, eCSSUnit_Enumerated);
break;
case BG_RIGHT:
values[4].SetIntValue(100, eCSSUnit_Enumerated);
break;
default:
NS_ERROR("bad x value");
}
switch (yValue) {
case BG_TOP:
values[5].SetIntValue(0, eCSSUnit_Enumerated);
break;
case BG_CENTER:
values[5].SetIntValue(50, eCSSUnit_Enumerated);
break;
case BG_BOTTOM:
values[5].SetIntValue(100, eCSSUnit_Enumerated);
break;
default:
NS_ERROR("bad y value");
}
}
else {
return PR_FALSE;
}
}
else {
if (eCSSUnit_Enumerated == yUnit) {
return PR_FALSE;
}
}
1998-10-27 02:22:40 +03:00
}
}
1998-04-14 00:24:54 +04:00
// Provide missing values
1999-02-10 11:37:52 +03:00
if ((found & 0x01) == 0) {
values[0].SetIntValue(NS_STYLE_BG_COLOR_TRANSPARENT, eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if ((found & 0x02) == 0) {
values[1].SetNoneValue();
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if ((found & 0x04) == 0) {
values[2].SetIntValue(NS_STYLE_BG_REPEAT_XY, eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if ((found & 0x08) == 0) {
values[3].SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL, eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if ((found & 0x30) == 0) {
values[4].SetPercentValue(0.0f);
values[5].SetPercentValue(0.0f);
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
// Note: no default for filter (yet)
PRInt32 index;
for (index = 0; index < numProps; index++) {
aDeclaration->AppendValue(kBackgroundIDs[index], values[index]);
}
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
// First try a number or a length value
1999-02-10 11:37:52 +03:00
nsCSSValue xValue;
if (ParseVariant(aErrorCode, xValue, VARIANT_HLP, nsnull)) {
if (eCSSUnit_Inherit == xValue.GetUnit()) { // both are inherited
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_BACKGROUND_X_POSITION, xValue);
aDeclaration->AppendValue(PROP_BACKGROUND_Y_POSITION, xValue);
return PR_TRUE;
}
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
1998-04-14 00:24:54 +04:00
// We have one number/length. Get the optional second number/length.
1999-02-10 11:37:52 +03:00
nsCSSValue yValue;
if (ParseVariant(aErrorCode, yValue, VARIANT_LP, nsnull)) {
1998-04-14 00:24:54 +04:00
// We have two numbers
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_BACKGROUND_X_POSITION, xValue);
aDeclaration->AppendValue(PROP_BACKGROUND_Y_POSITION, yValue);
return PR_TRUE;
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
// We have one number which is the x position. Create an value for
// the vertical position which is of value 50%
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_BACKGROUND_X_POSITION, xValue);
aDeclaration->AppendValue(PROP_BACKGROUND_Y_POSITION, nsCSSValue(0.5f, eCSSUnit_Percent));
return PR_TRUE;
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
// Now try keywords. We do this manually to allow for the first
// appearance of "center" to apply to the either the x or y
// position (it's ambiguous so we have to disambiguate). Each
// allowed keyword value is assigned it's own bit. We don't allow
// any duplicate keywords other than center. We try to get two
// keywords but it's okay if there is only one.
PRInt32 mask = 0;
PRInt32 centerBit = BG_CENTER1;
for (PRInt32 i = 0; i < 2; i++) {
1999-02-10 11:37:52 +03:00
if (PR_FALSE == ParseEnum(aErrorCode, xValue, kBackgroundXYPositionKTable)) {
1998-04-14 00:24:54 +04:00
break;
}
1999-02-10 11:37:52 +03:00
PRInt32 bit = xValue.GetIntValue();
if (BG_CENTER == bit) {
1999-02-10 11:37:52 +03:00
// Special hack for center bits: We can have two of them
mask |= centerBit;
centerBit <<= 1;
continue;
} else if ((mask & bit) != 0) {
// no duplicate values allowed (other than center)
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
mask |= bit;
1998-04-14 00:24:54 +04:00
}
// Check for bad input. Bad input consists of no matching keywords,
// or pairs of x keywords or pairs of y keywords.
if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) ||
(mask == (BG_LEFT | BG_RIGHT))) {
return PR_FALSE;
}
// Map good input
1999-02-10 11:37:52 +03:00
PRInt32 xEnumValue = 50;
1998-04-14 00:24:54 +04:00
if ((mask & (BG_LEFT | BG_RIGHT)) != 0) {
// We have an x value
1999-02-10 11:37:52 +03:00
xEnumValue = ((mask & BG_LEFT) != 0) ? 0 : 100;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
PRInt32 yEnumValue = 50;
1998-04-14 00:24:54 +04:00
if ((mask & (BG_TOP | BG_BOTTOM)) != 0) {
// We have a y value
1999-02-10 11:37:52 +03:00
yEnumValue = ((mask & BG_TOP) != 0) ? 0 : 100;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
// Create style values
aDeclaration->AppendValue(PROP_BACKGROUND_X_POSITION, nsCSSValue(xEnumValue, eCSSUnit_Enumerated));
aDeclaration->AppendValue(PROP_BACKGROUND_Y_POSITION, nsCSSValue(yEnumValue, eCSSUnit_Enumerated));
return PR_TRUE;
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseBackgroundFilter(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-04-14 00:24:54 +04:00
{
// XXX not yet supported
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseForegroundFilter(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-04-14 00:24:54 +04:00
{
// XXX not yet supported
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
// These must be in CSS order (top,right,bottom,left) for indexing to work
static const PRInt32 kBorderStyleIDs[] = {
PROP_BORDER_TOP_STYLE,
PROP_BORDER_RIGHT_STYLE,
PROP_BORDER_BOTTOM_STYLE,
PROP_BORDER_LEFT_STYLE
};
static const PRInt32 kBorderWidthIDs[] = {
PROP_BORDER_TOP_WIDTH,
PROP_BORDER_RIGHT_WIDTH,
PROP_BORDER_BOTTOM_WIDTH,
PROP_BORDER_LEFT_WIDTH
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
static const PRInt32 kBorderColorIDs[] = {
PROP_BORDER_TOP_COLOR,
PROP_BORDER_RIGHT_COLOR,
PROP_BORDER_BOTTOM_COLOR,
PROP_BORDER_LEFT_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBorder(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 3;
1998-10-27 02:22:40 +03:00
static const PRInt32 kBorderIDs[] = {
PROP_BORDER_TOP_WIDTH, // only one value per property
PROP_BORDER_TOP_STYLE,
PROP_BORDER_TOP_COLOR
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
1999-02-10 11:37:52 +03:00
nsCSSValue values[numProps];
1998-10-27 02:22:40 +03:00
1999-02-10 11:37:52 +03:00
PRInt32 found = ParseChoice(aErrorCode, values, kBorderIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if (0 == (found & 1)) { // provide missing border width's
values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
if (0 == (found & 2)) { // provide missing border style's
values[1].SetNoneValue();
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if (0 == (found & 4)) { // clear missing color values so color property will be used
values[2].Reset();
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
PRInt32 index;
for (index = 0; index < 4; index++) {
aDeclaration->AppendValue(kBorderWidthIDs[index], values[0]);
aDeclaration->AppendValue(kBorderStyleIDs[index], values[1]);
aDeclaration->AppendValue(kBorderColorIDs[index], values[2]);
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBorderColor(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
return ParseBoxProperties(aErrorCode, aDeclaration, kBorderColorIDs);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBorderSpacing(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
nsCSSValue xValue;
if (ParseVariant(aErrorCode, xValue, VARIANT_HL, nsnull)) {
if (xValue.IsLengthUnit()) {
// We have one length. Get the optional second length.
nsCSSValue yValue;
if (ParseVariant(aErrorCode, yValue, VARIANT_LENGTH, nsnull)) {
// We have two numbers
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_BORDER_X_SPACING, xValue);
aDeclaration->AppendValue(PROP_BORDER_Y_SPACING, yValue);
return PR_TRUE;
}
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
}
// We have one length which is the horizontal spacing. Create a value for
// the vertical spacing which is equal
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_BORDER_X_SPACING, xValue);
aDeclaration->AppendValue(PROP_BORDER_Y_SPACING, xValue);
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseBorderSide(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
1999-02-10 11:37:52 +03:00
const PRInt32 aPropIDs[])
1998-10-27 02:22:40 +03:00
{
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 3;
nsCSSValue values[numProps];
PRInt32 found = ParseChoice(aErrorCode, values, aPropIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if ((found & 1) == 0) { // Provide default border-width
values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
if ((found & 2) == 0) { // Provide default border-style
values[1].SetNoneValue();
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if ((found & 4) == 0) { // reset border-color so color property gets used
values[2].Reset();
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
PRInt32 index;
for (index = 0; index < numProps; index++) {
aDeclaration->AppendValue(aPropIDs[index], values[index]);
1998-04-14 00:24:54 +04:00
}
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBorderStyle(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
return ParseBoxProperties(aErrorCode, aDeclaration, kBorderStyleIDs);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseBorderWidth(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
return ParseBoxProperties(aErrorCode, aDeclaration, kBorderWidthIDs);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseClip(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
static const PRInt32 kClipIDs[] = {
PROP_CLIP_TOP,
PROP_CLIP_RIGHT,
PROP_CLIP_BOTTOM,
PROP_CLIP_LEFT
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
if (! GetToken(aErrorCode, PR_TRUE)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
PRInt32 index;
1998-10-27 02:22:40 +03:00
if ((eCSSToken_Ident == mToken.mType) &&
mToken.mIdent.EqualsIgnoreCase("auto")) {
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
nsCSSValue valueAuto(eCSSUnit_Auto);
for (index = 0; index < 4; index++) {
aDeclaration->AppendValue(kClipIDs[index], valueAuto);
}
return PR_TRUE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
} else if ((eCSSToken_Ident == mToken.mType) &&
mToken.mIdent.EqualsIgnoreCase("inherit")) {
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
nsCSSValue inherit(eCSSUnit_Inherit);
for (index = 0; index < 4; index++) {
aDeclaration->AppendValue(kClipIDs[index], inherit);
}
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
} else if ((eCSSToken_Function == mToken.mType) &&
mToken.mIdent.EqualsIgnoreCase("rect")) {
1998-04-14 00:24:54 +04:00
if (!ExpectSymbol(aErrorCode, '(', PR_TRUE)) {
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
nsCSSValue values[4];
1998-10-27 02:22:40 +03:00
for (index = 0; index < 4; index++) {
if (! ParseVariant(aErrorCode, values[index], VARIANT_AL, nsnull)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
if (3 != index) {
// skip optional commas between elements
ExpectSymbol(aErrorCode, ',', PR_TRUE);
}
1998-04-14 00:24:54 +04:00
}
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
for (index = 0; index < 4; index++) {
aDeclaration->AppendValue(kClipIDs[index], values[index]);
}
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
} else {
UngetToken();
}
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
#define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
VARIANT_KEYWORD)
PRBool CSSParserImpl::ParseContent(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
nsCSSValue value;
if (ParseVariant(aErrorCode, value, VARIANT_CONTENT | VARIANT_INHERIT,
nsCSSProps::kContentKTable)) {
if (eCSSUnit_Inherit == value.GetUnit()) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_CONTENT, value);
return PR_TRUE;
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
nsCSSValueList* listHead = new nsCSSValueList();
nsCSSValueList* list = listHead;
if (nsnull == list) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
list->mValue = value;
while (nsnull != list) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aErrorCode = aDeclaration->AppendStructValue(PROP_CONTENT, listHead);
return NS_SUCCEEDED(aErrorCode);
}
if (ParseVariant(aErrorCode, value, VARIANT_CONTENT, nsCSSProps::kContentKTable)) {
list->mNext = new nsCSSValueList();
list = list->mNext;
if (nsnull != list) {
list->mValue = value;
}
else {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
}
}
else {
break;
}
}
delete listHead;
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseCounterData(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration,
PRInt32 aPropID)
{
nsString* ident = NextIdent(aErrorCode);
if (nsnull == ident) {
return PR_FALSE;
}
if (ident->EqualsIgnoreCase("none")) {
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(aPropID, nsCSSValue(eCSSUnit_None));
return PR_TRUE;
}
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
else if (ident->EqualsIgnoreCase("inherit")) {
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(aPropID, nsCSSValue(eCSSUnit_Inherit));
return PR_TRUE;
}
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
else {
1999-02-10 11:37:52 +03:00
nsCSSCounterData* dataHead = new nsCSSCounterData();
nsCSSCounterData* data = dataHead;
if (nsnull == data) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
data->mCounter.SetStringValue(*ident, eCSSUnit_String);
while (nsnull != data) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aErrorCode = aDeclaration->AppendStructValue(aPropID, dataHead);
return NS_SUCCEEDED(aErrorCode);
}
if (! GetToken(aErrorCode, PR_TRUE)) {
break;
}
if ((eCSSToken_Number == mToken.mType) && (mToken.mIntegerValid)) {
data->mValue.SetIntValue(mToken.mInteger, eCSSUnit_Integer);
1998-10-27 02:22:40 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
1999-02-10 11:37:52 +03:00
aErrorCode = aDeclaration->AppendStructValue(aPropID, dataHead);
return NS_SUCCEEDED(aErrorCode);
1998-10-27 02:22:40 +03:00
}
if (! GetToken(aErrorCode, PR_TRUE)) {
break;
}
1999-02-10 11:37:52 +03:00
}
if (eCSSToken_Ident == mToken.mType) {
data->mNext = new nsCSSCounterData();
data = data->mNext;
if (nsnull != data) {
data->mCounter.SetStringValue(mToken.mIdent, eCSSUnit_String);
1998-10-27 02:22:40 +03:00
}
else {
1999-02-10 11:37:52 +03:00
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
1998-10-27 02:22:40 +03:00
}
}
1999-02-10 11:37:52 +03:00
else {
break;
}
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
delete dataHead;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
PRBool CSSParserImpl::ParseCue(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
nsCSSValue before;
if (ParseSingleValueProperty(aErrorCode, before, PROP_CUE_BEFORE)) {
if (eCSSUnit_URL == before.GetUnit()) {
nsCSSValue after;
if (ParseSingleValueProperty(aErrorCode, after, PROP_CUE_AFTER)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_CUE_BEFORE, before);
aDeclaration->AppendValue(PROP_CUE_AFTER, after);
return PR_TRUE;
}
return PR_FALSE;
}
}
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_CUE_BEFORE, before);
aDeclaration->AppendValue(PROP_CUE_AFTER, before);
return PR_TRUE;
1998-10-27 02:22:40 +03:00
}
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseCursor(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
nsCSSValue value;
if (ParseVariant(aErrorCode, value, VARIANT_AHUK, nsCSSProps::kCursorKTable)) {
if (eCSSUnit_URL == value.GetUnit()) {
nsCSSValueList* listHead = new nsCSSValueList();
nsCSSValueList* list = listHead;
if (nsnull == list) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
list->mValue = value;
while (nsnull != list) {
if (eCSSUnit_URL != value.GetUnit()) {
if (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE)) {
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
}
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aErrorCode = aDeclaration->AppendStructValue(PROP_CURSOR, listHead);
return NS_SUCCEEDED(aErrorCode);
}
if (ParseVariant(aErrorCode, value, VARIANT_AHUK, nsCSSProps::kCursorKTable)) {
list->mNext = new nsCSSValueList();
list = list->mNext;
if (nsnull != list) {
list->mValue = value;
1998-10-27 02:22:40 +03:00
}
else {
1999-02-10 11:37:52 +03:00
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
1998-10-27 02:22:40 +03:00
}
}
1999-02-10 11:37:52 +03:00
else {
break;
}
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
delete listHead;
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_CURSOR, value);
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
PRBool CSSParserImpl::ParseFont(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
static const PRInt32 fontIDs[] = {
PROP_FONT_STYLE,
PROP_FONT_VARIANT,
PROP_FONT_WEIGHT
1998-04-14 00:24:54 +04:00
};
1999-02-10 11:37:52 +03:00
nsCSSValue family;
if (ParseVariant(aErrorCode, family, VARIANT_HK, nsCSSProps::kFontKTable)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
if (eCSSUnit_Inherit == family.GetUnit()) {
aDeclaration->AppendValue(PROP_FONT_FAMILY, family);
aDeclaration->AppendValue(PROP_FONT_STYLE, family);
aDeclaration->AppendValue(PROP_FONT_VARIANT, family);
aDeclaration->AppendValue(PROP_FONT_WEIGHT, family);
aDeclaration->AppendValue(PROP_FONT_SIZE, family);
aDeclaration->AppendValue(PROP_LINE_HEIGHT, family);
aDeclaration->AppendValue(PROP_FONT_STRETCH, family);
aDeclaration->AppendValue(PROP_FONT_SIZE_ADJUST, family);
}
else {
1999-02-27 10:15:59 +03:00
aDeclaration->AppendValue(PROP_FONT_FAMILY, family); // keyword value overrides everything else
nsCSSValue empty;
aDeclaration->AppendValue(PROP_FONT_STYLE, empty);
aDeclaration->AppendValue(PROP_FONT_VARIANT, empty);
aDeclaration->AppendValue(PROP_FONT_WEIGHT, empty);
aDeclaration->AppendValue(PROP_FONT_SIZE, empty);
aDeclaration->AppendValue(PROP_LINE_HEIGHT, empty);
aDeclaration->AppendValue(PROP_FONT_STRETCH, empty);
aDeclaration->AppendValue(PROP_FONT_SIZE_ADJUST, empty);
1999-02-10 11:37:52 +03:00
}
return PR_TRUE;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
1998-04-14 00:24:54 +04:00
// Get optional font-style, font-variant and font-weight (in any order)
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 3;
nsCSSValue values[numProps];
PRInt32 found = ParseChoice(aErrorCode, values, fontIDs, numProps);
if ((found < 0) || (eCSSUnit_Inherit == values[0].GetUnit())) { // illegal data
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
if ((found & 1) == 0) {
// Provide default font-style
1999-02-10 11:37:52 +03:00
values[0].SetNormalValue();
1998-04-14 00:24:54 +04:00
}
if ((found & 2) == 0) {
// Provide default font-variant
1999-02-10 11:37:52 +03:00
values[1].SetNormalValue();
1998-04-14 00:24:54 +04:00
}
if ((found & 4) == 0) {
// Provide default font-weight
1999-02-10 11:37:52 +03:00
values[2].SetNormalValue();
1998-04-14 00:24:54 +04:00
}
// Get mandatory font-size
1999-02-10 11:37:52 +03:00
nsCSSValue size;
if (! ParseVariant(aErrorCode, size, VARIANT_KEYWORD | VARIANT_LP, nsCSSProps::kFontSizeKTable)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
// Get optional "/" line-height
1999-02-10 11:37:52 +03:00
nsCSSValue lineHeight;
1998-04-14 00:24:54 +04:00
if (ExpectSymbol(aErrorCode, '/', PR_TRUE)) {
1999-02-10 11:37:52 +03:00
if (! ParseVariant(aErrorCode, lineHeight, VARIANT_NUMBER | VARIANT_LP | VARIANT_NORMAL, nsnull)) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
}
1998-10-27 02:22:40 +03:00
else {
1999-02-10 11:37:52 +03:00
lineHeight.SetNormalValue();
1998-10-27 02:22:40 +03:00
}
1998-04-14 00:24:54 +04:00
// Get final mandatory font-family
1999-02-10 11:37:52 +03:00
if (ParseFamily(aErrorCode, family)) {
if ((eCSSUnit_Inherit != family.GetUnit()) && ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_FONT_FAMILY, family);
aDeclaration->AppendValue(PROP_FONT_STYLE, values[0]);
aDeclaration->AppendValue(PROP_FONT_VARIANT, values[1]);
aDeclaration->AppendValue(PROP_FONT_WEIGHT, values[2]);
aDeclaration->AppendValue(PROP_FONT_SIZE, size);
aDeclaration->AppendValue(PROP_LINE_HEIGHT, lineHeight);
aDeclaration->AppendValue(PROP_FONT_STRETCH, nsCSSValue(eCSSUnit_Normal));
aDeclaration->AppendValue(PROP_FONT_SIZE_ADJUST, nsCSSValue(eCSSUnit_None));
return PR_TRUE;
}
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseFamily(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-04-14 00:24:54 +04:00
{
nsCSSToken* tk = &mToken;
nsAutoString family;
PRBool firstOne = PR_TRUE;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Ident == tk->mType) {
1998-10-27 02:22:40 +03:00
if (firstOne) {
if (tk->mIdent.EqualsIgnoreCase("inherit")) {
1999-02-10 11:37:52 +03:00
aValue.SetInheritValue();
1998-10-27 02:22:40 +03:00
return PR_TRUE;
}
}
else {
1998-04-14 00:24:54 +04:00
family.Append(PRUnichar(','));
}
family.Append(tk->mIdent);
for (;;) {
if (!GetToken(aErrorCode, PR_FALSE)) {
break;
}
if (eCSSToken_Ident == tk->mType) {
family.Append(tk->mIdent);
} else if (eCSSToken_WhiteSpace == tk->mType) {
// Lookahead one token and drop whitespace if we ending the
// font name.
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Ident != tk->mType) {
UngetToken();
break;
}
UngetToken();
family.Append(PRUnichar(' '));
} else {
UngetToken();
break;
}
}
firstOne = PR_FALSE;
} else if (eCSSToken_String == tk->mType) {
if (!firstOne) {
family.Append(PRUnichar(','));
}
family.Append(tk->mSymbol); // replace the quotes
1998-04-14 00:24:54 +04:00
family.Append(tk->mIdent);
family.Append(tk->mSymbol);
1998-04-14 00:24:54 +04:00
firstOne = PR_FALSE;
} else if (eCSSToken_Symbol == tk->mType) {
if (',' != tk->mSymbol) {
UngetToken();
break;
}
} else {
UngetToken();
break;
}
}
if (family.Length() == 0) {
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
aValue.SetStringValue(family, eCSSUnit_String);
1998-04-14 00:24:54 +04:00
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseListStyle(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 3;
1998-10-27 02:22:40 +03:00
static const PRInt32 listStyleIDs[] = {
PROP_LIST_STYLE_TYPE,
PROP_LIST_STYLE_POSITION,
PROP_LIST_STYLE_IMAGE
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
1999-02-10 11:37:52 +03:00
nsCSSValue values[numProps];
PRInt32 index;
PRInt32 found = ParseChoice(aErrorCode, values, listStyleIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
1998-04-14 00:24:54 +04:00
return PR_FALSE;
}
1998-10-27 02:22:40 +03:00
// Provide default values
if ((found & 1) == 0) {
1999-02-10 11:37:52 +03:00
values[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
}
if ((found & 2) == 0) {
1999-02-10 11:37:52 +03:00
values[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
}
if ((found & 4) == 0) {
1999-02-10 11:37:52 +03:00
values[2].SetNoneValue();
}
for (index = 0; index < numProps; index++) {
aDeclaration->AppendValue(listStyleIDs[index], values[index]);
1998-04-14 00:24:54 +04:00
}
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseMargin(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
static const PRInt32 kMarginSideIDs[] = {
PROP_MARGIN_TOP,
PROP_MARGIN_RIGHT,
PROP_MARGIN_BOTTOM,
PROP_MARGIN_LEFT
};
return ParseBoxProperties(aErrorCode, aDeclaration, kMarginSideIDs);
}
1998-04-14 00:24:54 +04:00
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseMarks(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-10-27 02:22:40 +03:00
{
1999-02-10 11:37:52 +03:00
if (ParseVariant(aErrorCode, aValue, VARIANT_HOK, nsCSSProps::kPageMarksKTable)) {
if (eCSSUnit_Enumerated == aValue.GetUnit()) {
if (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE)) {
nsCSSValue second;
if (ParseEnum(aErrorCode, second, nsCSSProps::kPageMarksKTable)) {
aValue.SetIntValue(aValue.GetIntValue() | second.GetIntValue(), eCSSUnit_Enumerated);
return PR_TRUE;
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
}
1998-10-27 02:22:40 +03:00
return PR_TRUE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
PRBool CSSParserImpl::ParseOutline(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
const PRInt32 numProps = 3;
1998-10-27 02:22:40 +03:00
static const PRInt32 kOutlineIDs[] = {
PROP_OUTLINE_COLOR,
PROP_OUTLINE_STYLE,
PROP_OUTLINE_WIDTH
};
1998-04-14 00:24:54 +04:00
1999-02-10 11:37:52 +03:00
nsCSSValue values[numProps];
PRInt32 found = ParseChoice(aErrorCode, values, kOutlineIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty(aErrorCode, PR_TRUE))) {
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
1998-04-14 00:24:54 +04:00
// Provide default values
if ((found & 1) == 0) {
1999-02-10 11:37:52 +03:00
values[0].SetIntValue(NS_STYLE_COLOR_INVERT, eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
}
if ((found & 2) == 0) {
1999-02-10 11:37:52 +03:00
values[1].SetNoneValue();
1998-04-14 00:24:54 +04:00
}
if ((found & 4) == 0) {
1999-02-10 11:37:52 +03:00
values[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
}
PRInt32 index;
for (index = 0; index < numProps; index++) {
aDeclaration->AppendValue(kOutlineIDs[index], values[index]);
1998-04-14 00:24:54 +04:00
}
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParsePadding(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1998-10-27 02:22:40 +03:00
static const PRInt32 kPaddingSideIDs[] = {
PROP_PADDING_TOP,
PROP_PADDING_RIGHT,
PROP_PADDING_BOTTOM,
PROP_PADDING_LEFT
1998-04-14 00:24:54 +04:00
};
1998-10-27 02:22:40 +03:00
return ParseBoxProperties(aErrorCode, aDeclaration, kPaddingSideIDs);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParsePause(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
nsCSSValue before;
if (ParseSingleValueProperty(aErrorCode, before, PROP_PAUSE_BEFORE)) {
if (eCSSUnit_Inherit != before.GetUnit()) {
nsCSSValue after;
if (ParseSingleValueProperty(aErrorCode, after, PROP_PAUSE_AFTER)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_PAUSE_BEFORE, before);
aDeclaration->AppendValue(PROP_PAUSE_AFTER, after);
return PR_TRUE;
}
return PR_FALSE;
}
}
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_PAUSE_BEFORE, before);
aDeclaration->AppendValue(PROP_PAUSE_AFTER, before);
return PR_TRUE;
1998-10-27 02:22:40 +03:00
}
}
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParsePlayDuring(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration)
1998-04-14 00:24:54 +04:00
{
1999-02-10 11:37:52 +03:00
nsCSSValue playDuring;
nsCSSValue flags;
if (ParseVariant(aErrorCode, playDuring, VARIANT_AHUO, nsnull)) {
if (eCSSUnit_URL == playDuring.GetUnit()) {
if (ParseEnum(aErrorCode, flags, nsCSSProps::kPlayDuringKTable)) {
PRInt32 intValue = flags.GetIntValue();
if (ParseEnum(aErrorCode, flags, nsCSSProps::kPlayDuringKTable)) {
flags.SetIntValue(intValue | flags.GetIntValue(), eCSSUnit_Enumerated);
1998-10-27 02:22:40 +03:00
}
}
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_PLAY_DURING, playDuring);
aDeclaration->AppendValue(PROP_PLAY_DURING_FLAGS, flags);
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseQuotes(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
nsCSSValue open;
if (ParseVariant(aErrorCode, open, VARIANT_HOS, nsnull)) {
if (eCSSUnit_String == open.GetUnit()) {
nsCSSQuotes* quotesHead = new nsCSSQuotes();
nsCSSQuotes* quotes = quotesHead;
if (nsnull == quotes) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
quotes->mOpen = open;
while (nsnull != quotes) {
// get mandatory close
if (ParseVariant(aErrorCode, quotes->mClose, VARIANT_STRING, nsnull)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aErrorCode = aDeclaration->AppendStructValue(PROP_QUOTES, quotesHead);
return NS_SUCCEEDED(aErrorCode);
}
// look for another open
if (ParseVariant(aErrorCode, open, VARIANT_STRING, nsnull)) {
quotes->mNext = new nsCSSQuotes();
quotes = quotes->mNext;
if (nsnull != quotes) {
quotes->mOpen = open;
continue;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
1998-10-27 02:22:40 +03:00
}
}
1999-02-10 11:37:52 +03:00
break;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
delete quotesHead;
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_QUOTES_OPEN, open);
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
1998-04-14 00:24:54 +04:00
1998-10-27 02:22:40 +03:00
PRBool CSSParserImpl::ParseSize(PRInt32& aErrorCode, nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
nsCSSValue width;
if (ParseVariant(aErrorCode, width, VARIANT_AHKL, nsCSSProps::kPageSizeKTable)) {
if (width.IsLengthUnit()) {
nsCSSValue height;
if (ParseVariant(aErrorCode, height, VARIANT_LENGTH, nsnull)) {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_SIZE_WIDTH, width);
aDeclaration->AppendValue(PROP_SIZE_HEIGHT, height);
return PR_TRUE;
}
return PR_FALSE;
1998-10-27 02:22:40 +03:00
}
1998-04-14 00:24:54 +04:00
}
1999-02-10 11:37:52 +03:00
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_SIZE_WIDTH, width);
aDeclaration->AppendValue(PROP_SIZE_HEIGHT, width);
return PR_TRUE;
}
1998-10-27 02:22:40 +03:00
}
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
PRBool CSSParserImpl::ParseTextDecoration(PRInt32& aErrorCode, nsCSSValue& aValue)
1998-10-27 02:22:40 +03:00
{
1999-02-10 11:37:52 +03:00
if (ParseVariant(aErrorCode, aValue, VARIANT_HOK, nsCSSProps::kTextDecorationKTable)) {
if (eCSSUnit_Enumerated == aValue.GetUnit()) { // look for more keywords
PRInt32 intValue = aValue.GetIntValue();
nsCSSValue keyword;
PRInt32 index;
1998-10-27 02:22:40 +03:00
for (index = 0; index < 3; index++) {
1999-02-10 11:37:52 +03:00
if (ParseEnum(aErrorCode, keyword, nsCSSProps::kTextDecorationKTable)) {
intValue |= keyword.GetIntValue();
1998-10-27 02:22:40 +03:00
}
else {
break;
}
}
1999-02-10 11:37:52 +03:00
aValue.SetIntValue(intValue, eCSSUnit_Enumerated);
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_TRUE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
PRBool CSSParserImpl::ParseTextShadow(PRInt32& aErrorCode,
nsICSSDeclaration* aDeclaration)
{
1999-02-10 11:37:52 +03:00
nsCSSValue value;
if (ParseVariant(aErrorCode, value, VARIANT_HC | VARIANT_LENGTH | VARIANT_NONE, nsnull)) {
nsCSSUnit unit = value.GetUnit();
if ((eCSSUnit_Color == unit) || (eCSSUnit_String == unit) || value.IsLengthUnit()) {
nsCSSShadow* shadowHead = new nsCSSShadow();
nsCSSShadow* shadow = shadowHead;
if (nsnull == shadow) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
while (nsnull != shadow) {
PRBool haveColor = PR_FALSE;
if (value.IsLengthUnit()) {
shadow->mXOffset = value;
}
else {
haveColor = PR_TRUE;
shadow->mColor = value;
if (ParseVariant(aErrorCode, value, VARIANT_LENGTH, nsnull)) {
shadow->mXOffset = value;
1998-10-27 02:22:40 +03:00
}
else {
break;
}
1999-02-10 11:37:52 +03:00
}
if (ParseVariant(aErrorCode, value, VARIANT_LENGTH, nsnull)) {
shadow->mYOffset = value;
}
else {
break;
}
if (ParseVariant(aErrorCode, value, VARIANT_LENGTH, nsnull)) {
shadow->mRadius = value;
} // optional
if (PR_FALSE == haveColor) {
if (ParseVariant(aErrorCode, value, VARIANT_COLOR, nsnull)) {
shadow->mColor = value;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
}
if (ExpectSymbol(aErrorCode, ',', PR_TRUE)) {
shadow->mNext = new nsCSSShadow();
shadow = shadow->mNext;
if (nsnull == shadow) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
break;
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
if (PR_FALSE == ParseVariant(aErrorCode, value, VARIANT_COLOR | VARIANT_LENGTH, nsnull)) {
1998-10-27 02:22:40 +03:00
break;
}
}
1999-02-10 11:37:52 +03:00
else {
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aErrorCode = aDeclaration->AppendStructValue(PROP_TEXT_SHADOW, shadowHead);
return NS_SUCCEEDED(aErrorCode);
}
break;
}
1998-10-27 02:22:40 +03:00
}
1999-02-10 11:37:52 +03:00
delete shadowHead;
1998-10-27 02:22:40 +03:00
return PR_FALSE;
}
1999-02-10 11:37:52 +03:00
// value is inherit or none
if (ExpectEndProperty(aErrorCode, PR_TRUE)) {
aDeclaration->AppendValue(PROP_TEXT_SHADOW_X, value);
return PR_TRUE;
}
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00
return PR_FALSE;
1998-04-14 00:24:54 +04:00
}
1998-10-27 02:22:40 +03:00