blob: 8210e7167bb943e8edf43e5aa26acae9c2f6d179 [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 "third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
namespace blink {
ChunkToLayerMapper::ChunkToLayerMapper(const PropertyTreeState& layer_state,
const gfx::Vector2dF& layer_offset)
: layer_state_(layer_state),
layer_offset_(layer_offset),
chunk_state_(layer_state_),
translation_2d_or_matrix_(
FloatSize(-layer_offset.x(), -layer_offset.y())) {}
void ChunkToLayerMapper::SwitchToChunk(const PaintChunk& chunk) {
raster_effect_outset_ = chunk.raster_effect_outset;
const auto& new_chunk_state =
chunk.properties.GetPropertyTreeState().Unalias();
if (new_chunk_state == chunk_state_)
return;
if (new_chunk_state == layer_state_) {
has_filter_that_moves_pixels_ = false;
translation_2d_or_matrix_ = GeometryMapper::Translation2DOrMatrix(
FloatSize(-layer_offset_.x(), -layer_offset_.y()));
clip_rect_ = FloatClipRect();
chunk_state_ = new_chunk_state;
return;
}
if (&new_chunk_state.Transform() != &chunk_state_.Transform()) {
translation_2d_or_matrix_ = GeometryMapper::SourceToDestinationProjection(
new_chunk_state.Transform(), layer_state_.Transform());
translation_2d_or_matrix_.PostTranslate(-layer_offset_.x(),
-layer_offset_.y());
}
bool new_has_filter_that_moves_pixels = has_filter_that_moves_pixels_;
if (&new_chunk_state.Effect() != &chunk_state_.Effect()) {
new_has_filter_that_moves_pixels = false;
for (const auto* effect = &new_chunk_state.Effect();
effect && effect != &layer_state_.Effect();
effect = effect->UnaliasedParent()) {
if (effect->HasFilterThatMovesPixels()) {
new_has_filter_that_moves_pixels = true;
break;
}
}
}
bool needs_clip_recalculation =
new_has_filter_that_moves_pixels != has_filter_that_moves_pixels_ ||
&new_chunk_state.Clip() != &chunk_state_.Clip();
if (needs_clip_recalculation) {
clip_rect_ =
GeometryMapper::LocalToAncestorClipRect(new_chunk_state, layer_state_);
if (!clip_rect_.IsInfinite())
clip_rect_.MoveBy(FloatPoint(-layer_offset_.x(), -layer_offset_.y()));
}
chunk_state_ = new_chunk_state;
has_filter_that_moves_pixels_ = new_has_filter_that_moves_pixels;
}
IntRect ChunkToLayerMapper::MapVisualRect(const IntRect& rect) const {
if (rect.IsEmpty())
return IntRect();
if (UNLIKELY(has_filter_that_moves_pixels_))
return MapUsingGeometryMapper(rect);
FloatRect mapped_rect(rect);
translation_2d_or_matrix_.MapRect(mapped_rect);
if (!mapped_rect.IsEmpty() && !clip_rect_.IsInfinite())
mapped_rect.Intersect(clip_rect_.Rect());
IntRect result;
if (!mapped_rect.IsEmpty()) {
InflateForRasterEffectOutset(mapped_rect);
result = EnclosingIntRect(mapped_rect);
}
#if DCHECK_IS_ON()
auto slow_result = MapUsingGeometryMapper(rect);
if (result != slow_result) {
// Not a DCHECK because this may result from a floating point error.
LOG(WARNING) << "ChunkToLayerMapper::MapVisualRect: Different results from"
<< "fast path (" << result << ") and slow path ("
<< slow_result << ")";
}
#endif
return result;
}
// This is called when the fast path doesn't apply if there is any filter that
// moves pixels. GeometryMapper::LocalToAncestorVisualRect() will apply the
// visual effects of the filters, though slowly.
IntRect ChunkToLayerMapper::MapUsingGeometryMapper(const IntRect& rect) const {
FloatClipRect visual_rect((FloatRect(rect)));
GeometryMapper::LocalToAncestorVisualRect(chunk_state_, layer_state_,
visual_rect);
if (visual_rect.Rect().IsEmpty())
return IntRect();
visual_rect.Rect().Move(-layer_offset_.x(), -layer_offset_.y());
InflateForRasterEffectOutset(visual_rect.Rect());
return EnclosingIntRect(visual_rect.Rect());
}
void ChunkToLayerMapper::InflateForRasterEffectOutset(FloatRect& rect) const {
if (raster_effect_outset_ == RasterEffectOutset::kHalfPixel)
rect.Inflate(0.5);
else if (raster_effect_outset_ == RasterEffectOutset::kWholePixel)
rect.Inflate(1);
}
} // namespace blink