Bug 441469. Implement parsing of @font-face rules. r+sr=dbaron

This commit is contained in:
Zack Weinberg 2008-08-07 19:15:40 -04:00
Родитель a32dce381d
Коммит af751d9b0a
14 изменённых файлов: 1263 добавлений и 140 удалений

Просмотреть файл

@ -42,8 +42,8 @@ PEParseRuleWSOnly=Whitespace-only string given to be parsed as rule.
PEDeclDropped=Declaration dropped.
PEDeclSkipped=Skipped to next declaration.
PEUnknownProperty=Unknown property '%1$S'.
PEPropertyParsingError=Error in parsing value for property '%1$S'.
PEExpectEndProperty=Expected end of value for property but found '%1$S'.
PEValueParsingError=Error in parsing value for '%1$S'.
PEExpectEndValue=Expected end of value but found '%1$S'.
PESkipAtRuleEOF=end of unknown at-rule
PEUnknownAtRule=Unrecognized at-rule or error parsing at-rule '%1$S'.
PECharsetRuleEOF=charset string in @charset rule
@ -127,6 +127,8 @@ PEBadDeclOrRuleEnd2=Expected ';' or '}' to terminate declaration but found '%1$S
PEInaccessibleProperty2=Cannot specify value for internal property.
PECommentEOF=end of comment
SEUnterminatedString=Found unclosed string '%1$S'.
PEFontDescExpected=Expected font descriptor but found '%1$S'.
PEUnknownFontDesc=Unknown descriptor '%1$S' in @font-face rule.
PEMQExpectedExpressionStart=Expected '(' to start media query expression but found '%1$S'.
PEMQExpressionEOF=contents of media query expression
PEMQExpectedFeatureName=Expected media feature name but found '%1$S'.

Просмотреть файл

@ -428,6 +428,10 @@ enum nsDOMClassInfoID {
eDOMClassInfo_Geolocation_id,
eDOMClassInfo_Geolocator_id,
// @font-face in CSS
eDOMClassInfo_CSSFontFaceRule_id,
eDOMClassInfo_CSSFontFaceStyleDecl_id,
// WhatWG Video Element
#if defined(MOZ_MEDIA)
eDOMClassInfo_HTMLVideoElement_id,

Просмотреть файл

@ -325,6 +325,7 @@
#include "nsIDOMCSSCharsetRule.h"
#include "nsIDOMCSSImportRule.h"
#include "nsIDOMCSSMediaRule.h"
#include "nsIDOMCSSFontFaceRule.h"
#include "nsIDOMCSSMozDocumentRule.h"
#include "nsIDOMCSSPrimitiveValue.h"
#include "nsIDOMCSSStyleRule.h"
@ -814,7 +815,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CSSStyleDeclaration, nsCSSStyleDeclSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ComputedCSSStyleDeclaration, nsCSSStyleDeclSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ROCSSPrimitiveValue, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1253,6 +1254,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(Geolocator, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceStyleDecl, nsCSSStyleDeclSH,
ARRAY_SCRIPTABLE_FLAGS)
#if defined(MOZ_MEDIA)
NS_DEFINE_CLASSINFO_DATA(HTMLVideoElement, nsHTMLElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
@ -3440,6 +3446,15 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMGeolocator)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSFontFaceStyleDecl,
nsIDOMCSSStyleDeclaration)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleDeclaration)
DOM_CLASSINFO_MAP_END
#if defined(MOZ_MEDIA)
DOM_CLASSINFO_MAP_BEGIN(HTMLVideoElement, nsIDOMHTMLVideoElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLVideoElement)

Просмотреть файл

@ -150,6 +150,11 @@ public:
void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// return whether there was a value in |aValue| (i.e., it had a non-null unit)
static PRBool AppendCSSValueToString(nsCSSProperty aProperty,
const nsCSSValue& aValue,
nsAString& aResult);
private:
// Not implemented, and not supported.
nsCSSDeclaration& operator=(const nsCSSDeclaration& aCopy);
@ -158,13 +163,6 @@ private:
static void AppendImportanceToString(PRBool aIsImportant, nsAString& aString);
// return whether there was a value in |aValue| (i.e., it had a non-null unit)
PRBool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const;
public:
// return whether there was a value in |aValue| (i.e., it had a non-null unit)
static PRBool AppendCSSValueToString(nsCSSProperty aProperty,
const nsCSSValue& aValue,
nsAString& aResult);
private:
// May be called only for properties whose type is eCSSType_Value.
nsresult GetValueOrImportantValue(nsCSSProperty aProperty, nsCSSValue& aValue) const;

Просмотреть файл

@ -294,7 +294,12 @@ protected:
PRBool ProcessNameSpace(nsresult& aErrorCode, const nsString& aPrefix,
const nsString& aURLSpec, RuleAppendFunc aAppendFunc,
void* aProcessData);
PRBool ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseFontDescriptor(nsresult& aErrorCode, nsCSSFontFaceRule* aRule);
PRBool ParseFontDescriptorValue(nsresult& aErrorCode, nsCSSFontDesc aDescID,
nsCSSValue& aValue);
PRBool ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
enum nsSelectorParsingStatus {
@ -416,7 +421,11 @@ protected:
PRBool ParseCursor(nsresult& aErrorCode);
PRBool ParseFont(nsresult& aErrorCode);
PRBool ParseFontWeight(nsresult& aErrorCode, nsCSSValue& aValue);
PRBool ParseOneFamily(nsresult& aErrorCode, nsAString& aValue);
PRBool ParseFamily(nsresult& aErrorCode, nsCSSValue& aValue);
PRBool ParseFontSrc(nsresult& aErrorCode, nsCSSValue& aValue);
PRBool ParseFontSrcFormat(nsresult& aErrorCode, nsTArray<nsCSSValue>& values);
PRBool ParseFontRanges(nsresult& aErrorCode, nsCSSValue& aValue);
PRBool ParseListStyle(nsresult& aErrorCode);
PRBool ParseMargin(nsresult& aErrorCode);
PRBool ParseMarks(nsresult& aErrorCode, nsCSSValue& aValue);
@ -1076,13 +1085,13 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
} else {
if (parsedOK) {
// Junk at end of property value.
REPORT_UNEXPECTED_TOKEN(PEExpectEndProperty);
REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
}
NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
const PRUnichar *params[] = {
propName.get()
};
REPORT_UNEXPECTED_P(PEPropertyParsingError, params);
REPORT_UNEXPECTED_P(PEValueParsingError, params);
REPORT_UNEXPECTED(PEDeclDropped);
OUTPUT_ERROR();
ClearTempData(aPropID);
@ -1306,7 +1315,7 @@ PRBool CSSParserImpl::ExpectEndProperty(nsresult& aErrorCode)
UngetToken();
return PR_TRUE;
}
REPORT_UNEXPECTED_TOKEN(PEExpectEndProperty);
REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
UngetToken();
return PR_FALSE;
}
@ -1990,12 +1999,109 @@ PRBool CSSParserImpl::ProcessNameSpace(nsresult& aErrorCode, const nsString& aPr
return result;
}
PRBool CSSParserImpl::ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aData)
// font-face-rule: '@font-face' '{' font-description '}'
// font-description: font-descriptor+
PRBool
CSSParserImpl::ParseFontFaceRule(nsresult& aErrorCode,
RuleAppendFunc aAppendFunc, void* aData)
{
// XXX not yet implemented
return PR_FALSE;
if (!ExpectSymbol(aErrorCode, '{', PR_TRUE))
return PR_FALSE;
nsRefPtr<nsCSSFontFaceRule> rule(new nsCSSFontFaceRule());
if (!rule) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
REPORT_UNEXPECTED_EOF(PEFontFaceEOF);
break;
}
if (mToken.IsSymbol('}')) { // done!
UngetToken();
break;
}
// ignore extra semicolons
if (mToken.IsSymbol(';'))
continue;
if (!ParseFontDescriptor(aErrorCode, rule)) {
REPORT_UNEXPECTED(PEDeclSkipped);
OUTPUT_ERROR();
if (!SkipDeclaration(aErrorCode, PR_TRUE))
break;
}
}
if (!ExpectSymbol(aErrorCode, '}', PR_TRUE))
return PR_FALSE;
(*aAppendFunc)(rule, aData);
return PR_TRUE;
}
// font-descriptor: font-family-desc
// | font-style-desc
// | font-weight-desc
// | font-stretch-desc
// | font-src-desc
// | unicode-range-desc
//
// All font-*-desc productions follow the pattern
// IDENT ':' value ';'
//
// On entry to this function, mToken is the IDENT.
PRBool
CSSParserImpl::ParseFontDescriptor(nsresult& aErrorCode,
nsCSSFontFaceRule* aRule)
{
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PEFontDescExpected);
return PR_FALSE;
}
nsString descName = mToken.mIdent;
if (!ExpectSymbol(aErrorCode, ':', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
OUTPUT_ERROR();
return PR_FALSE;
}
nsCSSFontDesc descID = nsCSSProps::LookupFontDesc(descName);
nsCSSValue value;
if (descID == eCSSFontDesc_UNKNOWN) {
if (NonMozillaVendorIdentifier(descName)) {
// silently skip other vendors' extensions
SkipDeclaration(aErrorCode, PR_TRUE);
return PR_TRUE;
} else {
const PRUnichar *params[] = {
descName.get()
};
REPORT_UNEXPECTED_P(PEUnknownFontDesc, params);
return PR_FALSE;
}
}
if (!ParseFontDescriptorValue(aErrorCode, descID, value)) {
const PRUnichar *params[] = {
descName.get()
};
REPORT_UNEXPECTED_P(PEValueParsingError, params);
return PR_FALSE;
}
if (!ExpectEndProperty(aErrorCode))
return PR_FALSE;
aRule->SetDesc(descID, value);
return PR_TRUE;
}
PRBool CSSParserImpl::ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aData)
{
// XXX not yet implemented
@ -3747,7 +3853,7 @@ CSSParserImpl::ParseDeclaration(nsresult& aErrorCode,
const PRUnichar *params[] = {
propertyName.get()
};
REPORT_UNEXPECTED_P(PEPropertyParsingError, params);
REPORT_UNEXPECTED_P(PEValueParsingError, params);
REPORT_UNEXPECTED(PEDeclDropped);
OUTPUT_ERROR();
ClearTempData(propID);
@ -4444,46 +4550,48 @@ PRBool CSSParserImpl::ParseAttr(nsresult& aErrorCode, nsCSSValue& aValue)
return PR_FALSE;
}
PRBool CSSParserImpl::ParseURL(nsresult& aErrorCode, nsCSSValue& aValue)
PRBool
CSSParserImpl::ParseURL(nsresult& aErrorCode, nsCSSValue& aValue)
{
if (!mSheetPrincipal) {
NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
"origin principal");
return PR_FALSE;
}
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (! GetURLToken(aErrorCode)) {
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.
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), tk->mIdent, nsnull, mBaseURL);
if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
// Set a null value on failure. Most failure cases should be
// NS_ERROR_MALFORMED_URI.
nsStringBuffer* buffer = nsCSSValue::BufferFromString(tk->mIdent);
if (NS_UNLIKELY(!buffer)) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
nsCSSValue::URL *url =
new nsCSSValue::URL(uri, buffer, mSheetURL, mSheetPrincipal);
buffer->Release();
if (NS_UNLIKELY(!url)) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
aValue.SetURLValue(url);
return PR_TRUE;
}
}
if (!ExpectSymbol(aErrorCode, '(', PR_FALSE))
return PR_FALSE;
if (!GetURLToken(aErrorCode))
return PR_FALSE;
nsCSSToken* tk = &mToken;
if (eCSSToken_String != tk->mType && eCSSToken_URL != tk->mType)
return PR_FALSE;
nsString url = tk->mIdent;
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE))
return PR_FALSE;
// Translate url into an absolute url if the url is relative to the
// style sheet.
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), url, nsnull, mBaseURL);
nsStringBuffer* buffer = nsCSSValue::BufferFromString(url);
if (NS_UNLIKELY(!buffer)) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
return PR_FALSE;
nsCSSValue::URL *urlVal =
new nsCSSValue::URL(uri, buffer, mSheetURL, mSheetPrincipal);
buffer->Release();
if (NS_UNLIKELY(!urlVal)) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return PR_FALSE;
}
aValue.SetURLValue(urlVal);
return PR_TRUE;
}
PRInt32 CSSParserImpl::ParseChoice(nsresult& aErrorCode, nsCSSValue aValues[],
@ -5385,6 +5493,95 @@ PRBool CSSParserImpl::ParseSingleValueProperty(nsresult& aErrorCode,
return PR_FALSE;
}
// nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
struct NS_STACK_CLASS ExtractFirstFamilyData {
nsAutoString mFamilyName;
PRBool mGood;
ExtractFirstFamilyData() : mFamilyName(), mGood(PR_FALSE) {}
};
static PRBool
ExtractFirstFamily(const nsString& aFamily,
PRBool aGeneric,
void* aData)
{
ExtractFirstFamilyData* realData = (ExtractFirstFamilyData*) aData;
if (aGeneric || realData->mFamilyName.Length() > 0) {
realData->mGood = PR_FALSE;
return PR_FALSE;
}
realData->mFamilyName.Assign(aFamily);
realData->mGood = PR_TRUE;
return PR_TRUE;
}
// font-descriptor: descriptor ':' value ';'
// caller has advanced mToken to point at the descriptor
PRBool
CSSParserImpl::ParseFontDescriptorValue(nsresult& aErrorCode,
nsCSSFontDesc aDescID,
nsCSSValue& aValue)
{
switch (aDescID) {
// These four are similar to the properties of the same name,
// possibly with more restrictions on the values they can take.
case eCSSFontDesc_Family: {
if (!ParseFamily(aErrorCode, aValue) ||
aValue.GetUnit() != eCSSUnit_String)
return PR_FALSE;
// the style parameters to the nsFont constructor are ignored,
// because it's only being used to call EnumerateFamilies
nsAutoString valueStr;
aValue.GetStringValue(valueStr);
nsFont font(valueStr, 0, 0, 0, 0, 0);
ExtractFirstFamilyData dat;
font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
if (!dat.mGood)
return PR_FALSE;
aValue.SetStringValue(dat.mFamilyName, eCSSUnit_String);
return PR_TRUE;
}
case eCSSFontDesc_Style:
// property is VARIANT_HMK|VARIANT_SYSFONT
return ParseVariant(aErrorCode, aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
nsCSSProps::kFontStyleKTable);
case eCSSFontDesc_Weight:
return (ParseFontWeight(aErrorCode, aValue) &&
aValue.GetUnit() != eCSSUnit_Inherit &&
aValue.GetUnit() != eCSSUnit_Initial &&
(aValue.GetUnit() != eCSSUnit_Enumerated ||
(aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER &&
aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER)));
case eCSSFontDesc_Stretch:
// property is VARIANT_HMK|VARIANT_SYSFONT
return (ParseVariant(aErrorCode, aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
nsCSSProps::kFontStretchKTable) &&
(aValue.GetUnit() != eCSSUnit_Enumerated ||
(aValue.GetIntValue() != NS_STYLE_FONT_STRETCH_WIDER &&
aValue.GetIntValue() != NS_STYLE_FONT_STRETCH_NARROWER)));
// These two are unique to @font-face and have their own special grammar.
case eCSSFontDesc_Src:
return ParseFontSrc(aErrorCode, aValue);
case eCSSFontDesc_UnicodeRange:
return ParseFontRanges(aErrorCode, aValue);
case eCSSFontDesc_UNKNOWN:
case eCSSFontDesc_COUNT:
NS_NOTREACHED("bad nsCSSFontDesc code");
}
// explicitly do NOT have a default case to let the compiler
// help find missing descriptors
return PR_FALSE;
}
void
CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties)
{
@ -6424,78 +6621,86 @@ PRBool CSSParserImpl::ParseFontWeight(nsresult& aErrorCode, nsCSSValue& aValue)
return PR_FALSE;
}
PRBool CSSParserImpl::ParseFamily(nsresult& aErrorCode, nsCSSValue& aValue)
PRBool CSSParserImpl::ParseOneFamily(nsresult& aErrorCode, nsAString& aFamily)
{
if (!GetToken(aErrorCode, PR_TRUE))
return PR_FALSE;
nsCSSToken* tk = &mToken;
nsAutoString family;
PRBool firstOne = PR_TRUE;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE)) {
break;
}
if (eCSSToken_Ident == tk->mType) {
if (firstOne) {
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent);
if (keyword == eCSSKeyword_inherit) {
aValue.SetInheritValue();
return PR_TRUE;
}
if (keyword == eCSSKeyword__moz_initial) {
aValue.SetInitialValue();
return PR_TRUE;
}
if (keyword == eCSSKeyword__moz_use_system_font &&
!IsParsingCompoundProperty()) {
aValue.SetSystemFontValue();
return PR_TRUE;
}
}
else {
family.Append(PRUnichar(','));
}
family.Append(tk->mIdent);
for (;;) {
if (!GetToken(aErrorCode, PR_FALSE)) {
if (eCSSToken_Ident == tk->mType) {
aFamily.Append(tk->mIdent);
for (;;) {
if (!GetToken(aErrorCode, PR_FALSE))
break;
if (eCSSToken_Ident == tk->mType) {
aFamily.Append(tk->mIdent);
} else if (eCSSToken_WhiteSpace == tk->mType) {
// Lookahead one token and drop whitespace if we are ending the
// font name.
if (!GetToken(aErrorCode, PR_TRUE))
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();
UngetToken();
if (eCSSToken_Ident == tk->mType)
aFamily.Append(PRUnichar(' '));
else
break;
}
}
firstOne = PR_FALSE;
} else if (eCSSToken_String == tk->mType) {
if (!firstOne) {
family.Append(PRUnichar(','));
}
family.Append(tk->mSymbol); // replace the quotes
family.Append(tk->mIdent); // XXX What if it had escaped quotes?
family.Append(tk->mSymbol);
firstOne = PR_FALSE;
} else if (eCSSToken_Symbol == tk->mType) {
if (',' != tk->mSymbol) {
} else {
UngetToken();
break;
}
} else {
UngetToken();
break;
}
return PR_TRUE;
} else if (eCSSToken_String == tk->mType) {
aFamily.Append(tk->mSymbol); // replace the quotes
aFamily.Append(tk->mIdent); // XXX What if it had escaped quotes?
aFamily.Append(tk->mSymbol);
return PR_TRUE;
} else {
UngetToken();
return PR_FALSE;
}
}
PRBool CSSParserImpl::ParseFamily(nsresult& aErrorCode, nsCSSValue& aValue)
{
if (!GetToken(aErrorCode, PR_TRUE))
return PR_FALSE;
if (eCSSToken_Ident == mToken.mType) {
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
if (keyword == eCSSKeyword_inherit) {
aValue.SetInheritValue();
return PR_TRUE;
}
if (keyword == eCSSKeyword__moz_initial) {
aValue.SetInitialValue();
return PR_TRUE;
}
if (keyword == eCSSKeyword__moz_use_system_font &&
!IsParsingCompoundProperty()) {
aValue.SetSystemFontValue();
return PR_TRUE;
}
}
UngetToken();
nsAutoString family;
for (;;) {
if (!ParseOneFamily(aErrorCode, family))
return PR_FALSE;
if (!ExpectSymbol(aErrorCode, ',', PR_TRUE))
break;
family.Append(PRUnichar(','));
}
if (family.IsEmpty()) {
return PR_FALSE;
}
@ -6503,6 +6708,111 @@ PRBool CSSParserImpl::ParseFamily(nsresult& aErrorCode, nsCSSValue& aValue)
return PR_TRUE;
}
// src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
// uri-src: uri [ 'format(' string ( ',' string )* ')' ]
// local-src: 'local(' ( string | ident ) ')'
PRBool
CSSParserImpl::ParseFontSrc(nsresult& aErrorCode, nsCSSValue& aValue)
{
// could we maybe turn nsCSSValue::Array into nsTArray<nsCSSValue>?
nsTArray<nsCSSValue> values;
nsCSSValue cur;
for (;;) {
if (!GetToken(aErrorCode, PR_TRUE))
break;
if (mToken.mType == eCSSToken_Function &&
mToken.mIdent.LowerCaseEqualsLiteral("url")) {
if (!ParseURL(aErrorCode, cur))
return PR_FALSE;
values.AppendElement(cur);
if (!ParseFontSrcFormat(aErrorCode, values))
return PR_FALSE;
} else if (mToken.mType == eCSSToken_Function &&
mToken.mIdent.LowerCaseEqualsLiteral("local")) {
// css3-fonts does not specify a formal grammar for local().
// The text permits both unquoted identifiers and quoted
// strings. We resolve this ambiguity in the spec by
// assuming that the appropriate production is a single
// <family-name>, possibly surrounded by whitespace.
nsAutoString family;
if (!ExpectSymbol(aErrorCode, '(', PR_FALSE))
return PR_FALSE;
if (!ParseOneFamily(aErrorCode, family))
return PR_FALSE;
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE))
return PR_FALSE;
// the style parameters to the nsFont constructor are ignored,
// because it's only being used to call EnumerateFamilies
nsFont font(family, 0, 0, 0, 0, 0);
ExtractFirstFamilyData dat;
font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
if (!dat.mGood)
return PR_FALSE;
cur.SetStringValue(dat.mFamilyName, eCSSUnit_Local_Font);
values.AppendElement(cur);
} else {
return PR_FALSE;
}
if (!ExpectSymbol(aErrorCode, ',', PR_TRUE))
break;
}
nsRefPtr<nsCSSValue::Array> srcVals
= nsCSSValue::Array::Create(values.Length());
if (!srcVals)
return PR_FALSE;
PRUint32 i;
for (i = 0; i < values.Length(); i++)
srcVals->Item(i) = values[i];
aValue.SetArrayValue(srcVals, eCSSUnit_Array);
return PR_TRUE;
}
PRBool
CSSParserImpl::ParseFontSrcFormat(nsresult& aErrorCode,
nsTArray<nsCSSValue> & values)
{
if (!GetToken(aErrorCode, PR_TRUE))
return PR_TRUE; // EOF harmless here
if (mToken.mType != eCSSToken_Function ||
!mToken.mIdent.LowerCaseEqualsLiteral("format")) {
UngetToken();
return PR_TRUE;
}
if (!ExpectSymbol(aErrorCode, '(', PR_FALSE))
return PR_FALSE;
do {
if (!GetToken(aErrorCode, PR_TRUE))
return PR_FALSE;
if (mToken.mType != eCSSToken_String)
return PR_FALSE;
nsCSSValue cur(mToken.mIdent, eCSSUnit_Font_Format);
values.AppendElement(cur);
} while (ExpectSymbol(aErrorCode, ',', PR_TRUE));
return ExpectSymbol(aErrorCode, ')', PR_TRUE);
}
// font-ranges: urange ( ',' urange )*
PRBool
CSSParserImpl::ParseFontRanges(nsresult& aErrorCode, nsCSSValue& aValue)
{
// not currently implemented (bug 443976)
return PR_FALSE;
}
PRBool CSSParserImpl::ParseListStyle(nsresult& aErrorCode)
{
const PRInt32 numProps = 3;

Просмотреть файл

@ -75,4 +75,19 @@ enum nsCSSType {
eCSSType_ValuePairList
};
// The "descriptors" that can appear in a @font-face rule.
// They have the syntax of properties but different value rules.
// Keep in sync with kCSSRawFontDescs in nsCSSProps.cpp and
// nsCSSFontFaceStyleDecl::Fields in nsCSSRules.cpp.
enum nsCSSFontDesc {
eCSSFontDesc_UNKNOWN = -1,
eCSSFontDesc_Family,
eCSSFontDesc_Style,
eCSSFontDesc_Weight,
eCSSFontDesc_Stretch,
eCSSFontDesc_Src,
eCSSFontDesc_UnicodeRange,
eCSSFontDesc_COUNT
};
#endif /* nsCSSProperty_h___ */

Просмотреть файл

@ -68,12 +68,25 @@ const char* const kCSSRawProperties[] = {
static PRInt32 gTableRefCount;
static nsStaticCaseInsensitiveNameTable* gPropertyTable;
static nsStaticCaseInsensitiveNameTable* gFontDescTable;
// Keep in sync with enum nsCSSFontDesc in nsCSSProperty.h.
static const char* const kCSSRawFontDescs[] = {
"font-family",
"font-style",
"font-weight",
"font-stretch",
"src",
"unicode-range"
};
void
nsCSSProps::AddRefTable(void)
{
if (0 == gTableRefCount++) {
NS_ASSERTION(!gPropertyTable, "pre existing array!");
NS_ASSERTION(!gFontDescTable, "pre existing array!");
gPropertyTable = new nsStaticCaseInsensitiveNameTable();
if (gPropertyTable) {
#ifdef DEBUG
@ -83,12 +96,29 @@ nsCSSProps::AddRefTable(void)
nsCAutoString temp1(kCSSRawProperties[index]);
nsCAutoString temp2(kCSSRawProperties[index]);
ToLowerCase(temp1);
NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
NS_ASSERTION(-1 == temp1.FindChar('_'), "underscore char in table");
NS_ASSERTION(temp1.Equals(temp2), "upper case char in prop table");
NS_ASSERTION(-1 == temp1.FindChar('_'), "underscore char in prop table");
}
}
#endif
gPropertyTable->Init(kCSSRawProperties, eCSSProperty_COUNT);
gPropertyTable->Init(kCSSRawProperties, eCSSProperty_COUNT);
}
gFontDescTable = new nsStaticCaseInsensitiveNameTable();
if (gFontDescTable) {
#ifdef DEBUG
{
// let's verify the table...
for (PRInt32 index = 0; index < eCSSFontDesc_COUNT; ++index) {
nsCAutoString temp1(kCSSRawFontDescs[index]);
nsCAutoString temp2(kCSSRawFontDescs[index]);
ToLowerCase(temp1);
NS_ASSERTION(temp1.Equals(temp2), "upper case char in desc table");
NS_ASSERTION(-1 == temp1.FindChar('_'), "underscore char in desc table");
}
}
#endif
gFontDescTable->Init(kCSSRawFontDescs, eCSSFontDesc_COUNT);
}
}
}
@ -101,6 +131,10 @@ nsCSSProps::ReleaseTable(void)
delete gPropertyTable;
gPropertyTable = nsnull;
}
if (gFontDescTable) {
delete gFontDescTable;
gFontDescTable = nsnull;
}
}
}
@ -160,6 +194,20 @@ nsCSSProps::LookupProperty(const nsAString& aProperty)
return res;
}
nsCSSFontDesc
nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
{
NS_ASSERTION(gFontDescTable, "no lookup table, needs addref");
return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
}
nsCSSFontDesc
nsCSSProps::LookupFontDesc(const nsAString& aFontDesc)
{
NS_ASSERTION(gFontDescTable, "no lookup table, needs addref");
return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
}
const nsAFlatCString&
nsCSSProps::GetStringValue(nsCSSProperty aProperty)
{
@ -172,6 +220,18 @@ nsCSSProps::GetStringValue(nsCSSProperty aProperty)
}
}
const nsAFlatCString&
nsCSSProps::GetStringValue(nsCSSFontDesc aFontDescID)
{
NS_ASSERTION(gFontDescTable, "no lookup table, needs addref");
if (gFontDescTable) {
return gFontDescTable->GetStringValue(PRInt32(aFontDescID));
} else {
static nsDependentCString sNullStr("");
return sNullStr;
}
}
/***************************************************************************/

