blob: 022834fd28678af975e7c3585142f65210329528 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/vr/test/ui_test.h"
#include "chrome/browser/vr/elements/rect.h"
#include "chrome/browser/vr/model/model.h"
#include "chrome/browser/vr/render_info.h"
#include "chrome/browser/vr/test/animation_utils.h"
#include "chrome/browser/vr/test/constants.h"
#include "chrome/browser/vr/ui.h"
#include "chrome/browser/vr/ui_scene.h"
#include "chrome/browser/vr/ui_scene_creator.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace vr {
namespace {
gfx::Vector3dF ComputeNormal(const gfx::Transform& transform) {
gfx::Vector3dF x_axis = transform.MapVector(gfx::Vector3dF(1, 0, 0));
gfx::Vector3dF y_axis = transform.MapVector(gfx::Vector3dF(0, 1, 0));
gfx::Vector3dF normal = CrossProduct(x_axis, y_axis);
normal.GetNormalized(&normal);
return normal;
}
bool WillElementFaceCamera(const UiElement* element) {
// Element might become invisible due to incorrect rotation, i.e when rotation
// cause the visible side of the element flip.
// Here we calculate the dot product of (origin - center) and normal. If the
// result is greater than 0, it means the visible side of this element is
// facing camera.
gfx::Transform transform = element->ComputeTargetWorldSpaceTransform();
gfx::Point3F center = transform.MapPoint(gfx::Point3F());
gfx::Point3F origin;
gfx::Vector3dF normal = ComputeNormal(transform);
if (center == origin) {
// If the center of element is at origin, as our camera facing negative z.
// we only need to make sure the normal of the element have positive z.
return normal.z() > 0.f;
}
return gfx::DotProduct(origin - center, normal) > 0.f;
}
// This method tests whether an element will be visible after all pending scene
// animations complete.
bool WillElementBeVisible(const UiElement* element) {
if (!element)
return false;
if (element->ComputeTargetOpacity() == 0.f)
return false;
if (!element->IsWorldPositioned())
return true;
return WillElementFaceCamera(element);
}
} // namespace
UiTest::UiTest() = default;
UiTest::~UiTest() = default;
void UiTest::SetUp() {
ui_instance_ = std::make_unique<Ui>();
ui_ = ui_instance_.get();
scene_ = ui_instance_->scene();
model_ = ui_instance_->model_for_test();
OnBeginFrame();
// Need a second BeginFrame here because the first one will add controllers
// to the scene, which need an additional frame to get into a good state.
OnBeginFrame();
}
bool UiTest::IsVisible(UiElementName name) const {
OnBeginFrame();
UiElement* element = scene_->GetUiElementByName(name);
return WillElementBeVisible(element);
}
bool UiTest::VerifyVisibility(const std::set<UiElementName>& names,
bool expected_visibility) const {
OnBeginFrame();
for (auto name : names) {
SCOPED_TRACE(UiElementNameToString(name));
UiElement* element = scene_->GetUiElementByName(name);
bool will_be_visible = WillElementBeVisible(element);
// TODO(https://crbug.com/327467653): Timeout Spinner only visible on
// Windows.
#if !BUILDFLAG(IS_WIN)
if (name == kWebVrTimeoutSpinner) {
will_be_visible = expected_visibility;
}
#endif
EXPECT_EQ(will_be_visible, expected_visibility);
if (will_be_visible != expected_visibility)
return false;
}
return true;
}
void UiTest::VerifyOnlyElementsVisible(
const std::string& trace_context,
const std::set<UiElementName>& names) const {
OnBeginFrame();
SCOPED_TRACE(trace_context);
for (vr::UiElement* element : scene_->GetAllElements()) {
SCOPED_TRACE(element->DebugName());
UiElementName name = element->name();
UiElementName owner_name = element->owner_name_for_test();
if (element->draw_phase() == kPhaseNone && owner_name == kNone) {
EXPECT_TRUE(names.find(name) == names.end());
continue;
}
if (name == kNone)
name = owner_name;
bool should_be_visible = (names.find(name) != names.end());
EXPECT_EQ(WillElementBeVisible(element), should_be_visible);
}
}
bool UiTest::RunForMs(float milliseconds) {
return RunFor(base::Milliseconds(milliseconds));
}
bool UiTest::RunForSeconds(float seconds) {
return RunFor(base::Seconds(seconds));
}
bool UiTest::AdvanceFrame() {
current_time_ += base::Milliseconds(16);
return OnBeginFrame();
}
bool UiTest::RunFor(base::TimeDelta delta) {
base::TimeTicks target_time = current_time_ + delta;
base::TimeDelta frame_time = base::Milliseconds(16);
bool changed = false;
// Run a frame in the near future to trigger new state changes.
current_time_ += frame_time;
changed |= OnBeginFrame();
// If needed, skip ahead and run another frame at the target time.
if (current_time_ < target_time) {
current_time_ = target_time;
changed |= OnBeginFrame();
}
return changed;
}
bool UiTest::OnBeginFrame() const {
bool changed = false;
changed |= scene_->OnBeginFrame(current_time_, kStartHeadPose);
if (scene_->HasDirtyTextures()) {
scene_->UpdateTextures();
changed = true;
}
return changed;
}
} // namespace vr