diff --git a/README.md b/README.md index 9f837cb59..bc2c925f0 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ [![crates.io](https://img.shields.io/crates/v/skia-safe)](https://crates.io/crates/skia-safe) [![license](https://img.shields.io/crates/l/skia-safe)](LICENSE) [![Build Status](https://dev.azure.com/pragmatrix-github/rust-skia/_apis/build/status/rust-skia.rust-skia?branchName=master)](https://dev.azure.com/pragmatrix-github/rust-skia/_build/latest?definitionId=2&branchName=master) -Skia Submodule Status: chrome/m91 ([upstream changes][skia-upstream], [our changes][skia-ours]). +Skia Submodule Status: chrome/m92 ([upstream changes][skia-upstream], [our changes][skia-ours]). -[skia-upstream]: https://github.com/rust-skia/skia/compare/m91-0.39.3...google:chrome/m91 -[skia-ours]: https://github.com/google/skia/compare/chrome/m91...rust-skia:m91-0.39.3 +[skia-upstream]: https://github.com/rust-skia/skia/compare/m92-0.40.0...google:chrome/m92 +[skia-ours]: https://github.com/google/skia/compare/chrome/m92...rust-skia:m92-0.40.0 ## Goals diff --git a/skia-bindings/Cargo.toml b/skia-bindings/Cargo.toml index 90d110851..18636ff24 100644 --- a/skia-bindings/Cargo.toml +++ b/skia-bindings/Cargo.toml @@ -32,7 +32,7 @@ doctest = false # Metadata used from inside the packaged crate that defines where to download skia and depot_tools archives from. # Note: use short hashes here because of filesystem path size restrictions. [package.metadata] -skia = "m91-0.39.3" +skia = "m92-0.40.0" depot_tools = "a110bf6" [features] diff --git a/skia-bindings/build_support/skia.rs b/skia-bindings/build_support/skia.rs index a99b3a5a7..34c306348 100644 --- a/skia-bindings/build_support/skia.rs +++ b/skia-bindings/build_support/skia.rs @@ -189,6 +189,9 @@ pub struct FinalBuildConfiguration { /// the BuildConfiguration). pub definitions: Definitions, + /// The binding headers that are used. + pub binding_headers: Vec, + /// The binding source files to compile. pub binding_sources: Vec, @@ -421,6 +424,8 @@ impl FinalBuildConfiguration { files }; + let binding_headers = vec!["src/bindings.h".into()]; + let binding_sources = { let mut sources: Vec = vec!["src/bindings.cpp".into()]; if features.gl { @@ -450,6 +455,7 @@ impl FinalBuildConfiguration { gn_args, ninja_files, definitions: build.definitions.clone(), + binding_headers, binding_sources, use_system_libraries, } @@ -738,6 +744,7 @@ fn generate_bindings(build: &FinalBuildConfiguration, output_directory: &Path) { .raw_line("#![allow(clippy::all)]") // GrVkBackendContext contains u128 fields on macOS .raw_line("#![allow(improper_ctypes)]") + .allowlist_recursively(false) .allowlist_function("C_.*") .constified_enum(".*Mask") .constified_enum(".*Flags") @@ -746,39 +753,39 @@ fn generate_bindings(build: &FinalBuildConfiguration, output_directory: &Path) { .constified_enum("GrVkAlloc_Flag") .constified_enum("GrGLBackendState") // not used: - .blocklist_type("SkPathRef_Editor") - .blocklist_function("SkPathRef_Editor_Editor") + // .blocklist_type("SkPathRef_Editor") + // .blocklist_function("SkPathRef_Editor_Editor") // private types that pull in inline functions that cannot be linked: // https://github.com/rust-skia/rust-skia/issues/318 - .raw_line("pub enum GrContext_Base {}") - .blocklist_type("GrContext_Base") - .blocklist_function("GrContext_Base_.*") - .raw_line("pub enum GrImageContext {}") - .blocklist_type("GrImageContext") - .raw_line("pub enum GrImageContextPriv {}") - .blocklist_type("GrImageContextPriv") - .raw_line("pub enum GrContextThreadSafeProxy {}") - .blocklist_type("GrContextThreadSafeProxy") - .blocklist_type("GrContextThreadSafeProxyPriv") - .raw_line("pub enum GrContextThreadSafeProxyPriv {}") - .blocklist_type("GrRecordingContextPriv") - .raw_line("pub enum GrRecordingContextPriv {}") - .blocklist_function("GrRecordingContext_priv.*") - .blocklist_function("GrDirectContext_priv.*") - .blocklist_type("GrContextPriv") - .raw_line("pub enum GrContextPriv {}") - .blocklist_function("GrContext_priv.*") - .blocklist_function("SkDeferredDisplayList_priv.*") - .raw_line("pub enum SkVerticesPriv {}") - .blocklist_type("SkVerticesPriv") - .blocklist_function("SkVertices_priv.*") - .blocklist_function("std::bitset_flip.*") + // .raw_line("pub enum GrContext_Base {}") + // .blocklist_type("GrContext_Base") + // .blocklist_function("GrContext_Base_.*") + // .raw_line("pub enum GrImageContext {}") + // .blocklist_type("GrImageContext") + // .raw_line("pub enum GrImageContextPriv {}") + // .blocklist_type("GrImageContextPriv") + // .raw_line("pub enum GrContextThreadSafeProxy {}") + // .blocklist_type("GrContextThreadSafeProxy") + // .blocklist_type("GrContextThreadSafeProxyPriv") + // .raw_line("pub enum GrContextThreadSafeProxyPriv {}") + // .blocklist_type("GrRecordingContextPriv") + // .raw_line("pub enum GrRecordingContextPriv {}") + // .blocklist_function("GrRecordingContext_priv.*") + // .blocklist_function("GrDirectContext_priv.*") + // .blocklist_type("GrContextPriv") + // .raw_line("pub enum GrContextPriv {}") + // .blocklist_function("GrContext_priv.*") + // .blocklist_function("SkDeferredDisplayList_priv.*") + // .raw_line("pub enum SkVerticesPriv {}") + // .blocklist_type("SkVerticesPriv") + // .blocklist_function("SkVertices_priv.*") + // .blocklist_function("std::bitset_flip.*") // Vulkan reexports that got swallowed by making them opaque. // (these can not be allowlisted by a extern "C" function) - .allowlist_type("VkPhysicalDeviceFeatures") - .allowlist_type("VkPhysicalDeviceFeatures2"). + // .allowlist_type("VkPhysicalDeviceFeatures") + // .allowlist_type("VkPhysicalDeviceFeatures2"). // m91: These functions are not actually implemented. - blocklist_function("SkCustomTypefaceBuilder_setGlyph[123].*") + .blocklist_function("SkCustomTypefaceBuilder_setGlyph[123].*") // misc .allowlist_var("SK_Color.*") .allowlist_var("kAll_GrBackendState") @@ -798,13 +805,27 @@ fn generate_bindings(build: &FinalBuildConfiguration, output_directory: &Path) { builder }; + for ty in ALLOWLISTED_TYPES { + builder = builder.allowlist_type(ty) + } + + for ty in ALLOWED_OPAQUE_TYPES { + builder = builder.allowlist_type(ty).opaque_type(ty) + } + + for ty in PRIVATE_TYPES { + builder = builder.raw_line(format!("pub enum {} {{}}", ty)); + } + for function in ALLOWLISTED_FUNCTIONS { builder = builder.allowlist_function(function) } - for opaque_type in OPAQUE_TYPES { - builder = builder.opaque_type(opaque_type) - } + /* + for opaque_type in OPAQUE_TYPES { + builder = builder.opaque_type(opaque_type) + } + */ for t in BLOCKLISTED_TYPES { builder = builder.blocklist_type(t); @@ -812,6 +833,10 @@ fn generate_bindings(build: &FinalBuildConfiguration, output_directory: &Path) { let mut cc_build = Build::new(); + for header in &build.binding_headers { + cargo::rerun_if_changed(header.to_str().unwrap()); + } + for source in &build.binding_sources { cc_build.file(source); let source = source.to_str().unwrap(); @@ -928,6 +953,193 @@ fn generate_bindings(build: &FinalBuildConfiguration, output_directory: &Path) { .expect("Couldn't write bindings!"); } +const ALLOWLISTED_TYPES: &[&str] = &[]; + +const ALLOWED_OPAQUE_TYPES: &[&str] = &[ + "DXGI_FORMAT", + "FILE", + "GrBackendFormat", + "GrBackendSurfaceMutableState", + "GrBackendTexture", + "GrColorFormatDesc", + "GrColorType", + "GrContextOptions", + "GrD3DBackendSurfaceInfo", + "GrD3DResourceStateEnum", + "GrDirectContext", + "GrFlushInfo", + "GrGLBackendTextureInfo", + "GrGLEnum", + "GrGLExtensions", + "GrGLFormat", + "GrGLFrameBufferInfo", + "GrGLInterface", + "GrGLTextureInfo", + "GrMipmapped", + "GrMockTextureInfo", + "GrProtected", + "GrRecordingContext", + "GrSemaphoresSubmitted", + "GrSurfaceOrigin", + "GrVkImageInfo", + "GrVkYcbcrConversionInfo", + "sk_sp", + "Sk3DView", + "SkAlphaType", + "SkApplyPerspectiveClip", + "SkBitmap", + "SkBlendMode", + "SkBlendModeCoeff", + "SkBlurStyle", + "SkBudgeted", + "SkCanvas", + "SkClipOp", + "skcms_.*", + "SkCodec_Options", + "SkCodec_Result", + "SkCodec_SkScanlineOrder", + "SkCodec", + "SkCodecAnimation_.*", + "SkCodecAnimation_Blend", + "SkCodecAnimation_DisposalMethod", + "SkColor", + "SkColor4f", + "SkColorChannelFlag", + "SkColorFilter", + "SkColorInfo", + "SkColorMatrix", + "SkColorSpace", + "SkColorType", + "SkCoverageMode", + "SkCubicMap", + "SkCubicResampler", + "SkCustomTypefaceBuilder", + "SkData", + "SkDataTable", + "SkDeferredDisplayList", + "SkDeferredDisplayListRecorder", + "SkDrawable", + "SkDrawShadowRec", + "SkDynamicMemoryWStream", + "SkEncodedImageFormat", + "SkEncodedInfo", + "SkEncodedOrigin", + "SkFilterMode", + "SkFilterQuality", + "SkFlattenable", + "SkFont", + "SkGlyphID", + "SkGradientShader", + "SkGraphics", + "SkHighContrastConfig", + "SkImage", + "SkImageFilter", + "SkImageFilters_CropRect", + "SkImageGenerator", + "SkImageInfo", + "SkIPoint", + "SkIRect", + "SkISize", + "SkM44", + "SkMask", + "SkMaskFilter", + "SkMatrix", + "SkMemoryStream", + "SkOnce", + "SkOpBuilder", + "SkOrderedFontMgr", + "SkPaint", + "SkParsePath", + "SkPath", + "SkPath1DPathEffect_Style", + "SkPathDirection", + "SkPathEffect", + "SkPathFillType", + "SkPathOp", + "SkPDF_Metadata", + "SkPDF_StructureElementNode", + "SkPicture", + "SkPixelGeometry", + "SkPixmap", + "SkPMColor", + "SkPngChunkReader", + "SkPoint", + "SkPoint3", + "SkRasterHandleAllocator_Handle", + "SkRect", + "SkRefCnt", + "SkRegion", + "SkRRect", + "SkRSXform", + "SkRuntimeEffect", + "SkSamplingOptions", + "SkScalar", + "SkShader_GradientInfo", + "SkShader_GradientType", + "SkShader", + "SkShadowFlags", + "SkSize", + "SkStream", + "SkStreamMemory", + "SkString", + "SkStrings", + "SkStrokeRec", + "SkSurface", + "SkSurfaceCharacterization", + "SkSurfaceProps", + "SkTableMaskFilter", + "SkTextBlob", + "SkTextEncoding", + "SkTextUtils", + "SkTileMode", + "SkUnichar", + "SkV3", + "SkV4", + "SkVector", + "SkVertices", + "SkWStream", + "SkYUVAInfo_PlaneConfig", + "SkYUVAInfo_Subsampling", + "SkYUVAInfo", + "SkYUVAPixmapInfo_SupportedDataTypes", + "SkYUVAPixmapInfo", + "SkYUVAPixmaps", + "SkYUVColorSpace", + "std::atomic", + "std::function", + "std::string", + "std::unique_ptr", + "std::vector", + "U8CPU", + "va_list", + "VkBool32", + "VkFormat", + "VkStructureType", + "SkCodecAnimation::DisposalMethod", + "SkCodecAnimation::Blend", + "GrBackendSurfaceMutableState_.*", + "GrYUVABackendTextures", + "GrMipMapped", + "GrYUVABackendTextureInfo", +]; + +const PRIVATE_TYPES: &[&str] = &[ + "GrVkBackendSurfaceInfo", + "SkReadBuffer", + "SkSerialProcs", + "SkDeserialProcs", + "GrImageContext", +]; + +const BLOCKLISTED_TYPES: &[&str] = &[ + "sk_sp_.*", + "std::atomic_.*", + "std::vector_.*", + "std::unique_ptr_.*", + "std::string_.*", + "std::function_.*", +]; + const ALLOWLISTED_FUNCTIONS: &[&str] = &[ "SkAnnotateRectWithURL", "SkAnnotateNamedDestination", @@ -951,11 +1163,6 @@ const ALLOWLISTED_FUNCTIONS: &[&str] = &[ "Simplify", "TightBounds", "AsWinding", - // utils/ - "Sk3LookAt", - "Sk3Perspective", - "Sk3MapPts", - "SkUnitCubicInterp", ]; const OPAQUE_TYPES: &[&str] = &[ @@ -1071,8 +1278,11 @@ const OPAQUE_TYPES: &[&str] = &[ "GrD3DMemoryAllocator", // m87, yuva_pixmaps "std::tuple", + // m92: referred, but yet unused + "SkFontDescriptor", ]; +/* const BLOCKLISTED_TYPES: &[&str] = &[ // modules/skparagraph // pulls in a std::map<>, which we treat as opaque, but bindgen creates wrong bindings for @@ -1092,6 +1302,7 @@ const BLOCKLISTED_TYPES: &[&str] = &[ "std::__cxx.*", "std::array.*", ]; +*/ #[derive(Debug)] struct ParseCallbacks; diff --git a/skia-bindings/skia b/skia-bindings/skia index 74276ea93..e59695d76 160000 --- a/skia-bindings/skia +++ b/skia-bindings/skia @@ -1 +1 @@ -Subproject commit 74276ea938c607ceeebad2812d20189f0eb48adb +Subproject commit e59695d762b97d12ec9b041ac6a6743f30a36e86 diff --git a/skia-bindings/src/bindings.cpp b/skia-bindings/src/bindings.cpp index 60a43f043..3b3d19243 100644 --- a/skia-bindings/src/bindings.cpp +++ b/skia-bindings/src/bindings.cpp @@ -88,8 +88,8 @@ // utils/ #include "include/utils/SkCamera.h" #include "include/utils/SkCustomTypeface.h" -#include "include/utils/SkInterpolator.h" #include "include/utils/SkNullCanvas.h" +#include "include/utils/SkOrderedFontMgr.h" #include "include/utils/SkParsePath.h" #include "include/utils/SkShadowUtils.h" #include "include/utils/SkTextUtils.h" @@ -831,6 +831,10 @@ extern "C" bool C_SkM44_equals(const SkM44 *self, const SkM44 *other) { return *self == *other; } +extern "C" void C_SkM44_RectToRect(const SkRect* src, const SkRect* dst, SkM44* uninitialized) { + new(uninitialized) SkM44(SkM44::RectToRect(*src, *dst)); +} + extern "C" void C_SkM44_LookAt(const SkV3* eye, const SkV3* center, const SkV3* up, SkM44* uninitialized) { new(uninitialized) SkM44(SkM44::LookAt(*eye, *center, *up)); } @@ -1283,6 +1287,10 @@ extern "C" void C_SkFont_ConstructFromTypefaceWithSizeScaleAndSkew(SkFont* unini new(uninitialized) SkFont(sp(typeface), size, scaleX, skewX); } +extern "C" void C_SkFont_destruct(SkFont* self) { + self->~SkFont(); +} + extern "C" bool C_SkFont_Equals(const SkFont* self, const SkFont* other) { return *self == *other; } @@ -1307,8 +1315,16 @@ extern "C" void C_SkFont_setTypeface(SkFont* self, SkTypeface* tf) { self->setTypeface(sp(tf)); } -extern "C" void C_SkFont_destruct(SkFont* self) { - self->~SkFont(); +extern "C" void C_SkFont_getIntercepts( + const SkFont* self, + const SkGlyphID glyphs[], + int count, + const SkPoint pos[], + SkScalar top, SkScalar bottom, + const SkPaint* paint, + VecSink* vs) { + auto r = self->getIntercepts(glyphs, count, pos, top, bottom, paint); + vs->set(r); } // @@ -2280,12 +2296,22 @@ extern "C" SkColorFilter* C_SkOverdrawColorFilter_MakeWithSkColors(const SkColor extern "C" { -SkRuntimeEffect *C_SkRuntimeEffect_Make( +SkRuntimeEffect *C_SkRuntimeEffect_MakeForColorFilter( const SkString *sksl, const SkRuntimeEffect::Options *options, SkString *error) { - auto r = SkRuntimeEffect::Make(*sksl, *options); + auto r = SkRuntimeEffect::MakeForColorFilter(*sksl, *options); + *error = r.errorText; + return r.effect.release(); +} + +SkRuntimeEffect *C_SkRuntimeEffect_MakeForShader( + const SkString *sksl, + const SkRuntimeEffect::Options *options, + SkString *error) +{ + auto r = SkRuntimeEffect::MakeForShader(*sksl, *options); *error = r.errorText; return r.effect.release(); } @@ -2326,18 +2352,12 @@ const SkRuntimeEffect::Uniform* C_SkRuntimeEffect_uniforms(const SkRuntimeEffect return &*uniforms.begin(); } -const SkString* C_SkRuntimeEffect_children(const SkRuntimeEffect* self, size_t* count) { +const SkRuntimeEffect::Child* C_SkRuntimeEffect_children(const SkRuntimeEffect* self, size_t* count) { auto children = self->children(); *count = children.count(); return &*children.begin(); } -const SkRuntimeEffect::Varying* C_SkRuntimeEffect_varyings(const SkRuntimeEffect* self, size_t* count) { - auto varyings = self->varyings(); - *count = varyings.count(); - return &*varyings.begin(); -} - } // @@ -2699,23 +2719,15 @@ C_SkCustomTypefaceBuilder_setGlyph3(SkCustomTypefaceBuilder *self, SkGlyphID gly self->setGlyph(glyph, advance, sp(picture)); } */ - -extern "C" void C_SkInterpolator_destruct(SkInterpolator* self) { - self->~SkInterpolator(); -} -extern "C" void C_SkInterpolator_setRepeatCount(SkInterpolator* self, SkScalar repeatCount) { - self->setRepeatCount(repeatCount); -} - -extern "C" void C_SkInterpolator_setReset(SkInterpolator* self, bool reset) { - self->setReset(reset); +extern "C" SkCanvas* C_SkMakeNullCanvas() { + return SkMakeNullCanvas().release(); } -extern "C" void C_SkInterpolator_setMirror(SkInterpolator* self, bool mirror) { - self->setMirror(mirror); +extern "C" SkOrderedFontMgr* C_SkOrderedFontMgr_new() { + return new SkOrderedFontMgr(); } -extern "C" SkCanvas* C_SkMakeNullCanvas() { - return SkMakeNullCanvas().release(); +extern "C" void C_SkOrderedFontMgr_append(SkOrderedFontMgr* self, SkFontMgr* fontMgr) { + self->append(sp(fontMgr)); } diff --git a/skia-bindings/src/bindings.h b/skia-bindings/src/bindings.h index 0bb67c27b..4867066e6 100644 --- a/skia-bindings/src/bindings.h +++ b/skia-bindings/src/bindings.h @@ -15,7 +15,28 @@ inline sk_sp sp(T* pt) { return sk_sp(pt); } -// Used in textlayout::Paragraph::findTypefaces() +extern "C" struct TraitObject { + void* data; + void* vtable; +}; + +/// A VecSink is passed from Rust to C++ for receiving a slice of values. +template struct VecSink { + TraitObject fn_trait; + void (*set_fn)(T *, size_t, TraitObject); + + void set(T* ptr, size_t len) { + set_fn(ptr, len, fn_trait); + } + + void set(std::vector& v) { + if (v.empty()) { + set_fn(nullptr, 0, fn_trait); + } else { + set_fn(v.data(), v.size(), fn_trait); + } + } +}; struct SkStrings { std::vector strings; diff --git a/skia-bindings/src/defaults.rs b/skia-bindings/src/defaults.rs index c9f65e8d4..777e24669 100644 --- a/skia-bindings/src/defaults.rs +++ b/skia-bindings/src/defaults.rs @@ -3,7 +3,7 @@ use crate::{ SkBlendMode, SkBlurStyle, SkCanvas_Lattice_RectType, SkClipOp, SkPaint_Cap, SkPaint_Join, - SkPathDirection, SkTileMode, SkYUVColorSpace, + SkParsePath_PathEncoding, SkPathDirection, SkTileMode, SkYUVColorSpace, }; impl Default for SkBlendMode { @@ -61,6 +61,12 @@ impl Default for SkTileMode { } } +impl Default for SkParsePath_PathEncoding { + fn default() -> Self { + SkParsePath_PathEncoding::Absolute + } +} + #[cfg(feature = "textlayout")] pub mod textlayout { impl Default for crate::skia_textlayout_Affinity { diff --git a/skia-bindings/src/paragraph.cpp b/skia-bindings/src/paragraph.cpp index 0130434fb..ee10f5443 100644 --- a/skia-bindings/src/paragraph.cpp +++ b/skia-bindings/src/paragraph.cpp @@ -22,32 +22,6 @@ using namespace skia::textlayout; // FontCollection.h // -struct Typefaces { - std::vector> typefaces; -}; - -extern "C" { - void C_Typefaces_construct(Typefaces* uninitialized) { - new(uninitialized)Typefaces(); - } - - void C_Typefaces_destruct(Typefaces* self) { - self->~Typefaces(); - } - - size_t C_Typefaces_count(const Typefaces* faces) { - return faces->typefaces.size(); - } - - SkTypeface* C_Typefaces_get(const Typefaces* faces, size_t i) { - return faces->typefaces[i].get(); - } - - SkTypeface* C_Typefaces_release(Typefaces* faces, size_t i) { - return faces->typefaces[i].release(); - } -} - extern "C" { FontCollection* C_FontCollection_new() { return new FontCollection(); @@ -81,9 +55,9 @@ extern "C" { return self->getFallbackManager().release(); } - void C_FontCollection_findTypefaces(FontCollection* self, const SkStrings* familyNames, SkFontStyle fontStyle, Typefaces* typefaces) { + void C_FontCollection_findTypefaces(FontCollection* self, const SkStrings* familyNames, SkFontStyle fontStyle, VecSink>* typefaces) { auto tfs = self->findTypefaces(familyNames->strings, fontStyle); - typefaces->typefaces = std::move(tfs); + typefaces->set(tfs); } SkTypeface* C_FontCollection_defaultFallback(FontCollection* self, SkUnichar unicode, SkFontStyle fontStyle, const SkString* locale) { @@ -215,37 +189,6 @@ extern "C" { // Paragraph.h // -struct TextBoxes { - std::vector textBoxes; -}; - -extern "C" { - void C_TextBoxes_destruct(TextBoxes* self) { - self->~TextBoxes(); - } - - const TextBox* C_TextBoxes_ptr_count(const TextBoxes* boxes, size_t* count) { - *count = boxes->textBoxes.size(); - return &boxes->textBoxes.front(); - } -} - -struct LineMetricsVector { - std::vector lineMetrics; -}; - -extern "C" { - void C_LineMetricsVector_destruct(LineMetricsVector* self) { - self->~LineMetricsVector(); - } - - const LineMetrics* C_LineMetricsVector_ptr_count(const LineMetricsVector* metrics, size_t* count) { - *count = metrics->lineMetrics.size(); - return &metrics->lineMetrics.front(); - } -} - - extern "C" { void C_Paragraph_delete(Paragraph* self) { delete self; @@ -260,14 +203,14 @@ extern "C" { } void C_Paragraph_getRectsForRange(Paragraph *self, unsigned start, unsigned end, RectHeightStyle rectHeightStyle, - RectWidthStyle rectWidthStyle, TextBoxes* uninitialized) { + RectWidthStyle rectWidthStyle, VecSink* textBoxes) { auto v = self->getRectsForRange(start, end, rectHeightStyle, rectWidthStyle); - new(uninitialized) TextBoxes{std::move(v)}; + textBoxes->set(v); } - void C_Paragraph_getRectsForPlaceholders(Paragraph* self, TextBoxes* uninitialized) { + void C_Paragraph_getRectsForPlaceholders(Paragraph* self, VecSink* result) { auto v = self->getRectsForPlaceholders(); - new(uninitialized) TextBoxes{std::move(v)}; + result->set(v); } void C_Paragraph_getGlyphPositionAtCoordinate(Paragraph* self, SkScalar x, SkScalar y, PositionWithAffinity* position) { @@ -280,11 +223,12 @@ extern "C" { range[1] = sk_range.end; } - void C_Paragraph_getLineMetrics(Paragraph* self, LineMetricsVector* uninitialized) { - auto v = new(uninitialized) LineMetricsVector(); - self->getLineMetrics(v->lineMetrics); + void C_Paragraph_getLineMetrics(Paragraph* self, VecSink* result) { + std::vector vec; + self->getLineMetrics(vec); + result->set(vec); } - + size_t C_Paragraph_lineNumber(Paragraph* self) { return self->lineNumber(); } @@ -292,6 +236,10 @@ extern "C" { void C_Paragraph_markDirty(Paragraph* self) { self->markDirty(); } + + int32_t C_Paragraph_unresolvedGlyphs(Paragraph* self) { + return self->unresolvedGlyphs(); + } } // @@ -363,6 +311,12 @@ extern "C" { self->~TextStyle(); } + const TextShadow* C_TextStyle_getShadows(const std::vector* self, size_t* len_ref) { + auto len = self->size(); + *len_ref = len; + return len ? self->data() : nullptr; + } + void C_TextStyle_addShadow(TextStyle* self, const TextShadow* shadow) { self->addShadow(*shadow); } @@ -371,6 +325,12 @@ extern "C" { self->resetShadows(); } + const FontFeature* C_TextStyle_getFontFeatures(const std::vector* self, size_t* len_ref) { + auto size = self->size(); + *len_ref = size; + return size ? self->data() : nullptr; + } + void C_TextStyle_addFontFeature(TextStyle* self, const SkString* fontFeature, int value) { self->addFontFeature(*fontFeature, value); } @@ -394,24 +354,6 @@ extern "C" { } } -struct FontFeatures { - std::vector fontFeatures; -}; - -extern "C" const FontFeature *C_FontFeatures_ptr_count(const FontFeatures *features, size_t *count) { - *count = features->fontFeatures.size(); - return &features->fontFeatures.front(); -} - -struct TextShadows { - std::vector textShadows; -}; - -extern "C" const TextShadow *C_TextShadows_ptr_count(const TextShadows *shadows, size_t *count) { - *count = shadows->textShadows.size(); - return &shadows->textShadows.front(); -} - // // TypefaceFontProvider // diff --git a/skia-bindings/src/shaper.cpp b/skia-bindings/src/shaper.cpp index 90f2c2177..5dfa29d8f 100644 --- a/skia-bindings/src/shaper.cpp +++ b/skia-bindings/src/shaper.cpp @@ -2,6 +2,8 @@ #define SK_SHAPER_HARFBUZZ_AVAILABLE #endif +#include "bindings.h" + #include "modules/skshaper/include/SkShaper.h" #include "include/core/SkFontMgr.h" @@ -113,11 +115,6 @@ extern "C" void C_SkShaper_RunHandler_delete(SkShaper::RunHandler* self) { delete self; } -extern "C" struct TraitObject { - void* data; - void* vtable; -}; - namespace RunHandler { extern "C" typedef void (*BeginLine)(TraitObject); extern "C" typedef void (*RunInfo)(TraitObject, const SkShaper::RunHandler::RunInfo*); diff --git a/skia-safe/src/core/bitmap.rs b/skia-safe/src/core/bitmap.rs index e4d39d361..ae80e8421 100644 --- a/skia-safe/src/core/bitmap.rs +++ b/skia-safe/src/core/bitmap.rs @@ -1,10 +1,8 @@ -use crate::{prelude::*, Image, SamplingOptions}; use crate::{ - AlphaType, Color, ColorSpace, ColorType, IPoint, IRect, ISize, ImageInfo, Matrix, Paint, - PixelRef, Pixmap, Shader, TileMode, + prelude::*, AlphaType, Color, ColorSpace, ColorType, IPoint, IRect, ISize, Image, ImageInfo, + Matrix, Paint, PixelRef, Pixmap, SamplingOptions, Shader, TileMode, }; -use skia_bindings as sb; -use skia_bindings::SkBitmap; +use skia_bindings::{self as sb, SkBitmap}; use std::{ffi, fmt, ptr}; /// [Bitmap] describes a two-dimensional raster pixel array. [Bitmap] is built on [ImageInfo], diff --git a/skia-safe/src/core/canvas.rs b/skia-safe/src/core/canvas.rs index 813074b51..593bd0e95 100644 --- a/skia-safe/src/core/canvas.rs +++ b/skia-safe/src/core/canvas.rs @@ -2,9 +2,9 @@ use crate::gpu; use crate::{ prelude::*, scalar, u8cpu, Bitmap, BlendMode, ClipOp, Color, Color4f, Data, Drawable, - FilterMode, Font, IPoint, IRect, ISize, Image, ImageFilter, ImageInfo, Matrix, Paint, Path, - Picture, Pixmap, Point, QuickReject, RRect, Rect, Region, SamplingOptions, Shader, Surface, - SurfaceProps, TextBlob, TextEncoding, Vector, Vertices, M44, + FilterMode, Font, GlyphId, IPoint, IRect, ISize, Image, ImageFilter, ImageInfo, Matrix, Paint, + Path, Picture, Pixmap, Point, QuickReject, RRect, RSXform, Rect, Region, SamplingOptions, + Shader, Surface, SurfaceProps, TextBlob, TextEncoding, Vector, Vertices, M44, }; use skia_bindings as sb; use skia_bindings::{ @@ -165,6 +165,24 @@ pub struct TopLayerPixels<'a> { pub origin: IPoint, } +/// Used to pass either a slice of [`Point`] or [`RSXform`] to [`Canvas::draw_glyphs_at`]. +pub enum GlyphPositions<'a> { + Points(&'a [Point]), + RSXforms(&'a [RSXform]), +} + +impl<'a> From<&'a [Point]> for GlyphPositions<'a> { + fn from(points: &'a [Point]) -> Self { + Self::Points(points) + } +} + +impl<'a> From<&'a [RSXform]> for GlyphPositions<'a> { + fn from(rs_xforms: &'a [RSXform]) -> Self { + Self::RSXforms(rs_xforms) + } +} + /// [`Canvas`] provides an interface for drawing, and how the drawing is clipped and transformed. /// [`Canvas`] contains a stack of [`Matrix`] and clip values. /// @@ -1749,6 +1767,128 @@ impl Canvas { self } + /// Draws glyphs at positions relative to origin styled with font and paint with + /// supporting utf8 and cluster information. + /// + /// This function draw glyphs at the given positions relative to the given origin. + /// It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + /// + /// The drawing obeys the current transform matrix and clipping. + /// + /// All elements of paint: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`], + /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to text. By default, draws filled black + /// glyphs. + /// + /// - `count` number of glyphs to draw + /// - `glyphs` the array of glyphIDs to draw + /// - `positions` where to draw each glyph relative to origin + /// - `clusters` array of size count of cluster information + /// - `utf8_text` utf8text supporting information for the glyphs + /// - `origin` the origin of all the positions + /// - `font` typeface, text size and so, used to describe the text + /// - `paint` blend, color, and so on, used to draw + #[allow(clippy::too_many_arguments)] + pub fn draw_glyphs_utf8( + &mut self, + glyphs: &[GlyphId], + positions: &[Point], + clusters: &[u32], + utf8_text: impl AsRef, + origin: impl Into, + font: &Font, + paint: &Paint, + ) { + let count = glyphs.len(); + if count == 0 { + return; + } + assert_eq!(positions.len(), count); + assert_eq!(clusters.len(), count); + let utf8_text = utf8_text.as_ref().as_bytes(); + let origin = origin.into(); + unsafe { + self.native_mut().drawGlyphs( + count.try_into().unwrap(), + glyphs.as_ptr(), + positions.native().as_ptr(), + clusters.as_ptr(), + utf8_text.len().try_into().unwrap(), + utf8_text.as_ptr() as _, + origin.into_native(), + font.native(), + paint.native(), + ) + } + } + + /// Draws count glyphs, at positions relative to origin styled with font and paint. + /// + /// This function draw glyphs at the given positions relative to the given origin. + /// It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + /// + /// The drawing obeys the current transform matrix and clipping. + /// + /// All elements of paint: [`crate::PathEffect`], [`crate::MaskFilter`], [`Shader`], + /// [`crate::ColorFilter`], and [`ImageFilter`]; apply to text. By default, draws filled black + /// glyphs. + /// + /// - `count` number of glyphs to draw + /// - `glyphs` the array of glyphIDs to draw + /// - `positions` where to draw each glyph relative to origin, either a `&[Point]` or + /// `&[RSXform]` slice + /// - `origin` the origin of all the positions + /// - `font` typeface, text size and so, used to describe the text + /// - `paint` blend, color, and so on, used to draw + pub fn draw_glyphs_at<'a>( + &mut self, + glyphs: &[GlyphId], + positions: impl Into>, + origin: impl Into, + font: &Font, + paint: &Paint, + ) { + let count = glyphs.len(); + if count == 0 { + return; + } + let positions: GlyphPositions = positions.into(); + let origin = origin.into(); + + let glyphs = glyphs.as_ptr(); + let origin = origin.into_native(); + let font = font.native(); + let paint = paint.native(); + + match positions { + GlyphPositions::Points(points) => { + assert_eq!(points.len(), count); + unsafe { + self.native_mut().drawGlyphs1( + count.try_into().unwrap(), + glyphs, + points.native().as_ptr(), + origin, + font, + paint, + ) + } + } + GlyphPositions::RSXforms(xforms) => { + assert_eq!(xforms.len(), count); + unsafe { + self.native_mut().drawGlyphs2( + count.try_into().unwrap(), + glyphs, + xforms.native().as_ptr(), + origin, + font, + paint, + ) + } + } + } + } + /// Draws [`TextBlob`] blob at `(origin.x, origin.y)`, using clip, [`Matrix`], and [`Paint`] /// paint. /// diff --git a/skia-safe/src/core/font.rs b/skia-safe/src/core/font.rs index 44c091bf4..6f7fbed5c 100644 --- a/skia-safe/src/core/font.rs +++ b/skia-safe/src/core/font.rs @@ -1,10 +1,8 @@ -use crate::prelude::*; use crate::{ - scalar, FontHinting, FontMetrics, GlyphId, Paint, Path, Point, Rect, TextEncoding, Typeface, - Unichar, + interop::VecSink, prelude::*, scalar, FontHinting, FontMetrics, GlyphId, Paint, Path, Point, + Rect, TextEncoding, Typeface, Unichar, }; -use skia_bindings as sb; -use skia_bindings::{SkFont, SkFont_PrivFlags}; +use skia_bindings::{self as sb, SkFont, SkFont_PrivFlags}; use std::{fmt, ptr}; pub use skia_bindings::SkFont_Edging as Edging; @@ -391,6 +389,32 @@ impl Font { } } + pub fn get_intercepts<'a>( + &self, + glyphs: &[GlyphId], + pos: &[Point], + (top, bottom): (scalar, scalar), + paint: impl Into>, + ) -> Vec { + assert_eq!(glyphs.len(), pos.len()); + let count = glyphs.len().try_into().unwrap(); + let mut r: Vec = Vec::new(); + let mut set = |scalars: &[scalar]| r = scalars.to_vec(); + unsafe { + sb::C_SkFont_getIntercepts( + self.native(), + glyphs.as_ptr(), + count, + pos.native().as_ptr(), + top, + bottom, + paint.into().native_ptr_or_null(), + VecSink::new(&mut set).native_mut(), + ); + } + r + } + pub fn get_path(&self, glyph_id: GlyphId) -> Option { let mut path = Path::default(); unsafe { self.native().getPath(glyph_id, path.native_mut()) }.if_true_some(path) diff --git a/skia-safe/src/core/font_mgr.rs b/skia-safe/src/core/font_mgr.rs index 528f1b25b..9ba4c2ae7 100644 --- a/skia-safe/src/core/font_mgr.rs +++ b/skia-safe/src/core/font_mgr.rs @@ -128,7 +128,12 @@ impl FontMgr { (0..self.count_families()).map(move |i| self.family_name(i)) } + #[deprecated(since = "0.0.0", note = "Use new_style_set")] pub fn new_styleset(&self, index: usize) -> FontStyleSet { + self.new_style_set(index) + } + + pub fn new_style_set(&self, index: usize) -> FontStyleSet { assert!(index < self.count_families()); FontStyleSet::from_ptr(unsafe { self.native().createStyleSet(index.try_into().unwrap()) }) .unwrap() @@ -219,7 +224,7 @@ mod tests { for i in 0..families { let name = font_mgr.family_name(i); println!("font_family: {}", name); - let mut style_set = font_mgr.new_styleset(i); + let mut style_set = font_mgr.new_style_set(i); for style_index in 0..style_set.count() { let (_, style_name) = style_set.style(style_index); if let Some(style_name) = style_name { diff --git a/skia-safe/src/core/m44.rs b/skia-safe/src/core/m44.rs index bf7783e5e..b8e2b41b0 100644 --- a/skia-safe/src/core/m44.rs +++ b/skia-safe/src/core/m44.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{prelude::*, Rect}; #[allow(deprecated)] use crate::{scalar, Matrix, Matrix44, Scalars}; use bitflags::_core::ops::{AddAssign, MulAssign}; @@ -520,6 +520,11 @@ impl M44 { m } + pub fn rect_to_rect(src: impl AsRef, dst: impl AsRef) -> Self { + let (src, dst) = (src.as_ref(), dst.as_ref()); + Self::construct(|m| unsafe { sb::C_SkM44_RectToRect(src.native(), dst.native(), m) }) + } + pub fn look_at(eye: &V3, center: &V3, up: &V3) -> Self { Self::construct(|m| unsafe { sb::C_SkM44_LookAt(eye.native(), center.native(), up.native(), m) @@ -767,6 +772,11 @@ impl M44 { self } + pub fn pre_scale_xyz(&mut self, x: scalar, y: scalar, z: scalar) -> &mut Self { + unsafe { self.native_mut().preScale1(x, y, z) }; + self + } + // helper #[allow(deprecated)] diff --git a/skia-safe/src/core/milestone.rs b/skia-safe/src/core/milestone.rs index 207ed9555..5d126a0a6 100644 --- a/skia-safe/src/core/milestone.rs +++ b/skia-safe/src/core/milestone.rs @@ -1 +1 @@ -pub const MILESTONE: usize = 91; +pub const MILESTONE: usize = 92; diff --git a/skia-safe/src/core/path_effect.rs b/skia-safe/src/core/path_effect.rs index 02437aabd..1e765ee54 100644 --- a/skia-safe/src/core/path_effect.rs +++ b/skia-safe/src/core/path_effect.rs @@ -148,15 +148,6 @@ impl PathEffect { } } - pub fn compute_fast_bounds(&self, src: impl AsRef) -> Rect { - let mut r: Rect = Rect::default(); - unsafe { - self.native() - .computeFastBounds(r.native_mut(), src.as_ref().native()) - }; - r - } - // TODO: rename to to_points()? pub fn as_points( &self, diff --git a/skia-safe/src/core/rect.rs b/skia-safe/src/core/rect.rs index 166b3465a..986feb635 100644 --- a/skia-safe/src/core/rect.rs +++ b/skia-safe/src/core/rect.rs @@ -147,6 +147,14 @@ impl IRect { self.bottom = height; } + pub fn set_size(&mut self, size: impl Into) { + let size = size.into(); + self.left = 0; + self.top = 0; + self.right = size.width; + self.bottom = size.height; + } + #[must_use] pub fn with_offset(&self, delta: impl Into) -> Self { let mut copied = *self; diff --git a/skia-safe/src/core/surface_props.rs b/skia-safe/src/core/surface_props.rs index 0ca88cf33..361241d00 100644 --- a/skia-safe/src/core/surface_props.rs +++ b/skia-safe/src/core/surface_props.rs @@ -107,6 +107,10 @@ impl SurfaceProps { SurfacePropsFlags::from_bits_truncate(self.native().fFlags) } + pub fn clone_with_pixel_geometry(&self, new_pixel_geometry: PixelGeometry) -> Self { + Self::new(self.flags(), new_pixel_geometry) + } + pub fn pixel_geometry(self) -> PixelGeometry { PixelGeometry::from_native_c(self.native().fPixelGeometry) } diff --git a/skia-safe/src/core/vertices.rs b/skia-safe/src/core/vertices.rs index 972483971..20c43286d 100644 --- a/skia-safe/src/core/vertices.rs +++ b/skia-safe/src/core/vertices.rs @@ -1,9 +1,6 @@ use crate::{prelude::*, Color, Point, Rect}; -use skia_bindings::{ - self as sb, SkPoint, SkVertices, SkVertices_Attribute, SkVertices_Attribute_Type, - SkVertices_Builder, -}; -use std::{ffi::CStr, fmt, marker::PhantomData, os::raw::c_char, ptr, slice}; +use skia_bindings::{self as sb, SkPoint, SkVertices, SkVertices_Builder}; +use std::{fmt, ptr, slice}; #[deprecated(since = "0.29.0", note = "removed without replacement")] pub type BoneIndices = [u32; 4]; @@ -24,101 +21,6 @@ fn test_vertices_vertex_mode_naming() { let _ = VertexMode::Triangles; } -#[repr(u8)] -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AttributeType { - Float = sb::SkVertices_Attribute_Type::Float as _, - Float2 = sb::SkVertices_Attribute_Type::Float2 as _, - Float3 = sb::SkVertices_Attribute_Type::Float3 as _, - Float4 = sb::SkVertices_Attribute_Type::Float4 as _, - Byte4UNorm = sb::SkVertices_Attribute_Type::Byte4_unorm as _, -} - -impl NativeTransmutable for AttributeType {} -#[test] -fn test_attribute_type_layout() { - AttributeType::test_layout() -} - -pub use skia_bindings::SkVertices_Attribute_Usage as AttributeUsage; -#[test] -fn test_attribute_usage_naming() { - let _ = AttributeUsage::Vector; -} - -#[repr(C)] -#[derive(Copy, Clone, Eq, Debug)] -pub struct Attribute<'a> { - pub ty: AttributeType, - pub usage: AttributeUsage, - pub marker_id: u32, - marker_name: *const c_char, - pd: PhantomData<&'a CStr>, -} - -impl NativeTransmutable for Attribute<'_> {} -#[test] -fn test_attribute_layout() { - Attribute::test_layout() -} - -impl PartialEq for Attribute<'_> { - fn eq(&self, other: &Self) -> bool { - self.ty == other.ty && self.usage == other.usage && self.marker_id == other.marker_id - } -} - -impl Default for Attribute<'_> { - fn default() -> Self { - Attribute::new(AttributeType::Float) - } -} - -impl Attribute<'_> { - pub fn new(ty: AttributeType) -> Self { - Self::new_with_usage_and_marker(ty, None, None) - } - - pub fn new_with_usage_and_marker<'a>( - ty: AttributeType, - usage: impl Into>, - marker_name: impl Into>, - ) -> Attribute<'a> { - let marker_name = marker_name - .into() - .map(|m| m.as_ptr()) - .unwrap_or(ptr::null()); - - Attribute::from_native_c(unsafe { - SkVertices_Attribute::new( - ty.into_native(), - usage.into().unwrap_or(AttributeUsage::Raw), - marker_name, - ) - }) - } - - pub fn marker_name(&self) -> Option<&CStr> { - if !self.marker_name.is_null() { - unsafe { CStr::from_ptr(self.marker_name) }.into() - } else { - None - } - } - - pub fn channel_count(self) -> usize { - unsafe { self.native().channelCount() }.try_into().unwrap() - } - - pub fn bytes_per_vertex(self) -> usize { - unsafe { self.native().bytesPerVertex() } - } - - pub fn is_valid(self) -> bool { - unsafe { self.native().isValid() } - } -} - pub type Vertices = RCHandle; unsafe impl Send for Vertices {} unsafe impl Sync for Vertices {} @@ -354,8 +256,6 @@ impl Builder { } } - // TODO: customData() - pub fn tex_coords(&mut self) -> Option<&mut [Point]> { unsafe { let vertices = &*self.native().fVertices.fPtr; diff --git a/skia-safe/src/effects/runtime_effect.rs b/skia-safe/src/effects/runtime_effect.rs index 593369efd..5ebcf809e 100644 --- a/skia-safe/src/effects/runtime_effect.rs +++ b/skia-safe/src/effects/runtime_effect.rs @@ -3,9 +3,14 @@ use crate::{ prelude::*, ColorFilter, Data, Matrix, Shader, }; +use sb::SkRuntimeEffect_Child; use skia_bindings::{ - self as sb, SkRefCntBase, SkRuntimeEffect, SkRuntimeEffect_Options, SkRuntimeEffect_Uniform, - SkRuntimeEffect_Varying, + self as sb, + SkRefCntBase, + SkRuntimeEffect, + SkRuntimeEffect_Options, + SkRuntimeEffect_Uniform, + // SkRuntimeEffect_Varying, }; use std::{ffi::CStr, fmt}; @@ -50,10 +55,6 @@ impl Uniform { uniform::Flags::from_bits(self.native().flags).unwrap() } - pub fn marker(&self) -> u32 { - self.native().marker - } - pub fn is_array(&self) -> bool { self.flags().contains(uniform::Flags::ARRAY) } @@ -75,41 +76,31 @@ pub mod uniform { bitflags! { pub struct Flags : u32 { const ARRAY = sb::SkRuntimeEffect_Uniform_Flags_kArray_Flag as _; - const MARKER = sb::SkRuntimeEffect_Uniform_Flags_kMarker_Flag as _; - const MARKER_NORMALS = sb::SkRuntimeEffect_Uniform_Flags_kMarkerNormals_Flag as _; const SRGB_UNPREMUL = sb::SkRuntimeEffect_Uniform_Flags_kSRGBUnpremul_Flag as _; } } } -pub type Varying = Handle; -unsafe impl Send for Varying {} -unsafe impl Sync for Varying {} +#[deprecated(since = "0.0.0", note = "Use Child instead")] +pub type Varying = Child; + +pub type Child = Handle; +unsafe impl Send for Child {} +unsafe impl Sync for Child {} -impl NativeDrop for SkRuntimeEffect_Varying { +impl NativeDrop for SkRuntimeEffect_Child { fn drop(&mut self) { - panic!("native type SkRuntimeEffect::Varying can't be owned by Rust"); + panic!("native type SkRuntimeEffect::Child can't be owned in Rust"); } } -impl fmt::Debug for Varying { +impl fmt::Debug for Child { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Varying") - .field("name", &self.name()) - .field("width", &self.width()) - .finish() + self.native().fmt(f) } } -impl Varying { - pub fn name(&self) -> &str { - self.native().name.as_str() - } - - pub fn width(&self) -> i32 { - self.native().width - } -} +pub use sb::SkRuntimeEffect_Child_Type as ChildType; pub type RuntimeEffect = RCHandle; @@ -118,28 +109,21 @@ impl NativeRefCountedBase for SkRuntimeEffect { } #[repr(C)] -#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Options { pub force_no_inline: bool, + pub enforce_es2_restrictions: bool, } impl NativeTransmutable for Options {} -pub fn new(sksl: impl AsRef) -> Result { - new_with_options(sksl, None) -} - -pub fn new_with_options<'a>( - sksl: impl AsRef, - options: impl Into>, -) -> Result { - let str = interop::String::from_str(sksl); - let options = options.into().copied().unwrap_or_default(); - let mut error = interop::String::default(); - RuntimeEffect::from_ptr(unsafe { - sb::C_SkRuntimeEffect_Make(str.native(), options.native(), error.native_mut()) - }) - .ok_or_else(|| error.as_str().to_owned()) +impl Default for Options { + fn default() -> Self { + Options { + force_no_inline: false, + enforce_es2_restrictions: true, + } + } } impl fmt::Debug for RuntimeEffect { @@ -147,12 +131,41 @@ impl fmt::Debug for RuntimeEffect { f.debug_struct("RuntimeEffect") .field("uniform_size", &self.uniform_size()) .field("uniforms", &self.uniforms()) - .field("varyings", &self.varyings()) .finish() } } impl RuntimeEffect { + pub fn make_for_color_filer<'a>( + sksl: impl AsRef, + options: impl Into>, + ) -> Result { + let str = interop::String::from_str(sksl); + let options = options.into().copied().unwrap_or_default(); + let mut error = interop::String::default(); + RuntimeEffect::from_ptr(unsafe { + sb::C_SkRuntimeEffect_MakeForColorFilter( + str.native(), + options.native(), + error.native_mut(), + ) + }) + .ok_or_else(|| error.to_string()) + } + + pub fn make_for_shader<'a>( + sksl: impl AsRef, + options: impl Into>, + ) -> Result { + let str = interop::String::from_str(sksl); + let options = options.into().copied().unwrap_or_default(); + let mut error = interop::String::default(); + RuntimeEffect::from_ptr(unsafe { + sb::C_SkRuntimeEffect_MakeForShader(str.native(), options.native(), error.native_mut()) + }) + .ok_or_else(|| error.to_string()) + } + pub fn make_shader<'a>( &self, uniforms: impl Into, @@ -237,20 +250,11 @@ impl RuntimeEffect { } } - pub fn children(&self) -> impl Iterator { + pub fn children(&self) -> &[Child] { unsafe { let mut count: usize = 0; let ptr = sb::C_SkRuntimeEffect_children(self.native(), &mut count); - let slice = safer::from_raw_parts(ptr, count); - slice.iter().map(|str| str.as_str()) - } - } - - pub fn varyings(&self) -> &[Varying] { - unsafe { - let mut count: usize = 0; - let ptr = sb::C_SkRuntimeEffect_varyings(self.native(), &mut count); - safer::from_raw_parts(Varying::from_native_ptr(ptr), count) + safer::from_raw_parts(Child::from_native_ptr(ptr), count) } } @@ -265,13 +269,10 @@ impl RuntimeEffect { .map(|ptr| Uniform::from_native_ref(unsafe { &*ptr })) } - pub fn find_child(&self, name: impl AsRef) -> Option { - unsafe { - self.native() - .findChild(name.as_ref().as_ptr()) - .try_into() - .ok() - } + pub fn find_child(&self, name: impl AsRef) -> Option<&Child> { + unsafe { self.native().findChild(name.as_ref().as_ptr()) } + .into_option() + .map(|ptr| Child::from_native_ref(unsafe { &*ptr })) } } @@ -285,4 +286,9 @@ mod tests { fn options_layout() { super::Options::test_layout() } + + #[test] + fn test_child_type_naming() { + let _ = super::ChildType::ColorFilter; + } } diff --git a/skia-safe/src/gpu/backend_surface.rs b/skia-safe/src/gpu/backend_surface.rs index 0b38706fe..b71f2b678 100644 --- a/skia-safe/src/gpu/backend_surface.rs +++ b/skia-safe/src/gpu/backend_surface.rs @@ -6,7 +6,7 @@ use super::gl; use super::mtl; #[cfg(feature = "vulkan")] use super::vk; -use super::{BackendAPI, BackendSurfaceMutableState}; +use super::{BackendAPI, BackendSurfaceMutableState, Mipmapped}; use crate::{prelude::*, ISize}; use skia_bindings::{ self as sb, GrBackendFormat, GrBackendRenderTarget, GrBackendTexture, GrMipmapped, @@ -175,7 +175,7 @@ impl fmt::Debug for BackendTexture { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut d = f.debug_struct("BackendTexture"); d.field("dimensions", &self.dimensions()); - d.field("has_mipmaps", &self.has_mipmaps()); + d.field("mipmapped", &self.mipmapped()); d.field("backend", &self.backend()); #[cfg(feature = "gl")] d.field("gl_texture_info", &self.gl_texture_info()); @@ -269,6 +269,10 @@ impl BackendTexture { self.native().fHeight } + pub fn mipmapped(&self) -> Mipmapped { + self.native().fMipmapped + } + #[deprecated(since = "0.35.0", note = "Use has_mipmaps()")] pub fn has_mip_maps(&self) -> bool { self.has_mipmaps() diff --git a/skia-safe/src/gpu/d3d/types.rs b/skia-safe/src/gpu/d3d/types.rs index 19ca6be2e..2c2be3bbc 100644 --- a/skia-safe/src/gpu/d3d/types.rs +++ b/skia-safe/src/gpu/d3d/types.rs @@ -46,7 +46,7 @@ impl fmt::Debug for Alloc { } // TODO: support the implementation of custom D3D memory allocator's -// virtual createResource() function. +// virtual createResource() and createAliasingResource() functions. pub type MemoryAllocator = RCHandle; unsafe impl Send for MemoryAllocator {} unsafe impl Sync for MemoryAllocator {} diff --git a/skia-safe/src/interop.rs b/skia-safe/src/interop.rs index 7ca8db31a..e2c35008a 100644 --- a/skia-safe/src/interop.rs +++ b/skia-safe/src/interop.rs @@ -1,12 +1,14 @@ -/// Simple Skia types that are not exported and used to -/// to marshal between Rust and Skia types only. +/// Skia and C++ types that are used to to marshal between Rust and C++. +mod cpp; +pub use cpp::*; + mod stream; -pub(crate) use self::stream::*; +pub use self::stream::*; mod string; -pub(crate) use self::string::*; +pub use self::string::*; #[cfg(feature = "textlayout")] mod strings; #[cfg(feature = "textlayout")] -pub(crate) use self::strings::*; +pub use self::strings::*; diff --git a/skia-safe/src/interop/cpp.rs b/skia-safe/src/interop/cpp.rs new file mode 100644 index 000000000..583eafed1 --- /dev/null +++ b/skia-safe/src/interop/cpp.rs @@ -0,0 +1,50 @@ +use crate::prelude::safer; +use sb::TraitObject; +use skia_bindings as sb; +use std::{marker::PhantomData, mem}; + +/// A sink / receiver for array data that is copied from C++ to a Rust [`Vec`]. +#[derive(Debug)] +pub struct VecSink<'a, T> { + sink: sb::VecSink, + pd: PhantomData<&'a mut Vec>, +} + +impl VecSink<'_, T> { + /// Create a new sink that calls back into the closure given. + pub fn new(v: &mut dyn FnMut(&[T])) -> VecSink { + VecSink { + sink: sb::VecSink { + fn_trait: unsafe { mem::transmute(v) }, + set_fn: Some(Self::set_fn), + _phantom_0: PhantomData, + }, + pd: PhantomData, + } + } + + pub fn new_mut(v: &mut dyn FnMut(&mut [T])) -> VecSink { + VecSink { + sink: sb::VecSink { + fn_trait: unsafe { mem::transmute(v) }, + set_fn: Some(Self::set_fn_mut), + _phantom_0: PhantomData, + }, + pd: PhantomData, + } + } + + pub fn native_mut(&mut self) -> &mut sb::VecSink { + &mut self.sink + } + + unsafe extern "C" fn set_fn(ptr: *mut T, len: usize, rust_fn: TraitObject) { + let rust_fn: &mut dyn FnMut(&[T]) = mem::transmute(rust_fn); + (rust_fn)(safer::from_raw_parts(ptr, len)); + } + + unsafe extern "C" fn set_fn_mut(ptr: *mut T, len: usize, rust_fn: TraitObject) { + let rust_fn: &mut dyn FnMut(&mut [T]) = mem::transmute(rust_fn); + (rust_fn)(safer::from_raw_parts_mut(ptr, len)); + } +} diff --git a/skia-safe/src/modules/paragraph/font_collection.rs b/skia-safe/src/modules/paragraph/font_collection.rs index a76ad4565..4199d64bb 100644 --- a/skia-safe/src/modules/paragraph/font_collection.rs +++ b/skia-safe/src/modules/paragraph/font_collection.rs @@ -1,11 +1,11 @@ use crate::{ - interop::{self, FromStrs}, + interop::{self, FromStrs, VecSink}, prelude::*, textlayout::ParagraphCache, FontMgr, FontStyle, Typeface, Unichar, }; use skia_bindings::{self as sb, skia_textlayout_FontCollection}; -use std::{ffi, fmt}; +use std::{ffi, fmt, ptr}; pub type FontCollection = RCHandle; @@ -110,16 +110,28 @@ impl FontCollection { font_style: FontStyle, ) -> Vec { let family_names = interop::Strings::from_strs(family_names); - let mut typefaces = Typefaces::new(); + + let mut typefaces: Vec = Vec::new(); + let mut set_typefaces = |tfs: &mut [sb::sk_sp]| { + typefaces = tfs + .iter_mut() + .filter_map(|sp| { + let ptr = sp.fPtr; + sp.fPtr = ptr::null_mut(); + Typeface::from_ptr(ptr) + }) + .collect() + }; + unsafe { sb::C_FontCollection_findTypefaces( self.native_mut(), family_names.native(), font_style.into_native(), - typefaces.native_mut(), + VecSink::new_mut(&mut set_typefaces).native_mut(), ) }; - typefaces.into_vec() + typefaces } pub fn default_fallback_char( @@ -172,30 +184,6 @@ impl FontCollection { } } -type Typefaces = Handle; - -impl NativeDrop for sb::Typefaces { - fn drop(&mut self) { - unsafe { sb::C_Typefaces_destruct(self) } - } -} - -impl Typefaces { - pub fn new() -> Self { - Typefaces::construct(|tf| unsafe { sb::C_Typefaces_construct(tf) }) - } - - pub fn into_vec(mut self) -> Vec { - let count = unsafe { sb::C_Typefaces_count(self.native()) }; - (0..count) - .map(|i| { - Typeface::from_ptr(unsafe { sb::C_Typefaces_release(self.native_mut(), i) }) - .unwrap() - }) - .collect() - } -} - #[cfg(test)] mod tests { use crate::prelude::*; diff --git a/skia-safe/src/modules/paragraph/metrics.rs b/skia-safe/src/modules/paragraph/metrics.rs index 906c0f314..a0a47eca2 100644 --- a/skia-safe/src/modules/paragraph/metrics.rs +++ b/skia-safe/src/modules/paragraph/metrics.rs @@ -3,7 +3,7 @@ use skia_bindings::{self as sb, skia_textlayout_LineMetrics, skia_textlayout_Sty use std::{marker, mem, ops::Range, ptr}; #[repr(C)] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct StyleMetrics<'a> { pub text_style: &'a TextStyle, pub font_metrics: FontMetrics, @@ -26,7 +26,7 @@ impl<'a> StyleMetrics<'a> { } #[repr(C)] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct LineMetrics<'a> { pub start_index: usize, pub end_index: usize, @@ -46,8 +46,10 @@ pub struct LineMetrics<'a> { pd: marker::PhantomData<&'a StyleMetrics<'a>>, } +impl NativeTransmutable for LineMetrics<'_> {} + // Internal Line Metrics mirror to compute what the map takes up space. -// In case this computation is incorrect, the NativeTransmutable test below will fail. +// If the size of the structure does not match, the NativeTransmutable test below will fail. #[repr(C)] struct LMInternal { start_end: [usize; 4], @@ -56,8 +58,6 @@ struct LMInternal { line_number: usize, } -impl NativeTransmutable for LineMetrics<'_> {} - #[test] fn test_line_metrics_layout() { LineMetrics::test_layout(); diff --git a/skia-safe/src/modules/paragraph/paragraph.rs b/skia-safe/src/modules/paragraph/paragraph.rs index eb49fbaeb..05cdefbd6 100644 --- a/skia-safe/src/modules/paragraph/paragraph.rs +++ b/skia-safe/src/modules/paragraph/paragraph.rs @@ -1,10 +1,7 @@ use super::{PositionWithAffinity, RectHeightStyle, RectWidthStyle, TextBox}; -use crate::{prelude::*, scalar, textlayout::LineMetrics, Canvas, Point}; +use crate::{interop::VecSink, prelude::*, scalar, textlayout::LineMetrics, Canvas, Point}; use skia_bindings as sb; -use std::{ - fmt, - ops::{Index, Range}, -}; +use std::{fmt, ops::Range}; pub type Paragraph = RefHandle; unsafe impl Send for Paragraph {} @@ -79,23 +76,48 @@ impl Paragraph { range: Range, rect_height_style: RectHeightStyle, rect_width_style: RectWidthStyle, - ) -> TextBoxes { - TextBoxes::construct(|tb| unsafe { + ) -> Vec { + let mut result: Vec = Vec::new(); + + let mut set_tb = |tbs: &[sb::skia_textlayout_TextBox]| { + result = tbs + .iter() + .map(|tb| TextBox::from_native_ref(tb)) + .cloned() + .collect(); + }; + + unsafe { sb::C_Paragraph_getRectsForRange( self.native_mut_force(), range.start.try_into().unwrap(), range.end.try_into().unwrap(), rect_height_style, rect_width_style, - tb, - ) - }) + VecSink::new(&mut set_tb).native_mut(), + ); + } + result } - pub fn get_rects_for_placeholders(&self) -> TextBoxes { - TextBoxes::construct(|tb| unsafe { - sb::C_Paragraph_getRectsForPlaceholders(self.native_mut_force(), tb) - }) + pub fn get_rects_for_placeholders(&self) -> Vec { + let mut result: Vec = Vec::new(); + + let mut set_tb = |tbs: &[sb::skia_textlayout_TextBox]| { + result = tbs + .iter() + .map(|tb| TextBox::from_native_ref(tb)) + .cloned() + .collect(); + }; + + unsafe { + sb::C_Paragraph_getRectsForPlaceholders( + self.native_mut_force(), + VecSink::new(&mut set_tb).native_mut(), + ) + } + result } pub fn get_glyph_position_at_coordinate(&self, p: impl Into) -> PositionWithAffinity { @@ -115,11 +137,23 @@ impl Paragraph { range[0]..range[1] } - pub fn get_line_metrics(&self) -> LineMetricsVector { - Handle::::construct(|lmv| unsafe { - sb::C_Paragraph_getLineMetrics(self.native_mut_force(), lmv) - }) - .borrows(self) + pub fn get_line_metrics(&self) -> Vec { + let mut result: Vec = Vec::new(); + let mut set_lm = |lms: &[sb::skia_textlayout_LineMetrics]| { + result = lms + .iter() + .map(|lm| LineMetrics::from_native_ref(lm).clone()) + .collect(); + }; + + unsafe { + sb::C_Paragraph_getLineMetrics( + self.native_mut_force(), + VecSink::new(&mut set_lm).native_mut(), + ) + } + + result } pub fn line_number(&self) -> usize { @@ -129,116 +163,50 @@ impl Paragraph { pub fn mark_dirty(&mut self) { unsafe { sb::C_Paragraph_markDirty(self.native_mut()) } } -} -pub type TextBoxes = Handle; - -impl NativeDrop for sb::TextBoxes { - fn drop(&mut self) { - unsafe { sb::C_TextBoxes_destruct(self) } + pub fn unresolved_glyphs(&mut self) -> Option { + unsafe { sb::C_Paragraph_unresolvedGlyphs(self.native_mut()) } + .try_into() + .ok() } -} -impl Index for TextBoxes { - type Output = TextBox; - fn index(&self, index: usize) -> &Self::Output { - &self.as_slice()[index] - } + // TODO: wrap visit() } -impl AsRef<[TextBox]> for TextBoxes { - fn as_ref(&self) -> &[TextBox] { - self.as_slice() - } -} - -impl fmt::Debug for TextBoxes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("TextBoxes").field(&self.as_slice()).finish() - } -} - -impl TextBoxes { - pub fn iter(&self) -> impl Iterator { - self.as_slice().iter() - } - - pub fn as_slice(&self) -> &[TextBox] { - unsafe { - let mut count = 0; - let ptr = sb::C_TextBoxes_ptr_count(self.native(), &mut count); - safer::from_raw_parts(ptr as *const TextBox, count) - } - } -} - -pub type LineMetricsVector<'a> = Borrows<'a, Handle>; - -impl NativeDrop for sb::LineMetricsVector { - fn drop(&mut self) { - unsafe { sb::C_LineMetricsVector_destruct(self) } - } -} - -impl<'a> Index for LineMetricsVector<'a> { - type Output = LineMetrics<'a>; - fn index(&self, index: usize) -> &Self::Output { - &self.as_slice()[index] - } -} - -impl<'a> AsRef<[LineMetrics<'a>]> for LineMetricsVector<'a> { - fn as_ref(&self) -> &[LineMetrics<'a>] { - self.as_slice() - } -} - -impl fmt::Debug for LineMetricsVector<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("LineMetricsVector") - .field(&self.as_slice()) - .finish() - } -} - -impl<'a> LineMetricsVector<'a> { - pub fn iter(&self) -> impl Iterator> { - self.as_slice().iter() - } - - pub fn as_slice(&self) -> &'a [LineMetrics<'a>] { - unsafe { - let mut count = 0; - let ptr = sb::C_LineMetricsVector_ptr_count(self.native(), &mut count); - safer::from_raw_parts(ptr as *const LineMetrics, count) +#[deprecated(since = "0.0.0", note = "Use Vec")] +pub type TextBoxes = Vec; + +#[deprecated(since = "0.0.0", note = "Use Vec")] +pub type LineMetricsVector<'a> = Vec>; + +#[cfg(test)] +mod tests { + use crate::{ + icu, + textlayout::{FontCollection, ParagraphBuilder, ParagraphStyle, TextStyle}, + FontMgr, + }; + + #[test] + #[serial_test::serial] + fn test_line_metrics() { + icu::init(); + + let mut font_collection = FontCollection::new(); + font_collection.set_default_font_manager(FontMgr::new(), None); + let paragraph_style = ParagraphStyle::new(); + let mut paragraph_builder = ParagraphBuilder::new(¶graph_style, font_collection); + let ts = TextStyle::new(); + paragraph_builder.push_style(&ts); + paragraph_builder.add_text(LOREM_IPSUM); + let mut paragraph = paragraph_builder.build(); + paragraph.layout(256.0); + + let line_metrics = paragraph.get_line_metrics(); + for (line, lm) in line_metrics.iter().enumerate() { + println!("line {}: width: {}", line + 1, lm.width) } - } -} - -#[test] -#[serial_test::serial] -fn test_line_metrics() { - // note: some of the following code is copied from the skparagraph skia-org example. - use crate::icu; - use crate::textlayout::{FontCollection, ParagraphBuilder, ParagraphStyle, TextStyle}; - use crate::FontMgr; - icu::init(); - - let mut font_collection = FontCollection::new(); - font_collection.set_default_font_manager(FontMgr::new(), None); - let paragraph_style = ParagraphStyle::new(); - let mut paragraph_builder = ParagraphBuilder::new(¶graph_style, font_collection); - let ts = TextStyle::new(); - paragraph_builder.push_style(&ts); - paragraph_builder.add_text(LOREM_IPSUM); - let mut paragraph = paragraph_builder.build(); - paragraph.layout(256.0); - - let line_metrics = paragraph.get_line_metrics(); - for (line, lm) in line_metrics.iter().enumerate() { - println!("line {}: width: {}", line + 1, lm.width) + static LOREM_IPSUM: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at leo at nulla tincidunt placerat. Proin eget purus augue. Quisque et est ullamcorper, pellentesque felis nec, pulvinar massa. Aliquam imperdiet, nulla ut dictum euismod, purus dui pulvinar risus, eu suscipit elit neque ac est. Nullam eleifend justo quis placerat ultricies. Vestibulum ut elementum velit. Praesent et dolor sit amet purus bibendum mattis. Aliquam erat volutpat."; } - - static LOREM_IPSUM: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur at leo at nulla tincidunt placerat. Proin eget purus augue. Quisque et est ullamcorper, pellentesque felis nec, pulvinar massa. Aliquam imperdiet, nulla ut dictum euismod, purus dui pulvinar risus, eu suscipit elit neque ac est. Nullam eleifend justo quis placerat ultricies. Vestibulum ut elementum velit. Praesent et dolor sit amet purus bibendum mattis. Aliquam erat volutpat."; } diff --git a/skia-safe/src/modules/paragraph/paragraph_style.rs b/skia-safe/src/modules/paragraph/paragraph_style.rs index 9d89d03a2..904945ccd 100644 --- a/skia-safe/src/modules/paragraph/paragraph_style.rs +++ b/skia-safe/src/modules/paragraph/paragraph_style.rs @@ -47,6 +47,8 @@ impl fmt::Debug for StrutStyle { .field("leading", &self.leading()) .field("strut_enabled", &self.strut_enabled()) .field("force_strut_height", &self.force_strut_height()) + .field("height_override", &self.height_override()) + .field("half_leading", &self.half_leading()) .finish() } } @@ -126,6 +128,24 @@ impl StrutStyle { self.native_mut().fForceHeight = force_height; self } + + pub fn height_override(&self) -> bool { + self.native().fHeightOverride + } + + pub fn set_height_override(&mut self, height_override: bool) -> &mut Self { + self.native_mut().fHeightOverride = height_override; + self + } + + pub fn half_leading(&self) -> bool { + self.native().fHalfLeading + } + + pub fn set_half_leading(&mut self, half_leading: bool) -> &mut Self { + self.native_mut().fHalfLeading = half_leading; + self + } } // Can't use Handle<> here, std::u16string maintains an interior pointer. diff --git a/skia-safe/src/modules/paragraph/text_shadow.rs b/skia-safe/src/modules/paragraph/text_shadow.rs index 8b2ed8710..e919abce5 100644 --- a/skia-safe/src/modules/paragraph/text_shadow.rs +++ b/skia-safe/src/modules/paragraph/text_shadow.rs @@ -6,7 +6,7 @@ use skia_bindings as sb; pub struct TextShadow { pub color: Color, pub offset: Point, - pub blur_radius: f64, + pub blur_sigma: f64, } impl NativeTransmutable for TextShadow {} @@ -29,12 +29,12 @@ impl PartialEq for TextShadow { } impl TextShadow { - pub fn new(color: impl Into, offset: impl Into, blur_radius: f64) -> Self { + pub fn new(color: impl Into, offset: impl Into, blur_sigma: f64) -> Self { TextShadow::from_native_c(unsafe { sb::skia_textlayout_TextShadow::new1( color.into().into_native(), offset.into().into_native(), - blur_radius, + blur_sigma, ) }) } diff --git a/skia-safe/src/modules/paragraph/text_style.rs b/skia-safe/src/modules/paragraph/text_style.rs index 43cdeb607..4e164e954 100644 --- a/skia-safe/src/modules/paragraph/text_style.rs +++ b/skia-safe/src/modules/paragraph/text_style.rs @@ -177,7 +177,7 @@ impl NativePartialEq for sb::skia_textlayout_TextStyle { } } -impl Default for Handle { +impl Default for TextStyle { fn default() -> Self { Self::new() } @@ -197,6 +197,7 @@ impl fmt::Debug for TextStyle { .field("font_families", &self.font_families()) .field("height", &self.height()) .field("height_override", &self.height_override()) + .field("half_leading", &self.half_leading()) .field("letter_spacing", &self.letter_spacing()) .field("word_spacing", &self.word_spacing()) .field("typeface", &self.typeface()) @@ -207,7 +208,7 @@ impl fmt::Debug for TextStyle { } } -impl Handle { +impl TextStyle { pub fn new() -> Self { TextStyle::construct(|ts| unsafe { sb::C_TextStyle_Construct(ts) }) } @@ -286,10 +287,9 @@ impl Handle { pub fn shadows(&self) -> &[TextShadow] { unsafe { - let ts: &sb::TextShadows = transmute_ref(&self.native().fTextShadows); - let mut cnt = 0; - let ptr = TextShadow::from_native_ptr(sb::C_TextShadows_ptr_count(ts, &mut cnt)); - safer::from_raw_parts(ptr, cnt) + let mut count = 0; + let ptr = sb::C_TextStyle_getShadows(&self.native().fTextShadows, &mut count); + safer::from_raw_parts(TextShadow::from_native_ptr(ptr), count) } } @@ -305,10 +305,9 @@ impl Handle { pub fn font_features(&self) -> &[FontFeature] { unsafe { - let ff: &sb::FontFeatures = transmute_ref(&self.native().fFontFeatures); - let mut cnt = 0; - let ptr = FontFeature::from_native_ptr(sb::C_FontFeatures_ptr_count(ff, &mut cnt)); - safer::from_raw_parts(ptr, cnt) + let mut count = 0; + let ptr = sb::C_TextStyle_getFontFeatures(&self.native().fFontFeatures, &mut count); + safer::from_raw_parts(FontFeature::from_native_ptr(ptr), count) } } @@ -370,6 +369,15 @@ impl Handle { self.native().fHeightOverride } + pub fn set_half_leading(&mut self, half_leading: bool) -> &mut Self { + self.native_mut().fHalfLeading = half_leading; + self + } + + pub fn half_leading(&self) -> bool { + self.native().fHalfLeading + } + pub fn set_letter_spacing(&mut self, letter_spacing: scalar) -> &mut Self { self.native_mut().fLetterSpacing = letter_spacing; self diff --git a/skia-safe/src/modules/paragraph/typeface_font_provider.rs b/skia-safe/src/modules/paragraph/typeface_font_provider.rs index 062dc944d..a71cae5e2 100644 --- a/skia-safe/src/modules/paragraph/typeface_font_provider.rs +++ b/skia-safe/src/modules/paragraph/typeface_font_provider.rs @@ -6,6 +6,7 @@ use crate::{ use skia_bindings as sb; use std::{ fmt, + mem::transmute, ops::{Deref, DerefMut}, ptr, }; @@ -86,7 +87,7 @@ impl Default for TypefaceFontProvider { impl From for FontMgr { fn from(provider: TypefaceFontProvider) -> Self { - provider.deref().clone() + unsafe { transmute(provider) } } } diff --git a/skia-safe/src/modules/shaper.rs b/skia-safe/src/modules/shaper.rs index 72dab5681..952b5f768 100644 --- a/skia-safe/src/modules/shaper.rs +++ b/skia-safe/src/modules/shaper.rs @@ -457,7 +457,7 @@ impl<'a, T: RunHandler> AsRunHandler<'a> for T { where 'b: 'a, { - let param = rust_run_handler::new_param(self); + let param = unsafe { rust_run_handler::new_param(self) }; rust_run_handler::from_param(¶m) } } @@ -568,9 +568,9 @@ mod rust_run_handler { } } - pub fn new_param(run_handler: &mut dyn RunHandler) -> RustRunHandler_Param { + pub unsafe fn new_param(run_handler: &mut dyn RunHandler) -> RustRunHandler_Param { RustRunHandler_Param { - trait_: unsafe { mem::transmute(run_handler) }, + trait_: mem::transmute(run_handler), beginLine: Some(begin_line), runInfo: Some(run_info), commitRunInfo: Some(commit_run_info), diff --git a/skia-safe/src/prelude.rs b/skia-safe/src/prelude.rs index 691dddb18..b7d9d96ef 100644 --- a/skia-safe/src/prelude.rs +++ b/skia-safe/src/prelude.rs @@ -2,13 +2,16 @@ use skia_bindings::{ C_SkRefCntBase_ref, C_SkRefCntBase_unique, C_SkRefCntBase_unref, SkNVRefCnt, SkRefCnt, SkRefCntBase, }; -use std::hash::{Hash, Hasher}; -use std::mem::MaybeUninit; -use std::ops::{Deref, DerefMut, Index, IndexMut}; -use std::{mem, ptr, slice}; +use std::{ + hash::{Hash, Hasher}, + marker::PhantomData, + mem::{self, MaybeUninit}, + ops::{Deref, DerefMut, Index, IndexMut}, + ptr, slice, +}; + // Re-export TryFrom / TryInto to make them available in all modules that use prelude::*. pub use std::convert::{TryFrom, TryInto}; -use std::marker::PhantomData; /// Swiss army knife to convert any reference into any other. pub(crate) unsafe fn transmute_ref(from: &FromT) -> &ToT { @@ -509,17 +512,22 @@ impl AsRef> for RCHandle { } impl RCHandle { - /// Creates an RCHandle from a pointer. - /// Returns None if the pointer is null. - /// Does not increase the reference count. + /// Creates an reference counted handle from a native pointer. + /// + /// Takes ownership of the object the pointer points to, does not increase the reference count. + /// + /// Returns `None` if the pointer is `null`. #[inline] pub(crate) fn from_ptr(ptr: *mut N) -> Option { ptr::NonNull::new(ptr).map(Self) } - /// Creates an RCHandle from a pointer. - /// Returns None if the pointer is null. - /// Increases the reference count. + /// Creates an reference counted handle from a pointer. + /// + /// Returns `None` if the pointer is `null`. + /// + /// Shares ownership with the object referenced to by the pointer, therefore increases the + /// reference count. #[inline] pub(crate) fn from_unshared_ptr(ptr: *mut N) -> Option { ptr::NonNull::new(ptr).map(|ptr| { @@ -653,7 +661,10 @@ where /// Trait to use native types that as a rust type /// _inplace_ with the same size and field layout. -pub trait NativeTransmutable: Sized { +pub trait NativeTransmutable: Sized +where + Self: Sized, +{ /// Provides access to the native value through a /// transmuted reference to the Rust value. fn native(&self) -> &NT { diff --git a/skia-safe/src/svg/canvas.rs b/skia-safe/src/svg/canvas.rs index 34393e2f9..e05d7ba0e 100644 --- a/skia-safe/src/svg/canvas.rs +++ b/skia-safe/src/svg/canvas.rs @@ -1,13 +1,10 @@ -use crate::interop::DynamicMemoryWStream; -use crate::prelude::*; -use crate::{Data, Rect}; -use skia_bindings as sb; -use skia_bindings::SkCanvas; -use std::pin::Pin; -use std::ptr; +use crate::{interop::DynamicMemoryWStream, prelude::*, Data, Rect}; +use skia_bindings::{self as sb, SkCanvas}; use std::{ fmt, ops::{Deref, DerefMut}, + pin::Pin, + ptr, }; pub struct Canvas { @@ -42,6 +39,7 @@ bitflags! { pub struct Flags : u32 { const CONVERT_TEXT_TO_PATHS = sb::SkSVGCanvas_kConvertTextToPaths_Flag as _; const NO_PRETTY_XML = sb::SkSVGCanvas_kNoPrettyXML_Flag as _; + const RELATIVE_PATH_ENCODING = sb::SkSVGCanvas_kRelativePathEncoding_Flag as _; } } @@ -87,24 +85,30 @@ impl Canvas { } } -#[test] -fn test_svg() { - use crate::Paint; +#[cfg(test)] +mod tests { + use super::Canvas; + use crate::Rect; - let mut canvas = Canvas::new(&Rect::from_size((20, 20)), None); - let paint = Paint::default(); - canvas.draw_circle((10, 10), 10.0, &paint); - let data = canvas.end(); - let contents = String::from_utf8_lossy(data.as_bytes()); - dbg!(&contents); - assert!(contents.contains(r#""#)); - assert!(contents.contains(r#""#)); -} + #[test] + fn test_svg() { + use crate::Paint; + + let mut canvas = Canvas::new(&Rect::from_size((20, 20)), None); + let paint = Paint::default(); + canvas.draw_circle((10, 10), 10.0, &paint); + let data = canvas.end(); + let contents = String::from_utf8_lossy(data.as_bytes()); + dbg!(&contents); + assert!(contents.contains(r#""#)); + assert!(contents.contains(r#""#)); + } -#[test] -fn test_svg_without_ending() { - use crate::Paint; - let mut canvas = Canvas::new(&Rect::from_size((20, 20)), None); - let paint = Paint::default(); - canvas.draw_circle((10, 10), 10.0, &paint); + #[test] + fn test_svg_without_ending() { + use crate::Paint; + let mut canvas = Canvas::new(&Rect::from_size((20, 20)), None); + let paint = Paint::default(); + canvas.draw_circle((10, 10), 10.0, &paint); + } } diff --git a/skia-safe/src/utils.rs b/skia-safe/src/utils.rs index 7daee94aa..30232d814 100644 --- a/skia-safe/src/utils.rs +++ b/skia-safe/src/utils.rs @@ -1,15 +1,12 @@ mod camera; -pub use camera::*; - mod custom_typeface; -pub use custom_typeface::*; - -pub mod interpolator; -pub use interpolator::Interpolator; - mod null_canvas; -pub use null_canvas::*; - +mod ordered_font_mgr; pub mod parse_path; pub mod shadow_utils; pub mod text_utils; + +pub use camera::*; +pub use custom_typeface::*; +pub use null_canvas::*; +pub use ordered_font_mgr::*; diff --git a/skia-safe/src/utils/interpolator.rs b/skia-safe/src/utils/interpolator.rs deleted file mode 100644 index 935612482..000000000 --- a/skia-safe/src/utils/interpolator.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! This wrapper combines SkInterpolatorBase and SkInterpolator into the type Interpolator. - -use crate::{prelude::*, scalar, Point}; -use skia_bindings::{self as sb, SkInterpolator, SkUnitCubicInterp}; -use std::{fmt, time::Duration}; - -pub use skia_bindings::SkInterpolatorBase_Result as Result; -#[test] -fn test_interpolator_result_naming() { - let _ = Result::FreezeEnd_Result; -} - -pub type Interpolator = Handle; -unsafe impl Send for Interpolator {} -unsafe impl Sync for Interpolator {} - -impl NativeDrop for SkInterpolator { - fn drop(&mut self) { - unsafe { - sb::C_SkInterpolator_destruct(self); - } - } -} - -impl Default for Interpolator { - fn default() -> Self { - Handle::from_native_c(unsafe { SkInterpolator::new() }) - } -} - -impl fmt::Debug for Interpolator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Interpolator") - .field("duration", &self.duration()) - .field("elem_count", &self.elem_count()) - .finish() - } -} - -/// Wrapper for functions that are implemented in SkInterpolatorBase -impl Interpolator { - pub fn duration(&self) -> Option<(Duration, Duration)> { - let mut start_time = 0; - let mut end_time = 0; - unsafe { - self.native() - ._base - .getDuration(&mut start_time, &mut end_time) - } - .if_true_then_some(|| { - ( - Duration::from_millis(start_time.try_into().unwrap()), - Duration::from_millis(end_time.try_into().unwrap()), - ) - }) - } - - pub fn set_mirror(&mut self, mirror: bool) -> &mut Self { - unsafe { sb::C_SkInterpolator_setMirror(self.native_mut(), mirror) } - self - } - - pub fn set_repeat_count(&mut self, repeat_count: scalar) -> &mut Self { - unsafe { sb::C_SkInterpolator_setRepeatCount(self.native_mut(), repeat_count) } - self - } - - pub fn set_reset(&mut self, reset: bool) -> &mut Self { - unsafe { sb::C_SkInterpolator_setReset(self.native_mut(), reset) } - self - } - - pub fn time_to_t(&self, time: Duration) -> (Result, TimeToT) { - let mut t = 0.0; - let mut index = 0; - let mut exact = false; - let r = unsafe { - self.native()._base.timeToT( - time.as_millis().try_into().unwrap(), - &mut t, - &mut index, - &mut exact, - ) - }; - ( - r, - TimeToT { - t, - index: index.try_into().unwrap(), - exact, - }, - ) - } -} - -/// Wrapper for SkInterpolator functions. -impl Interpolator { - pub fn new(elem_count: usize, frame_count: usize) -> Self { - Handle::from_native_c(unsafe { - SkInterpolator::new1( - elem_count.try_into().unwrap(), - frame_count.try_into().unwrap(), - ) - }) - } - - pub fn reset(&mut self, elem_count: usize, frame_count: usize) -> &mut Self { - unsafe { - self.native_mut().reset( - elem_count.try_into().unwrap(), - frame_count.try_into().unwrap(), - ) - } - self - } - - pub fn set_key_frame<'a>( - &mut self, - index: usize, - time: Duration, - values: &[scalar], - blend: impl Into>, - ) -> bool { - assert_eq!(values.len(), self.elem_count()); - unsafe { - self.native_mut().setKeyFrame( - index.try_into().unwrap(), - time.as_millis().try_into().unwrap(), - values.as_ptr(), - blend.into().as_ptr_or_null() as _, - ) - } - } - - // TODO: may provide a variant that returns a Vec. - pub fn time_to_values<'a>( - &self, - time: Duration, - values: impl Into>, - ) -> Result { - let mut values = values.into(); - if let Some(ref values) = values { - assert_eq!(values.len(), self.elem_count()); - }; - unsafe { - self.native().timeToValues( - time.as_millis().try_into().unwrap(), - values.as_ptr_or_null_mut(), - ) - } - } -} - -/// Additional functions that seem useful. -impl Interpolator { - pub fn elem_count(&self) -> usize { - self.native()._base.fElemCount.try_into().unwrap() - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct TimeToT { - pub t: scalar, - pub index: usize, - pub exact: bool, -} - -pub fn unit_cubic_interp(value: scalar, b: impl Into, c: impl Into) -> scalar { - let b = b.into(); - let c = c.into(); - unsafe { SkUnitCubicInterp(value, b.x, b.y, c.x, c.y) } -} diff --git a/skia-safe/src/utils/ordered_font_mgr.rs b/skia-safe/src/utils/ordered_font_mgr.rs new file mode 100644 index 000000000..774587ac7 --- /dev/null +++ b/skia-safe/src/utils/ordered_font_mgr.rs @@ -0,0 +1,75 @@ +use crate::{prelude::*, FontMgr}; +use skia_bindings::{self as sb, SkOrderedFontMgr, SkRefCntBase}; +use std::{ + fmt, + mem::transmute, + ops::{Deref, DerefMut}, +}; + +pub type OrderedFontMgr = RCHandle; + +impl NativeRefCountedBase for SkOrderedFontMgr { + type Base = SkRefCntBase; +} + +impl Deref for OrderedFontMgr { + type Target = FontMgr; + fn deref(&self) -> &Self::Target { + unsafe { transmute_ref(self) } + } +} + +impl DerefMut for OrderedFontMgr { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { transmute_ref_mut(self) } + } +} + +impl Default for OrderedFontMgr { + fn default() -> Self { + Self::new() + } +} + +impl From for FontMgr { + fn from(font_mgr: OrderedFontMgr) -> Self { + unsafe { transmute(font_mgr) } + } +} + +impl fmt::Debug for OrderedFontMgr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OrderedFontMgr") + .field("base", self as &FontMgr) + .finish() + } +} + +impl OrderedFontMgr { + pub fn new() -> Self { + Self::from_ptr(unsafe { sb::C_SkOrderedFontMgr_new() }).unwrap() + } + + pub fn append(&mut self, font_mgr: impl Into) { + let font_mgr = font_mgr.into(); + unsafe { sb::C_SkOrderedFontMgr_append(self.native_mut(), font_mgr.into_ptr()) } + } +} + +#[cfg(test)] +mod tests { + use super::OrderedFontMgr; + + #[test] + fn can_use_font_mgr_functions() { + let ordered = OrderedFontMgr::default(); + let _families = ordered.count_families(); + } + + #[test] + fn can_pass_ordered_font_mgr_where_a_font_mgr_is_expected() { + let mut ordered = OrderedFontMgr::default(); + let another = OrderedFontMgr::default(); + ordered.append(another); + } +} diff --git a/skia-safe/src/utils/parse_path.rs b/skia-safe/src/utils/parse_path.rs index 884f8882a..c725258f0 100644 --- a/skia-safe/src/utils/parse_path.rs +++ b/skia-safe/src/utils/parse_path.rs @@ -12,12 +12,7 @@ pub fn from_svg(svg: impl AsRef) -> Option { unsafe { sb::SkParsePath_FromSVGString(str.as_ptr(), path.native_mut()) }.if_true_some(path) } -pub fn to_svg(path: &Path) -> String { - let mut svg = interop::String::default(); - unsafe { sb::SkParsePath_ToSVGString(path.native(), svg.native_mut()) }; - - svg.as_str().into() -} +pub use skia_bindings::SkParsePath_PathEncoding as PathEncoding; impl Path { pub fn from_svg(svg: impl AsRef) -> Option { @@ -27,4 +22,28 @@ impl Path { pub fn to_svg(&self) -> String { to_svg(self) } + + pub fn to_svg_with_encoding(&self, encoding: PathEncoding) -> String { + to_svg_with_encoding(self, encoding) + } +} + +pub fn to_svg(path: &Path) -> String { + to_svg_with_encoding(path, PathEncoding::Absolute) +} + +pub fn to_svg_with_encoding(path: &Path, encoding: PathEncoding) -> String { + let mut svg = interop::String::default(); + unsafe { sb::SkParsePath_ToSVGString(path.native(), svg.native_mut(), encoding) }; + svg.as_str().into() +} + +#[cfg(test)] +mod tests { + use super::PathEncoding; + + #[test] + fn test_path_encoding_naming() { + let _ = PathEncoding::Absolute; + } } diff --git a/skia-safe/tests/send_sync.rs b/skia-safe/tests/send_sync.rs index 0e62fe0da..8277d986c 100644 --- a/skia-safe/tests/send_sync.rs +++ b/skia-safe/tests/send_sync.rs @@ -103,7 +103,7 @@ mod core { assert_impl_all!(typeface::LocalizedString: Send, Sync); assert_impl_all!(Typeface: Send, Sync); assert_not_impl_any!(typeface::LocalizedStringsIter: Send, Sync); - assert_not_impl_any!(vertices::Attribute: Send, Sync); + // assert_not_impl_any!(vertices::Attribute: Send, Sync); assert_impl_all!(Vertices: Send, Sync); assert_impl_all!(vertices::Builder: Send, Sync); // core/sampling_options.rs @@ -140,7 +140,7 @@ mod effects { use static_assertions::*; assert_impl_all!(runtime_effect::Uniform: Send, Sync); - assert_impl_all!(runtime_effect::Varying: Send, Sync); + // assert_impl_all!(runtime_effect::Varying: Send, Sync); assert_not_impl_any!(RuntimeEffect: Send, Sync); assert_impl_all!(runtime_effect::Options: Send, Sync); assert_impl_all!(image_filters::CropRect: Send, Sync); @@ -271,12 +271,12 @@ mod svg { } mod utils { - use skia_safe::utils::interpolator::TimeToT; + // use skia_safe::utils::interpolator::TimeToT; use skia_safe::utils::*; use static_assertions::*; assert_impl_all!(CustomTypefaceBuilder: Send, Sync); - assert_impl_all!(Interpolator: Send, Sync); - assert_impl_all!(TimeToT: Send, Sync); + // assert_impl_all!(Interpolator: Send, Sync); + // assert_impl_all!(TimeToT: Send, Sync); } pub mod assert {