diff --git a/api/sixtyfps-cpp/include/sixtyfps_image.h b/api/sixtyfps-cpp/include/sixtyfps_image.h index d82bda13a..3ff253217 100644 --- a/api/sixtyfps-cpp/include/sixtyfps_image.h +++ b/api/sixtyfps-cpp/include/sixtyfps_image.h @@ -15,6 +15,20 @@ LICENSE END */ namespace sixtyfps { +#if !defined(DOXYGEN) +using cbindgen_private::types::Size; +#else +/// The Size structure is used to represent a two-dimensional size +/// with width and height. +struct Size +{ + /// The width of the size + float width; + /// The height of the size + float height; +}; +#endif + /// An image type that can be displayed by the Image element struct Image { @@ -22,7 +36,8 @@ public: Image() : data(Data::None()) { } /// Load an image from an image file - static Image load_from_path(const SharedString &file_path) { + static Image load_from_path(const SharedString &file_path) + { Image img; img.data = Data::AbsoluteFilePath(file_path); return img; @@ -35,12 +50,12 @@ public: return img; } */ - friend bool operator==(const Image &a, const Image &b) { - return a.data == b.data; - } - friend bool operator!=(const Image &a, const Image &b) { - return a.data != b.data; - } + + /// Returns the size of the Image in pixels. + Size size() const { return cbindgen_private::types::sixtyfps_image_size(&data); } + + friend bool operator==(const Image &a, const Image &b) { return a.data == b.data; } + friend bool operator!=(const Image &a, const Image &b) { return a.data != b.data; } private: using Tag = cbindgen_private::types::ImageInner::Tag; diff --git a/api/sixtyfps-cpp/tests/datastructures.cpp b/api/sixtyfps-cpp/tests/datastructures.cpp index ffffe51e2..eeac62631 100644 --- a/api/sixtyfps-cpp/tests/datastructures.cpp +++ b/api/sixtyfps-cpp/tests/datastructures.cpp @@ -13,6 +13,7 @@ LICENSE END */ #include "catch2/catch.hpp" #include +#include SCENARIO("SharedString API") { @@ -72,3 +73,24 @@ TEST_CASE("Property Tracker") REQUIRE(!tracker1.is_dirty()); } +TEST_CASE("Image") +{ + using namespace sixtyfps; + + // ensure a backend exists, using private api + private_api::ComponentWindow wnd; + + Image img; + { + auto size = img.size(); + REQUIRE(size.width == 0.); + REQUIRE(size.height == 0.); + } + + img = Image::load_from_path(SOURCE_DIR "/../../vscode_extension/extension-logo.png"); + { + auto size = img.size(); + REQUIRE(size.width == 128.); + REQUIRE(size.height == 128.); + } +} diff --git a/sixtyfps_runtime/corelib/graphics.rs b/sixtyfps_runtime/corelib/graphics.rs index f06d184eb..9dd4fb616 100644 --- a/sixtyfps_runtime/corelib/graphics.rs +++ b/sixtyfps_runtime/corelib/graphics.rs @@ -42,7 +42,7 @@ pub use path::*; mod brush; pub use brush::*; -mod image; +pub(crate) mod image; pub use self::image::*; /// CachedGraphicsData allows the graphics backend to store an arbitrary piece of data associated with diff --git a/sixtyfps_runtime/corelib/graphics/image.rs b/sixtyfps_runtime/corelib/graphics/image.rs index 10c545c01..e4d031921 100644 --- a/sixtyfps_runtime/corelib/graphics/image.rs +++ b/sixtyfps_runtime/corelib/graphics/image.rs @@ -80,3 +80,16 @@ impl Image { } } } + +#[cfg(feature = "ffi")] +pub(crate) mod ffi { + #![allow(unsafe_code)] + + use super::super::Size; + use super::*; + + #[no_mangle] + pub unsafe extern "C" fn sixtyfps_image_size(image: &Image) -> Size { + image.size() + } +} diff --git a/sixtyfps_runtime/corelib/lib.rs b/sixtyfps_runtime/corelib/lib.rs index b20d28824..07c503bec 100644 --- a/sixtyfps_runtime/corelib/lib.rs +++ b/sixtyfps_runtime/corelib/lib.rs @@ -90,6 +90,7 @@ pub fn use_modules() -> usize { + component::ffi::sixtyfps_component_init_items as usize + timers::ffi::sixtyfps_timer_start as usize + graphics::color::ffi::sixtyfps_color_brighter as usize + + graphics::image::ffi::sixtyfps_image_size as usize } #[cfg(not(feature = "ffi"))] { diff --git a/xtask/src/cbindgen.rs b/xtask/src/cbindgen.rs index d43bcacc0..b20ac6a29 100644 --- a/xtask/src/cbindgen.rs +++ b/xtask/src/cbindgen.rs @@ -130,6 +130,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { "KeyEventArg", "sixtyfps_color_brighter", "sixtyfps_color_darker", + "sixtyfps_image_size", ] .iter() .map(|x| x.to_string()) @@ -180,7 +181,11 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { .write_to_file(include_dir.join("sixtyfps_properties_internal.h")); for (rust_types, extra_excluded_types, internal_header) in [ - (vec!["ImageInner", "Image"], vec![], "sixtyfps_image_internal.h"), + ( + vec!["ImageInner", "Image", "Size", "sixtyfps_image_size"], + vec![], + "sixtyfps_image_internal.h", + ), ( vec!["Color", "sixtyfps_color_brighter", "sixtyfps_color_darker"], vec![], @@ -222,6 +227,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { "sixtyfps_new_path_events", "sixtyfps_color_brighter", "sixtyfps_color_darker", + "sixtyfps_image_size", ] .iter() .filter(|exclusion| rust_types.iter().find(|inclusion| inclusion == exclusion).is_none())