Beispiel #1
0
CSSSelectorList CSSSelectorParser::consumeCompoundSelectorList(
    CSSParserTokenRange& range) {
  Vector<std::unique_ptr<CSSParserSelector>> selectorList;
  std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range);
  range.consumeWhitespace();
  if (!selector)
    return CSSSelectorList();
  selectorList.append(std::move(selector));
  while (!range.atEnd() && range.peek().type() == CommaToken) {
    range.consumeIncludingWhitespace();
    selector = consumeCompoundSelector(range);
    range.consumeWhitespace();
    if (!selector)
      return CSSSelectorList();
    selectorList.append(std::move(selector));
  }

  if (m_failedParsing)
    return CSSSelectorList();

  return CSSSelectorList::adoptSelectorVector(selectorList);
}
Beispiel #2
0
PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(CSSParserTokenRange& range)
{
    OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range);
    if (!selector)
        return nullptr;
    while (CSSSelector::Relation combinator = consumeCombinator(range)) {
        OwnPtr<CSSParserSelector> nextSelector = consumeCompoundSelector(range);
        if (!nextSelector)
            return combinator == CSSSelector::Descendant ? selector.release() : nullptr;
        CSSParserSelector* end = nextSelector.get();
        while (end->tagHistory())
            end = end->tagHistory();
        end->setRelation(combinator);
        if (selector->isContentPseudoElement())
            end->setRelationIsAffectedByPseudoContent();
        end->setTagHistory(selector.release());

        selector = nextSelector.release();
    }

    return selector.release();
}
Beispiel #3
0
void CSSSelectorParser::consumeCompoundSelectorList(CSSParserTokenRange& range, CSSSelectorList& output)
{
    Vector<OwnPtr<CSSParserSelector>> selectorList;
    OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range);
    range.consumeWhitespace();
    if (!selector)
        return;
    selectorList.append(selector.release());
    while (!range.atEnd() && range.peek().type() == CommaToken) {
        // FIXME: This differs from the spec grammar:
        // Spec: compound_selector S* [ COMMA S* compound_selector ]* S*
        // Impl: compound_selector S* [ COMMA S* compound_selector S* ]*
        range.consumeIncludingWhitespace();
        selector = consumeCompoundSelector(range);
        range.consumeWhitespace();
        if (!selector)
            return;
        selectorList.append(selector.release());
    }

    if (!m_failedParsing)
        output.adoptSelectorVector(selectorList);
}
Beispiel #4
0
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(
    CSSParserTokenRange& range) {
  std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range);
  if (!selector)
    return nullptr;

  unsigned previousCompoundFlags = 0;

  for (CSSParserSelector* simple = selector.get();
       simple && !previousCompoundFlags; simple = simple->tagHistory())
    previousCompoundFlags |= extractCompoundFlags(*simple, m_context.mode());

  while (CSSSelector::RelationType combinator = consumeCombinator(range)) {
    std::unique_ptr<CSSParserSelector> nextSelector =
        consumeCompoundSelector(range);
    if (!nextSelector)
      return combinator == CSSSelector::Descendant ? std::move(selector)
                                                   : nullptr;
    if (previousCompoundFlags & HasPseudoElementForRightmostCompound)
      return nullptr;
    CSSParserSelector* end = nextSelector.get();
    unsigned compoundFlags = extractCompoundFlags(*end, m_context.mode());
    while (end->tagHistory()) {
      end = end->tagHistory();
      compoundFlags |= extractCompoundFlags(*end, m_context.mode());
    }
    end->setRelation(combinator);
    if (previousCompoundFlags & HasContentPseudoElement)
      end->setRelationIsAffectedByPseudoContent();
    previousCompoundFlags = compoundFlags;
    end->setTagHistory(std::move(selector));

    selector = std::move(nextSelector);
  }

  return selector;
}
Beispiel #5
0
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumePseudo(
    CSSParserTokenRange& range) {
  ASSERT(range.peek().type() == ColonToken);
  range.consume();

  int colons = 1;
  if (range.peek().type() == ColonToken) {
    range.consume();
    colons++;
  }

  const CSSParserToken& token = range.peek();
  if (token.type() != IdentToken && token.type() != FunctionToken)
    return nullptr;

  std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create();
  selector->setMatch(colons == 1 ? CSSSelector::PseudoClass
                                 : CSSSelector::PseudoElement);

  AtomicString value = token.value().toAtomicString().lowerASCII();
  bool hasArguments = token.type() == FunctionToken;
  selector->updatePseudoType(value, hasArguments);

  if (selector->match() == CSSSelector::PseudoElement &&
      m_disallowPseudoElements)
    return nullptr;

  if (token.type() == IdentToken) {
    range.consume();
    if (selector->pseudoType() == CSSSelector::PseudoUnknown)
      return nullptr;
    return selector;
  }

  CSSParserTokenRange block = range.consumeBlock();
  block.consumeWhitespace();
  if (selector->pseudoType() == CSSSelector::PseudoUnknown)
    return nullptr;

  switch (selector->pseudoType()) {
    case CSSSelector::PseudoHost:
    case CSSSelector::PseudoHostContext:
    case CSSSelector::PseudoAny:
    case CSSSelector::PseudoCue: {
      DisallowPseudoElementsScope scope(this);

      std::unique_ptr<CSSSelectorList> selectorList =
          wrapUnique(new CSSSelectorList());
      *selectorList = consumeCompoundSelectorList(block);
      if (!selectorList->isValid() || !block.atEnd())
        return nullptr;
      selector->setSelectorList(std::move(selectorList));
      return selector;
    }
    case CSSSelector::PseudoNot: {
      std::unique_ptr<CSSParserSelector> innerSelector =
          consumeCompoundSelector(block);
      block.consumeWhitespace();
      if (!innerSelector || !innerSelector->isSimple() || !block.atEnd())
        return nullptr;
      Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
      selectorVector.append(std::move(innerSelector));
      selector->adoptSelectorVector(selectorVector);
      return selector;
    }
    case CSSSelector::PseudoSlotted: {
      DisallowPseudoElementsScope scope(this);

      std::unique_ptr<CSSParserSelector> innerSelector =
          consumeCompoundSelector(block);
      block.consumeWhitespace();
      if (!innerSelector || !block.atEnd() ||
          !RuntimeEnabledFeatures::shadowDOMV1Enabled())
        return nullptr;
      Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
      selectorVector.append(std::move(innerSelector));
      selector->adoptSelectorVector(selectorVector);
      return selector;
    }
    case CSSSelector::PseudoLang: {
      // FIXME: CSS Selectors Level 4 allows :lang(*-foo)
      const CSSParserToken& ident = block.consumeIncludingWhitespace();
      if (ident.type() != IdentToken || !block.atEnd())
        return nullptr;
      selector->setArgument(ident.value().toAtomicString());
      return selector;
    }
    case CSSSelector::PseudoNthChild:
    case CSSSelector::PseudoNthLastChild:
    case CSSSelector::PseudoNthOfType:
    case CSSSelector::PseudoNthLastOfType: {
      std::pair<int, int> ab;
      if (!consumeANPlusB(block, ab))
        return nullptr;
      block.consumeWhitespace();
      if (!block.atEnd())
        return nullptr;
      selector->setNth(ab.first, ab.second);
      return selector;
    }
    default:
      break;
  }

  return nullptr;
}
Beispiel #6
0
PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumePseudo(CSSParserTokenRange& range)
{
    ASSERT(range.peek().type() == ColonToken);
    range.consume();

    int colons = 1;
    if (range.peek().type() == ColonToken) {
        range.consume();
        colons++;
    }

    const CSSParserToken& token = range.peek();
    if (token.type() != IdentToken && token.type() != FunctionToken)
        return nullptr;

    OwnPtr<CSSParserSelector> selector = CSSParserSelector::create();
    selector->setMatch(colons == 1 ? CSSSelector::PseudoClass : CSSSelector::PseudoElement);
    selector->setValue(AtomicString(String(token.value()).lower()));

    if (token.type() == IdentToken) {
        range.consume();
        if (selector->pseudoType() == CSSSelector::PseudoUnknown)
            return nullptr;
        return selector.release();
    }

    CSSParserTokenRange block = range.consumeBlock();
    block.consumeWhitespace();

    if ((colons == 1
        && (token.valueEqualsIgnoringCase("host")
            || token.valueEqualsIgnoringCase("host-context")
            || token.valueEqualsIgnoringCase("-webkit-any")))
        || (colons == 2 && token.valueEqualsIgnoringCase("cue"))) {

        CSSSelectorList* selectorList = new CSSSelectorList();
        consumeCompoundSelectorList(block, *selectorList);
        if (!selectorList->isValid() || !block.atEnd())
            return nullptr;

        selector->setSelectorList(adoptPtr(selectorList));
        selector->pseudoType(); // FIXME: Do we need to force the pseudo type to be cached?
        ASSERT(selector->pseudoType() != CSSSelector::PseudoUnknown);
        return selector.release();
    }

    if (colons == 1 && token.valueEqualsIgnoringCase("not")) {
        OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(block);
        if (!innerSelector || !innerSelector->isSimple() || !block.atEnd())
            return nullptr;
        Vector<OwnPtr<CSSParserSelector>> selectorVector;
        selectorVector.append(innerSelector.release());
        selector->adoptSelectorVector(selectorVector);
        return selector.release();
    }

    if (colons == 1 && token.valueEqualsIgnoringCase("lang")) {
        // FIXME: CSS Selectors Level 4 allows :lang(*-foo)
        const CSSParserToken& ident = block.consumeIncludingWhitespace();
        if (ident.type() != IdentToken || !block.atEnd())
            return nullptr;
        selector->setArgument(ident.value());
        selector->pseudoType(); // FIXME: Do we need to force the pseudo type to be cached?
        ASSERT(selector->pseudoType() == CSSSelector::PseudoLang);
        return selector.release();
    }

    if (colons == 1
        && (token.valueEqualsIgnoringCase("nth-child")
            || token.valueEqualsIgnoringCase("nth-last-child")
            || token.valueEqualsIgnoringCase("nth-of-type")
            || token.valueEqualsIgnoringCase("nth-last-of-type"))) {
        std::pair<int, int> ab;
        if (!consumeANPlusB(block, ab))
            return nullptr;
        block.consumeWhitespace();
        if (!block.atEnd())
            return nullptr;
        // FIXME: We shouldn't serialize here and reparse in CSSSelector!
        // Serialization should be in CSSSelector::selectorText instead.
        int a = ab.first;
        int b = ab.second;
        String string;
        if (a == 0 && b == 0)
            string = "0";
        else if (a == 0)
            string = String::number(b);
        else if (b == 0)
            string = String::format("%dn", a);
        else if (ab.second < 0)
            string = String::format("%dn%d", a, b);
        else
            string = String::format("%dn+%d", a, b);
        selector->setArgument(AtomicString(string));
        selector->pseudoType(); // FIXME: Do we need to force the pseudo type to be cached?
        ASSERT(selector->pseudoType() != CSSSelector::PseudoUnknown);
        return selector.release();
    }

    return nullptr;
}