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;
}
Exemple #2
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;
}
PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
{
    // We only support a small subset of the css-page spec.
    prelude.consumeWhitespace();
    AtomicString typeSelector;
    if (prelude.peek().type() == IdentToken)
        typeSelector = prelude.consume().value();

    AtomicString pseudo;
    if (prelude.peek().type() == ColonToken) {
        prelude.consume();
        if (prelude.peek().type() != IdentToken)
            return nullptr; // Parse error; expected ident token following colon in @page header
        pseudo = prelude.consume().value();
    }

    prelude.consumeWhitespace();
    if (!prelude.atEnd())
        return nullptr; // Parse error; extra tokens in @page header

    OwnPtr<CSSParserSelector> selector;
    if (!typeSelector.isNull() && pseudo.isNull()) {
        selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_defaultNamespace));
    } else {
        selector = CSSParserSelector::create();
        if (!pseudo.isNull()) {
            selector->setMatch(CSSSelector::PagePseudoClass);
            selector->setValue(pseudo.lower());
            if (selector->pseudoType() == CSSSelector::PseudoUnknown)
                return nullptr; // Parse error; unknown page pseudo-class
        }
        if (!typeSelector.isNull())
            selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_defaultNamespace));
    }

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

    selector->setForPage();

    RefPtrWillBeRawPtr<StyleRulePage> pageRule = StyleRulePage::create();
    Vector<OwnPtr<CSSParserSelector>> selectorVector;
    selectorVector.append(selector.release());
    pageRule->parserAdoptSelectorVector(selectorVector);

    consumeDeclarationList(block, StyleRule::Style);
    pageRule->setProperties(createStylePropertySet(m_parsedProperties, m_context.mode()));
    m_parsedProperties.clear();

    return pageRule.release();
}
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeClass(
    CSSParserTokenRange& range) {
  ASSERT(range.peek().type() == DelimiterToken);
  ASSERT(range.peek().delimiter() == '.');
  range.consume();
  if (range.peek().type() != IdentToken)
    return nullptr;
  std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create();
  selector->setMatch(CSSSelector::Class);
  AtomicString value = range.consume().value().toAtomicString();
  selector->setValue(value, isQuirksModeBehavior(m_context.matchMode()));
  return selector;
}
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
{
    ASSERT(range.peek().type() == AtKeywordToken);
    const CSSParserString& name = range.consume().value();
    const CSSParserToken* preludeStart = &range.peek();
    while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken)
        range.consumeComponentValue();

    CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());
    CSSAtRuleID id = cssAtRuleID(name);
    if (id != CSSAtRuleInvalid && m_context.useCounter())
        countAtRule(m_context.useCounter(), id);

    if (range.atEnd() || range.peek().type() == SemicolonToken) {
        range.consume();
        if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset)
            return consumeCharsetRule(prelude);
        if (allowedRules <= AllowImportRules && id == CSSAtRuleImport)
            return consumeImportRule(prelude);
        if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace)
            return consumeNamespaceRule(prelude);
        return nullptr; // Parse error, unrecognised at-rule without block
    }

    CSSParserTokenRange block = range.consumeBlock();
    if (allowedRules == KeyframeRules)
        return nullptr; // Parse error, no at-rules supported inside @keyframes
    if (allowedRules == NoRules)
        return nullptr; // Parse error, no at-rules supported inside declaration lists

    ASSERT(allowedRules <= RegularRules);

    switch (id) {
    case CSSAtRuleMedia:
        return consumeMediaRule(prelude, block);
    case CSSAtRuleSupports:
        return consumeSupportsRule(prelude, block);
    case CSSAtRuleViewport:
        return consumeViewportRule(prelude, block);
    case CSSAtRuleFontFace:
        return consumeFontFaceRule(prelude, block);
    case CSSAtRuleWebkitKeyframes:
        return consumeKeyframesRule(true, prelude, block);
    case CSSAtRuleKeyframes:
        return consumeKeyframesRule(false, prelude, block);
    case CSSAtRulePage:
        return consumePageRule(prelude, block);
    default:
        return nullptr; // Parse error, unrecognised at-rule with block
    }
}
Exemple #6
0
PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeClass(CSSParserTokenRange& range)
{
    ASSERT(range.peek().type() == DelimiterToken);
    ASSERT(range.peek().delimiter() == '.');
    range.consume();
    if (range.peek().type() != IdentToken)
        return nullptr;
    OwnPtr<CSSParserSelector> selector = CSSParserSelector::create();
    selector->setMatch(CSSSelector::Class);
    const AtomicString& value = range.consume().value();
    if (isQuirksModeBehavior(m_context.mode()))
        selector->setValue(value.lower());
    else
        selector->setValue(value);
    return selector.release();
}
bool SizesAttributeParser::parse(CSSParserTokenRange range)
{
    // Split on a comma token and parse the result tokens as (media-condition, length) pairs
    while (!range.atEnd()) {
        const CSSParserToken* mediaConditionStart = &range.peek();
        // The length is the last component value before the comma which isn't whitespace or a comment
        const CSSParserToken* lengthTokenStart = &range.peek();
        const CSSParserToken* lengthTokenEnd = &range.peek();
        while (!range.atEnd() && range.peek().type() != CommaToken) {
            lengthTokenStart = &range.peek();
            range.consumeComponentValue();
            lengthTokenEnd = &range.peek();
            range.consumeWhitespace();
        }
        range.consume();

        float length;
        if (!calculateLengthInPixels(range.makeSubRange(lengthTokenStart, lengthTokenEnd), length))
            continue;
        RefPtrWillBeRawPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(range.makeSubRange(mediaConditionStart, lengthTokenStart));
        if (!mediaCondition || !mediaConditionMatches(mediaCondition))
            continue;
        m_length = length;
        m_lengthWasSet = true;
        return true;
    }
    return false;
}
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());
}
    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;
    }
bool CSSVariableResolver::resolveFallback(CSSParserTokenRange range, Vector<CSSParserToken>& result)
{
    if (range.atEnd())
        return false;
    ASSERT(range.peek().type() == CommaToken);
    range.consume();
    return resolveTokenRange(range, result);
}
Exemple #11
0
bool CSSVariableData::resolveVariableFallback(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector<CSSParserToken>& result) const
{
    if (range.atEnd())
        return false;
    ASSERT(range.peek().type() == CommaToken);
    range.consume();
    return resolveTokenRange(customProperties, range, result);
}
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
{
    ASSERT(range.peek().type() == AtKeywordToken);
    const CSSParserString& name = range.consume().value();
    const CSSParserToken* preludeStart = &range.peek();
    while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken)
        range.consumeComponentValue();

    CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());

    if (range.atEnd() || range.peek().type() == SemicolonToken) {
        range.consume();
        if (allowedRules == AllowCharsetRules && name.equalIgnoringCase("charset"))
            return consumeCharsetRule(prelude);
        if (allowedRules <= AllowImportRules && name.equalIgnoringCase("import"))
            return consumeImportRule(prelude);
        if (allowedRules <= AllowNamespaceRules && name.equalIgnoringCase("namespace"))
            return consumeNamespaceRule(prelude);
        return nullptr; // Parse error, unrecognised at-rule without block
    }

    CSSParserTokenRange block = range.consumeBlock();
    if (allowedRules == KeyframeRules)
        return nullptr; // Parse error, no at-rules supported inside @keyframes
    if (allowedRules == NoRules)
        return nullptr; // Parse error, no at-rules supported inside declaration lists

    ASSERT(allowedRules <= RegularRules);

    if (name.equalIgnoringCase("media"))
        return consumeMediaRule(prelude, block);
    if (name.equalIgnoringCase("supports"))
        return consumeSupportsRule(prelude, block);
    if (name.equalIgnoringCase("viewport"))
        return consumeViewportRule(prelude, block);
    if (name.equalIgnoringCase("font-face"))
        return consumeFontFaceRule(prelude, block);
    if (name.equalIgnoringCase("-webkit-keyframes"))
        return consumeKeyframesRule(true, prelude, block);
    if (name.equalIgnoringCase("keyframes"))
        return consumeKeyframesRule(false, prelude, block);
    if (name.equalIgnoringCase("page"))
        return consumePageRule(prelude, block);
    return nullptr; // Parse error, unrecognised at-rule with block
}
Exemple #13
0
bool CSSVariableData::resolveTokenRange(const CustomPropertyValueMap& customProperties, CSSParserTokenRange range, Vector<CSSParserToken>& result) const
{
    bool success = true;
    while (!range.atEnd()) {
        if (range.peek().functionId() == CSSValueVar)
            success &= resolveVariableReference(customProperties, range.consumeBlock(), result);
        else
            result.append(range.consume());
    }
    return success;
}
Exemple #14
0
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeId(
    CSSParserTokenRange& range) {
  ASSERT(range.peek().type() == HashToken);
  if (range.peek().getHashTokenType() != HashTokenId)
    return nullptr;
  std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create();
  selector->setMatch(CSSSelector::Id);
  AtomicString value = range.consume().value().toAtomicString();
  selector->setValue(value, isQuirksModeBehavior(m_context.matchMode()));
  return selector;
}
Exemple #15
0
bool CSSSelectorParser::consumeName(CSSParserTokenRange& range,
                                    AtomicString& name,
                                    AtomicString& namespacePrefix) {
  name = nullAtom;
  namespacePrefix = nullAtom;

  const CSSParserToken& firstToken = range.peek();
  if (firstToken.type() == IdentToken) {
    name = firstToken.value().toAtomicString();
    range.consume();
  } else if (firstToken.type() == DelimiterToken &&
             firstToken.delimiter() == '*') {
    name = starAtom;
    range.consume();
  } else if (firstToken.type() == DelimiterToken &&
             firstToken.delimiter() == '|') {
    // This is an empty namespace, which'll get assigned this value below
    name = emptyAtom;
  } else {
    return false;
  }

  if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '|')
    return true;
  range.consume();

  namespacePrefix = name;
  const CSSParserToken& nameToken = range.consume();
  if (nameToken.type() == IdentToken) {
    name = nameToken.value().toAtomicString();
  } else if (nameToken.type() == DelimiterToken &&
             nameToken.delimiter() == '*') {
    name = starAtom;
  } else {
    name = nullAtom;
    namespacePrefix = nullAtom;
    return false;
  }

  return true;
}
Exemple #16
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;
}
bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType ruleListType, const T callback)
{
    AllowedRulesType allowedRules = RegularRules;
    switch (ruleListType) {
    case TopLevelRuleList:
        allowedRules = AllowCharsetRules;
        break;
    case RegularRuleList:
        allowedRules = RegularRules;
        break;
    case KeyframesRuleList:
        allowedRules = KeyframeRules;
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    bool seenRule = false;
    bool firstRuleValid = false;
    while (!range.atEnd()) {
        RefPtrWillBeRawPtr<StyleRuleBase> rule;
        switch (range.peek().type()) {
        case WhitespaceToken:
            range.consumeWhitespace();
            continue;
        case AtKeywordToken:
            rule = consumeAtRule(range, allowedRules);
            break;
        case CDOToken:
        case CDCToken:
            if (ruleListType == TopLevelRuleList) {
                range.consume();
                continue;
            }
            // fallthrough
        default:
            rule = consumeQualifiedRule(range, allowedRules);
            break;
        }
        if (!seenRule) {
            seenRule = true;
            firstRuleValid = rule;
        }
        if (rule) {
            allowedRules = computeNewAllowedRules(allowedRules, rule.get());
            callback(rule.release());
        }
    }

    return firstRuleValid;
}
Exemple #18
0
bool CSSSelectorParser::consumeName(CSSParserTokenRange& range, AtomicString& name, AtomicString& namespacePrefix, bool& hasNamespace)
{
    name = nullAtom;
    namespacePrefix = nullAtom;
    hasNamespace = false;

    const CSSParserToken& firstToken = range.peek();
    if (firstToken.type() == IdentToken) {
        name = firstToken.value();
        range.consume();
    } else if (firstToken.type() == DelimiterToken && firstToken.delimiter() == '*') {
        name = starAtom;
        range.consume();
    } else if (firstToken.type() == DelimiterToken && firstToken.delimiter() == '|') {
        // No namespace
    } else {
        return false;
    }

    if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '|')
        return true;
    range.consume();

    hasNamespace = true;
    namespacePrefix = name;
    const CSSParserToken& nameToken = range.consume();
    if (nameToken.type() == IdentToken) {
        name = nameToken.value();
    } else if (nameToken.type() == DelimiterToken && nameToken.delimiter() == '*') {
        name = starAtom;
    } else {
        name = nullAtom;
        namespacePrefix = nullAtom;
        return false;
    }

    return true;
}
Exemple #19
0
PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeId(CSSParserTokenRange& range)
{
    ASSERT(range.peek().type() == HashToken);
    if (range.peek().hashTokenType() != HashTokenId)
        return nullptr;
    OwnPtr<CSSParserSelector> selector = CSSParserSelector::create();
    selector->setMatch(CSSSelector::Id);
    const AtomicString& value = range.consume().value();
    if (isQuirksModeBehavior(m_context.mode()))
        selector->setValue(value.lower());
    else
        selector->setValue(value);
    return selector.release();
}
void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule::Type ruleType)
{
    ASSERT(m_parsedProperties.isEmpty());

    bool useObserver = m_observerWrapper && ruleType == StyleRule::Style;
    if (useObserver) {
        m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(range));
        m_observerWrapper->skipCommentsBefore(range, true);
    }

    while (!range.atEnd()) {
        switch (range.peek().type()) {
        case WhitespaceToken:
        case SemicolonToken:
            range.consume();
            break;
        case IdentToken: {
            const CSSParserToken* declarationStart = &range.peek();

            if (useObserver)
                m_observerWrapper->yieldCommentsBefore(range);

            while (!range.atEnd() && range.peek().type() != SemicolonToken)
                range.consumeComponentValue();

            consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), ruleType);

            if (useObserver)
                m_observerWrapper->skipCommentsBefore(range, false);
            break;
        }
        case AtKeywordToken: {
            RefPtrWillBeRawPtr<StyleRuleBase> rule = consumeAtRule(range, NoRules);
            ASSERT_UNUSED(rule, !rule);
            break;
        }
        default: // Parse error, unexpected token in declaration list
            while (!range.atEnd() && range.peek().type() != SemicolonToken)
                range.consumeComponentValue();
            break;
        }
    }

    // Yield remaining comments
    if (useObserver) {
        m_observerWrapper->yieldCommentsBefore(range);
        m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(range));
    }
}
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 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);
}
// The state machine loop
PassRefPtrWillBeRawPtr<MediaQuerySet> MediaQueryParser::parseImpl(CSSParserTokenRange range)
{
    while (!range.atEnd())
        processToken(range.consume());

    // FIXME: Can we get rid of this special case?
    if (m_parserType == MediaQuerySetParser)
        processToken(CSSParserToken(EOFToken));

    if (m_state != ReadAnd && m_state != ReadRestrictor && m_state != Done && m_state != ReadMediaNot)
        m_querySet->addMediaQuery(MediaQuery::createNotAll());
    else if (m_mediaQueryData.currentMediaQueryChanged())
        m_querySet->addMediaQuery(m_mediaQueryData.takeMediaQuery());

    return m_querySet;
}
Exemple #24
0
void CSSVariableData::consumeAndUpdateTokens(const CSSParserTokenRange& range)
{
    StringBuilder stringBuilder;
    CSSParserTokenRange localRange = range;

    while (!localRange.atEnd()) {
        CSSParserToken token = localRange.consume();
        if (token.hasStringBacking())
            stringBuilder.append(token.value());
    }
    m_backingString = stringBuilder.toString();
    if (m_backingString.is8Bit())
        updateTokens<LChar>(range);
    else
        updateTokens<UChar>(range);
}
bool CSSVariableResolver::resolveTokenRange(CSSParserTokenRange range,
    Vector<CSSParserToken>& result)
{
    bool success = true;
    while (!range.atEnd()) {
        if (range.peek().functionId() == CSSValueVar) {
            success &= resolveVariableReference(range.consumeBlock(), result);
        } else if (range.peek().type() == AtKeywordToken && range.peek().valueEqualsIgnoringASCIICase("apply")
            && RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) {
            resolveApplyAtRule(range, result);
        } else {
            result.append(range.consume());
        }
    }
    return success;
}
TEST(CSSTokenizerBlockTest, Basic)
{
    BlockTestCase testCases[] = {
        {"(max-width: 800px()), (max-width: 800px)", 2, 0},
        {"(max-width: 900px(()), (max-width: 900px)", 3, 1},
        {"(max-width: 600px(())))), (max-width: 600px)", 3, 0},
        {"(max-width: 500px(((((((((())))), (max-width: 500px)", 11, 6},
        {"(max-width: 800px[]), (max-width: 800px)", 2, 0},
        {"(max-width: 900px[[]), (max-width: 900px)", 3, 2},
        {"(max-width: 600px[[]]]]), (max-width: 600px)", 3, 0},
        {"(max-width: 500px[[[[[[[[[[]]]]), (max-width: 500px)", 11, 7},
        {"(max-width: 800px{}), (max-width: 800px)", 2, 0},
        {"(max-width: 900px{{}), (max-width: 900px)", 3, 2},
        {"(max-width: 600px{{}}}}), (max-width: 600px)", 3, 0},
        {"(max-width: 500px{{{{{{{{{{}}}}), (max-width: 500px)", 11, 7},
        {"[(), (max-width: 400px)", 2, 1},
        {"[{}, (max-width: 500px)", 2, 1},
        {"[{]}], (max-width: 900px)", 2, 0},
        {"[{[]{}{{{}}}}], (max-width: 900px)", 5, 0},
        {"[{[}], (max-width: 900px)", 3, 2},
        {"[({)}], (max-width: 900px)", 3, 2},
        {"[]((), (max-width: 900px)", 2, 1},
        {"((), (max-width: 900px)", 2, 1},
        {"(foo(), (max-width: 900px)", 2, 1},
        {"[](()), (max-width: 900px)", 2, 0},
        {"all an[isdfs bla())(i())]icalc(i)(()), (max-width: 400px)", 3, 0},
        {"all an[isdfs bla())(]icalc(i)(()), (max-width: 500px)", 4, 2},
        {"all an[isdfs bla())(]icalc(i)(())), (max-width: 600px)", 4, 1},
        {"all an[isdfs bla())(]icalc(i)(()))], (max-width: 800px)", 4, 0},
        {0, 0, 0} // Do not remove the terminator line.
    };
    for (int i = 0; testCases[i].input; ++i) {
        CSSTokenizer::Scope scope(testCases[i].input);
        CSSParserTokenRange range = scope.tokenRange();
        MediaQueryBlockWatcher blockWatcher;

        unsigned maxLevel = 0;
        unsigned level = 0;
        while (!range.atEnd()) {
            blockWatcher.handleToken(range.consume());
            level = blockWatcher.blockLevel();
            maxLevel = std::max(level, maxLevel);
        }
        ASSERT_EQ(testCases[i].maxLevel, maxLevel);
        ASSERT_EQ(testCases[i].finalLevel, level);
    }
}
Exemple #27
0
// The state machine loop
RefPtr<MediaQuerySet> MediaQueryParser::parseInternal(CSSParserTokenRange range)
{
    while (!range.atEnd())
        processToken(range.consume());

    // FIXME: Can we get rid of this special case?
    if (m_parserType == MediaQuerySetParser)
        processToken(CSSParserToken(EOFToken));

    if (m_state != ReadAnd && m_state != ReadRestrictor && m_state != Done && m_state != ReadMediaNot) {
        MediaQuery query = MediaQuery(MediaQuery::Not, "all", Vector<MediaQueryExpression>());
        m_querySet->addMediaQuery(WTFMove(query));
    } else if (m_mediaQueryData.currentMediaQueryChanged())
        commitMediaQuery();

    return m_querySet;
}
Exemple #28
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;
}
bool classifyBlock(CSSParserTokenRange range, bool& hasReferences, bool isTopLevelBlock = true)
{
    while (!range.atEnd()) {
        if (range.peek().blockType() == CSSParserToken::BlockStart) {
            const CSSParserToken& token = range.peek();
            CSSParserTokenRange block = range.consumeBlock();
            if (token.functionId() == CSSValueVar) {
                if (!isValidVariableReference(block))
                    return false; // Bail if any references are invalid
                hasReferences = true;
                continue;
            }
            if (!classifyBlock(block, hasReferences, false))
                return false;
            continue;
        }

        ASSERT(range.peek().blockType() != CSSParserToken::BlockEnd);

        const CSSParserToken& token = range.consume();
        switch (token.type()) {
        case DelimiterToken: {
            if (token.delimiter() == '!' && isTopLevelBlock)
                return false;
            break;
        }
        case RightParenthesisToken:
        case RightBraceToken:
        case RightBracketToken:
        case BadStringToken:
        case BadUrlToken:
            return false;
        case SemicolonToken:
            if (isTopLevelBlock)
                return false;
            break;
        default:
            break;
        }
    }
    return true;
}
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
    }
}