Просмотреть файл

@ -65,8 +65,13 @@ public:
return (aProperty >= eCSSProperty_COUNT_no_shorthands);
}
// Same but for @font-face descriptors
static nsCSSFontDesc LookupFontDesc(const nsAString& aProperty);
static nsCSSFontDesc LookupFontDesc(const nsACString& aProperty);
// Given a property enum, get the string value
static const nsAFlatCString& GetStringValue(nsCSSProperty aProperty);
static const nsAFlatCString& GetStringValue(nsCSSFontDesc aFontDesc);
// Given a CSS Property and a Property Enum Value
// Return back a const nsString& representation of the

Просмотреть файл

@ -39,6 +39,7 @@
/* rules in a CSS stylesheet other than style rules (e.g., @import rules) */
#include "nsCSSRules.h"
#include "nsCSSValue.h"
#include "nsICSSImportRule.h"
#include "nsICSSNameSpaceRule.h"
@ -47,6 +48,7 @@
#include "nsIURL.h"
#include "nsCSSRule.h"
#include "nsCSSProps.h"
#include "nsICSSStyleSheet.h"
#include "nsCOMPtr.h"
@ -56,6 +58,7 @@
#include "nsIDOMCSSMediaRule.h"
#include "nsIDOMCSSMozDocumentRule.h"
#include "nsIDOMCSSCharsetRule.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsIMediaList.h"
#include "nsIDOMMediaList.h"
#include "nsIDOMCSSRuleList.h"
@ -66,6 +69,8 @@
#include "nsContentUtils.h"
#include "nsStyleConsts.h"
#include "nsDOMError.h"
#include "nsStyleUtil.h"
#include "nsCSSDeclaration.h"
#define IMPL_STYLE_RULE_INHERIT(_class, super) \
NS_IMETHODIMP _class::GetStyleSheet(nsIStyleSheet*& aSheet) const { return super::GetStyleSheet(aSheet); } \
@ -1013,7 +1018,7 @@ nsCSSMediaRule::GetMedia(nsIDOMMediaList* *aMedia)
return NS_OK;
}
return CallQueryInterface(mMedia, aMedia);
return CallQueryInterface(mMedia.get(), aMedia);
}
NS_IMETHODIMP
@ -1451,3 +1456,424 @@ CSSNameSpaceRuleImpl::GetParentRule(nsIDOMCSSRule** aParentRule)
*aParentRule = nsnull;
return NS_OK;
}
// -------------------------------------------
// nsCSSFontFaceStyleDecl and related routines
//
// A src: descriptor is represented as an array value; each entry in
// the array can be eCSSUnit_URL, eCSSUnit_Local_Font, or
// eCSSUnit_Font_Format. Blocks of eCSSUnit_Font_Format may appear
// only after one of the first two. (css3-fonts only contemplates
// annotating URLs with formats, but we handle the general case.)
static void
SerializeFontSrc(const nsCSSValue& src, nsAString & aResult NS_OUTPARAM)
{
NS_PRECONDITION(src.GetUnit() == eCSSUnit_Null ||
src.GetUnit() == eCSSUnit_Array,
"improper value unit for src:");
aResult.Truncate();
if (src.GetUnit() != eCSSUnit_Array)
return;
const nsCSSValue::Array& sources = *src.GetArrayValue();
PRUint32 i = 0;
while (i < sources.Count()) {
nsAutoString formats;
if (sources[i].GetUnit() == eCSSUnit_URL) {
nsDependentString url(sources[i].GetOriginalURLValue());
nsAutoString escapedUrl;
nsStyleUtil::EscapeCSSString(url, escapedUrl);
aResult.AppendLiteral("url(\"");
aResult.Append(escapedUrl);
aResult.AppendLiteral("\")");
} else if (sources[i].GetUnit() == eCSSUnit_Local_Font) {
nsDependentString local(sources[i].GetStringBufferValue());
nsAutoString escapedLocal;
nsStyleUtil::EscapeCSSString(local, escapedLocal);
aResult.AppendLiteral("local(\"");
aResult.Append(escapedLocal);
aResult.AppendLiteral("\")");
} else {
NS_NOTREACHED("entry in src: descriptor with improper unit");
i++;
continue;
}
i++;
formats.Truncate();
while (i < sources.Count() &&
sources[i].GetUnit() == eCSSUnit_Font_Format) {
formats.Append('"');
formats.Append(sources[i].GetStringBufferValue());
formats.AppendLiteral("\", ");
i++;
}
if (formats.Length() > 0) {
formats.Truncate(formats.Length() - 2); // remove the last comma
aResult.AppendLiteral(" format(");
aResult.Append(formats);
aResult.Append(')');
}
aResult.AppendLiteral(", ");
}
aResult.Truncate(aResult.Length() - 2); // remove the last comma-space
}
// Mapping from nsCSSFontDesc codes to nsCSSFontFaceStyleDecl fields.
// Keep this in sync with enum nsCSSFontDesc in nsCSSProperty.h.
nsCSSValue nsCSSFontFaceStyleDecl::* const
nsCSSFontFaceStyleDecl::Fields[] = {
&nsCSSFontFaceStyleDecl::mFamily,
&nsCSSFontFaceStyleDecl::mStyle,
&nsCSSFontFaceStyleDecl::mWeight,
&nsCSSFontFaceStyleDecl::mStretch,
&nsCSSFontFaceStyleDecl::mSrc,
&nsCSSFontFaceStyleDecl::mUnicodeRange
};
// QueryInterface implementation for nsCSSFontFaceStyleDecl
NS_INTERFACE_MAP_BEGIN(nsCSSFontFaceStyleDecl)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleDeclaration)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSFontFaceStyleDecl)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF_USING_AGGREGATOR(nsCSSFontFaceStyleDecl, ContainingRule())
NS_IMPL_RELEASE_USING_AGGREGATOR(nsCSSFontFaceStyleDecl, ContainingRule())
// helper for string GetPropertyValue and RemovePropertyValue
nsresult
nsCSSFontFaceStyleDecl::GetPropertyValue(nsCSSFontDesc aFontDescID,
nsAString & aResult NS_OUTPARAM) const
{
NS_ENSURE_ARG_RANGE(aFontDescID, eCSSFontDesc_UNKNOWN,
eCSSFontDesc_COUNT - 1);
aResult.Truncate();
if (aFontDescID == eCSSFontDesc_UNKNOWN)
return NS_OK;
const nsCSSValue& val = this->*nsCSSFontFaceStyleDecl::Fields[aFontDescID];
switch (aFontDescID) {
case eCSSFontDesc_Family: {
// we don't use AppendCSSValueToString here because it doesn't
// canonicalize the way we want, and anyway it's overkill when
// we know we have eCSSUnit_String
nsDependentString family(val.GetStringBufferValue());
nsAutoString escapedFamily;
nsStyleUtil::EscapeCSSString(family, escapedFamily);
aResult.Append('"');
aResult.Append(escapedFamily);
aResult.Append('"');
return NS_OK;
}
case eCSSFontDesc_Style:
nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_font_style, val,
aResult);
return NS_OK;
case eCSSFontDesc_Weight:
nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_font_weight, val,
aResult);
return NS_OK;
case eCSSFontDesc_Stretch:
nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_font_stretch, val,
aResult);
return NS_OK;
case eCSSFontDesc_Src:
SerializeFontSrc(val, aResult);
return NS_OK;
case eCSSFontDesc_UnicodeRange:
// these are not implemented, so always return an empty string
return NS_OK;
case eCSSFontDesc_UNKNOWN:
case eCSSFontDesc_COUNT:
;
}
NS_NOTREACHED("nsCSSFontFaceStyleDecl::GetPropertyValue: "
"out-of-range value got to the switch");
return NS_ERROR_INVALID_ARG;
}
// attribute DOMString cssText;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetCssText(nsAString & aCssText)
{
nsAutoString descStr;
aCssText.Truncate();
for (nsCSSFontDesc id = nsCSSFontDesc(eCSSFontDesc_UNKNOWN + 1);
id < eCSSFontDesc_COUNT;
id = nsCSSFontDesc(id + 1)) {
if ((this->*nsCSSFontFaceStyleDecl::Fields[id]).GetUnit()
!= eCSSUnit_Null &&
NS_SUCCEEDED(GetPropertyValue(id, descStr))) {
NS_ASSERTION(descStr.Length() > 0,
"GetCssText: non-null unit, empty property value");
aCssText.AppendLiteral(" ");
aCssText.AppendASCII(nsCSSProps::GetStringValue(id).get());
aCssText.AppendLiteral(": ");
aCssText.Append(descStr);
aCssText.AppendLiteral(";\n");
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::SetCssText(const nsAString & aCssText)
{
return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
}
// DOMString getPropertyValue (in DOMString propertyName);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetPropertyValue(const nsAString & propertyName,
nsAString & aResult NS_OUTPARAM)
{
return GetPropertyValue(nsCSSProps::LookupFontDesc(propertyName), aResult);
}
// nsIDOMCSSValue getPropertyCSSValue (in DOMString propertyName);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetPropertyCSSValue(const nsAString & propertyName,
nsIDOMCSSValue **aResult NS_OUTPARAM)
{
// ??? nsDOMCSSDeclaration returns null/NS_OK, but that seems wrong.
return NS_ERROR_NOT_IMPLEMENTED;
}
// DOMString removeProperty (in DOMString propertyName) raises (DOMException);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::RemoveProperty(const nsAString & propertyName,
nsAString & aResult NS_OUTPARAM)
{
nsCSSFontDesc descID = nsCSSProps::LookupFontDesc(propertyName);
NS_ASSERTION(descID >= eCSSFontDesc_UNKNOWN &&
descID < eCSSFontDesc_COUNT,
"LookupFontDesc returned value out of range");
if (descID == eCSSFontDesc_UNKNOWN) {
aResult.Truncate();
} else {
nsresult rv = GetPropertyValue(descID, aResult);
NS_ENSURE_SUCCESS(rv, rv);
(this->*nsCSSFontFaceStyleDecl::Fields[descID]).Reset();
}
return NS_OK;
}
// DOMString getPropertyPriority (in DOMString propertyName);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetPropertyPriority(const nsAString & propertyName,
nsAString & aResult NS_OUTPARAM)
{
// font descriptors do not have priorities at present
aResult.Truncate();
return NS_OK;
}
// void setProperty (in DOMString propertyName, in DOMString value,
// in DOMString priority) raises (DOMException);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::SetProperty(const nsAString & propertyName,
const nsAString & value,
const nsAString & priority)
{
return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
}
// readonly attribute unsigned long length;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetLength(PRUint32 *aLength)
{
PRUint32 len = 0;
for (nsCSSFontDesc id = nsCSSFontDesc(eCSSFontDesc_UNKNOWN + 1);
id < eCSSFontDesc_COUNT;
id = nsCSSFontDesc(id + 1))
if ((this->*nsCSSFontFaceStyleDecl::Fields[id]).GetUnit() != eCSSUnit_Null)
len++;
*aLength = len;
return NS_OK;
}
// DOMString item (in unsigned long index);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::Item(PRUint32 index, nsAString & aResult NS_OUTPARAM)
{
PRInt32 nset = -1;
for (nsCSSFontDesc id = nsCSSFontDesc(eCSSFontDesc_UNKNOWN + 1);
id < eCSSFontDesc_COUNT;
id = nsCSSFontDesc(id + 1)) {
if ((this->*nsCSSFontFaceStyleDecl::Fields[id]).GetUnit()
!= eCSSUnit_Null) {
nset++;
if (nset == PRInt32(index)) {
aResult.AssignASCII(nsCSSProps::GetStringValue(id).get());
return NS_OK;
}
}
}
aResult.Truncate();
return NS_OK;
}
// readonly attribute nsIDOMCSSRule parentRule;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetParentRule(nsIDOMCSSRule** aParentRule)
{
return ContainingRule()->GetDOMRule(aParentRule);
}
// -------------------------------------------
// nsCSSFontFaceRule
//
NS_IMETHODIMP
nsCSSFontFaceRule::Clone(nsICSSRule*& aClone) const
{
nsCSSFontFaceRule* clone = new nsCSSFontFaceRule(*this);
if (clone) {
return CallQueryInterface(clone, &aClone);
}
aClone = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMPL_ADDREF_INHERITED(nsCSSFontFaceRule, nsCSSRule)
NS_IMPL_RELEASE_INHERITED(nsCSSFontFaceRule, nsCSSRule)
// QueryInterface implementation for nsCSSFontFaceRule
NS_INTERFACE_MAP_BEGIN(nsCSSFontFaceRule)
NS_INTERFACE_MAP_ENTRY(nsICSSRule)
NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSFontFaceRule)
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICSSRule)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSFontFaceRule)
NS_INTERFACE_MAP_END
IMPL_STYLE_RULE_INHERIT(nsCSSFontFaceRule, nsCSSRule)
#ifdef DEBUG
NS_IMETHODIMP
nsCSSFontFaceRule::List(FILE* out, PRInt32 aIndent) const
{
nsCString baseInd, descInd;
for (PRInt32 indent = aIndent; --indent >= 0; ) {
baseInd.AppendLiteral(" ");
descInd.AppendLiteral(" ");
}
descInd.AppendLiteral(" ");
nsString descStr;
fprintf(out, "%s@font-face {\n", baseInd.get());
for (nsCSSFontDesc id = nsCSSFontDesc(eCSSFontDesc_UNKNOWN + 1);
id < eCSSFontDesc_COUNT;
id = nsCSSFontDesc(id + 1))
if ((mDecl.*nsCSSFontFaceStyleDecl::Fields[id]).GetUnit()
!= eCSSUnit_Null) {
if (NS_FAILED(mDecl.GetPropertyValue(id, descStr)))
descStr.AssignLiteral("#<serialization error>");
else if (descStr.Length() == 0)
descStr.AssignLiteral("#<serialization missing>");
fprintf(out, "%s%s: %s\n",
descInd.get(), nsCSSProps::GetStringValue(id).get(),
NS_ConvertUTF16toUTF8(descStr).get());
}
fprintf(out, "%s}\n", baseInd.get());
return NS_OK;
}
#endif
NS_IMETHODIMP
nsCSSFontFaceRule::GetType(PRInt32& aType) const
{
aType = nsICSSRule::FONT_FACE_RULE;
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceRule::GetType(PRUint16* aType)
{
*aType = nsIDOMCSSRule::FONT_FACE_RULE;
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceRule::GetCssText(nsAString& aCssText)
{
nsAutoString propText;
mDecl.GetCssText(propText);
aCssText.AssignLiteral("@font-face {\n");
aCssText.Append(propText);
aCssText.Append('}');
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceRule::SetCssText(const nsAString& aCssText)
{
return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
}
NS_IMETHODIMP
nsCSSFontFaceRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
{
if (mSheet) {
return CallQueryInterface(mSheet, aSheet);
}
*aSheet = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceRule::GetParentRule(nsIDOMCSSRule** aParentRule)
{
if (mParentRule) {
return mParentRule->GetDOMRule(aParentRule);
}
*aParentRule = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsCSSFontFaceRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
{
return CallQueryInterface(&mDecl, aStyle);
}
// Arguably these should forward to nsCSSFontFaceStyleDecl methods.
void
nsCSSFontFaceRule::SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue)
{
NS_PRECONDITION(aDescID > eCSSFontDesc_UNKNOWN &&
aDescID < eCSSFontDesc_COUNT,
"aDescID out of range in nsCSSFontFaceRule::SetDesc");
mDecl.*nsCSSFontFaceStyleDecl::Fields[aDescID] = aValue;
}
void
nsCSSFontFaceRule::GetDesc(nsCSSFontDesc aDescID, nsCSSValue & aValue)
{
NS_PRECONDITION(aDescID > eCSSFontDesc_UNKNOWN &&
aDescID < eCSSFontDesc_COUNT,
"aDescID out of range in nsCSSFontFaceRule::GetDesc");
aValue = mDecl.*nsCSSFontFaceStyleDecl::Fields[aDescID];
}

Просмотреть файл

@ -45,12 +45,13 @@
#include "nsCSSRule.h"
#include "nsICSSGroupRule.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsCOMArray.h"
#include "nsIDOMCSSMediaRule.h"
#include "nsIDOMCSSMozDocumentRule.h"
#include "nsString.h"
#include "nsIDOMCSSFontFaceRule.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsAutoPtr.h"
#include "nsCSSProperty.h"
#include "nsCSSValue.h"
class CSSGroupRuleRuleListImpl;
class nsMediaList;
@ -142,7 +143,7 @@ public:
nsresult SetMedia(nsMediaList* aMedia);
protected:
nsCOMPtr<nsMediaList> mMedia;
nsRefPtr<nsMediaList> mMedia;
};
class nsCSSDocumentRule : public nsCSSGroupRule,
@ -201,5 +202,81 @@ protected:
nsAutoPtr<URL> mURLs; // linked list of |struct URL| above.
};
// A nsCSSFontFaceStyleDecl is always embedded in a nsCSSFontFaceRule.
class nsCSSFontFaceRule;
class nsCSSFontFaceStyleDecl : public nsIDOMCSSStyleDeclaration
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMCSSSTYLEDECLARATION
nsresult GetPropertyValue(nsCSSFontDesc aFontDescID,
nsAString & aResult NS_OUTPARAM) const;
protected:
friend class nsCSSFontFaceRule;
nsCSSValue mFamily;
nsCSSValue mStyle;
nsCSSValue mWeight;
nsCSSValue mStretch;
nsCSSValue mSrc;
nsCSSValue mUnicodeRange;
static nsCSSValue nsCSSFontFaceStyleDecl::* const Fields[];
inline nsCSSFontFaceRule* ContainingRule();
inline const nsCSSFontFaceRule* ContainingRule() const;
private:
// NOT TO BE IMPLEMENTED
// This object cannot be allocated on its own, only as part of
// nsCSSFontFaceRule.
void* operator new(size_t size) CPP_THROW_NEW;
};
class nsCSSFontFaceRule : public nsCSSRule,
public nsICSSRule,
public nsIDOMCSSFontFaceRule
{
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIStyleRule methods
#ifdef DEBUG
NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// nsICSSRule methods
DECL_STYLE_RULE_INHERIT
NS_IMETHOD GetType(PRInt32& aType) const;
NS_IMETHOD Clone(nsICSSRule*& aClone) const;
// nsIDOMCSSRule interface
NS_DECL_NSIDOMCSSRULE
// nsIDOMCSSFontFaceRule interface
NS_DECL_NSIDOMCSSFONTFACERULE
void SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue);
void GetDesc(nsCSSFontDesc aDescID, nsCSSValue & aValue);
protected:
friend class nsCSSFontFaceStyleDecl;
nsCSSFontFaceStyleDecl mDecl;
};
inline nsCSSFontFaceRule*
nsCSSFontFaceStyleDecl::ContainingRule()
{
return reinterpret_cast<nsCSSFontFaceRule*>
(reinterpret_cast<char*>(this) - offsetof(nsCSSFontFaceRule, mDecl));
}
inline const nsCSSFontFaceRule*
nsCSSFontFaceStyleDecl::ContainingRule() const
{
return reinterpret_cast<const nsCSSFontFaceRule*>
(reinterpret_cast<const char*>(this) - offsetof(nsCSSFontFaceRule, mDecl));
}
#endif /* !defined(nsCSSRules_h_) */

