| Index: third_party/WebKit/Source/core/dom/ModuleMap.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/ModuleMap.cpp b/third_party/WebKit/Source/core/dom/ModuleMap.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a59bda21fc645bb77d508b1e5ad89debc980f429
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/dom/ModuleMap.cpp
|
| @@ -0,0 +1,146 @@
|
| +// Copyright 2017 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 "core/dom/ModuleMap.h"
|
| +
|
| +#include "core/dom/Modulator.h"
|
| +#include "core/dom/ModuleScript.h"
|
| +#include "core/dom/ScriptModuleResolver.h"
|
| +#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
|
| +#include "core/loader/modulescript/ModuleScriptLoaderClient.h"
|
| +#include "platform/WebTaskRunner.h"
|
| +
|
| +namespace blink {
|
| +
|
| +// Entry struct represents a value in "module map" spec object.
|
| +class ModuleMap::Entry : public GarbageCollectedFinalized<Entry>,
|
| + public ModuleScriptLoaderClient {
|
| + USING_GARBAGE_COLLECTED_MIXIN(ModuleMap::Entry);
|
| +
|
| + public:
|
| + static Entry* create(ModuleMap* map) { return new Entry(map); }
|
| + virtual ~Entry() {}
|
| +
|
| + DECLARE_TRACE();
|
| +
|
| + // Asynchronously notify the client fetched |m_moduleScript|, or register the
|
| + // client to receive further callbacks if |m_isFetching|.
|
| + void addClient(SingleModuleClient*);
|
| +
|
| + // This is only to be used from ScriptModuleResolver implementations.
|
| + ModuleScript* retrieveModuleScriptSync() const;
|
| +
|
| + private:
|
| + Entry(ModuleMap*);
|
| +
|
| + void dispatchFinishedNotificationAsync(SingleModuleClient*);
|
| +
|
| + // Implements ModuleScriptLoaderClient
|
| + void notifyNewSingleModuleFinished(ModuleScript*) override;
|
| +
|
| + Member<ModuleScript> m_moduleScript;
|
| + Member<ModuleMap> m_map;
|
| +
|
| + // Correspond to the HTML spec: "fetching" state.
|
| + bool m_isFetching = true;
|
| +
|
| + HeapHashSet<Member<SingleModuleClient>> m_clients;
|
| +};
|
| +
|
| +ModuleMap::Entry::Entry(ModuleMap* map) : m_map(map) {
|
| + DCHECK(m_map);
|
| +}
|
| +
|
| +DEFINE_TRACE(ModuleMap::Entry) {
|
| + visitor->trace(m_moduleScript);
|
| + visitor->trace(m_map);
|
| + visitor->trace(m_clients);
|
| +}
|
| +
|
| +void ModuleMap::Entry::dispatchFinishedNotificationAsync(
|
| + SingleModuleClient* client) {
|
| + m_map->modulator()->taskRunner()->postTask(
|
| + BLINK_FROM_HERE,
|
| + WTF::bind(&SingleModuleClient::notifyModuleLoadFinished,
|
| + wrapPersistent(client), wrapPersistent(m_moduleScript.get())));
|
| +}
|
| +
|
| +void ModuleMap::Entry::addClient(SingleModuleClient* newClient) {
|
| + DCHECK(!m_clients.contains(newClient));
|
| + if (!m_isFetching) {
|
| + DCHECK(m_clients.isEmpty());
|
| + dispatchFinishedNotificationAsync(newClient);
|
| + return;
|
| + }
|
| +
|
| + m_clients.insert(newClient);
|
| +}
|
| +
|
| +void ModuleMap::Entry::notifyNewSingleModuleFinished(
|
| + ModuleScript* moduleScript) {
|
| + m_moduleScript = moduleScript;
|
| + m_isFetching = false;
|
| +
|
| + if (m_moduleScript) {
|
| + m_map->modulator()->scriptModuleResolver()->registerModuleScript(
|
| + m_moduleScript);
|
| + }
|
| +
|
| + for (const auto& client : m_clients) {
|
| + dispatchFinishedNotificationAsync(client);
|
| + }
|
| + m_clients.clear();
|
| +}
|
| +
|
| +ModuleScript* ModuleMap::Entry::retrieveModuleScriptSync() const {
|
| + DCHECK(!m_isFetching);
|
| + return m_moduleScript.get();
|
| +}
|
| +
|
| +ModuleMap::ModuleMap(Modulator* modulator) : m_modulator(modulator) {
|
| + DCHECK(modulator);
|
| +}
|
| +
|
| +DEFINE_TRACE(ModuleMap) {
|
| + visitor->trace(m_map);
|
| + visitor->trace(m_modulator);
|
| +}
|
| +
|
| +void ModuleMap::retrieveAndFetchIfNeeded(
|
| + const ModuleScriptFetchRequest& request,
|
| + ModuleGraphLevel level,
|
| + SingleModuleClient* client) {
|
| + // https://html.spec.whatwg.org/#fetch-a-single-module-script
|
| +
|
| + // Step 1. Let moduleMap be module map settings object's module map.
|
| + // Note: This is the ModuleMap.
|
| +
|
| + // Step 2. If moduleMap[url] is "fetching", wait in parallel until that
|
| + // entry's value changes, then queue a task on the networking task source to
|
| + // proceed with running the following steps.
|
| + MapImpl::AddResult result = m_map.insert(request.url(), nullptr);
|
| + Member<Entry>& entry = result.storedValue->value;
|
| + if (result.isNewEntry) {
|
| + entry = Entry::create(this);
|
| +
|
| + // Steps 4-9 loads a new single module script.
|
| + // Delegate to ModuleScriptLoader via Modulator.
|
| + m_modulator->fetchNewSingleModule(request, level, entry);
|
| + }
|
| + DCHECK(entry);
|
| +
|
| + // Step 3. If moduleMap[url] exists, asynchronously complete this algorithm
|
| + // with moduleMap[url], and abort these steps.
|
| + // Step 10. Set moduleMap[url] to module script, and asynchronously complete
|
| + // this algorithm with module script.
|
| + entry->addClient(client);
|
| +}
|
| +
|
| +ModuleScript* ModuleMap::retrieveFetchedModuleScript(const KURL& url) {
|
| + MapImpl::iterator it = m_map.find(url);
|
| + CHECK_NE(it, m_map.end());
|
| + return it->value->retrieveModuleScriptSync();
|
| +}
|
| +
|
| +} // namespace blink
|
|
|