react-native-vroom-chart 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/android/CMakeLists.txt +31 -42
- package/android/README.md +23 -21
- package/android/build.gradle +26 -8
- package/cpp/VroomChartHostObject.cpp +14 -10
- package/cpp/VroomFontMgr.cpp +25 -0
- package/cpp/VroomFontMgr.h +14 -0
- package/cpp/VroomJsiInstaller.cpp +31 -12
- package/cpp/_core_src/chart_internal.h +2 -2
- package/cpp/_core_src/fonts.h +3 -3
- package/package.json +6 -5
- package/react-native-vroom-chart.podspec +11 -5
- package/cpp/VroomSkiaContext.cpp +0 -33
- package/cpp/VroomSkiaContext.h +0 -30
package/README.md
CHANGED
|
@@ -16,8 +16,11 @@ import { VroomChart } from 'react-native-vroom-chart';
|
|
|
16
16
|
## Peer dependencies
|
|
17
17
|
|
|
18
18
|
- `react-native` ≥ 0.76
|
|
19
|
-
- `@shopify/react-native-skia` ≥
|
|
19
|
+
- `@shopify/react-native-skia` ≥ 2.11.0 — provides the Skia runtime we draw into. vroom links RN-Skia's native internals (`cpp/api`) and tracks that package closely; those headers have no semver guarantee.
|
|
20
|
+
|
|
20
21
|
- `react-native-gesture-handler` ≥ 2.16 — long-press / pan / pinch recognition
|
|
22
|
+
- `react-native-reanimated` ≥ 4.0 — gesture worklets
|
|
23
|
+
- `react-native-worklets` ≥ 0.7.0 — required by Skia 2.11's Reanimated integration on native
|
|
21
24
|
|
|
22
25
|
## Status
|
|
23
26
|
|
package/android/CMakeLists.txt
CHANGED
|
@@ -4,20 +4,21 @@
|
|
|
4
4
|
# core the iOS podspec compiles (see ../react-native-vroom-chart.podspec),
|
|
5
5
|
# plus this directory's small JNI entry point (src/main/cpp/VroomChartJni.cpp).
|
|
6
6
|
#
|
|
7
|
-
# RN-Skia's headers (
|
|
8
|
-
#
|
|
9
|
-
# instead we point directly at @shopify/react-native-skia's `cpp/`
|
|
10
|
-
# mirroring the podspec's
|
|
11
|
-
#
|
|
7
|
+
# RN-Skia's headers (JsiSkNativeObjects.h, JsiSkPicture.h, and the
|
|
8
|
+
# RNSkPlatformContext.h they pull in) aren't consumed via CMake's prefab
|
|
9
|
+
# mechanism; instead we point directly at @shopify/react-native-skia's `cpp/`
|
|
10
|
+
# sources, mirroring the podspec's
|
|
11
|
+
# `require.resolve('@shopify/react-native-skia/package.json')` trick
|
|
12
|
+
# (VROOM_SKIA_CPP_DIR is computed the same way in build.gradle).
|
|
12
13
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
14
|
+
# Prebuilt libskia.a lives in the sibling npm package react-native-skia-android
|
|
15
|
+
# (or react-native-skia-graphite-android). build.gradle resolves that package
|
|
16
|
+
# and passes VROOM_SKIA_ANDROID_LIBS_DIR = <pkg>/libs; we append ${ANDROID_ABI}.
|
|
17
|
+
#
|
|
18
|
+
# SK_GRAPHITE vs SK_GL/SK_GANESH must match RN-Skia's own build so our direct
|
|
19
|
+
# Skia calls see the same ABI. Graphite is detected from the
|
|
20
|
+
# <skia-pkg>/libs/.graphite marker (same file RN-Skia uses) and passed in as
|
|
21
|
+
# VROOM_SKIA_GRAPHITE.
|
|
21
22
|
cmake_minimum_required(VERSION 3.22)
|
|
22
23
|
project(vroomchart)
|
|
23
24
|
|
|
@@ -35,44 +36,30 @@ find_package(shopify_react-native-skia REQUIRED CONFIG)
|
|
|
35
36
|
if(NOT DEFINED VROOM_SKIA_CPP_DIR)
|
|
36
37
|
message(FATAL_ERROR "VROOM_SKIA_CPP_DIR not set — passed from android/build.gradle.")
|
|
37
38
|
endif()
|
|
39
|
+
if(NOT DEFINED VROOM_SKIA_ANDROID_LIBS_DIR)
|
|
40
|
+
message(FATAL_ERROR "VROOM_SKIA_ANDROID_LIBS_DIR not set — passed from android/build.gradle.")
|
|
41
|
+
endif()
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
# Skia static libs live at <root>/libs/android/<abi>/libskia.a.
|
|
41
|
-
get_filename_component(VROOM_SKIA_PKG_DIR "${VROOM_SKIA_CPP_DIR}" DIRECTORY)
|
|
42
|
-
set(VROOM_SKIA_LIBS_DIR "${VROOM_SKIA_PKG_DIR}/libs/android/${ANDROID_ABI}")
|
|
43
|
+
set(VROOM_SKIA_LIBS_DIR "${VROOM_SKIA_ANDROID_LIBS_DIR}/${ANDROID_ABI}")
|
|
43
44
|
|
|
44
45
|
# Our chart core calls Skia types (SkCanvas, SkPaint, SkFont, ...) and
|
|
45
|
-
# RN-Skia's own JSI plumbing (
|
|
46
|
+
# RN-Skia's own JSI plumbing (JsiSkPicture / NativeObject, ...)
|
|
46
47
|
# directly — none of that is header-only, and we need *both* libraries:
|
|
47
48
|
# - librnskia.so (RN-Skia's prefab-published `rnskia` module, consumed above
|
|
48
|
-
# via `implementation project(":shopify_react-native-skia")`) for
|
|
49
|
-
# own symbols (
|
|
50
|
-
# - libskia.a (
|
|
51
|
-
# calls (SkCanvas::drawRect, SkFont, ...): librnskia.so
|
|
52
|
-
# internally but doesn't re-export its symbols, so linking
|
|
53
|
-
# alone leaves every direct Skia call undefined.
|
|
49
|
+
# via `implementation project(":shopify_react-native-skia")`) for RN-Skia's
|
|
50
|
+
# own symbols (JsiSkPicture, NativeObject, ...), which only exist there.
|
|
51
|
+
# - libskia.a (the prebuilt Skia static lib from react-native-skia-android)
|
|
52
|
+
# for direct Skia calls (SkCanvas::drawRect, SkFont, ...): librnskia.so
|
|
53
|
+
# links libskia.a internally but doesn't re-export its symbols, so linking
|
|
54
|
+
# librnskia.so alone leaves every direct Skia call undefined.
|
|
54
55
|
# Recompiling RN-Skia's cpp/jsi/*.cpp ourselves instead of linking librnskia.so
|
|
55
|
-
# was considered and rejected — it would duplicate
|
|
56
|
+
# was considered and rejected — it would duplicate RN-Skia's symbols (and their
|
|
56
57
|
# static/global state) across two separately-loaded .so's, which is fine on
|
|
57
58
|
# iOS's single static binary but not here.
|
|
58
59
|
add_library(vroom_skia_prebuilt STATIC IMPORTED)
|
|
59
60
|
set_property(TARGET vroom_skia_prebuilt PROPERTY
|
|
60
61
|
IMPORTED_LOCATION "${VROOM_SKIA_LIBS_DIR}/libskia.a")
|
|
61
62
|
|
|
62
|
-
set(SK_GRAPHITE_AVAILABLE OFF)
|
|
63
|
-
if(EXISTS "${VROOM_SKIA_LIBS_DIR}/libskia.a")
|
|
64
|
-
execute_process(
|
|
65
|
-
COMMAND nm "${VROOM_SKIA_LIBS_DIR}/libskia.a"
|
|
66
|
-
COMMAND grep "dawn::\\|wgpu\\|_ZN4dawn\\|DawnDevice\\|dawn_native"
|
|
67
|
-
OUTPUT_VARIABLE VROOM_NM_OUTPUT
|
|
68
|
-
ERROR_QUIET
|
|
69
|
-
RESULT_VARIABLE VROOM_NM_RESULT
|
|
70
|
-
)
|
|
71
|
-
if(VROOM_NM_RESULT EQUAL 0 AND NOT "${VROOM_NM_OUTPUT}" STREQUAL "")
|
|
72
|
-
set(SK_GRAPHITE_AVAILABLE ON)
|
|
73
|
-
endif()
|
|
74
|
-
endif()
|
|
75
|
-
|
|
76
63
|
# The chart core (shared across iOS/Android/WASM — see ../../core/CMakeLists.txt).
|
|
77
64
|
set(VROOM_CORE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../cpp/_core_include")
|
|
78
65
|
set(VROOM_CORE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../cpp/_core_src")
|
|
@@ -81,7 +68,7 @@ file(GLOB VROOM_CORE_SOURCES CONFIGURE_DEPENDS "${VROOM_CORE_SRC_DIR}/*.cpp")
|
|
|
81
68
|
add_library(vroomchart SHARED
|
|
82
69
|
"${CMAKE_CURRENT_SOURCE_DIR}/../cpp/VroomJsiInstaller.cpp"
|
|
83
70
|
"${CMAKE_CURRENT_SOURCE_DIR}/../cpp/VroomChartHostObject.cpp"
|
|
84
|
-
"${CMAKE_CURRENT_SOURCE_DIR}/../cpp/
|
|
71
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/../cpp/VroomFontMgr.cpp"
|
|
85
72
|
${VROOM_CORE_SOURCES}
|
|
86
73
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/VroomChartJni.cpp"
|
|
87
74
|
)
|
|
@@ -101,7 +88,9 @@ target_include_directories(vroomchart PRIVATE
|
|
|
101
88
|
"${VROOM_SKIA_CPP_DIR}/dawn/include"
|
|
102
89
|
# RNSkPlatformContext.h pulls in ReactCommon/CallInvoker.h directly, which
|
|
103
90
|
# isn't part of the prefab-published jsi headers — same dirs RN-Skia's own
|
|
104
|
-
# android/CMakeLists.txt adds for the same reason.
|
|
91
|
+
# android/CMakeLists.txt adds for the same reason. Still required: we include
|
|
92
|
+
# JsiSkPicture.h, which includes JsiSkNativeObjects.h, which includes
|
|
93
|
+
# RNSkPlatformContext.h.
|
|
105
94
|
"${REACT_NATIVE_DIR}/ReactCommon"
|
|
106
95
|
"${REACT_NATIVE_DIR}/ReactCommon/callinvoker"
|
|
107
96
|
"${REACT_NATIVE_DIR}/ReactCommon/runtimeexecutor"
|
|
@@ -114,7 +103,7 @@ target_compile_definitions(vroomchart PRIVATE
|
|
|
114
103
|
ONANDROID
|
|
115
104
|
ON_ANDROID
|
|
116
105
|
)
|
|
117
|
-
if(
|
|
106
|
+
if(VROOM_SKIA_GRAPHITE)
|
|
118
107
|
target_compile_definitions(vroomchart PRIVATE SK_GRAPHITE)
|
|
119
108
|
else()
|
|
120
109
|
target_compile_definitions(vroomchart PRIVATE SK_GL SK_GANESH)
|
package/android/README.md
CHANGED
|
@@ -8,31 +8,33 @@ Android equivalent of `../ios/`: a small TurboModule
|
|
|
8
8
|
[`../cpp/VroomJsiInstaller.cpp`](../cpp/VroomJsiInstaller.cpp) the iOS bridge
|
|
9
9
|
uses.
|
|
10
10
|
|
|
11
|
-
The chart core
|
|
12
|
-
(`../cpp/
|
|
13
|
-
|
|
11
|
+
The chart core (`../cpp/_core_src`) and the platform font-manager helper
|
|
12
|
+
(`../cpp/VroomFontMgr.*`) are unmodified and shared across iOS and Android —
|
|
13
|
+
only the platform glue (this directory + `../ios/`) differs.
|
|
14
14
|
`../cpp/VroomChartHostObject.cpp` has one small `#if defined(__ANDROID__)`
|
|
15
15
|
branch (see "Cross-`.so` Skia objects" below).
|
|
16
16
|
|
|
17
17
|
`build.gradle` resolves `@shopify/react-native-skia`'s `cpp/` sources via
|
|
18
18
|
Node module resolution (mirroring `../react-native-vroom-chart.podspec`'s
|
|
19
|
-
`require.resolve` trick) so
|
|
20
|
-
`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
`require.resolve` trick) so we can include RN-Skia's `JsiSkPicture.h` /
|
|
20
|
+
`JsiSkNativeObjects.h`. Android prebuilt `libskia.a` lives in the sibling
|
|
21
|
+
`react-native-skia-android` package (or `react-native-skia-graphite-android`
|
|
22
|
+
when `<skia-pkg>/libs/.graphite` exists); Gradle resolves that package and
|
|
23
|
+
passes its `libs/` dir to CMake. Graphite vs Ganesh is the same marker file
|
|
24
|
+
RN-Skia uses, so `SK_GRAPHITE` / `SK_GL`+`SK_GANESH` match RN-Skia's own
|
|
25
|
+
build — needed for vroom's direct Skia calls, not for a virtual call into
|
|
26
|
+
RN-Skia (we construct the font manager ourselves).
|
|
26
27
|
|
|
27
28
|
We link two RN-Skia-adjacent libraries into `libvroomchart.so`, for two
|
|
28
29
|
different reasons:
|
|
29
30
|
- `shopify_react-native-skia::rnskia` (RN-Skia's own prefab-published
|
|
30
|
-
shared library, `librnskia.so`) — for `
|
|
31
|
-
whose out-of-line methods are compiled only there.
|
|
32
|
-
-
|
|
33
|
-
prefab-published) — for direct Skia calls
|
|
34
|
-
|
|
35
|
-
re-export its
|
|
31
|
+
shared library, `librnskia.so`) — for `JsiSkPicture` / `NativeObject`
|
|
32
|
+
and friends, whose out-of-line methods are compiled only there.
|
|
33
|
+
- `libskia.a` from `react-native-skia-android` (imported directly by path,
|
|
34
|
+
since it isn't prefab-published) — for direct Skia calls
|
|
35
|
+
(`SkCanvas::drawRect`, `SkFont`, `SkFontMgr_New_Android`, ...), since
|
|
36
|
+
`librnskia.so` links `libskia.a` internally but doesn't re-export its
|
|
37
|
+
symbols.
|
|
36
38
|
|
|
37
39
|
### Cross-`.so` Skia objects
|
|
38
40
|
|
|
@@ -43,11 +45,11 @@ of the JSI bridge, but **`RNSkia::JsiSkPicture` — the object `render()` /
|
|
|
43
45
|
`libvroomchart.so` on Android.** RN-Skia's own C++ (e.g.
|
|
44
46
|
`cpp/api/recorder/Convertor.h`'s `getPropertyValue<sk_sp<SkPicture>>`, which
|
|
45
47
|
runs whenever `<Picture>` reads the value) does
|
|
46
|
-
`
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
different, unmerged RTTI record for "the same" class and fails with
|
|
50
|
-
|
|
48
|
+
`getJsiObject<JsiSkPicture>(rt, value)`, a `dynamic_pointer_cast` under the
|
|
49
|
+
hood. A `JsiSkPicture` we construct ourselves has a vtable/typeinfo compiled
|
|
50
|
+
into *our* `.so`; that cast — running inside `librnskia.so` — sees a
|
|
51
|
+
different, unmerged RTTI record for "the same" class and fails with
|
|
52
|
+
`Expected a Skia object of a different type`.
|
|
51
53
|
|
|
52
54
|
`VroomChartHostObject.cpp`'s `wrapPicture()` works around this only on
|
|
53
55
|
Android: instead of constructing `RNSkia::JsiSkPicture` directly (as iOS
|
package/android/build.gradle
CHANGED
|
@@ -28,7 +28,23 @@ def resolvePackageDir(packageJsonSpecifier) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
def reactNativeDir = resolvePackageDir("react-native/package.json")
|
|
31
|
-
def
|
|
31
|
+
def skiaPkgDir = resolvePackageDir("@shopify/react-native-skia/package.json")
|
|
32
|
+
def skiaCppDir = new File(skiaPkgDir, "cpp")
|
|
33
|
+
|
|
34
|
+
// Skia 2.10+ ships Android prebuilts in react-native-skia-android (Ganesh)
|
|
35
|
+
// or react-native-skia-graphite-android (Graphite). Graphite is selected by
|
|
36
|
+
// the same libs/.graphite marker RN-Skia uses. Resolve from the skia package
|
|
37
|
+
// so pnpm's nested .pnpm layout still finds the sibling binary package.
|
|
38
|
+
def useGraphite = new File(skiaPkgDir, "libs/.graphite").exists()
|
|
39
|
+
def skiaAndroidPkgName = useGraphite
|
|
40
|
+
? "react-native-skia-graphite-android"
|
|
41
|
+
: "react-native-skia-android"
|
|
42
|
+
def skiaAndroidPkgJson = providers.exec {
|
|
43
|
+
workingDir(rootDir)
|
|
44
|
+
commandLine("node", "--print",
|
|
45
|
+
"require.resolve('${skiaAndroidPkgName}/package.json', { paths: ['${skiaPkgDir}'] })")
|
|
46
|
+
}.standardOutput.asText.get().trim()
|
|
47
|
+
def skiaAndroidLibsDir = new File(file(skiaAndroidPkgJson).parentFile, "libs")
|
|
32
48
|
|
|
33
49
|
// Mirror ../cpp/_core_{src,include} from ../../core/{src,include} whenever
|
|
34
50
|
// the monorepo core is present, so edits to packages/core/ propagate on the
|
|
@@ -72,7 +88,9 @@ android {
|
|
|
72
88
|
abiFilters(*reactNativeArchitectures())
|
|
73
89
|
arguments "-DANDROID_STL=c++_shared",
|
|
74
90
|
"-DREACT_NATIVE_DIR=${reactNativeDir}",
|
|
75
|
-
"-DVROOM_SKIA_CPP_DIR=${skiaCppDir}"
|
|
91
|
+
"-DVROOM_SKIA_CPP_DIR=${skiaCppDir}",
|
|
92
|
+
"-DVROOM_SKIA_ANDROID_LIBS_DIR=${skiaAndroidLibsDir}",
|
|
93
|
+
"-DVROOM_SKIA_GRAPHITE=${useGraphite ? 'ON' : 'OFF'}"
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
96
|
}
|
|
@@ -105,11 +123,11 @@ repositories {
|
|
|
105
123
|
|
|
106
124
|
dependencies {
|
|
107
125
|
implementation "com.facebook.react:react-android"
|
|
108
|
-
// ../cpp/VroomChartHostObject.cpp constructs RN-Skia JSI
|
|
109
|
-
// (JsiSkPicture, etc.) whose base
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
126
|
+
// ../cpp/VroomChartHostObject.cpp constructs RN-Skia JSI objects
|
|
127
|
+
// (JsiSkPicture, etc.) whose NativeObject base has out-of-line methods
|
|
128
|
+
// compiled into RN-Skia's own native library — we link against its
|
|
129
|
+
// prefab-published `rnskia` package (below, in CMakeLists.txt) rather than
|
|
130
|
+
// recompiling those .cpp files ourselves, to avoid duplicate definitions of
|
|
131
|
+
// RN-Skia's internals across two separately-loaded .so's.
|
|
114
132
|
implementation project(":shopify_react-native-skia")
|
|
115
133
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
#include "vroom/vroom_chart.h"
|
|
9
9
|
|
|
10
10
|
// RN-Skia headers.
|
|
11
|
-
#include "
|
|
11
|
+
#include "JsiSkNativeObjects.h"
|
|
12
12
|
#include "JsiSkPicture.h"
|
|
13
13
|
|
|
14
14
|
namespace vroom {
|
|
@@ -78,9 +78,9 @@ std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
|
|
|
78
78
|
// does, below) gives it a vtable/typeinfo from *our* .so; when RN-Skia's own
|
|
79
79
|
// compiled code later consumes it (e.g. Convertor.h's
|
|
80
80
|
// `getPropertyValue<sk_sp<SkPicture>>`, which does
|
|
81
|
-
// `
|
|
82
|
-
// under the hood), the cast fails cross-.so with "
|
|
83
|
-
//
|
|
81
|
+
// `getJsiObject<JsiSkPicture>(rt, value)` — a dynamic_pointer_cast
|
|
82
|
+
// under the hood), the cast fails cross-.so with "Expected a Skia object of
|
|
83
|
+
// a different type", because the object's *runtime* type was never actually
|
|
84
84
|
// compiled inside librnskia.so. iOS statically links everything into one
|
|
85
85
|
// binary, so no such mismatch exists there.
|
|
86
86
|
//
|
|
@@ -122,26 +122,30 @@ static facebook::jsi::Value wrapPicture(facebook::jsi::Runtime& rt,
|
|
|
122
122
|
if (!skiaApi.isObject()) return facebook::jsi::Value::null();
|
|
123
123
|
auto pictureFactory = skiaApi.asObject(rt).getProperty(rt, "Picture");
|
|
124
124
|
if (!pictureFactory.isObject()) return facebook::jsi::Value::null();
|
|
125
|
+
auto pictureFactoryObj = pictureFactory.asObject(rt);
|
|
125
126
|
auto makePicture =
|
|
126
|
-
|
|
127
|
+
pictureFactoryObj.getPropertyAsFunction(rt, "MakePicture");
|
|
127
128
|
|
|
128
129
|
// Mirrors JsiSkPictureFactory::MakePicture's expected argument shape: an
|
|
129
130
|
// object with a `.buffer` property holding the ArrayBuffer (matching a
|
|
130
131
|
// Uint8Array-like value; the factory ignores everything else about it).
|
|
132
|
+
//
|
|
133
|
+
// Skia 2.11's NativeState host methods recover the factory via `this`
|
|
134
|
+
// (`fromThis` → "Expected PictureFactory but got non-object" if unbound).
|
|
131
135
|
jsi::Object arg(rt);
|
|
132
136
|
arg.setProperty(rt, "buffer", arrayBuffer);
|
|
133
|
-
return makePicture.
|
|
137
|
+
return makePicture.callWithThis(rt, pictureFactoryObj, arg);
|
|
134
138
|
}
|
|
135
139
|
#else
|
|
136
|
-
// Shared helper: wraps a fresh picture for return to JS
|
|
137
|
-
//
|
|
140
|
+
// Shared helper: wraps a fresh picture for return to JS. Memory pressure is
|
|
141
|
+
// applied inside JsiSkPicture::create (NativeObject::create reads
|
|
142
|
+
// getMemoryPressure() → picture->approximateBytesUsed()).
|
|
138
143
|
static facebook::jsi::Value wrapPicture(facebook::jsi::Runtime& rt,
|
|
139
144
|
const sk_sp<SkPicture>& pic) {
|
|
140
145
|
if (!pic) return facebook::jsi::Value::null();
|
|
141
146
|
auto host =
|
|
142
147
|
std::make_shared<RNSkia::JsiSkPicture>(/*context=*/nullptr, pic);
|
|
143
|
-
return
|
|
144
|
-
/*context=*/nullptr);
|
|
148
|
+
return RNSkia::makeJsiObject(rt, host);
|
|
145
149
|
}
|
|
146
150
|
#endif
|
|
147
151
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#include "VroomFontMgr.h"
|
|
2
|
+
|
|
3
|
+
#pragma clang diagnostic push
|
|
4
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
5
|
+
#if defined(__APPLE__)
|
|
6
|
+
#include "include/ports/SkFontMgr_mac_ct.h"
|
|
7
|
+
#elif defined(__ANDROID__)
|
|
8
|
+
#include "include/ports/SkFontMgr_android.h"
|
|
9
|
+
#include "include/ports/SkFontScanner_FreeType.h"
|
|
10
|
+
#endif
|
|
11
|
+
#pragma clang diagnostic pop
|
|
12
|
+
|
|
13
|
+
namespace vroom {
|
|
14
|
+
|
|
15
|
+
sk_sp<SkFontMgr> makePlatformFontMgr() {
|
|
16
|
+
#if defined(__APPLE__)
|
|
17
|
+
return SkFontMgr_New_CoreText(nullptr);
|
|
18
|
+
#elif defined(__ANDROID__)
|
|
19
|
+
return SkFontMgr_New_Android(nullptr, SkFontScanner_Make_FreeType());
|
|
20
|
+
#else
|
|
21
|
+
return nullptr;
|
|
22
|
+
#endif
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
} // namespace vroom
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#pragma clang diagnostic push
|
|
4
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
5
|
+
#include "include/core/SkFontMgr.h"
|
|
6
|
+
#include "include/core/SkRefCnt.h"
|
|
7
|
+
#pragma clang diagnostic pop
|
|
8
|
+
|
|
9
|
+
namespace vroom {
|
|
10
|
+
|
|
11
|
+
// Returns the platform system font manager, or nullptr if unavailable.
|
|
12
|
+
sk_sp<SkFontMgr> makePlatformFontMgr();
|
|
13
|
+
|
|
14
|
+
} // namespace vroom
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
#include <memory>
|
|
16
16
|
|
|
17
17
|
#include "VroomChartHostObject.h"
|
|
18
|
-
#include "
|
|
18
|
+
#include "VroomFontMgr.h"
|
|
19
19
|
|
|
20
20
|
#include "chart_internal.h"
|
|
21
21
|
|
|
@@ -26,20 +26,36 @@
|
|
|
26
26
|
#include "include/core/SkTypeface.h"
|
|
27
27
|
#pragma clang diagnostic pop
|
|
28
28
|
|
|
29
|
+
#if defined(__ANDROID__)
|
|
30
|
+
#include <android/log.h>
|
|
31
|
+
#define VROOM_WARN(...) \
|
|
32
|
+
__android_log_print(ANDROID_LOG_WARN, "VroomChart", __VA_ARGS__)
|
|
33
|
+
#elif defined(__APPLE__)
|
|
34
|
+
#include <os/log.h>
|
|
35
|
+
#define VROOM_WARN(fmt, ...) \
|
|
36
|
+
os_log_error(OS_LOG_DEFAULT, "VroomChart: " fmt, ##__VA_ARGS__)
|
|
37
|
+
#else
|
|
38
|
+
#define VROOM_WARN(...)
|
|
39
|
+
#endif
|
|
40
|
+
|
|
29
41
|
namespace vroom {
|
|
30
42
|
|
|
31
43
|
namespace jsi = facebook::jsi;
|
|
32
44
|
|
|
33
|
-
// Loads the system typeface once via
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
45
|
+
// Loads the system typeface once via the platform SkFontMgr and hands it to
|
|
46
|
+
// the chart core. Built only once — constructing a font manager enumerates
|
|
47
|
+
// the system font set and is not cheap. Failure is logged once; we do not
|
|
48
|
+
// retry, because this no longer depends on RN-Skia's JSI bindings appearing.
|
|
49
|
+
static void ensureAxisTypeface() {
|
|
37
50
|
static bool done = false;
|
|
38
51
|
if (done) return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
auto mgr =
|
|
42
|
-
if (!mgr)
|
|
52
|
+
done = true;
|
|
53
|
+
|
|
54
|
+
auto mgr = vroom::makePlatformFontMgr();
|
|
55
|
+
if (!mgr) {
|
|
56
|
+
VROOM_WARN("axis typeface: platform font manager unavailable");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
43
59
|
|
|
44
60
|
// A null family name is meant to request "the platform default" — CoreText
|
|
45
61
|
// (iOS) honors that, but Android's SkFontMgr_New_Android does not: it
|
|
@@ -51,12 +67,16 @@ static void ensureAxisTypeface(jsi::Runtime& runtime) {
|
|
|
51
67
|
if (!tf) {
|
|
52
68
|
tf = mgr->matchFamilyStyle("sans-serif", SkFontStyle());
|
|
53
69
|
}
|
|
54
|
-
if (!tf)
|
|
70
|
+
if (!tf) {
|
|
71
|
+
VROOM_WARN("axis typeface: no default or sans-serif typeface");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
55
74
|
vroom::set_axis_typeface(tf);
|
|
56
|
-
done = true;
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
void installJsi(jsi::Runtime& runtime) {
|
|
78
|
+
ensureAxisTypeface();
|
|
79
|
+
|
|
60
80
|
auto create = jsi::Function::createFromHostFunction(
|
|
61
81
|
runtime,
|
|
62
82
|
jsi::PropNameID::forAscii(runtime, "create"),
|
|
@@ -65,7 +85,6 @@ void installJsi(jsi::Runtime& runtime) {
|
|
|
65
85
|
const jsi::Value& /*thisVal*/,
|
|
66
86
|
const jsi::Value* /*args*/,
|
|
67
87
|
size_t /*count*/) -> jsi::Value {
|
|
68
|
-
ensureAxisTypeface(rt);
|
|
69
88
|
auto host = std::make_shared<ChartHostObject>();
|
|
70
89
|
return jsi::Object::createFromHostObject(rt, host);
|
|
71
90
|
});
|
|
@@ -23,8 +23,8 @@ sk_sp<SkPicture> render_chart_picture(VroomChart* chart);
|
|
|
23
23
|
bool is_animating(VroomChart* chart);
|
|
24
24
|
|
|
25
25
|
// Sets the typeface used for axis labels. Bridge layer calls this once at
|
|
26
|
-
// startup with a system typeface
|
|
27
|
-
//
|
|
26
|
+
// startup with a system typeface from the platform SkFontMgr. Labels are
|
|
27
|
+
// skipped if no typeface is set.
|
|
28
28
|
void set_axis_typeface(sk_sp<SkTypeface> typeface);
|
|
29
29
|
|
|
30
30
|
} // namespace vroom
|
package/cpp/_core_src/fonts.h
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Global typeface for axis/label text rendering.
|
|
2
2
|
//
|
|
3
|
-
// Loaded once at startup by the bridge layer (which
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// Loaded once at startup by the bridge layer (which constructs a platform
|
|
4
|
+
// SkFontMgr and grabs the system default). Held as a process-global so all
|
|
5
|
+
// charts share it; per-chart font configuration is not modeled yet.
|
|
6
6
|
|
|
7
7
|
#pragma once
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-vroom-chart",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Mobile-first Skia candlestick chart for React Native",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Darion Welch",
|
|
@@ -59,20 +59,21 @@
|
|
|
59
59
|
"access": "public"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@shopify/react-native-skia": ">=2.
|
|
62
|
+
"@shopify/react-native-skia": ">=2.11.0",
|
|
63
63
|
"react": "*",
|
|
64
64
|
"react-native": "*",
|
|
65
65
|
"react-native-gesture-handler": ">=2.16.0",
|
|
66
|
-
"react-native-reanimated": ">=4.0.0"
|
|
66
|
+
"react-native-reanimated": ">=4.0.0",
|
|
67
|
+
"react-native-worklets": ">=0.7.0"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
|
-
"@shopify/react-native-skia": "2.
|
|
70
|
+
"@shopify/react-native-skia": "2.11.0",
|
|
70
71
|
"@types/react": "~19.1.0",
|
|
71
72
|
"react": "19.1.0",
|
|
72
73
|
"react-native": "0.81.5",
|
|
73
74
|
"react-native-gesture-handler": "~2.28.0",
|
|
74
75
|
"react-native-reanimated": "~4.1.7",
|
|
75
|
-
"react-native-worklets": "0.
|
|
76
|
+
"react-native-worklets": "0.7.4",
|
|
76
77
|
"tsup": "^8.5.1",
|
|
77
78
|
"typescript": "~5.9.2",
|
|
78
79
|
"vitest": "^3.2.6",
|
|
@@ -10,6 +10,11 @@ skia_pkg_json = `node --print "require.resolve('@shopify/react-native-skia/packa
|
|
|
10
10
|
skia_src_dir = File.dirname(skia_pkg_json)
|
|
11
11
|
skia_cpp_dir = File.join(skia_src_dir, "cpp")
|
|
12
12
|
skia_skia_dir = File.join(skia_src_dir, "cpp", "skia")
|
|
13
|
+
skia_api_dir = File.join(skia_src_dir, "cpp", "api")
|
|
14
|
+
use_graphite = File.exist?(File.join(skia_src_dir, "libs", ".graphite"))
|
|
15
|
+
skia_preprocessor_defs = use_graphite ?
|
|
16
|
+
"$(inherited) SK_GRAPHITE=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1" :
|
|
17
|
+
"$(inherited) SK_METAL=1 SK_GANESH=1 SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API=1 SK_DISABLE_LEGACY_SHAPER_FACTORY=1"
|
|
13
18
|
|
|
14
19
|
Pod::Spec.new do |s|
|
|
15
20
|
s.name = "react-native-vroom-chart"
|
|
@@ -60,12 +65,13 @@ Pod::Spec.new do |s|
|
|
|
60
65
|
'"$(PODS_TARGET_SRCROOT)/cpp"',
|
|
61
66
|
"\"#{skia_cpp_dir}\"",
|
|
62
67
|
"\"#{skia_skia_dir}\"",
|
|
68
|
+
"\"#{skia_api_dir}\"",
|
|
63
69
|
].join(" "),
|
|
64
|
-
"CLANG_CXX_LANGUAGE_STANDARD" => "c++
|
|
65
|
-
# Match RN-Skia's Skia build flags
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
|
|
71
|
+
# Match RN-Skia's Skia build flags (Ganesh vs Graphite, plus the
|
|
72
|
+
# SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API define both branches set) so our
|
|
73
|
+
# SkCanvas/SkPicture code sees the same ABI and doesn't mis-link.
|
|
74
|
+
"GCC_PREPROCESSOR_DEFINITIONS" => skia_preprocessor_defs,
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
s.dependency "React-Core"
|
package/cpp/VroomSkiaContext.cpp
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#include "VroomSkiaContext.h"
|
|
2
|
-
|
|
3
|
-
namespace vroom {
|
|
4
|
-
|
|
5
|
-
namespace jsi = facebook::jsi;
|
|
6
|
-
|
|
7
|
-
std::shared_ptr<RNSkia::RNSkPlatformContext> getRNSkContext(
|
|
8
|
-
jsi::Runtime& runtime) {
|
|
9
|
-
auto val = runtime.global().getProperty(runtime, "SkiaApi");
|
|
10
|
-
if (!val.isObject()) return nullptr;
|
|
11
|
-
auto obj = val.asObject(runtime);
|
|
12
|
-
if (!obj.isHostObject(runtime)) return nullptr;
|
|
13
|
-
auto host = obj.asHostObject(runtime);
|
|
14
|
-
|
|
15
|
-
// `global.SkiaApi` is always installed by RN-Skia's own
|
|
16
|
-
// RNSkManager::installBindings() as exactly a `JsiSkApi` host object — never
|
|
17
|
-
// any other JsiSkHostObject subclass — so this cast is safe as a plain
|
|
18
|
-
// static_cast, without any RTTI check. We deliberately avoid
|
|
19
|
-
// dynamic_pointer_cast here: on Android, RN-Skia is compiled into its own
|
|
20
|
-
// librnskia.so, separate from libvroomchart.so, so a `JsiSkApi` constructed
|
|
21
|
-
// by librnskia.so's code carries typeinfo from that .so; a dynamic_cast
|
|
22
|
-
// performed here (in libvroomchart.so) sees an unmerged RTTI record for
|
|
23
|
-
// "the same" class and always fails, even though the object is perfectly
|
|
24
|
-
// valid to use. (Same underlying issue as the JsiSkPicture cross-.so cast
|
|
25
|
-
// documented in VroomChartHostObject.cpp — but there RN-Skia's own compiled
|
|
26
|
-
// code does the cast on an object *we* construct, so we can't avoid it;
|
|
27
|
-
// here *we* do the cast on an object *they* construct, so we can just skip
|
|
28
|
-
// the runtime check we don't need.)
|
|
29
|
-
auto* accessor = static_cast<HostObjectAccessor*>(host.get());
|
|
30
|
-
return accessor->getContext();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
} // namespace vroom
|
package/cpp/VroomSkiaContext.h
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Helpers for reaching into RN-Skia's installed JSI bindings to grab its
|
|
2
|
-
// RNSkPlatformContext — which we need so we can use JsiSkFontMgrFactory to
|
|
3
|
-
// get the system font manager cross-platform.
|
|
4
|
-
//
|
|
5
|
-
// JsiSkHostObject::getContext() is protected, so we use a "friend helper"
|
|
6
|
-
// subclass that exposes it via `using`. We never construct an instance —
|
|
7
|
-
// we just static_cast existing host objects to the accessor type.
|
|
8
|
-
|
|
9
|
-
#pragma once
|
|
10
|
-
|
|
11
|
-
#include <memory>
|
|
12
|
-
|
|
13
|
-
#include <jsi/jsi.h>
|
|
14
|
-
|
|
15
|
-
#include "JsiSkHostObjects.h" // RNSkia::JsiSkHostObject
|
|
16
|
-
#include "RNSkPlatformContext.h" // RNSkia::RNSkPlatformContext
|
|
17
|
-
|
|
18
|
-
namespace vroom {
|
|
19
|
-
|
|
20
|
-
class HostObjectAccessor : public RNSkia::JsiSkHostObject {
|
|
21
|
-
public:
|
|
22
|
-
using RNSkia::JsiSkHostObject::getContext;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Returns the RN-Skia platform context by reading global.SkiaApi.
|
|
26
|
-
// Returns nullptr if SkiaApi isn't on the global yet (RN-Skia not installed).
|
|
27
|
-
std::shared_ptr<RNSkia::RNSkPlatformContext> getRNSkContext(
|
|
28
|
-
facebook::jsi::Runtime& runtime);
|
|
29
|
-
|
|
30
|
-
} // namespace vroom
|