blob: 8b10ff119db10ecf8dc2a336e85ee48ad6a77c03 [file] [log] [blame]
// Copyright 2017 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 "third_party/blink/renderer/core/paint/fragment_data.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "base/debug/stack_trace.h"
namespace blink {
// These are defined here because of PaintLayer dependency.
FragmentData::RareData::RareData() : unique_id(NewUniqueObjectId()) {}
FragmentData::RareData::~RareData() = default;
void FragmentData::DestroyTail() {
while (next_fragment_) {
// Take the following (next-next) fragment, clearing
// |next_fragment_->next_fragment_|.
std::unique_ptr<FragmentData> next =
std::move(next_fragment_->next_fragment_);
// Point |next_fragment_| to the following fragment and destroy
// the current |next_fragment_|.
next_fragment_ = std::move(next);
}
}
FragmentData& FragmentData::EnsureNextFragment() {
if (!next_fragment_)
next_fragment_ = std::make_unique<FragmentData>();
return *next_fragment_.get();
}
FragmentData::RareData& FragmentData::EnsureRareData() {
if (!rare_data_)
rare_data_ = std::make_unique<RareData>();
return *rare_data_;
}
void FragmentData::SetLayer(std::unique_ptr<PaintLayer> layer) {
if (rare_data_ || layer)
EnsureRareData().layer = std::move(layer);
}
const TransformPaintPropertyNode& FragmentData::PreTransform() const {
if (const auto* properties = PaintProperties()) {
if (const auto* transform = properties->Transform()) {
DCHECK(transform->Parent());
return *transform->Parent();
}
}
return LocalBorderBoxProperties().Transform();
}
const TransformPaintPropertyNode& FragmentData::PostScrollTranslation() const {
if (const auto* properties = PaintProperties()) {
if (properties->TransformIsolationNode())
return *properties->TransformIsolationNode();
if (properties->ScrollTranslation())
return *properties->ScrollTranslation();
if (properties->ReplacedContentTransform())
return *properties->ReplacedContentTransform();
if (properties->Perspective())
return *properties->Perspective();
}
return LocalBorderBoxProperties().Transform();
}
const ClipPaintPropertyNode& FragmentData::PreClip() const {
if (const auto* properties = PaintProperties()) {
if (const auto* clip = properties->ClipPathClip()) {
// SPv1 composited clip-path has an alternative clip tree structure.
// If the clip-path is parented by the mask clip, it is only used
// to clip mask layer chunks, and not in the clip inheritance chain.
DCHECK(clip->Parent());
if (clip->Parent() != properties->MaskClip())
return *clip->Parent();
}
if (const auto* mask_clip = properties->MaskClip()) {
DCHECK(mask_clip->Parent());
return *mask_clip->Parent();
}
if (const auto* css_clip = properties->CssClip()) {
DCHECK(css_clip->Parent());
return *css_clip->Parent();
}
}
return LocalBorderBoxProperties().Clip();
}
const ClipPaintPropertyNode& FragmentData::PostOverflowClip() const {
if (const auto* properties = PaintProperties()) {
if (properties->ClipIsolationNode())
return *properties->ClipIsolationNode();
if (properties->OverflowClip())
return *properties->OverflowClip();
if (properties->InnerBorderRadiusClip())
return *properties->InnerBorderRadiusClip();
}
return LocalBorderBoxProperties().Clip();
}
const EffectPaintPropertyNode& FragmentData::PreEffect() const {
if (const auto* properties = PaintProperties()) {
if (const auto* effect = properties->Effect()) {
DCHECK(effect->Parent());
return *effect->Parent();
}
if (const auto* filter = properties->Filter()) {
DCHECK(filter->Parent());
return *filter->Parent();
}
}
return LocalBorderBoxProperties().Effect();
}
const EffectPaintPropertyNode& FragmentData::PreFilter() const {
if (const auto* properties = PaintProperties()) {
if (const auto* filter = properties->Filter()) {
DCHECK(filter->Parent());
return *filter->Parent();
}
}
return LocalBorderBoxProperties().Effect();
}
const EffectPaintPropertyNode& FragmentData::PostIsolationEffect() const {
if (const auto* properties = PaintProperties()) {
if (properties->EffectIsolationNode())
return *properties->EffectIsolationNode();
}
return LocalBorderBoxProperties().Effect();
}
void FragmentData::InvalidateClipPathCache() {
if (!rare_data_)
return;
rare_data_->is_clip_path_cache_valid = false;
rare_data_->clip_path_bounding_box = base::nullopt;
rare_data_->clip_path_path = nullptr;
}
void FragmentData::SetClipPathCache(const base::Optional<IntRect>& bounding_box,
scoped_refptr<const RefCountedPath> path) {
EnsureRareData().is_clip_path_cache_valid = true;
rare_data_->clip_path_bounding_box = bounding_box;
rare_data_->clip_path_path = std::move(path);
}
template <typename Rect, typename PaintOffsetFunction>
static void MapRectBetweenFragment(
const FragmentData& from_fragment,
const FragmentData& to_fragment,
const PaintOffsetFunction& paint_offset_function,
Rect& rect) {
if (&from_fragment == &to_fragment)
return;
const auto& from_transform =
from_fragment.LocalBorderBoxProperties().Transform();
const auto& to_transform = to_fragment.LocalBorderBoxProperties().Transform();
rect.MoveBy(paint_offset_function(from_fragment.PaintOffset()));
GeometryMapper::SourceToDestinationRect(from_transform, to_transform, rect);
rect.MoveBy(-paint_offset_function(to_fragment.PaintOffset()));
}
void FragmentData::MapRectToFragment(const FragmentData& fragment,
IntRect& rect) const {
MapRectBetweenFragment(*this, fragment,
[](const LayoutPoint& paint_offset) {
return RoundedIntPoint(paint_offset);
},
rect);
}
void FragmentData::MapRectToFragment(const FragmentData& fragment,
LayoutRect& rect) const {
MapRectBetweenFragment(
*this, fragment,
[](const LayoutPoint& paint_offset) { return paint_offset; }, rect);
}
} // namespace blink