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 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;
}
CSSVariableData* CSSVariableResolver::valueForCustomProperty(AtomicString name)
{
    if (m_variablesSeen.contains(name)) {
        m_cycleStartPoints.add(name);
        return nullptr;
    }

    if (!m_styleVariableData)
        return nullptr;
    CSSVariableData* variableData = m_styleVariableData->getVariable(name);
    if (!variableData)
        return nullptr;
    if (!variableData->needsVariableResolution())
        return variableData;
    RefPtr<CSSVariableData> newVariableData = resolveCustomProperty(name, *variableData);
    m_styleVariableData->setVariable(name, newVariableData);
    return newVariableData.get();
}
PassRefPtr<CSSVariableData> CSSVariableResolver::resolveCustomProperty(AtomicString name, const CSSVariableData& variableData)
{
    ASSERT(variableData.needsVariableResolution());

    Vector<CSSParserToken> tokens;
    m_variablesSeen.add(name);
    bool success = resolveTokenRange(variableData.tokens(), tokens);
    m_variablesSeen.remove(name);

    // The old variable data holds onto the backing string the new resolved CSSVariableData
    // relies on. Ensure it will live beyond us overwriting the RefPtr in StyleVariableData.
    ASSERT(variableData.refCount() > 1);

    if (!success || !m_cycleStartPoints.isEmpty()) {
        m_cycleStartPoints.remove(name);
        return nullptr;
    }
    return CSSVariableData::createResolved(tokens, variableData);
}
bool CSSVariableData::operator==(const CSSVariableData& other) const
{
    return tokens() == other.tokens();
}