Commit 96555335 authored by Sahir Vellani's avatar Sahir Vellani Committed by Commit Bot

Resize Observer - Simple content-box and border-box observations

It is possible to now observe changes to content box and border box of
an element that is being observed. However, changes to an element's
content box without a change in its border box can not be observed yet,
and will be addressed in a subsequent change.

Bug: 1042537
Change-Id: I6415fc4f5cec783cc717051c11b2fdd95d3a28e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2004051Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Reviewed-by: default avatarDaniel Libby <dlibby@microsoft.com>
Commit-Queue: Sahir Vellani <sahir.vellani@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#737369}
parent cfc72663
...@@ -3,20 +3,23 @@ ...@@ -3,20 +3,23 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/renderer/core/resize_observer/resize_observation.h" #include "third_party/blink/renderer/core/resize_observer/resize_observation.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h" #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h"
#include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h" #include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
namespace blink { namespace blink {
ResizeObservation::ResizeObservation(Element* target, ResizeObserver* observer) ResizeObservation::ResizeObservation(Element* target,
ResizeObserver* observer,
ResizeObserverBoxOptions observed_box)
: target_(target), : target_(target),
observer_(observer), observer_(observer),
observation_size_(0, 0), observation_size_(0, 0),
element_size_changed_(true) { element_size_changed_(true),
observed_box_(observed_box) {
DCHECK(target_); DCHECK(target_);
observer_->ElementSizeChanged(); observer_->ElementSizeChanged();
} }
...@@ -55,25 +58,29 @@ size_t ResizeObservation::TargetDepth() { ...@@ -55,25 +58,29 @@ size_t ResizeObservation::TargetDepth() {
LayoutSize ResizeObservation::ComputeTargetSize() const { LayoutSize ResizeObservation::ComputeTargetSize() const {
if (target_) { if (target_) {
if (LayoutObject* layout_object = target_->GetLayoutObject()) { if (LayoutObject* layout_object = target_->GetLayoutObject()) {
// https://drafts.csswg.org/resize-observer/#calculate-box-size states
// that the bounding box should be used for SVGGraphicsElements regardless
// of the observed box.
if (auto* svg_graphics_element = if (auto* svg_graphics_element =
DynamicTo<SVGGraphicsElement>(target_.Get())) { DynamicTo<SVGGraphicsElement>(target_.Get())) {
return LayoutSize(svg_graphics_element->GetBBox().Size()); return LayoutSize(svg_graphics_element->GetBBox().Size());
} }
if (layout_object->IsBox()) if (!layout_object->IsBox())
return ToLayoutBox(layout_object)->ContentSize(); return LayoutSize();
switch (observed_box_) {
case ResizeObserverBoxOptions::BorderBox:
return ToLayoutBox(layout_object)->BorderBoxRect().Size();
case ResizeObserverBoxOptions::ContentBox:
return ToLayoutBox(layout_object)->ContentSize();
default:
NOTREACHED();
}
} }
} }
return LayoutSize(); return LayoutSize();
} }
LayoutPoint ResizeObservation::ComputeTargetLocation() const {
if (target_ && !target_->IsSVGElement()) {
if (LayoutBox* layout = target_->GetLayoutBox())
return LayoutPoint(layout->PaddingLeft(), layout->PaddingTop());
}
return LayoutPoint();
}
void ResizeObservation::ElementSizeChanged() { void ResizeObservation::ElementSizeChanged() {
element_size_changed_ = true; element_size_changed_ = true;
observer_->ElementSizeChanged(); observer_->ElementSizeChanged();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVATION_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVATION_H_
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h" #include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
...@@ -13,14 +14,15 @@ ...@@ -13,14 +14,15 @@
namespace blink { namespace blink {
class Element; class Element;
class LayoutPoint;
class ResizeObserver; class ResizeObserver;
// ResizeObservation represents an element that is being observed. // ResizeObservation represents an element that is being observed.
class CORE_EXPORT ResizeObservation final class CORE_EXPORT ResizeObservation final
: public GarbageCollected<ResizeObservation> { : public GarbageCollected<ResizeObservation> {
public: public:
ResizeObservation(Element* target, ResizeObserver*); ResizeObservation(Element* target,
ResizeObserver*,
ResizeObserverBoxOptions observed_box);
Element* Target() const { return target_; } Element* Target() const { return target_; }
size_t TargetDepth(); size_t TargetDepth();
...@@ -28,9 +30,9 @@ class CORE_EXPORT ResizeObservation final ...@@ -28,9 +30,9 @@ class CORE_EXPORT ResizeObservation final
bool ObservationSizeOutOfSync(); bool ObservationSizeOutOfSync();
void SetObservationSize(const LayoutSize&); void SetObservationSize(const LayoutSize&);
void ElementSizeChanged(); void ElementSizeChanged();
ResizeObserverBoxOptions observedBox() const { return observed_box_; }
LayoutSize ComputeTargetSize() const; LayoutSize ComputeTargetSize() const;
LayoutPoint ComputeTargetLocation() const;
void Trace(blink::Visitor*); void Trace(blink::Visitor*);
...@@ -40,6 +42,7 @@ class CORE_EXPORT ResizeObservation final ...@@ -40,6 +42,7 @@ class CORE_EXPORT ResizeObservation final
// Target size sent in last observation notification. // Target size sent in last observation notification.
LayoutSize observation_size_; LayoutSize observation_size_;
bool element_size_changed_; bool element_size_changed_;
ResizeObserverBoxOptions observed_box_;
}; };
} // namespace blink } // namespace blink
......
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
#include "third_party/blink/renderer/core/resize_observer/resize_observation.h" #include "third_party/blink/renderer/core/resize_observer/resize_observation.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_options.h"
namespace blink { namespace blink {
constexpr const char* kBoxOptionBorderBox = "border-box";
constexpr const char* kBoxOptionContentBox = "content-box";
ResizeObserver* ResizeObserver::Create(Document& document, ResizeObserver* ResizeObserver::Create(Document& document,
V8ResizeObserverCallback* callback) { V8ResizeObserverCallback* callback) {
return MakeGarbageCollected<ResizeObserver>(callback, document); return MakeGarbageCollected<ResizeObserver>(callback, document);
...@@ -45,12 +49,38 @@ ResizeObserver::ResizeObserver(Delegate* delegate, Document& document) ...@@ -45,12 +49,38 @@ ResizeObserver::ResizeObserver(Delegate* delegate, Document& document)
controller_->AddObserver(*this); controller_->AddObserver(*this);
} }
void ResizeObserver::observe(Element* target) { ResizeObserverBoxOptions ResizeObserver::ParseBoxOptions(
const String& box_options) {
if (box_options == kBoxOptionBorderBox)
return ResizeObserverBoxOptions::BorderBox;
if (box_options == kBoxOptionContentBox)
return ResizeObserverBoxOptions::ContentBox;
return ResizeObserverBoxOptions::ContentBox;
}
void ResizeObserver::observeInternal(Element* target,
ResizeObserverBoxOptions box_option) {
auto& observer_map = target->EnsureResizeObserverData(); auto& observer_map = target->EnsureResizeObserverData();
if (observer_map.Contains(this))
return; // Already registered.
auto* observation = MakeGarbageCollected<ResizeObservation>(target, this); if (observer_map.Contains(this)) {
auto observation = observer_map.find(this);
if ((*observation).value->observedBox() == box_option)
return;
// Unobserve target if box_option has changed and target already existed. If
// there is an existing observation of a different box, this new observation
// takes precedence. See:
// https://drafts.csswg.org/resize-observer/#processing-model
observations_.erase((*observation).value);
auto index = active_observations_.Find((*observation).value);
if (index != kNotFound) {
active_observations_.EraseAt(index);
}
observer_map.erase(observation);
}
auto* observation =
MakeGarbageCollected<ResizeObservation>(target, this, box_option);
observations_.insert(observation); observations_.insert(observation);
observer_map.Set(this, observation); observer_map.Set(this, observation);
...@@ -58,6 +88,16 @@ void ResizeObserver::observe(Element* target) { ...@@ -58,6 +88,16 @@ void ResizeObserver::observe(Element* target) {
frame_view->ScheduleAnimation(); frame_view->ScheduleAnimation();
} }
void ResizeObserver::observe(Element* target,
const ResizeObserverOptions* options) {
ResizeObserverBoxOptions box_option = ParseBoxOptions(options->box());
observeInternal(target, box_option);
}
void ResizeObserver::observe(Element* target) {
observeInternal(target, ResizeObserverBoxOptions::ContentBox);
}
void ResizeObserver::unobserve(Element* target) { void ResizeObserver::unobserve(Element* target) {
auto* observer_map = target ? target->ResizeObserverData() : nullptr; auto* observer_map = target ? target->ResizeObserverData() : nullptr;
if (!observer_map) if (!observer_map)
...@@ -123,26 +163,9 @@ void ResizeObserver::DeliverObservations() { ...@@ -123,26 +163,9 @@ void ResizeObserver::DeliverObservations() {
if (!execution_context || execution_context->IsContextDestroyed()) if (!execution_context || execution_context->IsContextDestroyed())
continue; continue;
LayoutPoint location = observation->ComputeTargetLocation(); observation->SetObservationSize(observation->ComputeTargetSize());
LayoutSize size = observation->ComputeTargetSize(); auto* entry =
observation->SetObservationSize(size); MakeGarbageCollected<ResizeObserverEntry>(observation->Target());
LayoutRect content_rect(location, size);
if (observation->Target()->GetLayoutObject()) {
// Must adjust for zoom in order to report non-zoomed size.
const ComputedStyle& style =
observation->Target()->GetLayoutObject()->StyleRef();
content_rect.SetX(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.X(), style));
content_rect.SetY(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.Y(), style));
content_rect.SetWidth(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.Width(), style));
content_rect.SetHeight(AdjustForAbsoluteZoom::AdjustLayoutUnit(
content_rect.Height(), style));
}
auto* entry = MakeGarbageCollected<ResizeObserverEntry>(
observation->Target(), content_rect);
entries.push_back(entry); entries.push_back(entry);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
...@@ -19,6 +20,7 @@ class ResizeObserverController; ...@@ -19,6 +20,7 @@ class ResizeObserverController;
class ResizeObserverEntry; class ResizeObserverEntry;
class ResizeObservation; class ResizeObservation;
class V8ResizeObserverCallback; class V8ResizeObserverCallback;
class ResizeObserverOptions;
// ResizeObserver represents ResizeObserver javascript api: // ResizeObserver represents ResizeObserver javascript api:
// https://github.com/WICG/ResizeObserver/ // https://github.com/WICG/ResizeObserver/
...@@ -47,6 +49,7 @@ class CORE_EXPORT ResizeObserver final ...@@ -47,6 +49,7 @@ class CORE_EXPORT ResizeObserver final
~ResizeObserver() override = default; ~ResizeObserver() override = default;
// API methods // API methods
void observe(Element*, const ResizeObserverOptions* options);
void observe(Element*); void observe(Element*);
void unobserve(Element*); void unobserve(Element*);
void disconnect(); void disconnect();
...@@ -59,12 +62,16 @@ class CORE_EXPORT ResizeObserver final ...@@ -59,12 +62,16 @@ class CORE_EXPORT ResizeObserver final
void ElementSizeChanged(); void ElementSizeChanged();
bool HasElementSizeChanged() { return element_size_changed_; } bool HasElementSizeChanged() { return element_size_changed_; }
ResizeObserverBoxOptions ParseBoxOptions(const String& box_options);
// ScriptWrappable override: // ScriptWrappable override:
bool HasPendingActivity() const override; bool HasPendingActivity() const override;
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
private: private:
void observeInternal(Element* target, ResizeObserverBoxOptions box_option);
using ObservationList = HeapLinkedHashSet<WeakMember<ResizeObservation>>; using ObservationList = HeapLinkedHashSet<WeakMember<ResizeObservation>>;
// Either of |callback_| and |delegate_| should be non-null. // Either of |callback_| and |delegate_| should be non-null.
......
...@@ -13,7 +13,7 @@ callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, R ...@@ -13,7 +13,7 @@ callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, R
ActiveScriptWrappable ActiveScriptWrappable
] interface ResizeObserver { ] interface ResizeObserver {
[CallWith=Document, MeasureAs=ResizeObserver_Constructor] constructor(ResizeObserverCallback callback); [CallWith=Document, MeasureAs=ResizeObserver_Constructor] constructor(ResizeObserverCallback callback);
void observe(Element target); void observe(Element target, optional ResizeObserverOptions options);
void unobserve(Element target); void unobserve(Element target);
void disconnect(); void disconnect();
}; };
...@@ -5,7 +5,6 @@ namespace blink { ...@@ -5,7 +5,6 @@ namespace blink {
enum class ResizeObserverBoxOptions { enum class ResizeObserverBoxOptions {
BorderBox, BorderBox,
ContentBox, ContentBox,
DevicePixelContentBox
}; };
} }
......
...@@ -3,24 +3,88 @@ ...@@ -3,24 +3,88 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h"
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/geometry/dom_rect_read_only.h" #include "third_party/blink/renderer/core/geometry/dom_rect_read_only.h"
#include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observation.h" #include "third_party/blink/renderer/core/resize_observer/resize_observation.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_size.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_size.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink { namespace blink {
ResizeObserverEntry::ResizeObserverEntry(Element* target, DOMRectReadOnly* ResizeObserverEntry::ZoomAdjustedLayoutRect(
const LayoutRect& content_rect) LayoutRect content_rect,
: target_(target) { const ComputedStyle& style) {
content_rect_ = DOMRectReadOnly::FromFloatRect(FloatRect( content_rect.SetX(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.X(), style));
content_rect.SetY(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.Y(), style));
content_rect.SetWidth(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.Width(), style));
content_rect.SetHeight(
AdjustForAbsoluteZoom::AdjustLayoutUnit(content_rect.Height(), style));
return DOMRectReadOnly::FromFloatRect(FloatRect(
FloatPoint(content_rect.Location()), FloatSize(content_rect.Size()))); FloatPoint(content_rect.Location()), FloatSize(content_rect.Size())));
} }
ResizeObserverSize* ResizeObserverEntry::ZoomAdjustedSize(
const LayoutSize box_size,
const ComputedStyle& style) {
return ResizeObserverSize::Create(
AdjustForAbsoluteZoom::AdjustLayoutUnit(box_size.Width(), style),
AdjustForAbsoluteZoom::AdjustLayoutUnit(box_size.Height(), style));
}
ResizeObserverEntry::ResizeObserverEntry(Element* target) : target_(target) {
if (LayoutObject* layout_object = target->GetLayoutObject()) {
const ComputedStyle& style = layout_object->StyleRef();
// SVG box properties are always based on bounding box
if (auto* svg_graphics_element = DynamicTo<SVGGraphicsElement>(target)) {
LayoutSize bounding_box_size =
LayoutSize(svg_graphics_element->GetBBox().Size());
LayoutRect content_rect(LayoutPoint(), bounding_box_size);
content_rect_ = ZoomAdjustedLayoutRect(content_rect, style);
if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) {
content_box_size_ = ZoomAdjustedSize(bounding_box_size, style);
border_box_size_ = ZoomAdjustedSize(bounding_box_size, style);
}
} else {
LayoutBox* layout_box = target->GetLayoutBox();
LayoutRect content_rect(
LayoutPoint(layout_box->PaddingLeft(), layout_box->PaddingTop()),
layout_box->ContentSize());
content_rect_ = ZoomAdjustedLayoutRect(content_rect, style);
if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) {
LayoutSize content_box_size =
LayoutSize(layout_box->ContentLogicalWidth(),
layout_box->ContentLogicalHeight());
LayoutSize border_box_size =
LayoutSize(layout_box->LogicalWidth(), layout_box->LogicalHeight());
content_box_size_ = ZoomAdjustedSize(content_box_size, style);
border_box_size_ = ZoomAdjustedSize(border_box_size, style);
}
}
} else {
content_rect_ = DOMRectReadOnly::FromFloatRect(
FloatRect(FloatPoint(LayoutPoint()), FloatSize(LayoutSize())));
content_box_size_ = ResizeObserverSize::Create(0, 0);
border_box_size_ = ResizeObserverSize::Create(0, 0);
}
}
void ResizeObserverEntry::Trace(blink::Visitor* visitor) { void ResizeObserverEntry::Trace(blink::Visitor* visitor) {
visitor->Trace(target_); visitor->Trace(target_);
visitor->Trace(content_rect_); visitor->Trace(content_rect_);
visitor->Trace(content_box_size_);
visitor->Trace(border_box_size_);
ScriptWrappable::Trace(visitor); ScriptWrappable::Trace(visitor);
} }
......
...@@ -13,22 +13,34 @@ namespace blink { ...@@ -13,22 +13,34 @@ namespace blink {
class Element; class Element;
class DOMRectReadOnly; class DOMRectReadOnly;
class LayoutSize;
class ComputedStyle;
class ResizeObserverSize;
class LayoutRect; class LayoutRect;
class CORE_EXPORT ResizeObserverEntry final : public ScriptWrappable { class CORE_EXPORT ResizeObserverEntry final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
ResizeObserverEntry(Element* target, const LayoutRect& content_rect); ResizeObserverEntry(Element* target);
Element* target() const { return target_; } Element* target() const { return target_; }
DOMRectReadOnly* contentRect() const { return content_rect_; } DOMRectReadOnly* contentRect() const { return content_rect_; }
ResizeObserverSize* contentBoxSize() const { return content_box_size_; }
ResizeObserverSize* borderBoxSize() const { return border_box_size_; }
void Trace(blink::Visitor*) override; void Trace(blink::Visitor*) override;
private: private:
Member<Element> target_; Member<Element> target_;
Member<DOMRectReadOnly> content_rect_; Member<DOMRectReadOnly> content_rect_;
Member<ResizeObserverSize> content_box_size_;
Member<ResizeObserverSize> border_box_size_;
static DOMRectReadOnly* ZoomAdjustedLayoutRect(LayoutRect content_rect,
const ComputedStyle& style);
static ResizeObserverSize* ZoomAdjustedSize(const LayoutSize box_size,
const ComputedStyle& style);
}; };
} // namespace blink } // namespace blink
......
...@@ -8,4 +8,6 @@ ...@@ -8,4 +8,6 @@
interface ResizeObserverEntry { interface ResizeObserverEntry {
readonly attribute Element target; readonly attribute Element target;
readonly attribute DOMRectReadOnly contentRect; readonly attribute DOMRectReadOnly contentRect;
[RuntimeEnabled=ResizeObserverUpdates] readonly attribute ResizeObserverSize contentBoxSize;
[RuntimeEnabled=ResizeObserverUpdates] readonly attribute ResizeObserverSize borderBoxSize;
}; };
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// https://drafts.csswg.org/resize-observer/#enumdef-resizeobserverboxoptions // https://drafts.csswg.org/resize-observer/#enumdef-resizeobserverboxoptions
enum ResizeObserverBoxOptions { enum ResizeObserverBoxOptions {
"border-box", "content-box", "device-pixel-content-box" "border-box", "content-box"
}; };
// https://drafts.csswg.org/resize-observer/#dictdef-resizeobserveroptions // https://drafts.csswg.org/resize-observer/#dictdef-resizeobserveroptions
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observation.h" #include "third_party/blink/renderer/core/resize_observer/resize_observation.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
#include "third_party/blink/renderer/core/resize_observer/resize_observer_options.h"
#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h" #include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
...@@ -60,6 +62,7 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { ...@@ -60,6 +62,7 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
main_resource.Write(R"HTML( main_resource.Write(R"HTML(
<div id='domTarget' style='width:100px;height:100px'>yo</div> <div id='domTarget' style='width:100px;height:100px'>yo</div>
<div id='domBorderTarget' style='width:100px;height:100px;padding:5px'>yoyo</div>
<svg height='200' width='200'> <svg height='200' width='200'>
<circle id='svgTarget' cx='100' cy='100' r='100'/> <circle id='svgTarget' cx='100' cy='100' r='100'/>
</svg> </svg>
...@@ -70,14 +73,19 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { ...@@ -70,14 +73,19 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument()); MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument());
ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate); ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate);
Element* dom_target = GetDocument().getElementById("domTarget"); Element* dom_target = GetDocument().getElementById("domTarget");
Element* dom_border_target = GetDocument().getElementById("domBorderTarget");
Element* svg_target = GetDocument().getElementById("svgTarget"); Element* svg_target = GetDocument().getElementById("svgTarget");
ResizeObservation* dom_observation = ResizeObservation* dom_observation = MakeGarbageCollected<ResizeObservation>(
MakeGarbageCollected<ResizeObservation>(dom_target, observer); dom_target, observer, ResizeObserverBoxOptions::ContentBox);
ResizeObservation* svg_observation = ResizeObservation* dom_border_observation =
MakeGarbageCollected<ResizeObservation>(svg_target, observer); MakeGarbageCollected<ResizeObservation>(
dom_border_target, observer, ResizeObserverBoxOptions::BorderBox);
ResizeObservation* svg_observation = MakeGarbageCollected<ResizeObservation>(
svg_target, observer, ResizeObserverBoxOptions::ContentBox);
// Initial observation is out of sync // Initial observation is out of sync
ASSERT_TRUE(dom_observation->ObservationSizeOutOfSync()); ASSERT_TRUE(dom_observation->ObservationSizeOutOfSync());
ASSERT_TRUE(dom_border_observation->ObservationSizeOutOfSync());
ASSERT_TRUE(svg_observation->ObservationSizeOutOfSync()); ASSERT_TRUE(svg_observation->ObservationSizeOutOfSync());
// Target size is correct // Target size is correct
...@@ -86,6 +94,11 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { ...@@ -86,6 +94,11 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
ASSERT_EQ(size.Height(), 100); ASSERT_EQ(size.Height(), 100);
dom_observation->SetObservationSize(size); dom_observation->SetObservationSize(size);
size = dom_border_observation->ComputeTargetSize();
ASSERT_EQ(size.Width(), 110);
ASSERT_EQ(size.Height(), 110);
dom_border_observation->SetObservationSize(size);
size = svg_observation->ComputeTargetSize(); size = svg_observation->ComputeTargetSize();
ASSERT_EQ(size.Width(), 200); ASSERT_EQ(size.Width(), 200);
ASSERT_EQ(size.Height(), 200); ASSERT_EQ(size.Height(), 200);
...@@ -93,12 +106,47 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { ...@@ -93,12 +106,47 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) {
// Target size is in sync // Target size is in sync
ASSERT_FALSE(dom_observation->ObservationSizeOutOfSync()); ASSERT_FALSE(dom_observation->ObservationSizeOutOfSync());
ASSERT_FALSE(dom_border_observation->ObservationSizeOutOfSync());
// Target depths // Target depths
ASSERT_EQ(svg_observation->TargetDepth() - dom_observation->TargetDepth(), ASSERT_EQ(svg_observation->TargetDepth() - dom_observation->TargetDepth(),
(size_t)1); (size_t)1);
} }
// Test whether a new observation is created when an observation's
// observed box is changed
TEST_F(ResizeObserverUnitTest, TestBoxOverwrite) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Write(R"HTML(
<div id='domTarget' style='width:100px;height:100px'>yo</div>
<svg height='200' width='200'>
<circle id='svgTarget' cx='100' cy='100' r='100'/>
</svg>
)HTML");
main_resource.Finish();
ResizeObserverOptions* border_box_option = ResizeObserverOptions::Create();
border_box_option->setBox("border-box");
ResizeObserver::Delegate* delegate =
MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument());
ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate);
Element* dom_target = GetDocument().getElementById("domTarget");
// Assert no observations (depth returned is kDepthBottom)
size_t min_observed_depth = ResizeObserverController::kDepthBottom;
ASSERT_EQ(observer->GatherObservations(0), min_observed_depth);
observer->observe(dom_target);
// 3 is Depth of observed element
ASSERT_EQ(observer->GatherObservations(0), (size_t)3);
observer->observe(dom_target, border_box_option);
// Active observations should be empty and GatherObservations should run
ASSERT_EQ(observer->GatherObservations(0), (size_t)3);
}
TEST_F(ResizeObserverUnitTest, TestMemoryLeaks) { TEST_F(ResizeObserverUnitTest, TestMemoryLeaks) {
ResizeObserverController& controller = ResizeObserverController& controller =
GetDocument().EnsureResizeObserverController(); GetDocument().EnsureResizeObserverController();
......
...@@ -9,12 +9,12 @@ PASS test4: unobserve target stops notifications, unobserve non-observed does no ...@@ -9,12 +9,12 @@ PASS test4: unobserve target stops notifications, unobserve non-observed does no
PASS test5: observe img PASS test5: observe img
PASS test6: iframe notifications PASS test6: iframe notifications
PASS test7: callback.this PASS test7: callback.this
FAIL test8: simple content-box observation Cannot read property 'inlineSize' of undefined PASS test8: simple content-box observation
FAIL test9: simple content-box observation but keep border-box size unchanged Cannot read property 'inlineSize' of undefined FAIL test9: simple content-box observation but keep border-box size unchanged assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code
FAIL test10: simple border-box observation Cannot read property 'inlineSize' of undefined PASS test10: simple border-box observation
FAIL test11: simple observation with vertical writing mode Cannot read property 'inlineSize' of undefined PASS test11: simple observation with vertical writing mode
FAIL test12: no observation is fired after the change of writing mode when box's specified size comes from logical size properties. Cannot read property 'inlineSize' of undefined FAIL test12: no observation is fired after the change of writing mode when box's specified size comes from logical size properties. assert_unreached: the logical size of content-box doesn't change Reached unreachable code
FAIL test13: an observation is fired after the change of writing mode when box's specified size comes from physical size properties. Cannot read property 'inlineSize' of undefined FAIL test13: an observation is fired after the change of writing mode when box's specified size comes from physical size properties. assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code
FAIL test14: observe the same target but using a different box should override the previous one Cannot read property 'inlineSize' of undefined PASS test14: observe the same target but using a different box should override the previous one
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -104,7 +104,9 @@ ResizeTestHelper.prototype = { ...@@ -104,7 +104,9 @@ ResizeTestHelper.prototype = {
this._currentStep.timeout(); this._currentStep.timeout();
} }
else { else {
assert_unreached("Timed out waiting for notification. (" + ResizeTestHelper.TIMEOUT + "ms)"); this._harnessTest.step(() => {
assert_unreached("Timed out waiting for notification. (" + ResizeTestHelper.TIMEOUT + "ms)");
});
} }
this._nextStep(); this._nextStep();
}); });
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
<polyline points="0,300 100,300 50,350" style="fill:orange;stroke:black;stroke-width:1"/> <polyline points="0,300 100,300 50,350" style="fill:orange;stroke:black;stroke-width:1"/>
<rect x="0" y="380" width="10" height="10" style="fill:orange; stroke:black; stroke-width:1" /> <rect x="0" y="380" width="10" height="10" style="fill:orange; stroke:black; stroke-width:1" />
<text x="0" y="400" font-size="20">svg text tag</text> <text x="0" y="400" font-size="20">svg text tag</text>
<g fill="white" stroke="green" stroke-width="5">
<rect x="0" y="380" width="50" height="20" id="g_rect" />
</g>
</svg> </svg>
<script> <script>
'use strict'; 'use strict';
...@@ -363,6 +366,105 @@ function test11() { ...@@ -363,6 +366,105 @@ function test11() {
return helper.start(() => svg.remove()); return helper.start(() => svg.remove());
} }
function test12() {
let target = document.querySelector('rect');
let helper = new ResizeTestHelper(
"test12: observe svg:rect content box",
[
{
setup: observer => {
observer.observe(target);
},
notify: (entries, observer) => {
return true; // Delay next step
}
},
{
setup: observer => {
target.setAttribute('width', 45);
},
notify: (entries, observer) => {
assert_equals(entries.length, 1);
assert_equals(entries[0].contentRect.width, 45);
assert_equals(entries[0].contentRect.height, 10);
assert_equals(entries[0].contentBoxSize.inlineSize, 45);
assert_equals(entries[0].contentBoxSize.blockSize, 10);
}
}
]);
return helper.start();
}
function test13() {
let target = document.querySelector('rect');
let helper = new ResizeTestHelper(
"test13: observe svg:circle border box",
[
{
setup: observer => {
observer.observe(target);
},
notify: (entries, observer) => {
return true; // Delay next step
}
},
{
setup: observer => {
target.setAttribute('width', 20);
target.setAttribute('height', 20);
},
notify: (entries, observer) => {
assert_equals(entries.length, 1);
assert_equals(entries[0].contentRect.width, 20);
assert_equals(entries[0].contentRect.height, 20);
assert_equals(entries[0].contentBoxSize.inlineSize, 20);
assert_equals(entries[0].contentBoxSize.blockSize, 20);
assert_equals(entries[0].borderBoxSize.inlineSize, 20);
assert_equals(entries[0].borderBoxSize.blockSize, 20);
}
}
]);
return helper.start();
}
function test14() {
let target = document.querySelector('#g_rect');
let helper = new ResizeTestHelper(
"test14: observe g:rect content and border box",
[
{
setup: observer => {
observer.observe(target);
},
notify: (entries, observer) => {
assert_equals(entries.length, 1);
assert_equals(entries[0].contentRect.width, 50);
assert_equals(entries[0].contentRect.height, 20);
assert_equals(entries[0].contentBoxSize.inlineSize, 50);
assert_equals(entries[0].contentBoxSize.blockSize, 20);
assert_equals(entries[0].borderBoxSize.inlineSize, 50);
assert_equals(entries[0].borderBoxSize.blockSize, 20);
return true; // Delay next step
}
},
{
setup: observer => {
target.setAttribute('width', 15);
},
notify: (entries, observer) => {
assert_equals(entries.length, 1);
assert_equals(entries[0].contentRect.width, 15);
assert_equals(entries[0].contentRect.height, 20);
assert_equals(entries[0].contentBoxSize.inlineSize, 15);
assert_equals(entries[0].contentBoxSize.blockSize, 20);
assert_equals(entries[0].borderBoxSize.inlineSize, 15);
assert_equals(entries[0].borderBoxSize.blockSize, 20);
}
}
]);
return helper.start();
}
let guard; let guard;
test(_ => { test(_ => {
assert_own_property(window, "ResizeObserver"); assert_own_property(window, "ResizeObserver");
...@@ -381,6 +483,9 @@ test0() ...@@ -381,6 +483,9 @@ test0()
.then(() => { return test9(); }) .then(() => { return test9(); })
.then(() => { return test10(); }) .then(() => { return test10(); })
.then(() => { return test11(); }) .then(() => { return test11(); })
.then(() => { return test12(); })
.then(() => { return test13(); })
.then(() => { return test14(); })
.then(() => { guard.done(); }); .then(() => { guard.done(); });
</script> </script>
...@@ -6634,6 +6634,8 @@ interface ResizeObserver ...@@ -6634,6 +6634,8 @@ interface ResizeObserver
method unobserve method unobserve
interface ResizeObserverEntry interface ResizeObserverEntry
attribute @@toStringTag attribute @@toStringTag
getter borderBoxSize
getter contentBoxSize
getter contentRect getter contentRect
getter target getter target
method constructor method constructor
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment