From 024aec1d6bb70f71f83454f58e68676632f0a8da Mon Sep 17 00:00:00 2001 From: Ionel Popescu Date: Mon, 13 Sep 2021 23:58:49 +0000 Subject: [PATCH] [EyeDropper API] Add optional AbortSignal parameter to EyeDropper.open Per TAG review[1], this CL adds an optional AbortSignal parameter to EyeDropper.open to allow authors to dismiss the eyedropper with no selection in case another high-priority event occurs. [1]: https://github.com/w3ctag/design-reviews/issues/587#issuecomment-911951900 Bug: 1248286 Change-Id: I15580609ece85f947f019a724b23b5e4898e42f2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3152761 Commit-Queue: Ionel Popescu Reviewed-by: Mason Freed Cr-Commit-Position: refs/heads/main@{#920997} --- .../bindings/generated_in_modules.gni | 2 + .../renderer/bindings/idl_in_modules.gni | 1 + .../eyedropper/color_selection_options.idl | 9 ++++ .../modules/eyedropper/eye_dropper.cc | 36 ++++++++++++--- .../renderer/modules/eyedropper/eye_dropper.h | 8 +++- .../modules/eyedropper/eye_dropper.idl | 3 +- .../eye-dropper-abort-signal.tentative.html | 45 +++++++++++++++++++ 7 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 third_party/blink/renderer/modules/eyedropper/color_selection_options.idl create mode 100644 third_party/blink/web_tests/external/wpt/eyedropper/eye-dropper-abort-signal.tentative.html diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index 5a8104517a4bcf..3e91f15dcdf40f 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni @@ -227,6 +227,8 @@ generated_dictionary_sources_in_modules = [ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_close_event_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_collected_client_data.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_options.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_compute_pressure_observer_options.cc", diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index 53063df09886c0..6fa8e7af7d3f23 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni @@ -229,6 +229,7 @@ static_idl_files_in_modules = get_path_info( "//third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.idl", "//third_party/blink/renderer/modules/eventsource/event_source.idl", "//third_party/blink/renderer/modules/eventsource/event_source_init.idl", + "//third_party/blink/renderer/modules/eyedropper/color_selection_options.idl", "//third_party/blink/renderer/modules/eyedropper/color_selection_result.idl", "//third_party/blink/renderer/modules/eyedropper/eye_dropper.idl", "//third_party/blink/renderer/modules/file_system_access/data_transfer_item_file_system_access.idl", diff --git a/third_party/blink/renderer/modules/eyedropper/color_selection_options.idl b/third_party/blink/renderer/modules/eyedropper/color_selection_options.idl new file mode 100644 index 00000000000000..009873db759b21 --- /dev/null +++ b/third_party/blink/renderer/modules/eyedropper/color_selection_options.idl @@ -0,0 +1,9 @@ +// Copyright 2021 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://wicg.github.io/eyedropper-api/#colorselectionoptions-dictionary + +dictionary ColorSelectionOptions { + AbortSignal signal; +}; diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc index 8149ab3aa3601c..ee31cfa5eb0da3 100644 --- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc +++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.cc @@ -7,10 +7,13 @@ #include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_color_selection_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_color_selection_result.h" +#include "third_party/blink/renderer/core/dom/abort_signal.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -18,6 +21,9 @@ namespace blink { +constexpr char kAbortMessage[] = "Color selection aborted."; +constexpr char kNotAvailableMessage[] = "EyeDropper is not available."; + EyeDropper::EyeDropper(ExecutionContext* context) : eye_dropper_chooser_(context) {} @@ -26,6 +32,7 @@ EyeDropper* EyeDropper::Create(ExecutionContext* context) { } ScriptPromise EyeDropper::open(ScriptState* script_state, + const ColorSelectionOptions* options, ExceptionState& exception_state) { DCHECK(RuntimeEnabledFeatures::EyeDropperAPIEnabled()); @@ -46,7 +53,7 @@ ScriptPromise EyeDropper::open(ScriptState* script_state, if (!features::IsEyeDropperEnabled()) { exception_state.ThrowDOMException(DOMExceptionCode::kOperationError, - "EyeDropper is not available."); + kNotAvailableMessage); return ScriptPromise(); } @@ -56,6 +63,16 @@ ScriptPromise EyeDropper::open(ScriptState* script_state, return ScriptPromise(); } + if (options->hasSignal()) { + if (options->signal()->aborted()) { + exception_state.ThrowDOMException(DOMExceptionCode::kAbortError, + kAbortMessage); + return ScriptPromise(); + } + options->signal()->AddAlgorithm( + WTF::Bind(&EyeDropper::Abort, WrapWeakPersistent(this))); + } + resolver_ = MakeGarbageCollected(script_state); ScriptPromise promise = resolver_->Promise(); @@ -72,6 +89,10 @@ ScriptPromise EyeDropper::open(ScriptState* script_state, return promise; } +void EyeDropper::Abort() { + RejectPromiseHelper(DOMExceptionCode::kAbortError, kAbortMessage); +} + void EyeDropper::EyeDropperResponseHandler(ScriptPromiseResolver* resolver, bool success, uint32_t color) { @@ -87,16 +108,21 @@ void EyeDropper::EyeDropperResponseHandler(ScriptPromiseResolver* resolver, result->setSRGBHex(Color(color).Serialized()); resolver->Resolve(result); } else { - resolver->Reject(MakeGarbageCollected( - DOMExceptionCode::kAbortError, "The user canceled the selection.")); + RejectPromiseHelper(DOMExceptionCode::kAbortError, + "The user canceled the selection."); } } void EyeDropper::EndChooser() { + RejectPromiseHelper(DOMExceptionCode::kOperationError, kNotAvailableMessage); +} + +void EyeDropper::RejectPromiseHelper(DOMExceptionCode exception_code, + const WTF::String& message) { eye_dropper_chooser_.reset(); if (resolver_) { - resolver_->Reject(MakeGarbageCollected( - DOMExceptionCode::kOperationError, "EyeDropper is not available.")); + resolver_->Reject( + MakeGarbageCollected(exception_code, message)); resolver_ = nullptr; } } diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h index 3c44cb33b832f9..68143d9c986943 100644 --- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.h +++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.h @@ -13,6 +13,8 @@ namespace blink { +class ColorSelectionOptions; +enum class DOMExceptionCode; class ExceptionState; class ScriptPromise; class ScriptPromiseResolver; @@ -35,13 +37,17 @@ class EyeDropper final : public ScriptWrappable { // Opens the eyedropper and replaces the cursor with a browser-defined // preview. - ScriptPromise open(ScriptState*, ExceptionState&); + ScriptPromise open(ScriptState*, + const ColorSelectionOptions*, + ExceptionState&); void Trace(Visitor*) const override; private: + void Abort(); void EyeDropperResponseHandler(ScriptPromiseResolver*, bool, uint32_t); void EndChooser(); + void RejectPromiseHelper(DOMExceptionCode, const WTF::String&); HeapMojoRemote eye_dropper_chooser_; Member resolver_; diff --git a/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl b/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl index c6ce2db4100e45..304bd8632458d7 100644 --- a/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl +++ b/third_party/blink/renderer/modules/eyedropper/eye_dropper.idl @@ -8,5 +8,6 @@ interface EyeDropper { [CallWith=ExecutionContext] constructor(); - [CallWith=ScriptState, RaisesException] Promise open(); + [CallWith=ScriptState, RaisesException] Promise open( + optional ColorSelectionOptions options = {}); }; diff --git a/third_party/blink/web_tests/external/wpt/eyedropper/eye-dropper-abort-signal.tentative.html b/third_party/blink/web_tests/external/wpt/eyedropper/eye-dropper-abort-signal.tentative.html new file mode 100644 index 00000000000000..ff57b270287d0b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/eyedropper/eye-dropper-abort-signal.tentative.html @@ -0,0 +1,45 @@ + +EyeDropper Test: abort signal + + + + + + + + + +