Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(462)

Unified Diff: Source/core/css/parser/CSSPropertyParser.cpp

Issue 1331233003: Move parseFontFaceDescriptor to CSSPropertyParser.cpp (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Cleanup consumeFontWeight and consumeUrl Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/css/parser/CSSPropertyParser.h ('k') | Source/core/css/parser/LegacyCSSPropertyParser.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/css/parser/CSSPropertyParser.cpp
diff --git a/Source/core/css/parser/CSSPropertyParser.cpp b/Source/core/css/parser/CSSPropertyParser.cpp
index 2e6c483da002877dc8980b5b0be85f790357171b..b03689723686ef719395a9b0e00aa86e68611ddf 100644
--- a/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/Source/core/css/parser/CSSPropertyParser.cpp
@@ -7,6 +7,9 @@
#include "core/StylePropertyShorthand.h"
#include "core/css/CSSCalculationValue.h"
+#include "core/css/CSSFontFaceSrcValue.h"
+#include "core/css/CSSFontFeatureValue.h"
+#include "core/css/CSSUnicodeRangeValue.h"
#include "core/css/CSSValuePool.h"
#include "core/css/parser/CSSParserFastPaths.h"
#include "core/css/parser/CSSParserValues.h"
@@ -91,6 +94,41 @@ static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeString(CSSParserTokenRan
return cssValuePool().createValue(range.consumeIncludingWhitespace().value(), CSSPrimitiveValue::UnitType::String);
}
+static String consumeUrl(CSSParserTokenRange& range)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.type() == UrlToken) {
+ range.consumeIncludingWhitespace();
+ return token.value();
+ }
+ if (token.functionId() == CSSValueUrl) {
+ CSSParserTokenRange urlRange = range;
+ CSSParserTokenRange urlArgs = urlRange.consumeBlock();
+ const CSSParserToken& next = urlArgs.consumeIncludingWhitespace();
+ if (next.type() == BadStringToken || !urlArgs.atEnd())
+ return String();
+ ASSERT(next.type() == StringToken);
+ range = urlRange;
+ range.consumeWhitespace();
+ return next.value();
+ }
+
+ return String();
+}
+
+static CSSParserTokenRange consumeFunction(CSSParserTokenRange& range)
+{
+ ASSERT(range.peek().type() == FunctionToken);
+ CSSParserTokenRange contens = range.consumeBlock();
Timothy Loh 2015/09/16 03:22:28 contens -> contents? :-)
+ range.consumeWhitespace();
+ return contens;
+}
+
+static inline bool isComma(const CSSParserToken& value)
+{
+ return value.type() == CommaToken;
+}
+
// Methods for consuming non-shorthand properties starts here.
static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& range)
{
@@ -142,6 +180,105 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& r
return values.release();
}
+static PassRefPtrWillBeRawPtr<CSSValue> consumeFontVariantLigatures(CSSParserTokenRange& range)
Timothy Loh 2015/09/16 03:22:28 Can we move the properties which are not @font-fac
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+ RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceSeparated();
+ bool sawCommonLigaturesValue = false;
+ bool sawDiscretionaryLigaturesValue = false;
+ bool sawHistoricalLigaturesValue = false;
+ bool sawContextualLigaturesValue = false;
+ do {
+ CSSValueID id = range.peek().id();
+ switch (id) {
+ case CSSValueNoCommonLigatures:
+ case CSSValueCommonLigatures:
+ if (sawCommonLigaturesValue)
+ return nullptr;
+ sawCommonLigaturesValue = true;
+ break;
+ case CSSValueNoDiscretionaryLigatures:
+ case CSSValueDiscretionaryLigatures:
+ if (sawDiscretionaryLigaturesValue)
+ return nullptr;
+ sawDiscretionaryLigaturesValue = true;
+ break;
+ case CSSValueNoHistoricalLigatures:
+ case CSSValueHistoricalLigatures:
+ if (sawHistoricalLigaturesValue)
+ return nullptr;
+ sawHistoricalLigaturesValue = true;
+ break;
+ case CSSValueNoContextual:
+ case CSSValueContextual:
+ if (sawContextualLigaturesValue)
+ return nullptr;
+ sawContextualLigaturesValue = true;
+ break;
+ default:
+ return nullptr;
+ }
+ ligatureValues->append(consumeIdent(range));
+ } while (!range.atEnd());
+
+ if (!ligatureValues->length())
Timothy Loh 2015/09/16 03:22:28 The list will never be empty here
+ return nullptr;
+
+ return ligatureValues.release();
+}
+
+static bool consumeFontFeatureTag(CSSParserTokenRange& range, CSSValueList* settings)
Timothy Loh 2015/09/16 03:22:28 should probably just return a CSSFontFeatureValue
+{
+ // Feature tag name consists of 4-letter characters.
+ static const unsigned tagNameLength = 4;
+
+ CSSParserToken token = range.peek();
Timothy Loh 2015/09/16 03:22:28 const CSSParserToken&. Also maybe easier if this i
+ // Feature tag name comes first
+ if (token.type() != StringToken)
+ return false;
+ if (token.value().length() != tagNameLength)
+ return false;
+ AtomicString tag = token.value();
+ for (unsigned i = 0; i < tagNameLength; ++i) {
+ // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
+ UChar character = tag[i];
+ if (character < 0x20 || character > 0x7E)
+ return false;
+ }
+
+ int tagValue = 1;
+ // Feature tag values could follow: <integer> | on | off
+ range.consumeIncludingWhitespace();
+ if (!range.atEnd()) {
Timothy Loh 2015/09/16 03:22:28 don't need this check, peek() will just return EOF
+ if (range.peek().type() == NumberToken && range.peek().numericValueType() == IntegerValueType && range.peek().numericValue() >= 0) {
+ tagValue = clampTo<int>(range.peek().numericValue());
Timothy Loh 2015/09/16 03:22:28 range.consumeIncludingWhitespace().numericValue()?
+ if (tagValue < 0)
+ return false;
Timothy Loh 2015/09/16 03:22:28 does this ever get hit?
+ range.consumeIncludingWhitespace();
+ } else if (range.peek().id() == CSSValueOn || range.peek().id() == CSSValueOff) {
+ tagValue = range.peek().id() == CSSValueOn;
Timothy Loh 2015/09/16 03:22:28 range.consumeIncludingWhitespace().id()
+ range.consumeIncludingWhitespace();
+ }
+ }
+ settings->append(CSSFontFeatureValue::create(tag, tagValue));
+ return true;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeFontFeatureSettings(CSSParserTokenRange& range)
Timothy Loh 2015/09/16 03:22:28 this one too, separate patch
+{
+ if (range.peek().id() == CSSValueNormal)
+ return consumeIdent(range);
+ RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
+ do {
+ if (!consumeFontFeatureTag(range, settings.get()))
+ return nullptr;
+ if (range.atEnd())
Timothy Loh 2015/09/16 03:22:28 I think just return the value outside the loop and
+ return settings.release();
+ } while (consumeCommaIncludingWhitespace(range));
+ return nullptr;
+}
+
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumePage(CSSParserTokenRange& range)
{
if (range.peek().id() == CSSValueAuto)
@@ -173,6 +310,52 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeWebkitHighlight(CSSParserTokenRan
return consumeString(range);
}
+// normal | small-caps | inherit
Timothy Loh 2015/09/16 03:22:28 Comment is wrong, let's just drop these (as well a
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::consumeFontVariant()
Timothy Loh 2015/09/16 03:22:28 static for consistency?
+{
+ RefPtrWillBeRawPtr<CSSValueList> values = nullptr;
Timothy Loh 2015/09/16 03:22:28 Can we rewrite this function so it isn't super com
+ bool expectComma = false;
+ while (!m_range.atEnd()) {
+ RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr;
+ if (!expectComma) {
+ expectComma = true;
+ if (m_range.peek().id() == CSSValueNormal || m_range.peek().id() == CSSValueSmallCaps) {
+ parsedValue = consumeIdent(m_range);
+ } else if (m_range.peek().id() == CSSValueAll && !values) {
+ // FIXME: CSSPropertyParser::parseFontVariant() implements
+ // the old css3 draft:
+ // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
+ // 'all' is only allowed in @font-face and with no other values. Make a value list to
+ // indicate that we are in the @font-face case.
+ values = CSSValueList::createCommaSeparated();
+ parsedValue = consumeIdent(m_range);
+ }
+ } else if (consumeCommaIncludingWhitespace(m_range)) {
+ expectComma = false;
+ continue;
+ }
+
+ if (!parsedValue)
+ return nullptr;
+
+ if (isComma(m_range.peek()))
+ values = CSSValueList::createCommaSeparated();
+
+ if (values)
+ values->append(parsedValue.release());
+ else
+ return parsedValue.release();
+ }
+
+ if (values && values->length()) {
+ if (m_ruleType != StyleRule::FontFace)
+ return nullptr;
+ return values.release();
+ }
+
+ return nullptr;
+}
+
PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID propId)
{
m_range.consumeWhitespace();
@@ -185,11 +368,246 @@ PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty
return consumeQuotes(m_range);
case CSSPropertyWebkitHighlight:
return consumeWebkitHighlight(m_range);
+ case CSSPropertyFontVariantLigatures:
+ return consumeFontVariantLigatures(m_range);
+ case CSSPropertyWebkitFontFeatureSettings:
+ return consumeFontFeatureSettings(m_range);
+ case CSSPropertyFontVariant:
+ return consumeFontVariant();
+ case CSSPropertyFontFamily:
+ // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
+ return consumeFontFamily();
default:
return nullptr;
}
}
+static PassRefPtrWillBeRawPtr<CSSValueList> consumeFontFaceUnicodeRange(CSSParserTokenRange& range)
+{
+ RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+
+ do {
+ const CSSParserToken& token = range.consumeIncludingWhitespace();
+ if (token.type() != UnicodeRangeToken)
+ return nullptr;
+
+ UChar32 start = token.unicodeRangeStart();
+ UChar32 end = token.unicodeRangeEnd();
+ if (start > end)
+ return nullptr;
+ values->append(CSSUnicodeRangeValue::create(start, end));
+ } while (consumeCommaIncludingWhitespace(range));
+
+ return values.release();
+}
+
+bool CSSPropertyParser::consumeFontFaceSrcURI(CSSValueList* valueList)
Timothy Loh 2015/09/16 03:22:28 return a CSSValue instead of updating a CSSValueLi
+{
+ String url = consumeUrl(m_range);
+ if (url.isNull())
+ return false;
+ RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create(completeURL(url), m_context.shouldCheckContentSecurityPolicy()));
+ uriValue->setReferrer(m_context.referrer());
+
+ if (m_range.peek().functionId() != CSSValueFormat) {
+ valueList->append(uriValue.release());
+ return true;
+ }
+
+ // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
Timothy Loh 2015/09/16 03:22:28 Should update the URL (https://drafts.csswg.org/cs
+ // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
+ CSSParserTokenRange args = consumeFunction(m_range);
+ if (args.peek().type() != StringToken && args.peek().type() != IdentToken)
+ return false;
+ uriValue->setFormat(args.consumeIncludingWhitespace().value());
Timothy Loh 2015/09/16 03:22:28 need to check for any tokens after the string?
+ valueList->append(uriValue.release());
+ return true;
+}
+
+bool CSSPropertyParser::consumeFontFaceSrcLocal(CSSValueList* valueList)
Timothy Loh 2015/09/16 03:22:28 return a CSSValue
+{
+ CSSParserTokenRange args = consumeFunction(m_range);
+ if (args.atEnd())
+ return false;
+
+ const CSSParserToken& arg = args.consumeIncludingWhitespace();
Timothy Loh 2015/09/16 03:22:28 This is just <family-name>, right? We should share
+ ContentSecurityPolicyDisposition shouldCheckContentSecurityPolicy = m_context.shouldCheckContentSecurityPolicy();
+ if (arg.type() == StringToken) {
+ if (!args.atEnd())
+ return false;
+ valueList->append(CSSFontFaceSrcValue::createLocal(arg.value(), shouldCheckContentSecurityPolicy));
+ } else if (arg.type() == IdentToken) {
+ StringBuilder builder;
+ builder.append(arg.value());
+ while (!args.atEnd()) {
+ CSSParserToken localValue = args.consumeIncludingWhitespace();
+ if (localValue.type() != IdentToken)
+ return false;
+ if (!builder.isEmpty())
+ builder.append(' ');
+ builder.append(localValue.value());
+ }
+ valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString(), shouldCheckContentSecurityPolicy));
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::consumeFontFaceSrc()
+{
+ RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated());
+
+ do {
+ const CSSParserToken& token = m_range.peek();
+ if (token.functionId() == CSSValueLocal) {
+ if (!consumeFontFaceSrcLocal(values.get()))
+ return nullptr;
+ } else if (!consumeFontFaceSrcURI(values.get())) {
+ return nullptr;
+ }
+
+ if (m_range.atEnd())
+ return values.release();
+ } while (consumeCommaIncludingWhitespace(m_range));
+ return nullptr;
+}
+
+static inline bool isCSSWideKeyword(const CSSParserToken& token)
+{
+ return token.id() == CSSValueInitial || token.id() == CSSValueInherit || token.id() == CSSValueUnset || token.id() == CSSValueDefault;
Timothy Loh 2015/09/16 03:22:28 I know id() has a cache but can we pull the value
+}
+
+PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::consumeFontFamily()
+{
+ RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
+ CSSParserToken token = m_range.consumeIncludingWhitespace();
+
+ FontFamilyValueBuilder familyBuilder(list.get());
+ bool inFamily = false;
+
+ while (token.type() != EOFToken) {
+ const CSSParserToken& nextToken = m_range.consumeIncludingWhitespace();
+ bool nextValBreaksFont = nextToken.type() == EOFToken || isComma(nextToken);
+ bool nextValIsFontName = ((nextToken.id() >= CSSValueSerif && nextToken.id() <= CSSValueWebkitBody)
+ || (nextToken.type() == StringToken || nextToken.type() == IdentToken));
+
+ if (isCSSWideKeyword(token) && !inFamily) {
+ if (nextValBreaksFont)
+ return nullptr;
+ if (nextValIsFontName)
+ token = nextToken;
+ continue;
+ }
+
+ if (token.id() >= CSSValueSerif && token.id() <= CSSValueWebkitBody) {
+ if (inFamily) {
+ familyBuilder.add(token.value());
+ } else if (nextValBreaksFont || !nextValIsFontName) {
+ list->append(cssValuePool().createIdentifierValue(token.id()));
+ } else {
+ familyBuilder.commit();
+ familyBuilder.add(token.value());
+ inFamily = true;
+ }
+ } else if (token.type() == StringToken) {
+ // Strings never share in a family name.
+ inFamily = false;
+ familyBuilder.commit();
+ list->append(cssValuePool().createFontFamilyValue(token.value()));
+ } else if (token.type() == IdentToken) {
+ if (inFamily) {
+ familyBuilder.add(token.value());
+ } else if (nextValBreaksFont || !nextValIsFontName) {
+ list->append(cssValuePool().createFontFamilyValue(token.value()));
+ } else {
+ familyBuilder.commit();
+ familyBuilder.add(token.value());
+ inFamily = true;
+ }
+ } else {
+ break;
+ }
+
+ if (nextToken.type() == EOFToken)
+ break;
+
+ if (nextValBreaksFont) {
+ token = m_range.consumeIncludingWhitespace();
+ familyBuilder.commit();
+ inFamily = false;
+ } else if (nextValIsFontName) {
+ token = nextToken;
+ } else {
+ break;
+ }
+ }
+ familyBuilder.commit();
+ if (!list->length() || (m_ruleType == StyleRule::FontFace && list->length() > 1))
+ list = nullptr;
+ return list.release();
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeFontWeight(CSSParserTokenRange& range)
+{
+ const CSSParserToken& token = range.peek();
+ if (token.id() >= CSSValueNormal && token.id() <= CSSValueLighter)
+ return consumeIdent(range);
+ if (token.type() != NumberToken)
Timothy Loh 2015/09/16 03:22:28 || token.numericValueType() != IntegerValueType?
+ return nullptr;
+ int weight = static_cast<int>(token.numericValue());
+ if ((weight % 100) || weight < 100 || weight > 900)
+ return nullptr;
+ range.consumeIncludingWhitespace();
+ return cssValuePool().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1));
+}
+
+bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
Timothy Loh 2015/09/16 03:22:28 I think we decided a while ago to split this into
+{
+ RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
+
+ m_range.consumeWhitespace();
+ switch (propId) {
+ case CSSPropertyFontFamily:
+ // <family-name>
+ // TODO(rwlbuis): check there is only one family-name
+ parsedValue = consumeFontFamily();
+ break;
+ case CSSPropertySrc: // This is a list of urls or local references.
+ parsedValue = consumeFontFaceSrc();
+ break;
+ case CSSPropertyUnicodeRange:
+ parsedValue = consumeFontFaceUnicodeRange(m_range);
+ break;
+ case CSSPropertyFontWeight: // normal | bold | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
+ parsedValue = consumeFontWeight(m_range);
+ break;
+ case CSSPropertyFontStretch:
+ case CSSPropertyFontStyle: {
+ CSSValueID id = m_range.consumeIncludingWhitespace().id();
+ if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id))
+ return false;
+ addProperty(propId, cssValuePool().createIdentifierValue(id), false);
Timothy Loh 2015/09/16 03:22:28 parsedValue = ?
+ return true;
+ }
+ case CSSPropertyFontVariant: // normal | small-caps | inherit
+ parsedValue = consumeFontVariant();
+ break;
+ case CSSPropertyWebkitFontFeatureSettings:
+ parsedValue = parseSingleValue(propId);
+ break;
+ default:
+ break;
+ }
+
+ if (!parsedValue || !m_range.atEnd())
+ return false;
+
+ addProperty(propId, parsedValue.release(), false);
+ return true;
+}
+
bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, bool important)
{
m_range.consumeWhitespace();
« no previous file with comments | « Source/core/css/parser/CSSPropertyParser.h ('k') | Source/core/css/parser/LegacyCSSPropertyParser.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698