Introduce platform services interface

This commit is contained in:
2026-06-03 03:59:59 +02:00
parent 6960bd3410
commit 4ed72ebc80
10 changed files with 259 additions and 38 deletions

View File

@@ -210,6 +210,18 @@ target_link_libraries(pp_ui_core
pp_xml_tinyxml2 pp_xml_tinyxml2
pp_project_warnings) pp_project_warnings)
add_library(pp_platform_api STATIC
src/platform_api/platform_services.cpp
src/platform_api/platform_services.h)
target_include_directories(pp_platform_api
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/src")
target_link_libraries(pp_platform_api
PUBLIC
pp_project_options
PRIVATE
pp_project_warnings)
add_library(pp_app_core STATIC add_library(pp_app_core STATIC
src/app_core/document_cloud.h src/app_core/document_cloud.h
src/app_core/document_export.cpp src/app_core/document_export.cpp
@@ -482,6 +494,7 @@ if(PP_BUILD_APP)
pp_app_core pp_app_core
pp_legacy_app pp_legacy_app
pp_panopainter_ui pp_panopainter_ui
pp_platform_api
pp_project_options pp_project_options
PRIVATE PRIVATE
pp_project_warnings) pp_project_warnings)

View File

@@ -10,7 +10,7 @@ Keep it updated as platform paths move to shared CMake targets.
| Platform/Target | Current Entrypoint | Notes | | Platform/Target | Current Entrypoint | Notes |
| --- | --- | --- | | --- | --- | --- |
| Windows desktop | Root `CMakeLists.txt`, preset `windows-msvc-default`; target preset `windows-vs2026-x64` retained for VS 2026 | Raw `.sln/.vcxproj` files removed on 2026-05-31; local machine currently uses Visual Studio 17 2022; `PanoPainter` now links through `pp_platform_windows` and `panopainter_app`, with Windows/vendor link dependencies owned by the platform shell, runtime payload deployment in `cmake/PanoPainterRuntime.cmake`, tested app-level document-open routing plus open/close/save session decisions owned by `pp_app_core`, retained third-party source dependencies contained by `pp_legacy_vendor`, retained asset/file/serialization sources contained by `pp_legacy_assets_io`, retained paint/document/canvas sources contained by `pp_legacy_paint_document`, retained OpenGL runtime sources contained by `pp_legacy_renderer_gl` and folded into `pp_legacy_engine`, retained runtime shell sources contained by `pp_legacy_engine`, retained base UI controls contained by `pp_legacy_ui_core` and folded into `pp_legacy_app`, app orchestration/version metadata owned by `panopainter_app`, and app-specific modal/dialog/panel/canvas workflow nodes owned by `pp_panopainter_ui` | | Windows desktop | Root `CMakeLists.txt`, preset `windows-msvc-default`; target preset `windows-vs2026-x64` retained for VS 2026 | Raw `.sln/.vcxproj` files removed on 2026-05-31; local machine currently uses Visual Studio 17 2022; `PanoPainter` now links through `pp_platform_windows` and `panopainter_app`, with Windows/vendor link dependencies owned by the platform shell, runtime payload deployment in `cmake/PanoPainterRuntime.cmake`, tested app-level document-open routing plus open/close/save session decisions owned by `pp_app_core`, SDK-free clipboard/cursor/virtual-keyboard service contracts owned by `pp_platform_api`, retained third-party source dependencies contained by `pp_legacy_vendor`, retained asset/file/serialization sources contained by `pp_legacy_assets_io`, retained paint/document/canvas sources contained by `pp_legacy_paint_document`, retained OpenGL runtime sources contained by `pp_legacy_renderer_gl` and folded into `pp_legacy_engine`, retained runtime shell sources contained by `pp_legacy_engine`, retained base UI controls contained by `pp_legacy_ui_core` and folded into `pp_legacy_app`, app orchestration/version metadata owned by `panopainter_app`, and app-specific modal/dialog/panel/canvas workflow nodes owned by `pp_panopainter_ui` |
| Windows AppX | `PanoPainterPackage/Package.appxmanifest`, `.wapproj` referenced by solution | Distribution packaging | | Windows AppX | `PanoPainterPackage/Package.appxmanifest`, `.wapproj` referenced by solution | Distribution packaging |
| macOS | `PanoPainter-OSX/` project files and `Info.plist` | Uses `NSOpenGLView` today | | macOS | `PanoPainter-OSX/` project files and `Info.plist` | Uses `NSOpenGLView` today |
| iOS | `PanoPainter/Info.plist`, related Apple sources | Uses OpenGL ES today | | iOS | `PanoPainter/Info.plist`, related Apple sources | Uses OpenGL ES today |
@@ -444,6 +444,10 @@ Known local toolchain state:
`pp_app_core` clipboard text planning as JSON, including empty text writes; `pp_app_core` clipboard text planning as JSON, including empty text writes;
live clipboard get/set requests consume the same contracts before retained live clipboard get/set requests consume the same contracts before retained
platform clipboard bridges. platform clipboard bridges.
- `pp_platform_api` exposes the SDK-free `PlatformServices` interface for
clipboard text, cursor visibility, and virtual-keyboard visibility; live
app execution now reaches retained platform bridges through the
debt-tracked legacy adapter in `app_events.cpp`.
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability, - `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability,
new-document warning, publish prompt, and save-before-upload planning as JSON; new-document warning, publish prompt, and save-before-upload planning as JSON;
the live cloud upload command consumes the same start contract before the live cloud upload command consumes the same start contract before
@@ -480,6 +484,9 @@ Known local toolchain state:
show/hide planning before platform keyboard callbacks, plus cursor visibility show/hide planning before platform keyboard callbacks, plus cursor visibility
planning before platform cursor callbacks, plus clipboard read/write planning before platform cursor callbacks, plus clipboard read/write
planning before platform clipboard callbacks. planning before platform clipboard callbacks.
- `pp_platform_api_tests` covers service dispatch for clipboard read/write,
empty clipboard writes, cursor visibility, and virtual-keyboard visibility
without platform SDK headers or a window.
- `pp_app_core_document_cloud_tests` covers cloud upload no-canvas, - `pp_app_core_document_cloud_tests` covers cloud upload no-canvas,
new-document warning, clean publish prompt, and dirty save-before-upload new-document warning, clean publish prompt, and dirty save-before-upload
decisions, plus cloud browse no-canvas/show-browser and selected-download decisions, plus cloud browse no-canvas/show-browser and selected-download

View File

@@ -65,10 +65,10 @@ and validation command.
| Capability | Current Area | Target Owner | Required Tests | | Capability | Current Area | Target Owner | Required Tests |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Mouse/keyboard/touch/gestures/cursor | `App`, platform entrypoints | `pp_app_core`, `pp_platform_*`, app | Cursor visibility decision tests, synthetic event playback | | Mouse/keyboard/touch/gestures/cursor | `App`, platform entrypoints | `pp_app_core`, `pp_platform_api`, `pp_platform_*`, app | Cursor visibility decision tests, platform service dispatch tests, synthetic event playback |
| Wacom pressure | `WacomTablet` | `pp_platform_windows` | Adapter smoke with fallback | | Wacom pressure | `WacomTablet` | `pp_platform_windows` | Adapter smoke with fallback |
| Clipboard/file picker/share/display | `App` platform methods | `pp_app_core`, `pp_platform_*` | Clipboard read/write, share saved-path, picked-path, and display-file decision tests, platform smoke or mocked service | | Clipboard/file picker/share/display | `App` platform methods | `pp_app_core`, `pp_platform_api`, `pp_platform_*` | Clipboard read/write, share saved-path, picked-path, and display-file decision tests, platform service dispatch tests, platform smoke or mocked service |
| Virtual keyboard | `App`, platform entrypoints | `pp_app_core`, `pp_platform_*` | Keyboard visibility decision tests, platform smoke | | Virtual keyboard | `App`, platform entrypoints | `pp_app_core`, `pp_platform_api`, `pp_platform_*` | Keyboard visibility decision tests, platform service dispatch tests, platform smoke |
| OpenVR desktop | `HMD`, `Vive`, `app_vr` | `pp_platform_vr`, app | Compile gate and mocked pose tests | | OpenVR desktop | `HMD`, `Vive`, `app_vr` | `pp_platform_vr`, app | Compile gate and mocked pose tests |
| Quest/OVR | Android Quest files | `pp_platform_android_quest` | Compile/package gate | | Quest/OVR | Android Quest files | `pp_platform_android_quest` | Compile/package gate |
| Focus/Wave | Android Focus files | `pp_platform_android_wave` | Compile/package gate | | Focus/Wave | Android Focus files | `pp_platform_android_wave` | Compile/package gate |

View File

@@ -1,7 +1,7 @@
# Modernization Debt Log # Modernization Debt Log
Status: live Status: live
Last updated: 2026-06-02 Last updated: 2026-06-03
Every shortcut, temporary adapter, retained vendored dependency, skipped Every shortcut, temporary adapter, retained vendored dependency, skipped
platform gate, compatibility shim, or incomplete automation path must be platform gate, compatibility shim, or incomplete automation path must be
@@ -35,6 +35,7 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix | | DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix |
| DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, but live cursor execution still reaches retained Win32/macOS platform bridges from `App::show_cursor` and `App::hide_cursor` | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls | | DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, but live cursor execution still reaches retained Win32/macOS platform bridges from `App::show_cursor` and `App::hide_cursor` | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls |
| DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, but live clipboard execution still reaches retained Win32/Apple/Android platform bridges from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls | | DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, but live clipboard execution still reaches retained Win32/Apple/Android platform bridges from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by `pp_platform_*` services and live app code depends on an injected platform interface instead of direct singleton/platform calls |
| DEBT-0017 | Open | Modernization | `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, and `App::hideKeyboard` now call the SDK-free `pp::platform::PlatformServices` interface, but the live implementation is still a legacy adapter in `app_events.cpp` that forwards to retained Win32/Apple/Android bridge functions | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace the `app_events.cpp` legacy adapter with injected `pp_platform_*` service implementations owned by each platform shell |
## Closed Debt ## Closed Debt

View File

@@ -1,7 +1,7 @@
# PanoPainter Modernization Roadmap # PanoPainter Modernization Roadmap
Status: live Status: live
Last updated: 2026-06-02 Last updated: 2026-06-03
This is the living roadmap for modernizing PanoPainter into independently This is the living roadmap for modernizing PanoPainter into independently
testable C++23 components while retaining all existing functionality. Keep this testable C++23 components while retaining all existing functionality. Keep this
@@ -87,6 +87,8 @@ Intended responsibilities:
- `pp_ui_core`: `Node`, layout, generic controls, text/image primitives. - `pp_ui_core`: `Node`, layout, generic controls, text/image primitives.
- `pp_panopainter_ui`: panels, dialogs, `NodeCanvas`, and app-specific - `pp_panopainter_ui`: panels, dialogs, `NodeCanvas`, and app-specific
workflows. workflows.
- `pp_platform_api`: SDK-free service interfaces for clipboard, cursor,
virtual keyboard, file pickers, sharing, and future platform automation.
- `pp_platform_*`: Windows, macOS/iOS, Android, Linux, and WebGL shells. - `pp_platform_*`: Windows, macOS/iOS, Android, Linux, and WebGL shells.
- `panopainter_app`: composition root only. - `panopainter_app`: composition root only.
@@ -466,6 +468,11 @@ cursor bridges continue.
`pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write` expose the `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write` expose the
app-core clipboard text decisions used by live clipboard get/set requests app-core clipboard text decisions used by live clipboard get/set requests
before retained platform clipboard bridges continue. before retained platform clipboard bridges continue.
`pp_platform_api` now owns a headless `PlatformServices` interface for
clipboard text, cursor visibility, and virtual-keyboard visibility. Live app
clipboard/cursor/keyboard execution routes through a debt-tracked legacy
adapter in `app_events.cpp`, so behavior is preserved while later platform
shell implementations can replace direct bridge calls.
`pano_cli plan-cloud-upload` exposes the app-core cloud upload decision used by `pano_cli plan-cloud-upload` exposes the app-core cloud upload decision used by
the live cloud upload command for missing-canvas, new-document warning, publish the live cloud upload command for missing-canvas, new-document warning, publish
prompt, and dirty-document save-before-upload states before legacy UI, canvas, prompt, and dirty-document save-before-upload states before legacy UI, canvas,
@@ -494,8 +501,9 @@ Implementation tasks:
7. `pp_paint_renderer` 7. `pp_paint_renderer`
8. `pp_ui_core` 8. `pp_ui_core`
9. `pp_panopainter_ui` 9. `pp_panopainter_ui`
10. `pp_platform_*` 10. `pp_platform_api`
11. `panopainter_app` 11. `pp_platform_*`
12. `panopainter_app`
- Remove renderer/platform dependencies from pure headers first, especially: - Remove renderer/platform dependencies from pure headers first, especially:
- `Brush` - `Brush`
- document/layer model - document/layer model
@@ -975,6 +983,11 @@ Results:
`pano_cli_plan_clipboard_write_smoke`, and `pano_cli_plan_clipboard_write_smoke`, and
`pano_cli_plan_clipboard_write_empty_smoke` passed and expose app-core `pano_cli_plan_clipboard_write_empty_smoke` passed and expose app-core
clipboard decisions as JSON, including empty write text. clipboard decisions as JSON, including empty write text.
- `pp_platform_api_tests` passed, covering the SDK-free `PlatformServices`
interface for clipboard read/write, empty clipboard writes, cursor
visibility dispatch, and virtual-keyboard visibility dispatch. The live app
now consumes this interface through the legacy platform adapter for
clipboard/cursor/keyboard execution.
- `panopainter_validate_shaders` passed, validating 25 shader programs and 7 - `panopainter_validate_shaders` passed, validating 25 shader programs and 7
shader includes for stage markers and include graph integrity. shader includes for stage markers and include graph integrity.
- `pp_renderer_gl_capabilities_tests` passed on default MSVC, vcpkg-headless, - `pp_renderer_gl_capabilities_tests` passed on default MSVC, vcpkg-headless,

View File

@@ -2,6 +2,7 @@
#include "app.h" #include "app.h"
#include "app_core/document_platform_io.h" #include "app_core/document_platform_io.h"
#include "app_core/document_sharing.h" #include "app_core/document_sharing.h"
#include "platform_api/platform_services.h"
#include "renderer_gl/opengl_capabilities.h" #include "renderer_gl/opengl_capabilities.h"
namespace { namespace {
@@ -60,21 +61,84 @@ void webgl_pick_file_save(const std::string& path,
void webgl_sync(); void webgl_sync();
#endif #endif
namespace {
class LegacyPlatformServices final : public pp::platform::PlatformServices {
public:
[[nodiscard]] std::string clipboard_text() override
{
#if _WIN32
return win32_clipboard_get_text();
#elif __IOS__
return [App::I->ios_view clipboard_get_string];
#elif __OSX__
return [App::I->osx_view clipboard_get_string];
#elif __ANDROID__
return android_get_clipboard();
#else
return {};
#endif
}
[[nodiscard]] bool set_clipboard_text(std::string_view text) override
{
const std::string value(text);
#if _WIN32
return win32_clipboard_set_text(value);
#elif __IOS__
return [App::I->ios_view clipboard_set_string:value];
#elif __OSX__
return [App::I->osx_view clipboard_set_string:value];
#elif __ANDROID__
return android_set_clipboard(value);
#else
return false;
#endif
}
void set_cursor_visible(bool visible) override
{
#ifdef _WIN32
win32_show_cursor(visible);
#elif __OSX__
[App::I->osx_view show_cursor:visible];
#else
(void)visible;
#endif
}
void set_virtual_keyboard_visible(bool visible) override
{
#ifdef __IOS__
dispatch_async(dispatch_get_main_queue(), ^{
if (visible)
[App::I->ios_view show_keyboard];
else
[App::I->ios_view hide_keyboard];
});
#elif __ANDROID__
displayKeyboard(visible);
#else
(void)visible;
#endif
}
};
[[nodiscard]] pp::platform::PlatformServices& legacy_platform_services()
{
static LegacyPlatformServices services;
return services;
}
}
std::string App::clipboard_get_text() std::string App::clipboard_get_text()
{ {
if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text) if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text)
return {}; return {};
#if _WIN32 return legacy_platform_services().clipboard_text();
return win32_clipboard_get_text();
#elif __IOS__
return [ios_view clipboard_get_string];
#elif __OSX__
return [osx_view clipboard_get_string];
#elif __ANDROID__
return android_get_clipboard();
#endif
} }
bool App::clipboard_set_text(const std::string& s) bool App::clipboard_set_text(const std::string& s)
@@ -82,15 +146,7 @@ bool App::clipboard_set_text(const std::string& s)
if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text) if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text)
return false; return false;
#if _WIN32 return legacy_platform_services().set_clipboard_text(s);
return win32_clipboard_set_text(s);
#elif __IOS__
return [ios_view clipboard_set_string:s];
#elif __OSX__
return [osx_view clipboard_set_string:s];
#elif __ANDROID__
return android_set_clipboard(s);
#endif
} }
void App::stacktrace() void App::stacktrace()
@@ -138,9 +194,9 @@ void App::show_cursor()
return; return;
#ifdef _WIN32 #ifdef _WIN32
win32_show_cursor(true); legacy_platform_services().set_cursor_visible(true);
#elif __OSX__ #elif __OSX__
[osx_view show_cursor:true]; legacy_platform_services().set_cursor_visible(true);
#endif #endif
} }
@@ -150,9 +206,9 @@ void App::hide_cursor()
return; return;
#ifdef _WIN32 #ifdef _WIN32
win32_show_cursor(false); legacy_platform_services().set_cursor_visible(false);
#elif __OSX__ #elif __OSX__
[osx_view show_cursor:false]; legacy_platform_services().set_cursor_visible(false);
#endif #endif
} }
@@ -163,11 +219,9 @@ void App::showKeyboard()
if (!should_dispatch_keyboard_visibility(true)) if (!should_dispatch_keyboard_visibility(true))
return; return;
#ifdef __IOS__ #ifdef __IOS__
dispatch_async(dispatch_get_main_queue(), ^{ legacy_platform_services().set_virtual_keyboard_visible(true);
[ios_view show_keyboard];
});
#elif __ANDROID__ #elif __ANDROID__
displayKeyboard(true); legacy_platform_services().set_virtual_keyboard_visible(true);
#endif #endif
} }
@@ -178,11 +232,9 @@ void App::hideKeyboard()
if (!should_dispatch_keyboard_visibility(false)) if (!should_dispatch_keyboard_visibility(false))
return; return;
#ifdef __IOS__ #ifdef __IOS__
dispatch_async(dispatch_get_main_queue(), ^{ legacy_platform_services().set_virtual_keyboard_visible(false);
[ios_view hide_keyboard];
});
#elif __ANDROID__ #elif __ANDROID__
displayKeyboard(false); legacy_platform_services().set_virtual_keyboard_visible(false);
#endif #endif
} }

View File

@@ -0,0 +1,7 @@
#include "platform_api/platform_services.h"
namespace pp::platform {
namespace {
static_assert(sizeof(PlatformServices*) == sizeof(void*));
}
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include <string>
#include <string_view>
namespace pp::platform {
class PlatformServices {
public:
virtual ~PlatformServices() = default;
[[nodiscard]] virtual std::string clipboard_text() = 0;
[[nodiscard]] virtual bool set_clipboard_text(std::string_view text) = 0;
virtual void set_cursor_visible(bool visible) = 0;
virtual void set_virtual_keyboard_visible(bool visible) = 0;
};
}

View File

@@ -228,6 +228,16 @@ add_test(NAME pp_paint_renderer_compositor_tests COMMAND pp_paint_renderer_compo
set_tests_properties(pp_paint_renderer_compositor_tests PROPERTIES set_tests_properties(pp_paint_renderer_compositor_tests PROPERTIES
LABELS "renderer;paint;desktop-fast") LABELS "renderer;paint;desktop-fast")
add_executable(pp_platform_api_tests
platform_api/platform_services_tests.cpp)
target_link_libraries(pp_platform_api_tests PRIVATE
pp_platform_api
pp_test_harness)
add_test(NAME pp_platform_api_tests COMMAND pp_platform_api_tests)
set_tests_properties(pp_platform_api_tests PROPERTIES
LABELS "os-api;desktop-fast")
add_executable(pp_ui_core_color_tests add_executable(pp_ui_core_color_tests
ui_core/color_tests.cpp) ui_core/color_tests.cpp)
target_link_libraries(pp_ui_core_color_tests PRIVATE target_link_libraries(pp_ui_core_color_tests PRIVATE

View File

@@ -0,0 +1,100 @@
#include "platform_api/platform_services.h"
#include "test_harness.h"
#include <string>
#include <string_view>
#include <utility>
namespace {
class FakePlatformServices final : public pp::platform::PlatformServices {
public:
explicit FakePlatformServices(std::string clipboard_value)
: clipboard_value_(std::move(clipboard_value))
{
}
[[nodiscard]] std::string clipboard_text() override
{
++clipboard_reads;
return clipboard_value_;
}
[[nodiscard]] bool set_clipboard_text(std::string_view text) override
{
++clipboard_writes;
clipboard_value_.assign(text);
return true;
}
void set_cursor_visible(bool visible) override
{
++cursor_updates;
cursor_visible = visible;
}
void set_virtual_keyboard_visible(bool visible) override
{
++keyboard_updates;
keyboard_visible = visible;
}
int clipboard_reads = 0;
int clipboard_writes = 0;
int cursor_updates = 0;
int keyboard_updates = 0;
bool cursor_visible = false;
bool keyboard_visible = false;
private:
std::string clipboard_value_;
};
void platform_services_dispatch_clipboard_reads_and_writes(pp::tests::Harness& harness)
{
FakePlatformServices fake("#112233");
pp::platform::PlatformServices& services = fake;
PP_EXPECT(harness, services.clipboard_text() == "#112233");
PP_EXPECT(harness, services.set_clipboard_text("#ff00aa"));
PP_EXPECT(harness, services.clipboard_text() == "#ff00aa");
PP_EXPECT(harness, fake.clipboard_reads == 2);
PP_EXPECT(harness, fake.clipboard_writes == 1);
}
void platform_services_preserve_empty_clipboard_writes(pp::tests::Harness& harness)
{
FakePlatformServices fake("initial");
pp::platform::PlatformServices& services = fake;
PP_EXPECT(harness, services.set_clipboard_text(""));
PP_EXPECT(harness, services.clipboard_text().empty());
PP_EXPECT(harness, fake.clipboard_writes == 1);
}
void platform_services_dispatch_visibility_updates(pp::tests::Harness& harness)
{
FakePlatformServices fake("unused");
pp::platform::PlatformServices& services = fake;
services.set_cursor_visible(true);
services.set_virtual_keyboard_visible(true);
services.set_cursor_visible(false);
services.set_virtual_keyboard_visible(false);
PP_EXPECT(harness, fake.cursor_updates == 2);
PP_EXPECT(harness, fake.keyboard_updates == 2);
PP_EXPECT(harness, !fake.cursor_visible);
PP_EXPECT(harness, !fake.keyboard_visible);
}
}
int main()
{
pp::tests::Harness harness;
harness.run("platform services dispatch clipboard reads and writes", platform_services_dispatch_clipboard_reads_and_writes);
harness.run("platform services preserve empty clipboard writes", platform_services_preserve_empty_clipboard_writes);
harness.run("platform services dispatch visibility updates", platform_services_dispatch_visibility_updates);
return harness.finish();
}