Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
}