void CSSVariableResolver::resolveApplyAtRule(CSSParserTokenRange& range,
    Vector<CSSParserToken>& result)
{
    ASSERT(range.peek().type() == AtKeywordToken && range.peek().valueEqualsIgnoringASCIICase("apply"));
    range.consumeIncludingWhitespace();
    const CSSParserToken& variableName = range.consumeIncludingWhitespace();
    // TODO(timloh): Should we actually be consuming this?
    if (range.peek().type() == SemicolonToken)
        range.consume();

    CSSVariableData* variableData = valueForCustomProperty(variableName.value());
    if (!variableData)
        return; // Invalid custom property

    CSSParserTokenRange rule = variableData->tokenRange();
    rule.consumeWhitespace();
    if (rule.peek().type() != LeftBraceToken)
        return;
    CSSParserTokenRange ruleContents = rule.consumeBlock();
    rule.consumeWhitespace();
    if (!rule.atEnd())
        return;

    result.appendRange(ruleContents.begin(), ruleContents.end());
}
Beispiel #2
0
CSSSelector::RelationType CSSSelectorParser::consumeCombinator(
    CSSParserTokenRange& range) {
  CSSSelector::RelationType fallbackResult = CSSSelector::SubSelector;
  while (range.peek().type() == WhitespaceToken) {
    range.consume();
    fallbackResult = CSSSelector::Descendant;
  }

  if (range.peek().type() != DelimiterToken)
    return fallbackResult;

  UChar delimiter = range.peek().delimiter();

  if (delimiter == '+' || delimiter == '~' || delimiter == '>') {
    range.consumeIncludingWhitespace();
    if (delimiter == '+')
      return CSSSelector::DirectAdjacent;
    if (delimiter == '~')
      return CSSSelector::IndirectAdjacent;
    return CSSSelector::Child;
  }

  // Match /deep/
  if (delimiter != '/')
    return fallbackResult;
  range.consume();
  const CSSParserToken& ident = range.consume();
  if (ident.type() != IdentToken ||
      !equalIgnoringASCIICase(ident.value(), "deep"))
    m_failedParsing = true;
  const CSSParserToken& slash = range.consumeIncludingWhitespace();
  if (slash.type() != DelimiterToken || slash.delimiter() != '/')
    m_failedParsing = true;
  return CSSSelector::ShadowDeep;
}
PassRefPtrWillBeRawPtr<StyleRuleKeyframes> CSSParserImpl::consumeKeyframesRule(bool webkitPrefixed, CSSParserTokenRange prelude, CSSParserTokenRange block)
{
    prelude.consumeWhitespace();
    const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace();
    if (!prelude.atEnd())
        return nullptr; // Parse error; expected single non-whitespace token in @keyframes header

    String name;
    if (nameToken.type() == IdentToken) {
        name = nameToken.value();
    } else if (nameToken.type() == StringToken && webkitPrefixed) {
        if (m_context.useCounter())
            m_context.useCounter()->count(UseCounter::QuotedKeyframesRule);
        name = nameToken.value();
    } else {
        return nullptr; // Parse error; expected ident token in @keyframes header
    }

    if (m_observerWrapper) {
        unsigned endOffset = m_observerWrapper->endOffset(prelude);
        m_observerWrapper->observer().startRuleHeader(StyleRule::Keyframes, m_observerWrapper->startOffset(prelude));
        m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
        m_observerWrapper->observer().startRuleBody(endOffset);
        m_observerWrapper->observer().endRuleBody(endOffset);
    }

    RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframeRule = StyleRuleKeyframes::create();
    consumeRuleList(block, KeyframesRuleList, [keyframeRule](PassRefPtrWillBeRawPtr<StyleRuleBase> keyframe) {
        keyframeRule->parserAppendKeyframe(toStyleRuleKeyframe(keyframe.get()));
    });
    keyframeRule->setName(name);
    keyframeRule->setVendorPrefixed(webkitPrefixed);
    return keyframeRule.release();
}
    bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
    {
        if (checkDepthAndIndex(&depth, tokens) != OK)
            return false;

        if (!parseValueTerm(tokens, depth, result))
            return false;

        while (!tokens.atEnd()) {
            char operatorCharacter = operatorValue(tokens.peek());
            if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide)
                break;
            tokens.consumeIncludingWhitespace();

            Value rhs;
            if (!parseValueTerm(tokens, depth, &rhs))
                return false;

            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
            if (!result->value)
                return false;
        }

        return true;
    }
    bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
    {
        if (checkDepthAndIndex(&depth, tokens) != OK)
            return false;

        if (!parseValueMultiplicativeExpression(tokens, depth, result))
            return false;

        while (!tokens.atEnd()) {
            char operatorCharacter = operatorValue(tokens.peek());
            if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract)
                break;
            if ((&tokens.peek() - 1)->type() != WhitespaceToken)
                return false; // calc(1px+ 2px) is invalid
            tokens.consume();
            if (tokens.peek().type() != WhitespaceToken)
                return false; // calc(1px +2px) is invalid
            tokens.consumeIncludingWhitespace();

            Value rhs;
            if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
                return false;

            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
            if (!result->value)
                return false;
        }

        return true;
    }
