@shopify/react-native-skia 0.1.193 → 0.1.195
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/android/cpp/rnskia-android/RNSkAndroidView.h +4 -0
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +3 -2
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +1 -1
- package/android/cpp/rnskia-android/SkiaOpenGLRenderer.cpp +35 -69
- package/android/cpp/rnskia-android/SkiaOpenGLRenderer.h +1 -12
- package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +104 -103
- package/cpp/rnskia/RNSkDomView.cpp +3 -2
- package/cpp/rnskia/RNSkPictureView.h +6 -8
- package/cpp/rnskia/RNSkView.h +13 -2
- package/cpp/rnskia/dom/base/JsiDomDrawingNode.h +3 -1
- package/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h +1 -1
- package/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm +8 -7
- package/ios/RNSkia-iOS/SkiaUIView.mm +10 -0
- package/package.json +1 -1
@@ -42,6 +42,10 @@ public:
|
|
42
42
|
void surfaceAvailable(jobject surface, int width, int height) override {
|
43
43
|
std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
|
44
44
|
->surfaceAvailable(surface, width, height);
|
45
|
+
|
46
|
+
// Try to render directly when the surface has been set so that
|
47
|
+
// we don't have to wait until the draw loop returns.
|
48
|
+
RNSkView::renderImmediate();
|
45
49
|
}
|
46
50
|
|
47
51
|
void surfaceDestroyed() override {
|
@@ -23,11 +23,12 @@ float RNSkOpenGLCanvasProvider::getScaledWidth() { return _width; }
|
|
23
23
|
|
24
24
|
float RNSkOpenGLCanvasProvider::getScaledHeight() { return _height; }
|
25
25
|
|
26
|
-
|
26
|
+
bool RNSkOpenGLCanvasProvider::renderToCanvas(
|
27
27
|
const std::function<void(SkCanvas *)> &cb) {
|
28
28
|
if (_renderer != nullptr) {
|
29
|
-
_renderer->run(cb, _width, _height);
|
29
|
+
return _renderer->run(cb, _width, _height);
|
30
30
|
}
|
31
|
+
return false;
|
31
32
|
}
|
32
33
|
|
33
34
|
void RNSkOpenGLCanvasProvider::surfaceAvailable(jobject surface, int width,
|
@@ -25,7 +25,7 @@ public:
|
|
25
25
|
|
26
26
|
float getScaledHeight() override;
|
27
27
|
|
28
|
-
|
28
|
+
bool renderToCanvas(const std::function<void(SkCanvas *)> &cb) override;
|
29
29
|
|
30
30
|
void surfaceAvailable(jobject surface, int width, int height);
|
31
31
|
|
@@ -4,6 +4,8 @@
|
|
4
4
|
#include <android/native_window.h>
|
5
5
|
#include <android/native_window_jni.h>
|
6
6
|
|
7
|
+
#define STENCIL_BUFFER_SIZE 8
|
8
|
+
|
7
9
|
namespace RNSkia {
|
8
10
|
/** Static members */
|
9
11
|
sk_sp<SkSurface> MakeOffscreenGLSurface(int width, int height) {
|
@@ -137,7 +139,7 @@ SkiaOpenGLRenderer::~SkiaOpenGLRenderer() {
|
|
137
139
|
_nativeWindow = nullptr;
|
138
140
|
}
|
139
141
|
|
140
|
-
|
142
|
+
bool SkiaOpenGLRenderer::run(const std::function<void(SkCanvas *)> &cb,
|
141
143
|
int width, int height) {
|
142
144
|
switch (_renderState) {
|
143
145
|
case RenderState::Initializing: {
|
@@ -148,31 +150,48 @@ void SkiaOpenGLRenderer::run(const std::function<void(SkCanvas *)> &cb,
|
|
148
150
|
case RenderState::Rendering: {
|
149
151
|
// Make sure to initialize the rendering pipeline
|
150
152
|
if (!ensureInitialised()) {
|
151
|
-
|
152
|
-
}
|
153
|
-
|
154
|
-
// Ensure we have the Skia surface to draw on. We need to
|
155
|
-
// pass width and height since the surface will be recreated
|
156
|
-
// when the view is resized.
|
157
|
-
if (!ensureSkiaSurface(width, height)) {
|
158
|
-
return;
|
153
|
+
return false;
|
159
154
|
}
|
160
155
|
|
161
156
|
if (cb != nullptr) {
|
162
|
-
//
|
163
|
-
|
157
|
+
// RNSkLogger::logToConsole("SKIARENDER - Render begin");
|
158
|
+
|
164
159
|
getThreadDrawingContext()->skContext->resetContext();
|
165
160
|
|
161
|
+
SkColorType colorType;
|
162
|
+
// setup surface for fbo0
|
163
|
+
GrGLFramebufferInfo fboInfo;
|
164
|
+
fboInfo.fFBOID = 0;
|
165
|
+
fboInfo.fFormat = 0x8058;
|
166
|
+
colorType = kN32_SkColorType;
|
167
|
+
|
168
|
+
GrBackendRenderTarget backendRT(width, height, 0, STENCIL_BUFFER_SIZE,
|
169
|
+
fboInfo);
|
170
|
+
|
171
|
+
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
|
172
|
+
|
173
|
+
sk_sp<SkSurface> renderTarget(SkSurface::MakeFromBackendRenderTarget(
|
174
|
+
getThreadDrawingContext()->skContext.get(), backendRT,
|
175
|
+
kBottomLeft_GrSurfaceOrigin, colorType, nullptr, &props));
|
176
|
+
|
177
|
+
auto canvas = renderTarget->getCanvas();
|
178
|
+
|
166
179
|
// Draw picture into surface
|
167
|
-
cb(
|
180
|
+
cb(canvas);
|
181
|
+
|
168
182
|
// Flush
|
169
|
-
|
183
|
+
canvas->flush();
|
170
184
|
|
171
185
|
if (!eglSwapBuffers(getThreadDrawingContext()->glDisplay, _glSurface)) {
|
172
186
|
RNSkLogger::logToConsole("eglSwapBuffers failed: %d\n", eglGetError());
|
187
|
+
return false;
|
173
188
|
}
|
189
|
+
|
190
|
+
// RNSkLogger::logToConsole("SKIARENDER - render done");
|
191
|
+
return true;
|
174
192
|
}
|
175
|
-
|
193
|
+
|
194
|
+
return false;
|
176
195
|
}
|
177
196
|
case RenderState::Finishing: {
|
178
197
|
_renderState = RenderState::Done;
|
@@ -184,14 +203,11 @@ void SkiaOpenGLRenderer::run(const std::function<void(SkCanvas *)> &cb,
|
|
184
203
|
_glSurface = EGL_NO_SURFACE;
|
185
204
|
}
|
186
205
|
|
187
|
-
|
188
|
-
_skSurface = nullptr;
|
189
|
-
|
190
|
-
break;
|
206
|
+
return true;
|
191
207
|
}
|
192
208
|
case RenderState::Done: {
|
193
209
|
// Do nothing. We're done.
|
194
|
-
|
210
|
+
return true;
|
195
211
|
}
|
196
212
|
}
|
197
213
|
}
|
@@ -326,54 +342,4 @@ bool SkiaOpenGLRenderer::initGLSurface() {
|
|
326
342
|
|
327
343
|
return true;
|
328
344
|
}
|
329
|
-
|
330
|
-
bool SkiaOpenGLRenderer::ensureSkiaSurface(int width, int height) {
|
331
|
-
if (getThreadDrawingContext()->skContext == nullptr) {
|
332
|
-
return false;
|
333
|
-
}
|
334
|
-
|
335
|
-
if (_skSurface == nullptr || !_skRenderTarget.isValid() ||
|
336
|
-
_prevWidth != width || _prevHeight != height) {
|
337
|
-
glViewport(0, 0, width, height);
|
338
|
-
|
339
|
-
_prevWidth = width;
|
340
|
-
_prevHeight = height;
|
341
|
-
|
342
|
-
GLint buffer;
|
343
|
-
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer);
|
344
|
-
|
345
|
-
GLint stencil;
|
346
|
-
glGetIntegerv(GL_STENCIL_BITS, &stencil);
|
347
|
-
|
348
|
-
GLint samples;
|
349
|
-
glGetIntegerv(GL_SAMPLES, &samples);
|
350
|
-
|
351
|
-
auto maxSamples =
|
352
|
-
getThreadDrawingContext()->skContext->maxSurfaceSampleCountForColorType(
|
353
|
-
kRGBA_8888_SkColorType);
|
354
|
-
|
355
|
-
if (samples > maxSamples)
|
356
|
-
samples = maxSamples;
|
357
|
-
|
358
|
-
GrGLFramebufferInfo fbInfo;
|
359
|
-
fbInfo.fFBOID = buffer;
|
360
|
-
fbInfo.fFormat = 0x8058;
|
361
|
-
|
362
|
-
_skRenderTarget =
|
363
|
-
GrBackendRenderTarget(width, height, samples, stencil, fbInfo);
|
364
|
-
|
365
|
-
_skSurface = SkSurface::MakeFromBackendRenderTarget(
|
366
|
-
getThreadDrawingContext()->skContext.get(), _skRenderTarget,
|
367
|
-
kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, nullptr, nullptr);
|
368
|
-
|
369
|
-
if (!_skSurface) {
|
370
|
-
RNSkLogger::logToConsole(
|
371
|
-
"JniSkiaDrawView::setupSurface - skSurface could not be created!");
|
372
|
-
return false;
|
373
|
-
}
|
374
|
-
|
375
|
-
return true;
|
376
|
-
}
|
377
|
-
return true;
|
378
|
-
}
|
379
345
|
} // namespace RNSkia
|
@@ -60,7 +60,7 @@ public:
|
|
60
60
|
* @param width Width of surface to render if there is a picture
|
61
61
|
* @param height Height of surface to render if there is a picture
|
62
62
|
*/
|
63
|
-
|
63
|
+
bool run(const std::function<void(SkCanvas *)> &cb, int width, int height);
|
64
64
|
|
65
65
|
/**
|
66
66
|
* Sets the state to finishing. Next time the renderer will be called it
|
@@ -102,15 +102,6 @@ private:
|
|
102
102
|
*/
|
103
103
|
bool initGLSurface();
|
104
104
|
|
105
|
-
/**
|
106
|
-
* Ensures that we have a valid Skia surface to draw to. The surface will
|
107
|
-
* be recreated if the width/height change.
|
108
|
-
* @param width Width of the underlying view
|
109
|
-
* @param height Height of the underlying view
|
110
|
-
* @return True if initialization went well
|
111
|
-
*/
|
112
|
-
bool ensureSkiaSurface(int width, int height);
|
113
|
-
|
114
105
|
/**
|
115
106
|
* To be able to use static contexts (and avoid reloading the skia context for
|
116
107
|
* each new view, we track the OpenGL and Skia drawing context per thread.
|
@@ -121,8 +112,6 @@ private:
|
|
121
112
|
EGLSurface _glSurface = EGL_NO_SURFACE;
|
122
113
|
|
123
114
|
ANativeWindow *_nativeWindow = nullptr;
|
124
|
-
GrBackendRenderTarget _skRenderTarget;
|
125
|
-
sk_sp<SkSurface> _skSurface;
|
126
115
|
|
127
116
|
int _prevWidth = 0;
|
128
117
|
int _prevHeight = 0;
|
@@ -58,123 +58,124 @@ public class ViewScreenshotService {
|
|
58
58
|
paint.setDither(true);
|
59
59
|
|
60
60
|
// Render the main view and its children
|
61
|
-
final Canvas
|
62
|
-
view.draw(c);
|
61
|
+
final Canvas canvas = new Canvas(bitmap);
|
63
62
|
|
64
|
-
//
|
65
|
-
|
63
|
+
// Renders view with child views to canvas
|
64
|
+
renderViewToCanvas(canvas, view, paint);
|
66
65
|
|
67
|
-
|
68
|
-
|
69
|
-
if (child instanceof TextureView) {
|
70
|
-
// skip all invisible to user child views
|
71
|
-
if (child.getVisibility() != VISIBLE) continue;
|
66
|
+
return bitmap;
|
67
|
+
}
|
72
68
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
if (
|
92
|
-
|
93
|
-
|
94
|
-
PixelCopy.request(svChild, childBitmapBuffer, new PixelCopy.OnPixelCopyFinishedListener() {
|
95
|
-
@Override
|
96
|
-
public void onPixelCopyFinished(int copyResult) {
|
97
|
-
final int countCanvasSave = c.save();
|
98
|
-
applyTransformations(c, view, child);
|
99
|
-
c.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
100
|
-
c.restoreToCount(countCanvasSave);
|
101
|
-
latch.countDown();
|
102
|
-
}
|
103
|
-
}, new Handler(Looper.getMainLooper()));
|
104
|
-
latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
|
105
|
-
} catch (Exception e) {
|
106
|
-
Log.e(TAG, "Cannot PixelCopy for " + svChild, e);
|
107
|
-
}
|
108
|
-
} else {
|
109
|
-
Bitmap cache = svChild.getDrawingCache();
|
110
|
-
if (cache != null) {
|
111
|
-
c.drawBitmap(svChild.getDrawingCache(), 0, 0, paint);
|
112
|
-
}
|
69
|
+
private static void renderViewToCanvas(Canvas canvas, View view, Paint paint) {
|
70
|
+
// Apply transformations for the current view
|
71
|
+
canvas.save();
|
72
|
+
applyTransformations(canvas, view);
|
73
|
+
|
74
|
+
// Draw children if the view has children
|
75
|
+
if ((view instanceof ViewGroup)) {
|
76
|
+
// Draw children
|
77
|
+
ViewGroup group = (ViewGroup) view;
|
78
|
+
|
79
|
+
// Hide visible children - this needs to be done because view.draw(canvas)
|
80
|
+
// will render all visible non-texture/surface views directly - causing
|
81
|
+
// views to be rendered twice - once by view.draw() and once when we
|
82
|
+
// enumerate children. We therefore need to turn off rendering of visible
|
83
|
+
// children before we call view.draw:
|
84
|
+
List<View> visibleChildren = new ArrayList<>();
|
85
|
+
for (int i = 0; i < group.getChildCount(); i++) {
|
86
|
+
View child = group.getChildAt(i);
|
87
|
+
if (child.getVisibility() == VISIBLE) {
|
88
|
+
visibleChildren.add(child);
|
89
|
+
child.setVisibility(View.INVISIBLE);
|
113
90
|
}
|
114
91
|
}
|
115
|
-
}
|
116
|
-
|
117
|
-
return bitmap;
|
118
|
-
}
|
119
92
|
|
120
|
-
|
121
|
-
|
122
|
-
final ArrayList<View> viewArrayList = new ArrayList<>();
|
123
|
-
viewArrayList.add(v);
|
93
|
+
// Draw ourselves
|
94
|
+
view.draw(canvas);
|
124
95
|
|
125
|
-
|
126
|
-
|
96
|
+
// Enable children again
|
97
|
+
for (int i = 0; i < visibleChildren.size(); i++) {
|
98
|
+
View child = visibleChildren.get(i);
|
99
|
+
child.setVisibility(VISIBLE);
|
100
|
+
}
|
127
101
|
|
128
|
-
|
102
|
+
// Draw children
|
103
|
+
for (int i = 0; i < group.getChildCount(); i++) {
|
104
|
+
View child = group.getChildAt(i);
|
129
105
|
|
130
|
-
|
131
|
-
|
132
|
-
View child = viewGroup.getChildAt(i);
|
106
|
+
// skip all invisible to user child views
|
107
|
+
if (child.getVisibility() != VISIBLE) continue;
|
133
108
|
|
134
|
-
|
135
|
-
|
109
|
+
// skip any child that we don't know how to process
|
110
|
+
if (child instanceof TextureView) {
|
111
|
+
final TextureView tvChild = (TextureView) child;
|
112
|
+
tvChild.setOpaque(false); // <-- switch off background fill
|
113
|
+
|
114
|
+
canvas.save();
|
115
|
+
applyTransformations(canvas, child);
|
116
|
+
|
117
|
+
// TextureView should use bitmaps with matching size,
|
118
|
+
// otherwise content of the TextureView will be scaled to provided bitmap dimensions
|
119
|
+
final Bitmap childBitmapBuffer = tvChild.getBitmap(Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888));
|
120
|
+
canvas.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
121
|
+
|
122
|
+
canvas.restore();
|
123
|
+
|
124
|
+
} else if (child instanceof SurfaceView) {
|
125
|
+
final SurfaceView svChild = (SurfaceView) child;
|
126
|
+
final CountDownLatch latch = new CountDownLatch(1);
|
127
|
+
|
128
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
129
|
+
final Bitmap childBitmapBuffer = Bitmap.createBitmap(child.getWidth(), child.getHeight(), Bitmap.Config.ARGB_8888);
|
130
|
+
try {
|
131
|
+
PixelCopy.request(svChild, childBitmapBuffer, copyResult -> {
|
132
|
+
canvas.save();
|
133
|
+
applyTransformations(canvas, child);
|
134
|
+
canvas.drawBitmap(childBitmapBuffer, 0, 0, paint);
|
135
|
+
canvas.restore();
|
136
|
+
latch.countDown();
|
137
|
+
}, new Handler(Looper.getMainLooper()));
|
138
|
+
latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
|
139
|
+
} catch (Exception e) {
|
140
|
+
Log.e(TAG, "Cannot PixelCopy for " + svChild, e);
|
141
|
+
}
|
142
|
+
} else {
|
143
|
+
Bitmap cache = svChild.getDrawingCache();
|
144
|
+
if (cache != null) {
|
145
|
+
canvas.save();
|
146
|
+
applyTransformations(canvas, child);
|
147
|
+
canvas.drawBitmap(svChild.getDrawingCache(), 0, 0, paint);
|
148
|
+
canvas.restore();
|
149
|
+
}
|
150
|
+
}
|
151
|
+
} else {
|
152
|
+
// Regular views needs to be rendered again to ensure correct z-index
|
153
|
+
// order with texture views and surface views.
|
154
|
+
renderViewToCanvas(canvas, child, paint);
|
155
|
+
}
|
156
|
+
}
|
157
|
+
} else {
|
158
|
+
// Draw ourselves
|
159
|
+
view.draw(canvas);
|
136
160
|
}
|
137
161
|
|
138
|
-
|
162
|
+
// Restore canvas
|
163
|
+
canvas.restore();
|
139
164
|
}
|
140
165
|
|
141
|
-
/**
|
142
|
-
* Concat all the transformation matrix's from parent to child.
|
143
|
-
*/
|
144
166
|
@NonNull
|
145
|
-
@
|
146
|
-
|
147
|
-
final Matrix
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
// apply transformations from parent --> child order
|
159
|
-
Collections.reverse(ms);
|
160
|
-
|
161
|
-
for (final View v : ms) {
|
162
|
-
c.save();
|
163
|
-
|
164
|
-
// apply each view transformations, so each child will be affected by them
|
165
|
-
final float dx = v.getLeft() + ((v != child) ? v.getPaddingLeft() : 0) + v.getTranslationX();
|
166
|
-
final float dy = v.getTop() + ((v != child) ? v.getPaddingTop() : 0) + v.getTranslationY();
|
167
|
-
c.translate(dx, dy);
|
168
|
-
c.rotate(v.getRotation(), v.getPivotX(), v.getPivotY());
|
169
|
-
c.scale(v.getScaleX(), v.getScaleY());
|
170
|
-
|
171
|
-
// compute the matrix just for any future use
|
172
|
-
transform.postTranslate(dx, dy);
|
173
|
-
transform.postRotate(v.getRotation(), v.getPivotX(), v.getPivotY());
|
174
|
-
transform.postScale(v.getScaleX(), v.getScaleY());
|
175
|
-
}
|
176
|
-
|
177
|
-
return transform;
|
167
|
+
private static void applyTransformations(final Canvas c, @NonNull final View view) {
|
168
|
+
// Get the transformation matrix of the view
|
169
|
+
final Matrix matrix = view.getMatrix();
|
170
|
+
|
171
|
+
// Create a new matrix for translation
|
172
|
+
final Matrix translateMatrix = new Matrix();
|
173
|
+
final float dx = view.getLeft() + view.getPaddingLeft() + view.getTranslationX();
|
174
|
+
final float dy = view.getTop() + view.getPaddingTop() + view.getTranslationY();
|
175
|
+
translateMatrix.setTranslate(dx, dy);
|
176
|
+
|
177
|
+
// Pre-concatenate the current matrix of the canvas with the translation and transformation matrices of the view
|
178
|
+
c.concat(translateMatrix);
|
179
|
+
c.concat(matrix);
|
178
180
|
}
|
179
|
-
|
180
181
|
}
|
@@ -36,15 +36,16 @@ bool RNSkDomRenderer::tryRender(
|
|
36
36
|
|
37
37
|
// We render on the main thread
|
38
38
|
if (_renderLock->try_lock()) {
|
39
|
+
bool result = false;
|
39
40
|
// If we have a Dom Node we can render directly on the main thread
|
40
41
|
if (_root != nullptr) {
|
41
|
-
canvasProvider->renderToCanvas(std::bind(
|
42
|
+
result = canvasProvider->renderToCanvas(std::bind(
|
42
43
|
&RNSkDomRenderer::renderCanvas, this, std::placeholders::_1,
|
43
44
|
canvasProvider->getScaledWidth(), canvasProvider->getScaledHeight()));
|
44
45
|
}
|
45
46
|
|
46
47
|
_renderLock->unlock();
|
47
|
-
return
|
48
|
+
return result;
|
48
49
|
} else {
|
49
50
|
return false;
|
50
51
|
}
|
@@ -44,8 +44,7 @@ public:
|
|
44
44
|
: RNSkRenderer(requestRedraw), _platformContext(context) {}
|
45
45
|
|
46
46
|
bool tryRender(std::shared_ptr<RNSkCanvasProvider> canvasProvider) override {
|
47
|
-
performDraw(canvasProvider);
|
48
|
-
return true;
|
47
|
+
return performDraw(canvasProvider);
|
49
48
|
}
|
50
49
|
|
51
50
|
void
|
@@ -64,11 +63,7 @@ public:
|
|
64
63
|
}
|
65
64
|
|
66
65
|
private:
|
67
|
-
|
68
|
-
if (_picture == nullptr) {
|
69
|
-
return;
|
70
|
-
}
|
71
|
-
|
66
|
+
bool performDraw(std::shared_ptr<RNSkCanvasProvider> canvasProvider) {
|
72
67
|
canvasProvider->renderToCanvas([=](SkCanvas *canvas) {
|
73
68
|
// Make sure to scale correctly
|
74
69
|
auto pd = _platformContext->getPixelDensity();
|
@@ -76,10 +71,13 @@ private:
|
|
76
71
|
canvas->save();
|
77
72
|
canvas->scale(pd, pd);
|
78
73
|
|
79
|
-
|
74
|
+
if (_picture != nullptr) {
|
75
|
+
canvas->drawPicture(_picture->getObject());
|
76
|
+
}
|
80
77
|
|
81
78
|
canvas->restore();
|
82
79
|
});
|
80
|
+
return true;
|
83
81
|
}
|
84
82
|
|
85
83
|
std::shared_ptr<RNSkPlatformContext> _platformContext;
|
package/cpp/rnskia/RNSkView.h
CHANGED
@@ -44,7 +44,7 @@ public:
|
|
44
44
|
/**
|
45
45
|
Render to a canvas
|
46
46
|
*/
|
47
|
-
virtual
|
47
|
+
virtual bool renderToCanvas(const std::function<void(SkCanvas *)> &) = 0;
|
48
48
|
|
49
49
|
protected:
|
50
50
|
std::function<void()> _requestRedraw;
|
@@ -123,8 +123,9 @@ public:
|
|
123
123
|
/**
|
124
124
|
Render to a canvas
|
125
125
|
*/
|
126
|
-
|
126
|
+
bool renderToCanvas(const std::function<void(SkCanvas *)> &cb) override {
|
127
127
|
cb(_surface->getCanvas());
|
128
|
+
return true;
|
128
129
|
};
|
129
130
|
|
130
131
|
private:
|
@@ -224,6 +225,15 @@ public:
|
|
224
225
|
*/
|
225
226
|
void requestRedraw() { _redrawRequestCounter++; }
|
226
227
|
|
228
|
+
/**
|
229
|
+
Renders immediate. Be carefull to not call this method from another thread
|
230
|
+
than the UI thread
|
231
|
+
*/
|
232
|
+
void renderImmediate() {
|
233
|
+
_renderer->renderImmediate(_canvasProvider);
|
234
|
+
_redrawRequestCounter = 0;
|
235
|
+
}
|
236
|
+
|
227
237
|
/**
|
228
238
|
Sets the native id of the view
|
229
239
|
*/
|
@@ -409,6 +419,7 @@ private:
|
|
409
419
|
|
410
420
|
size_t _drawingLoopId = 0;
|
411
421
|
std::atomic<int> _redrawRequestCounter = {1};
|
422
|
+
bool _initialDrawingDone = false;
|
412
423
|
};
|
413
424
|
|
414
425
|
} // namespace RNSkia
|
@@ -30,7 +30,9 @@ protected:
|
|
30
30
|
#endif
|
31
31
|
// Save paint if the paint property is set
|
32
32
|
if (_paintProp->isSet()) {
|
33
|
-
|
33
|
+
auto localCtx = _paintProp->getUnsafeDerivedValue().get();
|
34
|
+
localCtx->setCanvas(context->getCanvas());
|
35
|
+
draw(localCtx);
|
34
36
|
} else {
|
35
37
|
// Call abstract draw method
|
36
38
|
draw(context);
|
@@ -24,7 +24,7 @@ public:
|
|
24
24
|
float getScaledWidth() override;
|
25
25
|
float getScaledHeight() override;
|
26
26
|
|
27
|
-
|
27
|
+
bool renderToCanvas(const std::function<void(SkCanvas *)> &cb) override;
|
28
28
|
|
29
29
|
void setSize(int width, int height);
|
30
30
|
|
@@ -63,10 +63,10 @@ float RNSkMetalCanvasProvider::getScaledHeight() {
|
|
63
63
|
/**
|
64
64
|
Render to a canvas
|
65
65
|
*/
|
66
|
-
|
66
|
+
bool RNSkMetalCanvasProvider::renderToCanvas(
|
67
67
|
const std::function<void(SkCanvas *)> &cb) {
|
68
68
|
if (_width <= 0 || _height <= 0) {
|
69
|
-
return;
|
69
|
+
return false;
|
70
70
|
}
|
71
71
|
|
72
72
|
// Make sure to NOT render or try any render operations while we're in the
|
@@ -77,13 +77,12 @@ void RNSkMetalCanvasProvider::renderToCanvas(
|
|
77
77
|
// accessed from the main thread so we need to check here.
|
78
78
|
if ([[NSThread currentThread] isMainThread]) {
|
79
79
|
auto state = UIApplication.sharedApplication.applicationState;
|
80
|
-
if (state == UIApplicationStateBackground
|
81
|
-
state == UIApplicationStateInactive) {
|
80
|
+
if (state == UIApplicationStateBackground) {
|
82
81
|
// Request a redraw in the next run loop callback
|
83
82
|
_requestRedraw();
|
84
83
|
// and don't draw now since it might cause errors in the metal renderer if
|
85
84
|
// we try to render while in the background. (see above issue)
|
86
|
-
return;
|
85
|
+
return false;
|
87
86
|
}
|
88
87
|
}
|
89
88
|
|
@@ -114,7 +113,7 @@ void RNSkMetalCanvasProvider::renderToCanvas(
|
|
114
113
|
*/
|
115
114
|
id<CAMetalDrawable> currentDrawable = [_layer nextDrawable];
|
116
115
|
if (currentDrawable == nullptr) {
|
117
|
-
return;
|
116
|
+
return false;
|
118
117
|
}
|
119
118
|
|
120
119
|
GrMtlTextureInfo fbInfo;
|
@@ -130,7 +129,7 @@ void RNSkMetalCanvasProvider::renderToCanvas(
|
|
130
129
|
if (skSurface == nullptr || skSurface->getCanvas() == nullptr) {
|
131
130
|
RNSkia::RNSkLogger::logToConsole(
|
132
131
|
"Skia surface could not be created from parameters.");
|
133
|
-
return;
|
132
|
+
return false;
|
134
133
|
}
|
135
134
|
|
136
135
|
SkCanvas *canvas = skSurface->getCanvas();
|
@@ -143,6 +142,8 @@ void RNSkMetalCanvasProvider::renderToCanvas(
|
|
143
142
|
[commandBuffer presentDrawable:currentDrawable];
|
144
143
|
[commandBuffer commit];
|
145
144
|
}
|
145
|
+
|
146
|
+
return true;
|
146
147
|
};
|
147
148
|
|
148
149
|
void RNSkMetalCanvasProvider::setSize(int width, int height) {
|
@@ -93,6 +93,16 @@
|
|
93
93
|
assert(_impl == nullptr);
|
94
94
|
}
|
95
95
|
|
96
|
+
#pragma Render
|
97
|
+
|
98
|
+
- (void)drawRect:(CGRect)rect {
|
99
|
+
// We override drawRect to ensure we to direct rendering when the
|
100
|
+
// underlying OS view needs to render:
|
101
|
+
if (_impl != nullptr) {
|
102
|
+
_impl->getDrawView()->renderImmediate();
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
96
106
|
#pragma mark Layout
|
97
107
|
|
98
108
|
- (void)layoutSubviews {
|
package/package.json
CHANGED