1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/css/cssom/CSSUnparsedValue.h"
#include "core/css/cssom/CSSStyleVariableReferenceValue.h"
#include "core/css/parser/CSSTokenizer.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
namespace {
class UnparsedValueIterationSource final
: public ValueIterable<StringOrCSSVariableReferenceValue>::IterationSource {
public:
explicit UnparsedValueIterationSource(CSSUnparsedValue* unparsedValue)
: m_unparsedValue(unparsedValue) {}
bool next(ScriptState*,
StringOrCSSVariableReferenceValue& value,
ExceptionState&) override {
if (m_index >= m_unparsedValue->size())
return false;
value = m_unparsedValue->fragmentAtIndex(m_index);
return true;
}
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->trace(m_unparsedValue);
ValueIterable<StringOrCSSVariableReferenceValue>::IterationSource::trace(
visitor);
}
private:
const Member<CSSUnparsedValue> m_unparsedValue;
};
StringView findVariableName(CSSParserTokenRange& range) {
range.consumeWhitespace();
return range.consume().value();
}
StringOrCSSVariableReferenceValue variableReferenceValue(
const StringView& variableName,
const HeapVector<StringOrCSSVariableReferenceValue>& fragments) {
CSSUnparsedValue* unparsedValue;
if (fragments.size() == 0)
unparsedValue = nullptr;
else
unparsedValue = CSSUnparsedValue::create(fragments);
CSSStyleVariableReferenceValue* variableReference =
CSSStyleVariableReferenceValue::create(variableName.toString(),
unparsedValue);
return StringOrCSSVariableReferenceValue::fromCSSVariableReferenceValue(
variableReference);
}
HeapVector<StringOrCSSVariableReferenceValue> parserTokenRangeToFragments(
CSSParserTokenRange range) {
HeapVector<StringOrCSSVariableReferenceValue> fragments;
StringBuilder builder;
while (!range.atEnd()) {
if (range.peek().functionId() == CSSValueVar) {
if (!builder.isEmpty()) {
fragments.push_back(
StringOrCSSVariableReferenceValue::fromString(builder.toString()));
builder.clear();
}
CSSParserTokenRange block = range.consumeBlock();
StringView variableName = findVariableName(block);
block.consumeWhitespace();
if (block.peek().type() == CSSParserTokenType::CommaToken)
block.consume();
fragments.push_back(variableReferenceValue(
variableName, parserTokenRangeToFragments(block)));
} else {
range.consume().serialize(builder);
}
}
if (!builder.isEmpty()) {
fragments.push_back(
StringOrCSSVariableReferenceValue::fromString(builder.toString()));
}
return fragments;
}
} // namespace
ValueIterable<StringOrCSSVariableReferenceValue>::IterationSource*
CSSUnparsedValue::startIteration(ScriptState*, ExceptionState&) {
return new UnparsedValueIterationSource(this);
}
CSSUnparsedValue* CSSUnparsedValue::fromCSSValue(
const CSSVariableReferenceValue& cssVariableReferenceValue) {
return CSSUnparsedValue::create(parserTokenRangeToFragments(
cssVariableReferenceValue.variableDataValue()->tokenRange()));
}
CSSValue* CSSUnparsedValue::toCSSValue() const {
StringBuilder tokens;
for (unsigned i = 0; i < m_fragments.size(); i++) {
if (i) {
tokens.append("/**/");
}
if (m_fragments[i].isString()) {
tokens.append(m_fragments[i].getAsString());
} else if (m_fragments[i].isCSSVariableReferenceValue()) {
tokens.append(
m_fragments[i].getAsCSSVariableReferenceValue()->variable());
} else {
NOTREACHED();
}
}
CSSTokenizer tokenizer(tokens.toString());
return CSSVariableReferenceValue::create(CSSVariableData::create(
tokenizer.tokenRange(), false /* isAnimationTainted */,
true /* needsVariableResolution */));
}
} // namespace blink
|