Commit cb55336e authored by morrita@chromium.org's avatar morrita@chromium.org

HTML Imports: Get rid of needsProcessOrStop() from dom/custom/

This is a revision of r173794, which introduced extra complexity
to CustomElementMicrotaskStep classes.

This change moves the responsibility that introduces the complexity
to HTMLImportChild. This localizes the tricky part in the single class
and helps overall code sanity.

TEST=no
BUG=371654
R=dominicc@chromium.org, dglazkov@chromium.org

Review URL: https://codereview.chromium.org/288323004

git-svn-id: svn://svn.chromium.org/blink/trunk@175007 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent c5d38253
......@@ -15,13 +15,13 @@ var t2 = async_test('Custom elements in async imports wait preceeding sync impor
var latch = new ImportTestLatch(function() {
window.setTimeout(function() {
t1.step(function() {
assert_array_equals(['hello-slow', 'hello-1', 'hello-2'], Hello.ids);
assert_array_equals(['hello-slow', 'hello-2', 'hello-1'], Hello.ids);
t1.done();
});
t2.step(function() {
var Bye = registerTestingCustomElement('x-bye');
assert_array_equals(['bye-slow', 'bye-1', 'bye-2'], Bye.ids);
assert_array_equals(['bye-slow', 'bye-2', 'bye-1'], Bye.ids);
t2.done();
});
}, 0);
......
......@@ -2148,6 +2148,8 @@
'dom/XMLDocument.h',
'dom/custom/CustomElement.cpp',
'dom/custom/CustomElement.h',
'dom/custom/CustomElementAsyncImportMicrotaskQueue.cpp',
'dom/custom/CustomElementAsyncImportMicrotaskQueue.h',
'dom/custom/CustomElementCallbackDispatcher.cpp',
'dom/custom/CustomElementCallbackDispatcher.h',
'dom/custom/CustomElementCallbackInvocation.cpp',
......
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of Google Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "core/dom/custom/CustomElementAsyncImportMicrotaskQueue.h"
#include "core/dom/custom/CustomElementMicrotaskImportStep.h"
namespace WebCore {
void CustomElementAsyncImportMicrotaskQueue::enqueue(PassOwnPtr<CustomElementMicrotaskImportStep> step)
{
m_queue.append(step);
}
void CustomElementAsyncImportMicrotaskQueue::doDispatch()
{
WillBeHeapVector<OwnPtr<CustomElementMicrotaskStep> > remaining;
for (unsigned i = 0; i < m_queue.size(); ++i) {
if (CustomElementMicrotaskStep::Processing == m_queue[i]->process())
remaining.append(m_queue[i].release());
}
m_queue.swap(remaining);
}
} // namespace WebCore
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of Google Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CustomElementAsyncImportMicrotaskQueue_h
#define CustomElementAsyncImportMicrotaskQueue_h
#include "core/dom/custom/CustomElementMicrotaskQueue.h"
namespace WebCore {
class CustomElementMicrotaskImportStep;
class CustomElementAsyncImportMicrotaskQueue : public CustomElementMicrotaskQueueBase {
public:
static PassRefPtrWillBeRawPtr<CustomElementAsyncImportMicrotaskQueue> create() { return adoptRefWillBeNoop(new CustomElementAsyncImportMicrotaskQueue()); }
void enqueue(PassOwnPtr<CustomElementMicrotaskImportStep>);
private:
CustomElementAsyncImportMicrotaskQueue() { }
virtual void doDispatch() OVERRIDE;
};
}
#endif // CustomElementAsyncImportMicrotaskQueue_h
......@@ -6,6 +6,7 @@
#include "core/dom/custom/CustomElementMicrotaskDispatcher.h"
#include "core/dom/Microtask.h"
#include "core/dom/custom/CustomElementAsyncImportMicrotaskQueue.h"
#include "core/dom/custom/CustomElementCallbackDispatcher.h"
#include "core/dom/custom/CustomElementCallbackQueue.h"
#include "core/dom/custom/CustomElementMicrotaskImportStep.h"
......@@ -22,6 +23,7 @@ CustomElementMicrotaskDispatcher::CustomElementMicrotaskDispatcher()
: m_hasScheduledMicrotask(false)
, m_phase(Quiescent)
, m_resolutionAndImports(CustomElementMicrotaskQueue::create())
, m_asyncImports(CustomElementAsyncImportMicrotaskQueue::create())
{
}
......@@ -33,30 +35,48 @@ CustomElementMicrotaskDispatcher& CustomElementMicrotaskDispatcher::instance()
return *instance;
}
void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* importLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step)
void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step)
{
ASSERT(m_phase == Quiescent || m_phase == DispatchingCallbacks);
ensureMicrotaskScheduled();
if (importLoader)
importLoader->microtaskQueue()->enqueue(step);
ensureMicrotaskScheduledForMicrotaskSteps();
if (parentLoader)
parentLoader->microtaskQueue()->enqueue(step);
else
m_resolutionAndImports->enqueue(step);
}
void CustomElementMicrotaskDispatcher::enqueue(HTMLImportLoader* parentLoader, PassOwnPtr<CustomElementMicrotaskImportStep> step, bool importIsSync)
{
ensureMicrotaskScheduledForMicrotaskSteps();
if (importIsSync)
enqueue(parentLoader, PassOwnPtr<CustomElementMicrotaskStep>(step));
else
m_asyncImports->enqueue(step);
}
void CustomElementMicrotaskDispatcher::enqueue(CustomElementCallbackQueue* queue)
{
ASSERT(m_phase == Quiescent || m_phase == Resolving);
ensureMicrotaskScheduled();
ensureMicrotaskScheduledForElementQueue();
queue->setOwner(kMicrotaskQueueId);
m_elements.append(queue);
}
void CustomElementMicrotaskDispatcher::importDidFinish(CustomElementMicrotaskImportStep* step)
{
ensureMicrotaskScheduledForMicrotaskSteps();
}
void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForMicrotaskSteps()
{
ASSERT(m_phase == Quiescent || m_phase == DispatchingCallbacks);
ensureMicrotaskScheduled();
}
void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduledForElementQueue()
{
ASSERT(m_phase == Quiescent || m_phase == Resolving);
ensureMicrotaskScheduled();
}
void CustomElementMicrotaskDispatcher::ensureMicrotaskScheduled()
{
if (!m_hasScheduledMicrotask) {
......@@ -84,6 +104,8 @@ void CustomElementMicrotaskDispatcher::doDispatch()
m_phase = Resolving;
m_resolutionAndImports->dispatch();
if (m_resolutionAndImports->isEmpty())
m_asyncImports->dispatch();
m_phase = DispatchingCallbacks;
for (WillBeHeapVector<RawPtrWillBeMember<CustomElementCallbackQueue> >::iterator it = m_elements.begin(); it != m_elements.end(); ++it) {
......@@ -109,7 +131,11 @@ void CustomElementMicrotaskDispatcher::trace(Visitor* visitor)
void CustomElementMicrotaskDispatcher::show()
{
fprintf(stderr, "Dispatcher:\n");
m_resolutionAndImports->show(1);
fprintf(stderr, " Sync:\n");
m_resolutionAndImports->show(3);
fprintf(stderr, " Async:\n");
m_asyncImports->show(3);
}
#endif
......
......@@ -5,7 +5,6 @@
#ifndef CustomElementMicrotaskDispatcher_h
#define CustomElementMicrotaskDispatcher_h
#include "core/dom/custom/CustomElementMicrotaskQueue.h"
#include "platform/heap/Handle.h"
#include "wtf/Noncopyable.h"
#include "wtf/PassOwnPtr.h"
......@@ -13,8 +12,10 @@
namespace WebCore {
class CustomElementAsyncImportMicrotaskQueue;
class CustomElementCallbackQueue;
class CustomElementMicrotaskImportStep;
class CustomElementMicrotaskQueue;
class CustomElementMicrotaskStep;
class HTMLImportLoader;
......@@ -22,12 +23,14 @@ class CustomElementMicrotaskDispatcher FINAL : public NoBaseWillBeGarbageCollect
WTF_MAKE_NONCOPYABLE(CustomElementMicrotaskDispatcher);
DECLARE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CustomElementMicrotaskDispatcher);
public:
static CustomElementMicrotaskDispatcher& instance();
void enqueue(HTMLImportLoader*, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep>);
void enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep>);
void enqueue(HTMLImportLoader* parentLoader, PassOwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep>, bool importIsSync);
void enqueue(CustomElementCallbackQueue*);
void importDidFinish(CustomElementMicrotaskImportStep*);
bool elementQueueIsEmpty() { return m_elements.isEmpty(); }
......@@ -41,6 +44,8 @@ public:
private:
CustomElementMicrotaskDispatcher();
void ensureMicrotaskScheduledForElementQueue();
void ensureMicrotaskScheduledForMicrotaskSteps();
void ensureMicrotaskScheduled();
static void dispatch();
......@@ -54,6 +59,7 @@ private:
} m_phase;
RefPtrWillBeMember<CustomElementMicrotaskQueue> m_resolutionAndImports;
RefPtrWillBeMember<CustomElementAsyncImportMicrotaskQueue> m_asyncImports;
WillBeHeapVector<RawPtrWillBeMember<CustomElementCallbackQueue> > m_elements;
};
......
......@@ -66,11 +66,6 @@ bool CustomElementMicrotaskImportStep::shouldWaitForImport() const
return m_import && !m_import->isLoaded();
}
bool CustomElementMicrotaskImportStep::shouldStopProcessing() const
{
return m_import && m_import->isSync();
}
void CustomElementMicrotaskImportStep::didUpgradeAllCustomElements()
{
ASSERT(m_queue);
......@@ -80,20 +75,12 @@ void CustomElementMicrotaskImportStep::didUpgradeAllCustomElements()
CustomElementMicrotaskStep::Result CustomElementMicrotaskImportStep::process()
{
Result result = m_queue->dispatch();
if (!(result & ShouldStop) && !shouldWaitForImport())
didUpgradeAllCustomElements();
m_queue->dispatch();
if (!m_queue->isEmpty() || shouldWaitForImport())
return Processing;
if (shouldWaitForImport())
result = Result(result | ShouldRemain | ShouldStop);
if (!shouldStopProcessing())
result = Result(result & ~ShouldStop);
return result;
}
bool CustomElementMicrotaskImportStep::needsProcessOrStop() const
{
return shouldStopProcessing() || m_queue->needsProcessOrStop();
didUpgradeAllCustomElements();
return FinishedProcessing;
}
void CustomElementMicrotaskImportStep::trace(Visitor* visitor)
......@@ -105,7 +92,7 @@ void CustomElementMicrotaskImportStep::trace(Visitor* visitor)
#if !defined(NDEBUG)
void CustomElementMicrotaskImportStep::show(unsigned indent)
{
fprintf(stderr, "%*sImport(wait=%d sync=%d, url=%s)\n", indent, "", shouldWaitForImport(), shouldStopProcessing(), m_import ? m_import->url().string().utf8().data() : "null");
fprintf(stderr, "%*sImport(wait=%d sync=%d, url=%s)\n", indent, "", shouldWaitForImport(), m_import && m_import->isSync(), m_import ? m_import->url().string().utf8().data() : "null");
m_queue->show(indent + 1);
}
#endif
......
......@@ -68,11 +68,9 @@ private:
void didUpgradeAllCustomElements();
bool shouldWaitForImport() const;
bool shouldStopProcessing() const;
// CustomElementMicrotaskStep
virtual Result process() OVERRIDE FINAL;
virtual bool needsProcessOrStop() const OVERRIDE FINAL;
#if !defined(NDEBUG)
virtual void show(unsigned indent) OVERRIDE;
......
......@@ -38,9 +38,9 @@ namespace WebCore {
class MicrotaskQueueInvocationScope {
public:
#if defined(NDEBUG)
explicit MicrotaskQueueInvocationScope(CustomElementMicrotaskQueue*) { }
explicit MicrotaskQueueInvocationScope(CustomElementMicrotaskQueueBase*) { }
#else
explicit MicrotaskQueueInvocationScope(CustomElementMicrotaskQueue* queue)
explicit MicrotaskQueueInvocationScope(CustomElementMicrotaskQueueBase* queue)
: m_parent(s_top)
, m_queue(queue)
{
......@@ -65,7 +65,7 @@ private:
}
MicrotaskQueueInvocationScope* m_parent;
CustomElementMicrotaskQueue* m_queue;
CustomElementMicrotaskQueueBase* m_queue;
static MicrotaskQueueInvocationScope* s_top;
#endif
......@@ -75,51 +75,19 @@ private:
MicrotaskQueueInvocationScope* MicrotaskQueueInvocationScope::s_top = 0;
#endif
void CustomElementMicrotaskQueue::enqueue(PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep> step)
{
m_queue.append(step);
}
CustomElementMicrotaskStep::Result CustomElementMicrotaskQueue::dispatch()
void CustomElementMicrotaskQueueBase::dispatch()
{
MicrotaskQueueInvocationScope scope(this);
WillBeHeapVector<OwnPtrWillBeMember<CustomElementMicrotaskStep> > remaining;
Result accumulatedResult = CustomElementMicrotaskStep::ContinueWithRemoving;
unsigned i;
for (i = 0; i < m_queue.size(); ++i) {
Result result = m_queue[i]->process();
accumulatedResult = CustomElementMicrotaskStep::Result(result | accumulatedResult);
if (result & CustomElementMicrotaskStep::ShouldRemain)
remaining.append(m_queue[i].release());
if (result & CustomElementMicrotaskStep::ShouldStop)
break;
}
for (++i; i < m_queue.size(); ++i)
remaining.append(m_queue[i].release());
m_queue.swap(remaining);
return accumulatedResult;
doDispatch();
}
bool CustomElementMicrotaskQueue::needsProcessOrStop() const
{
for (size_t i = 0; i < m_queue.size(); ++i) {
if (m_queue[i]->needsProcessOrStop())
return true;
}
return false;
}
void CustomElementMicrotaskQueue::trace(Visitor* visitor)
void CustomElementMicrotaskQueueBase::trace(Visitor* visitor)
{
visitor->trace(m_queue);
}
#if !defined(NDEBUG)
void CustomElementMicrotaskQueue::show(unsigned indent)
void CustomElementMicrotaskQueueBase::show(unsigned indent)
{
for (unsigned q = 0; q < m_queue.size(); ++q) {
if (m_queue[q])
......@@ -130,4 +98,21 @@ void CustomElementMicrotaskQueue::show(unsigned indent)
}
#endif
void CustomElementMicrotaskQueue::enqueue(PassOwnPtr<CustomElementMicrotaskStep> step)
{
m_queue.append(step);
}
void CustomElementMicrotaskQueue::doDispatch()
{
unsigned i;
for (i = 0; i < m_queue.size(); ++i) {
if (CustomElementMicrotaskStep::Processing == m_queue[i]->process())
break;
}
m_queue.remove(0, i);
}
} // namespace WebCore
......@@ -42,32 +42,38 @@
namespace WebCore {
class CustomElementMicrotaskQueue FINAL : public RefCountedWillBeGarbageCollectedFinalized<CustomElementMicrotaskQueue> {
WTF_MAKE_NONCOPYABLE(CustomElementMicrotaskQueue);
class CustomElementMicrotaskQueueBase : public RefCountedWillBeGarbageCollectedFinalized<CustomElementMicrotaskQueueBase> {
WTF_MAKE_NONCOPYABLE(CustomElementMicrotaskQueueBase);
public:
static PassRefPtrWillBeRawPtr<CustomElementMicrotaskQueue> create()
{
return adoptRefWillBeNoop(new CustomElementMicrotaskQueue());
}
virtual ~CustomElementMicrotaskQueueBase() { }
bool isEmpty() const { return m_queue.isEmpty(); }
void enqueue(PassOwnPtrWillBeRawPtr<CustomElementMicrotaskStep>);
typedef CustomElementMicrotaskStep::Result Result;
Result dispatch();
bool needsProcessOrStop() const;
void dispatch();
void trace(Visitor*);
#if !defined(NDEBUG)
void show(unsigned indent);
#endif
private:
CustomElementMicrotaskQueue() { }
protected:
CustomElementMicrotaskQueueBase() { }
virtual void doDispatch() = 0;
WillBeHeapVector<OwnPtrWillBeMember<CustomElementMicrotaskStep> > m_queue;
};
class CustomElementMicrotaskQueue : public CustomElementMicrotaskQueueBase {
public:
static PassRefPtrWillBeRawPtr<CustomElementMicrotaskQueue> create() { return adoptRefWillBeNoop(new CustomElementMicrotaskQueue()); }
void enqueue(PassOwnPtr<CustomElementMicrotaskStep>);
private:
CustomElementMicrotaskQueue() { }
virtual void doDispatch();
};
}
#endif // CustomElementMicrotaskQueue_h
......@@ -55,12 +55,7 @@ CustomElementMicrotaskResolutionStep::~CustomElementMicrotaskResolutionStep()
CustomElementMicrotaskStep::Result CustomElementMicrotaskResolutionStep::process()
{
m_context->resolve(m_element.get(), m_descriptor);
return CustomElementMicrotaskStep::ContinueWithRemoving;
}
bool CustomElementMicrotaskResolutionStep::needsProcessOrStop() const
{
return true;
return CustomElementMicrotaskStep::FinishedProcessing;
}
void CustomElementMicrotaskResolutionStep::trace(Visitor* visitor)
......
......@@ -56,7 +56,6 @@ private:
CustomElementMicrotaskResolutionStep(PassRefPtrWillBeRawPtr<CustomElementRegistrationContext>, PassRefPtrWillBeRawPtr<Element>, const CustomElementDescriptor&);
virtual Result process() OVERRIDE;
virtual bool needsProcessOrStop() const OVERRIDE;
#if !defined(NDEBUG)
virtual void show(unsigned indent) OVERRIDE;
......
......@@ -43,13 +43,11 @@ public:
virtual ~CustomElementMicrotaskStep() { }
enum Result {
ContinueWithRemoving = 0,
ShouldStop = 1 << 0,
ShouldRemain = 1 << 1
Processing,
FinishedProcessing
};
virtual Result process() = 0;
virtual bool needsProcessOrStop() const = 0;
virtual void trace(Visitor*) { }
......
......@@ -84,13 +84,11 @@ CustomElementMicrotaskImportStep* CustomElementScheduler::scheduleImport(HTMLImp
ASSERT(!import->isDone());
ASSERT(import->parent());
OwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep> step = CustomElementMicrotaskImportStep::create(import);
CustomElementMicrotaskImportStep* rawStep = step.get();
// Ownership of the new step is transferred to the parent
// processing step, or the base queue.
CustomElementMicrotaskDispatcher::instance().enqueue(import->parent()->loader(), step.release());
OwnPtrWillBeRawPtr<CustomElementMicrotaskImportStep> step = CustomElementMicrotaskImportStep::create(import);
CustomElementMicrotaskImportStep* rawStep = step.get();
CustomElementMicrotaskDispatcher::instance().enqueue(import->parent()->loader(), step.release(), import->isSync());
return rawStep;
}
......
......@@ -35,6 +35,7 @@
#include "core/dom/custom/CustomElement.h"
#include "core/dom/custom/CustomElementMicrotaskDispatcher.h"
#include "core/dom/custom/CustomElementMicrotaskImportStep.h"
#include "core/dom/custom/CustomElementMicrotaskQueue.h"
#include "core/html/imports/HTMLImportChildClient.h"
#include "core/html/imports/HTMLImportLoader.h"
#include "core/html/imports/HTMLImportsController.h"
......@@ -158,7 +159,7 @@ void HTMLImportChild::createCustomElementMicrotaskStepIfNeeded()
bool HTMLImportChild::isDone() const
{
return m_loader && m_loader->isDone() && !m_loader->microtaskQueue()->needsProcessOrStop() && !m_customElementMicrotaskStep;
return m_loader && m_loader->isDone() && m_loader->microtaskQueue()->isEmpty() && !m_customElementMicrotaskStep;
}
bool HTMLImportChild::loaderHasError() const
......
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