| // Copyright 2013 The Flutter 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 "impeller/entity/entity.h" | |
| #include <algorithm> | |
| #include <optional> | |
| #include "impeller/base/validation.h" | |
| #include "impeller/entity/contents/content_context.h" | |
| #include "impeller/entity/contents/filters/filter_contents.h" | |
| #include "impeller/entity/contents/texture_contents.h" | |
| #include "impeller/entity/entity_pass.h" | |
| #include "impeller/geometry/color.h" | |
| #include "impeller/geometry/vector.h" | |
| #include "impeller/renderer/render_pass.h" | |
| namespace impeller { | |
| std::optional<Entity> Entity::FromSnapshot( | |
| const std::optional<Snapshot>& snapshot, | |
| BlendMode blend_mode, | |
| uint32_t clip_depth) { | |
| if (!snapshot.has_value()) { | |
| return std::nullopt; | |
| } | |
| auto texture_rect = Rect::MakeSize(snapshot->texture->GetSize()); | |
| auto contents = TextureContents::MakeRect(texture_rect); | |
| contents->SetTexture(snapshot->texture); | |
| contents->SetSamplerDescriptor(snapshot->sampler_descriptor); | |
| contents->SetSourceRect(texture_rect); | |
| contents->SetOpacity(snapshot->opacity); | |
| Entity entity; | |
| entity.SetBlendMode(blend_mode); | |
| entity.SetClipDepth(clip_depth); | |
| entity.SetTransformation(snapshot->transform); | |
| entity.SetContents(contents); | |
| return entity; | |
| } | |
| Entity::Entity() = default; | |
| Entity::~Entity() = default; | |
| const Matrix& Entity::GetTransformation() const { | |
| return transformation_; | |
| } | |
| void Entity::SetTransformation(const Matrix& transformation) { | |
| transformation_ = transformation; | |
| } | |
| std::optional<Rect> Entity::GetCoverage() const { | |
| if (!contents_) { | |
| return std::nullopt; | |
| } | |
| return contents_->GetCoverage(*this); | |
| } | |
| Contents::ClipCoverage Entity::GetClipCoverage( | |
| const std::optional<Rect>& current_clip_coverage) const { | |
| if (!contents_) { | |
| return {}; | |
| } | |
| return contents_->GetClipCoverage(*this, current_clip_coverage); | |
| } | |
| bool Entity::ShouldRender(const std::optional<Rect>& clip_coverage) const { | |
| return contents_->ShouldRender(*this, clip_coverage); | |
| } | |
| void Entity::SetContents(std::shared_ptr<Contents> contents) { | |
| contents_ = std::move(contents); | |
| } | |
| const std::shared_ptr<Contents>& Entity::GetContents() const { | |
| return contents_; | |
| } | |
| void Entity::SetClipDepth(uint32_t depth) { | |
| clip_depth_ = depth; | |
| } | |
| uint32_t Entity::GetClipDepth() const { | |
| return clip_depth_; | |
| } | |
| void Entity::IncrementStencilDepth(uint32_t increment) { | |
| clip_depth_ += increment; | |
| } | |
| void Entity::SetBlendMode(BlendMode blend_mode) { | |
| blend_mode_ = blend_mode; | |
| } | |
| BlendMode Entity::GetBlendMode() const { | |
| return blend_mode_; | |
| } | |
| bool Entity::CanInheritOpacity() const { | |
| if (!contents_) { | |
| return false; | |
| } | |
| if (!((blend_mode_ == BlendMode::kSource && contents_->IsOpaque()) || | |
| blend_mode_ == BlendMode::kSourceOver)) { | |
| return false; | |
| } | |
| return contents_->CanInheritOpacity(*this); | |
| } | |
| bool Entity::SetInheritedOpacity(Scalar alpha) { | |
| if (!CanInheritOpacity()) { | |
| return false; | |
| } | |
| if (blend_mode_ == BlendMode::kSource && contents_->IsOpaque()) { | |
| blend_mode_ = BlendMode::kSourceOver; | |
| } | |
| contents_->SetInheritedOpacity(alpha); | |
| return true; | |
| } | |
| std::optional<Color> Entity::AsBackgroundColor(ISize target_size) const { | |
| return contents_->AsBackgroundColor(*this, target_size); | |
| } | |
| /// @brief Returns true if the blend mode is "destructive", meaning that even | |
| /// fully transparent source colors would result in the destination | |
| /// getting changed. | |
| /// | |
| /// This is useful for determining if EntityPass textures can be | |
| /// shrinkwrapped to their Entities' coverage; they can be shrinkwrapped | |
| /// if all of the contained Entities have non-destructive blends. | |
| bool Entity::IsBlendModeDestructive(BlendMode blend_mode) { | |
| switch (blend_mode) { | |
| case BlendMode::kClear: | |
| case BlendMode::kSource: | |
| case BlendMode::kSourceIn: | |
| case BlendMode::kDestinationIn: | |
| case BlendMode::kSourceOut: | |
| case BlendMode::kDestinationOut: | |
| case BlendMode::kDestinationATop: | |
| case BlendMode::kXor: | |
| case BlendMode::kModulate: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| bool Entity::Render(const ContentContext& renderer, | |
| RenderPass& parent_pass) const { | |
| if (!contents_) { | |
| return true; | |
| } | |
| if (!contents_->GetCoverageHint().has_value()) { | |
| contents_->SetCoverageHint( | |
| Rect::MakeSize(parent_pass.GetRenderTargetSize())); | |
| } | |
| return contents_->Render(renderer, *this, parent_pass); | |
| } | |
| Scalar Entity::DeriveTextScale() const { | |
| return GetTransformation().GetMaxBasisLengthXY(); | |
| } | |
| Capture& Entity::GetCapture() const { | |
| return capture_; | |
| } | |
| void Entity::SetCapture(Capture capture) const { | |
| capture_ = std::move(capture); | |
| } | |
| } // namespace impeller |