Просмотреть файл

@ -80,8 +80,8 @@ nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit)
nsCSSValue::nsCSSValue(const nsString& aValue, nsCSSUnit aUnit)
: mUnit(aUnit)
{
NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr), "not a string value");
if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr)) {
NS_ASSERTION(UnitHasStringValue(), "not a string value");
if (UnitHasStringValue()) {
mValue.mString = BufferFromString(aValue);
if (NS_UNLIKELY(!mValue.mString)) {
// XXXbz not much we can do here; just make sure that our promise of a
@ -133,7 +133,7 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
else if (eCSSUnit_Percent <= mUnit) {
mValue.mFloat = aCopy.mValue.mFloat;
}
else if (eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr) {
else if (UnitHasStringValue()) {
mValue.mString = aCopy.mValue.mString;
mValue.mString->AddRef();
}
@ -175,7 +175,7 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const
if (mUnit <= eCSSUnit_Dummy) {
return PR_TRUE;
}
else if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr)) {
else if (UnitHasStringValue()) {
return (NS_strcmp(GetBufferValue(mValue.mString),
GetBufferValue(aOther.mValue.mString)) == 0);
}
@ -247,7 +247,7 @@ nscoord nsCSSValue::GetLengthTwips() const
void nsCSSValue::DoReset()
{
if (eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr) {
if (UnitHasStringValue()) {
mValue.mString->Release();
} else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) {
mValue.mArray->Release();
@ -291,17 +291,18 @@ void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit)
void nsCSSValue::SetStringValue(const nsString& aValue,
nsCSSUnit aUnit)
{
NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr), "not a string unit");
Reset();
if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr)) {
mUnit = aUnit;
mUnit = aUnit;
NS_ASSERTION(UnitHasStringValue(), "not a string unit");
if (UnitHasStringValue()) {
mValue.mString = BufferFromString(aValue);
if (NS_UNLIKELY(!mValue.mString)) {
// XXXbz not much we can do here; just make sure that our promise of a
// non-null mValue.mString holds for string units.
mUnit = eCSSUnit_Null;
}
}
} else
mUnit = eCSSUnit_Null;
}
void nsCSSValue::SetColorValue(nscolor aValue)

