blob: f5ce2f8c1299cf12810d7d7cc37635da13176b24 [file] [log] [blame]
// 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 "core/html/shadow/MediaControls.h"
#include "core/HTMLNames.h"
#include "core/css/StylePropertySet.h"
#include "core/dom/Document.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/StyleEngine.h"
#include "core/frame/Settings.h"
#include "core/html/HTMLVideoElement.h"
#include "core/testing/DummyPageHolder.h"
#include "platform/heap/Handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
Element* getElementByShadowPseudoId(Node& rootNode, const char* shadowPseudoId)
{
for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
if (element.shadowPseudoId() == shadowPseudoId)
return &element;
}
return nullptr;
}
bool isElementVisible(Element& element)
{
const StylePropertySet* inlineStyle = element.inlineStyle();
if (!inlineStyle)
return true;
if (inlineStyle->getPropertyValue(CSSPropertyDisplay) == "none")
return false;
if (inlineStyle->hasProperty(CSSPropertyOpacity)
&& inlineStyle->getPropertyValue(CSSPropertyOpacity).toDouble() == 0.0)
return false;
if (inlineStyle->getPropertyValue(CSSPropertyVisibility) == "hidden")
return false;
if (Element* parent = element.parentElement())
return isElementVisible(*parent);
return true;
}
} // namespace
class MediaControlsTest : public testing::Test {
protected:
virtual void SetUp()
{
m_pageHolder = DummyPageHolder::create(IntSize(800, 600));
Document& document = this->document();
document.write("<video>");
HTMLVideoElement& video = toHTMLVideoElement(*document.querySelector("video", ASSERT_NO_EXCEPTION));
m_mediaControls = video.mediaControls();
// If scripts are not enabled, controls will always be shown.
m_pageHolder->frame().settings()->setScriptEnabled(true);
}
void simulateRouteAvailabe()
{
m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(true);
}
void ensureLayout()
{
// Force a relayout, so that the controls know the width. Otherwise,
// they don't know if, for example, the cast button will fit.
m_mediaControls->mediaElement().clientWidth();
}
MediaControls& mediaControls() { return *m_mediaControls; }
Document& document() { return m_pageHolder->document(); }
private:
OwnPtr<DummyPageHolder> m_pageHolder;
Persistent<MediaControls> m_mediaControls;
};
TEST_F(MediaControlsTest, HideAndShow)
{
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
ASSERT_NE(nullptr, panel);
ASSERT_TRUE(isElementVisible(*panel));
mediaControls().hide();
ASSERT_FALSE(isElementVisible(*panel));
mediaControls().show();
ASSERT_TRUE(isElementVisible(*panel));
}
TEST_F(MediaControlsTest, Reset)
{
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
ASSERT_NE(nullptr, panel);
ASSERT_TRUE(isElementVisible(*panel));
mediaControls().reset();
ASSERT_TRUE(isElementVisible(*panel));
}
TEST_F(MediaControlsTest, HideAndReset)
{
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
Element* panel = getElementByShadowPseudoId(mediaControls(), "-webkit-media-controls-panel");
ASSERT_NE(nullptr, panel);
ASSERT_TRUE(isElementVisible(*panel));
mediaControls().hide();
ASSERT_FALSE(isElementVisible(*panel));
mediaControls().reset();
ASSERT_FALSE(isElementVisible(*panel));
}
TEST_F(MediaControlsTest, ResetDoesNotTriggerInitialLayout)
{
Document& document = this->document();
int oldElementCount = document.styleEngine().styleForElementCount();
// Also assert that there are no layouts yet.
ASSERT_EQ(0, oldElementCount);
mediaControls().reset();
int newElementCount = document.styleEngine().styleForElementCount();
ASSERT_EQ(oldElementCount, newElementCount);
}
TEST_F(MediaControlsTest, CastButtonRequiresRoute)
{
ensureLayout();
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
Element* castButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-cast-button");
ASSERT_NE(nullptr, castButton);
ASSERT_FALSE(isElementVisible(*castButton));
simulateRouteAvailabe();
ASSERT_TRUE(isElementVisible(*castButton));
}
TEST_F(MediaControlsTest, CastButtonDisableRemotePlaybackAttr)
{
ensureLayout();
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::controlsAttr, true);
Element* castButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-cast-button");
ASSERT_NE(nullptr, castButton);
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, true);
simulateRouteAvailabe();
ASSERT_FALSE(isElementVisible(*castButton));
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, false);
mediaControls().reset();
ASSERT_TRUE(isElementVisible(*castButton));
}
TEST_F(MediaControlsTest, CastOverlayDefault)
{
Element* castOverlayButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-overlay-cast-button");
ASSERT_NE(nullptr, castOverlayButton);
simulateRouteAvailabe();
ASSERT_TRUE(isElementVisible(*castOverlayButton));
}
TEST_F(MediaControlsTest, CastOverlayDisableRemotePlaybackAttr)
{
Element* castOverlayButton = getElementByShadowPseudoId(mediaControls(), "-internal-media-controls-overlay-cast-button");
ASSERT_NE(nullptr, castOverlayButton);
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, true);
simulateRouteAvailabe();
ASSERT_FALSE(isElementVisible(*castOverlayButton));
mediaControls().mediaElement().setBooleanAttribute(HTMLNames::disableremoteplaybackAttr, false);
mediaControls().reset();
ASSERT_TRUE(isElementVisible(*castOverlayButton));
}
} // namespace blink