Consolidate and deCOMtaminate parsing and storage of media lists. b=156716 r+sr=bzbarsky

This commit is contained in:
dbaron@dbaron.org
2005-03-30 00:36:57 +00:00
parent 33d8293e9d
commit b1497c8162
24 changed files with 442 additions and 634 deletions

View File

@@ -74,6 +74,7 @@
#include "nsContentErrors.h"
#include "nsUnitConversion.h"
#include "nsPrintfCString.h"
#include "nsIMediaList.h"
#include "prprf.h"
#include "math.h"
@@ -133,13 +134,27 @@ public:
nsCSSDeclaration* aDeclaration,
PRBool* aChanged);
NS_IMETHOD ParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsMediaList* aMediaList,
PRBool aHTMLMode);
void AppendRule(nsICSSRule* aRule);
protected:
nsresult InitScanner(nsIUnicharInputStream* aInput, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI);
// the caller must hold on to aBuffer until parsing is done
nsresult InitScanner(const nsAString& aBuffer, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI);
nsresult ReleaseScanner(void);
nsresult DoParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsMediaList* aMediaList);
PRBool GetToken(nsresult& aErrorCode, PRBool aSkipWS);
PRBool GetURLToken(nsresult& aErrorCode, PRBool aSkipWS);
void UngetToken();
@@ -160,10 +175,11 @@ protected:
PRBool ParseCharsetRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseImportRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool GatherURL(nsresult& aErrorCode, nsString& aURL);
PRBool GatherMedia(nsresult& aErrorCode, nsISupportsArray* aMediaAtoms);
PRBool GatherMedia(nsresult& aErrorCode, nsMediaList* aMedia,
PRUnichar aStopSymbol);
PRBool ProcessImport(nsresult& aErrorCode,
const nsString& aURLSpec,
nsISupportsArray* aMedia,
nsMediaList* aMedia,
RuleAppendFunc aAppendFunc,
void* aProcessData);
PRBool ParseGroupRule(nsresult& aErrorCode, nsICSSGroupRule* aRule, RuleAppendFunc aAppendFunc, void* aProcessData);
@@ -374,6 +390,10 @@ protected:
PRPackedBool mSVGMode;
#endif
// True for parsing media lists for HTML attributes, where we have to
// ignore CSS comments.
PRPackedBool mHTMLMediaMode;
// True if tagnames and attributes are case-sensitive
PRPackedBool mCaseSensitive;
@@ -471,6 +491,7 @@ CSSParserImpl::CSSParserImpl()
#ifdef MOZ_SVG
mSVGMode(PR_FALSE),
#endif
mHTMLMediaMode(PR_FALSE),
mCaseSensitive(PR_FALSE),
mParsingCompoundProperty(PR_FALSE)
#ifdef DEBUG
@@ -552,6 +573,22 @@ CSSParserImpl::InitScanner(nsIUnicharInputStream* aInput, nsIURI* aSheetURI,
return NS_OK;
}
nsresult
CSSParserImpl::InitScanner(const nsAString& aBuffer, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI)
{
// Having it not own the string is OK since the caller will hold on to
// the stream until we're done parsing.
nsCOMPtr<nsIUnicharInputStream> input;
nsresult rv = NS_NewStringUnicharInputStream(getter_AddRefs(input),
&aBuffer, PR_FALSE);
if (NS_FAILED(rv)) {
return rv;
}
return InitScanner(input, aSheetURI, aLineNumber, aBaseURI);
}
nsresult
CSSParserImpl::ReleaseScanner(void)
{
@@ -660,16 +697,8 @@ CSSParserImpl::ParseStyleAttribute(const nsAString& aAttributeValue,
{
NS_ASSERTION(nsnull != aBaseURL, "need base URL");
nsCOMPtr<nsIUnicharInputStream> input;
// Style attribute parsing can't make the stream outlive this
// function call, so having it not own the string is OK.
nsresult rv = NS_NewStringUnicharInputStream(getter_AddRefs(input),
&aAttributeValue, PR_FALSE);
if (NS_FAILED(rv)) {
return rv;
}
rv = InitScanner(input, aDocURL, 0, aBaseURL); // XXX line number
nsresult rv =
InitScanner(aAttributeValue, aDocURL, 0, aBaseURL); // XXX line number
if (! NS_SUCCEEDED(rv)) {
return rv;
}
@@ -723,16 +752,7 @@ CSSParserImpl::ParseAndAppendDeclaration(const nsAString& aBuffer,
// NS_ASSERTION(nsnull != aBaseURL, "need base URL");
*aChanged = PR_FALSE;
nsCOMPtr<nsIUnicharInputStream> input;
// Parsing a single declaration block can't make the stream outlive this
// function call, so having it not own the string is OK.
nsresult rv = NS_NewStringUnicharInputStream(getter_AddRefs(input),
&aBuffer, PR_FALSE);
if (NS_FAILED(rv)) {
return rv;
}
rv = InitScanner(input, aSheetURL, 0, aBaseURL);
nsresult rv = InitScanner(aBuffer, aSheetURL, 0, aBaseURL);
if (! NS_SUCCEEDED(rv)) {
return rv;
}
@@ -779,16 +799,7 @@ CSSParserImpl::ParseRule(const nsAString& aRule,
NS_ASSERTION(nsnull != aBaseURL, "need base URL");
NS_ENSURE_ARG_POINTER(aResult);
nsCOMPtr<nsIUnicharInputStream> input;
// Parsing a single rule can't make the stream outlive this
// function call, so having it not own the string is OK.
nsresult rv = NS_NewStringUnicharInputStream(getter_AddRefs(input),
&aRule, PR_FALSE);
if (NS_FAILED(rv)) {
return rv;
}
rv = InitScanner(input, aSheetURL, 0, aBaseURL);
nsresult rv = InitScanner(aRule, aSheetURL, 0, aBaseURL);
if (NS_FAILED(rv)) {
return rv;
}
@@ -835,16 +846,7 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
NS_ASSERTION(nsnull != aDeclaration, "Need declaration to parse into!");
*aChanged = PR_FALSE;
nsCOMPtr<nsIUnicharInputStream> input;
// Parsing a single property value can't make the stream outlive this
// function call, so having it not own the string is OK.
nsresult rv = NS_NewStringUnicharInputStream(getter_AddRefs(input),
&aPropValue, PR_FALSE);
if (NS_FAILED(rv)) {
return rv;
}
rv = InitScanner(input, aSheetURL, 0, aBaseURL);
nsresult rv = InitScanner(aPropValue, aSheetURL, 0, aBaseURL);
if (NS_FAILED(rv)) {
return rv;
}
@@ -889,6 +891,79 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
ReleaseScanner();
return result;
}
NS_IMETHODIMP
CSSParserImpl::ParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsMediaList* aMediaList,
PRBool aHTMLMode)
{
aMediaList->Clear();
nsresult rv;
if (aHTMLMode) {
mHTMLMediaMode = PR_TRUE;
// XXXldb We need to make the scanner not skip CSS comments! (Or
// should we?)
// Follow the parsing rules in
// http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
for (PRUint32 sub = 0, sub_end; sub < aBuffer.Length(); sub = sub_end + 1) {
sub_end = aBuffer.FindChar(PRUnichar(','), sub);
if (sub_end == -1)
sub_end = aBuffer.Length();
PRUint32 parse_start, parse_end;
for (parse_start = sub;
parse_start < sub_end && nsCRT::IsAsciiSpace(aBuffer[parse_start]);
++parse_start)
;
for (parse_end = parse_start;
parse_end < sub_end &&
(nsCRT::IsAsciiAlpha(aBuffer[parse_end]) ||
nsCRT::IsAsciiDigit(aBuffer[parse_end]) ||
aBuffer[parse_end] == PRUnichar('-'));
++parse_end)
;
DoParseMediaList(Substring(aBuffer, parse_start, parse_end - parse_start),
aURL, aLineNumber, aMediaList);
}
mHTMLMediaMode = PR_FALSE;
} else {
rv = DoParseMediaList(aBuffer, aURL, aLineNumber, aMediaList);
}
return rv;
}
// All parameters but the first are the same as for |ParseMediaList|,
// but for HTML we get the buffer in chunks according to the HTML spec's
// parsing rules instead of in one piece.
nsresult
CSSParserImpl::DoParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsMediaList* aMediaList)
{
// fake base URL since media lists don't have URLs in them
nsresult rv = InitScanner(aBuffer, aURL, aLineNumber, aURL);
if (NS_FAILED(rv)) {
return rv;
}
if (!GatherMedia(rv, aMediaList, PRUnichar(0)) && !mHTMLMediaMode) {
OUTPUT_ERROR();
}
CLEAR_ERROR();
ReleaseScanner();
}
//----------------------------------------------------------------------
PRBool CSSParserImpl::GetToken(nsresult& aErrorCode, PRBool aSkipWS)
@@ -1110,79 +1185,67 @@ PRBool CSSParserImpl::GatherURL(nsresult& aErrorCode, nsString& aURL)
}
PRBool CSSParserImpl::GatherMedia(nsresult& aErrorCode,
nsISupportsArray* aMediaAtoms)
nsMediaList* aMedia,
PRUnichar aStopSymbol)
{
PRBool expectIdent = PR_TRUE;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);
break;
}
if (eCSSToken_Symbol == mToken.mType) {
PRUnichar symbol = mToken.mSymbol;
if ((';' == symbol) || ('{' == symbol)) {
UngetToken();
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent);
UngetToken();
break;
}
ToLowerCase(mToken.mIdent); // case insensitive from CSS - must be lower cased
nsCOMPtr<nsIAtom> medium = do_GetAtom(mToken.mIdent);
aMedia->AppendAtom(medium);
if (!GetToken(aErrorCode, PR_TRUE)) {
if (aStopSymbol == PRUnichar(0))
return PR_TRUE;
} else if (',' != symbol) {
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);
UngetToken();
break;
} else if (expectIdent) {
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent);
UngetToken();
break;
}
else {
expectIdent = PR_TRUE;
}
REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);
break;
}
else if (eCSSToken_Ident == mToken.mType) {
if (expectIdent) {
ToLowerCase(mToken.mIdent); // case insensitive from CSS - must be lower cased
nsCOMPtr<nsIAtom> medium = do_GetAtom(mToken.mIdent);
aMediaAtoms->AppendElement(medium);
expectIdent = PR_FALSE;
}
else {
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);
UngetToken();
break;
}
}
else {
if (expectIdent)
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent);
else
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);
if (eCSSToken_Symbol == mToken.mType &&
mToken.mSymbol == aStopSymbol) {
UngetToken();
return PR_TRUE;
} else if (eCSSToken_Symbol != mToken.mType ||
mToken.mSymbol != ',') {
REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);
UngetToken();
break;
}
}
aMediaAtoms->Clear();
return PR_FALSE;
}
// Parse a CSS2 import rule: "@import STRING | URL [medium [, mdeium]]"
// Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
PRBool CSSParserImpl::ParseImportRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aData)
{
nsAutoString url;
nsCOMPtr<nsISupportsArray> media;
aErrorCode = NS_NewISupportsArray(getter_AddRefs(media));
nsCOMPtr<nsMediaList> media = new nsMediaList();
if (!media) {
// Out of memory
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
nsAutoString url;
if (!GatherURL(aErrorCode, url)) {
REPORT_UNEXPECTED_TOKEN(PEImportNotURI);
return PR_FALSE;
}
if (!GatherMedia(aErrorCode, media) ||
!ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PEImportUnexpected);
// don't advance section, simply ignore invalid @import
return PR_FALSE;
if (!ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
if (!GatherMedia(aErrorCode, media, ';') ||
!ExpectSymbol(aErrorCode, ';', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PEImportUnexpected);
// don't advance section, simply ignore invalid @import
return PR_FALSE;
}
NS_ASSERTION(media->Count() != 0, "media list must be nonempty");
}
ProcessImport(aErrorCode, url, media, aAppendFunc, aData);
@@ -1192,7 +1255,7 @@ PRBool CSSParserImpl::ParseImportRule(nsresult& aErrorCode, RuleAppendFunc aAppe
PRBool CSSParserImpl::ProcessImport(nsresult& aErrorCode,
const nsString& aURLSpec,
nsISupportsArray* aMedia,
nsMediaList* aMedia,
RuleAppendFunc aAppendFunc,
void* aData)
{
@@ -1271,22 +1334,21 @@ PRBool CSSParserImpl::ParseMediaRule(nsresult& aErrorCode,
RuleAppendFunc aAppendFunc,
void* aData)
{
nsCOMPtr<nsISupportsArray> media;
aErrorCode = NS_NewISupportsArray(getter_AddRefs(media));
if (media) {
if (GatherMedia(aErrorCode, media)) {
// XXXbz this could use better error reporting throughout the method
PRUint32 count;
media->Count(&count);
if (count > 0) {
nsRefPtr<nsCSSMediaRule> rule(new nsCSSMediaRule());
// Append first, so when we do SetMedia() the rule
// knows what its stylesheet is.
if (rule && ParseGroupRule(aErrorCode, rule, aAppendFunc, aData)) {
rule->SetMedia(media);
return PR_TRUE;
}
}
nsCOMPtr<nsMediaList> media = new nsMediaList();
if (!media) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
if (GatherMedia(aErrorCode, media, '{')) {
NS_ASSERTION(media->Count() != 0, "media list must be nonempty");
// XXXbz this could use better error reporting throughout the method
nsRefPtr<nsCSSMediaRule> rule(new nsCSSMediaRule());
// Append first, so when we do SetMedia() the rule
// knows what its stylesheet is.
if (rule && ParseGroupRule(aErrorCode, rule, aAppendFunc, aData)) {
rule->SetMedia(media);
return PR_TRUE;
}
}