Beispiel #6
0
bool CSSVariableData::checkVariablesForCyclesWithRange(CSSParserTokenRange range, CustomPropertyValueMap& customProperties, HashSet<AtomicString>& seenProperties, HashSet<AtomicString>& invalidProperties) const
{
    while (!range.atEnd()) {
        if (range.peek().functionId() == CSSValueVar) {
            CSSParserTokenRange block = range.consumeBlock();
            
            block.consumeWhitespace();
            ASSERT(block.peek().type() == IdentToken);
            AtomicString variableName = block.consumeIncludingWhitespace().value().toAtomicString();
            ASSERT(block.atEnd() || block.peek().type() == CommaToken);
            if (seenProperties.contains(variableName))
                return false;

            RefPtr<CSSCustomPropertyValue> value = customProperties.get(variableName);
            if (value && value->containsVariables() && !value->checkVariablesForCycles(variableName, customProperties, seenProperties, invalidProperties))
                return false;

            if (range.peek().type() == CommaToken) {
                // Fallback.
                range.consume();
                return checkVariablesForCyclesWithRange(block, customProperties, seenProperties, invalidProperties);
            }
        } else
            range.consume();
    }
    return true;
}
Beispiel #7
0
static bool parseHexColor(CSSParserTokenRange& range, RGBA32& result, bool acceptQuirkyColors)
{
    const CSSParserToken& token = range.peek();
    String color;
    if (acceptQuirkyColors) {
        if (token.type() == NumberToken || token.type() == DimensionToken) {
            if (token.numericValueType() != IntegerValueType
                || token.numericValue() < 0. || token.numericValue() >= 1000000.)
                return false;
            if (token.type() == NumberToken) // e.g. 112233
                color = String::format("%d", static_cast<int>(token.numericValue()));
            else // e.g. 0001FF
                color = String::number(static_cast<int>(token.numericValue())) + String(token.value());
            while (color.length() < 6)
                color = "0" + color;
        } else if (token.type() == IdentToken) { // e.g. FF0000
            unsigned length = token.value().length();
            if (length != 3 && length != 6)
                return false;
            color = token.value();
        }
    }
    if (token.type() == HashToken)
        color = token.value();
    if (!Color::parseHexColor(color, result))
        return false;
    range.consumeIncludingWhitespace();
    return true;
}
PassRefPtrWillBeRawPtr<StyleRuleCharset> CSSParserImpl::consumeCharsetRule(CSSParserTokenRange prelude)
{
    prelude.consumeWhitespace();
    const CSSParserToken& string = prelude.consumeIncludingWhitespace();
    if (string.type() != StringToken || !prelude.atEnd())
        return nullptr; // Parse error, expected a single string
    return StyleRuleCharset::create();
}
Beispiel #9
0
bool consumeCommaIncludingWhitespace(CSSParserTokenRange& range)
{
    CSSParserToken value = range.peek();
    if (value.type() != CommaToken)
        return false;
    range.consumeIncludingWhitespace();
    return true;
}
Beispiel #10
0
bool consumeSlashIncludingWhitespace(CSSParserTokenRange& range)
{
    CSSParserToken value = range.peek();
    if (value.type() != DelimiterToken || value.delimiter() != '/')
        return false;
    range.consumeIncludingWhitespace();
    return true;
}
// This may still consume tokens if it fails
static AtomicString consumeStringOrURI(CSSParserTokenRange& range)
{
    const CSSParserToken& token = range.peek();

    if (token.type() == StringToken || token.type() == UrlToken)
        return range.consumeIncludingWhitespace().value();

    if (token.type() != FunctionToken || !token.valueEqualsIgnoringCase("url"))
        return AtomicString();

    CSSParserTokenRange contents = range.consumeBlock();
    const CSSParserToken& uri = contents.consumeIncludingWhitespace();
    ASSERT(uri.type() == StringToken);
    if (!contents.atEnd())
        return AtomicString();
    return uri.value();
}
Beispiel #12
0
bool consumeNumberRaw(CSSParserTokenRange& range, double& result)
{
    if (range.peek().type() == NumberToken) {
        result = range.consumeIncludingWhitespace().numericValue();
        return true;
    }
    CalcParser calcParser(range, ValueRangeAll);
    return calcParser.consumeNumberRaw(result);
}
Beispiel #13
0
CSSSelector::AttributeMatchType CSSSelectorParser::consumeAttributeFlags(
    CSSParserTokenRange& range) {
  if (range.peek().type() != IdentToken)
    return CSSSelector::CaseSensitive;
  const CSSParserToken& flag = range.consumeIncludingWhitespace();
  if (equalIgnoringASCIICase(flag.value(), "i"))
    return CSSSelector::CaseInsensitive;
  m_failedParsing = true;
  return CSSSelector::CaseSensitive;
}
Beispiel #14
0
CSSSupportsParser::SupportsResult CSSSupportsParser::consumeCondition(
    CSSParserTokenRange range) {
  if (range.peek().type() == IdentToken)
    return consumeNegation(range);

  bool result;
  ClauseType clauseType = Unresolved;

  while (true) {
    SupportsResult nextResult = consumeConditionInParenthesis(range);
    if (nextResult == Invalid)
      return Invalid;
    bool nextSupported = nextResult;
    if (clauseType == Unresolved)
      result = nextSupported;
    else if (clauseType == Conjunction)
      result &= nextSupported;
    else
      result |= nextSupported;

    if (range.atEnd())
      break;
    if (range.consumeIncludingWhitespace().type() != WhitespaceToken)
      return Invalid;
    if (range.atEnd())
      break;

    const CSSParserToken& token = range.consume();
    if (token.type() != IdentToken)
      return Invalid;
    if (clauseType == Unresolved)
      clauseType = token.value().length() == 3 ? Conjunction : Disjunction;
    if ((clauseType == Conjunction &&
         !equalIgnoringASCIICase(token.value(), "and")) ||
        (clauseType == Disjunction &&
         !equalIgnoringASCIICase(token.value(), "or")))
      return Invalid;

    if (range.consumeIncludingWhitespace().type() != WhitespaceToken)
      return Invalid;
  }
  return result ? Supported : Unsupported;
}
Beispiel #15
0
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();
}
Beispiel #16
0
CSSSelector::AttributeMatchType CSSSelectorParser::consumeAttributeFlags(CSSParserTokenRange& range)
{
    if (range.peek().type() != IdentToken)
        return CSSSelector::CaseSensitive;
    const CSSParserToken& flag = range.consumeIncludingWhitespace();
    if (String(flag.value()) == "i") {
        if (RuntimeEnabledFeatures::cssAttributeCaseSensitivityEnabled() || isUASheetBehavior(m_context.mode()))
            return CSSSelector::CaseInsensitive;
    }
    m_failedParsing = true;
    return CSSSelector::CaseSensitive;
}
Beispiel #17
0
CSSSupportsParser::SupportsResult CSSSupportsParser::consumeNegation(
    CSSParserTokenRange range) {
  ASSERT(range.peek().type() == IdentToken);
  if (!equalIgnoringASCIICase(range.consume().value(), "not"))
    return Invalid;
  if (range.consumeIncludingWhitespace().type() != WhitespaceToken)
    return Invalid;
  SupportsResult result = consumeConditionInParenthesis(range);
  range.consumeWhitespace();
  if (!range.atEnd() || result == Invalid)
    return Invalid;
  return result ? Unsupported : Supported;
}
PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(CSSParserTokenRange prelude)
{
    prelude.consumeWhitespace();
    AtomicString namespacePrefix;
    if (prelude.peek().type() == IdentToken)
        namespacePrefix = prelude.consumeIncludingWhitespace().value();

    AtomicString uri(consumeStringOrURI(prelude));
    prelude.consumeWhitespace();
    if (uri.isNull() || !prelude.atEnd())
        return nullptr; // Parse error, expected string or URI

    return StyleRuleNamespace::create(namespacePrefix, uri);
}
static CSSValueID classifyVariableRange(CSSParserTokenRange range, bool& hasReferences)
{
    hasReferences = false;

    range.consumeWhitespace();
    if (range.peek().type() == IdentToken) {
        CSSValueID id = range.consumeIncludingWhitespace().id();
        if (range.atEnd() && (id == CSSValueInherit || id == CSSValueInitial || id == CSSValueUnset))
            return id;
    }

    if (classifyBlock(range, hasReferences))
        return CSSValueInternalVariableValue;
    return CSSValueInvalid;
}
    bool parseValue(CSSParserTokenRange& tokens, Value* result)
    {
        CSSParserToken token = tokens.consumeIncludingWhitespace();
        if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
            return false;

        CSSPrimitiveValue::UnitType type = token.unitType();
        if (unitCategory(type) == CalcOther)
            return false;

        result->value = CSSCalcPrimitiveValue::create(
            CSSPrimitiveValue::create(token.numericValue(), type), token.numericValueType() == IntegerValueType);

        return true;
    }
