blob: 590a68971c517e9d591f8bfe6e6c8997b04623d0 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/toolkit/interop/impeller.h"
#include <algorithm>
#include <iterator>
#include <sstream>
#include "flutter/fml/mapping.h"
#include "impeller/base/validation.h"
#include "impeller/geometry/scalar.h"
#include "impeller/renderer/backend/gles/context_gles.h"
#include "impeller/renderer/backend/gles/texture_gles.h"
#include "impeller/renderer/context.h"
#include "impeller/toolkit/interop/color_filter.h"
#include "impeller/toolkit/interop/color_source.h"
#include "impeller/toolkit/interop/context.h"
#include "impeller/toolkit/interop/dl_builder.h"
#include "impeller/toolkit/interop/formats.h"
#include "impeller/toolkit/interop/fragment_program.h"
#include "impeller/toolkit/interop/glyph_info.h"
#include "impeller/toolkit/interop/image_filter.h"
#include "impeller/toolkit/interop/line_metrics.h"
#include "impeller/toolkit/interop/mask_filter.h"
#include "impeller/toolkit/interop/object.h"
#include "impeller/toolkit/interop/paint.h"
#include "impeller/toolkit/interop/paragraph.h"
#include "impeller/toolkit/interop/paragraph_builder.h"
#include "impeller/toolkit/interop/paragraph_style.h"
#include "impeller/toolkit/interop/path.h"
#include "impeller/toolkit/interop/path_builder.h"
#include "impeller/toolkit/interop/surface.h"
#include "impeller/toolkit/interop/texture.h"
#include "impeller/toolkit/interop/typography_context.h"
#if IMPELLER_ENABLE_OPENGLES
#include "impeller/toolkit/interop/backend/gles/context_gles.h"
#include "impeller/toolkit/interop/backend/gles/surface_gles.h"
#endif // IMPELLER_ENABLE_OPENGLES
#if IMPELLER_ENABLE_METAL
#include "impeller/toolkit/interop/backend/metal/context_mtl.h"
#include "impeller/toolkit/interop/backend/metal/surface_mtl.h"
#endif // IMPELLER_ENABLE_METAL
#if IMPELLER_ENABLE_VULKAN
#include "impeller/toolkit/interop/backend/vulkan/context_vk.h"
#include "impeller/toolkit/interop/backend/vulkan/surface_vk.h"
#include "impeller/toolkit/interop/backend/vulkan/swapchain_vk.h"
#endif // IMPELLER_ENABLE_VULKAN
namespace impeller::interop {
#define DEFINE_PEER_GETTER(cxx_type, c_type) \
cxx_type* GetPeer(c_type object) { \
return reinterpret_cast<cxx_type*>(object); \
}
DEFINE_PEER_GETTER(ColorFilter, ImpellerColorFilter);
DEFINE_PEER_GETTER(ColorSource, ImpellerColorSource);
DEFINE_PEER_GETTER(Context, ImpellerContext);
DEFINE_PEER_GETTER(DisplayList, ImpellerDisplayList);
DEFINE_PEER_GETTER(DisplayListBuilder, ImpellerDisplayListBuilder);
DEFINE_PEER_GETTER(FragmentProgram, ImpellerFragmentProgram);
DEFINE_PEER_GETTER(GlyphInfo, ImpellerGlyphInfo);
DEFINE_PEER_GETTER(ImageFilter, ImpellerImageFilter);
DEFINE_PEER_GETTER(LineMetrics, ImpellerLineMetrics);
DEFINE_PEER_GETTER(MaskFilter, ImpellerMaskFilter);
DEFINE_PEER_GETTER(Paint, ImpellerPaint);
DEFINE_PEER_GETTER(Paragraph, ImpellerParagraph);
DEFINE_PEER_GETTER(ParagraphBuilder, ImpellerParagraphBuilder);
DEFINE_PEER_GETTER(ParagraphStyle, ImpellerParagraphStyle);
DEFINE_PEER_GETTER(Path, ImpellerPath);
DEFINE_PEER_GETTER(PathBuilder, ImpellerPathBuilder);
DEFINE_PEER_GETTER(Surface, ImpellerSurface);
DEFINE_PEER_GETTER(SwapchainVK, ImpellerVulkanSwapchain);
DEFINE_PEER_GETTER(Texture, ImpellerTexture);
DEFINE_PEER_GETTER(TypographyContext, ImpellerTypographyContext);
static std::string GetVersionAsString(uint32_t version) {
std::stringstream stream;
stream << IMPELLER_VERSION_GET_VARIANT(version) << "."
<< IMPELLER_VERSION_GET_MAJOR(version) << "."
<< IMPELLER_VERSION_GET_MINOR(version) << "."
<< IMPELLER_VERSION_GET_PATCH(version);
return stream.str();
}
IMPELLER_EXTERN_C
uint32_t ImpellerGetVersion() {
return IMPELLER_VERSION;
}
static bool CheckVersion(uint32_t version) {
if (version != IMPELLER_VERSION) {
VALIDATION_LOG << "This version of Impeller ("
<< GetVersionAsString(ImpellerGetVersion()) << ") "
<< "doesn't match the version the user expects ("
<< GetVersionAsString(version) << ").";
return false;
}
return true;
}
IMPELLER_EXTERN_C
ImpellerContext ImpellerContextCreateOpenGLESNew(
uint32_t version,
ImpellerProcAddressCallback gl_proc_address_callback,
void* gl_proc_address_callback_user_data) {
if (!CheckVersion(version)) {
return nullptr;
}
#if IMPELLER_ENABLE_OPENGLES
auto context = ContextGLES::Create(
[gl_proc_address_callback,
gl_proc_address_callback_user_data](const char* proc_name) -> void* {
return gl_proc_address_callback(proc_name,
gl_proc_address_callback_user_data);
});
if (!context || !context->IsValid()) {
VALIDATION_LOG << "Could not create valid context.";
return nullptr;
}
return context.Leak();
#else // IMPELLER_ENABLE_OPENGLES
VALIDATION_LOG << "OpenGLES not available.";
return nullptr;
#endif // IMPELLER_ENABLE_OPENGLES
}
IMPELLER_EXTERN_C ImpellerContext
ImpellerContextCreateMetalNew(uint32_t version) {
if (!CheckVersion(version)) {
return nullptr;
}
#if IMPELLER_ENABLE_METAL
auto context = ContextMTL::Create();
if (!context || !context->IsValid()) {
VALIDATION_LOG << "Could not create valid context.";
return nullptr;
}
return context.Leak();
#else // IMPELLER_ENABLE_METAL
VALIDATION_LOG << "Metal not available.";
return nullptr;
#endif // IMPELLER_ENABLE_METAL
}
IMPELLER_EXTERN_C ImpellerContext
ImpellerContextCreateVulkanNew(uint32_t version,
const ImpellerContextVulkanSettings* settings) {
if (!CheckVersion(version)) {
return nullptr;
}
#if IMPELLER_ENABLE_VULKAN
auto context = ContextVK::Create(ContextVK::Settings(*settings));
if (!context || !context->IsValid()) {
VALIDATION_LOG << "Could not create valid context.";
return nullptr;
}
return context.Leak();
#else // IMPELLER_ENABLE_VULKAN
VALIDATION_LOG << "Vulkan not available.";
return nullptr;
#endif // IMPELLER_ENABLE_VULKAN
}
IMPELLER_EXTERN_C
void ImpellerContextRetain(ImpellerContext context) {
ObjectBase::SafeRetain(context);
}
IMPELLER_EXTERN_C
void ImpellerContextRelease(ImpellerContext context) {
ObjectBase::SafeRelease(context);
}
IMPELLER_EXTERN_C
bool ImpellerContextGetVulkanInfo(ImpellerContext IMPELLER_NONNULL context,
ImpellerContextVulkanInfo* out_vulkan_info) {
#if IMPELLER_ENABLE_VULKAN
if (!GetPeer(context)->IsVulkan()) {
VALIDATION_LOG << "Not a Vulkan context.";
return false;
}
return reinterpret_cast<ContextVK*>(GetPeer(context))
->GetInfo(*out_vulkan_info);
#else // IMPELLER_ENABLE_VULKAN
VALIDATION_LOG << "Vulkan not available.";
return nullptr;
#endif // IMPELLER_ENABLE_VULKAN
}
IMPELLER_EXTERN_C
ImpellerVulkanSwapchain ImpellerVulkanSwapchainCreateNew(
ImpellerContext context,
void* vulkan_surface_khr) {
#if IMPELLER_ENABLE_VULKAN
return Create<SwapchainVK>(
*GetPeer(context), //
reinterpret_cast<VkSurfaceKHR>(vulkan_surface_khr) //
)
.Leak();
#else // IMPELLER_ENABLE_VULKAN
VALIDATION_LOG << "Vulkan not available.";
return nullptr;
#endif // IMPELLER_ENABLE_VULKAN
}
IMPELLER_EXTERN_C
void ImpellerVulkanSwapchainRetain(ImpellerVulkanSwapchain swapchain) {
ObjectBase::SafeRetain(swapchain);
}
IMPELLER_EXTERN_C
void ImpellerVulkanSwapchainRelease(ImpellerVulkanSwapchain swapchain) {
ObjectBase::SafeRelease(swapchain);
}
IMPELLER_EXTERN_C
ImpellerSurface ImpellerVulkanSwapchainAcquireNextSurfaceNew(
ImpellerVulkanSwapchain swapchain) {
return GetPeer(swapchain)->AcquireNextSurface().Leak();
}
IMPELLER_EXTERN_C ImpellerDisplayListBuilder
ImpellerDisplayListBuilderNew(const ImpellerRect* cull_rect) {
return Create<DisplayListBuilder>(cull_rect).Leak();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderRetain(ImpellerDisplayListBuilder builder) {
ObjectBase::SafeRetain(builder);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderRelease(ImpellerDisplayListBuilder builder) {
ObjectBase::SafeRelease(builder);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderSave(ImpellerDisplayListBuilder builder) {
GetPeer(builder)->Save();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderSaveLayer(ImpellerDisplayListBuilder builder,
const ImpellerRect* bounds,
ImpellerPaint paint,
ImpellerImageFilter backdrop) {
GetPeer(builder)->SaveLayer(ToImpellerType(*bounds), //
GetPeer(paint), //
GetPeer(backdrop) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderRestore(ImpellerDisplayListBuilder builder) {
GetPeer(builder)->Restore();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderScale(ImpellerDisplayListBuilder builder,
float x_scale,
float y_scale) {
GetPeer(builder)->Scale(Size{x_scale, y_scale});
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderRotate(ImpellerDisplayListBuilder builder,
float angle_degrees) {
GetPeer(builder)->Rotate(Degrees{angle_degrees});
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderTranslate(ImpellerDisplayListBuilder builder,
float x_translation,
float y_translation) {
GetPeer(builder)->Translate(Point{x_translation, y_translation});
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderSetTransform(ImpellerDisplayListBuilder builder,
const ImpellerMatrix* transform) {
GetPeer(builder)->SetTransform(ToImpellerType(*transform));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderTransform(ImpellerDisplayListBuilder builder,
const ImpellerMatrix* transform) {
GetPeer(builder)->Transform(ToImpellerType(*transform));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderGetTransform(ImpellerDisplayListBuilder builder,
ImpellerMatrix* out_transform) {
FromImpellerType(GetPeer(builder)->GetTransform(), *out_transform);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderResetTransform(
ImpellerDisplayListBuilder builder) {
GetPeer(builder)->ResetTransform();
}
IMPELLER_EXTERN_C
uint32_t ImpellerDisplayListBuilderGetSaveCount(
ImpellerDisplayListBuilder builder) {
return GetPeer(builder)->GetSaveCount();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderRestoreToCount(
ImpellerDisplayListBuilder builder,
uint32_t count) {
GetPeer(builder)->RestoreToCount(count);
}
IMPELLER_EXTERN_C
void ImpellerPathRetain(ImpellerPath path) {
ObjectBase::SafeRetain(path);
}
IMPELLER_EXTERN_C
void ImpellerPathRelease(ImpellerPath path) {
ObjectBase::SafeRelease(path);
}
IMPELLER_EXTERN_C
void ImpellerPathGetBounds(ImpellerPath path, ImpellerRect* out_bounds) {
*out_bounds = GetPeer(path)->GetBounds();
}
IMPELLER_EXTERN_C
ImpellerPathBuilder ImpellerPathBuilderNew() {
return Create<PathBuilder>().Leak();
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderRetain(ImpellerPathBuilder builder) {
ObjectBase::SafeRetain(builder);
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderRelease(ImpellerPathBuilder builder) {
ObjectBase::SafeRelease(builder);
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderMoveTo(ImpellerPathBuilder builder,
const ImpellerPoint* location) {
GetPeer(builder)->MoveTo(ToImpellerType(*location));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderLineTo(ImpellerPathBuilder builder,
const ImpellerPoint* location) {
GetPeer(builder)->LineTo(ToImpellerType(*location));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderQuadraticCurveTo(ImpellerPathBuilder builder,
const ImpellerPoint* control_point,
const ImpellerPoint* end_point) {
GetPeer(builder)->QuadraticCurveTo(ToImpellerType(*control_point),
ToImpellerType(*end_point));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderCubicCurveTo(ImpellerPathBuilder builder,
const ImpellerPoint* control_point_1,
const ImpellerPoint* control_point_2,
const ImpellerPoint* end_point) {
GetPeer(builder)->CubicCurveTo(ToImpellerType(*control_point_1), //
ToImpellerType(*control_point_2), //
ToImpellerType(*end_point) //
);
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderAddRect(ImpellerPathBuilder builder,
const ImpellerRect* rect) {
GetPeer(builder)->AddRect(ToImpellerType(*rect));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderAddArc(ImpellerPathBuilder builder,
const ImpellerRect* oval_bounds,
float start_angle_degrees,
float end_angle_degrees) {
GetPeer(builder)->AddArc(ToImpellerType(*oval_bounds), //
Degrees{start_angle_degrees}, //
Degrees{end_angle_degrees} //
);
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderAddOval(ImpellerPathBuilder builder,
const ImpellerRect* oval_bounds) {
GetPeer(builder)->AddOval(ToImpellerType(*oval_bounds));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderAddRoundedRect(
ImpellerPathBuilder builder,
const ImpellerRect* rect,
const ImpellerRoundingRadii* rounding_radii) {
GetPeer(builder)->AddRoundedRect(ToImpellerType(*rect),
ToImpellerType(*rounding_radii));
}
IMPELLER_EXTERN_C
void ImpellerPathBuilderClose(ImpellerPathBuilder builder) {
GetPeer(builder)->Close();
}
IMPELLER_EXTERN_C
ImpellerPath ImpellerPathBuilderCopyPathNew(ImpellerPathBuilder builder,
ImpellerFillType fill) {
return GetPeer(builder)->CopyPath(ToImpellerType(fill)).Leak();
}
IMPELLER_EXTERN_C
ImpellerPath ImpellerPathBuilderTakePathNew(ImpellerPathBuilder builder,
ImpellerFillType fill) {
return GetPeer(builder)->TakePath(ToImpellerType(fill)).Leak();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderClipRect(ImpellerDisplayListBuilder builder,
const ImpellerRect* rect,
ImpellerClipOperation op) {
GetPeer(builder)->ClipRect(ToImpellerType(*rect), ToImpellerType(op));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderClipOval(ImpellerDisplayListBuilder builder,
const ImpellerRect* oval_bounds,
ImpellerClipOperation op) {
GetPeer(builder)->ClipOval(ToImpellerType(*oval_bounds), ToImpellerType(op));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderClipRoundedRect(
ImpellerDisplayListBuilder builder,
const ImpellerRect* rect,
const ImpellerRoundingRadii* radii,
ImpellerClipOperation op) {
GetPeer(builder)->ClipRoundedRect(ToImpellerType(*rect), //
ToImpellerType(*radii), //
ToImpellerType(op) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderClipPath(ImpellerDisplayListBuilder builder,
ImpellerPath path,
ImpellerClipOperation op) {
GetPeer(builder)->ClipPath(*GetPeer(path), ToImpellerType(op));
}
IMPELLER_EXTERN_C
ImpellerPaint ImpellerPaintNew() {
return Create<Paint>().Leak();
}
IMPELLER_EXTERN_C
void ImpellerPaintRetain(ImpellerPaint paint) {
ObjectBase::SafeRetain(paint);
}
IMPELLER_EXTERN_C
void ImpellerPaintRelease(ImpellerPaint paint) {
ObjectBase::SafeRelease(paint);
}
IMPELLER_EXTERN_C
void ImpellerPaintSetColor(ImpellerPaint paint, const ImpellerColor* color) {
GetPeer(paint)->SetColor(ToDisplayListType(*color));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetBlendMode(ImpellerPaint paint, ImpellerBlendMode mode) {
GetPeer(paint)->SetBlendMode(ToImpellerType(mode));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetDrawStyle(ImpellerPaint paint, ImpellerDrawStyle style) {
GetPeer(paint)->SetDrawStyle(ToDisplayListType(style));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetStrokeCap(ImpellerPaint paint, ImpellerStrokeCap cap) {
GetPeer(paint)->SetStrokeCap(ToDisplayListType(cap));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetStrokeJoin(ImpellerPaint paint, ImpellerStrokeJoin join) {
GetPeer(paint)->SetStrokeJoin(ToDisplayListType(join));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetStrokeWidth(ImpellerPaint paint, float width) {
GetPeer(paint)->SetStrokeWidth(width);
}
IMPELLER_EXTERN_C
void ImpellerPaintSetStrokeMiter(ImpellerPaint paint, float miter) {
GetPeer(paint)->SetStrokeMiter(miter);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawPaint(ImpellerDisplayListBuilder builder,
ImpellerPaint paint) {
GetPeer(builder)->DrawPaint(*GetPeer(paint));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawLine(ImpellerDisplayListBuilder builder,
const ImpellerPoint* from,
const ImpellerPoint* to,
ImpellerPaint paint) {
GetPeer(builder)->DrawLine(ToImpellerType(*from), //
ToImpellerType(*to), //
*GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawDashedLine(
ImpellerDisplayListBuilder builder,
const ImpellerPoint* from,
const ImpellerPoint* to,
float on_length,
float off_length,
ImpellerPaint paint) {
GetPeer(builder)->DrawDashedLine(ToImpellerType(*from), //
ToImpellerType(*to), //
on_length, //
off_length, //
*GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawRect(ImpellerDisplayListBuilder builder,
const ImpellerRect* rect,
ImpellerPaint paint) {
GetPeer(builder)->DrawRect(ToImpellerType(*rect), *GetPeer(paint));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawOval(ImpellerDisplayListBuilder builder,
const ImpellerRect* oval_bounds,
ImpellerPaint paint) {
GetPeer(builder)->DrawOval(ToImpellerType(*oval_bounds), *GetPeer(paint));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawRoundedRect(
ImpellerDisplayListBuilder builder,
const ImpellerRect* rect,
const ImpellerRoundingRadii* radii,
ImpellerPaint paint) {
GetPeer(builder)->DrawRoundedRect(ToImpellerType(*rect), //
ToImpellerType(*radii), //
*GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawRoundedRectDifference(
ImpellerDisplayListBuilder builder,
const ImpellerRect* outer_rect,
const ImpellerRoundingRadii* outer_radii,
const ImpellerRect* inner_rect,
const ImpellerRoundingRadii* inner_radii,
ImpellerPaint paint) {
GetPeer(builder)->DrawRoundedRectDifference(ToImpellerType(*outer_rect), //
ToImpellerType(*outer_radii), //
ToImpellerType(*inner_rect), //
ToImpellerType(*inner_radii), //
*GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawPath(ImpellerDisplayListBuilder builder,
ImpellerPath path,
ImpellerPaint paint) {
GetPeer(builder)->DrawPath(*GetPeer(path), *GetPeer(paint));
}
IMPELLER_EXTERN_C
ImpellerTexture ImpellerTextureCreateWithContentsNew(
ImpellerContext context,
const ImpellerTextureDescriptor* descriptor,
const ImpellerMapping* contents,
void* contents_on_release_user_data) {
TextureDescriptor desc;
desc.storage_mode = StorageMode::kHostVisible;
desc.type = TextureType::kTexture2D;
desc.format = ToImpellerType(descriptor->pixel_format);
desc.size = ToImpellerType(descriptor->size);
desc.mip_count = std::min(descriptor->mip_count, 1u);
desc.usage = TextureUsage::kShaderRead;
desc.compression_type = CompressionType::kLossless;
auto texture = Create<Texture>(*GetPeer(context), desc);
if (!texture->IsValid()) {
VALIDATION_LOG << "Could not create texture.";
return nullptr;
}
// Depending on whether the de-allocation can be delayed, it may be possible
// to avoid a data copy.
if (contents->on_release) {
// Avoids data copy.
auto wrapped_contents = std::make_shared<fml::NonOwnedMapping>(
contents->data, // data ptr
contents->length, // data length
[on_release = contents->on_release, contents_on_release_user_data](
auto, auto) {
on_release(contents_on_release_user_data);
} // release callback
);
if (!texture->SetContents(std::move(wrapped_contents))) {
VALIDATION_LOG << "Could not set texture contents.";
return nullptr;
}
} else {
// May copy.
if (!texture->SetContents(contents->data, contents->length)) {
VALIDATION_LOG << "Could not set texture contents.";
return nullptr;
}
}
return texture.Leak();
}
IMPELLER_EXTERN_C
ImpellerTexture ImpellerTextureCreateWithOpenGLTextureHandleNew(
ImpellerContext context,
const ImpellerTextureDescriptor* descriptor,
uint64_t external_gl_handle) {
auto impeller_context = GetPeer(context)->GetContext();
if (impeller_context->GetBackendType() !=
impeller::Context::BackendType::kOpenGLES) {
VALIDATION_LOG << "Context is not OpenGL.";
return nullptr;
}
const auto& impeller_context_gl =
impeller::ContextGLES::Cast(*impeller_context);
const auto& reactor = impeller_context_gl.GetReactor();
TextureDescriptor desc;
desc.storage_mode = StorageMode::kDevicePrivate;
desc.type = TextureType::kTexture2D;
desc.format = ToImpellerType(descriptor->pixel_format);
desc.size = ToImpellerType(descriptor->size);
desc.mip_count = std::min(descriptor->mip_count, 1u);
desc.usage = TextureUsage::kShaderRead;
desc.compression_type = CompressionType::kLossless;
auto texture = TextureGLES::WrapTexture(
reactor, //
desc, //
reactor->CreateHandle(HandleType::kTexture, external_gl_handle) //
);
if (!texture || !texture->IsValid()) {
VALIDATION_LOG << "Could not wrap external texture.";
return nullptr;
}
texture->SetCoordinateSystem(TextureCoordinateSystem::kUploadFromHost);
return Create<Texture>(impeller::Context::BackendType::kOpenGLES,
std::move(texture))
.Leak();
}
IMPELLER_EXTERN_C
void ImpellerTextureRetain(ImpellerTexture texture) {
ObjectBase::SafeRetain(texture);
}
IMPELLER_EXTERN_C
void ImpellerTextureRelease(ImpellerTexture texture) {
ObjectBase::SafeRelease(texture);
}
IMPELLER_EXTERN_C
uint64_t ImpellerTextureGetOpenGLHandle(ImpellerTexture texture) {
auto interop_texture = GetPeer(texture);
if (interop_texture->GetBackendType() !=
impeller::Context::BackendType::kOpenGLES) {
VALIDATION_LOG << "Can only fetch the texture handle of an OpenGL texture.";
return 0u;
}
return TextureGLES::Cast(*interop_texture->GetTexture())
.GetGLHandle()
.value_or(0u);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListRetain(ImpellerDisplayList display_list) {
ObjectBase::SafeRetain(display_list);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListRelease(ImpellerDisplayList display_list) {
ObjectBase::SafeRelease(display_list);
}
IMPELLER_EXTERN_C
ImpellerDisplayList ImpellerDisplayListBuilderCreateDisplayListNew(
ImpellerDisplayListBuilder builder) {
auto dl = GetPeer(builder)->Build();
if (!dl->IsValid()) {
return nullptr;
}
return dl.Leak();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawDisplayList(
ImpellerDisplayListBuilder builder,
ImpellerDisplayList display_list,
float opacity) {
GetPeer(builder)->DrawDisplayList(*GetPeer(display_list), opacity);
}
IMPELLER_EXTERN_C
ImpellerSurface ImpellerSurfaceCreateWrappedFBONew(ImpellerContext context,
uint64_t fbo,
ImpellerPixelFormat format,
const ImpellerISize* size) {
#if IMPELLER_ENABLE_OPENGLES
if (!GetPeer(context)->IsGL()) {
VALIDATION_LOG << "Context is not OpenGL.";
return nullptr;
}
return Create<SurfaceGLES>(*GetPeer(context), //
fbo, //
ToImpellerType(format), //
ToImpellerType(*size)) //
.Leak();
#else // IMPELLER_ENABLE_OPENGLES
VALIDATION_LOG << "OpenGL unavailable.";
return nullptr;
#endif // IMPELLER_ENABLE_OPENGLES
}
IMPELLER_EXTERN_C
ImpellerSurface ImpellerSurfaceCreateWrappedMetalDrawableNew(
ImpellerContext context,
void* metal_drawable) {
#if IMPELLER_ENABLE_METAL
if (!GetPeer(context)->IsMetal()) {
VALIDATION_LOG << "Context is not Metal.";
return nullptr;
}
return Create<SurfaceMTL>(*GetPeer(context), metal_drawable).Leak();
#else // IMPELLER_ENABLE_METAL
VALIDATION_LOG << "Metal unavailable.";
return nullptr;
#endif // IMPELLER_ENABLE_METAL
}
IMPELLER_EXTERN_C void ImpellerSurfaceRetain(ImpellerSurface surface) {
ObjectBase::SafeRetain(surface);
}
IMPELLER_EXTERN_C
void ImpellerSurfaceRelease(ImpellerSurface surface) {
ObjectBase::SafeRelease(surface);
}
IMPELLER_EXTERN_C
bool ImpellerSurfaceDrawDisplayList(ImpellerSurface surface,
ImpellerDisplayList display_list) {
return GetPeer(surface)->DrawDisplayList(*GetPeer(display_list));
}
IMPELLER_EXTERN_C
bool ImpellerSurfacePresent(ImpellerSurface surface) {
return GetPeer(surface)->Present();
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawTexture(ImpellerDisplayListBuilder builder,
ImpellerTexture texture,
const ImpellerPoint* point,
ImpellerTextureSampling sampling,
ImpellerPaint paint) {
GetPeer(builder)->DrawTexture(*GetPeer(texture), //
ToImpellerType(*point), //
ToDisplayListType(sampling), //
GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawTextureRect(
ImpellerDisplayListBuilder builder,
ImpellerTexture texture,
const ImpellerRect* src_rect,
const ImpellerRect* dst_rect,
ImpellerTextureSampling sampling,
ImpellerPaint paint) {
GetPeer(builder)->DrawTextureRect(*GetPeer(texture), //
ToImpellerType(*src_rect), //
ToImpellerType(*dst_rect), //
ToDisplayListType(sampling), //
GetPeer(paint) //
);
}
IMPELLER_EXTERN_C
void ImpellerColorSourceRetain(ImpellerColorSource color_source) {
ObjectBase::SafeRetain(color_source);
}
IMPELLER_EXTERN_C
void ImpellerColorSourceRelease(ImpellerColorSource color_source) {
ObjectBase::SafeRelease(color_source);
}
static std::pair<std::vector<flutter::DlColor>, std::vector<Scalar>>
ParseColorsAndStops(uint32_t stop_count,
const ImpellerColor* colors,
const float* stops) {
if (stop_count == 0) {
return {};
}
std::pair<std::vector<flutter::DlColor>, std::vector<Scalar>> result;
result.first.reserve(stop_count);
result.second.reserve(stop_count);
for (size_t i = 0; i < stop_count; i++) {
result.first.emplace_back(ToDisplayListType(colors[i]));
result.second.emplace_back(stops[i]);
}
return result;
}
IMPELLER_EXTERN_C
ImpellerColorSource ImpellerColorSourceCreateLinearGradientNew(
const ImpellerPoint* start_point,
const ImpellerPoint* end_point,
uint32_t stop_count,
const ImpellerColor* colors,
const float* stops,
ImpellerTileMode tile_mode,
const ImpellerMatrix* transformation) {
const auto colors_and_stops = ParseColorsAndStops(stop_count, colors, stops);
return ColorSource::MakeLinearGradient(
ToImpellerType(*start_point), //
ToImpellerType(*end_point), //
colors_and_stops.first, //
colors_and_stops.second, //
ToDisplayListType(tile_mode), //
transformation == nullptr ? Matrix{}
: ToImpellerType(*transformation) //
)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerColorSource ImpellerColorSourceCreateRadialGradientNew(
const ImpellerPoint* center,
float radius,
uint32_t stop_count,
const ImpellerColor* colors,
const float* stops,
ImpellerTileMode tile_mode,
const ImpellerMatrix* transformation) {
const auto colors_and_stops = ParseColorsAndStops(stop_count, colors, stops);
return ColorSource::MakeRadialGradient(
ToImpellerType(*center), //
radius, //
colors_and_stops.first, //
colors_and_stops.second, //
ToDisplayListType(tile_mode), //
transformation == nullptr ? Matrix{}
: ToImpellerType(*transformation) //
)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerColorSource ImpellerColorSourceCreateConicalGradientNew(
const ImpellerPoint* start_center,
float start_radius,
const ImpellerPoint* end_center,
float end_radius,
uint32_t stop_count,
const ImpellerColor* colors,
const float* stops,
ImpellerTileMode tile_mode,
const ImpellerMatrix* transformation) {
const auto colors_and_stops = ParseColorsAndStops(stop_count, colors, stops);
return ColorSource::MakeConicalGradient(
ToImpellerType(*start_center), //
start_radius, //
ToImpellerType(*end_center), //
end_radius, //
colors_and_stops.first, //
colors_and_stops.second, //
ToDisplayListType(tile_mode), //
transformation == nullptr ? Matrix{}
: ToImpellerType(*transformation) //
)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerColorSource ImpellerColorSourceCreateSweepGradientNew(
const ImpellerPoint* center,
float start,
float end,
uint32_t stop_count,
const ImpellerColor* colors,
const float* stops,
ImpellerTileMode tile_mode,
const ImpellerMatrix* transformation) {
const auto colors_and_stops = ParseColorsAndStops(stop_count, colors, stops);
return ColorSource::MakeSweepGradient(
ToImpellerType(*center), //
start, //
end, //
colors_and_stops.first, //
colors_and_stops.second, //
ToDisplayListType(tile_mode), //
transformation == nullptr ? Matrix{}
: ToImpellerType(*transformation) //
)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerColorSource ImpellerColorSourceCreateImageNew(
ImpellerTexture image,
ImpellerTileMode horizontal_tile_mode,
ImpellerTileMode vertical_tile_mode,
ImpellerTextureSampling sampling,
const ImpellerMatrix* transformation) {
return ColorSource::MakeImage(
*GetPeer(image), //
ToDisplayListType(horizontal_tile_mode), //
ToDisplayListType(vertical_tile_mode), //
ToDisplayListType(sampling), //
transformation == nullptr ? Matrix{}
: ToImpellerType(*transformation) //
)
.Leak();
}
struct SamplersAndUniforms {
std::vector<std::shared_ptr<flutter::DlColorSource>> samplers;
std::shared_ptr<std::vector<uint8_t>> uniforms;
};
static SamplersAndUniforms ReadSamplersAndUniforms(ImpellerTexture* samplers,
size_t samplers_count,
const uint8_t* data,
size_t data_bytes_length) {
SamplersAndUniforms result;
result.uniforms = std::make_shared<std::vector<uint8_t>>();
if (data_bytes_length > 0) {
std::copy(data, data + data_bytes_length,
std::back_inserter(*result.uniforms));
}
if (samplers_count > 0) {
result.samplers.reserve(samplers_count);
for (size_t i = 0; i < samplers_count; i++) {
result.samplers.emplace_back(flutter::DlColorSource::MakeImage(
DlImageImpeller::Make(GetPeer(samplers[i])->GetTexture()), //
flutter::DlTileMode::kClamp, //
flutter::DlTileMode::kClamp //
));
}
}
return result;
}
IMPELLER_EXTERN_C ImpellerColorSource
ImpellerColorSourceCreateFragmentProgramNew(
ImpellerContext context,
ImpellerFragmentProgram fragment_program,
ImpellerTexture* samplers,
size_t samplers_count,
const uint8_t* data,
size_t data_bytes_length) {
auto bindings = ReadSamplersAndUniforms(samplers, samplers_count, data,
data_bytes_length);
return ColorSource::MakeFragmentProgram(*GetPeer(context), //
*GetPeer(fragment_program), //
std::move(bindings.samplers), //
std::move(bindings.uniforms) //
)
.Leak();
}
IMPELLER_EXTERN_C
void ImpellerColorFilterRetain(ImpellerColorFilter color_filter) {
ObjectBase::SafeRetain(color_filter);
}
IMPELLER_EXTERN_C
void ImpellerColorFilterRelease(ImpellerColorFilter color_filter) {
ObjectBase::SafeRelease(color_filter);
}
IMPELLER_EXTERN_C
ImpellerColorFilter ImpellerColorFilterCreateBlendNew(
const ImpellerColor* color,
ImpellerBlendMode blend_mode) {
return ColorFilter::MakeBlend(ToImpellerType(*color),
ToImpellerType(blend_mode))
.Leak();
}
IMPELLER_EXTERN_C
ImpellerColorFilter ImpellerColorFilterCreateColorMatrixNew(
const ImpellerColorMatrix* color_matrix) {
return ColorFilter::MakeMatrix(color_matrix->m).Leak();
}
IMPELLER_EXTERN_C
void ImpellerMaskFilterRetain(ImpellerMaskFilter mask_filter) {
ObjectBase::SafeRetain(mask_filter);
}
IMPELLER_EXTERN_C
void ImpellerMaskFilterRelease(ImpellerMaskFilter mask_filter) {
ObjectBase::SafeRelease(mask_filter);
}
IMPELLER_EXTERN_C
ImpellerMaskFilter ImpellerMaskFilterCreateBlurNew(ImpellerBlurStyle style,
float sigma) {
return MaskFilter::MakeBlur(ToDisplayListType(style), sigma).Leak();
}
IMPELLER_EXTERN_C
void ImpellerImageFilterRetain(ImpellerImageFilter image_filter) {
ObjectBase::SafeRetain(image_filter);
}
IMPELLER_EXTERN_C
void ImpellerImageFilterRelease(ImpellerImageFilter image_filter) {
ObjectBase::SafeRelease(image_filter);
}
IMPELLER_EXTERN_C
ImpellerImageFilter ImpellerImageFilterCreateBlurNew(
float x_sigma,
float y_sigma,
ImpellerTileMode tile_mode) {
return ImageFilter::MakeBlur(x_sigma, y_sigma, ToDisplayListType(tile_mode))
.Leak();
}
IMPELLER_EXTERN_C
ImpellerImageFilter ImpellerImageFilterCreateDilateNew(float x_radius,
float y_radius) {
return ImageFilter::MakeDilate(x_radius, y_radius).Leak();
}
IMPELLER_EXTERN_C
ImpellerImageFilter ImpellerImageFilterCreateErodeNew(float x_radius,
float y_radius) {
return ImageFilter::MakeErode(x_radius, y_radius).Leak();
}
IMPELLER_EXTERN_C
ImpellerImageFilter ImpellerImageFilterCreateMatrixNew(
const ImpellerMatrix* matrix,
ImpellerTextureSampling sampling) {
return ImageFilter::MakeMatrix(ToImpellerType(*matrix),
ToDisplayListType(sampling))
.Leak();
}
IMPELLER_EXTERN_C
ImpellerImageFilter ImpellerImageFilterCreateFragmentProgramNew(
ImpellerContext context,
ImpellerFragmentProgram fragment_program,
ImpellerTexture* samplers,
size_t samplers_count,
const uint8_t* data,
size_t data_bytes_length) {
auto bindings = ReadSamplersAndUniforms(samplers, samplers_count, data,
data_bytes_length);
return ImageFilter::MakeFragmentProgram(*GetPeer(context), //
*GetPeer(fragment_program), //
std::move(bindings.samplers), //
std::move(bindings.uniforms) //
)
.Leak();
}
IMPELLER_EXTERN_C ImpellerImageFilter
ImpellerImageFilterCreateComposeNew(ImpellerImageFilter outer,
ImpellerImageFilter inner) {
return ImageFilter::MakeCompose(*GetPeer(outer), *GetPeer(inner)).Leak();
}
IMPELLER_EXTERN_C
void ImpellerPaintSetColorFilter(ImpellerPaint paint,
ImpellerColorFilter color_filter) {
GetPeer(paint)->SetColorFilter(*GetPeer(color_filter));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetColorSource(ImpellerPaint paint,
ImpellerColorSource color_source) {
GetPeer(paint)->SetColorSource(*GetPeer(color_source));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetImageFilter(ImpellerPaint paint,
ImpellerImageFilter image_filter) {
GetPeer(paint)->SetImageFilter(*GetPeer(image_filter));
}
IMPELLER_EXTERN_C
void ImpellerPaintSetMaskFilter(ImpellerPaint paint,
ImpellerMaskFilter mask_filter) {
GetPeer(paint)->SetMaskFilter(*GetPeer(mask_filter));
}
IMPELLER_EXTERN_C
ImpellerParagraphStyle ImpellerParagraphStyleNew() {
return Create<ParagraphStyle>().Leak();
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleRetain(ImpellerParagraphStyle paragraph_style) {
ObjectBase::SafeRetain(paragraph_style);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleRelease(ImpellerParagraphStyle paragraph_style) {
ObjectBase::SafeRelease(paragraph_style);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetForeground(ImpellerParagraphStyle paragraph_style,
ImpellerPaint paint) {
GetPeer(paragraph_style)->SetForeground(Ref(GetPeer(paint)));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetBackground(ImpellerParagraphStyle paragraph_style,
ImpellerPaint paint) {
GetPeer(paragraph_style)->SetBackground(Ref(GetPeer(paint)));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetFontWeight(ImpellerParagraphStyle paragraph_style,
ImpellerFontWeight weight) {
GetPeer(paragraph_style)->SetFontWeight(ToTxtType(weight));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetFontStyle(ImpellerParagraphStyle paragraph_style,
ImpellerFontStyle style) {
GetPeer(paragraph_style)->SetFontStyle(ToTxtType(style));
}
static std::string ReadString(const char* string) {
if (string == nullptr) {
return "";
}
return std::string{string};
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetFontFamily(ImpellerParagraphStyle paragraph_style,
const char* family_name) {
GetPeer(paragraph_style)->SetFontFamily(ReadString(family_name));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetFontSize(ImpellerParagraphStyle paragraph_style,
float size) {
GetPeer(paragraph_style)->SetFontSize(size);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetHeight(ImpellerParagraphStyle paragraph_style,
float height) {
GetPeer(paragraph_style)->SetHeight(height);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetTextAlignment(
ImpellerParagraphStyle paragraph_style,
ImpellerTextAlignment align) {
GetPeer(paragraph_style)->SetTextAlignment(ToTxtType(align));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetTextDirection(
ImpellerParagraphStyle paragraph_style,
ImpellerTextDirection direction) {
GetPeer(paragraph_style)->SetTextDirection(ToTxtType(direction));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetTextDecoration(
ImpellerParagraphStyle paragraph_style,
const ImpellerTextDecoration* decoration) {
GetPeer(paragraph_style)->SetTextDecoration(*decoration);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetMaxLines(ImpellerParagraphStyle paragraph_style,
uint32_t max_lines) {
GetPeer(paragraph_style)->SetMaxLines(max_lines);
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetLocale(ImpellerParagraphStyle paragraph_style,
const char* locale) {
GetPeer(paragraph_style)->SetLocale(ReadString(locale));
}
IMPELLER_EXTERN_C
void ImpellerParagraphStyleSetEllipsis(ImpellerParagraphStyle paragraph_style,
const char* ellipsis) {
GetPeer(paragraph_style)->SetEllipsis(ReadString(ellipsis));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawParagraph(ImpellerDisplayListBuilder builder,
ImpellerParagraph paragraph,
const ImpellerPoint* point) {
GetPeer(builder)->DrawParagraph(*GetPeer(paragraph), ToImpellerType(*point));
}
IMPELLER_EXTERN_C
void ImpellerDisplayListBuilderDrawShadow(ImpellerDisplayListBuilder builder,
ImpellerPath path,
const ImpellerColor* color,
float elevation,
bool occluder_is_transparent,
float device_pixel_ratio) {
GetPeer(builder)->DrawShadow(*GetPeer(path), //
ToDisplayListType(*color), //
elevation, //
occluder_is_transparent, //
device_pixel_ratio //
);
}
IMPELLER_EXTERN_C
ImpellerParagraphBuilder ImpellerParagraphBuilderNew(
ImpellerTypographyContext context) {
auto builder =
Create<ParagraphBuilder>(Ref<TypographyContext>(GetPeer(context)));
if (!builder->IsValid()) {
VALIDATION_LOG << "Could not create valid paragraph builder.";
return nullptr;
}
return builder.Leak();
}
IMPELLER_EXTERN_C
void ImpellerParagraphBuilderRetain(
ImpellerParagraphBuilder paragraph_builder) {
ObjectBase::SafeRetain(paragraph_builder);
}
IMPELLER_EXTERN_C
void ImpellerParagraphBuilderRelease(
ImpellerParagraphBuilder paragraph_builder) {
ObjectBase::SafeRelease(paragraph_builder);
}
IMPELLER_EXTERN_C
void ImpellerParagraphBuilderPushStyle(
ImpellerParagraphBuilder paragraph_builder,
ImpellerParagraphStyle style) {
GetPeer(paragraph_builder)->PushStyle(*GetPeer(style));
}
IMPELLER_EXTERN_C
void ImpellerParagraphBuilderPopStyle(
ImpellerParagraphBuilder paragraph_builder) {
GetPeer(paragraph_builder)->PopStyle();
}
IMPELLER_EXTERN_C
void ImpellerParagraphBuilderAddText(ImpellerParagraphBuilder paragraph_builder,
const uint8_t* data,
uint32_t length) {
if (data == nullptr) {
length = 0;
}
if (length == 0) {
return;
}
GetPeer(paragraph_builder)->AddText(data, length);
}
IMPELLER_EXTERN_C
ImpellerParagraph ImpellerParagraphBuilderBuildParagraphNew(
ImpellerParagraphBuilder paragraph_builder,
float width) {
return GetPeer(paragraph_builder)->Build(width).Leak();
}
IMPELLER_EXTERN_C
void ImpellerParagraphRetain(ImpellerParagraph paragraph) {
ObjectBase::SafeRetain(paragraph);
}
IMPELLER_EXTERN_C
void ImpellerParagraphRelease(ImpellerParagraph paragraph) {
ObjectBase::SafeRelease(paragraph);
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetMaxWidth(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetMaxWidth();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetHeight(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetHeight();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetLongestLineWidth(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetLongestLineWidth();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetMinIntrinsicWidth(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetMinIntrinsicWidth();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetMaxIntrinsicWidth(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetMaxIntrinsicWidth();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetIdeographicBaseline(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetIdeographicBaseline();
}
IMPELLER_EXTERN_C
float ImpellerParagraphGetAlphabeticBaseline(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetAlphabeticBaseline();
}
IMPELLER_EXTERN_C
uint32_t ImpellerParagraphGetLineCount(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetLineCount();
}
IMPELLER_EXTERN_C
void ImpellerParagraphGetWordBoundary(ImpellerParagraph paragraph,
size_t code_unit_index,
ImpellerRange* out_range) {
*out_range = GetPeer(paragraph)->GetWordBoundary(code_unit_index);
}
IMPELLER_EXTERN_C
ImpellerTypographyContext ImpellerTypographyContextNew() {
auto context = Create<TypographyContext>();
if (!context->IsValid()) {
VALIDATION_LOG << "Could not create typography context.";
return nullptr;
}
return context.Leak();
}
IMPELLER_EXTERN_C
void ImpellerTypographyContextRetain(ImpellerTypographyContext context) {
ObjectBase::SafeRetain(context);
}
IMPELLER_EXTERN_C
void ImpellerTypographyContextRelease(ImpellerTypographyContext context) {
ObjectBase::SafeRelease(context);
}
IMPELLER_EXTERN_C
bool ImpellerTypographyContextRegisterFont(ImpellerTypographyContext context,
const ImpellerMapping* contents,
void* contents_on_release_user_data,
const char* family_name_alias) {
auto wrapped_contents = std::make_unique<fml::NonOwnedMapping>(
contents->data, // data ptr
contents->length, // data length
[on_release = contents->on_release, contents_on_release_user_data](auto,
auto) {
on_release(contents_on_release_user_data);
} // release callback
);
return GetPeer(context)->RegisterFont(std::move(wrapped_contents),
family_name_alias);
}
IMPELLER_EXTERN_C
ImpellerLineMetrics ImpellerParagraphGetLineMetrics(
ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetLineMetrics().GetC();
}
IMPELLER_EXTERN_C
ImpellerGlyphInfo ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew(
ImpellerParagraph paragraph,
size_t code_unit_index) {
return GetPeer(paragraph)
->GetGlyphInfoAtCodeUnitIndex(code_unit_index)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerGlyphInfo ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew(
ImpellerParagraph paragraph,
double x,
double y) {
return GetPeer(paragraph)
->GetClosestGlyphInfoAtParagraphCoordinates(x, y)
.Leak();
}
//------------------------------------------------------------------------------
// Line Metrics
//------------------------------------------------------------------------------
IMPELLER_EXTERN_C
void ImpellerLineMetricsRetain(ImpellerLineMetrics line_metrics) {
ObjectBase::SafeRetain(line_metrics);
}
IMPELLER_EXTERN_C
void ImpellerLineMetricsRelease(ImpellerLineMetrics line_metrics) {
ObjectBase::SafeRelease(line_metrics);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetUnscaledAscent(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetUnscaledAscent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetAscent(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetAscent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetDescent(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetDescent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetBaseline(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetBaseline(line);
}
IMPELLER_EXTERN_C
bool ImpellerLineMetricsIsHardbreak(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->IsHardbreak(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetWidth(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetWidth(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetHeight(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetHeight(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetLeft(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetLeft(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitStartIndex(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitStartIndex(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndex(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndex(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace(
ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndexExcludingWhitespace(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline(
ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndexIncludingNewline(line);
}
//------------------------------------------------------------------------------
// Glyph Info
//------------------------------------------------------------------------------
IMPELLER_EXTERN_C
void ImpellerGlyphInfoRetain(ImpellerGlyphInfo glyph_info) {
ObjectBase::SafeRetain(glyph_info);
}
IMPELLER_EXTERN_C
void ImpellerGlyphInfoRelease(ImpellerGlyphInfo glyph_info) {
ObjectBase::SafeRelease(glyph_info);
}
IMPELLER_EXTERN_C
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetGraphemeClusterCodeUnitRangeBegin();
}
IMPELLER_EXTERN_C
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetGraphemeClusterCodeUnitRangeEnd();
}
IMPELLER_EXTERN_C
void ImpellerGlyphInfoGetGraphemeClusterBounds(ImpellerGlyphInfo glyph_info,
ImpellerRect* out_bounds) {
*out_bounds = GetPeer(glyph_info)->GetGraphemeClusterBounds();
}
IMPELLER_EXTERN_C
bool ImpellerGlyphInfoIsEllipsis(ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->IsEllipsis();
}
IMPELLER_EXTERN_C
ImpellerTextDirection ImpellerGlyphInfoGetTextDirection(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetTextDirection();
}
//------------------------------------------------------------------------------
// Fragment Program
//------------------------------------------------------------------------------
static std::shared_ptr<fml::Mapping> MakeCopyableMapping(
const ImpellerMapping* data,
void* user_data) {
if (data == nullptr) {
return nullptr;
}
// If the user has supplied a release callback, defer deallocation to them.
if (auto callback = data->on_release) {
return std::make_shared<fml::NonOwnedMapping>(
data->data, //
data->length, //
[user_data, callback](const uint8_t* data, size_t size) {
callback(user_data);
});
}
return std::make_shared<fml::MallocMapping>(
fml::MallocMapping::Copy(data->data, data->length));
}
IMPELLER_EXTERN_C
ImpellerFragmentProgram ImpellerFragmentProgramNew(
const ImpellerMapping* data,
void* data_release_user_data) {
auto data_mapping = MakeCopyableMapping(data, data_release_user_data);
auto program = Create<FragmentProgram>(std::move(data_mapping));
if (!program->IsValid()) {
VALIDATION_LOG << "Could not create valid fragment program.";
return nullptr;
}
return program.Leak();
}
IMPELLER_EXTERN_C
void ImpellerFragmentProgramRetain(ImpellerFragmentProgram fragment_program) {
ObjectBase::SafeRetain(fragment_program);
}
IMPELLER_EXTERN_C
void ImpellerFragmentProgramRelease(ImpellerFragmentProgram fragment_program) {
ObjectBase::SafeRelease(fragment_program);
}
} // namespace impeller::interop