Commit 7c8fc787 authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

[DL] Add a DisplayLocking callback queue.

This patch adds a callback queue to display locking context in order to
process scheduled tasks in the correct order.

Currently the behavior is:
- Put callbacks in a queue, and post a task to run them.
- While running the task, process all callbacks in the existing queue
- If any of the callbacks schedule a _new_ callback, then they go into
  a new queue, and a new task is scheduled to run them.

R=chrishtr@chromium.org

Bug: 882663
Change-Id: I41dfc756bb5585d33da85746054a42cc7f5072ef
Reviewed-on: https://chromium-review.googlesource.com/c/1277696
Commit-Queue: vmpstr <vmpstr@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600814}
parent 8bd7e583
...@@ -168,9 +168,6 @@ crbug.com/857490 virtual/paint-touchaction-rects/fast/events/touch/gesture/touch ...@@ -168,9 +168,6 @@ crbug.com/857490 virtual/paint-touchaction-rects/fast/events/touch/gesture/touch
# Display locking, currently only available via a virtual test. # Display locking, currently only available via a virtual test.
crbug.com/882663 display-lock [ Skip ] crbug.com/882663 display-lock [ Skip ]
crbug.com/882663 virtual/display-lock/display-lock/acquire-callback-throws.html [ Failure ]
crbug.com/882663 virtual/display-lock/display-lock/multiple-schedules-recursive.html [ Failure ]
crbug.com/882663 virtual/display-lock/display-lock/simple-schedule-2.html [ Failure ]
# Sheriff 2018/05/25 # Sheriff 2018/05/25
crbug.com/846747 http/tests/navigation/navigation-interrupted-by-fragment.html [ Pass Timeout ] crbug.com/846747 http/tests/navigation/navigation-interrupted-by-fragment.html [ Pass Timeout ]
......
...@@ -4,15 +4,114 @@ ...@@ -4,15 +4,114 @@
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h" #include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h" #include "third_party/blink/renderer/bindings/core/v8/v8_display_lock_callback.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
namespace blink { namespace blink {
DisplayLockContext::~DisplayLockContext() {} DisplayLockContext::DisplayLockContext(ExecutionContext* context)
: ContextLifecycleObserver(context) {}
void DisplayLockContext::Dispose() {} DisplayLockContext::~DisplayLockContext() {
DCHECK(!resolver_);
DCHECK(callbacks_.IsEmpty());
}
void DisplayLockContext::Trace(blink::Visitor* visitor) {
ScriptWrappable::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
visitor->Trace(callbacks_);
visitor->Trace(resolver_);
}
void DisplayLockContext::Dispose() {
RejectAndCleanUp();
}
void DisplayLockContext::ContextDestroyed(ExecutionContext*) {
RejectAndCleanUp();
}
bool DisplayLockContext::HasPendingActivity() const {
// If we don't have a task scheduled, then we should already be resolved.
// TODO(vmpstr): This should also be kept alive if we're doing co-operative
// work.
DCHECK(process_queue_task_scheduled_ || !resolver_);
return process_queue_task_scheduled_;
}
void DisplayLockContext::ScheduleTask(V8DisplayLockCallback* callback,
ScriptState* script_state) {
callbacks_.push_back(callback);
if (!resolver_) {
DCHECK(script_state);
resolver_ = ScriptPromiseResolver::Create(script_state);
}
if (!process_queue_task_scheduled_) {
DCHECK(GetExecutionContext());
DCHECK(GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI));
GetExecutionContext()
->GetTaskRunner(TaskType::kMiscPlatformAPI)
->PostTask(FROM_HERE, WTF::Bind(&DisplayLockContext::ProcessQueue,
WrapWeakPersistent(this)));
process_queue_task_scheduled_ = true;
}
}
void DisplayLockContext::schedule(V8DisplayLockCallback* callback) { void DisplayLockContext::schedule(V8DisplayLockCallback* callback) {
callback->InvokeAndReportException(nullptr, this); ScheduleTask(callback);
}
void DisplayLockContext::ProcessQueue() {
// It's important to clear this before running the tasks, since the tasks can
// call ScheduleTask() which will re-schedule a PostTask() for us to continue
// the work.
process_queue_task_scheduled_ = false;
// We might have cleaned up already due to exeuction context being destroyed.
if (callbacks_.IsEmpty()) {
DCHECK(!resolver_);
return;
}
// Get a local copy of all the tasks we will run.
// TODO(vmpstr): This should possibly be subject to a budget instead.
HeapVector<Member<V8DisplayLockCallback>> callbacks;
callbacks.swap(callbacks_);
for (auto& callback : callbacks) {
DCHECK(callback);
{
// A re-implementation of InvokeAndReportException, in order for us to
// be able to query |try_catch| to determine whether or not we need to
// reject our promise.
v8::TryCatch try_catch(callback->GetIsolate());
try_catch.SetVerbose(true);
auto result = callback->Invoke(nullptr, this);
ALLOW_UNUSED_LOCAL(result);
if (try_catch.HasCaught()) {
RejectAndCleanUp();
return;
}
}
Microtask::PerformCheckpoint(callback->GetIsolate());
}
// TODO(vmpstr): This should be resolved after all of the co-operative work
// finishes, not here.
if (callbacks_.IsEmpty()) {
DCHECK(!process_queue_task_scheduled_);
resolver_->Resolve();
resolver_ = nullptr;
}
}
void DisplayLockContext::RejectAndCleanUp() {
if (resolver_) {
resolver_->Reject();
resolver_ = nullptr;
}
callbacks_.clear();
} }
} // namespace blink } // namespace blink
...@@ -5,22 +5,65 @@ ...@@ -5,22 +5,65 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_CONTEXT_H_
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
namespace blink { namespace blink {
class V8DisplayLockCallback; class V8DisplayLockCallback;
class CORE_EXPORT DisplayLockContext final : public ScriptWrappable { class CORE_EXPORT DisplayLockContext final
: public ScriptWrappable,
public ActiveScriptWrappable<DisplayLockContext>,
public ContextLifecycleObserver {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(DisplayLockContext);
public: public:
DisplayLockContext() = default; DisplayLockContext(ExecutionContext*);
~DisplayLockContext() override; ~DisplayLockContext() override;
// GC Functions.
void Trace(blink::Visitor*) override;
void Dispose(); void Dispose();
// ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
// ActiveScriptWrappable overrides. If there is an outstanding task scheduled
// to process the callback queue, then this return true.
// TODO(vmpstr): In the future this would also be true while we're doing
// co-operative work.
bool HasPendingActivity() const final;
// Schedules a new callback. If this is the first callback to be scheduled,
// then a valid ScriptState must be provided, which will be used to create a
// new ScriptPromiseResolver. In other cases, the ScriptState is ignored.
void ScheduleTask(V8DisplayLockCallback*, ScriptState* = nullptr);
// Returns true if the promise associated with this context was already
// resolved (or rejected).
bool IsResolved() const { return !resolver_; }
// Returns a ScriptPromise associated with this context.
ScriptPromise Promise() const {
DCHECK(resolver_);
return resolver_->Promise();
}
// JavaScript interface implementation.
void schedule(V8DisplayLockCallback*); void schedule(V8DisplayLockCallback*);
private:
// Processes the current queue of callbacks.
void ProcessQueue();
// Rejects the associated promise if one exists, and clears the current queue.
// This effectively makes the context finalized.
void RejectAndCleanUp();
HeapVector<Member<V8DisplayLockCallback>> callbacks_;
Member<ScriptPromiseResolver> resolver_;
bool process_queue_task_scheduled_ = false;
}; };
} // namespace blink } // namespace blink
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
[RuntimeEnabled=DisplayLocking] callback DisplayLockCallback = void(DisplayLockContext context); [RuntimeEnabled=DisplayLocking] callback DisplayLockCallback = void(DisplayLockContext context);
[RuntimeEnabled=DisplayLocking] interface DisplayLockContext { [RuntimeEnabled=DisplayLocking, ActiveScriptWrappable] interface DisplayLockContext {
void schedule(DisplayLockCallback callback); void schedule(DisplayLockCallback callback);
}; };
...@@ -3723,14 +3723,10 @@ void Element::DidEndCustomizedScrollPhase() { ...@@ -3723,14 +3723,10 @@ void Element::DidEndCustomizedScrollPhase() {
ScriptPromise Element::acquireDisplayLock(ScriptState* script_state, ScriptPromise Element::acquireDisplayLock(ScriptState* script_state,
V8DisplayLockCallback* callback) { V8DisplayLockCallback* callback) {
// For now, just invoke the callback, and resolve the promise immediately. auto* context =
// TODO(vmpstr): Finish implementation. EnsureElementRareData().EnsureDisplayLockContext(GetExecutionContext());
callback->InvokeAndReportException(nullptr, new DisplayLockContext); context->ScheduleTask(callback, script_state);
return context->Promise();
auto* resolver = ScriptPromiseResolver::Create(script_state);
const auto& promise = resolver->Promise();
resolver->Resolve();
return promise;
} }
// Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml() // Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
......
...@@ -41,7 +41,7 @@ namespace blink { ...@@ -41,7 +41,7 @@ namespace blink {
struct SameSizeAsElementRareData : NodeRareData { struct SameSizeAsElementRareData : NodeRareData {
IntSize scroll_offset; IntSize scroll_offset;
void* pointers_or_strings[5]; void* pointers_or_strings[5];
Member<void*> members[14]; Member<void*> members[15];
}; };
ElementRareData::ElementRareData(NodeRenderingData* node_layout_data) ElementRareData::ElementRareData(NodeRenderingData* node_layout_data)
...@@ -102,6 +102,7 @@ void ElementRareData::TraceAfterDispatch(blink::Visitor* visitor) { ...@@ -102,6 +102,7 @@ void ElementRareData::TraceAfterDispatch(blink::Visitor* visitor) {
visitor->Trace(cssom_map_wrapper_); visitor->Trace(cssom_map_wrapper_);
visitor->Trace(pseudo_element_data_); visitor->Trace(pseudo_element_data_);
visitor->Trace(accessible_node_); visitor->Trace(accessible_node_);
visitor->Trace(display_lock_context_);
visitor->Trace(v0_custom_element_definition_); visitor->Trace(v0_custom_element_definition_);
visitor->Trace(custom_element_definition_); visitor->Trace(custom_element_definition_);
visitor->Trace(intersection_observer_data_); visitor->Trace(intersection_observer_data_);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/aom/accessible_node.h" #include "third_party/blink/renderer/core/aom/accessible_node.h"
#include "third_party/blink/renderer/core/css/cssom/inline_style_property_map.h" #include "third_party/blink/renderer/core/css/cssom/inline_style_property_map.h"
#include "third_party/blink/renderer/core/css/inline_css_style_declaration.h" #include "third_party/blink/renderer/core/css/inline_css_style_declaration.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/dom/attr.h" #include "third_party/blink/renderer/core/dom/attr.h"
#include "third_party/blink/renderer/core/dom/dataset_dom_string_map.h" #include "third_party/blink/renderer/core/dom/dataset_dom_string_map.h"
#include "third_party/blink/renderer/core/dom/dom_token_list.h" #include "third_party/blink/renderer/core/dom/dom_token_list.h"
...@@ -187,6 +188,13 @@ class ElementRareData : public NodeRareData { ...@@ -187,6 +188,13 @@ class ElementRareData : public NodeRareData {
} }
ResizeObserverDataMap& EnsureResizeObserverData(); ResizeObserverDataMap& EnsureResizeObserverData();
DisplayLockContext* EnsureDisplayLockContext(ExecutionContext* context) {
if (!display_lock_context_ || display_lock_context_->IsResolved()) {
display_lock_context_ = new DisplayLockContext(context);
}
return display_lock_context_.Get();
}
const AtomicString& GetNonce() const { return nonce_; } const AtomicString& GetNonce() const { return nonce_; }
void SetNonce(const AtomicString& nonce) { nonce_ = nonce; } void SetNonce(const AtomicString& nonce) { nonce_ = nonce; }
...@@ -221,6 +229,8 @@ class ElementRareData : public NodeRareData { ...@@ -221,6 +229,8 @@ class ElementRareData : public NodeRareData {
TraceWrapperMember<AccessibleNode> accessible_node_; TraceWrapperMember<AccessibleNode> accessible_node_;
Member<DisplayLockContext> display_lock_context_;
explicit ElementRareData(NodeRenderingData*); explicit ElementRareData(NodeRenderingData*);
}; };
......
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