void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType)
{
    CSSParserTokenRange rangeCopy = range; // For inspector callbacks

    ASSERT(range.peek().type() == IdentToken);
    const CSSParserToken& token = range.consumeIncludingWhitespace();
    CSSPropertyID unresolvedProperty = token.parseAsUnresolvedCSSPropertyID();
    if (range.consume().type() != ColonToken)
        return; // Parse error

    bool important = false;
    const CSSParserToken* declarationValueEnd = range.end();
    const CSSParserToken* last = range.end() - 1;
    while (last->type() == WhitespaceToken)
        --last;
    if (last->type() == IdentToken && last->valueEqualsIgnoringCase("important")) {
        --last;
        while (last->type() == WhitespaceToken)
            --last;
        if (last->type() == DelimiterToken && last->delimiter() == '!') {
            important = true;
            declarationValueEnd = last;
        }
    }
    if (RuntimeEnabledFeatures::cssVariablesEnabled() && unresolvedProperty == CSSPropertyInvalid && CSSVariableParser::isValidVariableName(token)) {
        AtomicString variableName = token.value();
        consumeVariableDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), variableName, important);
        return;
    }

    if (important && (ruleType == StyleRule::FontFace || ruleType == StyleRule::Keyframes))
        return;

    if (m_observerWrapper && ruleType == StyleRule::Style) {
        size_t propertiesCount = m_parsedProperties.size();
        if (unresolvedProperty != CSSPropertyInvalid)
            consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType);
        m_observerWrapper->observer().observeProperty(
            m_observerWrapper->startOffset(rangeCopy), m_observerWrapper->endOffset(rangeCopy),
            important, m_parsedProperties.size() != propertiesCount);
        return;
    }

    if (unresolvedProperty == CSSPropertyInvalid)
        return;

    consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType);
}
bool CSSVariableResolver::resolveVariableReference(CSSParserTokenRange range, Vector<CSSParserToken>& result)
{
    range.consumeWhitespace();
    ASSERT(range.peek().type() == IdentToken);
    AtomicString variableName = range.consumeIncludingWhitespace().value();
    ASSERT(range.atEnd() || (range.peek().type() == CommaToken));

    CSSVariableData* variableData = valueForCustomProperty(variableName);
    if (!variableData)
        return resolveFallback(range, result);

    result.appendVector(variableData->tokens());
    Vector<CSSParserToken> trash;
    resolveFallback(range, trash);
    return true;
}
bool isValidVariableReference(CSSParserTokenRange range)
{
    range.consumeWhitespace();
    if (!CSSVariableParser::isValidVariableName(range.consumeIncludingWhitespace()))
        return false;
    if (range.atEnd())
        return true;

    if (range.consume().type() != CommaToken)
        return false;
    if (range.atEnd())
        return false;

    bool hasReferences = false;
    return classifyBlock(range, hasReferences);
}
Beispiel #24
0
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeAttribute(
    CSSParserTokenRange& range) {
  ASSERT(range.peek().type() == LeftBracketToken);
  CSSParserTokenRange block = range.consumeBlock();
  block.consumeWhitespace();

  AtomicString namespacePrefix;
  AtomicString attributeName;
  if (!consumeName(block, attributeName, namespacePrefix))
    return nullptr;
  block.consumeWhitespace();

  if (m_context.isHTMLDocument())
    attributeName = attributeName.lower();

  AtomicString namespaceURI = determineNamespace(namespacePrefix);
  if (namespaceURI.isNull())
    return nullptr;

  QualifiedName qualifiedName =
      namespacePrefix.isNull()
          ? QualifiedName(nullAtom, attributeName, nullAtom)
          : QualifiedName(namespacePrefix, attributeName, namespaceURI);

  std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create();

  if (block.atEnd()) {
    selector->setAttribute(qualifiedName, CSSSelector::CaseSensitive);
    selector->setMatch(CSSSelector::AttributeSet);
    return selector;
  }

  selector->setMatch(consumeAttributeMatch(block));

  const CSSParserToken& attributeValue = block.consumeIncludingWhitespace();
  if (attributeValue.type() != IdentToken &&
      attributeValue.type() != StringToken)
    return nullptr;
  selector->setValue(attributeValue.value().toAtomicString());
  selector->setAttribute(qualifiedName, consumeAttributeFlags(block));

  if (!block.atEnd())
    return nullptr;
  return selector;
}
Beispiel #25
0
void CSSSelectorParser::consumeComplexSelectorList(CSSParserTokenRange& range, CSSSelectorList& output)
{
    Vector<OwnPtr<CSSParserSelector>> selectorList;
    OwnPtr<CSSParserSelector> selector = consumeComplexSelector(range);
    if (!selector)
        return;
    selectorList.append(selector.release());
    while (!range.atEnd() && range.peek().type() == CommaToken) {
        range.consumeIncludingWhitespace();
        selector = consumeComplexSelector(range);
        if (!selector)
            return;
        selectorList.append(selector.release());
    }

    if (!m_failedParsing)
        output.adoptSelectorVector(selectorList);
}
static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRange selectors)
{
    // This is easier than hooking into the CSSSelectorParser
    selectors.consumeWhitespace();
    CSSParserTokenRange originalRange = selectors;
    wrapper.observer().startRuleHeader(StyleRule::Style, wrapper.startOffset(originalRange));

    while (!selectors.atEnd()) {
        const CSSParserToken* selectorStart = &selectors.peek();
        while (!selectors.atEnd() && selectors.peek().type() != CommaToken)
            selectors.consumeComponentValue();
        CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &selectors.peek());
        selectors.consumeIncludingWhitespace();

        wrapper.observer().observeSelector(wrapper.startOffset(selector), wrapper.endOffset(selector));
    }

    wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange));
}
Beispiel #27
0
CSSSelectorList CSSSelectorParser::consumeComplexSelectorList(
    CSSParserTokenRange& range) {
  Vector<std::unique_ptr<CSSParserSelector>> selectorList;
  std::unique_ptr<CSSParserSelector> selector = consumeComplexSelector(range);
  if (!selector)
    return CSSSelectorList();
  selectorList.append(std::move(selector));
  while (!range.atEnd() && range.peek().type() == CommaToken) {
    range.consumeIncludingWhitespace();
    selector = consumeComplexSelector(range);
    if (!selector)
      return CSSSelectorList();
    selectorList.append(std::move(selector));
  }

  if (m_failedParsing)
    return CSSSelectorList();

  return CSSSelectorList::adoptSelectorVector(selectorList);
}
PassOwnPtr<Vector<double>> CSSParserImpl::consumeKeyframeKeyList(CSSParserTokenRange range)
{
    OwnPtr<Vector<double>> result = adoptPtr(new Vector<double>);
    while (true) {
        range.consumeWhitespace();
        const CSSParserToken& token = range.consumeIncludingWhitespace();
        if (token.type() == PercentageToken && token.numericValue() >= 0 && token.numericValue() <= 100)
            result->append(token.numericValue() / 100);
        else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("from"))
            result->append(0);
        else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("to"))
            result->append(1);
        else
            return nullptr; // Parser error, invalid value in keyframe selector
        if (range.atEnd())
            return result.release();
        if (range.consume().type() != CommaToken)
            return nullptr; // Parser error
    }
}
void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType)
{
    CSSParserTokenRange rangeCopy = range; // For inspector callbacks

    ASSERT(range.peek().type() == IdentToken);
    CSSPropertyID unresolvedProperty = range.consumeIncludingWhitespace().parseAsUnresolvedCSSPropertyID();
    if (range.consume().type() != ColonToken)
        return; // Parse error

    // FIXME: We shouldn't allow !important in @keyframes or @font-face
    bool important = false;
    const CSSParserToken* declarationValueEnd = range.end();
    const CSSParserToken* last = range.end() - 1;
    while (last->type() == WhitespaceToken)
        --last;
    if (last->type() == IdentToken && last->valueEqualsIgnoringCase("important")) {
        --last;
        while (last->type() == WhitespaceToken)
            --last;
        if (last->type() == DelimiterToken && last->delimiter() == '!') {
            important = true;
            declarationValueEnd = last;
        }
    }

    if (m_observerWrapper && ruleType == StyleRule::Style) {
        size_t propertiesCount = m_parsedProperties.size();
        if (unresolvedProperty != CSSPropertyInvalid)
            consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType);
        m_observerWrapper->observer().startProperty(m_observerWrapper->startOffset(rangeCopy));
        m_observerWrapper->observer().endProperty(important,
            m_parsedProperties.size() != propertiesCount,
            m_observerWrapper->endOffset(rangeCopy), NoCSSError);
        return;
    }

    if (unresolvedProperty == CSSPropertyInvalid)
        return;

    consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType);
}
Beispiel #30
0
bool CSSVariableData::resolveVariableReference(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector<CSSParserToken>& result) const
{
    range.consumeWhitespace();
    ASSERT(range.peek().type() == IdentToken);
    AtomicString variableName = range.consumeIncludingWhitespace().value().toAtomicString();
    ASSERT(range.atEnd() || (range.peek().type() == CommaToken));
    
    RefPtr<CSSCustomPropertyValue> property = customProperties.get(variableName);
    if (!property || !property->value())
        return resolveVariableFallback(customProperties, range, result);
    
    if (property->containsVariables()) {
        // FIXME: Avoid doing this work more than once.
        RefPtr<CSSVariableData> resolvedData = property->value()->resolveVariableReferences(customProperties);
        if (!resolvedData)
            return false;
        result.appendVector(resolvedData->tokens());
    } else
        result.appendVector(property->value()->tokens());
    
    return true;
}