diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 41093c8c61d5..734f1f90e54a 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -913,6 +913,8 @@ static nsDOMClassInfoData sClassInfoData[] = { NS_DEFINE_CLASSINFO_DATA(LockedFile, nsEventTargetSH, EVENTTARGET_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) #ifdef MOZ_TIME_MANAGER NS_DEFINE_CLASSINFO_DATA(MozTimeManager, nsDOMGenericSH, @@ -2304,6 +2306,10 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMLockedFile) DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule) + DOM_CLASSINFO_MAP_END + #ifdef MOZ_TIME_MANAGER DOM_CLASSINFO_MAP_BEGIN(MozTimeManager, nsIDOMMozTimeManager) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozTimeManager) diff --git a/dom/base/nsDOMClassInfoClasses.h b/dom/base/nsDOMClassInfoClasses.h index 8491b0873529..324927d79d7a 100644 --- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -237,6 +237,8 @@ DOMCI_CLASS(AsyncScrollEventDetail) DOMCI_CLASS(LockedFile) +DOMCI_CLASS(CSSFontFeatureValuesRule) + #ifdef MOZ_TIME_MANAGER DOMCI_CLASS(MozTimeManager) #endif diff --git a/dom/interfaces/base/domstubs.idl b/dom/interfaces/base/domstubs.idl index 9877a0bcd705..dc9fe948f4d2 100644 --- a/dom/interfaces/base/domstubs.idl +++ b/dom/interfaces/base/domstubs.idl @@ -69,6 +69,7 @@ interface nsIDOMCSSPrimitiveValue; interface nsIDOMCSSRule; interface nsIDOMCSSRuleList; interface nsIDOMMozCSSKeyframeRule; +interface nsIDOMCSSFontFeatureValuesRule; interface nsIDOMCSSStyleSheet; interface nsIDOMCSSStyleDeclaration; interface nsIDOMCounter; diff --git a/dom/interfaces/css/moz.build b/dom/interfaces/css/moz.build index dea142e01363..8a295ecdbbd3 100644 --- a/dom/interfaces/css/moz.build +++ b/dom/interfaces/css/moz.build @@ -8,6 +8,7 @@ XPIDL_SOURCES += [ 'nsIDOMCSSCharsetRule.idl', 'nsIDOMCSSConditionRule.idl', 'nsIDOMCSSFontFaceRule.idl', + 'nsIDOMCSSFontFeatureValuesRule.idl', 'nsIDOMCSSGroupingRule.idl', 'nsIDOMCSSImportRule.idl', 'nsIDOMCSSMediaRule.idl', diff --git a/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl new file mode 100644 index 000000000000..1347d5a1c386 --- /dev/null +++ b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.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 (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 +}; diff --git a/dom/interfaces/css/nsIDOMCSSRule.idl b/dom/interfaces/css/nsIDOMCSSRule.idl index d334e7463d9f..94c81fc73c4e 100644 --- a/dom/interfaces/css/nsIDOMCSSRule.idl +++ b/dom/interfaces/css/nsIDOMCSSRule.idl @@ -32,6 +32,7 @@ interface nsIDOMCSSRule : nsISupports const unsigned short MOZ_KEYFRAME_RULE = 8; const unsigned short NAMESPACE_RULE = 10; const unsigned short SUPPORTS_RULE = 12; + const unsigned short FONT_FEATURE_VALUES_RULE = 14; readonly attribute unsigned short type; attribute DOMString cssText; diff --git a/dom/locales/en-US/chrome/layout/css.properties b/dom/locales/en-US/chrome/layout/css.properties index a82d1aeb9a04..463acdae6818 100644 --- a/dom/locales/en-US/chrome/layout/css.properties +++ b/dom/locales/en-US/chrome/layout/css.properties @@ -115,6 +115,17 @@ PEMQExpectedFeatureValue=Found invalid value for media feature. PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'. PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'. 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'. PESupportsConditionStartEOF2='not', '(', or function PESupportsConditionInParensEOF=')' diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index bd75d363faba..3eee5df56bf0 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -492,6 +492,7 @@ var interfaceNamesInGlobalScope = "CloseEvent", "IDBCursorWithValue", "CSSFontFaceRule", + "CSSFontFeatureValuesRule", "XMLHttpRequestEventTarget", "CompositionEvent", "HTMLOutputElement", diff --git a/gfx/src/nsFont.cpp b/gfx/src/nsFont.cpp index db9f74bd83b5..408ad5d0259d 100644 --- a/gfx/src/nsFont.cpp +++ b/gfx/src/nsFont.cpp @@ -35,7 +35,7 @@ nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant, 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, nscoord aSize) : name(aName) diff --git a/gfx/src/nsFont.h b/gfx/src/nsFont.h index b54cb9e861bd..8491f962f764 100644 --- a/gfx/src/nsFont.h +++ b/gfx/src/nsFont.h @@ -113,7 +113,7 @@ struct NS_GFX nsFont { nscoord aSize); // 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, nscoord aSize); diff --git a/layout/style/Rule.h b/layout/style/Rule.h index 3ba96accd4f2..900040533727 100644 --- a/layout/style/Rule.h +++ b/layout/style/Rule.h @@ -65,7 +65,8 @@ public: KEYFRAME_RULE, KEYFRAMES_RULE, DOCUMENT_RULE, - SUPPORTS_RULE + SUPPORTS_RULE, + FONT_FEATURE_VALUES_RULE }; virtual int32_t GetType() const = 0; diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index a135281bcf2a..d9c362186af2 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -375,6 +375,9 @@ protected: void* aProcessData); bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData); + bool ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc, + void* aProcessData); + bool ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule *aRule); bool ParseFontDescriptor(nsCSSFontFaceRule* aRule); bool ParseFontDescriptorValue(nsCSSFontDesc aDescID, nsCSSValue& aValue); @@ -1635,6 +1638,11 @@ CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc, parseFunc = &CSSParserImpl::ParseFontFaceRule; 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")) { parseFunc = &CSSParserImpl::ParsePageRule; newSection = eCSSSection_General; @@ -2360,6 +2368,233 @@ CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule* aRule) return true; } +// @font-feature-values # { +// @ { +// : +; +// : +; +// ... +// } +// ... +// } + +bool +CSSParserImpl::ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc, + void* aData) +{ + nsRefPtr + 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 +// @ { [ : + ; ]* } +// 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 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 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 CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData) @@ -8012,7 +8247,7 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, int32_t& aVariantMask) // ... or just a value UngetToken(); // 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)) { return false; } diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index df4e0d1b0e96..6836bb845669 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -649,7 +649,7 @@ void RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo) } AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue); RULE_HASH_STAT_INCREMENT(mTagSelectors); - if (selector->mCasedTag && + if (selector->mCasedTag && selector->mCasedTag != selector->mLowercaseTag) { AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue); RULE_HASH_STAT_INCREMENT(mTagSelectors); @@ -978,6 +978,7 @@ struct RuleCascadeData { nsTArray mFontFaceRules; nsTArray mKeyframesRules; + nsTArray mFontFeatureValuesRules; nsTArray mPageRules; // Looks up or creates the appropriate list in |mAttributeSelectors|. @@ -1029,6 +1030,7 @@ RuleCascadeData::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf); n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf); + n += mFontFeatureValuesRules.SizeOfExcludingThis(aMallocSizeOf); n += mPageRules.SizeOfExcludingThis(aMallocSizeOf); return n; @@ -1437,11 +1439,11 @@ static bool AttrMatchesValue(const nsAttrSelector* aAttrSelector, : static_cast(ciComparator); switch (aAttrSelector->mFunction) { - case NS_ATTR_FUNC_EQUALS: + case NS_ATTR_FUNC_EQUALS: return aValue.Equals(aAttrSelector->mValue, comparator); - case NS_ATTR_FUNC_INCLUDES: + case NS_ATTR_FUNC_INCLUDES: return ValueIncludes(aValue, aAttrSelector->mValue, comparator); - case NS_ATTR_FUNC_DASHMATCH: + case NS_ATTR_FUNC_DASHMATCH: return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator); case NS_ATTR_FUNC_ENDSMATCH: return StringEndsWith(aValue, aAttrSelector->mValue, comparator); @@ -2749,6 +2751,21 @@ nsCSSRuleProcessor::AppendPageRules( return true; } +bool +nsCSSRuleProcessor::AppendFontFeatureValuesRules( + nsPresContext *aPresContext, + nsTArray& aArray) +{ + RuleCascadeData* cascade = GetRuleCascade(aPresContext); + + if (cascade) { + if (!aArray.AppendElements(cascade->mFontFeatureValuesRules)) + return false; + } + + return true; +} + nsresult nsCSSRuleProcessor::ClearRuleCascades() { @@ -3047,12 +3064,14 @@ struct CascadeEnumData { CascadeEnumData(nsPresContext* aPresContext, nsTArray& aFontFaceRules, nsTArray& aKeyframesRules, + nsTArray& aFontFeatureValuesRules, nsTArray& aPageRules, nsMediaQueryResultCacheKey& aKey, uint8_t aSheetType) : mPresContext(aPresContext), mFontFaceRules(aFontFaceRules), mKeyframesRules(aKeyframesRules), + mFontFeatureValuesRules(aFontFeatureValuesRules), mPageRules(aPageRules), mCacheKey(aKey), mSheetType(aSheetType) @@ -3076,6 +3095,7 @@ struct CascadeEnumData { nsPresContext* mPresContext; nsTArray& mFontFaceRules; nsTArray& mKeyframesRules; + nsTArray& mFontFeatureValuesRules; nsTArray& mPageRules; nsMediaQueryResultCacheKey& mCacheKey; PLArenaPool mArena; @@ -3093,7 +3113,9 @@ struct CascadeEnumData { * but kept in order per-weight, and * (2) add any @font-face rules, in order, into data->mFontFaceRules. * (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 CascadeRuleEnumFunc(css::Rule* aRule, void* aData) @@ -3146,6 +3168,13 @@ CascadeRuleEnumFunc(css::Rule* aRule, void* aData) return false; } } + else if (css::Rule::FONT_FEATURE_VALUES_RULE == type) { + nsCSSFontFeatureValuesRule *fontFeatureValuesRule = + static_cast(aRule); + if (!data->mFontFeatureValuesRules.AppendElement(fontFeatureValuesRule)) { + return false; + } + } else if (css::Rule::PAGE_RULE == type) { nsCSSPageRule* pageRule = static_cast(aRule); if (!data->mPageRules.AppendElement(pageRule)) { @@ -3252,6 +3281,7 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext) if (newCascade) { CascadeEnumData data(aPresContext, newCascade->mFontFaceRules, newCascade->mKeyframesRules, + newCascade->mFontFeatureValuesRules, newCascade->mPageRules, newCascade->mCacheKey, mSheetType); diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index 94809df3a193..11f00abf8704 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -128,6 +128,9 @@ public: bool AppendPageRules(nsPresContext* aPresContext, nsTArray& aArray); + bool AppendFontFeatureValuesRules(nsPresContext* aPresContext, + nsTArray& aArray); + /** * Returns the scope element for the scoped style sheets this rule * processor is for. If this is not a rule processor for scoped style diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp index a9d4d7094d37..c5efbc0af698 100644 --- a/layout/style/nsCSSRules.cpp +++ b/layout/style/nsCSSRules.cpp @@ -34,6 +34,7 @@ #include "nsDOMClassInfoID.h" #include "mozilla/dom/CSSStyleDeclarationBinding.h" #include "StyleRule.h" +#include "nsFont.h" using namespace mozilla; @@ -718,7 +719,7 @@ GroupRule::AppendRulesToCssText(nsAString& aCssText) } aCssText.AppendLiteral("}"); - + return NS_OK; } @@ -1910,6 +1911,255 @@ nsCSSFontFaceRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const } +// ----------------------------------- +// nsCSSFontFeatureValuesRule +// + +/* virtual */ already_AddRefed +nsCSSFontFeatureValuesRule::Clone() const +{ + nsRefPtr 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& 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& 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& aFamilyList, + const nsTArray& 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& aFamilyArray) + : familyArray(aFamilyArray), hasGeneric(false) + {} + + static bool + AddFamily(const nsString& aFamily, bool aGeneric, void* aData) + { + MakeFamilyArray *familyArr = reinterpret_cast (aData); + if (!aGeneric && !aFamily.IsEmpty()) { + familyArr->familyArray.AppendElement(aFamily); + } + if (aGeneric) { + familyArr->hasGeneric = true; + } + return true; + } + + nsTArray& 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& 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 // diff --git a/layout/style/nsCSSRules.h b/layout/style/nsCSSRules.h index 1a2865e84a03..56a1e034bb8d 100644 --- a/layout/style/nsCSSRules.h +++ b/layout/style/nsCSSRules.h @@ -15,6 +15,7 @@ #include "mozilla/Preferences.h" #include "nsIDOMCSSConditionRule.h" #include "nsIDOMCSSFontFaceRule.h" +#include "nsIDOMCSSFontFeatureValuesRule.h" #include "nsIDOMCSSGroupingRule.h" #include "nsIDOMCSSMediaRule.h" #include "nsIDOMCSSMozDocumentRule.h" @@ -31,6 +32,7 @@ #include "Declaration.h" #include "nsIDOMCSSPageRule.h" #include "StyleRule.h" +#include "gfxFontFeatures.h" class nsMediaList; @@ -212,7 +214,7 @@ protected: #include "nsCSSFontDescList.h" #undef CSS_FONT_DESC - static nsCSSValue nsCSSFontFaceStyleDecl::* const Fields[]; + static nsCSSValue nsCSSFontFaceStyleDecl::* const Fields[]; inline nsCSSFontFaceRule* ContainingRule(); inline const nsCSSFontFaceRule* ContainingRule() const; @@ -264,7 +266,7 @@ protected: nsCSSFontFaceStyleDecl mDecl; }; -// nsFontFaceRuleContainer - used for associating sheet type with +// nsFontFaceRuleContainer - used for associating sheet type with // specific @font-face rules struct nsFontFaceRuleContainer { nsRefPtr mRule; @@ -285,6 +287,61 @@ nsCSSFontFaceStyleDecl::ContainingRule() const (reinterpret_cast(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 Clone() const MOZ_OVERRIDE; + + // nsIDOMCSSRule interface + NS_DECL_NSIDOMCSSRULE + + // nsIDOMCSSFontFaceRule interface + NS_DECL_NSIDOMCSSFONTFEATUREVALUESRULE + + const nsTArray& GetFamilyList() { return mFamilyList; } + void SetFamilyList(const nsAString& aFamilyList, bool& aContainsGeneric); + + void AddValueList(int32_t aVariantAlternate, + nsTArray& aValueList); + + const nsTArray& GetFeatureValues() + { + return mFeatureValues; + } + + virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; + + static bool PrefEnabled() + { + return mozilla::Preferences::GetBool("layout.css.font-features.enabled"); + } + +protected: + nsTArray mFamilyList; + nsTArray mFeatureValues; +}; + namespace mozilla { namespace css { diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 089fcabbea50..7105db27e632 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -110,6 +110,7 @@ nsStyleSet::nsStyleSet() mInShutdown(false), mAuthorStyleDisabled(false), mInReconstruct(false), + mInitFontFeatureValuesLookup(true), mDirty(0), mUnusedRuleNodeCount(0) { @@ -1104,7 +1105,7 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc, if (mRuleProcessors[ePresHintSheet]) (*aFunc)(mRuleProcessors[ePresHintSheet], aData); - + bool cutOffInheritance = false; if (mBindingManager) { // We can supply additional document-level sheets that should be walked. @@ -1540,6 +1541,59 @@ nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext, return true; } +bool +nsStyleSet::AppendFontFeatureValuesRules(nsPresContext* aPresContext, + nsTArray& aArray) +{ + NS_ENSURE_FALSE(mInShutdown, false); + + for (uint32_t i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) { + nsCSSRuleProcessor *ruleProc = static_cast + (mRuleProcessors[gCSSSheetTypes[i]].get()); + if (ruleProc && + !ruleProc->AppendFontFeatureValuesRules(aPresContext, aArray)) + { + return false; + } + } + return true; +} + +already_AddRefed +nsStyleSet::GetFontFeatureValuesLookup() +{ + if (mInitFontFeatureValuesLookup) { + mInitFontFeatureValuesLookup = false; + + nsTArray 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& familyList = rule->GetFamilyList(); + const nsTArray& + 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 lookup = mFontFeatureValuesLookup; + return lookup.forget(); +} + bool nsStyleSet::AppendPageRules(nsPresContext* aPresContext, nsTArray& aArray) @@ -1812,7 +1866,7 @@ struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData { mHint(nsRestyleHint(0)) {} nsRestyleHint mHint; -}; +}; static bool SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData) diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 4f990c46d4b5..40e8c7d617d8 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -28,6 +28,7 @@ class nsIURI; class nsCSSFontFaceRule; class nsCSSKeyframesRule; +class nsCSSFontFeatureValuesRule; class nsCSSPageRule; class nsRuleWalker; struct ElementDependentRuleProcessorData; @@ -137,7 +138,7 @@ class nsStyleSet nsCSSPseudoElements::Type aType, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext); - + // Get a style context for an anonymous box. aPseudoTag is the // pseudo-tag to use and must be non-null. already_AddRefed @@ -164,11 +165,13 @@ class nsStyleSet bool AppendKeyframesRules(nsPresContext* aPresContext, nsTArray& aArray); - already_AddRefed - GetFontFeatureValuesLookup() - { - return nullptr; // not implemented yet - } + // Fetch object for looking up font feature values + already_AddRefed GetFontFeatureValuesLookup(); + + // Append all the currently-active font feature values rules to aArray. + // Return true for success and false for failure. + bool AppendFontFeatureValuesRules(nsPresContext* aPresContext, + nsTArray& aArray); // Append all the currently-active page rules to aArray. Return // true for success and false for failure. @@ -412,6 +415,7 @@ class nsStyleSet unsigned mInShutdown : 1; unsigned mAuthorStyleDisabled: 1; unsigned mInReconstruct : 1; + unsigned mInitFontFeatureValuesLookup : 1; unsigned mDirty : 9; // one dirty bit is used per sheet type 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 // style contexts to exist too long, may last longer. nsTArray mOldRuleTrees; + + // whether font feature values lookup object needs initialization + nsRefPtr mFontFeatureValuesLookup; }; #ifdef _IMPL_NS_LAYOUT diff --git a/layout/style/test/Makefile.in b/layout/style/test/Makefile.in index b5f76ee5712f..e760cab04745 100644 --- a/layout/style/test/Makefile.in +++ b/layout/style/test/Makefile.in @@ -101,6 +101,7 @@ MOCHITEST_FILES = test_acid3_test46.html \ test_dont_use_document_colors.html \ test_font_face_parser.html \ test_font_family_parsing.html \ + test_font_feature_values_parsing.html \ test_garbage_at_end_of_declarations.html \ test_group_insertRule.html \ test_html_attribute_computed_values.html \ diff --git a/layout/style/test/test_font_feature_values_parsing.html b/layout/style/test/test_font_feature_values_parsing.html new file mode 100644 index 000000000000..a5d4a6834062 --- /dev/null +++ b/layout/style/test/test_font_feature_values_parsing.html @@ -0,0 +1,356 @@ + + + + + @font-feature-values rule parsing tests + + + + + + + + + +
+

+
+
+
+