blob: ed04bc1bf55e6d54b996aff95036c268f5ac0c9b [file] [log] [blame]
// Copyright 2018 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 <memory>
#include <utility>
#include "third_party/blink/renderer/core/css/cssom/paint_worklet_style_property_map.h"
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
#include "third_party/blink/renderer/core/css/css_custom_property_declaration.h"
#include "third_party/blink/renderer/core/css/css_variable_data.h"
#include "third_party/blink/renderer/core/css/cssom/computed_style_property_map.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_keyword_value.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_unit_value.h"
#include "third_party/blink/renderer/core/css/cssom/cross_thread_unsupported_value.h"
#include "third_party/blink/renderer/core/css/cssom/css_unparsed_value.h"
#include "third_party/blink/renderer/core/css/cssom/css_unsupported_style_value.h"
#include "third_party/blink/renderer/core/css/properties/css_property_ref.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
namespace {
class PaintWorkletStylePropertyMapIterationSource final
: public PairIterable<String, CSSStyleValueVector>::IterationSource {
public:
explicit PaintWorkletStylePropertyMapIterationSource(
HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> values)
: index_(0), values_(values) {}
bool Next(ScriptState*,
String& key,
CSSStyleValueVector& value,
ExceptionState&) override {
if (index_ >= values_.size())
return false;
const PaintWorkletStylePropertyMap::StylePropertyMapEntry& pair =
values_.at(index_++);
key = pair.first;
value = pair.second;
return true;
}
void Trace(Visitor* visitor) const override {
visitor->Trace(values_);
PairIterable<String, CSSStyleValueVector>::IterationSource::Trace(visitor);
}
private:
wtf_size_t index_;
const HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> values_;
};
bool BuildNativeValues(const ComputedStyle& style,
const Vector<CSSPropertyID>& native_properties,
PaintWorkletStylePropertyMap::CrossThreadData& data) {
DCHECK(IsMainThread());
for (const auto& property_id : native_properties) {
// Silently drop shorthand properties.
DCHECK_NE(property_id, CSSPropertyID::kInvalid);
DCHECK_NE(property_id, CSSPropertyID::kVariable);
if (CSSProperty::Get(property_id).IsShorthand())
continue;
std::unique_ptr<CrossThreadStyleValue> value =
CSSProperty::Get(property_id)
.CrossThreadStyleValueFromComputedStyle(
style, /* layout_object */ nullptr,
/* allow_visited_style */ false);
if (value->GetType() == CrossThreadStyleValue::StyleValueType::kUnknownType)
return false;
String key = CSSProperty::Get(property_id).GetPropertyNameString();
if (!key.IsSafeToSendToAnotherThread())
key = key.IsolatedCopy();
data.Set(key, std::move(value));
}
return true;
}
bool BuildCustomValues(
const Document& document,
UniqueObjectId unique_object_id,
const ComputedStyle& style,
const Vector<AtomicString>& custom_properties,
PaintWorkletStylePropertyMap::CrossThreadData& data,
CompositorPaintWorkletInput::PropertyKeys& input_property_keys) {
DCHECK(IsMainThread());
for (const auto& property_name : custom_properties) {
CSSPropertyRef ref(property_name, document);
std::unique_ptr<CrossThreadStyleValue> value =
ref.GetProperty().CrossThreadStyleValueFromComputedStyle(
style, /* layout_object */ nullptr,
/* allow_visited_style */ false);
if (value->GetType() == CrossThreadStyleValue::StyleValueType::kUnknownType)
return false;
// In order to animate properties, we need to track the compositor element
// id on which they will be animated.
const bool animatable_property =
value->GetType() == CrossThreadStyleValue::StyleValueType::kUnitType ||
value->GetType() == CrossThreadStyleValue::StyleValueType::kColorType;
if (animatable_property) {
CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
unique_object_id,
CompositorAnimations::CompositorElementNamespaceForProperty(
ref.GetProperty().PropertyID()));
input_property_keys.emplace_back(property_name.Utf8(), element_id);
}
// Ensure that the String can be safely passed cross threads.
String key = property_name.GetString();
if (!key.IsSafeToSendToAnotherThread())
key = key.IsolatedCopy();
data.Set(key, std::move(value));
}
return true;
}
} // namespace
// static
base::Optional<PaintWorkletStylePropertyMap::CrossThreadData>
PaintWorkletStylePropertyMap::BuildCrossThreadData(
const Document& document,
UniqueObjectId unique_object_id,
const ComputedStyle& style,
const Vector<CSSPropertyID>& native_properties,
const Vector<AtomicString>& custom_properties,
CompositorPaintWorkletInput::PropertyKeys& input_property_keys) {
DCHECK(IsMainThread());
PaintWorkletStylePropertyMap::CrossThreadData data;
data.ReserveCapacityForSize(native_properties.size() +
custom_properties.size());
if (!BuildNativeValues(style, native_properties, data))
return base::nullopt;
if (!BuildCustomValues(document, unique_object_id, style, custom_properties,
data, input_property_keys))
return base::nullopt;
return data;
}
// static
PaintWorkletStylePropertyMap::CrossThreadData
PaintWorkletStylePropertyMap::CopyCrossThreadData(const CrossThreadData& data) {
PaintWorkletStylePropertyMap::CrossThreadData copied_data;
copied_data.ReserveCapacityForSize(data.size());
for (auto& pair : data)
copied_data.Set(pair.key.IsolatedCopy(), pair.value->IsolatedCopy());
return copied_data;
}
// The |data| comes from PaintWorkletInput, where its string is already an
// isolated copy from the main thread string, so we don't need to make another
// isolated copy here.
PaintWorkletStylePropertyMap::PaintWorkletStylePropertyMap(CrossThreadData data)
: data_(std::move(data)) {
DCHECK(!IsMainThread());
}
CSSStyleValue* PaintWorkletStylePropertyMap::get(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) const {
CSSStyleValueVector all_values =
getAll(execution_context, property_name, exception_state);
return all_values.IsEmpty() ? nullptr : all_values[0];
}
CSSStyleValueVector PaintWorkletStylePropertyMap::getAll(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) const {
CSSPropertyID property_id = CssPropertyID(execution_context, property_name);
if (property_id == CSSPropertyID::kInvalid) {
exception_state.ThrowTypeError("Invalid propertyName: " + property_name);
return CSSStyleValueVector();
}
DCHECK(IsValidCSSPropertyID(property_id));
CSSStyleValueVector values;
auto value = data_.find(property_name);
if (value == data_.end())
return CSSStyleValueVector();
values.push_back(value->value->ToCSSStyleValue());
return values;
}
bool PaintWorkletStylePropertyMap::has(
const ExecutionContext* execution_context,
const String& property_name,
ExceptionState& exception_state) const {
return !getAll(execution_context, property_name, exception_state).IsEmpty();
}
unsigned PaintWorkletStylePropertyMap::size() const {
return data_.size();
}
PaintWorkletStylePropertyMap::IterationSource*
PaintWorkletStylePropertyMap::StartIteration(ScriptState* script_state,
ExceptionState& exception_state) {
// TODO(xidachen): implement this function. Note that the output should be
// sorted.
HeapVector<PaintWorkletStylePropertyMap::StylePropertyMapEntry> result;
return MakeGarbageCollected<PaintWorkletStylePropertyMapIterationSource>(
result);
}
void PaintWorkletStylePropertyMap::Trace(Visitor* visitor) const {
StylePropertyMapReadOnly::Trace(visitor);
}
} // namespace blink