Refactor visual overflow computation for view-transitions (part 2)
Use the new CC mechanism to compute the visual overflow.
We pass the layout-computed visual overflow as the max extent, and
then let CC correct it in order to map the content rect.
- We keep the replaced-content geometry projection as is, but also pass
the "max extents" to the CC laye (ViewTransitionContentLayerImpl),
and use it to map the border box of the original element to the
content box of the pseudo-element. Note that the border-box is now
in enclosing-layer space, as it needs to map correctly to the
max extents and actual extents. The border box sent over the wire
also has includes the offset from the enclosing layer, which would
only be different from zero for inline elements.
- When the captured rects from CC are delivered, they are used to map.
the contents of the old
pseudo-elements.
Bug: 347947051
Change-Id: I5202078666d016156c5abee99772726947e8a1d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5920431
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Reviewed-by: Khushal Sagar <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1368988}
diff --git a/cc/layers/view_transition_content_layer_impl.cc b/cc/layers/view_transition_content_layer_impl.cc
index 38780c5..98d2dde6 100644
--- a/cc/layers/view_transition_content_layer_impl.cc
+++ b/cc/layers/view_transition_content_layer_impl.cc
@@ -82,10 +82,9 @@
return;
}
- DUMP_WILL_BE_CHECK(
- max_extents_rect_in_originating_layer_coordinate_space_.Contains(
- gfx::RectF(
- originating_surface_content_rect_in_layer_coordinate_space)));
+ // TODO(crbug.com/40840594): Add a CHECK that the surface rect is a subset of
+ // the max extents. ATM this fails in one edge case (negative clip-path), the
+ // CHECK should be added once that's fixed.
// The actual extents rect is a subset of the max extents rect. This
// projection maps this subset to the coordinate space of this layer (0, 0,
diff --git a/components/viz/common/viz_utils.cc b/components/viz/common/viz_utils.cc
index 594a21a..4a6bd22 100644
--- a/components/viz/common/viz_utils.cc
+++ b/components/viz/common/viz_utils.cc
@@ -163,15 +163,17 @@
gfx::Rect view_transition_content_output) {
gfx::Transform view_transition_transform;
+ view_transition_transform.Translate(shared_element_quad.x(),
+ shared_element_quad.y());
+
view_transition_transform.Scale(
shared_element_quad.width() /
static_cast<SkScalar>(view_transition_content_output.width()),
shared_element_quad.height() /
static_cast<SkScalar>(view_transition_content_output.height()));
- view_transition_transform.Translate(
- shared_element_quad.x() - view_transition_content_output.x(),
- shared_element_quad.y() - view_transition_content_output.y());
+ view_transition_transform.Translate(-view_transition_content_output.x(),
+ -view_transition_content_output.y());
return view_transition_transform;
}
diff --git a/third_party/blink/common/frame/view_transition_state_mojom_traits.cc b/third_party/blink/common/frame/view_transition_state_mojom_traits.cc
index 7b723b7..27f0cc1 100644
--- a/third_party/blink/common/frame/view_transition_state_mojom_traits.cc
+++ b/third_party/blink/common/frame/view_transition_state_mojom_traits.cc
@@ -15,7 +15,8 @@
Read(blink::mojom::ViewTransitionElementDataView data,
blink::ViewTransitionElement* out) {
if (!data.ReadTagName(&out->tag_name) ||
- !data.ReadBorderBoxSizeInCssSpace(&out->border_box_size_in_css_space) ||
+ !data.ReadBorderBoxRectInEnclosingLayerCssSpace(
+ &out->border_box_rect_in_enclosing_layer_css_space) ||
!data.ReadViewportMatrix(&out->viewport_matrix) ||
!data.ReadOverflowRectInLayoutSpace(
&out->overflow_rect_in_layout_space) ||
diff --git a/third_party/blink/public/common/frame/view_transition_state.h b/third_party/blink/public/common/frame/view_transition_state.h
index 43f89bb..2bafad2c6 100644
--- a/third_party/blink/public/common/frame/view_transition_state.h
+++ b/third_party/blink/public/common/frame/view_transition_state.h
@@ -34,7 +34,7 @@
ViewTransitionElement>;
std::string tag_name;
- gfx::SizeF border_box_size_in_css_space;
+ gfx::RectF border_box_rect_in_enclosing_layer_css_space;
gfx::Transform viewport_matrix;
gfx::RectF overflow_rect_in_layout_space;
viz::ViewTransitionElementResourceId snapshot_id;
diff --git a/third_party/blink/public/common/frame/view_transition_state_mojom_traits.h b/third_party/blink/public/common/frame/view_transition_state_mojom_traits.h
index 17b23fa..cb3b059 100644
--- a/third_party/blink/public/common/frame/view_transition_state_mojom_traits.h
+++ b/third_party/blink/public/common/frame/view_transition_state_mojom_traits.h
@@ -13,6 +13,7 @@
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/frame/view_transition_state.h"
#include "third_party/blink/public/mojom/frame/view_transition_state.mojom-shared.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace mojo {
@@ -24,9 +25,9 @@
return r.tag_name;
}
- static const gfx::SizeF& border_box_size_in_css_space(
+ static const gfx::RectF& border_box_rect_in_enclosing_layer_css_space(
const blink::ViewTransitionElement& r) {
- return r.border_box_size_in_css_space;
+ return r.border_box_rect_in_enclosing_layer_css_space;
}
static const gfx::Transform& viewport_matrix(
diff --git a/third_party/blink/public/mojom/frame/view_transition_state.mojom b/third_party/blink/public/mojom/frame/view_transition_state.mojom
index e1162fad..c744fd9dd 100644
--- a/third_party/blink/public/mojom/frame/view_transition_state.mojom
+++ b/third_party/blink/public/mojom/frame/view_transition_state.mojom
@@ -29,7 +29,7 @@
string tag_name;
// Geometry information for this shared element.
- gfx.mojom.SizeF border_box_size_in_css_space;
+ gfx.mojom.RectF border_box_rect_in_enclosing_layer_css_space;
gfx.mojom.Transform viewport_matrix;
gfx.mojom.RectF overflow_rect_in_layout_space;
gfx.mojom.RectF? captured_rect_in_layout_space;
diff --git a/third_party/blink/renderer/core/layout/layout_view_transition_content.cc b/third_party/blink/renderer/core/layout/layout_view_transition_content.cc
index 0623ea4..97baf36 100644
--- a/third_party/blink/renderer/core/layout/layout_view_transition_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_view_transition_content.cc
@@ -4,8 +4,12 @@
#include "third_party/blink/renderer/core/layout/layout_view_transition_content.h"
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/graphics/paint/foreign_layer_display_item.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/transform_util.h"
namespace blink {
@@ -16,7 +20,8 @@
element->resource_id(),
element->is_live_content_element())),
captured_rect_(element->captured_rect()),
- border_box_rect_(element->border_box_rect()) {
+ border_box_rect_(element->border_box_rect()),
+ propagate_max_extent_rect_(element->propagate_max_extent_rect()) {
SetIntrinsicSize(PhysicalSize(LayoutUnit(border_box_rect_.width()),
LayoutUnit(border_box_rect_.height())));
}
@@ -25,7 +30,8 @@
void LayoutViewTransitionContent::OnIntrinsicSizeUpdated(
const gfx::RectF& captured_rect,
- const gfx::RectF& border_box_rect) {
+ const gfx::RectF& border_box_rect,
+ bool propagate_max_extent_rect) {
NOT_DESTROYED();
SetIntrinsicSize(PhysicalSize(LayoutUnit(border_box_rect.width()),
LayoutUnit(border_box_rect.height())));
@@ -36,6 +42,7 @@
captured_rect_ = captured_rect;
border_box_rect_ = border_box_rect;
+ propagate_max_extent_rect_ = propagate_max_extent_rect;
SetIntrinsicLogicalWidthsDirty();
SetNeedsLayout(layout_invalidation_reason::kSizeChanged);
@@ -66,6 +73,12 @@
layer_->SetBounds(
gfx::Size(pixel_snapped_rect.width(), pixel_snapped_rect.height()));
layer_->SetIsDrawable(true);
+
+ if (propagate_max_extent_rect_) {
+ layer_->SetMaxExtentsRectInOriginatingLayerSpace(
+ propagate_max_extent_rect_ ? captured_rect_ : gfx::RectF());
+ }
+
RecordForeignLayer(
context, *this, DisplayItem::kForeignLayerViewTransitionContent, layer_,
gfx::Point(pixel_snapped_rect.x(), pixel_snapped_rect.y()));
diff --git a/third_party/blink/renderer/core/layout/layout_view_transition_content.h b/third_party/blink/renderer/core/layout/layout_view_transition_content.h
index 44baed4..8db4c0f 100644
--- a/third_party/blink/renderer/core/layout/layout_view_transition_content.h
+++ b/third_party/blink/renderer/core/layout/layout_view_transition_content.h
@@ -24,7 +24,8 @@
return "LayoutViewTransitionContent";
}
void OnIntrinsicSizeUpdated(const gfx::RectF& captured_rect,
- const gfx::RectF& border_box_rect);
+ const gfx::RectF& border_box_rect,
+ bool propagate_max_extent_rect);
bool IsViewTransitionContent() const override {
NOT_DESTROYED();
@@ -43,6 +44,7 @@
scoped_refptr<cc::ViewTransitionContentLayer> layer_;
gfx::RectF captured_rect_;
gfx::RectF border_box_rect_;
+ bool propagate_max_extent_rect_;
};
template <>
diff --git a/third_party/blink/renderer/core/view_transition/view_transition.cc b/third_party/blink/renderer/core/view_transition/view_transition.cc
index 76e101e..d2e8d32 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition.cc
@@ -688,12 +688,14 @@
}
void ViewTransition::NotifyCaptureFinished(
- const std::unordered_map<viz::ViewTransitionElementResourceId,
- gfx::RectF>&) {
+ const std::unordered_map<viz::ViewTransitionElementResourceId, gfx::RectF>&
+ capture_rects) {
if (state_ != State::kCapturing) {
DCHECK(IsTerminalState(state_));
return;
}
+
+ style_tracker_->SetCaptureRectsFromCompositor(capture_rects);
bool process_next_state = AdvanceTo(State::kCaptured);
DCHECK(process_next_state);
ProcessCurrentState();
diff --git a/third_party/blink/renderer/core/view_transition/view_transition.h b/third_party/blink/renderer/core/view_transition/view_transition.h
index 8993934..df472b05 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/types/pass_key.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/blink/public/common/frame/view_transition_state.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_content_element.cc b/third_party/blink/renderer/core/view_transition/view_transition_content_element.cc
index b9e7de9..87555253 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_content_element.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_content_element.cc
@@ -28,12 +28,15 @@
void ViewTransitionContentElement::SetIntrinsicSize(
const gfx::RectF& captured_rect,
- const gfx::RectF& border_box_rect) {
+ const gfx::RectF& border_box_rect,
+ bool propagate_max_extent_rect) {
captured_rect_ = captured_rect;
border_box_rect_ = border_box_rect;
+ propagate_max_extent_rect_ = propagate_max_extent_rect;
if (auto* layout_object = GetLayoutObject()) {
static_cast<LayoutViewTransitionContent*>(layout_object)
- ->OnIntrinsicSizeUpdated(captured_rect_, border_box_rect_);
+ ->OnIntrinsicSizeUpdated(captured_rect_, border_box_rect_,
+ propagate_max_extent_rect_);
}
}
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_content_element.h b/third_party/blink/renderer/core/view_transition/view_transition_content_element.h
index 5fa50ea16..83a9e61 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_content_element.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition_content_element.h
@@ -31,7 +31,8 @@
~ViewTransitionContentElement() override;
void SetIntrinsicSize(const gfx::RectF& captured_rect,
- const gfx::RectF& border_box_rect);
+ const gfx::RectF& border_box_rect,
+ bool propagates_max_extents_rect);
const gfx::RectF& captured_rect() const { return captured_rect_; }
const gfx::RectF& border_box_rect() const { return border_box_rect_; }
const viz::ViewTransitionElementResourceId& resource_id() const {
@@ -39,6 +40,8 @@
}
bool is_live_content_element() const { return is_live_content_element_; }
+ bool propagate_max_extent_rect() const { return propagate_max_extent_rect_; }
+
private:
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
@@ -52,6 +55,7 @@
// The size of the element's texture generated by the compositor.
gfx::RectF captured_rect_;
gfx::RectF border_box_rect_;
+ bool propagate_max_extent_rect_;
};
} // namespace blink
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
index d9d2de83..bf69f20 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_style_builder.cc
@@ -125,8 +125,8 @@
height: %3fpx;
)CSS",
GetTransformString(source_properties, parent_inverse_transform).c_str(),
- source_properties.border_box_size_in_css_space.width.ToFloat(),
- source_properties.border_box_size_in_css_space.height.ToFloat());
+ source_properties.border_box_rect_in_css_space.Width().ToFloat(),
+ source_properties.border_box_rect_in_css_space.Height().ToFloat());
for (const auto& [id, value] : animated_css_properties) {
builder_.AppendFormat(
@@ -150,8 +150,8 @@
height: %.3fpx;
transform: %s;
)CSS",
- properties.border_box_size_in_css_space.width.ToFloat(),
- properties.border_box_size_in_css_space.height.ToFloat(),
+ properties.border_box_rect_in_css_space.Width().ToFloat(),
+ properties.border_box_rect_in_css_space.Height().ToFloat(),
GetTransformString(properties, parent_inverse_transform).c_str());
for (const auto& [id, value] : captured_css_properties) {
rule_builder.AppendFormat(
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
index 475eab9..1075b70 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
@@ -5,7 +5,9 @@
#include "third_party/blink/renderer/core/view_transition/view_transition_style_tracker.h"
#include <limits>
+#include <unordered_map>
+#include "base/check.h"
#include "base/containers/contains.h"
#include "base/not_fatal_until.h"
#include "components/viz/common/view_transition_element_resource_id.h"
@@ -56,9 +58,11 @@
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "ui/display/screen_info.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace blink {
namespace {
@@ -514,8 +518,9 @@
auto* element_data = MakeGarbageCollected<ElementData>();
element_data->container_properties.emplace_back(
- PhysicalSize::FromSizeFFloor(
- transition_state_element.border_box_size_in_css_space),
+ PhysicalRect::EnclosingRect(
+ transition_state_element
+ .border_box_rect_in_enclosing_layer_css_space),
transition_state_element.viewport_matrix);
element_data->old_snapshot_id = transition_state_element.snapshot_id;
@@ -958,6 +963,55 @@
return true;
}
+void ViewTransitionStyleTracker::SetCaptureRectsFromCompositor(
+ const std::unordered_map<viz::ViewTransitionElementResourceId, gfx::RectF>&
+ rects) {
+ if (!RuntimeEnabledFeatures::ViewTransitionOverflowRectFromSurfaceEnabled()) {
+ // CC might collect these rects when the feature is disabled, but we're
+ // ignoring them in that case.
+ return;
+ }
+
+ CHECK(!HasLiveNewContent());
+ for (auto& entry : element_data_map_) {
+ auto& element_data = entry.value;
+
+ // This implies that the snapshot wasn't painted.
+ if (!rects.contains(element_data->old_snapshot_id) ||
+ !element_data->ShouldPropagateVisualOverflowRectAsMaxExtentsRect()) {
+ continue;
+ }
+
+ // The capture rects from the compositor are now the source of truth for the
+ // old elements. We no longer need to guess the max extents using the layout
+ // ink overflow and apply corrections, as old pseudo-elements paint existing
+ // textures with the captured geometry.
+ auto rect_from_compositor = rects.at(element_data->old_snapshot_id);
+ auto captured_rect =
+ PhysicalRect(gfx::ToEnclosedRect(rect_from_compositor));
+
+ // TODO(crbug.com/40840594): Add a CHECK that the compositor rect is a
+ // subset of the computed visual overflow. ATM this fails in one edge case
+ // (negative clip-path), the CHECK should be added once that's fixed.
+
+ element_data->cached_visual_overflow_rect_in_layout_space =
+ element_data->visual_overflow_rect_in_layout_space = captured_rect;
+
+ // This rect no longer matters.
+ element_data->cached_captured_rect_in_layout_space.reset();
+
+ if (auto* pseudo_element =
+ document_->documentElement()->GetStyledPseudoElement(
+ PseudoId::kPseudoIdViewTransitionOld, entry.key)) {
+ static_cast<ViewTransitionContentElement*>(pseudo_element)
+ ->SetIntrinsicSize(rect_from_compositor,
+ element_data->GetBorderBoxRect(
+ /*use_cached_data=*/true, device_pixel_ratio_),
+ /*propagates_max_extents_rect=*/false);
+ }
+ }
+}
+
void ViewTransitionStyleTracker::CaptureResolved() {
DCHECK_EQ(state_, State::kCapturing);
@@ -1246,7 +1300,9 @@
auto* pseudo_element = MakeGarbageCollected<ViewTransitionContentElement>(
parent, pseudo_id, view_transition_name, snapshot_id,
/*is_live_content_element=*/false, this);
- pseudo_element->SetIntrinsicSize(captured_rect, border_box_rect);
+ pseudo_element->SetIntrinsicSize(
+ captured_rect, border_box_rect,
+ element_data->ShouldPropagateVisualOverflowRectAsMaxExtentsRect());
return pseudo_element;
}
@@ -1263,7 +1319,9 @@
auto* pseudo_element = MakeGarbageCollected<ViewTransitionContentElement>(
parent, pseudo_id, view_transition_name, snapshot_id,
/*is_live_content_element=*/true, this);
- pseudo_element->SetIntrinsicSize(captured_rect, border_box_rect);
+ pseudo_element->SetIntrinsicSize(
+ captured_rect, border_box_rect,
+ element_data->ShouldPropagateVisualOverflowRectAsMaxExtentsRect());
return pseudo_element;
}
@@ -1355,8 +1413,9 @@
auto layout_view_size = PhysicalSize(GetSnapshotRootSize());
auto layout_view_size_in_css_space = layout_view_size;
layout_view_size_in_css_space.Scale(1 / device_pixel_ratio_);
- container_properties =
- ContainerProperties(layout_view_size_in_css_space, gfx::Transform());
+ container_properties = ContainerProperties{
+ PhysicalRect(PhysicalOffset(), layout_view_size_in_css_space),
+ gfx::Transform()};
visual_overflow_rect_in_layout_space.size = layout_view_size;
} else {
ComputeLiveElementGeometry(
@@ -1432,7 +1491,10 @@
auto border_box_rect =
element_data->GetBorderBoxRect(use_cached_data, device_pixel_ratio_);
static_cast<ViewTransitionContentElement*>(pseudo_element)
- ->SetIntrinsicSize(captured_rect, border_box_rect);
+ ->SetIntrinsicSize(
+ captured_rect, border_box_rect,
+ element_data
+ ->ShouldPropagateVisualOverflowRectAsMaxExtentsRect());
}
// Ensure that the cached state stays in sync with the current state while
@@ -1490,6 +1552,19 @@
auto snapshot_matrix_in_css_space = snapshot_matrix_in_layout_space;
snapshot_matrix_in_css_space.Zoom(1.0 / device_pixel_ratio_);
+ PhysicalOffset offset_in_css_space;
+ if (RuntimeEnabledFeatures::ViewTransitionOverflowRectFromSurfaceEnabled()) {
+ // In this mode, the max extents rect (the capture rect we guess here) and
+ // the border box are in the enclosing layer coordinate space. That's a more
+ // convenient coordinate space than the element's own space as it matches
+ // CC's coordinate space (e.g. RenderSurfaceImpl::content_rect()).
+ if (auto* layout_inline = DynamicTo<LayoutInline>(layout_object)) {
+ offset_in_css_space = layout_inline->PhysicalLinesBoundingBox().offset;
+ }
+
+ offset_in_css_space.Scale(1.f / device_pixel_ratio_);
+ }
+
PhysicalSize border_box_size_in_css_space;
if (layout_object.IsSVGChild() || IsA<LayoutBox>(layout_object)) {
// ResizeObserverEntry is created to reuse the logic for parsing object
@@ -1534,8 +1609,9 @@
max_capture_size, visual_overflow_rect_in_layout_space,
snapshot_matrix_in_layout_space, *snapshot_root_layout_size_at_capture_);
- container_properties = ContainerProperties(border_box_size_in_css_space,
- snapshot_matrix_in_css_space);
+ container_properties = ContainerProperties{
+ PhysicalRect(offset_in_css_space, border_box_size_in_css_space),
+ snapshot_matrix_in_css_space};
}
bool ViewTransitionStyleTracker::HasActiveAnimations() const {
@@ -1778,12 +1854,13 @@
auto& element = transition_state.elements.emplace_back();
element.tag_name = entry.key.Utf8();
- element.border_box_size_in_css_space = gfx::SizeF(
- element_data->container_properties[0].border_box_size_in_css_space);
+ element.border_box_rect_in_enclosing_layer_css_space = gfx::RectF(
+ element_data->container_properties[0].border_box_rect_in_css_space);
element.viewport_matrix =
element_data->container_properties[0].snapshot_matrix;
element.overflow_rect_in_layout_space =
gfx::RectF(element_data->visual_overflow_rect_in_layout_space);
+
element.snapshot_id = element_data->old_snapshot_id;
element.paint_order = element_data->element_index;
element.captured_rect_in_layout_space =
@@ -2028,6 +2105,10 @@
gfx::RectF ViewTransitionStyleTracker::ElementData::GetCapturedSubrect(
bool use_cached_data) const {
+ if (RuntimeEnabledFeatures::ViewTransitionOverflowRectFromSurfaceEnabled() &&
+ use_cached_data) {
+ return GetInkOverflowRect(true);
+ }
auto captured_rect = use_cached_data ? cached_captured_rect_in_layout_space
: captured_rect_in_layout_space;
return captured_rect.value_or(GetInkOverflowRect(use_cached_data));
@@ -2040,12 +2121,19 @@
if (!use_cached_data && container_properties.size() == 0) {
return gfx::RectF();
}
- PhysicalSize border_box_size_in_layout_space =
+ auto border_box_rect_in_layout_space =
use_cached_data
- ? cached_container_properties.border_box_size_in_css_space
- : container_properties.back().border_box_size_in_css_space;
- border_box_size_in_layout_space.Scale(device_scale_factor);
- return gfx::RectF(gfx::SizeF(border_box_size_in_layout_space));
+ ? cached_container_properties.border_box_rect_in_css_space
+ : container_properties.back().border_box_rect_in_css_space;
+ border_box_rect_in_layout_space.Scale(device_scale_factor);
+ return gfx::RectF(border_box_rect_in_layout_space);
+}
+
+bool ViewTransitionStyleTracker::ElementData::
+ ShouldPropagateVisualOverflowRectAsMaxExtentsRect() const {
+ return RuntimeEnabledFeatures::
+ ViewTransitionOverflowRectFromSurfaceEnabled() &&
+ target_element && !target_element->IsDocumentElement();
}
void ViewTransitionStyleTracker::ElementData::CacheStateForOldSnapshot() {
@@ -2077,6 +2165,25 @@
LayoutBoxModelObject& box,
const LayoutBoxModelObject* ancestor) const {
DCHECK(!box.IsLayoutView());
+ if (RuntimeEnabledFeatures::ViewTransitionOverflowRectFromSurfaceEnabled()) {
+ // In this mode, we don't try to compute the pixel-precise capture rect.
+ // Instead, we compute the max extents: a rect that's close enough to that
+ // rect and contains it. This rect is used for clipping computation in CC.
+ // When displaying live content, ViewTransitionContentImpl would later
+ // "correct" this rect to the actual capture rect that's computed inside CC.
+ // Note that this rect is in enclosing layer space, to match the CC
+ // coordinate space. So the border box rect also has to be in the same
+ // coordinate space.
+ auto rect = box.EnclosingLayer()
+ ->LocalBoundingBoxIncludingSelfPaintingDescendants();
+ if (!RuntimeEnabledFeatures::ViewTransitionLayeredCaptureEnabled()) {
+ rect = box.ApplyFiltersToRect(rect);
+ }
+
+ // Correct for fractional offset.
+ rect.Move(box.FirstFragment().PaintOffset());
+ return PhysicalRect(ToEnclosingRect(rect));
+ }
if (ancestor) {
if (auto* element = DynamicTo<Element>(box.GetNode());
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.h b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.h
index 1e7585f..157b6827 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.h
+++ b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.h
@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_VIEW_TRANSITION_VIEW_TRANSITION_STYLE_TRACKER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_VIEW_TRANSITION_VIEW_TRANSITION_STYLE_TRACKER_H_
+#include <unordered_map>
+
#include "base/containers/flat_map.h"
#include "base/unguessable_token.h"
#include "cc/layers/view_transition_content_layer.h"
@@ -59,20 +61,16 @@
public:
// Properties that transition on container elements.
struct ContainerProperties {
- ContainerProperties() = default;
- ContainerProperties(const PhysicalSize& size, const gfx::Transform& matrix)
- : border_box_size_in_css_space(size), snapshot_matrix(matrix) {}
-
bool operator==(const ContainerProperties& other) const {
- return border_box_size_in_css_space ==
- other.border_box_size_in_css_space &&
+ return border_box_rect_in_css_space ==
+ other.border_box_rect_in_css_space &&
snapshot_matrix == other.snapshot_matrix;
}
bool operator!=(const ContainerProperties& other) const {
return !(*this == other);
}
- PhysicalSize border_box_size_in_css_space;
+ PhysicalRect border_box_rect_in_css_space;
// Transforms a point from local space into the snapshot viewport. For
// details of the snapshot viewport, see README.md.
@@ -96,9 +94,13 @@
// set elements and names is valid. Returns true if capture phase started,
// and false if the transition should be aborted. If `snap_browser_controls`
// is set, browser controls will be forced to a fully shown state to ensure a
- // consistent state for cross-document transitions.
+ // consistent state for cross-document transitiopns.
bool Capture(bool snap_browser_controls);
+ void SetCaptureRectsFromCompositor(
+ const std::unordered_map<viz::ViewTransitionElementResourceId,
+ gfx::RectF>&);
+
// Notifies when caching snapshots for elements in the old DOM finishes. This
// is dispatched before script is notified to ensure this class releases any
// references to elements in the old DOM before it is mutated by script.
@@ -239,6 +241,8 @@
gfx::RectF GetBorderBoxRect(bool use_cached_data,
float device_scale_factor) const;
+ bool ShouldPropagateVisualOverflowRectAsMaxExtentsRect() const;
+
// Caches the current state for the old snapshot.
void CacheStateForOldSnapshot();
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 7ff3f25f..7932100 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4469,7 +4469,7 @@
},
{
name: "ViewTransitionLayeredCapture",
- status: "experimental",
+ status: "test",
},
{
name: "ViewTransitionLongCallbackTimeoutForTesting",
@@ -4487,6 +4487,10 @@
status: "stable",
},
{
+ name: "ViewTransitionOverflowRectFromSurface",
+ status: "test",
+ },
+ {
name: "ViewTransitionTreeScopedNames",
status: "stable",
},
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html
new file mode 100644
index 0000000..69ed62d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: inline child with overflowing shadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+body {
+ background: rebeccapurple;
+ margin: 0;
+}
+
+.target {
+ width: 100px;
+ height: 200px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ font-size: 100px;
+ box-shadow: -20px -20px yellow;
+}
+</style>
+
+<div class=target>
+ <span class=child> </span>
+</div>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow.html
new file mode 100644
index 0000000..2c2d50a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-overflow-shadow.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: inline child with overflowing shadow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="match" href="inline-child-with-overflow-shadow-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+::view-transition { background: rebeccapurple; }
+body {
+ margin: 0;
+}
+
+.target {
+ width: 100px;
+ height: 200px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ view-transition-name: target;
+}
+
+.child {
+ background: green;
+ font-size: 100px;
+ box-shadow: -20px -20px yellow;
+}
+
+html::view-transition-group(target) {
+ animation-play-state: paused;
+ }
+html::view-transition-old(target),
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-old(target) {
+ opacity: 0;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden }
+</style>
+
+<div class=target>
+ <span class=child> </span>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-with-offset-from-containing-block.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-with-offset-from-containing-block.html
index 026ecb24..6bbb8b49 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-with-offset-from-containing-block.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-with-offset-from-containing-block.html
@@ -4,7 +4,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
<link rel="author" href="mailto:khushalsagar@chromium.org">
<link rel="match" href="inline-with-offset-from-containing-block-ref.html">
-<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1400">
+<meta name="fuzzy" content="maxDifference=0-255; totalPixels=0-1500">
<script src="/common/reftest-wait.js"></script>
<script src="/common/rendering-utils.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow-ref.html
new file mode 100644
index 0000000..a05172f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<title>View transitions: nested named element in overflow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+body {
+ background: rebeccapurple;
+ margin: 0;
+}
+.outer {
+ width: 50px;
+ height: 100px;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ border: 2px solid black;
+}
+.inner {
+ background: lightblue;
+ width: 50px;
+ height: 50px;
+ view-transition-name: outer;
+ position: absolute;
+ top: 25px;
+}
+.grey {
+ background: lightgrey;
+ position: relative;
+ width: 50px;
+ height: 50px;
+}
+</style>
+<div class="outer">
+ <div class="inner"></div>
+</div>
+<div class="grey"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow.html
new file mode 100644
index 0000000..cce8fe8d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nested-elements-in-overflow.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<meta name="timeout" content="long">
+<title>View transitions: nested named element in overflow</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+<link rel="match" href="nested-elements-in-overflow-ref.html">
+<meta name="fuzzy" content="maxDifference=0-60; totalPixels=0-500">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root {
+ view-transition-name: none;
+}
+
+.outer {
+ background: lightblue;
+ width: 100px;
+ height: 100px;
+ view-transition-name: outer;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+}
+.inner {
+ background: lightgrey;
+ position: relative;
+ top: -50px;
+ left: -50px;
+ width: 50px;
+ height: 50px;
+ view-transition-name: inner;
+}
+
+::view-transition { background: rebeccapurple; }
+::view-transition-group(*) {
+ animation-duration: 300s;
+}
+::view-transition-group(outer) {
+ width: 50px;
+ height: 100px;
+ border: 2px solid black;
+ animation: none;
+}
+::view-transition-new(*),
+::view-transition-old(*) {
+ position: absolute;
+ inset-block-start: unset;
+ inline-size: 100%;
+ block-size: 100%;
+ object-fit: contain;
+}
+::view-transition-old(*) {
+ opacity: 0;
+ animation: none;
+}
+::view-transition-new(*) {
+ opacity: 1;
+ animation: none;
+}
+</style>
+<div class="outer">
+ <div class="inner"></div>
+</div>
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition().ready.then(takeScreenshot);
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html
index f23f63d..7245e4b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html
@@ -4,7 +4,7 @@
<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
<link rel="author" href="mailto:vmpstr@chromium.org">
<link rel="match" href="new-and-old-sizes-match-ref.html">
-<meta name="fuzzy" content="maxDifference=0-15; totalPixels=0-500">
+<meta name="fuzzy" content="maxDifference=0-25; totalPixels=0-1500">
<script src="/common/reftest-wait.js"></script>
<style>
.box {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background-ref.html
new file mode 100644
index 0000000..7c7ee53
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<style>
+:root { background: rebeccapurple; }
+.target {
+ width: 200px;
+ height: 200px;
+ contain: paint;
+ view-transition-name: target;
+ padding: 20px;
+}
+
+.child {
+ width: 100px;
+ height: 200px;
+ position: relative;
+ background: green;
+}
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background.html
new file mode 100644
index 0000000..6bbcf51
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/outer-padding-inner-background.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: named element has padding, inner element has background</title>
+<link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
+<link rel="match" href="outer-padding-inner-background-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+:root { view-transition-name: none; }
+::view-transition { background: rebeccapurple; }
+.target {
+ width: 200px;
+ height: 200px;
+ view-transition-name: target;
+ padding: 20px;
+}
+
+.child {
+ width: 100px;
+ height: 100px;
+ position: relative;
+ background: green;
+}
+
+html::view-transition-group(target) {
+ animation-play-state: paused;
+ }
+html::view-transition-old(target),
+html::view-transition-new(target) {
+ animation: unset;
+ opacity: 1;
+}
+
+html::view-transition-new(target) {
+ position: relative;
+ top: 100px;
+}
+
+/* None of these should apply, so make everything red if it does */
+html::view-transition-group(root) { animation: unset; opacity: 1; background: red; }
+html::view-transition-image-pair(root) { visibility: hidden }
+</style>
+
+<div class=target>
+ <div class=child>
+ </div>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+ document.startViewTransition(() =>
+ requestAnimationFrame(() => requestAnimationFrame(takeScreenshot)));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-new.html b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-new.html
new file mode 100644
index 0000000..f3009908
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-new.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>View transitions: browser controls should not affect root layer position</title>
+ <link rel="match" href="browser-controls-root-offset-ref.html">
+ <meta name="viewport" content="width=400">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ body {
+ background-color: cornflowerblue;
+ margin: 0;
+ }
+ #wideElement {
+ position: absolute;
+ top: 20px;
+ left: 0;
+ /* Double the width of the initial-containing-block */
+ width: 800px;
+ height: 100px;
+ background-color: limegreen;
+ }
+ .corner {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background-color: coral;
+ }
+ .transitioned .corner {
+ background-color: darkseagreen;
+ }
+ ::view-transition-group(*),
+ ::view-transition-new(*),
+ ::view-transition-old(*) {
+ animation-play-state: paused;
+ }
+ ::view-transition-old(*) {
+ display: none;
+ }
+ ::view-transition-new(*) {
+ animation-name: none;
+ opacity: 1;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="corner" style="top: 0; right: 0; view-transition-name:topright;"></div>
+ <div id="wideElement"></div>
+ <script>
+ internals.setBrowserControlsState(20, 0, true);
+ requestAnimationFrame(() => {
+ document.startViewTransition().ready.then(() => takeScreenshot());
+ });
+ </script>
+ </body>
+</html>
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-old.html b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-old.html
new file mode 100644
index 0000000..eded0790
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-old.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>View transitions: browser controls should not affect root layer position</title>
+ <link rel="match" href="browser-controls-root-offset-ref.html">
+ <meta name="viewport" content="width=400">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ body {
+ background-color: cornflowerblue;
+ margin: 0;
+ }
+ #wideElement {
+ position: absolute;
+ top: 20px;
+ left: 0;
+ /* Double the width of the initial-containing-block */
+ width: 800px;
+ height: 100px;
+ background-color: limegreen;
+ }
+ .corner {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background-color: coral;
+ }
+ .transitioned .corner {
+ background-color: darkseagreen;
+ }
+ ::view-transition-group(*),
+ ::view-transition-new(*),
+ ::view-transition-old(*) {
+ animation-play-state: paused;
+ }
+ ::view-transition-new(*) {
+ display: none;
+ }
+ ::view-transition-old(*) {
+ animation-name: none;
+ opacity: 1;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="corner" style="top: 0; right: 0; view-transition-name:topright;"></div>
+ <div id="wideElement"></div>
+ <script>
+ internals.setBrowserControlsState(20, 0, true);
+ requestAnimationFrame(() => {
+ document.startViewTransition().ready.then(() => takeScreenshot());
+ });
+ </script>
+ </body>
+</html>
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-ref.html b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-ref.html
new file mode 100644
index 0000000..8938b26
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/view-transition/browser-controls-root-offset-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>View transitions: page scale factor should not distort capture</title>
+ <meta name="viewport" content="width=400">
+ <script src="/common/reftest-wait.js"></script>
+ <style>
+ body {
+ background-color: cornflowerblue;
+ }
+ #wideElement {
+ position: absolute;
+ top: 20px;
+ left: 0;
+ /* Double the width of the initial-containing-block */
+ width: 800px;
+ height: 100px;
+ background-color: limegreen;
+ }
+ .corner {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background-color: coral;
+ }
+ .transitioned .corner {
+ background-color: darkseagreen;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="wideElement"></div>
+ <div class="corner" style="top: 0; right: 0;"></div>
+ <script>
+ internals.setBrowserControlsState(20, 0, true);
+ requestAnimationFrame(() => {
+ takeScreenshot();
+ });
+ </script>
+ </body>
+</html>