Commit 91a2313e authored by zhaobin's avatar zhaobin Committed by Commit bot

[Presentation API] Resolve PresentationRequest::reconnect() with existing...

[Presentation API] Resolve PresentationRequest::reconnect() with existing presentation connection if such connection exists

Check if any presentation connection with specific presentationUrl and presentationId exists in current browsing context. If so, resolve reconnect() with existing connection instead of creating a new connection.

BUG=677540

Review-Url: https://codereview.chromium.org/2602523002
Cr-Commit-Position: refs/heads/master@{#441462}
parent 86897c09
<!DOCTYPE html>
<html>
<body>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="../resources/gc.js"></script>
<script src="../resources/mojo-helpers.js"></script>
<script src="resources/presentation-service-mock.js"></script>
<button>click me</button>
<script>
function waitForClick(callback) {
var button = document.querySelector('button');
button.addEventListener('click', callback, { once: true });
if (!('eventSender' in window))
return;
var boundingRect = button.getBoundingClientRect();
var x = boundingRect.left + boundingRect.width / 2;
var y = boundingRect.top + boundingRect.height / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseDown();
eventSender.mouseUp();
}
async_test(t => {
presentationServiceMock.then(mockService => {
var connection = null;
var request = new PresentationRequest('https://example.com');
waitForClick(_ => {
request.start().then(conn => {
connection = conn;
assert_not_equals(connection, null);
request.reconnect(connection.id).then(
t.step_func_done(conn => {
assert_true(connection === conn);
}));
});
});
});
}, "Test that Presentation.reconnect() resolves with existing presentation connection.");
</script>
</body>
</html>
...@@ -29,6 +29,13 @@ let presentationServiceMock = loadMojoModules( ...@@ -29,6 +29,13 @@ let presentationServiceMock = loadMojoModules(
error: null, error: null,
}); });
} }
joinSession(urls) {
return Promise.resolve({
sessionInfo: { url: urls[0], id: 'fakeSessionId' },
error: null,
});
}
} }
return new PresentationServiceMock(mojo.frameInterfaces); return new PresentationServiceMock(mojo.frameInterfaces);
......
...@@ -6,6 +6,8 @@ import("//third_party/WebKit/Source/modules/modules.gni") ...@@ -6,6 +6,8 @@ import("//third_party/WebKit/Source/modules/modules.gni")
blink_modules_sources("presentation") { blink_modules_sources("presentation") {
sources = [ sources = [
"ExistingPresentationConnectionCallbacks.cpp",
"ExistingPresentationConnectionCallbacks.h",
"NavigatorPresentation.cpp", "NavigatorPresentation.cpp",
"NavigatorPresentation.h", "NavigatorPresentation.h",
"Presentation.cpp", "Presentation.cpp",
......
// Copyright 2015 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 "modules/presentation/ExistingPresentationConnectionCallbacks.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "modules/presentation/PresentationConnection.h"
#include "modules/presentation/PresentationError.h"
#include "public/platform/modules/presentation/WebPresentationError.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
ExistingPresentationConnectionCallbacks::
ExistingPresentationConnectionCallbacks(ScriptPromiseResolver* resolver,
PresentationConnection* connection)
: m_resolver(resolver), m_connection(connection) {
DCHECK(m_resolver);
DCHECK(m_connection);
}
void ExistingPresentationConnectionCallbacks::onSuccess(
const WebPresentationSessionInfo& sessionInfo) {
if (!m_resolver->getExecutionContext() ||
m_resolver->getExecutionContext()->isContextDestroyed()) {
return;
}
if (m_connection->getState() == WebPresentationConnectionState::Closed)
m_connection->didChangeState(WebPresentationConnectionState::Connecting);
m_resolver->resolve(m_connection);
}
void ExistingPresentationConnectionCallbacks::onError(
const WebPresentationError& error) {
NOTREACHED();
}
} // namespace blink
// Copyright 2015 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 ExistingPresentationConnectionCallbacks_h
#define ExistingPresentationConnectionCallbacks_h
#include "platform/heap/Handle.h"
#include "public/platform/WebCallbacks.h"
#include "wtf/Noncopyable.h"
namespace blink {
class PresentationConnection;
class ScriptPromiseResolver;
struct WebPresentationError;
struct WebPresentationSessionInfo;
// ExistingPresentationConnectionCallbacks extends WebCallbacks to resolve the
// underlying promise. It takes the PresentationConnection object that
// originated the call in its constructor and will resolve underlying promise
// with that object.
class ExistingPresentationConnectionCallbacks final
: public WebCallbacks<const WebPresentationSessionInfo&,
const WebPresentationError&> {
public:
ExistingPresentationConnectionCallbacks(ScriptPromiseResolver*,
PresentationConnection*);
~ExistingPresentationConnectionCallbacks() override = default;
void onSuccess(const WebPresentationSessionInfo&) override;
void onError(const WebPresentationError&) override;
private:
Persistent<ScriptPromiseResolver> m_resolver;
Persistent<PresentationConnection> m_connection;
WTF_MAKE_NONCOPYABLE(ExistingPresentationConnectionCallbacks);
};
} // namespace blink
#endif // ExistingPresentationConnectionCallbacks_h
...@@ -381,6 +381,10 @@ void PresentationConnection::didReceiveBinaryMessage(const uint8_t* data, ...@@ -381,6 +381,10 @@ void PresentationConnection::didReceiveBinaryMessage(const uint8_t* data,
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
WebPresentationConnectionState PresentationConnection::getState() {
return m_state;
}
void PresentationConnection::close() { void PresentationConnection::close() {
if (m_state != WebPresentationConnectionState::Connecting && if (m_state != WebPresentationConnectionState::Connecting &&
m_state != WebPresentationConnectionState::Connected) { m_state != WebPresentationConnectionState::Connected) {
...@@ -408,6 +412,10 @@ bool PresentationConnection::matches( ...@@ -408,6 +412,10 @@ bool PresentationConnection::matches(
return m_url == KURL(sessionInfo.url) && m_id == String(sessionInfo.id); return m_url == KURL(sessionInfo.url) && m_id == String(sessionInfo.id);
} }
bool PresentationConnection::matches(const String& id, const KURL& url) const {
return m_url == url && m_id == id;
}
void PresentationConnection::didChangeState( void PresentationConnection::didChangeState(
WebPresentationConnectionState state) { WebPresentationConnectionState state) {
if (m_state == state) if (m_state == state)
......
...@@ -73,6 +73,10 @@ class PresentationConnection final : public EventTargetWithInlineData, ...@@ -73,6 +73,10 @@ class PresentationConnection final : public EventTargetWithInlineData,
// connection. // connection.
bool matches(const WebPresentationSessionInfo&) const; bool matches(const WebPresentationSessionInfo&) const;
// Returns true if this connection's id equals to |id| and its url equals to
// |url|.
bool matches(const String& id, const KURL&) const;
// Notifies the connection about its state change. // Notifies the connection about its state change.
void didChangeState(WebPresentationConnectionState); void didChangeState(WebPresentationConnectionState);
...@@ -83,6 +87,8 @@ class PresentationConnection final : public EventTargetWithInlineData, ...@@ -83,6 +87,8 @@ class PresentationConnection final : public EventTargetWithInlineData,
void didReceiveTextMessage(const String& message); void didReceiveTextMessage(const String& message);
void didReceiveBinaryMessage(const uint8_t* data, size_t length); void didReceiveBinaryMessage(const uint8_t* data, size_t length);
WebPresentationConnectionState getState();
protected: protected:
// EventTarget implementation. // EventTarget implementation.
void addedEventListener(const AtomicString& eventType, void addedEventListener(const AtomicString& eventType,
......
...@@ -26,8 +26,9 @@ PresentationConnectionCallbacks::PresentationConnectionCallbacks( ...@@ -26,8 +26,9 @@ PresentationConnectionCallbacks::PresentationConnectionCallbacks(
void PresentationConnectionCallbacks::onSuccess( void PresentationConnectionCallbacks::onSuccess(
const WebPresentationSessionInfo& sessionInfo) { const WebPresentationSessionInfo& sessionInfo) {
if (!m_resolver->getExecutionContext() || if (!m_resolver->getExecutionContext() ||
m_resolver->getExecutionContext()->isContextDestroyed()) m_resolver->getExecutionContext()->isContextDestroyed()) {
return; return;
}
m_resolver->resolve( m_resolver->resolve(
PresentationConnection::take(m_resolver.get(), sessionInfo, m_request)); PresentationConnection::take(m_resolver.get(), sessionInfo, m_request));
} }
......
...@@ -136,6 +136,21 @@ void PresentationController::contextDestroyed() { ...@@ -136,6 +136,21 @@ void PresentationController::contextDestroyed() {
} }
} }
PresentationConnection* PresentationController::findExistingConnection(
const blink::WebVector<blink::WebURL>& presentationUrls,
const blink::WebString& presentationId) {
for (const auto& connection : m_connections) {
for (const auto& presentationUrl : presentationUrls) {
if (connection->getState() !=
WebPresentationConnectionState::Terminated &&
connection->matches(presentationId, presentationUrl)) {
return connection.get();
}
}
}
return nullptr;
}
PresentationConnection* PresentationController::findConnection( PresentationConnection* PresentationController::findConnection(
const WebPresentationSessionInfo& sessionInfo) { const WebPresentationSessionInfo& sessionInfo) {
for (const auto& connection : m_connections) { for (const auto& connection : m_connections) {
......
...@@ -70,6 +70,13 @@ class MODULES_EXPORT PresentationController final ...@@ -70,6 +70,13 @@ class MODULES_EXPORT PresentationController final
// Handling of running connections. // Handling of running connections.
void registerConnection(PresentationConnection*); void registerConnection(PresentationConnection*);
// Return a connection in |m_connections| with id equals to |presentationId|,
// url equals to one of |presentationUrls|, and state is not terminated.
// Return null if such a connection does not exist.
PresentationConnection* findExistingConnection(
const blink::WebVector<blink::WebURL>& presentationUrls,
const blink::WebString& presentationId);
private: private:
PresentationController(LocalFrame&, WebPresentationClient*); PresentationController(LocalFrame&, WebPresentationClient*);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "core/frame/UseCounter.h" #include "core/frame/UseCounter.h"
#include "core/loader/MixedContentChecker.h" #include "core/loader/MixedContentChecker.h"
#include "modules/EventTargetModules.h" #include "modules/EventTargetModules.h"
#include "modules/presentation/ExistingPresentationConnectionCallbacks.h"
#include "modules/presentation/PresentationAvailability.h" #include "modules/presentation/PresentationAvailability.h"
#include "modules/presentation/PresentationAvailabilityCallbacks.h" #include "modules/presentation/PresentationAvailabilityCallbacks.h"
#include "modules/presentation/PresentationConnection.h" #include "modules/presentation/PresentationConnection.h"
...@@ -28,14 +29,18 @@ namespace blink { ...@@ -28,14 +29,18 @@ namespace blink {
namespace { namespace {
// TODO(mlamouri): refactor in one common place. // TODO(mlamouri): refactor in one common place.
WebPresentationClient* presentationClient(ExecutionContext* executionContext) { PresentationController* presentationController(
ExecutionContext* executionContext) {
DCHECK(executionContext); DCHECK(executionContext);
Document* document = toDocument(executionContext); Document* document = toDocument(executionContext);
if (!document->frame()) if (!document->frame())
return nullptr; return nullptr;
PresentationController* controller = return PresentationController::from(*document->frame());
PresentationController::from(*document->frame()); }
WebPresentationClient* presentationClient(ExecutionContext* executionContext) {
PresentationController* controller = presentationController(executionContext);
return controller ? controller->client() : nullptr; return controller ? controller->client() : nullptr;
} }
...@@ -163,9 +168,23 @@ ScriptPromise PresentationRequest::reconnect(ScriptState* scriptState, ...@@ -163,9 +168,23 @@ ScriptPromise PresentationRequest::reconnect(ScriptState* scriptState,
// TODO(crbug.com/627655): Accept multiple URLs per PresentationRequest. // TODO(crbug.com/627655): Accept multiple URLs per PresentationRequest.
WebVector<WebURL> presentationUrls(static_cast<size_t>(1U)); WebVector<WebURL> presentationUrls(static_cast<size_t>(1U));
presentationUrls[0] = m_url; presentationUrls[0] = m_url;
client->joinSession(
presentationUrls, id, PresentationController* controller =
WTF::makeUnique<PresentationConnectionCallbacks>(resolver, this)); presentationController(getExecutionContext());
DCHECK(controller);
PresentationConnection* existingConnection =
controller->findExistingConnection(presentationUrls, id);
if (existingConnection) {
client->joinSession(
presentationUrls, id,
WTF::makeUnique<ExistingPresentationConnectionCallbacks>(
resolver, existingConnection));
} else {
client->joinSession(
presentationUrls, id,
WTF::makeUnique<PresentationConnectionCallbacks>(resolver, this));
}
return resolver->promise(); return resolver->promise();
} }
......
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