Просмотреть файл

@ -66,6 +66,8 @@ enum nsCSSUnit {
// only in temporary values
eCSSUnit_String = 10, // (PRUnichar*) a string value
eCSSUnit_Attr = 11, // (PRUnichar*) a attr(string) value
eCSSUnit_Local_Font = 12, // (PRUnichar*) a local font name
eCSSUnit_Font_Format = 13, // (PRUnichar*) a font format name
eCSSUnit_Array = 20, // (nsCSSValue::Array*) a list of values
eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value
eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value
@ -161,17 +163,20 @@ public:
nsCSSUnit GetUnit() const { return mUnit; }
PRBool IsLengthUnit() const
{ return PRBool((eCSSUnit_Inch <= mUnit) && (mUnit <= eCSSUnit_Pixel)); }
{ return eCSSUnit_Inch <= mUnit && mUnit <= eCSSUnit_Pixel; }
PRBool IsFixedLengthUnit() const
{ return PRBool((eCSSUnit_Inch <= mUnit) && (mUnit <= eCSSUnit_Cicero)); }
{ return eCSSUnit_Inch <= mUnit && mUnit <= eCSSUnit_Cicero; }
PRBool IsRelativeLengthUnit() const
{ return PRBool((eCSSUnit_EM <= mUnit) && (mUnit <= eCSSUnit_Pixel)); }
{ return eCSSUnit_EM <= mUnit && mUnit <= eCSSUnit_Pixel; }
PRBool IsAngularUnit() const
{ return PRBool((eCSSUnit_Degree <= mUnit) && (mUnit <= eCSSUnit_Radian)); }
{ return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Radian; }
PRBool IsFrequencyUnit() const
{ return PRBool((eCSSUnit_Hertz <= mUnit) && (mUnit <= eCSSUnit_Kilohertz)); }
{ return eCSSUnit_Hertz <= mUnit && mUnit <= eCSSUnit_Kilohertz; }
PRBool IsTimeUnit() const
{ return PRBool((eCSSUnit_Seconds <= mUnit) && (mUnit <= eCSSUnit_Milliseconds)); }
{ return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; }
PRBool UnitHasStringValue() const
{ return eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Font_Format; }
PRInt32 GetIntValue() const
{
@ -195,8 +200,7 @@ public:
nsAString& GetStringValue(nsAString& aBuffer) const
{
NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr,
"not a string value");
NS_ASSERTION(UnitHasStringValue(), "not a string value");
aBuffer.Truncate();
PRUint32 len = NS_strlen(GetBufferValue(mValue.mString));
mValue.mString->ToString(len, aBuffer);
@ -205,8 +209,7 @@ public:
const PRUnichar* GetStringBufferValue() const
{
NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr,
"not a string value");
NS_ASSERTION(UnitHasStringValue(), "not a string value");
return GetBufferValue(mValue.mString);
}

Просмотреть файл

@ -99,6 +99,7 @@ _TEST_FILES = test_acid3_test46.html \
test_compute_data_with_start_struct.html \
test_css_eof_handling.html \
test_dont_use_document_colors.html \
test_font_face_parser.html \
test_inherit_computation.html \
test_inherit_storage.html \
test_initial_computation.html \

Просмотреть файл

@ -0,0 +1,206 @@
<!DOCTYPE HTML><html>
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=441469 -->
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Test of @font-face parser</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<p>@font-face parsing (<a
target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=441469"
>bug 441469</a>)</p>
<pre id="display"></pre>
<style type="text/css" id="testbox"></style>
<script class="testbody" type="text/javascript">
function _(b) { return "@font-face { " + b + " }"; };
var testset = [
// Complete nonsense - shouldn't make a font-face rule at all.
{ rule: "@font-face;" },
{ rule: "font-face { }" },
{ rule: "@fontface { }" },
{ rule: "@namespace foo url(http://example.com/foo);" },
// Empty rule.
{ rule: "@font-face { }", d: {} },
{ rule: "@font-face {", d: {} },
{ rule: "@font-face { ; }", d: {}, noncanonical: true },
// Correct font-family.
{ rule: _("font-family: \"Mouse\";"), d: {"font-family" : "\"Mouse\""} },
{ rule: _("font-family: \"Mouse\""), d: {"font-family" : "\"Mouse\""},
noncanonical: true },
{ rule: _("font-family: Mouse;"), d: {"font-family" : "\"Mouse\"" },
noncanonical: true },
{ rule: _("font-family: Mouse"), d: {"font-family" : "\"Mouse\"" },
noncanonical: true },
// Correct but unusual font-family.
{ rule: _("font-family: Hoefler Text;"),
d: {"font-family" : "\"Hoefler Text\""},
noncanonical: true },
// Incorrect font-family.
{ rule: _("font-family:"), d: {} },
{ rule: _("font-family \"Mouse\""), d: {} },
{ rule: _("font-family: *"), d: {} },
{ rule: _("font-family: Mouse, Rat"), d: {} },
{ rule: _("font-family: sans-serif"), d: {} },
// Correct font-style.
{ rule: _("font-style: normal;"), d: {"font-style" : "normal"} },
{ rule: _("font-style: italic;"), d: {"font-style" : "italic"} },
{ rule: _("font-style: oblique;"), d: {"font-style" : "oblique"} },
// Correct font-weight.
{ rule: _("font-weight: 100;"), d: {"font-weight" : "100"} },
{ rule: _("font-weight: 200;"), d: {"font-weight" : "200"} },
{ rule: _("font-weight: 300;"), d: {"font-weight" : "300"} },
{ rule: _("font-weight: 400;"), d: {"font-weight" : "400"} },
{ rule: _("font-weight: 500;"), d: {"font-weight" : "500"} },
{ rule: _("font-weight: 600;"), d: {"font-weight" : "600"} },
{ rule: _("font-weight: 700;"), d: {"font-weight" : "700"} },
{ rule: _("font-weight: 800;"), d: {"font-weight" : "800"} },
{ rule: _("font-weight: 900;"), d: {"font-weight" : "900"} },
{ rule: _("font-weight: normal;"), d: {"font-weight" : "normal"} },
{ rule: _("font-weight: bold;"), d: {"font-weight" : "bold"} },
// Incorrect font-weight.
{ rule: _("font-weight: bolder;"), d: {} },
{ rule: _("font-weight: lighter;"), d: {} },
// Correct font-stretch.
{ rule: _("font-stretch: ultra-condensed;"),
d: {"font-stretch" : "ultra-condensed"} },
{ rule: _("font-stretch: extra-condensed;"),
d: {"font-stretch" : "extra-condensed"} },
{ rule: _("font-stretch: condensed;"),
d: {"font-stretch" : "condensed"} },
{ rule: _("font-stretch: semi-condensed;"),
d: {"font-stretch" : "semi-condensed"} },
{ rule: _("font-stretch: normal;"),
d: {"font-stretch" : "normal"} },
{ rule: _("font-stretch: semi-expanded;"),
d: {"font-stretch" : "semi-expanded"} },
{ rule: _("font-stretch: expanded;"),
d: {"font-stretch" : "expanded"} },
{ rule: _("font-stretch: extra-expanded;"),
d: {"font-stretch" : "extra-expanded"} },
{ rule: _("font-stretch: ultra-expanded;"),
d: {"font-stretch" : "ultra-expanded"} },
// Incorrect font-stretch.
{ rule: _("font-stretch: wider;"), d: {} },
{ rule: _("font-stretch: narrower;"), d: {} },
// Correct src:
{ rule: _("src: url(\"/fonts/Mouse\");"),
d: { "src" : "url(\"/fonts/Mouse\")" } },
{ rule: _("src: url(/fonts/Mouse);"),
d: { "src" : "url(\"/fonts/Mouse\")" }, noncanonical: true },
{ rule: _("src: url(\"/fonts/Mouse\") format(\"truetype\");"),
d: { "src" : "url(\"/fonts/Mouse\") format(\"truetype\")" } },
{ rule: _("src: url(\"/fonts/Mouse\") format(\"truetype\", \"opentype\");"),
d: { "src" : "url(\"/fonts/Mouse\") format(\"truetype\", \"opentype\")" } },
{ rule: _("src: url(\"/fonts/Mouse\"), url(\"/fonts/Rat\");"),
d: { "src" : "url(\"/fonts/Mouse\"), url(\"/fonts/Rat\")" } },
{ rule: _("src: local(Mouse), url(\"/fonts/Mouse\");"),
d: { "src" : "local(\"Mouse\"), url(\"/fonts/Mouse\")" },
noncanonical: true },
{ rule: _("src: local(\"老鼠\"), url(\"/fonts/Mouse\");"),
d: { "src" : "local(\"老鼠\"), url(\"/fonts/Mouse\")" } },
{ rule: _("src: local(\"老鼠\"), url(\"/fonts/Mouse\") format(\"truetype\");"),
d: { "src" : "local(\"老鼠\"), url(\"/fonts/Mouse\") format(\"truetype\")" } },
// Correct but unusual src:
{ rule: _("src: local(Hoefler Text);"),
d: {"src" : "local(\"Hoefler Text\")"}, noncanonical: true },
// Incorrect src:
{ rule: _("src: \"/fonts/Mouse\";"), d: {} },
{ rule: _("src: /fonts/Mouse;"), d: {} },
{ rule: _("src: url(\"/fonts/Mouse\") format(truetype);"), d: {} },
{ rule: _("src: url(\"/fonts/Mouse\") format(\"truetype\",opentype);"), d: {} },
{ rule: _("src: local(*);"), d: {} },
{ rule: _("src: format(\"truetype\");"), d: {} },
{ rule: _("src: local(Mouse) format(\"truetype\");"), d: {} },
{ rule: _("src: local(Mouse, Rat);"), d: {} },
{ rule: _("src: local(sans-serif);"), d: {} }
// unicode-range is not implemented (bug 443976).
// tests for that omitted for now.
];
var display = document.getElementById("display");
var sheet = document.styleSheets[1];
for (var curTest = 0; curTest < testset.length; curTest++) {
try {
while(sheet.cssRules.length > 0)
sheet.deleteRule(0);
sheet.insertRule(testset[curTest].rule, 0);
} catch (e if e instanceof DOMException) {
ok(e.code == DOMException.SYNTAX_ERR
&& !('d' in testset[curTest]),
testset[curTest].rule + " syntax error thrown", e);
} catch (e) {
ok(false, testset[curTest].rule, "During prep: " + e);
}
try {
if (testset[curTest].d) {
is(sheet.cssRules.length, 1,
testset[curTest].rule + " rule count");
is(sheet.cssRules[0].type, 5 /*FONT_FACE_RULE*/,
testset[curTest].rule + " rule type");
var d = testset[curTest].d;
var s = sheet.cssRules[0].style;
var n = 0;
// everything is set that should be
for (var name in d) {
is(s.getPropertyValue(name), d[name],
testset[curTest].rule + " (prop " + name + ")");
n++;
}
// nothing else is set
is(s.length, n, testset[curTest].rule + "prop count");
for (var i = 0; i < s.length; i++) {
ok(s[i] in d, testset[curTest].rule,
"Unexpected item #" + i + ": " + s[i]);
}
// round-tripping of cssText
// this is a strong test; it's okay if the exact serialization
// changes in the future
if (n && !testset[curTest].noncanonical) {
is(sheet.cssRules[0].cssText.replace(/[ \n]+/g, " "),
testset[curTest].rule,
testset[curTest].rule + " rule text");
}
} else {
if (sheet.cssRules.length == 0) {
is(sheet.cssRules.length, 0,
testset[curTest].rule + " rule count (0)");
} else {
is(sheet.cssRules.length, 1,
testset[curTest].rule + " rule count (1 non-fontface)");
isnot(sheet.cssRules[0].type, 5 /*FONT_FACE_RULE*/,
testset[curTest].rule + " rule type (1 non-fontface)");
}
}
} catch (e) {
ok(false, testset[curTest].rule, "During test: " + e);
}
}
</script>
</body>
</html>