diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/core/resize_observer | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/resize_observer')
17 files changed, 517 insertions, 134 deletions
diff --git a/chromium/third_party/blink/renderer/core/resize_observer/BUILD.gn b/chromium/third_party/blink/renderer/core/resize_observer/BUILD.gn index 6fb48dcfec6..94e42d6b0b3 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/BUILD.gn +++ b/chromium/third_party/blink/renderer/core/resize_observer/BUILD.gn @@ -10,9 +10,12 @@ blink_core_sources("resize_observer") { "resize_observation.h", "resize_observer.cc", "resize_observer.h", + "resize_observer_box_options.h", "resize_observer_controller.cc", "resize_observer_controller.h", "resize_observer_entry.cc", "resize_observer_entry.h", + "resize_observer_size.cc", + "resize_observer_size.h", ] } diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.cc index 855dbf5c50e..f6eb3c33a46 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.cc +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.cc @@ -3,26 +3,29 @@ // found in the LICENSE file. #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/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_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_graphics_element.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" namespace blink { -ResizeObservation::ResizeObservation(Element* target, ResizeObserver* observer) +ResizeObservation::ResizeObservation(Element* target, + ResizeObserver* observer, + ResizeObserverBoxOptions observed_box) : target_(target), observer_(observer), observation_size_(0, 0), - element_size_changed_(true) { + observed_box_(observed_box) { DCHECK(target_); - observer_->ElementSizeChanged(); } bool ResizeObservation::ObservationSizeOutOfSync() { - if (!element_size_changed_ || observation_size_ == ComputeTargetSize()) + if (observation_size_ == ComputeTargetSize()) return false; // Skip resize observations on locked elements. @@ -36,13 +39,6 @@ bool ResizeObservation::ObservationSizeOutOfSync() { void ResizeObservation::SetObservationSize(const LayoutSize& observation_size) { observation_size_ = observation_size; - - // Don't clear the dirty bit while locked. This allows us to make sure to - // compare sizes when becoming unlocked. - if (UNLIKELY(DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(*target_))) - return; - - element_size_changed_ = false; } size_t ResizeObservation::TargetDepth() { @@ -55,31 +51,52 @@ size_t ResizeObservation::TargetDepth() { LayoutSize ResizeObservation::ComputeTargetSize() const { if (target_) { 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 = DynamicTo<SVGGraphicsElement>(target_.Get())) { return LayoutSize(svg_graphics_element->GetBBox().Size()); } - if (layout_object->IsBox()) - return ToLayoutBox(layout_object)->ContentSize(); + if (!layout_object->IsBox()) + return LayoutSize(); + + if (LayoutBox* layout_box = ToLayoutBox(layout_object)) { + const ComputedStyle& style = layout_object->StyleRef(); + switch (observed_box_) { + case ResizeObserverBoxOptions::BorderBox: + return LayoutSize(AdjustForAbsoluteZoom::AdjustLayoutUnit( + layout_box->LogicalWidth(), style), + AdjustForAbsoluteZoom::AdjustLayoutUnit( + layout_box->LogicalHeight(), style)); + case ResizeObserverBoxOptions::ContentBox: + return LayoutSize(AdjustForAbsoluteZoom::AdjustLayoutUnit( + layout_box->ContentLogicalWidth(), style), + AdjustForAbsoluteZoom::AdjustLayoutUnit( + layout_box->ContentLogicalHeight(), style)); + case ResizeObserverBoxOptions::DevicePixelContentBox: { + LayoutSize paint_offset = + layout_object->FirstFragment().PaintOffset().ToLayoutSize(); + return LayoutSize( + SnapSizeToPixel(layout_box->ContentLogicalWidth(), + style.IsHorizontalWritingMode() + ? paint_offset.Width() + : paint_offset.Height()), + SnapSizeToPixel(layout_box->ContentLogicalHeight(), + style.IsHorizontalWritingMode() + ? paint_offset.Height() + : paint_offset.Width())); + } + default: + NOTREACHED(); + } + } } } 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() { - element_size_changed_ = true; - observer_->ElementSizeChanged(); -} - -void ResizeObservation::Trace(blink::Visitor* visitor) { +void ResizeObservation::Trace(Visitor* visitor) { visitor->Trace(target_); visitor->Trace(observer_); } diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.h index 444fd0ac83a..66c0ac6561c 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.h +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observation.h @@ -6,6 +6,7 @@ #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/resize_observer/resize_observer_box_options.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/heap/handle.h" @@ -13,33 +14,33 @@ namespace blink { class Element; -class LayoutPoint; class ResizeObserver; // ResizeObservation represents an element that is being observed. class CORE_EXPORT ResizeObservation final : public GarbageCollected<ResizeObservation> { public: - ResizeObservation(Element* target, ResizeObserver*); + ResizeObservation(Element* target, + ResizeObserver*, + ResizeObserverBoxOptions observed_box); Element* Target() const { return target_; } size_t TargetDepth(); // True if observationSize differs from target's current size. bool ObservationSizeOutOfSync(); void SetObservationSize(const LayoutSize&); - void ElementSizeChanged(); + ResizeObserverBoxOptions observedBox() const { return observed_box_; } LayoutSize ComputeTargetSize() const; - LayoutPoint ComputeTargetLocation() const; - void Trace(blink::Visitor*); + void Trace(Visitor*); private: WeakMember<Element> target_; Member<ResizeObserver> observer_; // Target size sent in last observation notification. LayoutSize observation_size_; - bool element_size_changed_; + ResizeObserverBoxOptions observed_box_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.cc index 831ac96a5de..2290704ac1d 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.cc +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/resize_observer/resize_observer.h" #include "third_party/blink/renderer/bindings/core/v8/v8_resize_observer_callback.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_resize_observer_options.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h" @@ -15,6 +16,11 @@ namespace blink { +constexpr const char* kBoxOptionBorderBox = "border-box"; +constexpr const char* kBoxOptionContentBox = "content-box"; +constexpr const char* kBoxOptionDevicePixelContentBox = + "device-pixel-content-box"; + ResizeObserver* ResizeObserver::Create(Document& document, V8ResizeObserverCallback* callback) { return MakeGarbageCollected<ResizeObserver>(callback, document); @@ -26,31 +32,57 @@ ResizeObserver* ResizeObserver::Create(Document& document, Delegate* delegate) { ResizeObserver::ResizeObserver(V8ResizeObserverCallback* callback, Document& document) - : ContextClient(&document), + : ExecutionContextClient(document.ToExecutionContext()), callback_(callback), - skipped_observations_(false), - element_size_changed_(false) { + skipped_observations_(false) { DCHECK(callback_); controller_ = &document.EnsureResizeObserverController(); controller_->AddObserver(*this); } ResizeObserver::ResizeObserver(Delegate* delegate, Document& document) - : ContextClient(&document), + : ExecutionContextClient(document.ToExecutionContext()), delegate_(delegate), - skipped_observations_(false), - element_size_changed_(false) { + skipped_observations_(false) { DCHECK(delegate_); controller_ = &document.EnsureResizeObserverController(); 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; + if (box_options == kBoxOptionDevicePixelContentBox) + return ResizeObserverBoxOptions::DevicePixelContentBox; + return ResizeObserverBoxOptions::ContentBox; +} + +void ResizeObserver::observeInternal(Element* target, + ResizeObserverBoxOptions box_option) { 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); observer_map.Set(this, observation); @@ -58,6 +90,16 @@ void ResizeObserver::observe(Element* target) { 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) { auto* observer_map = target ? target->ResizeObserverData() : nullptr; if (!observer_map) @@ -89,8 +131,6 @@ size_t ResizeObserver::GatherObservations(size_t deeper_than) { DCHECK(active_observations_.IsEmpty()); size_t min_observed_depth = ResizeObserverController::kDepthBottom; - if (!element_size_changed_) - return min_observed_depth; for (auto& observation : observations_) { if (!observation->ObservationSizeOutOfSync()) continue; @@ -106,9 +146,6 @@ size_t ResizeObserver::GatherObservations(size_t deeper_than) { } void ResizeObserver::DeliverObservations() { - // We can only clear this flag after all observations have been - // broadcast. - element_size_changed_ = skipped_observations_; if (active_observations_.IsEmpty()) return; @@ -123,26 +160,9 @@ void ResizeObserver::DeliverObservations() { if (!execution_context || execution_context->IsContextDestroyed()) continue; - LayoutPoint location = observation->ComputeTargetLocation(); - LayoutSize size = observation->ComputeTargetSize(); - observation->SetObservationSize(size); - - 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); + observation->SetObservationSize(observation->ComputeTargetSize()); + auto* entry = + MakeGarbageCollected<ResizeObserverEntry>(observation->Target()); entries.push_back(entry); } @@ -168,24 +188,18 @@ void ResizeObserver::ClearObservations() { skipped_observations_ = false; } -void ResizeObserver::ElementSizeChanged() { - element_size_changed_ = true; - if (controller_) - controller_->ObserverChanged(); -} - bool ResizeObserver::HasPendingActivity() const { return !observations_.IsEmpty(); } -void ResizeObserver::Trace(blink::Visitor* visitor) { +void ResizeObserver::Trace(Visitor* visitor) { visitor->Trace(callback_); visitor->Trace(delegate_); visitor->Trace(observations_); visitor->Trace(active_observations_); visitor->Trace(controller_); ScriptWrappable::Trace(visitor); - ContextClient::Trace(visitor); + ExecutionContextClient::Trace(visitor); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.h index 572f88ee1c4..8e8dd97ea24 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.h +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.h @@ -7,7 +7,8 @@ #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/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/execution_context/execution_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/heap/handle.h" @@ -19,13 +20,14 @@ class ResizeObserverController; class ResizeObserverEntry; class ResizeObservation; class V8ResizeObserverCallback; +class ResizeObserverOptions; // ResizeObserver represents ResizeObserver javascript api: // https://github.com/WICG/ResizeObserver/ class CORE_EXPORT ResizeObserver final : public ScriptWrappable, public ActiveScriptWrappable<ResizeObserver>, - public ContextClient { + public ExecutionContextClient { USING_GARBAGE_COLLECTED_MIXIN(ResizeObserver); DEFINE_WRAPPERTYPEINFO(); @@ -36,7 +38,7 @@ class CORE_EXPORT ResizeObserver final virtual ~Delegate() = default; virtual void OnResize( const HeapVector<Member<ResizeObserverEntry>>& entries) = 0; - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} }; static ResizeObserver* Create(Document&, V8ResizeObserverCallback*); @@ -47,6 +49,7 @@ class CORE_EXPORT ResizeObserver final ~ResizeObserver() override = default; // API methods + void observe(Element*, const ResizeObserverOptions* options); void observe(Element*); void unobserve(Element*); void disconnect(); @@ -56,15 +59,17 @@ class CORE_EXPORT ResizeObserver final bool SkippedObservations() { return skipped_observations_; } void DeliverObservations(); void ClearObservations(); - void ElementSizeChanged(); - bool HasElementSizeChanged() { return element_size_changed_; } + + ResizeObserverBoxOptions ParseBoxOptions(const String& box_options); // ScriptWrappable override: bool HasPendingActivity() const override; - void Trace(blink::Visitor*) override; + void Trace(Visitor*) override; private: + void observeInternal(Element* target, ResizeObserverBoxOptions box_option); + using ObservationList = HeapLinkedHashSet<WeakMember<ResizeObservation>>; // Either of |callback_| and |delegate_| should be non-null. @@ -79,8 +84,7 @@ class CORE_EXPORT ResizeObserver final HeapVector<Member<ResizeObservation>> active_observations_; // True if observations were skipped gatherObservations bool skipped_observations_; - // True if any ResizeObservation reported size change - bool element_size_changed_; + WeakMember<ResizeObserverController> controller_; }; diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl index 8e09fdd4212..f6e0e947513 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer.idl @@ -10,11 +10,10 @@ callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, R [ Exposed=Window, - ActiveScriptWrappable, - Constructor(ResizeObserverCallback callback), - MeasureAs=ResizeObserver_Constructor, - ConstructorCallWith=Document + ActiveScriptWrappable ] interface ResizeObserver { + [CallWith=Document, MeasureAs=ResizeObserver_Constructor] constructor(ResizeObserverCallback callback); + [RuntimeEnabled=ResizeObserverUpdates] void observe(Element target, ResizeObserverOptions options); void observe(Element target); void unobserve(Element target); void disconnect(); diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h new file mode 100644 index 00000000000..15e4cd9bdf6 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_box_options.h @@ -0,0 +1,12 @@ +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_BOX_OPTIONS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_BOX_OPTIONS_H_ + +namespace blink { +enum class ResizeObserverBoxOptions { + BorderBox, + ContentBox, + DevicePixelContentBox +}; +} + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_BOX_OPTIONS_H_ diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.cc index e1ae935916c..4a7aa879403 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.cc +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.cc @@ -8,31 +8,22 @@ namespace blink { -ResizeObserverController::ResizeObserverController() - : observers_changed_(false) {} +ResizeObserverController::ResizeObserverController() = default; void ResizeObserverController::AddObserver(ResizeObserver& observer) { observers_.insert(&observer); } -size_t ResizeObserverController::GatherObservations(size_t deeper_than) { +size_t ResizeObserverController::GatherObservations() { size_t shallowest = ResizeObserverController::kDepthBottom; - if (!observers_changed_) - return shallowest; + for (auto& observer : observers_) { - size_t depth = observer->GatherObservations(deeper_than); + size_t depth = observer->GatherObservations(min_depth_); if (depth < shallowest) shallowest = depth; } - return shallowest; -} - -void ResizeObserverController::SetNeedsForcedResizeObservations() { - for (auto& observer : observers_) { - // Set ElementSizeChanged as a way of forcing the observer to check all - // observations. - observer->ElementSizeChanged(); - } + min_depth_ = shallowest; + return min_depth_; } bool ResizeObserverController::SkippedObservations() { @@ -44,7 +35,6 @@ bool ResizeObserverController::SkippedObservations() { } void ResizeObserverController::DeliverObservations() { - observers_changed_ = false; // Copy is needed because m_observers might get modified during // deliverObservations. HeapVector<Member<ResizeObserver>> observers; @@ -53,8 +43,6 @@ void ResizeObserverController::DeliverObservations() { for (auto& observer : observers) { if (observer) { observer->DeliverObservations(); - observers_changed_ = - observers_changed_ || observer->HasElementSizeChanged(); } } } @@ -64,7 +52,7 @@ void ResizeObserverController::ClearObservations() { observer->ClearObservations(); } -void ResizeObserverController::Trace(blink::Visitor* visitor) { +void ResizeObserverController::Trace(Visitor* visitor) { visitor->Trace(observers_); } diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h index 27511e15ddc..f8de314f644 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_controller.h @@ -28,29 +28,28 @@ class ResizeObserverController final void AddObserver(ResizeObserver&); // observation API - // Returns depth of shallowest observed node, kDepthLimit if none. - size_t GatherObservations(size_t deeper_than); + // Returns min depth of shallowest observed node, kDepthLimit if none. + size_t GatherObservations(); // Returns true if gatherObservations has skipped observations // because they were too shallow. bool SkippedObservations(); void DeliverObservations(); void ClearObservations(); - void ObserverChanged() { observers_changed_ = true; } - void SetNeedsForcedResizeObservations(); + void ClearMinDepth() { min_depth_ = 0; } - void Trace(blink::Visitor*); + void Trace(Visitor*); // For testing only. - const HeapHashSet<WeakMember<ResizeObserver>>& Observers() { + const HeapLinkedHashSet<WeakMember<ResizeObserver>>& Observers() { return observers_; } private: // Active observers - HeapHashSet<WeakMember<ResizeObserver>> observers_; - // True if any observers were changed since last notification. - bool observers_changed_; + HeapLinkedHashSet<WeakMember<ResizeObserver>> observers_; + // Minimum depth for observations to be active + size_t min_depth_ = 0; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc index 53d101951cd..e4c23d5b7a1 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.cc @@ -3,24 +3,115 @@ // found in the LICENSE file. #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/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_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_size.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { -ResizeObserverEntry::ResizeObserverEntry(Element* target, - const LayoutRect& content_rect) - : target_(target) { - content_rect_ = DOMRectReadOnly::FromFloatRect(FloatRect( +DOMRectReadOnly* ResizeObserverEntry::ZoomAdjustedLayoutRect( + LayoutRect content_rect, + const ComputedStyle& style) { + 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()))); } -void ResizeObserverEntry::Trace(blink::Visitor* visitor) { +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()); + content_rect_ = DOMRectReadOnly::FromFloatRect( + FloatRect(FloatPoint(), FloatSize(bounding_box_size))); + if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) { + ResizeObserverSize* size = ResizeObserverSize::Create( + bounding_box_size.Width(), bounding_box_size.Height()); + content_box_size_.push_back(size); + border_box_size_.push_back(size); + device_pixel_content_box_size_.push_back(size); + } + } else if (layout_object->IsBox()) { + 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()); + + LayoutSize paint_offset = + layout_object->FirstFragment().PaintOffset().ToLayoutSize(); + ResizeObserverSize* device_pixel_content_box_size = + ResizeObserverSize::Create( + SnapSizeToPixel(layout_box->ContentLogicalWidth(), + style.IsHorizontalWritingMode() + ? paint_offset.Width() + : paint_offset.Height()), + SnapSizeToPixel(layout_box->ContentLogicalHeight(), + style.IsHorizontalWritingMode() + ? paint_offset.Height() + : paint_offset.Width())); + + content_box_size_.push_back(ZoomAdjustedSize(content_box_size, style)); + border_box_size_.push_back(ZoomAdjustedSize(border_box_size, style)); + device_pixel_content_box_size_.push_back(device_pixel_content_box_size); + } + } + } + if (!content_rect_) + content_rect_ = DOMRectReadOnly::FromFloatRect( + FloatRect(FloatPoint(LayoutPoint()), FloatSize(LayoutSize()))); + if (RuntimeEnabledFeatures::ResizeObserverUpdatesEnabled()) { + if (content_box_size_.size() == 0) + content_box_size_.push_back(ResizeObserverSize::Create(0, 0)); + if (border_box_size_.size() == 0) + border_box_size_.push_back(ResizeObserverSize::Create(0, 0)); + if (device_pixel_content_box_size_.size() == 0) { + device_pixel_content_box_size_.push_back( + ResizeObserverSize::Create(0, 0)); + } + } +} + +void ResizeObserverEntry::Trace(Visitor* visitor) { visitor->Trace(target_); visitor->Trace(content_rect_); + visitor->Trace(content_box_size_); + visitor->Trace(border_box_size_); + visitor->Trace(device_pixel_content_box_size_); ScriptWrappable::Trace(visitor); } diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h index 379cc05381d..39494322080 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.h @@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_ENTRY_H_ #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/resize_observer/resize_observer_size.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -13,22 +14,42 @@ namespace blink { class Element; class DOMRectReadOnly; +class LayoutSize; +class ComputedStyle; +class ResizeObserverSize; class LayoutRect; class CORE_EXPORT ResizeObserverEntry final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - ResizeObserverEntry(Element* target, const LayoutRect& content_rect); + ResizeObserverEntry(Element* target); Element* target() const { return target_; } DOMRectReadOnly* contentRect() const { return content_rect_; } - - void Trace(blink::Visitor*) override; + HeapVector<Member<ResizeObserverSize>> contentBoxSize() const { + return content_box_size_; + } + HeapVector<Member<ResizeObserverSize>> borderBoxSize() const { + return border_box_size_; + } + HeapVector<Member<ResizeObserverSize>> devicePixelContentBoxSize() const { + return device_pixel_content_box_size_; + } + + void Trace(Visitor*) override; private: Member<Element> target_; Member<DOMRectReadOnly> content_rect_; + HeapVector<Member<ResizeObserverSize>> device_pixel_content_box_size_; + HeapVector<Member<ResizeObserverSize>> content_box_size_; + HeapVector<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 diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl index 969b0f53a73..4a4006cc795 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_entry.idl @@ -8,4 +8,7 @@ interface ResizeObserverEntry { readonly attribute Element target; readonly attribute DOMRectReadOnly contentRect; + [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> contentBoxSize; + [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> borderBoxSize; + [RuntimeEnabled=ResizeObserverUpdates] readonly attribute FrozenArray<ResizeObserverSize> devicePixelContentBoxSize; }; diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_options.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_options.idl new file mode 100644 index 00000000000..4b58e04f842 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_options.idl @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +// https://drafts.csswg.org/resize-observer/#enumdef-resizeobserverboxoptions + +enum ResizeObserverBoxOptions { + "border-box", "content-box", "device-pixel-content-box" +}; + +// https://drafts.csswg.org/resize-observer/#dictdef-resizeobserveroptions + +dictionary ResizeObserverOptions { + ResizeObserverBoxOptions box = "content-box"; +}; diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.cc new file mode 100644 index 00000000000..e6a190d62d2 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.cc @@ -0,0 +1,22 @@ +// Copyright 2019 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/resize_observer/resize_observer_size.h" +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +ResizeObserverSize* ResizeObserverSize::Create(double inline_size, + double block_size) { + return MakeGarbageCollected<ResizeObserverSize>(inline_size, block_size); +} + +ResizeObserverSize::ResizeObserverSize(double inline_size, double block_size) + : inline_size_(inline_size), block_size_(block_size) {} + +ResizeObserverSize::ResizeObserverSize() = default; + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.h b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.h new file mode 100644 index 00000000000..1d0e50f9281 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.h @@ -0,0 +1,32 @@ +// Copyright 2019 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_SIZE_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_SIZE_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" + +namespace blink { + +class CORE_EXPORT ResizeObserverSize final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + static ResizeObserverSize* Create(double inline_size, double block_size); + + ResizeObserverSize(const double inline_size, const double block_size); + ResizeObserverSize(); + + double inlineSize() const { return inline_size_; } + double blockSize() const { return block_size_; } + + private: + double inline_size_; + double block_size_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_RESIZE_OBSERVER_RESIZE_OBSERVER_SIZE_H_ diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl new file mode 100644 index 00000000000..a9d93b39056 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_size.idl @@ -0,0 +1,12 @@ +// Copyright 2019 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. + +// https://drafts.csswg.org/resize-observer-1/#resizeobserversize + +[ + RuntimeEnabled=ResizeObserverUpdates +] interface ResizeObserverSize { + readonly attribute unrestricted double inlineSize; + readonly attribute unrestricted double blockSize; +}; diff --git a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc index abc73217cd1..988b84e3d24 100644 --- a/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc +++ b/chromium/third_party/blink/renderer/core/resize_observer/resize_observer_test.cc @@ -9,9 +9,13 @@ #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h" #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_resize_observer_options.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h" +#include "third_party/blink/renderer/core/geometry/dom_rect_read_only.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_size.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_test.h" @@ -30,10 +34,12 @@ class TestResizeObserverDelegate : public ResizeObserver::Delegate { const HeapVector<Member<ResizeObserverEntry>>& entries) override { call_count_++; } - ExecutionContext* GetExecutionContext() const { return document_; } + ExecutionContext* GetExecutionContext() const { + return document_->ToExecutionContext(); + } int CallCount() const { return call_count_; } - void Trace(blink::Visitor* visitor) override { + void Trace(Visitor* visitor) override { ResizeObserver::Delegate::Trace(visitor); visitor->Trace(document_); } @@ -54,7 +60,7 @@ class TestResizeObserverDelegate : public ResizeObserver::Delegate { */ class ResizeObserverUnitTest : public SimTest {}; -TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { +TEST_F(ResizeObserverUnitTest, ResizeObserverDOMContentBoxAndSVG) { SimRequest main_resource("https://example.com/", "text/html"); LoadURL("https://example.com/"); @@ -71,10 +77,10 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate); Element* dom_target = GetDocument().getElementById("domTarget"); Element* svg_target = GetDocument().getElementById("svgTarget"); - ResizeObservation* dom_observation = - MakeGarbageCollected<ResizeObservation>(dom_target, observer); - ResizeObservation* svg_observation = - MakeGarbageCollected<ResizeObservation>(svg_target, observer); + ResizeObservation* dom_observation = MakeGarbageCollected<ResizeObservation>( + dom_target, observer, ResizeObserverBoxOptions::ContentBox); + ResizeObservation* svg_observation = MakeGarbageCollected<ResizeObservation>( + svg_target, observer, ResizeObserverBoxOptions::ContentBox); // Initial observation is out of sync ASSERT_TRUE(dom_observation->ObservationSizeOutOfSync()); @@ -93,16 +99,160 @@ TEST_F(ResizeObserverUnitTest, ResizeObservationSize) { // Target size is in sync ASSERT_FALSE(dom_observation->ObservationSizeOutOfSync()); + ASSERT_FALSE(svg_observation->ObservationSizeOutOfSync()); // Target depths ASSERT_EQ(svg_observation->TargetDepth() - dom_observation->TargetDepth(), (size_t)1); } +TEST_F(ResizeObserverUnitTest, ResizeObserverDOMBorderBox) { + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + + main_resource.Write(R"HTML( + <div id='domBorderTarget' style='width:100px;height:100px;padding:5px'> + yoyo + </div> + )HTML"); + main_resource.Finish(); + + ResizeObserver::Delegate* delegate = + MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument()); + ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate); + Element* dom_border_target = GetDocument().getElementById("domBorderTarget"); + ResizeObservation* dom_border_observation = + MakeGarbageCollected<ResizeObservation>( + dom_border_target, observer, ResizeObserverBoxOptions::BorderBox); + + // Initial observation is out of sync + ASSERT_TRUE(dom_border_observation->ObservationSizeOutOfSync()); + + // Target size is correct + LayoutSize size = dom_border_observation->ComputeTargetSize(); + ASSERT_EQ(size.Width(), 110); + ASSERT_EQ(size.Height(), 110); + dom_border_observation->SetObservationSize(size); + + // Target size is in sync + ASSERT_FALSE(dom_border_observation->ObservationSizeOutOfSync()); +} + +TEST_F(ResizeObserverUnitTest, ResizeObserverDOMDevicePixelContentBox) { + 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'> + <div style='zoom:3;'> + <div id='domDPTarget' style='width:50px;height:30px'></div> + </div> + </svg> + )HTML"); + main_resource.Finish(); + + ResizeObserver::Delegate* delegate = + MakeGarbageCollected<TestResizeObserverDelegate>(GetDocument()); + ResizeObserver* observer = ResizeObserver::Create(GetDocument(), delegate); + Element* dom_target = GetDocument().getElementById("domTarget"); + Element* dom_dp_target = GetDocument().getElementById("domDPTarget"); + + ResizeObservation* dom_dp_nested_observation = + MakeGarbageCollected<ResizeObservation>( + dom_dp_target, observer, + ResizeObserverBoxOptions::DevicePixelContentBox); + ResizeObservation* dom_dp_observation = + MakeGarbageCollected<ResizeObservation>( + dom_target, observer, + ResizeObserverBoxOptions::DevicePixelContentBox); + + // Initial observation is out of sync + ASSERT_TRUE(dom_dp_observation->ObservationSizeOutOfSync()); + ASSERT_TRUE(dom_dp_nested_observation->ObservationSizeOutOfSync()); + + // Target size is correct + LayoutSize size = dom_dp_observation->ComputeTargetSize(); + ASSERT_EQ(size.Width(), 100); + ASSERT_EQ(size.Height(), 100); + dom_dp_observation->SetObservationSize(size); + + size = dom_dp_nested_observation->ComputeTargetSize(); + ASSERT_EQ(size.Width(), 150); + ASSERT_EQ(size.Height(), 90); + dom_dp_nested_observation->SetObservationSize(size); + + // Target size is in sync + ASSERT_FALSE(dom_dp_observation->ObservationSizeOutOfSync()); + ASSERT_FALSE(dom_dp_nested_observation->ObservationSizeOutOfSync()); +} + +// 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 that default content rect, content box, and border box are created when +// a non box target's entry is made +TEST_F(ResizeObserverUnitTest, TestNonBoxTarget) { + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + + main_resource.Write(R"HTML( + <span id='domTarget'>yo</div> + )HTML"); + main_resource.Finish(); + + ResizeObserverOptions* border_box_option = ResizeObserverOptions::Create(); + border_box_option->setBox("border-box"); + + Element* dom_target = GetDocument().getElementById("domTarget"); + + auto* entry = MakeGarbageCollected<ResizeObserverEntry>(dom_target); + + EXPECT_EQ(entry->contentRect()->width(), 0); + EXPECT_EQ(entry->contentRect()->height(), 0); + EXPECT_EQ(entry->contentBoxSize().at(0)->inlineSize(), 0); + EXPECT_EQ(entry->contentBoxSize().at(0)->blockSize(), 0); + EXPECT_EQ(entry->borderBoxSize().at(0)->inlineSize(), 0); + EXPECT_EQ(entry->borderBoxSize().at(0)->blockSize(), 0); + EXPECT_EQ(entry->devicePixelContentBoxSize().at(0)->inlineSize(), 0); + EXPECT_EQ(entry->devicePixelContentBoxSize().at(0)->blockSize(), 0); +} + TEST_F(ResizeObserverUnitTest, TestMemoryLeaks) { ResizeObserverController& controller = GetDocument().EnsureResizeObserverController(); - const HeapHashSet<WeakMember<ResizeObserver>>& observers = + const HeapLinkedHashSet<WeakMember<ResizeObserver>>& observers = controller.Observers(); ASSERT_EQ(observers.size(), 0U); v8::HandleScope scope(v8::Isolate::GetCurrent()); |