зеркало из https://github.com/mozilla/gecko-dev.git
Bug 549861. Implement support for @font-feature-values rule. r=dbaron
This commit is contained in:
Родитель
6f990b3fc6
Коммит
5b570d8745
|
@ -913,6 +913,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
|
NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH,
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||||
|
NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
|
||||||
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
|
||||||
#ifdef MOZ_TIME_MANAGER
|
#ifdef MOZ_TIME_MANAGER
|
||||||
NS_DEFINE_CLASSINFO_DATA(MozTimeManager, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(MozTimeManager, nsDOMGenericSH,
|
||||||
|
@ -2304,6 +2306,10 @@ nsDOMClassInfo::Init()
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile)
|
||||||
DOM_CLASSINFO_MAP_END
|
DOM_CLASSINFO_MAP_END
|
||||||
|
|
||||||
|
DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
|
||||||
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
|
||||||
|
DOM_CLASSINFO_MAP_END
|
||||||
|
|
||||||
#ifdef MOZ_TIME_MANAGER
|
#ifdef MOZ_TIME_MANAGER
|
||||||
DOM_CLASSINFO_MAP_BEGIN(MozTimeManager, nsIDOMMozTimeManager)
|
DOM_CLASSINFO_MAP_BEGIN(MozTimeManager, nsIDOMMozTimeManager)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozTimeManager)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozTimeManager)
|
||||||
|
|
|
@ -237,6 +237,8 @@ DOMCI_CLASS(AsyncScrollEventDetail)
|
||||||
|
|
||||||
DOMCI_CLASS(LockedFile)
|
DOMCI_CLASS(LockedFile)
|
||||||
|
|
||||||
|
DOMCI_CLASS(CSSFontFeatureValuesRule)
|
||||||
|
|
||||||
#ifdef MOZ_TIME_MANAGER
|
#ifdef MOZ_TIME_MANAGER
|
||||||
DOMCI_CLASS(MozTimeManager)
|
DOMCI_CLASS(MozTimeManager)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -69,6 +69,7 @@ interface nsIDOMCSSPrimitiveValue;
|
||||||
interface nsIDOMCSSRule;
|
interface nsIDOMCSSRule;
|
||||||
interface nsIDOMCSSRuleList;
|
interface nsIDOMCSSRuleList;
|
||||||
interface nsIDOMMozCSSKeyframeRule;
|
interface nsIDOMMozCSSKeyframeRule;
|
||||||
|
interface nsIDOMCSSFontFeatureValuesRule;
|
||||||
interface nsIDOMCSSStyleSheet;
|
interface nsIDOMCSSStyleSheet;
|
||||||
interface nsIDOMCSSStyleDeclaration;
|
interface nsIDOMCSSStyleDeclaration;
|
||||||
interface nsIDOMCounter;
|
interface nsIDOMCounter;
|
||||||
|
|
|
@ -8,6 +8,7 @@ XPIDL_SOURCES += [
|
||||||
'nsIDOMCSSCharsetRule.idl',
|
'nsIDOMCSSCharsetRule.idl',
|
||||||
'nsIDOMCSSConditionRule.idl',
|
'nsIDOMCSSConditionRule.idl',
|
||||||
'nsIDOMCSSFontFaceRule.idl',
|
'nsIDOMCSSFontFaceRule.idl',
|
||||||
|
'nsIDOMCSSFontFeatureValuesRule.idl',
|
||||||
'nsIDOMCSSGroupingRule.idl',
|
'nsIDOMCSSGroupingRule.idl',
|
||||||
'nsIDOMCSSImportRule.idl',
|
'nsIDOMCSSImportRule.idl',
|
||||||
'nsIDOMCSSMediaRule.idl',
|
'nsIDOMCSSMediaRule.idl',
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* John Daggett <jdaggett@mozilla.com> (original author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "nsIDOMCSSRule.idl"
|
||||||
|
|
||||||
|
[scriptable, uuid(f4cb1776-389d-4f52-a4d8-68bea5bd00c1)]
|
||||||
|
interface nsIDOMCSSFontFeatureValuesRule : nsIDOMCSSRule
|
||||||
|
{
|
||||||
|
attribute DOMString fontFamily;
|
||||||
|
// raises(DOMException) on setting
|
||||||
|
|
||||||
|
attribute DOMString valueText;
|
||||||
|
// raises(DOMException) on setting
|
||||||
|
};
|
|
@ -32,6 +32,7 @@ interface nsIDOMCSSRule : nsISupports
|
||||||
const unsigned short MOZ_KEYFRAME_RULE = 8;
|
const unsigned short MOZ_KEYFRAME_RULE = 8;
|
||||||
const unsigned short NAMESPACE_RULE = 10;
|
const unsigned short NAMESPACE_RULE = 10;
|
||||||
const unsigned short SUPPORTS_RULE = 12;
|
const unsigned short SUPPORTS_RULE = 12;
|
||||||
|
const unsigned short FONT_FEATURE_VALUES_RULE = 14;
|
||||||
|
|
||||||
readonly attribute unsigned short type;
|
readonly attribute unsigned short type;
|
||||||
attribute DOMString cssText;
|
attribute DOMString cssText;
|
||||||
|
|
|
@ -115,6 +115,17 @@ PEMQExpectedFeatureValue=Found invalid value for media feature.
|
||||||
PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'.
|
PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'.
|
||||||
PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'.
|
PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'.
|
||||||
PEAnonBoxNotAlone=Did not expect anonymous box.
|
PEAnonBoxNotAlone=Did not expect anonymous box.
|
||||||
|
PEFFVUnexpectedEOF=Unexpected end of @font-feature-values rule.
|
||||||
|
PEFFVBlockStart=Expected opening { of @font-feature-values rule but found '%1$S'.
|
||||||
|
PEFFVValueSetStart=Expected opening { of feature value set but found '%1$S'.
|
||||||
|
PEFFVNoFamily=Expected font family list for @font-feature-values rule but found '%1$S'.
|
||||||
|
PEFFVUnexpectedBlockEnd=Expected '}' to end @font-feature-values rule but found '%1$S'.
|
||||||
|
PEFFVUnknownFontVariantPropValue=Unknown font-variant property value '%1$S'.
|
||||||
|
PEFFVExpectedIdent=Expected identifier but found '%1$S'.
|
||||||
|
PEFFVExpectedValue=Expected non-negative integer value but found '%1$S'.
|
||||||
|
PEFFVTooManyValues=Too many values for feature type '%1$S'.
|
||||||
|
PEFFVGenericInFamilyList=Family list cannot contain generic font family name.
|
||||||
|
PEFFVValueDefinitionTrailing=Expected end of value definition but found '%1$S'.
|
||||||
PEBadDirValue=Expected 'ltr' or 'rtl' in direction selector but found '%1$S'.
|
PEBadDirValue=Expected 'ltr' or 'rtl' in direction selector but found '%1$S'.
|
||||||
PESupportsConditionStartEOF2='not', '(', or function
|
PESupportsConditionStartEOF2='not', '(', or function
|
||||||
PESupportsConditionInParensEOF=')'
|
PESupportsConditionInParensEOF=')'
|
||||||
|
|
|
@ -492,6 +492,7 @@ var interfaceNamesInGlobalScope =
|
||||||
"CloseEvent",
|
"CloseEvent",
|
||||||
"IDBCursorWithValue",
|
"IDBCursorWithValue",
|
||||||
"CSSFontFaceRule",
|
"CSSFontFaceRule",
|
||||||
|
"CSSFontFeatureValuesRule",
|
||||||
"XMLHttpRequestEventTarget",
|
"XMLHttpRequestEventTarget",
|
||||||
"CompositionEvent",
|
"CompositionEvent",
|
||||||
"HTMLOutputElement",
|
"HTMLOutputElement",
|
||||||
|
|
|
@ -35,7 +35,7 @@ nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
|
||||||
variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
|
variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsFont::nsFont(const nsString& aName, uint8_t aStyle, uint8_t aVariant,
|
nsFont::nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
|
||||||
uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
|
uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
|
||||||
nscoord aSize)
|
nscoord aSize)
|
||||||
: name(aName)
|
: name(aName)
|
||||||
|
|
|
@ -113,7 +113,7 @@ struct NS_GFX nsFont {
|
||||||
nscoord aSize);
|
nscoord aSize);
|
||||||
|
|
||||||
// Initialize the font struct with a (potentially) unicode name
|
// Initialize the font struct with a (potentially) unicode name
|
||||||
nsFont(const nsString& aName, uint8_t aStyle, uint8_t aVariant,
|
nsFont(const nsSubstring& aName, uint8_t aStyle, uint8_t aVariant,
|
||||||
uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
|
uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
|
||||||
nscoord aSize);
|
nscoord aSize);
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,8 @@ public:
|
||||||
KEYFRAME_RULE,
|
KEYFRAME_RULE,
|
||||||
KEYFRAMES_RULE,
|
KEYFRAMES_RULE,
|
||||||
DOCUMENT_RULE,
|
DOCUMENT_RULE,
|
||||||
SUPPORTS_RULE
|
SUPPORTS_RULE,
|
||||||
|
FONT_FEATURE_VALUES_RULE
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual int32_t GetType() const = 0;
|
virtual int32_t GetType() const = 0;
|
||||||
|
|
|
@ -375,6 +375,9 @@ protected:
|
||||||
void* aProcessData);
|
void* aProcessData);
|
||||||
|
|
||||||
bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
|
bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
|
||||||
|
bool ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc,
|
||||||
|
void* aProcessData);
|
||||||
|
bool ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule *aRule);
|
||||||
bool ParseFontDescriptor(nsCSSFontFaceRule* aRule);
|
bool ParseFontDescriptor(nsCSSFontFaceRule* aRule);
|
||||||
bool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
|
bool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
|
||||||
nsCSSValue& aValue);
|
nsCSSValue& aValue);
|
||||||
|
@ -1635,6 +1638,11 @@ CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc,
|
||||||
parseFunc = &CSSParserImpl::ParseFontFaceRule;
|
parseFunc = &CSSParserImpl::ParseFontFaceRule;
|
||||||
newSection = eCSSSection_General;
|
newSection = eCSSSection_General;
|
||||||
|
|
||||||
|
} else if (mToken.mIdent.LowerCaseEqualsLiteral("font-feature-values") &&
|
||||||
|
nsCSSFontFeatureValuesRule::PrefEnabled()) {
|
||||||
|
parseFunc = &CSSParserImpl::ParseFontFeatureValuesRule;
|
||||||
|
newSection = eCSSSection_General;
|
||||||
|
|
||||||
} else if (mToken.mIdent.LowerCaseEqualsLiteral("page")) {
|
} else if (mToken.mIdent.LowerCaseEqualsLiteral("page")) {
|
||||||
parseFunc = &CSSParserImpl::ParsePageRule;
|
parseFunc = &CSSParserImpl::ParsePageRule;
|
||||||
newSection = eCSSSection_General;
|
newSection = eCSSSection_General;
|
||||||
|
@ -2360,6 +2368,233 @@ CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule* aRule)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @font-feature-values <font-family># {
|
||||||
|
// @<feature-type> {
|
||||||
|
// <feature-ident> : <feature-index>+;
|
||||||
|
// <feature-ident> : <feature-index>+;
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool
|
||||||
|
CSSParserImpl::ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc,
|
||||||
|
void* aData)
|
||||||
|
{
|
||||||
|
nsRefPtr<nsCSSFontFeatureValuesRule>
|
||||||
|
valuesRule(new nsCSSFontFeatureValuesRule());
|
||||||
|
|
||||||
|
// parse family list
|
||||||
|
nsCSSValue familyValue;
|
||||||
|
|
||||||
|
if (!ParseFamily(familyValue) ||
|
||||||
|
familyValue.GetUnit() != eCSSUnit_Families)
|
||||||
|
{
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVNoFamily);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add family to rule
|
||||||
|
nsAutoString familyList;
|
||||||
|
bool hasGeneric;
|
||||||
|
familyValue.GetStringValue(familyList);
|
||||||
|
valuesRule->SetFamilyList(familyList, hasGeneric);
|
||||||
|
|
||||||
|
// family list has generic ==> parse error
|
||||||
|
if (hasGeneric) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVGenericInFamilyList);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open brace
|
||||||
|
if (!ExpectSymbol('{', true)) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVBlockStart);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// list of sets of feature values, each set bound to a specific
|
||||||
|
// feature-type (e.g. swash, annotation)
|
||||||
|
for (;;) {
|
||||||
|
if (!GetToken(true)) {
|
||||||
|
REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mToken.IsSymbol('}')) { // done!
|
||||||
|
UngetToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ParseFontFeatureValueSet(valuesRule)) {
|
||||||
|
if (!SkipAtRule(false)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ExpectSymbol('}', true)) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVUnexpectedBlockEnd);
|
||||||
|
SkipUntil('}');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*aAppendFunc)(valuesRule, aData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NUMVALUES_NO_LIMIT 0xFFFF
|
||||||
|
|
||||||
|
// parse a single value set containing name-value pairs for a single feature type
|
||||||
|
// @<feature-type> { [ <feature-ident> : <feature-index>+ ; ]* }
|
||||||
|
// Ex: @swash { flowing: 1; delicate: 2; }
|
||||||
|
bool
|
||||||
|
CSSParserImpl::ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule
|
||||||
|
*aFeatureValuesRule)
|
||||||
|
{
|
||||||
|
// -- @keyword (e.g. swash, styleset)
|
||||||
|
if (eCSSToken_AtKeyword != mToken.mType) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFontFeatureValuesNoAt);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
UngetToken();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// which font-specific variant of font-variant-alternates
|
||||||
|
int32_t whichVariant;
|
||||||
|
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
|
||||||
|
if (keyword == eCSSKeyword_UNKNOWN ||
|
||||||
|
!nsCSSProps::FindKeyword(keyword,
|
||||||
|
nsCSSProps::kFontVariantAlternatesFuncsKTable,
|
||||||
|
whichVariant))
|
||||||
|
{
|
||||||
|
if (!NonMozillaVendorIdentifier(mToken.mIdent)) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVUnknownFontVariantPropValue);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
}
|
||||||
|
UngetToken();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString featureType(mToken.mIdent);
|
||||||
|
|
||||||
|
// open brace
|
||||||
|
if (!ExpectSymbol('{', true)) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVValueSetStart);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// styleset and character-variant can be multi-valued, otherwise single value
|
||||||
|
int32_t limitNumValues;
|
||||||
|
|
||||||
|
switch (keyword) {
|
||||||
|
case eCSSKeyword_styleset:
|
||||||
|
limitNumValues = NUMVALUES_NO_LIMIT;
|
||||||
|
break;
|
||||||
|
case eCSSKeyword_character_variant:
|
||||||
|
limitNumValues = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
limitNumValues = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- ident integer+ [, ident integer+]
|
||||||
|
nsAutoTArray<gfxFontFeatureValueSet::ValueList, 5> values;
|
||||||
|
|
||||||
|
// list of font-feature-values-declaration's
|
||||||
|
for (;;) {
|
||||||
|
nsAutoString valueId;
|
||||||
|
|
||||||
|
if (!GetToken(true)) {
|
||||||
|
REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore extra semicolons
|
||||||
|
if (mToken.IsSymbol(';')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close brace ==> done
|
||||||
|
if (mToken.IsSymbol('}')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ident
|
||||||
|
if (eCSSToken_Ident != mToken.mType) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVExpectedIdent);
|
||||||
|
if (!SkipDeclaration(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueId.Assign(mToken.mIdent);
|
||||||
|
|
||||||
|
// colon
|
||||||
|
if (!ExpectSymbol(':', true)) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
if (!SkipDeclaration(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// value list
|
||||||
|
nsAutoTArray<uint32_t,4> featureSelectors;
|
||||||
|
|
||||||
|
nsCSSValue intValue;
|
||||||
|
while (ParseNonNegativeVariant(intValue, VARIANT_INTEGER, nullptr)) {
|
||||||
|
featureSelectors.AppendElement(uint32_t(intValue.GetIntValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t numValues = featureSelectors.Length();
|
||||||
|
|
||||||
|
if (numValues == 0) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVExpectedValue);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
if (!SkipDeclaration(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numValues > limitNumValues) {
|
||||||
|
REPORT_UNEXPECTED_P(PEFFVTooManyValues, featureType);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
if (!SkipDeclaration(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetToken(true)) {
|
||||||
|
REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF);
|
||||||
|
gfxFontFeatureValueSet::ValueList v(valueId, featureSelectors);
|
||||||
|
values.AppendElement(v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ';' or '}' to end definition
|
||||||
|
if (!mToken.IsSymbol(';') && !mToken.IsSymbol('}')) {
|
||||||
|
REPORT_UNEXPECTED_TOKEN(PEFFVValueDefinitionTrailing);
|
||||||
|
OUTPUT_ERROR();
|
||||||
|
if (!SkipDeclaration(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfxFontFeatureValueSet::ValueList v(valueId, featureSelectors);
|
||||||
|
values.AppendElement(v);
|
||||||
|
|
||||||
|
if (mToken.IsSymbol('}')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aFeatureValuesRule->AddValueList(whichVariant, values);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData)
|
CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData)
|
||||||
|
@ -8012,7 +8247,7 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, int32_t& aVariantMask)
|
||||||
// ... or just a value
|
// ... or just a value
|
||||||
UngetToken();
|
UngetToken();
|
||||||
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
|
// Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
|
||||||
// always gets picked up
|
// always gets picked up
|
||||||
if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr)) {
|
if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -649,7 +649,7 @@ void RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
|
||||||
}
|
}
|
||||||
AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue);
|
AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue);
|
||||||
RULE_HASH_STAT_INCREMENT(mTagSelectors);
|
RULE_HASH_STAT_INCREMENT(mTagSelectors);
|
||||||
if (selector->mCasedTag &&
|
if (selector->mCasedTag &&
|
||||||
selector->mCasedTag != selector->mLowercaseTag) {
|
selector->mCasedTag != selector->mLowercaseTag) {
|
||||||
AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue);
|
AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue);
|
||||||
RULE_HASH_STAT_INCREMENT(mTagSelectors);
|
RULE_HASH_STAT_INCREMENT(mTagSelectors);
|
||||||
|
@ -978,6 +978,7 @@ struct RuleCascadeData {
|
||||||
|
|
||||||
nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
|
nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
|
||||||
nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
|
nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*> mFontFeatureValuesRules;
|
||||||
nsTArray<nsCSSPageRule*> mPageRules;
|
nsTArray<nsCSSPageRule*> mPageRules;
|
||||||
|
|
||||||
// Looks up or creates the appropriate list in |mAttributeSelectors|.
|
// Looks up or creates the appropriate list in |mAttributeSelectors|.
|
||||||
|
@ -1029,6 +1030,7 @@ RuleCascadeData::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||||
|
|
||||||
n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf);
|
n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf);
|
n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
|
n += mFontFeatureValuesRules.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
n += mPageRules.SizeOfExcludingThis(aMallocSizeOf);
|
n += mPageRules.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
@ -1437,11 +1439,11 @@ static bool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
|
||||||
: static_cast<const nsStringComparator&>(ciComparator);
|
: static_cast<const nsStringComparator&>(ciComparator);
|
||||||
|
|
||||||
switch (aAttrSelector->mFunction) {
|
switch (aAttrSelector->mFunction) {
|
||||||
case NS_ATTR_FUNC_EQUALS:
|
case NS_ATTR_FUNC_EQUALS:
|
||||||
return aValue.Equals(aAttrSelector->mValue, comparator);
|
return aValue.Equals(aAttrSelector->mValue, comparator);
|
||||||
case NS_ATTR_FUNC_INCLUDES:
|
case NS_ATTR_FUNC_INCLUDES:
|
||||||
return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
|
return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
|
||||||
case NS_ATTR_FUNC_DASHMATCH:
|
case NS_ATTR_FUNC_DASHMATCH:
|
||||||
return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
|
return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
|
||||||
case NS_ATTR_FUNC_ENDSMATCH:
|
case NS_ATTR_FUNC_ENDSMATCH:
|
||||||
return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
|
return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
|
||||||
|
@ -2749,6 +2751,21 @@ nsCSSRuleProcessor::AppendPageRules(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsCSSRuleProcessor::AppendFontFeatureValuesRules(
|
||||||
|
nsPresContext *aPresContext,
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
|
||||||
|
{
|
||||||
|
RuleCascadeData* cascade = GetRuleCascade(aPresContext);
|
||||||
|
|
||||||
|
if (cascade) {
|
||||||
|
if (!aArray.AppendElements(cascade->mFontFeatureValuesRules))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsCSSRuleProcessor::ClearRuleCascades()
|
nsCSSRuleProcessor::ClearRuleCascades()
|
||||||
{
|
{
|
||||||
|
@ -3047,12 +3064,14 @@ struct CascadeEnumData {
|
||||||
CascadeEnumData(nsPresContext* aPresContext,
|
CascadeEnumData(nsPresContext* aPresContext,
|
||||||
nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
|
nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
|
||||||
nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
|
nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& aFontFeatureValuesRules,
|
||||||
nsTArray<nsCSSPageRule*>& aPageRules,
|
nsTArray<nsCSSPageRule*>& aPageRules,
|
||||||
nsMediaQueryResultCacheKey& aKey,
|
nsMediaQueryResultCacheKey& aKey,
|
||||||
uint8_t aSheetType)
|
uint8_t aSheetType)
|
||||||
: mPresContext(aPresContext),
|
: mPresContext(aPresContext),
|
||||||
mFontFaceRules(aFontFaceRules),
|
mFontFaceRules(aFontFaceRules),
|
||||||
mKeyframesRules(aKeyframesRules),
|
mKeyframesRules(aKeyframesRules),
|
||||||
|
mFontFeatureValuesRules(aFontFeatureValuesRules),
|
||||||
mPageRules(aPageRules),
|
mPageRules(aPageRules),
|
||||||
mCacheKey(aKey),
|
mCacheKey(aKey),
|
||||||
mSheetType(aSheetType)
|
mSheetType(aSheetType)
|
||||||
|
@ -3076,6 +3095,7 @@ struct CascadeEnumData {
|
||||||
nsPresContext* mPresContext;
|
nsPresContext* mPresContext;
|
||||||
nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
|
nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
|
||||||
nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
|
nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& mFontFeatureValuesRules;
|
||||||
nsTArray<nsCSSPageRule*>& mPageRules;
|
nsTArray<nsCSSPageRule*>& mPageRules;
|
||||||
nsMediaQueryResultCacheKey& mCacheKey;
|
nsMediaQueryResultCacheKey& mCacheKey;
|
||||||
PLArenaPool mArena;
|
PLArenaPool mArena;
|
||||||
|
@ -3093,7 +3113,9 @@ struct CascadeEnumData {
|
||||||
* but kept in order per-weight, and
|
* but kept in order per-weight, and
|
||||||
* (2) add any @font-face rules, in order, into data->mFontFaceRules.
|
* (2) add any @font-face rules, in order, into data->mFontFaceRules.
|
||||||
* (3) add any @keyframes rules, in order, into data->mKeyframesRules.
|
* (3) add any @keyframes rules, in order, into data->mKeyframesRules.
|
||||||
* (4) add any @page rules, in order, into data->mPageRules.
|
* (4) add any @font-feature-value rules, in order,
|
||||||
|
* into data->mFontFeatureValuesRules.
|
||||||
|
* (5) add any @page rules, in order, into data->mPageRules.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
|
CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
|
||||||
|
@ -3146,6 +3168,13 @@ CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (css::Rule::FONT_FEATURE_VALUES_RULE == type) {
|
||||||
|
nsCSSFontFeatureValuesRule *fontFeatureValuesRule =
|
||||||
|
static_cast<nsCSSFontFeatureValuesRule*>(aRule);
|
||||||
|
if (!data->mFontFeatureValuesRules.AppendElement(fontFeatureValuesRule)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (css::Rule::PAGE_RULE == type) {
|
else if (css::Rule::PAGE_RULE == type) {
|
||||||
nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule);
|
nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule);
|
||||||
if (!data->mPageRules.AppendElement(pageRule)) {
|
if (!data->mPageRules.AppendElement(pageRule)) {
|
||||||
|
@ -3252,6 +3281,7 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
|
||||||
if (newCascade) {
|
if (newCascade) {
|
||||||
CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
|
CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
|
||||||
newCascade->mKeyframesRules,
|
newCascade->mKeyframesRules,
|
||||||
|
newCascade->mFontFeatureValuesRules,
|
||||||
newCascade->mPageRules,
|
newCascade->mPageRules,
|
||||||
newCascade->mCacheKey,
|
newCascade->mCacheKey,
|
||||||
mSheetType);
|
mSheetType);
|
||||||
|
|
|
@ -128,6 +128,9 @@ public:
|
||||||
bool AppendPageRules(nsPresContext* aPresContext,
|
bool AppendPageRules(nsPresContext* aPresContext,
|
||||||
nsTArray<nsCSSPageRule*>& aArray);
|
nsTArray<nsCSSPageRule*>& aArray);
|
||||||
|
|
||||||
|
bool AppendFontFeatureValuesRules(nsPresContext* aPresContext,
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& aArray);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the scope element for the scoped style sheets this rule
|
* Returns the scope element for the scoped style sheets this rule
|
||||||
* processor is for. If this is not a rule processor for scoped style
|
* processor is for. If this is not a rule processor for scoped style
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "nsDOMClassInfoID.h"
|
#include "nsDOMClassInfoID.h"
|
||||||
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
|
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
|
||||||
#include "StyleRule.h"
|
#include "StyleRule.h"
|
||||||
|
#include "nsFont.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
@ -718,7 +719,7 @@ GroupRule::AppendRulesToCssText(nsAString& aCssText)
|
||||||
}
|
}
|
||||||
|
|
||||||
aCssText.AppendLiteral("}");
|
aCssText.AppendLiteral("}");
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1910,6 +1911,255 @@ nsCSSFontFaceRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// nsCSSFontFeatureValuesRule
|
||||||
|
//
|
||||||
|
|
||||||
|
/* virtual */ already_AddRefed<css::Rule>
|
||||||
|
nsCSSFontFeatureValuesRule::Clone() const
|
||||||
|
{
|
||||||
|
nsRefPtr<css::Rule> clone = new nsCSSFontFeatureValuesRule(*this);
|
||||||
|
return clone.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ADDREF(nsCSSFontFeatureValuesRule)
|
||||||
|
NS_IMPL_RELEASE(nsCSSFontFeatureValuesRule)
|
||||||
|
|
||||||
|
DOMCI_DATA(CSSFontFeatureValuesRule, nsCSSFontFeatureValuesRule)
|
||||||
|
|
||||||
|
// QueryInterface implementation for nsCSSFontFeatureValuesRule
|
||||||
|
NS_INTERFACE_MAP_BEGIN(nsCSSFontFeatureValuesRule)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
|
||||||
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
|
||||||
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSFontFeatureValuesRule)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
IMPL_STYLE_RULE_INHERIT(nsCSSFontFeatureValuesRule, Rule)
|
||||||
|
|
||||||
|
static void
|
||||||
|
FamilyListToString(const nsTArray<nsString>& aFamilyList, nsAString& aOutStr)
|
||||||
|
{
|
||||||
|
uint32_t i, n = aFamilyList.Length();
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
nsStyleUtil::AppendEscapedCSSString(aFamilyList[i], aOutStr);
|
||||||
|
if (i != n - 1) {
|
||||||
|
aOutStr.AppendLiteral(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FeatureValuesToString(
|
||||||
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aFeatureValues,
|
||||||
|
nsAString& aOutStr)
|
||||||
|
{
|
||||||
|
uint32_t i, n;
|
||||||
|
|
||||||
|
// append values
|
||||||
|
n = aFeatureValues.Length();
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const gfxFontFeatureValueSet::FeatureValues& fv = aFeatureValues[i];
|
||||||
|
|
||||||
|
// @alternate
|
||||||
|
aOutStr.AppendLiteral(" @");
|
||||||
|
nsAutoString functAlt;
|
||||||
|
nsStyleUtil::GetFunctionalAlternatesName(fv.alternate, functAlt);
|
||||||
|
aOutStr.Append(functAlt);
|
||||||
|
aOutStr.AppendLiteral(" {");
|
||||||
|
|
||||||
|
// for each ident-values tuple
|
||||||
|
uint32_t j, numValues = fv.valuelist.Length();
|
||||||
|
for (j = 0; j < numValues; j++) {
|
||||||
|
aOutStr.AppendLiteral(" ");
|
||||||
|
const gfxFontFeatureValueSet::ValueList& vlist = fv.valuelist[j];
|
||||||
|
nsStyleUtil::AppendEscapedCSSIdent(vlist.name, aOutStr);
|
||||||
|
aOutStr.AppendLiteral(":");
|
||||||
|
|
||||||
|
uint32_t k, numSelectors = vlist.featureSelectors.Length();
|
||||||
|
for (k = 0; k < numSelectors; k++) {
|
||||||
|
aOutStr.AppendLiteral(" ");
|
||||||
|
aOutStr.AppendInt(vlist.featureSelectors[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
aOutStr.AppendLiteral(";");
|
||||||
|
}
|
||||||
|
aOutStr.AppendLiteral(" }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FontFeatureValuesRuleToString(
|
||||||
|
const nsTArray<nsString>& aFamilyList,
|
||||||
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aFeatureValues,
|
||||||
|
nsAString& aOutStr)
|
||||||
|
{
|
||||||
|
aOutStr.AssignLiteral("@font-feature-values ");
|
||||||
|
nsAutoString familyListStr, valueTextStr;
|
||||||
|
FamilyListToString(aFamilyList, familyListStr);
|
||||||
|
aOutStr.Append(familyListStr);
|
||||||
|
aOutStr.AppendLiteral(" {\n");
|
||||||
|
FeatureValuesToString(aFeatureValues, valueTextStr);
|
||||||
|
aOutStr.Append(valueTextStr);
|
||||||
|
aOutStr.AppendLiteral("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
nsCSSFontFeatureValuesRule::List(FILE* out, int32_t aIndent) const
|
||||||
|
{
|
||||||
|
nsAutoString text;
|
||||||
|
FontFeatureValuesRuleToString(mFamilyList, mFeatureValues, text);
|
||||||
|
NS_ConvertUTF16toUTF8 utf8(text);
|
||||||
|
|
||||||
|
// replace newlines with newlines plus indent spaces
|
||||||
|
char* indent = new char[(aIndent + 1) * 2];
|
||||||
|
int32_t i;
|
||||||
|
for (i = 1; i < (aIndent + 1) * 2 - 1; i++) {
|
||||||
|
indent[i] = 0x20;
|
||||||
|
}
|
||||||
|
indent[0] = 0xa;
|
||||||
|
indent[aIndent * 2 + 1] = 0;
|
||||||
|
utf8.ReplaceSubstring("\n", indent);
|
||||||
|
delete [] indent;
|
||||||
|
|
||||||
|
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
||||||
|
fprintf(out, "%s\n", utf8.get());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* virtual */ int32_t
|
||||||
|
nsCSSFontFeatureValuesRule::GetType() const
|
||||||
|
{
|
||||||
|
return Rule::FONT_FEATURE_VALUES_RULE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetType(uint16_t* aType)
|
||||||
|
{
|
||||||
|
*aType = nsIDOMCSSRule::FONT_FEATURE_VALUES_RULE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetCssText(nsAString& aCssText)
|
||||||
|
{
|
||||||
|
FontFeatureValuesRuleToString(mFamilyList, mFeatureValues, aCssText);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::SetCssText(const nsAString& aCssText)
|
||||||
|
{
|
||||||
|
// FIXME: implement???
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
|
||||||
|
{
|
||||||
|
return Rule::GetParentStyleSheet(aSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetParentRule(nsIDOMCSSRule** aParentRule)
|
||||||
|
{
|
||||||
|
return Rule::GetParentRule(aParentRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetFontFamily(nsAString& aFontFamily)
|
||||||
|
{
|
||||||
|
FamilyListToString(mFamilyList, aFontFamily);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::SetFontFamily(const nsAString& aFontFamily)
|
||||||
|
{
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::GetValueText(nsAString& aValueText)
|
||||||
|
{
|
||||||
|
FeatureValuesToString(mFeatureValues, aValueText);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsCSSFontFeatureValuesRule::SetValueText(const nsAString& aValueText)
|
||||||
|
{
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MakeFamilyArray {
|
||||||
|
MakeFamilyArray(nsTArray<nsString>& aFamilyArray)
|
||||||
|
: familyArray(aFamilyArray), hasGeneric(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
AddFamily(const nsString& aFamily, bool aGeneric, void* aData)
|
||||||
|
{
|
||||||
|
MakeFamilyArray *familyArr = reinterpret_cast<MakeFamilyArray*> (aData);
|
||||||
|
if (!aGeneric && !aFamily.IsEmpty()) {
|
||||||
|
familyArr->familyArray.AppendElement(aFamily);
|
||||||
|
}
|
||||||
|
if (aGeneric) {
|
||||||
|
familyArr->hasGeneric = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<nsString>& familyArray;
|
||||||
|
bool hasGeneric;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
nsCSSFontFeatureValuesRule::SetFamilyList(const nsAString& aFamilyList,
|
||||||
|
bool& aContainsGeneric)
|
||||||
|
{
|
||||||
|
nsFont font(aFamilyList, 0, 0, 0, 0, 0, 0);
|
||||||
|
MakeFamilyArray families(mFamilyList);
|
||||||
|
font.EnumerateFamilies(MakeFamilyArray::AddFamily, (void*) &families);
|
||||||
|
aContainsGeneric = families.hasGeneric;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsCSSFontFeatureValuesRule::AddValueList(int32_t aVariantAlternate,
|
||||||
|
nsTArray<gfxFontFeatureValueSet::ValueList>& aValueList)
|
||||||
|
{
|
||||||
|
uint32_t i, len = mFeatureValues.Length();
|
||||||
|
bool foundAlternate = false;
|
||||||
|
|
||||||
|
// add to an existing list for a given property value
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
gfxFontFeatureValueSet::FeatureValues& f = mFeatureValues.ElementAt(i);
|
||||||
|
|
||||||
|
if (f.alternate == uint32_t(aVariantAlternate)) {
|
||||||
|
f.valuelist.AppendElements(aValueList);
|
||||||
|
foundAlternate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new list for a given property value
|
||||||
|
if (!foundAlternate) {
|
||||||
|
gfxFontFeatureValueSet::FeatureValues &f = *mFeatureValues.AppendElement();
|
||||||
|
f.alternate = aVariantAlternate;
|
||||||
|
f.valuelist.AppendElements(aValueList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
nsCSSFontFeatureValuesRule::SizeOfIncludingThis(
|
||||||
|
nsMallocSizeOfFun aMallocSizeOf) const
|
||||||
|
{
|
||||||
|
return aMallocSizeOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// nsCSSKeyframeStyleDeclaration
|
// nsCSSKeyframeStyleDeclaration
|
||||||
//
|
//
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "nsIDOMCSSConditionRule.h"
|
#include "nsIDOMCSSConditionRule.h"
|
||||||
#include "nsIDOMCSSFontFaceRule.h"
|
#include "nsIDOMCSSFontFaceRule.h"
|
||||||
|
#include "nsIDOMCSSFontFeatureValuesRule.h"
|
||||||
#include "nsIDOMCSSGroupingRule.h"
|
#include "nsIDOMCSSGroupingRule.h"
|
||||||
#include "nsIDOMCSSMediaRule.h"
|
#include "nsIDOMCSSMediaRule.h"
|
||||||
#include "nsIDOMCSSMozDocumentRule.h"
|
#include "nsIDOMCSSMozDocumentRule.h"
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
#include "Declaration.h"
|
#include "Declaration.h"
|
||||||
#include "nsIDOMCSSPageRule.h"
|
#include "nsIDOMCSSPageRule.h"
|
||||||
#include "StyleRule.h"
|
#include "StyleRule.h"
|
||||||
|
#include "gfxFontFeatures.h"
|
||||||
|
|
||||||
class nsMediaList;
|
class nsMediaList;
|
||||||
|
|
||||||
|
@ -212,7 +214,7 @@ protected:
|
||||||
#include "nsCSSFontDescList.h"
|
#include "nsCSSFontDescList.h"
|
||||||
#undef CSS_FONT_DESC
|
#undef CSS_FONT_DESC
|
||||||
|
|
||||||
static nsCSSValue nsCSSFontFaceStyleDecl::* const Fields[];
|
static nsCSSValue nsCSSFontFaceStyleDecl::* const Fields[];
|
||||||
inline nsCSSFontFaceRule* ContainingRule();
|
inline nsCSSFontFaceRule* ContainingRule();
|
||||||
inline const nsCSSFontFaceRule* ContainingRule() const;
|
inline const nsCSSFontFaceRule* ContainingRule() const;
|
||||||
|
|
||||||
|
@ -264,7 +266,7 @@ protected:
|
||||||
nsCSSFontFaceStyleDecl mDecl;
|
nsCSSFontFaceStyleDecl mDecl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// nsFontFaceRuleContainer - used for associating sheet type with
|
// nsFontFaceRuleContainer - used for associating sheet type with
|
||||||
// specific @font-face rules
|
// specific @font-face rules
|
||||||
struct nsFontFaceRuleContainer {
|
struct nsFontFaceRuleContainer {
|
||||||
nsRefPtr<nsCSSFontFaceRule> mRule;
|
nsRefPtr<nsCSSFontFaceRule> mRule;
|
||||||
|
@ -285,6 +287,61 @@ nsCSSFontFaceStyleDecl::ContainingRule() const
|
||||||
(reinterpret_cast<const char*>(this) - offsetof(nsCSSFontFaceRule, mDecl));
|
(reinterpret_cast<const char*>(this) - offsetof(nsCSSFontFaceRule, mDecl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class nsCSSFontFeatureValuesRule MOZ_FINAL :
|
||||||
|
public mozilla::css::Rule,
|
||||||
|
public nsIDOMCSSFontFeatureValuesRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsCSSFontFeatureValuesRule() {}
|
||||||
|
|
||||||
|
nsCSSFontFeatureValuesRule(const nsCSSFontFeatureValuesRule& aCopy)
|
||||||
|
// copy everything except our reference count
|
||||||
|
: mozilla::css::Rule(aCopy),
|
||||||
|
mFamilyList(aCopy.mFamilyList),
|
||||||
|
mFeatureValues(aCopy.mFeatureValues) {}
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
// nsIStyleRule methods
|
||||||
|
#ifdef DEBUG
|
||||||
|
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Rule methods
|
||||||
|
DECL_STYLE_RULE_INHERIT
|
||||||
|
|
||||||
|
virtual int32_t GetType() const MOZ_OVERRIDE;
|
||||||
|
virtual already_AddRefed<mozilla::css::Rule> Clone() const MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
// nsIDOMCSSRule interface
|
||||||
|
NS_DECL_NSIDOMCSSRULE
|
||||||
|
|
||||||
|
// nsIDOMCSSFontFaceRule interface
|
||||||
|
NS_DECL_NSIDOMCSSFONTFEATUREVALUESRULE
|
||||||
|
|
||||||
|
const nsTArray<nsString>& GetFamilyList() { return mFamilyList; }
|
||||||
|
void SetFamilyList(const nsAString& aFamilyList, bool& aContainsGeneric);
|
||||||
|
|
||||||
|
void AddValueList(int32_t aVariantAlternate,
|
||||||
|
nsTArray<gfxFontFeatureValueSet::ValueList>& aValueList);
|
||||||
|
|
||||||
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>& GetFeatureValues()
|
||||||
|
{
|
||||||
|
return mFeatureValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
|
||||||
|
|
||||||
|
static bool PrefEnabled()
|
||||||
|
{
|
||||||
|
return mozilla::Preferences::GetBool("layout.css.font-features.enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsTArray<nsString> mFamilyList;
|
||||||
|
nsTArray<gfxFontFeatureValueSet::FeatureValues> mFeatureValues;
|
||||||
|
};
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace css {
|
namespace css {
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@ nsStyleSet::nsStyleSet()
|
||||||
mInShutdown(false),
|
mInShutdown(false),
|
||||||
mAuthorStyleDisabled(false),
|
mAuthorStyleDisabled(false),
|
||||||
mInReconstruct(false),
|
mInReconstruct(false),
|
||||||
|
mInitFontFeatureValuesLookup(true),
|
||||||
mDirty(0),
|
mDirty(0),
|
||||||
mUnusedRuleNodeCount(0)
|
mUnusedRuleNodeCount(0)
|
||||||
{
|
{
|
||||||
|
@ -1104,7 +1105,7 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
|
||||||
|
|
||||||
if (mRuleProcessors[ePresHintSheet])
|
if (mRuleProcessors[ePresHintSheet])
|
||||||
(*aFunc)(mRuleProcessors[ePresHintSheet], aData);
|
(*aFunc)(mRuleProcessors[ePresHintSheet], aData);
|
||||||
|
|
||||||
bool cutOffInheritance = false;
|
bool cutOffInheritance = false;
|
||||||
if (mBindingManager) {
|
if (mBindingManager) {
|
||||||
// We can supply additional document-level sheets that should be walked.
|
// We can supply additional document-level sheets that should be walked.
|
||||||
|
@ -1540,6 +1541,59 @@ nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsStyleSet::AppendFontFeatureValuesRules(nsPresContext* aPresContext,
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
|
||||||
|
{
|
||||||
|
NS_ENSURE_FALSE(mInShutdown, false);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
|
||||||
|
nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
|
||||||
|
(mRuleProcessors[gCSSSheetTypes[i]].get());
|
||||||
|
if (ruleProc &&
|
||||||
|
!ruleProc->AppendFontFeatureValuesRules(aPresContext, aArray))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<gfxFontFeatureValueSet>
|
||||||
|
nsStyleSet::GetFontFeatureValuesLookup()
|
||||||
|
{
|
||||||
|
if (mInitFontFeatureValuesLookup) {
|
||||||
|
mInitFontFeatureValuesLookup = false;
|
||||||
|
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*> rules;
|
||||||
|
AppendFontFeatureValuesRules(PresContext(), rules);
|
||||||
|
|
||||||
|
mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
|
||||||
|
|
||||||
|
uint32_t i, numRules = rules.Length();
|
||||||
|
for (i = 0; i < numRules; i++) {
|
||||||
|
nsCSSFontFeatureValuesRule *rule = rules[i];
|
||||||
|
|
||||||
|
const nsTArray<nsString>& familyList = rule->GetFamilyList();
|
||||||
|
const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
|
||||||
|
featureValues = rule->GetFeatureValues();
|
||||||
|
|
||||||
|
// for each family
|
||||||
|
uint32_t f, numFam;
|
||||||
|
|
||||||
|
numFam = familyList.Length();
|
||||||
|
for (f = 0; f < numFam; f++) {
|
||||||
|
const nsString& family = familyList.ElementAt(f);
|
||||||
|
nsAutoString silly(family);
|
||||||
|
mFontFeatureValuesLookup->AddFontFeatureValues(silly, featureValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
|
||||||
|
return lookup.forget();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
|
nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
|
||||||
nsTArray<nsCSSPageRule*>& aArray)
|
nsTArray<nsCSSPageRule*>& aArray)
|
||||||
|
@ -1812,7 +1866,7 @@ struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
|
||||||
mHint(nsRestyleHint(0))
|
mHint(nsRestyleHint(0))
|
||||||
{}
|
{}
|
||||||
nsRestyleHint mHint;
|
nsRestyleHint mHint;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
|
SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
class nsCSSFontFaceRule;
|
class nsCSSFontFaceRule;
|
||||||
class nsCSSKeyframesRule;
|
class nsCSSKeyframesRule;
|
||||||
|
class nsCSSFontFeatureValuesRule;
|
||||||
class nsCSSPageRule;
|
class nsCSSPageRule;
|
||||||
class nsRuleWalker;
|
class nsRuleWalker;
|
||||||
struct ElementDependentRuleProcessorData;
|
struct ElementDependentRuleProcessorData;
|
||||||
|
@ -137,7 +138,7 @@ class nsStyleSet
|
||||||
nsCSSPseudoElements::Type aType,
|
nsCSSPseudoElements::Type aType,
|
||||||
nsStyleContext* aParentContext,
|
nsStyleContext* aParentContext,
|
||||||
TreeMatchContext& aTreeMatchContext);
|
TreeMatchContext& aTreeMatchContext);
|
||||||
|
|
||||||
// Get a style context for an anonymous box. aPseudoTag is the
|
// Get a style context for an anonymous box. aPseudoTag is the
|
||||||
// pseudo-tag to use and must be non-null.
|
// pseudo-tag to use and must be non-null.
|
||||||
already_AddRefed<nsStyleContext>
|
already_AddRefed<nsStyleContext>
|
||||||
|
@ -164,11 +165,13 @@ class nsStyleSet
|
||||||
bool AppendKeyframesRules(nsPresContext* aPresContext,
|
bool AppendKeyframesRules(nsPresContext* aPresContext,
|
||||||
nsTArray<nsCSSKeyframesRule*>& aArray);
|
nsTArray<nsCSSKeyframesRule*>& aArray);
|
||||||
|
|
||||||
already_AddRefed<gfxFontFeatureValueSet>
|
// Fetch object for looking up font feature values
|
||||||
GetFontFeatureValuesLookup()
|
already_AddRefed<gfxFontFeatureValueSet> GetFontFeatureValuesLookup();
|
||||||
{
|
|
||||||
return nullptr; // not implemented yet
|
// Append all the currently-active font feature values rules to aArray.
|
||||||
}
|
// Return true for success and false for failure.
|
||||||
|
bool AppendFontFeatureValuesRules(nsPresContext* aPresContext,
|
||||||
|
nsTArray<nsCSSFontFeatureValuesRule*>& aArray);
|
||||||
|
|
||||||
// Append all the currently-active page rules to aArray. Return
|
// Append all the currently-active page rules to aArray. Return
|
||||||
// true for success and false for failure.
|
// true for success and false for failure.
|
||||||
|
@ -412,6 +415,7 @@ class nsStyleSet
|
||||||
unsigned mInShutdown : 1;
|
unsigned mInShutdown : 1;
|
||||||
unsigned mAuthorStyleDisabled: 1;
|
unsigned mAuthorStyleDisabled: 1;
|
||||||
unsigned mInReconstruct : 1;
|
unsigned mInReconstruct : 1;
|
||||||
|
unsigned mInitFontFeatureValuesLookup : 1;
|
||||||
unsigned mDirty : 9; // one dirty bit is used per sheet type
|
unsigned mDirty : 9; // one dirty bit is used per sheet type
|
||||||
|
|
||||||
uint32_t mUnusedRuleNodeCount; // used to batch rule node GC
|
uint32_t mUnusedRuleNodeCount; // used to batch rule node GC
|
||||||
|
@ -429,6 +433,9 @@ class nsStyleSet
|
||||||
// BeginReconstruct and EndReconstruct, but in case of bugs that cause
|
// BeginReconstruct and EndReconstruct, but in case of bugs that cause
|
||||||
// style contexts to exist too long, may last longer.
|
// style contexts to exist too long, may last longer.
|
||||||
nsTArray<nsRuleNode*> mOldRuleTrees;
|
nsTArray<nsRuleNode*> mOldRuleTrees;
|
||||||
|
|
||||||
|
// whether font feature values lookup object needs initialization
|
||||||
|
nsRefPtr<gfxFontFeatureValueSet> mFontFeatureValuesLookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _IMPL_NS_LAYOUT
|
#ifdef _IMPL_NS_LAYOUT
|
||||||
|
|
|
@ -101,6 +101,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
|
||||||
test_dont_use_document_colors.html \
|
test_dont_use_document_colors.html \
|
||||||
test_font_face_parser.html \
|
test_font_face_parser.html \
|
||||||
test_font_family_parsing.html \
|
test_font_family_parsing.html \
|
||||||
|
test_font_feature_values_parsing.html \
|
||||||
test_garbage_at_end_of_declarations.html \
|
test_garbage_at_end_of_declarations.html \
|
||||||
test_group_insertRule.html \
|
test_group_insertRule.html \
|
||||||
test_html_attribute_computed_values.html \
|
test_html_attribute_computed_values.html \
|
||||||
|
|
|
@ -0,0 +1,356 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>@font-feature-values rule parsing tests</title>
|
||||||
|
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com">
|
||||||
|
<link rel="help" href="http://www.w3.org/TR/css3-fonts/#font-feature-values" />
|
||||||
|
<meta name="assert" content="tests that valid @font-feature-values rules parse and invalid ones don't" />
|
||||||
|
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=549861 -->
|
||||||
|
<script type="text/javascript" src="/resources/testharness.js"></script>
|
||||||
|
<script type="text/javascript" src="/resources/testharnessreport.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<pre id="display"></pre>
|
||||||
|
<style type="text/css" id="testbox"></style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var gPrefix = "";
|
||||||
|
var kFontFeatureValuesRuleType = 14;
|
||||||
|
|
||||||
|
function ruleName() { return "@" + gPrefix + "font-feature-values"; }
|
||||||
|
function makeRule(f, v) {
|
||||||
|
return ruleName() + " " + f + " { " + v + " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
function _()
|
||||||
|
{
|
||||||
|
var i, decl = [];
|
||||||
|
for (i = 0; i < arguments.length; i++) {
|
||||||
|
decl.push(arguments[i]);
|
||||||
|
}
|
||||||
|
return makeRule("bongo", decl.join(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: because of bugs in the way family names are serialized,
|
||||||
|
// 'serializationSame' only implies that the value definition block
|
||||||
|
// is the same (i.e. not including the family name list)
|
||||||
|
|
||||||
|
var testrules = [
|
||||||
|
|
||||||
|
/* basic syntax */
|
||||||
|
{ rule: ruleName() + ";", invalid: true },
|
||||||
|
{ rule: ruleName() + " bongo;", invalid: true },
|
||||||
|
{ rule: ruleName().replace("values", "value") + " {;}", invalid: true },
|
||||||
|
{ rule: ruleName().replace("feature", "features") + " {;}", invalid: true },
|
||||||
|
{ rule: makeRule("bongo", ""), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", ";"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", ",;"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", ";,"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", ",;,"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset;"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset,;"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset abc;"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { ;;abc }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc;; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc: }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc,: }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc:, }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc:,; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { a,b }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { a;b }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { a:;b: }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { a:,;b: }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { a:1,;b: }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc 1 2 3 }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc:, 1 2 3 }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc:; 1 2 3 }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc:; 1 2 3 }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc: 1 2 3a }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@styleset { abc: 1 2 3, def: 1; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@blah @styleset { abc: 1 2 3; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@blah } @styleset { abc: 1 2 3; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: makeRule("bongo", "@blah , @styleset { abc: 1 2 3; }"), serializationNoValueDefn: true },
|
||||||
|
{ rule: ruleName() + " bongo { @styleset { abc: 1 2 3; }", serialization: _("@styleset { abc: 1 2 3; }") },
|
||||||
|
{ rule: ruleName() + " bongo { @styleset { abc: 1 2 3 }", serialization: _("@styleset { abc: 1 2 3; }") },
|
||||||
|
{ rule: ruleName() + " bongo { @styleset { abc: 1 2 3;", serialization: _("@styleset { abc: 1 2 3; }") },
|
||||||
|
{ rule: ruleName() + " bongo { @styleset { abc: 1 2 3", serialization: _("@styleset { abc: 1 2 3; }") },
|
||||||
|
{ rule: _("@styleset { ok-1: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@annotation { ok-1: 3; }"), serializationSame: true },
|
||||||
|
{ rule: _("@stylistic { blah: 3; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("bongo", "\n@styleset\n { blah: 3; super-blah: 4 5;\n more-blah: 5 6 7;\n }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("bongo", "\n@styleset\n {\n blah:\n 3\n;\n super-blah:\n 4\n 5\n;\n more-blah:\n 5 6\n 7;\n }"), serializationSame: true },
|
||||||
|
|
||||||
|
/* limits on number of values */
|
||||||
|
{ rule: _("@stylistic { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { blah: 1 2 3 4; }"), serializationSame: true },
|
||||||
|
{ rule: _("@character-variant { blah: 1 2; }"), serializationSame: true },
|
||||||
|
{ rule: _("@swash { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@ornaments { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@annotation { blah: 1; }"), serializationSame: true },
|
||||||
|
|
||||||
|
/* values ignored when used */
|
||||||
|
{ rule: _("@styleset { blah: 0; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { blah: 120 124; }"), serializationSame: true },
|
||||||
|
{ rule: _("@character-variant { blah: 0; }"), serializationSame: true },
|
||||||
|
{ rule: _("@character-variant { blah: 111; }"), serializationSame: true },
|
||||||
|
{ rule: _("@character-variant { blah: 111 13; }"), serializationSame: true },
|
||||||
|
|
||||||
|
/* invalid value name */
|
||||||
|
{ rulesrc: ["styleset { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["stylistic { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["character-variant { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["swash { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["ornaments { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["annotation { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@bongo { blah: 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@bongo { blah: 1 2 3 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@bongo { blah: 1 2 3; burp: 1;;; }"], serializationNoValueDefn: true },
|
||||||
|
|
||||||
|
/* values */
|
||||||
|
{ rulesrc: ["@styleset { blah: -1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1 -1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1.5 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 15px }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: red }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: (1) }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah:(1) }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah:, 1 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: <1> }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1! }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1,, }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1 1 1 1; }"], serializationSame: true },
|
||||||
|
|
||||||
|
/* limits on number of values */
|
||||||
|
{ rulesrc: ["@stylistic { blah: 1 2 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@character-variant { blah: 1 2 3 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@swash { blah: 1 2 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@ornaments { blah: 1 2 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@annotation { blah: 1 2 }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { blah: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; }"], serializationSame: true },
|
||||||
|
|
||||||
|
/* family names */
|
||||||
|
{ rule: makeRule("bongo", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("\"bongo\"", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("'bongo'", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("\\62 ongo", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("bongo, super bongo, bongo the supreme", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("bongo,, super bongo", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
{ rule: makeRule("bongo,*", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
{ rule: makeRule("bongo, sans-serif", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
{ rule: makeRule("serif, sans-serif", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
{ rule: makeRule("'serif', 'sans-serif'", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("bongo, \"super bongo\", 'bongo the supreme'", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("毎日カレーを食べたい!", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: makeRule("毎日カレーを食べたい!, 納豆嫌い", "@styleset { blah: 1; }"), serializationSame: true },
|
||||||
|
|
||||||
|
{ rule: makeRule("bongo, \"super\" bongo, bongo the supreme", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
{ rule: makeRule("--bongo", "@styleset { blah: 1; }"), invalid: true },
|
||||||
|
|
||||||
|
/* ident tests */
|
||||||
|
{ rule: _("@styleset { blah: 1; blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { blah: 1; de-blah: 1; blah: 2; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { \\tra-la: 1; }"), serialization: _("@styleset { tra-la: 1; }") },
|
||||||
|
{ rule: _("@styleset { b\\lah: 1; }"), serialization: _("@styleset { blah: 1; }") },
|
||||||
|
{ rule: _("@styleset { \\62 lah: 1; }"), serialization: _("@styleset { blah: 1; }") },
|
||||||
|
{ rule: _("@styleset { \\:blah: 1; }"), serialization: _("@styleset { \\:blah: 1; }") },
|
||||||
|
{ rule: _("@styleset { \\;blah: 1; }"), serialization: _("@styleset { \\;blah: 1; }") },
|
||||||
|
{ rule: _("@styleset { complex\\20 blah: 1; }"), serialization: _("@styleset { complex\\ blah: 1; }") },
|
||||||
|
{ rule: _("@styleset { complex\\ blah: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { Håkon: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { Åквариум: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { \\1f449\\1f4a9\\1f448: 1; }"), serialization: _("@styleset { 👉💩👈: 1; }") },
|
||||||
|
{ rule: _("@styleset { 魅力: 1; }"), serializationSame: true },
|
||||||
|
{ rule: _("@styleset { 毎日カレーを食べたい!: 1; }"), serializationSame: true },
|
||||||
|
/* from http://en.wikipedia.org/wiki/Metal_umlaut */
|
||||||
|
{ rule: _("@styleset { TECHNICIÄNS\\ ÖF\\ SPÅCE\\ SHIP\\ EÅRTH\\ THIS\\ IS\\ YÖÜR\\ CÄPTÅIN\\ SPEÄKING\\ YÖÜR\\ ØÅPTÅIN\\ IS\\ DEA̋D: 1; }"), serializationSame: true },
|
||||||
|
|
||||||
|
{ rulesrc: ["@styleset { 123blah: 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { :123blah 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { :123blah: 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { ?123blah: 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { \"blah\": 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { complex blah: 1; }"], serializationNoValueDefn: true },
|
||||||
|
{ rulesrc: ["@styleset { complex\\ blah: 1; }"], serializationNoValueDefn: true }
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
// test that invalid value declarations don't affect the parsing of surrounding
|
||||||
|
// declarations. So before + invalid + after should match the serialization
|
||||||
|
// given in s.
|
||||||
|
|
||||||
|
var gSurroundingTests = [
|
||||||
|
// -- invalid, valid ==> valid
|
||||||
|
{ before: "", after: "@ornaments { whatchamacallit-1: 23; thingy-dingy: 3; }", s: _("@ornaments { whatchamacallit-1: 23; thingy-dingy: 3; }") },
|
||||||
|
|
||||||
|
// -- valid, invalid ==> valid
|
||||||
|
{ before: "@ornaments { whatchamacallit-1: 23; thingy-dingy: 7; }", after: "", s: _("@ornaments { whatchamacallit-1: 23; thingy-dingy: 7; }") },
|
||||||
|
|
||||||
|
// -- valid, invalid, valid ==> valid, valid
|
||||||
|
{ before: "@ornaments { whatchamacallit-1: 23; thingy-dingy: 3; }", after: "@character-variant { whatchamacallit-2: 23 4; }", s: _("@ornaments { whatchamacallit-1: 23; thingy-dingy: 3; } @character-variant { whatchamacallit-2: 23 4; }") },
|
||||||
|
|
||||||
|
// -- invalid, valid, invalid ==> valid
|
||||||
|
{ between: "@ornaments { whatchamacallit-1: 23; thingy-dingy: 4; }", s: _("@ornaments { whatchamacallit-1: 23; thingy-dingy: 4; }") }
|
||||||
|
];
|
||||||
|
|
||||||
|
/* strip out just values, along with empty value blocks (e.g. @swash { })*/
|
||||||
|
function valuesText(ruletext)
|
||||||
|
{
|
||||||
|
var t = ruletext.replace(/@[a-zA-Z0-9\-]+[ \n]*{[ \n]*}/g, "");
|
||||||
|
t = t.replace(/[ \n]+/g, " ");
|
||||||
|
t = t.replace(/^[^{]+{[ \n]*/, "");
|
||||||
|
t = t.replace(/[ \n]*}[^}]*$/, "");
|
||||||
|
t = t.replace(/[ \n]*;/g, ";");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testParse(rulesrc)
|
||||||
|
{
|
||||||
|
var sheet = document.styleSheets[1];
|
||||||
|
var rule = _.apply(this, rulesrc);
|
||||||
|
|
||||||
|
while(sheet.cssRules.length > 0)
|
||||||
|
sheet.deleteRule(0);
|
||||||
|
try {
|
||||||
|
sheet.insertRule(rule, 0);
|
||||||
|
} catch (e) {
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sheet.cssRules.length == 1 && sheet.cssRules[0].type == kFontFeatureValuesRuleType) {
|
||||||
|
return sheet.cssRules[0].cssText.replace(/[ \n]+/g, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOneRule(testrule) {
|
||||||
|
var sheet = document.styleSheets[1];
|
||||||
|
var rule;
|
||||||
|
|
||||||
|
if ("rulesrc" in testrule) {
|
||||||
|
rule = _.apply(this, testrule.rulesrc);
|
||||||
|
} else {
|
||||||
|
rule = testrule.rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseErr = false;
|
||||||
|
var expectedErr = false;
|
||||||
|
var invalid = false;
|
||||||
|
if ("invalid" in testrule && testrule.invalid) invalid = true;
|
||||||
|
|
||||||
|
while(sheet.cssRules.length > 0)
|
||||||
|
sheet.deleteRule(0);
|
||||||
|
try {
|
||||||
|
sheet.insertRule(rule, 0);
|
||||||
|
} catch (e) {
|
||||||
|
expectedErr = (e.name == "SyntaxError"
|
||||||
|
&& e instanceof DOMException
|
||||||
|
&& e.code == DOMException.SYNTAX_ERR
|
||||||
|
&& invalid);
|
||||||
|
parseErr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assert_true(!parseErr || expectedErr, "unexpected syntax error");
|
||||||
|
if (!parseErr) {
|
||||||
|
assert_equals(sheet.cssRules.length, 1, "bad rule count");
|
||||||
|
assert_equals(sheet.cssRules[0].type, kFontFeatureValuesRuleType, "bad rule type");
|
||||||
|
}
|
||||||
|
}, "basic parse tests - " + rule);
|
||||||
|
|
||||||
|
var sanitizedRule = rule.replace(/[ \n]+/g, " ");
|
||||||
|
if (parseErr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should result in one @font-feature-values rule constructed
|
||||||
|
|
||||||
|
// serialization matches expectation
|
||||||
|
// -- note: due to inconsistent font family serialization problems,
|
||||||
|
// only the serialization of the values is tested currently
|
||||||
|
|
||||||
|
var ruleValues = valuesText(rule);
|
||||||
|
var serialized = sheet.cssRules[0].cssText;
|
||||||
|
var serializedValues = valuesText(serialized);
|
||||||
|
var haveSerialization = true;
|
||||||
|
|
||||||
|
if (testrule.serializationSame) {
|
||||||
|
test(function() {
|
||||||
|
assert_equals(serializedValues, ruleValues, "canonical cssText serialization doesn't match");
|
||||||
|
}, "serialization check - " + rule);
|
||||||
|
} else if ("serialization" in testrule) {
|
||||||
|
var s = valuesText(testrule.serialization);
|
||||||
|
test(function() {
|
||||||
|
assert_equals(serializedValues, s, "non-canonical cssText serialization doesn't match - ");
|
||||||
|
}, "serialization check - " + rule);
|
||||||
|
} else if (testrule.serializationNoValueDefn) {
|
||||||
|
test(function() {
|
||||||
|
assert_equals(serializedValues, "", "cssText serialization should have no value defintions - ");
|
||||||
|
}, "no value definitions in serialization - " + rule);
|
||||||
|
|
||||||
|
haveSerialization = false;
|
||||||
|
|
||||||
|
if ("rulesrc" in testrule) {
|
||||||
|
test(function() {
|
||||||
|
var j, rulesrc = testrule.rulesrc;
|
||||||
|
|
||||||
|
// invalid value definitions shouldn't affect the parsing of valid
|
||||||
|
// definitions before or after an invalid one
|
||||||
|
for (var j = 0; j < gSurroundingTests.length; j++) {
|
||||||
|
var t = gSurroundingTests[j];
|
||||||
|
var srulesrc = [];
|
||||||
|
|
||||||
|
if ("between" in t) {
|
||||||
|
srulesrc = srulesrc.concat(rulesrc);
|
||||||
|
srulesrc = srulesrc.concat(t.between);
|
||||||
|
srulesrc = srulesrc.concat(rulesrc);
|
||||||
|
} else {
|
||||||
|
if (t.before != "")
|
||||||
|
srulesrc = srulesrc.concat(t.before);
|
||||||
|
srulesrc = srulesrc.concat(rulesrc);
|
||||||
|
if (t.after != "")
|
||||||
|
srulesrc = srulesrc.concat(t.after);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = testParse(srulesrc);
|
||||||
|
assert_equals(valuesText(result), valuesText(t.s), "invalid declarations should not affect valid ones - ");
|
||||||
|
}
|
||||||
|
}, "invalid declarations don't affect valid ones - " + rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if serialization non-empty, serialization should round-trip to itself
|
||||||
|
if (haveSerialization) {
|
||||||
|
var roundTripText = testParse([serializedValues]);
|
||||||
|
test(function() {
|
||||||
|
assert_equals(valuesText(roundTripText), serializedValues,
|
||||||
|
"serialization should round-trip to itself - ");
|
||||||
|
}, "serialization round-trip - " + rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFontFeatureValuesRuleParsing() {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < testrules.length; i++) {
|
||||||
|
var testrule = testrules[i];
|
||||||
|
var rule;
|
||||||
|
|
||||||
|
if ("rulesrc" in testrule) {
|
||||||
|
rule = _.apply(this, testrule.rulesrc);
|
||||||
|
} else {
|
||||||
|
rule = testrule.rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
testOneRule(testrule);
|
||||||
|
//test(function() { testOneRule(testrule); }, "parsing " + rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testFontFeatureValuesRuleParsing();
|
||||||
|
</script>
|
||||||
|
</body></html>
|
Загрузка…
Ссылка в новой задаче