Commit ee6e4b4c authored by alancutter's avatar alancutter Committed by Commit bot

Ensure string data is kept alive as long as there are CSSVariableData tokens pointing to it

This change is part of animating registered custom properties.
Animated CSSVariableData objects won't have the same
ownership guarantees as ones owned by CSSValues.

This change removes the assumption that the tokens spliced into a
CSSVariableData during var() resolution will have their backing strings
kept alive somewhere else and instead keeps all necessary string handles
alongside the tokens.

This patch introduces no changes in behaviour.

BUG=671904

Review-Url: https://codereview.chromium.org/2901213005
Cr-Commit-Position: refs/heads/master@{#474970}
parent fe4711c9
...@@ -22,21 +22,23 @@ StylePropertySet* CSSVariableData::PropertySet() { ...@@ -22,21 +22,23 @@ StylePropertySet* CSSVariableData::PropertySet() {
} }
template <typename CharacterType> template <typename CharacterType>
void CSSVariableData::UpdateTokens(const CSSParserTokenRange& range) { static void UpdateTokens(const CSSParserTokenRange& range,
const String& backing_string,
Vector<CSSParserToken>& result) {
const CharacterType* current_offset = const CharacterType* current_offset =
backing_string_.GetCharacters<CharacterType>(); backing_string.GetCharacters<CharacterType>();
for (const CSSParserToken& token : range) { for (const CSSParserToken& token : range) {
if (token.HasStringBacking()) { if (token.HasStringBacking()) {
unsigned length = token.Value().length(); unsigned length = token.Value().length();
StringView string(current_offset, length); StringView string(current_offset, length);
tokens_.push_back(token.CopyWithUpdatedString(string)); result.push_back(token.CopyWithUpdatedString(string));
current_offset += length; current_offset += length;
} else { } else {
tokens_.push_back(token); result.push_back(token);
} }
} }
DCHECK(current_offset == backing_string_.GetCharacters<CharacterType>() + DCHECK(current_offset == backing_string.GetCharacters<CharacterType>() +
backing_string_.length()); backing_string.length());
} }
bool CSSVariableData::operator==(const CSSVariableData& other) const { bool CSSVariableData::operator==(const CSSVariableData& other) const {
...@@ -44,6 +46,8 @@ bool CSSVariableData::operator==(const CSSVariableData& other) const { ...@@ -44,6 +46,8 @@ bool CSSVariableData::operator==(const CSSVariableData& other) const {
} }
void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) { void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) {
DCHECK_EQ(tokens_.size(), 0u);
DCHECK_EQ(backing_strings_.size(), 0u);
StringBuilder string_builder; StringBuilder string_builder;
CSSParserTokenRange local_range = range; CSSParserTokenRange local_range = range;
...@@ -52,11 +56,12 @@ void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) { ...@@ -52,11 +56,12 @@ void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) {
if (token.HasStringBacking()) if (token.HasStringBacking())
string_builder.Append(token.Value()); string_builder.Append(token.Value());
} }
backing_string_ = string_builder.ToString(); String backing_string = string_builder.ToString();
if (backing_string_.Is8Bit()) backing_strings_.push_back(backing_string);
UpdateTokens<LChar>(range); if (backing_string.Is8Bit())
UpdateTokens<LChar>(range, backing_string, tokens_);
else else
UpdateTokens<UChar>(range); UpdateTokens<UChar>(range, backing_string, tokens_);
} }
CSSVariableData::CSSVariableData(const CSSParserTokenRange& range, CSSVariableData::CSSVariableData(const CSSParserTokenRange& range,
......
...@@ -31,16 +31,16 @@ class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> { ...@@ -31,16 +31,16 @@ class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> {
static PassRefPtr<CSSVariableData> CreateResolved( static PassRefPtr<CSSVariableData> CreateResolved(
const Vector<CSSParserToken>& resolved_tokens, const Vector<CSSParserToken>& resolved_tokens,
const CSSVariableData& unresolved_data, Vector<String> backing_strings,
bool is_animation_tainted) { bool is_animation_tainted) {
return AdoptRef(new CSSVariableData(resolved_tokens, return AdoptRef(new CSSVariableData(
unresolved_data.backing_string_, resolved_tokens, std::move(backing_strings), is_animation_tainted));
is_animation_tainted));
} }
CSSParserTokenRange TokenRange() const { return tokens_; } CSSParserTokenRange TokenRange() const { return tokens_; }
const Vector<CSSParserToken>& Tokens() const { return tokens_; } const Vector<CSSParserToken>& Tokens() const { return tokens_; }
const Vector<String>& BackingStrings() const { return backing_strings_; }
bool operator==(const CSSVariableData& other) const; bool operator==(const CSSVariableData& other) const;
...@@ -57,25 +57,21 @@ class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> { ...@@ -57,25 +57,21 @@ class CORE_EXPORT CSSVariableData : public RefCounted<CSSVariableData> {
bool is_animation_tainted, bool is_animation_tainted,
bool needs_variable_resolution); bool needs_variable_resolution);
// We can safely copy the tokens (which have raw pointers to substrings)
// because StylePropertySets contain references to
// CSSCustomPropertyDeclarations, which point to the unresolved
// CSSVariableData values that own the backing strings this will potentially
// reference.
CSSVariableData(const Vector<CSSParserToken>& resolved_tokens, CSSVariableData(const Vector<CSSParserToken>& resolved_tokens,
String backing_string, Vector<String> backing_strings,
bool is_animation_tainted) bool is_animation_tainted)
: backing_string_(backing_string), : backing_strings_(std::move(backing_strings)),
tokens_(resolved_tokens), tokens_(resolved_tokens),
is_animation_tainted_(is_animation_tainted), is_animation_tainted_(is_animation_tainted),
needs_variable_resolution_(false), needs_variable_resolution_(false),
cached_property_set_(false) {} cached_property_set_(false) {}
void ConsumeAndUpdateTokens(const CSSParserTokenRange&); void ConsumeAndUpdateTokens(const CSSParserTokenRange&);
template <typename CharacterType>
void UpdateTokens(const CSSParserTokenRange&);
String backing_string_; // tokens_ may have raw pointers to string data, we store the String objects
// owning that data in backing_strings_ to keep it alive alongside the
// tokens_.
Vector<String> backing_strings_;
Vector<CSSParserToken> tokens_; Vector<CSSParserToken> tokens_;
const bool is_animation_tainted_; const bool is_animation_tainted_;
const bool needs_variable_resolution_; const bool needs_variable_resolution_;
......
...@@ -27,16 +27,18 @@ ...@@ -27,16 +27,18 @@
namespace blink { namespace blink {
bool CSSVariableResolver::ResolveFallback(CSSParserTokenRange range, bool CSSVariableResolver::ResolveFallback(
bool disallow_animation_tainted, CSSParserTokenRange range,
Vector<CSSParserToken>& result, bool disallow_animation_tainted,
bool& result_is_animation_tainted) { Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted) {
if (range.AtEnd()) if (range.AtEnd())
return false; return false;
DCHECK_EQ(range.Peek().GetType(), kCommaToken); DCHECK_EQ(range.Peek().GetType(), kCommaToken);
range.Consume(); range.Consume();
return ResolveTokenRange(range, disallow_animation_tainted, result, return ResolveTokenRange(range, disallow_animation_tainted, result,
result_is_animation_tainted); result_backing_strings, result_is_animation_tainted);
} }
CSSVariableData* CSSVariableResolver::ValueForCustomProperty( CSSVariableData* CSSVariableResolver::ValueForCustomProperty(
...@@ -96,22 +98,19 @@ PassRefPtr<CSSVariableData> CSSVariableResolver::ResolveCustomProperty( ...@@ -96,22 +98,19 @@ PassRefPtr<CSSVariableData> CSSVariableResolver::ResolveCustomProperty(
bool disallow_animation_tainted = false; bool disallow_animation_tainted = false;
bool is_animation_tainted = variable_data.IsAnimationTainted(); bool is_animation_tainted = variable_data.IsAnimationTainted();
Vector<CSSParserToken> tokens; Vector<CSSParserToken> tokens;
Vector<String> backing_strings;
backing_strings.AppendVector(variable_data.BackingStrings());
variables_seen_.insert(name); variables_seen_.insert(name);
bool success = bool success =
ResolveTokenRange(variable_data.Tokens(), disallow_animation_tainted, ResolveTokenRange(variable_data.Tokens(), disallow_animation_tainted,
tokens, is_animation_tainted); tokens, backing_strings, is_animation_tainted);
variables_seen_.erase(name); variables_seen_.erase(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 StyleInheritedVariables.
DCHECK_GT(variable_data.RefCount(), 1);
if (!success || !cycle_start_points_.IsEmpty()) { if (!success || !cycle_start_points_.IsEmpty()) {
cycle_start_points_.erase(name); cycle_start_points_.erase(name);
return nullptr; return nullptr;
} }
return CSSVariableData::CreateResolved(tokens, variable_data, return CSSVariableData::CreateResolved(tokens, std::move(backing_strings),
is_animation_tainted); is_animation_tainted);
} }
...@@ -119,6 +118,7 @@ bool CSSVariableResolver::ResolveVariableReference( ...@@ -119,6 +118,7 @@ bool CSSVariableResolver::ResolveVariableReference(
CSSParserTokenRange range, CSSParserTokenRange range,
bool disallow_animation_tainted, bool disallow_animation_tainted,
Vector<CSSParserToken>& result, Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted) { bool& result_is_animation_tainted) {
range.ConsumeWhitespace(); range.ConsumeWhitespace();
DCHECK_EQ(range.Peek().GetType(), kIdentToken); DCHECK_EQ(range.Peek().GetType(), kIdentToken);
...@@ -132,21 +132,26 @@ bool CSSVariableResolver::ResolveVariableReference( ...@@ -132,21 +132,26 @@ bool CSSVariableResolver::ResolveVariableReference(
// TODO(alancutter): Append the registered initial custom property value if // TODO(alancutter): Append the registered initial custom property value if
// we are disallowing an animation tainted value. // we are disallowing an animation tainted value.
return ResolveFallback(range, disallow_animation_tainted, result, return ResolveFallback(range, disallow_animation_tainted, result,
result_is_animation_tainted); result_backing_strings, result_is_animation_tainted);
} }
result.AppendVector(variable_data->Tokens()); result.AppendVector(variable_data->Tokens());
// TODO(alancutter): Avoid adding backing strings multiple times in a row.
result_backing_strings.AppendVector(variable_data->BackingStrings());
result_is_animation_tainted |= variable_data->IsAnimationTainted(); result_is_animation_tainted |= variable_data->IsAnimationTainted();
Vector<CSSParserToken> trash; Vector<CSSParserToken> trash;
Vector<String> trash_backing_strings;
bool trash_is_animation_tainted; bool trash_is_animation_tainted;
ResolveFallback(range, disallow_animation_tainted, trash, ResolveFallback(range, disallow_animation_tainted, trash,
trash_is_animation_tainted); trash_backing_strings, trash_is_animation_tainted);
return true; return true;
} }
void CSSVariableResolver::ResolveApplyAtRule(CSSParserTokenRange& range, void CSSVariableResolver::ResolveApplyAtRule(
Vector<CSSParserToken>& result) { CSSParserTokenRange& range,
Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings) {
DCHECK(range.Peek().GetType() == kAtKeywordToken && DCHECK(range.Peek().GetType() == kAtKeywordToken &&
EqualIgnoringASCIICase(range.Peek().Value(), "apply")); EqualIgnoringASCIICase(range.Peek().Value(), "apply"));
range.ConsumeIncludingWhitespace(); range.ConsumeIncludingWhitespace();
...@@ -170,22 +175,25 @@ void CSSVariableResolver::ResolveApplyAtRule(CSSParserTokenRange& range, ...@@ -170,22 +175,25 @@ void CSSVariableResolver::ResolveApplyAtRule(CSSParserTokenRange& range,
return; return;
result.AppendRange(rule_contents.begin(), rule_contents.end()); result.AppendRange(rule_contents.begin(), rule_contents.end());
result_backing_strings.AppendVector(variable_data->BackingStrings());
} }
bool CSSVariableResolver::ResolveTokenRange(CSSParserTokenRange range, bool CSSVariableResolver::ResolveTokenRange(
bool disallow_animation_tainted, CSSParserTokenRange range,
Vector<CSSParserToken>& result, bool disallow_animation_tainted,
bool& result_is_animation_tainted) { Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted) {
bool success = true; bool success = true;
while (!range.AtEnd()) { while (!range.AtEnd()) {
if (range.Peek().FunctionId() == CSSValueVar) { if (range.Peek().FunctionId() == CSSValueVar) {
success &= ResolveVariableReference(range.ConsumeBlock(), success &= ResolveVariableReference(
disallow_animation_tainted, result, range.ConsumeBlock(), disallow_animation_tainted, result,
result_is_animation_tainted); result_backing_strings, result_is_animation_tainted);
} else if (range.Peek().GetType() == kAtKeywordToken && } else if (range.Peek().GetType() == kAtKeywordToken &&
EqualIgnoringASCIICase(range.Peek().Value(), "apply") && EqualIgnoringASCIICase(range.Peek().Value(), "apply") &&
RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) { RuntimeEnabledFeatures::cssApplyAtRulesEnabled()) {
ResolveApplyAtRule(range, result); ResolveApplyAtRule(range, result, result_backing_strings);
} else { } else {
result.push_back(range.Consume()); result.push_back(range.Consume());
} }
...@@ -223,10 +231,11 @@ const CSSValue* CSSVariableResolver::ResolveVariableReferences( ...@@ -223,10 +231,11 @@ const CSSValue* CSSVariableResolver::ResolveVariableReferences(
bool disallow_animation_tainted) { bool disallow_animation_tainted) {
CSSVariableResolver resolver(state); CSSVariableResolver resolver(state);
Vector<CSSParserToken> tokens; Vector<CSSParserToken> tokens;
Vector<String> backing_strings;
bool is_animation_tainted = false; bool is_animation_tainted = false;
if (!resolver.ResolveTokenRange(value.VariableDataValue()->Tokens(), if (!resolver.ResolveTokenRange(value.VariableDataValue()->Tokens(),
disallow_animation_tainted, tokens, disallow_animation_tainted, tokens,
is_animation_tainted)) backing_strings, is_animation_tainted))
return CSSUnsetValue::Create(); return CSSUnsetValue::Create();
const CSSValue* result = const CSSValue* result =
CSSPropertyParser::ParseSingleValue(id, tokens, value.ParserContext()); CSSPropertyParser::ParseSingleValue(id, tokens, value.ParserContext());
...@@ -254,11 +263,12 @@ const CSSValue* CSSVariableResolver::ResolvePendingSubstitutions( ...@@ -254,11 +263,12 @@ const CSSValue* CSSVariableResolver::ResolvePendingSubstitutions(
CSSVariableResolver resolver(state); CSSVariableResolver resolver(state);
Vector<CSSParserToken> tokens; Vector<CSSParserToken> tokens;
Vector<String> backing_strings;
bool is_animation_tainted = false; bool is_animation_tainted = false;
if (resolver.ResolveTokenRange( if (resolver.ResolveTokenRange(
shorthand_value->VariableDataValue()->Tokens(), shorthand_value->VariableDataValue()->Tokens(),
disallow_animation_tainted, tokens, is_animation_tainted)) { disallow_animation_tainted, tokens, backing_strings,
is_animation_tainted)) {
HeapVector<CSSProperty, 256> parsed_properties; HeapVector<CSSProperty, 256> parsed_properties;
if (CSSPropertyParser::ParseValue( if (CSSPropertyParser::ParseValue(
......
...@@ -58,20 +58,25 @@ class CSSVariableResolver { ...@@ -58,20 +58,25 @@ class CSSVariableResolver {
bool ResolveTokenRange(CSSParserTokenRange, bool ResolveTokenRange(CSSParserTokenRange,
bool disallow_animation_tainted, bool disallow_animation_tainted,
Vector<CSSParserToken>& result, Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted); bool& result_is_animation_tainted);
// Resolves the fallback (if present) of a var() reference, starting from the // Resolves the fallback (if present) of a var() reference, starting from the
// comma. // comma.
bool ResolveFallback(CSSParserTokenRange, bool ResolveFallback(CSSParserTokenRange,
bool disallow_animation_tainted, bool disallow_animation_tainted,
Vector<CSSParserToken>& result, Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted); bool& result_is_animation_tainted);
// Resolves the contents of a var() reference. // Resolves the contents of a var() reference.
bool ResolveVariableReference(CSSParserTokenRange, bool ResolveVariableReference(CSSParserTokenRange,
bool disallow_animation_tainted, bool disallow_animation_tainted,
Vector<CSSParserToken>& result, Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings,
bool& result_is_animation_tainted); bool& result_is_animation_tainted);
// Consumes and resolves an @apply rule. // Consumes and resolves an @apply rule.
void ResolveApplyAtRule(CSSParserTokenRange&, Vector<CSSParserToken>& result); void ResolveApplyAtRule(CSSParserTokenRange&,
Vector<CSSParserToken>& result,
Vector<String>& result_backing_strings);
// These return null if the custom property is invalid. // These return null if the custom property is invalid.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment