Commit 3acfe10b authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

ws: EnsureClientHasDrawnWindow sanity check output

Make WindowServerTestImpl::EnsureClientHasDrawnWindow capture
output of the first ClientRoot window of the client and sanity
check the captured pixels. The output is considered okay when
there are more than 5 colors.

Bug: 908545
Change-Id: Iaa2306da6e2b40b0cf9a8379e71f564b0cf92a8b
Reviewed-on: https://chromium-review.googlesource.com/c/1406189Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#622086}
parent 9970df42
......@@ -92,8 +92,10 @@ component("lib") {
]
deps = [
"//components/viz/common",
"//services/ws/public/cpp",
"//services/ws/public/cpp/host",
"//skia",
]
if (use_ozone) {
......
......@@ -4,16 +4,52 @@
#include "services/ws/window_server_test_impl.h"
#include <set>
#include <utility>
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "services/ws/client_root.h"
#include "services/ws/public/mojom/window_tree.mojom.h"
#include "services/ws/window_service.h"
#include "services/ws/window_tree.h"
#include "ui/aura/window.h"
namespace ws {
namespace {
// Returns true if bitmap contains more than 5 different colors.
bool SanityCheckOutputSkBitmap(const SkBitmap& bitmap) {
DCHECK_EQ(bitmap.info().colorType(), kN32_SkColorType);
const uint32_t* packed_pixels =
reinterpret_cast<uint32_t*>(bitmap.getPixels());
if (!packed_pixels)
return false;
constexpr size_t kMaxColors = 5;
std::set<uint32_t> colors;
for (size_t i = 0; i < bitmap.computeByteSize(); i += 4) {
// Get the color ignoring alpha.
uint32_t c = SkColorSetA(packed_pixels[i >> 2], 0);
if (colors.find(c) != colors.end())
continue;
colors.insert(c);
if (colors.size() >= kMaxColors)
return true;
}
return false;
}
} // namespace
WindowServerTestImpl::WindowServerTestImpl(WindowService* window_service)
: window_service_(window_service) {}
WindowServerTestImpl::~WindowServerTestImpl() {}
WindowServerTestImpl::~WindowServerTestImpl() = default;
WindowTree* WindowServerTestImpl::GetWindowTreeWithClientName(
const std::string& name) {
......@@ -29,7 +65,7 @@ void WindowServerTestImpl::OnSurfaceActivated(
EnsureClientHasDrawnWindowCallback cb,
const std::string& actual_client_name) {
if (desired_client_name == actual_client_name) {
std::move(cb).Run(true);
RequestWindowContents(desired_client_name, std::move(cb));
} else {
// No tree with the given name, or it hasn't painted yet. Install a callback
// for the next time a client creates a CompositorFramesink.
......@@ -45,12 +81,46 @@ void WindowServerTestImpl::InstallCallback(
base::Unretained(this), client_name, std::move(cb)));
}
void WindowServerTestImpl::RequestWindowContents(
const std::string& client_name,
EnsureClientHasDrawnWindowCallback cb) {
ClientRoot* client_root = GetWindowTreeWithClientName(client_name)
->GetFirstRootWithCompositorFrameSink();
if (!client_root || client_root->window()->bounds().IsEmpty()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&WindowServerTestImpl::RequestWindowContents,
base::Unretained(this), client_name, std::move(cb)));
return;
}
auto copy_output_request = std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(&WindowServerTestImpl::OnWindowContentsCaptured,
base::Unretained(this), client_name, std::move(cb)));
aura::Window* window = client_root->window();
copy_output_request->set_area(gfx::Rect(window->bounds().size()));
window->layer()->RequestCopyOfOutput(std::move(copy_output_request));
}
void WindowServerTestImpl::OnWindowContentsCaptured(
const std::string& client_name,
EnsureClientHasDrawnWindowCallback cb,
std::unique_ptr<viz::CopyOutputResult> result) {
if (result->IsEmpty()) {
RequestWindowContents(client_name, std::move(cb));
return;
}
std::move(cb).Run(SanityCheckOutputSkBitmap(result->AsSkBitmap()));
}
void WindowServerTestImpl::EnsureClientHasDrawnWindow(
const std::string& client_name,
EnsureClientHasDrawnWindowCallback callback) {
WindowTree* tree = GetWindowTreeWithClientName(client_name);
if (tree && tree->HasAtLeastOneRootWithCompositorFrameSink()) {
std::move(callback).Run(true);
if (tree && tree->GetFirstRootWithCompositorFrameSink()) {
RequestWindowContents(client_name, std::move(callback));
return;
}
InstallCallback(client_name, std::move(callback));
......
......@@ -5,8 +5,14 @@
#ifndef SERVICES_WS_WINDOW_SERVER_TEST_IMPL_H_
#define SERVICES_WS_WINDOW_SERVER_TEST_IMPL_H_
#include <memory>
#include "services/ws/public/mojom/window_server_test.mojom.h"
namespace viz {
class CopyOutputResult;
}
namespace ws {
class WindowService;
......@@ -34,6 +40,14 @@ class WindowServerTestImpl : public mojom::WindowServerTest {
void InstallCallback(const std::string& name,
EnsureClientHasDrawnWindowCallback cb);
// Request to capture the window contents of the client and invoke the
// callback with sanity check result of the captured pixels.
void RequestWindowContents(const std::string& client_name,
EnsureClientHasDrawnWindowCallback cb);
void OnWindowContentsCaptured(const std::string& client_name,
EnsureClientHasDrawnWindowCallback cb,
std::unique_ptr<viz::CopyOutputResult> result);
// mojom::WindowServerTest:
void EnsureClientHasDrawnWindow(
const std::string& client_name,
......
......@@ -309,14 +309,14 @@ void WindowTree::CompleteScheduleEmbedForExistingClient(
client_root->RegisterVizEmbeddingSupport();
}
bool WindowTree::HasAtLeastOneRootWithCompositorFrameSink() {
ClientRoot* WindowTree::GetFirstRootWithCompositorFrameSink() {
for (auto& client_root : client_roots_) {
if (ProxyWindow::GetMayBeNull(client_root->window())
->attached_compositor_frame_sink()) {
return true;
return client_root.get();
}
}
return false;
return nullptr;
}
bool WindowTree::IsWindowKnown(aura::Window* window) const {
......
......@@ -140,9 +140,8 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowTree
ConnectionType connection_type() const { return connection_type_; }
// Returns true if at a compositor frame sink has been created for at least
// one of the roots.
bool HasAtLeastOneRootWithCompositorFrameSink();
// Returns the first ClientRoot that has its compositor frame sink created.
ClientRoot* GetFirstRootWithCompositorFrameSink();
// Returns true if |window| has been exposed to this client. A client
// typically only sees a limited set of windows that may exist. The set of
......
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