SVG Text NG: Fix text layout after <svg> transform change
If 'transform' property of the owner <svg> is changed, and <text> is painted without laying out, the content was painted at a wrong position because the <text> kept positions computed with the old scaling factor. This CL fixes it by invalidating <text> layout on 'transform' changes on the owner <svg>. This CL is similar to crrev.com/942976 but for <svg>, not for containing blocks. Bug: 1271931 Change-Id: Iefc7d9b50a8474ed536be2267ad7e5e237ed2546 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3293550 Commit-Queue: Kent Tamura <tkent@chromium.org> Commit-Queue: Koji Ishii <kojii@chromium.org> Commit-Queue: Yoshifumi Inoue <yosin@chromium.org> Auto-Submit: Kent Tamura <tkent@chromium.org> Reviewed-by: Koji Ishii <kojii@chromium.org> Reviewed-by: Yoshifumi Inoue <yosin@chromium.org> Cr-Commit-Position: refs/heads/main@{#943987}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
8610693146
commit
00e19d90d3
third_party/blink
renderer
core
layout
web_tests
external
wpt
@@ -11,6 +11,7 @@
|
||||
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
|
||||
@@ -88,12 +89,25 @@ void LayoutNGSVGText::InsertedIntoTree() {
|
||||
LayoutNGBlockFlowMixin<LayoutSVGBlock>::InsertedIntoTree();
|
||||
for (LayoutBlock* cb = ContainingBlock(); cb; cb = cb->ContainingBlock())
|
||||
cb->AddSvgTextDescendant(*this);
|
||||
|
||||
for (auto* ancestor = Parent(); ancestor; ancestor = ancestor->Parent()) {
|
||||
if (auto* root = DynamicTo<LayoutSVGRoot>(ancestor)) {
|
||||
root->AddSvgTextDescendant(*this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutNGSVGText::WillBeRemovedFromTree() {
|
||||
NOT_DESTROYED();
|
||||
for (LayoutBlock* cb = ContainingBlock(); cb; cb = cb->ContainingBlock())
|
||||
cb->RemoveSvgTextDescendant(*this);
|
||||
for (auto* ancestor = Parent(); ancestor; ancestor = ancestor->Parent()) {
|
||||
if (auto* root = DynamicTo<LayoutSVGRoot>(ancestor)) {
|
||||
root->RemoveSvgTextDescendant(*this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
LayoutNGBlockFlowMixin<LayoutSVGBlock>::WillBeRemovedFromTree();
|
||||
}
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
|
||||
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
|
||||
#include "third_party/blink/renderer/core/layout/layout_view.h"
|
||||
#include "third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
|
||||
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
|
||||
@@ -70,6 +71,7 @@ LayoutSVGRoot::~LayoutSVGRoot() = default;
|
||||
|
||||
void LayoutSVGRoot::Trace(Visitor* visitor) const {
|
||||
visitor->Trace(content_);
|
||||
visitor->Trace(text_set_);
|
||||
LayoutReplaced::Trace(visitor);
|
||||
}
|
||||
|
||||
@@ -376,6 +378,15 @@ void LayoutSVGRoot::StyleDidChange(StyleDifference diff,
|
||||
|
||||
SVGResources::UpdateClipPathFilterMask(To<SVGSVGElement>(*GetNode()),
|
||||
old_style, StyleRef());
|
||||
|
||||
if (diff.TransformChanged()) {
|
||||
for (auto& svg_text : text_set_) {
|
||||
svg_text->SetNeedsLayout(layout_invalidation_reason::kStyleChange,
|
||||
kMarkContainerChain);
|
||||
svg_text->SetNeedsTextMetricsUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
if (!Parent())
|
||||
return;
|
||||
if (diff.HasDifference())
|
||||
@@ -588,6 +599,18 @@ void LayoutSVGRoot::NotifyDescendantCompositingReasonsChanged() {
|
||||
SetNeedsLayout(layout_invalidation_reason::kSvgChanged);
|
||||
}
|
||||
|
||||
void LayoutSVGRoot::AddSvgTextDescendant(LayoutNGSVGText& svg_text) {
|
||||
NOT_DESTROYED();
|
||||
DCHECK(!text_set_.Contains(&svg_text));
|
||||
text_set_.insert(&svg_text);
|
||||
}
|
||||
|
||||
void LayoutSVGRoot::RemoveSvgTextDescendant(LayoutNGSVGText& svg_text) {
|
||||
NOT_DESTROYED();
|
||||
DCHECK(text_set_.Contains(&svg_text));
|
||||
text_set_.erase(&svg_text);
|
||||
}
|
||||
|
||||
PaintLayerType LayoutSVGRoot::LayerTypeRequired() const {
|
||||
NOT_DESTROYED();
|
||||
auto layer_type_required = LayoutReplaced::LayerTypeRequired();
|
||||
|
@@ -28,6 +28,7 @@
|
||||
|
||||
namespace blink {
|
||||
|
||||
class LayoutNGSVGText;
|
||||
class SVGElement;
|
||||
enum class SVGTransformChange;
|
||||
|
||||
@@ -106,6 +107,9 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
|
||||
}
|
||||
void NotifyDescendantCompositingReasonsChanged();
|
||||
|
||||
void AddSvgTextDescendant(LayoutNGSVGText& svg_text);
|
||||
void RemoveSvgTextDescendant(LayoutNGSVGText& svg_text);
|
||||
|
||||
const char* GetName() const override {
|
||||
NOT_DESTROYED();
|
||||
return "LayoutSVGRoot";
|
||||
@@ -208,6 +212,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
|
||||
SVGContentContainer content_;
|
||||
LayoutSize container_size_;
|
||||
AffineTransform local_to_border_box_transform_;
|
||||
HeapHashSet<Member<LayoutNGSVGText>> text_set_;
|
||||
bool is_layout_size_changed_ : 1;
|
||||
bool did_screen_scale_factor_change_ : 1;
|
||||
bool needs_boundaries_or_transform_update_ : 1;
|
||||
|
4
third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html
vendored
4
third_party/blink/web_tests/external/wpt/svg/text/reftests/transform-dynamic-change-ref.html
vendored
@@ -7,5 +7,9 @@
|
||||
<text fill="red" style="font-size: 40px;" transform="matrix(1, 0, 0, 1, 468, 988)">A</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<svg width="500" height="400" style="transform-origin: 0px 0px; transform: scale(2) translate(-300px, -300px);">
|
||||
<text x="300" y="350" font-size="50" fill="green">PASS</text>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1270713">
|
||||
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1271931">
|
||||
<link rel="match" href="transform-dynamic-change-ref.html">
|
||||
<body>
|
||||
|
||||
@@ -11,11 +12,18 @@
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<svg id="svg2" width="500" height="400" style="transform-origin: 0px 0px; transform: translate(-300px, -300px);">
|
||||
<text x="300" y="350" id="text2" font-size="50">PASS</text>
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
document.getElementById('moveme').style.transform = 'matrix(0.9, 0, 0, 0.9, -210, -777)';
|
||||
document.getElementById('txt').style.fill = 'red';
|
||||
|
||||
document.getElementById('svg2').style.transform = 'scale(2) translate(-300px, -300px)';
|
||||
document.getElementById('text2').style.fill = 'green';
|
||||
document.documentElement.classList.remove('reftest-wait');
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user