blob: 65d7ad8173caf892127e8fff2cd5d076abb26f98 [file] [log] [blame]
// 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 "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_menu_source_type.h"
#include "third_party/blink/public/web/web_context_menu_data.h"
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/geometry/dom_rect.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
using testing::Return;
namespace blink {
namespace {
class MockWebMediaPlayerForContextMenu : public EmptyWebMediaPlayer {
public:
MOCK_CONST_METHOD0(HasAudio, bool());
MOCK_CONST_METHOD0(HasVideo, bool());
};
class TestWebFrameClientImpl : public FrameTestHelpers::TestWebFrameClient {
public:
void ShowContextMenu(const WebContextMenuData& data) override {
context_menu_data_ = data;
}
WebMediaPlayer* CreateMediaPlayer(const WebMediaPlayerSource&,
WebMediaPlayerClient*,
WebMediaPlayerEncryptedMediaClient*,
WebContentDecryptionModule*,
const WebString& sink_id,
WebLayerTreeView*) override {
return new MockWebMediaPlayerForContextMenu();
}
const WebContextMenuData& GetContextMenuData() const {
return context_menu_data_;
}
private:
WebContextMenuData context_menu_data_;
};
} // anonymous namespace
class ContextMenuControllerTest : public testing::Test {
public:
void SetUp() override {
web_view_helper_.Initialize(&web_frame_client_);
WebLocalFrameImpl* local_main_frame = web_view_helper_.LocalMainFrame();
local_main_frame->ViewImpl()->Resize(WebSize(640, 480));
local_main_frame->ViewImpl()->UpdateAllLifecyclePhases();
}
bool ShowContextMenu(const LayoutPoint& location, WebMenuSourceType source) {
return web_view_helper_.GetWebView()
->GetPage()
->GetContextMenuController()
.ShowContextMenu(GetDocument()->GetFrame(), location, source);
}
Document* GetDocument() {
return static_cast<Document*>(
web_view_helper_.LocalMainFrame()->GetDocument());
}
Page* GetPage() { return web_view_helper_.GetWebView()->GetPage(); }
const TestWebFrameClientImpl& GetWebFrameClient() const {
return web_frame_client_;
}
void SetReadyState(HTMLVideoElement* video,
HTMLMediaElement::ReadyState state) {
video->SetReadyState(state);
}
private:
TestWebFrameClientImpl web_frame_client_;
FrameTestHelpers::WebViewHelper web_view_helper_;
};
TEST_F(ContextMenuControllerTest, VideoNotLoaded) {
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
// Setup video element.
Persistent<HTMLVideoElement> video = HTMLVideoElement::Create(*GetDocument());
video->SetSrc(video_url);
GetDocument()->body()->AppendChild(video);
test::RunPendingTasks();
SetReadyState(video.Get(), HTMLMediaElement::kHaveNothing);
test::RunPendingTasks();
EXPECT_CALL(*static_cast<MockWebMediaPlayerForContextMenu*>(
video->GetWebMediaPlayer()),
HasVideo())
.WillRepeatedly(Return(false));
DOMRect* rect = video->getBoundingClientRect();
LayoutPoint location((rect->left() + rect->right()) / 2,
(rect->top() + rect->bottom()) / 2);
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
WebContextMenuData context_menu_data =
GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type);
EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>>
expected_media_flags = {
{WebContextMenuData::kMediaInError, false},
{WebContextMenuData::kMediaPaused, true},
{WebContextMenuData::kMediaMuted, false},
{WebContextMenuData::kMediaLoop, false},
{WebContextMenuData::kMediaCanSave, true},
{WebContextMenuData::kMediaHasAudio, false},
{WebContextMenuData::kMediaCanToggleControls, false},
{WebContextMenuData::kMediaControls, false},
{WebContextMenuData::kMediaCanPrint, false},
{WebContextMenuData::kMediaCanRotate, false},
{WebContextMenuData::kMediaCanPictureInPicture, false},
{WebContextMenuData::kMediaPictureInPicture, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
EXPECT_EQ(expected_media_flag.second,
!!(context_menu_data.media_flags & expected_media_flag.first))
<< "Flag 0x" << std::hex << expected_media_flag.first;
}
}
TEST_F(ContextMenuControllerTest, VideoWithAudioOnly) {
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
// Setup video element.
Persistent<HTMLVideoElement> video = HTMLVideoElement::Create(*GetDocument());
video->SetSrc(video_url);
GetDocument()->body()->AppendChild(video);
test::RunPendingTasks();
SetReadyState(video.Get(), HTMLMediaElement::kHaveNothing);
test::RunPendingTasks();
EXPECT_CALL(*static_cast<MockWebMediaPlayerForContextMenu*>(
video->GetWebMediaPlayer()),
HasVideo())
.WillRepeatedly(Return(false));
EXPECT_CALL(*static_cast<MockWebMediaPlayerForContextMenu*>(
video->GetWebMediaPlayer()),
HasAudio())
.WillRepeatedly(Return(true));
DOMRect* rect = video->getBoundingClientRect();
LayoutPoint location((rect->left() + rect->right()) / 2,
(rect->top() + rect->bottom()) / 2);
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
WebContextMenuData context_menu_data =
GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(WebContextMenuData::kMediaTypeAudio, context_menu_data.media_type);
EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>>
expected_media_flags = {
{WebContextMenuData::kMediaInError, false},
{WebContextMenuData::kMediaPaused, true},
{WebContextMenuData::kMediaMuted, false},
{WebContextMenuData::kMediaLoop, false},
{WebContextMenuData::kMediaCanSave, true},
{WebContextMenuData::kMediaHasAudio, true},
{WebContextMenuData::kMediaCanToggleControls, false},
{WebContextMenuData::kMediaControls, false},
{WebContextMenuData::kMediaCanPrint, false},
{WebContextMenuData::kMediaCanRotate, false},
{WebContextMenuData::kMediaCanPictureInPicture, false},
{WebContextMenuData::kMediaPictureInPicture, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
EXPECT_EQ(expected_media_flag.second,
!!(context_menu_data.media_flags & expected_media_flag.first))
<< "Flag 0x" << std::hex << expected_media_flag.first;
}
}
TEST_F(ContextMenuControllerTest, PictureInPictureEnabledVideoLoaded) {
// Make sure Picture-in-Picture is enabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(true);
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
// Setup video element.
Persistent<HTMLVideoElement> video = HTMLVideoElement::Create(*GetDocument());
video->SetSrc(video_url);
GetDocument()->body()->AppendChild(video);
test::RunPendingTasks();
SetReadyState(video.Get(), HTMLMediaElement::kHaveMetadata);
test::RunPendingTasks();
EXPECT_CALL(*static_cast<MockWebMediaPlayerForContextMenu*>(
video->GetWebMediaPlayer()),
HasVideo())
.WillRepeatedly(Return(true));
DOMRect* rect = video->getBoundingClientRect();
LayoutPoint location((rect->left() + rect->right()) / 2,
(rect->top() + rect->bottom()) / 2);
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
WebContextMenuData context_menu_data =
GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type);
EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>>
expected_media_flags = {
{WebContextMenuData::kMediaInError, false},
{WebContextMenuData::kMediaPaused, true},
{WebContextMenuData::kMediaMuted, false},
{WebContextMenuData::kMediaLoop, false},
{WebContextMenuData::kMediaCanSave, true},
{WebContextMenuData::kMediaHasAudio, false},
{WebContextMenuData::kMediaCanToggleControls, true},
{WebContextMenuData::kMediaControls, false},
{WebContextMenuData::kMediaCanPrint, false},
{WebContextMenuData::kMediaCanRotate, false},
{WebContextMenuData::kMediaCanPictureInPicture, true},
{WebContextMenuData::kMediaPictureInPicture, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
EXPECT_EQ(expected_media_flag.second,
!!(context_menu_data.media_flags & expected_media_flag.first))
<< "Flag 0x" << std::hex << expected_media_flag.first;
}
}
TEST_F(ContextMenuControllerTest, PictureInPictureDisabledVideoLoaded) {
// Make sure Picture-in-Picture is disabled.
GetDocument()->GetSettings()->SetPictureInPictureEnabled(false);
ContextMenuAllowedScope context_menu_allowed_scope;
HitTestResult hit_test_result;
const char video_url[] = "https://example.com/foo.webm";
// Setup video element.
Persistent<HTMLVideoElement> video = HTMLVideoElement::Create(*GetDocument());
video->SetSrc(video_url);
GetDocument()->body()->AppendChild(video);
test::RunPendingTasks();
SetReadyState(video.Get(), HTMLMediaElement::kHaveMetadata);
test::RunPendingTasks();
EXPECT_CALL(*static_cast<MockWebMediaPlayerForContextMenu*>(
video->GetWebMediaPlayer()),
HasVideo())
.WillRepeatedly(Return(true));
DOMRect* rect = video->getBoundingClientRect();
LayoutPoint location((rect->left() + rect->right()) / 2,
(rect->top() + rect->bottom()) / 2);
EXPECT_TRUE(ShowContextMenu(location, kMenuSourceMouse));
// Context menu info are sent to the WebLocalFrameClient.
WebContextMenuData context_menu_data =
GetWebFrameClient().GetContextMenuData();
EXPECT_EQ(WebContextMenuData::kMediaTypeVideo, context_menu_data.media_type);
EXPECT_EQ(video_url, context_menu_data.src_url.GetString());
const std::vector<std::pair<WebContextMenuData::MediaFlags, bool>>
expected_media_flags = {
{WebContextMenuData::kMediaInError, false},
{WebContextMenuData::kMediaPaused, true},
{WebContextMenuData::kMediaMuted, false},
{WebContextMenuData::kMediaLoop, false},
{WebContextMenuData::kMediaCanSave, true},
{WebContextMenuData::kMediaHasAudio, false},
{WebContextMenuData::kMediaCanToggleControls, true},
{WebContextMenuData::kMediaControls, false},
{WebContextMenuData::kMediaCanPrint, false},
{WebContextMenuData::kMediaCanRotate, false},
{WebContextMenuData::kMediaCanPictureInPicture, false},
{WebContextMenuData::kMediaPictureInPicture, false},
};
for (const auto& expected_media_flag : expected_media_flags) {
EXPECT_EQ(expected_media_flag.second,
!!(context_menu_data.media_flags & expected_media_flag.first))
<< "Flag 0x" << std::hex << expected_media_flag.first;
}
}
} // namespace blink