blob: fec96dbf71389ffe604b0795f966765e9b1e8c7f [file] [log] [blame]
// Copyright 2013 The Flutter 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 <memory>
#include <vector>
#include "flutter/shell/platform/windows/compositor_software.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
#include "flutter/shell/platform/windows/testing/windows_test.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
namespace {
using ::testing::Return;
class MockFlutterWindowsView : public FlutterWindowsView {
public:
MockFlutterWindowsView(FlutterWindowsEngine* engine,
std::unique_ptr<WindowBindingHandler> window)
: FlutterWindowsView(kImplicitViewId, engine, std::move(window)) {}
virtual ~MockFlutterWindowsView() = default;
MOCK_METHOD(bool,
PresentSoftwareBitmap,
(const void* allocation, size_t row_bytes, size_t height),
(override));
MOCK_METHOD(bool, ClearSoftwareBitmap, (), (override));
private:
FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
};
class CompositorSoftwareTest : public WindowsTest {
public:
CompositorSoftwareTest() = default;
virtual ~CompositorSoftwareTest() = default;
protected:
FlutterWindowsEngine* engine() { return engine_.get(); }
MockFlutterWindowsView* view() { return view_.get(); }
void UseEngineWithView() {
FlutterWindowsEngineBuilder builder{GetContext()};
auto window = std::make_unique<MockWindowBindingHandler>();
EXPECT_CALL(*window.get(), SetView).Times(1);
EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr));
engine_ = builder.Build();
view_ = std::make_unique<MockFlutterWindowsView>(engine_.get(),
std::move(window));
}
private:
std::unique_ptr<FlutterWindowsEngine> engine_;
std::unique_ptr<MockFlutterWindowsView> view_;
FML_DISALLOW_COPY_AND_ASSIGN(CompositorSoftwareTest);
};
} // namespace
TEST_F(CompositorSoftwareTest, CreateBackingStore) {
CompositorSoftware compositor;
FlutterBackingStoreConfig config = {};
FlutterBackingStore backing_store = {};
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
}
TEST_F(CompositorSoftwareTest, Present) {
UseEngineWithView();
CompositorSoftware compositor;
FlutterBackingStoreConfig config = {};
FlutterBackingStore backing_store = {};
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
FlutterLayer layer = {};
layer.type = kFlutterLayerContentTypeBackingStore;
layer.backing_store = &backing_store;
const FlutterLayer* layer_ptr = &layer;
EXPECT_CALL(*view(), PresentSoftwareBitmap).WillOnce(Return(true));
EXPECT_TRUE(compositor.Present(view(), &layer_ptr, 1));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
}
TEST_F(CompositorSoftwareTest, PresentEmpty) {
UseEngineWithView();
CompositorSoftware compositor;
EXPECT_CALL(*view(), ClearSoftwareBitmap).WillOnce(Return(true));
EXPECT_TRUE(compositor.Present(view(), nullptr, 0));
}
// Test compositing an upper layer on a base layer, each 2x2 pixels.
// Base layer has opaque pixel values:
// BLACK RED
// GREEN WHITE
// Overlay layer has pixel values:
// RED: 127 WHITE: 0
// BLUE: 127 BLACK: 255
TEST_F(CompositorSoftwareTest, PresentMultiLayers) {
UseEngineWithView();
CompositorSoftware compositor;
FlutterBackingStoreConfig config = {sizeof(config), {2, 2}};
FlutterBackingStore backing_store0 = {sizeof(FlutterBackingStore), nullptr};
FlutterBackingStore backing_store1 = {sizeof(FlutterBackingStore), nullptr};
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store0));
ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store1));
uint32_t pixels0[4] = {0xff000000, 0xff0000ff, 0xff00ff00, 0xffffffff};
uint32_t pixels1[4] = {0x7f0000ff, 0x00ffffff, 0x7fff0000, 0xff000000};
std::memcpy(const_cast<void*>(backing_store0.software.allocation), pixels0,
sizeof(uint32_t) * 4);
std::memcpy(const_cast<void*>(backing_store1.software.allocation), pixels1,
sizeof(uint32_t) * 4);
FlutterLayer layer0 = {};
layer0.type = kFlutterLayerContentTypeBackingStore;
layer0.backing_store = &backing_store0;
layer0.offset = {0, 0};
layer0.size = {2, 2};
FlutterLayer layer1 = layer0;
layer1.backing_store = &backing_store1;
const FlutterLayer* layer_ptr[2] = {&layer0, &layer1};
EXPECT_CALL(*view(), PresentSoftwareBitmap)
.WillOnce([&](const void* allocation, size_t row_bytes, size_t height) {
auto pixel_data = static_cast<const uint32_t*>(allocation);
EXPECT_EQ(row_bytes, 2 * sizeof(uint32_t));
EXPECT_EQ(height, 2);
EXPECT_EQ(pixel_data[0], 0xff00007f);
EXPECT_EQ(pixel_data[1], 0xff0000ff);
EXPECT_EQ(pixel_data[2], 0xff7f8000);
EXPECT_EQ(pixel_data[3], 0xff000000);
return true;
});
EXPECT_TRUE(compositor.Present(view(), layer_ptr, 2));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store0));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store1));
}
// Test compositing layers with offsets.
// 0th layer is a single red pixel in the top-left.
// 1st layer is a row of two blue pixels on the second row.
TEST_F(CompositorSoftwareTest, PresentOffsetLayers) {
UseEngineWithView();
CompositorSoftware compositor;
FlutterBackingStoreConfig config0 = {sizeof(FlutterBackingStoreConfig),
{1, 1}};
FlutterBackingStore backing_store0 = {sizeof(FlutterBackingStore), nullptr};
FlutterBackingStoreConfig config1 = {sizeof(FlutterBackingStoreConfig),
{2, 1}};
FlutterBackingStore backing_store1 = {sizeof(FlutterBackingStore), nullptr};
ASSERT_TRUE(compositor.CreateBackingStore(config0, &backing_store0));
ASSERT_TRUE(compositor.CreateBackingStore(config1, &backing_store1));
uint32_t pixels0 = 0xff0000ff;
uint32_t pixels1[2] = {0xffff0000, 0xffff0000};
std::memcpy(const_cast<void*>(backing_store0.software.allocation), &pixels0,
sizeof(uint32_t) * 1);
std::memcpy(const_cast<void*>(backing_store1.software.allocation), pixels1,
sizeof(uint32_t) * 2);
FlutterLayer layer0 = {};
layer0.type = kFlutterLayerContentTypeBackingStore;
layer0.backing_store = &backing_store0;
layer0.offset = {0, 0};
layer0.size = {1, 1};
FlutterLayer layer1 = layer0;
layer1.backing_store = &backing_store1;
layer1.offset = {0, 1};
layer1.size = {2, 1};
const FlutterLayer* layer_ptr[2] = {&layer0, &layer1};
EXPECT_CALL(*view(), PresentSoftwareBitmap)
.WillOnce([&](const void* allocation, size_t row_bytes, size_t height) {
auto pixel_data = static_cast<const uint32_t*>(allocation);
EXPECT_EQ(row_bytes, 2 * sizeof(uint32_t));
EXPECT_EQ(height, 2);
EXPECT_EQ(pixel_data[0], 0xff0000ff);
EXPECT_EQ(pixel_data[1], 0xff000000);
EXPECT_EQ(pixel_data[2], 0xffff0000);
EXPECT_EQ(pixel_data[3], 0xffff0000);
return true;
});
EXPECT_TRUE(compositor.Present(view(), layer_ptr, 2));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store0));
ASSERT_TRUE(compositor.CollectBackingStore(&backing_store1));
}
} // namespace testing
} // namespace flutter