@shopify/react-native-skia 0.1.184 → 0.1.186

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. package/android/build.gradle +2 -1
  2. package/android/cpp/jni/JniPlatformContext.cpp +92 -3
  3. package/android/cpp/jni/include/JniPlatformContext.h +4 -0
  4. package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +8 -0
  5. package/android/src/main/java/com/shopify/reactnative/skia/PlatformContext.java +17 -1
  6. package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +180 -0
  7. package/cpp/api/JsiSkFont.h +1 -1
  8. package/cpp/api/JsiSkHostObjects.h +1 -1
  9. package/cpp/api/JsiSkImage.h +8 -1
  10. package/cpp/api/JsiSkImageFactory.h +29 -0
  11. package/cpp/api/JsiSkPaint.h +7 -7
  12. package/cpp/api/JsiSkPathFactory.h +1 -1
  13. package/cpp/api/JsiSkPicture.h +2 -2
  14. package/cpp/api/JsiSkRuntimeEffect.h +3 -3
  15. package/cpp/api/JsiSkSVG.h +12 -2
  16. package/cpp/api/JsiSkShader.h +1 -1
  17. package/cpp/api/JsiSkSurface.h +3 -3
  18. package/cpp/api/JsiSkSurfaceFactory.h +1 -1
  19. package/cpp/api/JsiSkTypeface.h +1 -1
  20. package/cpp/rnskia/RNSkAnimation.h +3 -3
  21. package/cpp/rnskia/RNSkDomView.h +9 -9
  22. package/cpp/rnskia/RNSkInfoParameter.h +2 -2
  23. package/cpp/rnskia/RNSkJsView.h +8 -8
  24. package/cpp/rnskia/RNSkJsiViewApi.h +5 -5
  25. package/cpp/rnskia/RNSkPictureView.h +8 -8
  26. package/cpp/rnskia/RNSkPlatformContext.h +32 -3
  27. package/cpp/rnskia/RNSkValueApi.h +5 -5
  28. package/cpp/rnskia/RNSkView.h +10 -8
  29. package/cpp/rnskia/dom/base/ConcatablePaint.h +6 -6
  30. package/cpp/rnskia/dom/base/Declaration.h +1 -1
  31. package/cpp/rnskia/dom/base/DeclarationContext.h +7 -7
  32. package/cpp/rnskia/dom/base/DrawingContext.h +3 -3
  33. package/cpp/rnskia/dom/base/NodePropsContainer.h +1 -1
  34. package/cpp/rnskia/dom/nodes/JsiBlurMaskNode.h +1 -1
  35. package/cpp/rnskia/dom/nodes/JsiColorFilterNodes.h +1 -1
  36. package/cpp/rnskia/dom/nodes/JsiGlyphsNode.h +8 -7
  37. package/cpp/rnskia/dom/nodes/JsiImageFilterNodes.h +9 -6
  38. package/cpp/rnskia/dom/nodes/JsiImageNode.h +5 -2
  39. package/cpp/rnskia/dom/nodes/JsiImageSvgNode.h +9 -9
  40. package/cpp/rnskia/dom/nodes/JsiPathEffectNodes.h +1 -1
  41. package/cpp/rnskia/dom/nodes/JsiPathNode.h +1 -1
  42. package/cpp/rnskia/dom/nodes/JsiPointsNode.h +1 -1
  43. package/cpp/rnskia/dom/nodes/JsiShaderNodes.h +7 -3
  44. package/cpp/rnskia/dom/nodes/JsiTextNode.h +5 -4
  45. package/cpp/rnskia/dom/nodes/JsiTextPathNode.h +3 -1
  46. package/cpp/rnskia/dom/props/BlendModeProp.h +1 -1
  47. package/cpp/rnskia/dom/props/CircleProp.h +1 -1
  48. package/cpp/rnskia/dom/props/ClipProp.h +1 -1
  49. package/cpp/rnskia/dom/props/FontProp.h +15 -10
  50. package/cpp/rnskia/dom/props/ImageProps.h +30 -16
  51. package/cpp/rnskia/dom/props/PaintProps.h +1 -1
  52. package/cpp/rnskia/dom/props/PathProp.h +1 -1
  53. package/cpp/rnskia/dom/props/PointProp.h +1 -1
  54. package/cpp/rnskia/dom/props/PointsProp.h +1 -1
  55. package/cpp/rnskia/dom/props/RRectProp.h +2 -2
  56. package/cpp/rnskia/dom/props/RadiusProp.h +1 -1
  57. package/cpp/rnskia/dom/props/RectProp.h +1 -1
  58. package/cpp/rnskia/dom/props/StrokeProps.h +1 -1
  59. package/cpp/rnskia/dom/props/SvgProp.h +18 -12
  60. package/cpp/rnskia/dom/props/TextBlobProp.h +60 -57
  61. package/cpp/rnskia/dom/props/TileModeProp.h +1 -1
  62. package/cpp/rnskia/dom/props/UniformsProp.h +1 -1
  63. package/cpp/rnskia/dom/props/VertexModeProp.h +1 -1
  64. package/cpp/rnskia/dom/props/VerticesProps.h +1 -1
  65. package/cpp/rnskia/values/RNSkClockValue.h +2 -2
  66. package/cpp/rnskia/values/RNSkComputedValue.h +1 -1
  67. package/cpp/rnskia/values/RNSkReadonlyValue.h +3 -3
  68. package/cpp/rnskia/values/RNSkValue.h +4 -4
  69. package/cpp/utils/RNSkMeasureTime.h +1 -1
  70. package/cpp/utils/RNSkTimingInfo.h +1 -1
  71. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +16 -13
  72. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +8 -0
  73. package/ios/RNSkia-iOS/SkiaManager.mm +20 -1
  74. package/ios/RNSkia-iOS/ViewScreenshotService.h +21 -0
  75. package/ios/RNSkia-iOS/ViewScreenshotService.mm +79 -0
  76. package/lib/commonjs/dom/nodes/drawings/ImageNode.js +22 -1
  77. package/lib/commonjs/dom/nodes/drawings/ImageNode.js.map +1 -1
  78. package/lib/commonjs/dom/nodes/drawings/ImageSVG.js +5 -0
  79. package/lib/commonjs/dom/nodes/drawings/ImageSVG.js.map +1 -1
  80. package/lib/commonjs/dom/nodes/drawings/Text.d.ts +2 -2
  81. package/lib/commonjs/dom/nodes/drawings/Text.js +13 -2
  82. package/lib/commonjs/dom/nodes/drawings/Text.js.map +1 -1
  83. package/lib/commonjs/dom/nodes/paint/Shaders.js +5 -0
  84. package/lib/commonjs/dom/nodes/paint/Shaders.js.map +1 -1
  85. package/lib/commonjs/dom/types/Drawings.d.ts +5 -5
  86. package/lib/commonjs/dom/types/Drawings.js.map +1 -1
  87. package/lib/commonjs/dom/types/Shaders.d.ts +1 -1
  88. package/lib/commonjs/dom/types/Shaders.js.map +1 -1
  89. package/lib/commonjs/mock/index.js +2 -1
  90. package/lib/commonjs/mock/index.js.map +1 -1
  91. package/lib/commonjs/skia/core/Image.d.ts +14 -2
  92. package/lib/commonjs/skia/core/Image.js +37 -1
  93. package/lib/commonjs/skia/core/Image.js.map +1 -1
  94. package/lib/commonjs/skia/types/Image/Image.d.ts +6 -0
  95. package/lib/commonjs/skia/types/Image/Image.js.map +1 -1
  96. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +7 -0
  97. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  98. package/lib/commonjs/skia/types/SVG/SVG.d.ts +4 -1
  99. package/lib/commonjs/skia/types/SVG/SVG.js.map +1 -1
  100. package/lib/commonjs/skia/web/JsiSkImage.d.ts +1 -0
  101. package/lib/commonjs/skia/web/JsiSkImage.js +4 -0
  102. package/lib/commonjs/skia/web/JsiSkImage.js.map +1 -1
  103. package/lib/commonjs/skia/web/JsiSkImageFactory.d.ts +2 -1
  104. package/lib/commonjs/skia/web/JsiSkImageFactory.js +7 -0
  105. package/lib/commonjs/skia/web/JsiSkImageFactory.js.map +1 -1
  106. package/lib/module/dom/nodes/drawings/ImageNode.js +22 -1
  107. package/lib/module/dom/nodes/drawings/ImageNode.js.map +1 -1
  108. package/lib/module/dom/nodes/drawings/ImageSVG.js +5 -0
  109. package/lib/module/dom/nodes/drawings/ImageSVG.js.map +1 -1
  110. package/lib/module/dom/nodes/drawings/Text.d.ts +2 -2
  111. package/lib/module/dom/nodes/drawings/Text.js +13 -2
  112. package/lib/module/dom/nodes/drawings/Text.js.map +1 -1
  113. package/lib/module/dom/nodes/paint/Shaders.js +5 -0
  114. package/lib/module/dom/nodes/paint/Shaders.js.map +1 -1
  115. package/lib/module/dom/types/Drawings.d.ts +5 -5
  116. package/lib/module/dom/types/Drawings.js.map +1 -1
  117. package/lib/module/dom/types/Shaders.d.ts +1 -1
  118. package/lib/module/dom/types/Shaders.js.map +1 -1
  119. package/lib/module/mock/index.js +2 -1
  120. package/lib/module/mock/index.js.map +1 -1
  121. package/lib/module/skia/core/Image.d.ts +14 -2
  122. package/lib/module/skia/core/Image.js +32 -0
  123. package/lib/module/skia/core/Image.js.map +1 -1
  124. package/lib/module/skia/types/Image/Image.d.ts +6 -0
  125. package/lib/module/skia/types/Image/Image.js.map +1 -1
  126. package/lib/module/skia/types/Image/ImageFactory.d.ts +7 -0
  127. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  128. package/lib/module/skia/types/SVG/SVG.d.ts +4 -1
  129. package/lib/module/skia/types/SVG/SVG.js.map +1 -1
  130. package/lib/module/skia/web/JsiSkImage.d.ts +1 -0
  131. package/lib/module/skia/web/JsiSkImage.js +4 -0
  132. package/lib/module/skia/web/JsiSkImage.js.map +1 -1
  133. package/lib/module/skia/web/JsiSkImageFactory.d.ts +2 -1
  134. package/lib/module/skia/web/JsiSkImageFactory.js +7 -0
  135. package/lib/module/skia/web/JsiSkImageFactory.js.map +1 -1
  136. package/lib/typescript/src/dom/nodes/drawings/Text.d.ts +2 -2
  137. package/lib/typescript/src/dom/types/Drawings.d.ts +5 -5
  138. package/lib/typescript/src/dom/types/Shaders.d.ts +1 -1
  139. package/lib/typescript/src/skia/core/Image.d.ts +14 -2
  140. package/lib/typescript/src/skia/types/Image/Image.d.ts +6 -0
  141. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +7 -0
  142. package/lib/typescript/src/skia/types/SVG/SVG.d.ts +4 -1
  143. package/lib/typescript/src/skia/web/JsiSkImage.d.ts +1 -0
  144. package/lib/typescript/src/skia/web/JsiSkImageFactory.d.ts +2 -1
  145. package/package.json +2 -2
  146. package/scripts/install-npm.js +3 -2
  147. package/src/dom/nodes/drawings/ImageNode.ts +9 -1
  148. package/src/dom/nodes/drawings/ImageSVG.ts +3 -0
  149. package/src/dom/nodes/drawings/Text.ts +13 -3
  150. package/src/dom/nodes/paint/Shaders.ts +4 -0
  151. package/src/dom/types/Drawings.ts +5 -5
  152. package/src/dom/types/Shaders.ts +1 -1
  153. package/src/mock/index.ts +1 -0
  154. package/src/skia/core/Image.ts +43 -1
  155. package/src/skia/types/Image/Image.ts +7 -0
  156. package/src/skia/types/Image/ImageFactory.ts +8 -0
  157. package/src/skia/types/SVG/SVG.ts +4 -1
  158. package/src/skia/web/JsiSkImage.ts +7 -0
  159. package/src/skia/web/JsiSkImageFactory.ts +8 -1
@@ -9,7 +9,7 @@
9
9
  #pragma clang diagnostic push
10
10
  #pragma clang diagnostic ignored "-Wdocumentation"
11
11
 
12
- #include <SkPoint.h>
12
+ #include "SkPoint.h"
13
13
 
14
14
  #pragma clang diagnostic pop
15
15
 
@@ -11,7 +11,7 @@
11
11
  #pragma clang diagnostic push
12
12
  #pragma clang diagnostic ignored "-Wdocumentation"
13
13
 
14
- #include <SkPoint.h>
14
+ #include "SkPoint.h"
15
15
 
16
16
  #pragma clang diagnostic pop
17
17
 
@@ -9,8 +9,8 @@
9
9
  #pragma clang diagnostic push
10
10
  #pragma clang diagnostic ignored "-Wdocumentation"
11
11
 
12
- #include <SkRRect.h>
13
- #include <SkRect.h>
12
+ #include "SkRRect.h"
13
+ #include "SkRect.h"
14
14
 
15
15
  #pragma clang diagnostic pop
16
16
 
@@ -8,7 +8,7 @@
8
8
  #pragma clang diagnostic push
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
- #include <SkPoint.h>
11
+ #include "SkPoint.h"
12
12
 
13
13
  #pragma clang diagnostic pop
14
14
 
@@ -8,7 +8,7 @@
8
8
  #pragma clang diagnostic push
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
- #include <SkRect.h>
11
+ #include "SkRect.h"
12
12
 
13
13
  #pragma clang diagnostic pop
14
14
 
@@ -8,7 +8,7 @@
8
8
  #pragma clang diagnostic push
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
- #include <SkPaint.h>
11
+ #include "SkPaint.h"
12
12
 
13
13
  #pragma clang diagnostic pop
14
14
 
@@ -17,19 +17,25 @@ public:
17
17
  }
18
18
 
19
19
  void updateDerivedValue() override {
20
- if (_imageSvgProp->value().getType() != PropType::HostObject) {
21
- throw std::runtime_error(
22
- "Expected SkSvgDom object for the svg property.");
20
+ if (_imageSvgProp->isSet()) {
21
+
22
+ if (_imageSvgProp->value().getType() == PropType::HostObject) {
23
+
24
+ auto ptr = std::dynamic_pointer_cast<JsiSkSVG>(
25
+ _imageSvgProp->value().getAsHostObject());
26
+ if (ptr == nullptr) {
27
+ throw std::runtime_error(
28
+ "Expected SkSvgDom object for the svg property.");
29
+ }
30
+ setDerivedValue(ptr->getObject());
31
+ } else {
32
+ throw std::runtime_error(
33
+ "Expected SkSvgDom object or null/undefined for the svg property.");
34
+ }
35
+
36
+ } else {
37
+ setDerivedValue(nullptr);
23
38
  }
24
-
25
- auto ptr = std::dynamic_pointer_cast<JsiSkSVG>(
26
- _imageSvgProp->value().getAsHostObject());
27
- if (ptr == nullptr) {
28
- throw std::runtime_error(
29
- "Expected SkSvgDom object for the svg property.");
30
- }
31
-
32
- setDerivedValue(ptr->getObject());
33
39
  }
34
40
 
35
41
  private:
@@ -46,7 +46,6 @@ public:
46
46
  _pathProp = defineProperty<PathProp>("path");
47
47
  _offsetProp = defineProperty<NodeProp>("initialOffset");
48
48
 
49
- _fontProp->require();
50
49
  _textProp->require();
51
50
  _pathProp->require();
52
51
  _offsetProp->require();
@@ -58,66 +57,70 @@ public:
58
57
  auto path = _pathProp->getDerivedValue();
59
58
  auto offset = _offsetProp->value().getAsNumber();
60
59
 
61
- // Get glyphs
62
- auto numGlyphIds =
63
- font->countText(text.c_str(), text.length(), SkTextEncoding::kUTF8);
64
-
65
- std::vector<SkGlyphID> glyphIds;
66
- glyphIds.reserve(numGlyphIds);
67
- auto ids = font->textToGlyphs(
68
- text.c_str(), text.length(), SkTextEncoding::kUTF8,
69
- static_cast<SkGlyphID *>(glyphIds.data()), numGlyphIds);
70
-
71
- // Get glyph widths
72
- int glyphsSize = static_cast<int>(ids);
73
- std::vector<SkScalar> widthPtrs;
74
- widthPtrs.resize(glyphsSize);
75
- font->getWidthsBounds(glyphIds.data(), numGlyphIds,
76
- static_cast<SkScalar *>(widthPtrs.data()), nullptr,
77
- nullptr); // TODO: Should we use paint somehow here?
78
-
79
- std::vector<SkRSXform> rsx;
80
- SkContourMeasureIter meas(*path, false, 1);
81
-
82
- auto cont = meas.next();
83
- auto dist = offset;
84
-
85
- for (size_t i = 0; i < text.length() && cont != nullptr; ++i) {
86
- auto width = widthPtrs[i];
87
- dist += width / 2;
88
- if (dist > cont->length()) {
89
- // jump to next contour
90
- cont = meas.next();
91
- if (cont == nullptr) {
92
- // We have come to the end of the path - terminate the string
93
- // right here.
94
- text = text.substr(0, i);
95
- break;
60
+ if (font != nullptr) {
61
+ // Get glyphs
62
+ auto numGlyphIds =
63
+ font->countText(text.c_str(), text.length(), SkTextEncoding::kUTF8);
64
+
65
+ std::vector<SkGlyphID> glyphIds;
66
+ glyphIds.reserve(numGlyphIds);
67
+ auto ids = font->textToGlyphs(
68
+ text.c_str(), text.length(), SkTextEncoding::kUTF8,
69
+ static_cast<SkGlyphID *>(glyphIds.data()), numGlyphIds);
70
+
71
+ // Get glyph widths
72
+ int glyphsSize = static_cast<int>(ids);
73
+ std::vector<SkScalar> widthPtrs;
74
+ widthPtrs.resize(glyphsSize);
75
+ font->getWidthsBounds(glyphIds.data(), numGlyphIds,
76
+ static_cast<SkScalar *>(widthPtrs.data()), nullptr,
77
+ nullptr); // TODO: Should we use paint somehow here?
78
+
79
+ std::vector<SkRSXform> rsx;
80
+ SkContourMeasureIter meas(*path, false, 1);
81
+
82
+ auto cont = meas.next();
83
+ auto dist = offset;
84
+
85
+ for (size_t i = 0; i < text.length() && cont != nullptr; ++i) {
86
+ auto width = widthPtrs[i];
87
+ dist += width / 2;
88
+ if (dist > cont->length()) {
89
+ // jump to next contour
90
+ cont = meas.next();
91
+ if (cont == nullptr) {
92
+ // We have come to the end of the path - terminate the string
93
+ // right here.
94
+ text = text.substr(0, i);
95
+ break;
96
+ }
97
+ dist = width / 2;
96
98
  }
97
- dist = width / 2;
98
- }
99
- // Gives us the (x, y) coordinates as well as the cos/sin of the tangent
100
- // line at that position.
101
- SkPoint pos;
102
- SkVector tan;
103
- if (!cont->getPosTan(dist, &pos, &tan)) {
104
- throw std::runtime_error(
105
- "Could not calculate distance when resolving text path");
106
- }
107
- auto px = pos.x();
108
- auto py = pos.y();
109
- auto tx = tan.x();
110
- auto ty = tan.y();
99
+ // Gives us the (x, y) coordinates as well as the cos/sin of the tangent
100
+ // line at that position.
101
+ SkPoint pos;
102
+ SkVector tan;
103
+ if (!cont->getPosTan(dist, &pos, &tan)) {
104
+ throw std::runtime_error(
105
+ "Could not calculate distance when resolving text path");
106
+ }
107
+ auto px = pos.x();
108
+ auto py = pos.y();
109
+ auto tx = tan.x();
110
+ auto ty = tan.y();
111
111
 
112
- auto adjustedX = px - (width / 2) * tx;
113
- auto adjustedY = py - (width / 2) * ty;
112
+ auto adjustedX = px - (width / 2) * tx;
113
+ auto adjustedY = py - (width / 2) * ty;
114
114
 
115
- rsx.push_back(SkRSXform::Make(tx, ty, adjustedX, adjustedY));
116
- dist += width / 2;
117
- }
115
+ rsx.push_back(SkRSXform::Make(tx, ty, adjustedX, adjustedY));
116
+ dist += width / 2;
117
+ }
118
118
 
119
- setDerivedValue(SkTextBlob::MakeFromRSXform(text.c_str(), text.length(),
120
- rsx.data(), *font));
119
+ setDerivedValue(SkTextBlob::MakeFromRSXform(text.c_str(), text.length(),
120
+ rsx.data(), *font));
121
+ } else {
122
+ setDerivedValue(nullptr);
123
+ }
121
124
  }
122
125
 
123
126
  private:
@@ -5,7 +5,7 @@
5
5
  #pragma clang diagnostic push
6
6
  #pragma clang diagnostic ignored "-Wdocumentation"
7
7
 
8
- #include <SkTileMode.h>
8
+ #include "SkTileMode.h"
9
9
 
10
10
  #include <memory>
11
11
  #include <string>
@@ -10,7 +10,7 @@
10
10
  #pragma clang diagnostic push
11
11
  #pragma clang diagnostic ignored "-Wdocumentation"
12
12
 
13
- #include <SkRuntimeEffect.h>
13
+ #include "SkRuntimeEffect.h"
14
14
 
15
15
  #pragma clang diagnostic pop
16
16
 
@@ -8,7 +8,7 @@
8
8
  #pragma clang diagnostic push
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
- #include <SkVertices.h>
11
+ #include "SkVertices.h"
12
12
 
13
13
  #pragma clang diagnostic pop
14
14
 
@@ -13,7 +13,7 @@
13
13
  #pragma clang diagnostic push
14
14
  #pragma clang diagnostic ignored "-Wdocumentation"
15
15
 
16
- #include <SkVertices.h>
16
+ #include "SkVertices.h"
17
17
 
18
18
  #pragma clang diagnostic pop
19
19
 
@@ -1,8 +1,8 @@
1
1
 
2
2
  #pragma once
3
3
 
4
- #include <RNSkPlatformContext.h>
5
- #include <RNSkReadonlyValue.h>
4
+ #include "RNSkPlatformContext.h"
5
+ #include "RNSkReadonlyValue.h"
6
6
  #include <jsi/jsi.h>
7
7
 
8
8
  #include <algorithm>
@@ -1,8 +1,8 @@
1
1
 
2
2
  #pragma once
3
3
 
4
+ #include "RNSkPlatformContext.h"
4
5
  #include "RNSkReadonlyValue.h"
5
- #include <RNSkPlatformContext.h>
6
6
  #include <jsi/jsi.h>
7
7
 
8
8
  #include <algorithm>
@@ -10,9 +10,9 @@
10
10
 
11
11
  #include <jsi/jsi.h>
12
12
 
13
- #include <JsiSkHostObjects.h>
14
- #include <JsiValueWrapper.h>
15
- #include <RNSkPlatformContext.h>
13
+ #include "JsiSkHostObjects.h"
14
+ #include "JsiValueWrapper.h"
15
+ #include "RNSkPlatformContext.h"
16
16
 
17
17
  namespace RNSkia {
18
18
  namespace jsi = facebook::jsi;
@@ -3,10 +3,10 @@
3
3
  #include <functional>
4
4
  #include <memory>
5
5
 
6
- #include <JsiHostObject.h>
7
- #include <RNSkAnimation.h>
8
- #include <RNSkPlatformContext.h>
9
- #include <RNSkReadonlyValue.h>
6
+ #include "JsiHostObject.h"
7
+ #include "RNSkAnimation.h"
8
+ #include "RNSkPlatformContext.h"
9
+ #include "RNSkReadonlyValue.h"
10
10
  #include <jsi/jsi.h>
11
11
 
12
12
  namespace RNSkia {
@@ -7,7 +7,7 @@
7
7
  #include <chrono>
8
8
  #include <string>
9
9
 
10
- #include <RNSkLog.h>
10
+ #include "RNSkLog.h"
11
11
 
12
12
  namespace RNSkia {
13
13
 
@@ -1,6 +1,6 @@
1
1
  #pragma once
2
2
 
3
- #include <RNSkLog.h>
3
+ #include "RNSkLog.h"
4
4
  #include <chrono>
5
5
  #include <string>
6
6
  #include <utility>
@@ -6,16 +6,8 @@
6
6
  #include <memory>
7
7
  #include <string>
8
8
 
9
- #include <DisplayLink.h>
10
- #include <RNSkPlatformContext.h>
11
-
12
- #pragma clang diagnostic push
13
- #pragma clang diagnostic ignored "-Wdocumentation"
14
-
15
- #include "SkStream.h"
16
- #include "SkSurface.h"
17
-
18
- #pragma clang diagnostic pop
9
+ #include "DisplayLink.h"
10
+ #include "RNSkPlatformContext.h"
19
11
 
20
12
  #include <jsi/jsi.h>
21
13
 
@@ -35,10 +27,15 @@ static void handleNotification(CFNotificationCenterRef center, void *observer,
35
27
 
36
28
  class RNSkiOSPlatformContext : public RNSkPlatformContext {
37
29
  public:
38
- RNSkiOSPlatformContext(jsi::Runtime *runtime,
39
- std::shared_ptr<react::CallInvoker> callInvoker)
40
- : RNSkPlatformContext(runtime, callInvoker,
30
+ RNSkiOSPlatformContext(
31
+ jsi::Runtime *runtime, std::shared_ptr<react::CallInvoker> callInvoker,
32
+ std::function<void(std::function<void()>)> dispatchMainThread,
33
+ std::function<sk_sp<SkImage>(size_t viewTag)> takeViewScreenshot)
34
+ : _dispatchMainThread(dispatchMainThread),
35
+ _takeViewScreenshot(takeViewScreenshot),
36
+ RNSkPlatformContext(runtime, callInvoker,
41
37
  [[UIScreen mainScreen] scale]) {
38
+
42
39
  // We need to make sure we invalidate when modules are freed
43
40
  CFNotificationCenterAddObserver(
44
41
  CFNotificationCenterGetLocalCenter(), this, &handleNotification,
@@ -55,6 +52,10 @@ public:
55
52
  void startDrawLoop() override;
56
53
  void stopDrawLoop() override;
57
54
 
55
+ void runOnMainThread(std::function<void()>) override;
56
+
57
+ sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag) override;
58
+
58
59
  virtual void performStreamOperation(
59
60
  const std::string &sourceUri,
60
61
  const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) override;
@@ -69,6 +70,8 @@ public:
69
70
 
70
71
  private:
71
72
  DisplayLink *_displayLink;
73
+ std::function<void(std::function<void()>)> _dispatchMainThread;
74
+ std::function<sk_sp<SkImage>(size_t viewTag)> _takeViewScreenshot;
72
75
  };
73
76
 
74
77
  static void handleNotification(CFNotificationCenterRef center, void *observer,
@@ -62,6 +62,14 @@ sk_sp<SkSurface> RNSkiOSPlatformContext::makeOffscreenSurface(int width,
62
62
  return MakeOffscreenMetalSurface(width, height);
63
63
  }
64
64
 
65
+ void RNSkiOSPlatformContext::runOnMainThread(std::function<void()> func) {
66
+ _dispatchMainThread(func);
67
+ }
68
+
69
+ sk_sp<SkImage> RNSkiOSPlatformContext::takeScreenshotFromViewTag(size_t tag) {
70
+ return _takeViewScreenshot(tag);
71
+ }
72
+
65
73
  void RNSkiOSPlatformContext::startDrawLoop() {
66
74
  if (_displayLink == nullptr) {
67
75
  _displayLink = [[DisplayLink alloc] init];
@@ -4,14 +4,17 @@
4
4
 
5
5
  #import <React/RCTBridge+Private.h>
6
6
  #import <React/RCTBridge.h>
7
+ #import <React/RCTUIManager.h>
7
8
 
8
9
  #import <ReactCommon/RCTTurboModule.h>
9
10
 
10
11
  #import "RNSkiOSPlatformContext.h"
12
+ #import "ViewScreenshotService.h"
11
13
 
12
14
  @implementation SkiaManager {
13
15
  std::shared_ptr<RNSkia::RNSkManager> _skManager;
14
16
  std::shared_ptr<RNSkia::RNSkiOSPlatformContext> _platformContext;
17
+ ViewScreenshotService *_screenshot;
15
18
  __weak RCTBridge *weakBridge;
16
19
  }
17
20
 
@@ -37,9 +40,25 @@
37
40
  facebook::jsi::Runtime *jsRuntime =
38
41
  (facebook::jsi::Runtime *)cxxBridge.runtime;
39
42
 
43
+ // Create screenshot manager
44
+ _screenshot =
45
+ [[ViewScreenshotService alloc] initWithUiManager:bridge.uiManager];
46
+
47
+ auto takeScreenshot = [self](size_t viewTag) {
48
+ return [_screenshot
49
+ screenshotOfViewWithTag:[NSNumber numberWithLong:viewTag]];
50
+ };
51
+
52
+ auto dispatchOnMainThread = [self](std::function<void()> fp) {
53
+ dispatch_async(dispatch_get_main_queue(), ^{
54
+ fp();
55
+ });
56
+ };
57
+
40
58
  // Create platform context
41
59
  _platformContext = std::make_shared<RNSkia::RNSkiOSPlatformContext>(
42
- jsRuntime, callInvoker);
60
+ jsRuntime, callInvoker, std::move(dispatchOnMainThread),
61
+ std::move(takeScreenshot));
43
62
 
44
63
  // Create the RNSkiaManager (cross platform)
45
64
  _skManager = std::make_shared<RNSkia::RNSkManager>(jsRuntime, callInvoker,
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ #import <CoreFoundation/CoreFoundation.h>
4
+ #import <UIKit/UIKit.h>
5
+
6
+ #import <React/RCTUIManager.h>
7
+
8
+ #pragma clang diagnostic push
9
+ #pragma clang diagnostic ignored "-Wdocumentation"
10
+
11
+ #include "SkImage.h"
12
+
13
+ #pragma clang diagnostic pop
14
+
15
+ @interface ViewScreenshotService : NSObject {
16
+ }
17
+
18
+ - (instancetype)initWithUiManager:(RCTUIManager *)uiManager;
19
+ - (sk_sp<SkImage>)screenshotOfViewWithTag:(NSNumber *)viewTag;
20
+
21
+ @end
@@ -0,0 +1,79 @@
1
+ #import "ViewScreenshotService.h"
2
+ #import <QuartzCore/QuartzCore.h>
3
+
4
+ #pragma clang diagnostic push
5
+ #pragma clang diagnostic ignored "-Wdocumentation"
6
+
7
+ #include "SkData.h"
8
+
9
+ #pragma clang diagnostic pop
10
+
11
+ @implementation ViewScreenshotService {
12
+ RCTUIManager *_uiManager;
13
+ }
14
+
15
+ - (instancetype)initWithUiManager:(RCTUIManager *)uiManager {
16
+ if (self = [super init]) {
17
+ _uiManager = uiManager;
18
+ }
19
+ return self;
20
+ }
21
+
22
+ - (sk_sp<SkImage>)screenshotOfViewWithTag:(NSNumber *)viewTag {
23
+ // Find view corresponding to the tag
24
+ auto view = [_uiManager viewForReactTag:viewTag];
25
+ if (view == NULL) {
26
+ RCTFatal(RCTErrorWithMessage(@"Could not find view with tag"));
27
+ }
28
+
29
+ // Get size
30
+ CGSize size = view.frame.size;
31
+
32
+ // Setup context
33
+ UIGraphicsImageRendererFormat *format =
34
+ [UIGraphicsImageRendererFormat defaultFormat];
35
+ format.opaque = NO;
36
+ UIGraphicsImageRenderer *renderer =
37
+ [[UIGraphicsImageRenderer alloc] initWithSize:size format:format];
38
+
39
+ // Render to context - this is now the only part of this function that shows
40
+ // up in the profiler!
41
+ UIImage *image = [renderer
42
+ imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) {
43
+ [view drawViewHierarchyInRect:(CGRect){CGPointZero, size}
44
+ afterScreenUpdates:YES];
45
+ }];
46
+
47
+ // Convert from UIImage -> CGImage -> SkImage
48
+ CGImageRef cgImage = image.CGImage;
49
+
50
+ // Get some info about the image
51
+ auto width = CGImageGetWidth(cgImage);
52
+ auto height = CGImageGetHeight(cgImage);
53
+ auto bytesPerRow = CGImageGetBytesPerRow(cgImage);
54
+
55
+ // Convert from UIImage -> SkImage, start by getting the pixels directly from
56
+ // the CGImage:
57
+ auto dataRef = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
58
+ auto length = CFDataGetLength(dataRef);
59
+ void *data = CFDataGetMutableBytePtr((CFMutableDataRef)dataRef);
60
+
61
+ // Now we'll capture the data in an SkData object and control releasing it:
62
+ auto skData = SkData::MakeWithProc(
63
+ data, length,
64
+ [](const void *ptr, void *context) {
65
+ CFDataRef dataRef = (CFDataRef)context;
66
+ CFRelease(dataRef);
67
+ },
68
+ (void *)dataRef);
69
+
70
+ // Make SkImageInfo
71
+ SkImageInfo info =
72
+ SkImageInfo::Make(static_cast<int>(width), static_cast<int>(height),
73
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
74
+
75
+ // ... and then create the SkImage itself!
76
+ return SkImage::MakeRasterData(info, skData, bytesPerRow);
77
+ }
78
+
79
+ @end
@@ -20,6 +20,24 @@ class ImageNode extends _DrawingNode.JsiDrawingNode {
20
20
  const {
21
21
  image
22
22
  } = this.props;
23
+
24
+ if (!image) {
25
+ return {
26
+ src: {
27
+ x: 0,
28
+ y: 0,
29
+ width: 0,
30
+ height: 0
31
+ },
32
+ dst: {
33
+ x: 0,
34
+ y: 0,
35
+ width: 0,
36
+ height: 0
37
+ }
38
+ };
39
+ }
40
+
23
41
  const fit = this.props.fit ?? "contain";
24
42
  const rect = (0, _datatypes.processRect)(this.Skia, this.props);
25
43
  const {
@@ -54,7 +72,10 @@ class ImageNode extends _DrawingNode.JsiDrawingNode {
54
72
  src,
55
73
  dst
56
74
  } = this.derived;
57
- canvas.drawImageRect(image, src, dst, paint);
75
+
76
+ if (image) {
77
+ canvas.drawImageRect(image, src, dst, paint);
78
+ }
58
79
  }
59
80
 
60
81
  }
@@ -1 +1 @@
1
- {"version":3,"names":["ImageNode","JsiDrawingNode","constructor","ctx","props","NodeType","Image","deriveProps","image","fit","rect","processRect","Skia","src","dst","fitRects","x","y","width","height","draw","canvas","paint","derived","Error","drawImageRect"],"sources":["ImageNode.ts"],"sourcesContent":["import type { SkRect } from \"../../../skia/types\";\nimport type { DrawingContext, ImageProps } from \"../../types\";\nimport { NodeType } from \"../../types\";\nimport { fitRects, processRect } from \"../datatypes\";\nimport { JsiDrawingNode } from \"../DrawingNode\";\nimport type { NodeContext } from \"../Node\";\n\nexport class ImageNode extends JsiDrawingNode<\n ImageProps,\n { src: SkRect; dst: SkRect }\n> {\n constructor(ctx: NodeContext, props: ImageProps) {\n super(ctx, NodeType.Image, props);\n }\n\n deriveProps() {\n const { image } = this.props;\n const fit = this.props.fit ?? \"contain\";\n const rect = processRect(this.Skia, this.props);\n const { src, dst } = fitRects(\n fit,\n {\n x: 0,\n y: 0,\n width: image.width(),\n height: image.height(),\n },\n rect\n );\n return { src, dst };\n }\n\n draw({ canvas, paint }: DrawingContext) {\n const { image } = this.props;\n if (!this.derived) {\n throw new Error(\"ImageNode: src and dst are undefined\");\n }\n const { src, dst } = this.derived;\n canvas.drawImageRect(image, src, dst, paint);\n }\n}\n"],"mappings":";;;;;;;AAEA;;AACA;;AACA;;AAGO,MAAMA,SAAN,SAAwBC,2BAAxB,CAGL;EACAC,WAAW,CAACC,GAAD,EAAmBC,KAAnB,EAAsC;IAC/C,MAAMD,GAAN,EAAWE,eAAA,CAASC,KAApB,EAA2BF,KAA3B;EACD;;EAEDG,WAAW,GAAG;IACZ,MAAM;MAAEC;IAAF,IAAY,KAAKJ,KAAvB;IACA,MAAMK,GAAG,GAAG,KAAKL,KAAL,CAAWK,GAAX,IAAkB,SAA9B;IACA,MAAMC,IAAI,GAAG,IAAAC,sBAAA,EAAY,KAAKC,IAAjB,EAAuB,KAAKR,KAA5B,CAAb;IACA,MAAM;MAAES,GAAF;MAAOC;IAAP,IAAe,IAAAC,mBAAA,EACnBN,GADmB,EAEnB;MACEO,CAAC,EAAE,CADL;MAEEC,CAAC,EAAE,CAFL;MAGEC,KAAK,EAAEV,KAAK,CAACU,KAAN,EAHT;MAIEC,MAAM,EAAEX,KAAK,CAACW,MAAN;IAJV,CAFmB,EAQnBT,IARmB,CAArB;IAUA,OAAO;MAAEG,GAAF;MAAOC;IAAP,CAAP;EACD;;EAEDM,IAAI,OAAoC;IAAA,IAAnC;MAAEC,MAAF;MAAUC;IAAV,CAAmC;IACtC,MAAM;MAAEd;IAAF,IAAY,KAAKJ,KAAvB;;IACA,IAAI,CAAC,KAAKmB,OAAV,EAAmB;MACjB,MAAM,IAAIC,KAAJ,CAAU,sCAAV,CAAN;IACD;;IACD,MAAM;MAAEX,GAAF;MAAOC;IAAP,IAAe,KAAKS,OAA1B;IACAF,MAAM,CAACI,aAAP,CAAqBjB,KAArB,EAA4BK,GAA5B,EAAiCC,GAAjC,EAAsCQ,KAAtC;EACD;;AA7BD"}
1
+ {"version":3,"names":["ImageNode","JsiDrawingNode","constructor","ctx","props","NodeType","Image","deriveProps","image","src","x","y","width","height","dst","fit","rect","processRect","Skia","fitRects","draw","canvas","paint","derived","Error","drawImageRect"],"sources":["ImageNode.ts"],"sourcesContent":["import type { SkRect } from \"../../../skia/types\";\nimport type { DrawingContext, ImageProps } from \"../../types\";\nimport { NodeType } from \"../../types\";\nimport { fitRects, processRect } from \"../datatypes\";\nimport { JsiDrawingNode } from \"../DrawingNode\";\nimport type { NodeContext } from \"../Node\";\n\nexport class ImageNode extends JsiDrawingNode<\n ImageProps,\n { src: SkRect; dst: SkRect }\n> {\n constructor(ctx: NodeContext, props: ImageProps) {\n super(ctx, NodeType.Image, props);\n }\n\n deriveProps() {\n const { image } = this.props;\n if (!image) {\n return {\n src: { x: 0, y: 0, width: 0, height: 0 },\n dst: { x: 0, y: 0, width: 0, height: 0 },\n };\n }\n const fit = this.props.fit ?? \"contain\";\n const rect = processRect(this.Skia, this.props);\n const { src, dst } = fitRects(\n fit,\n {\n x: 0,\n y: 0,\n width: image.width(),\n height: image.height(),\n },\n rect\n );\n return { src, dst };\n }\n\n draw({ canvas, paint }: DrawingContext) {\n const { image } = this.props;\n if (!this.derived) {\n throw new Error(\"ImageNode: src and dst are undefined\");\n }\n const { src, dst } = this.derived;\n if (image) {\n canvas.drawImageRect(image, src, dst, paint);\n }\n }\n}\n"],"mappings":";;;;;;;AAEA;;AACA;;AACA;;AAGO,MAAMA,SAAN,SAAwBC,2BAAxB,CAGL;EACAC,WAAW,CAACC,GAAD,EAAmBC,KAAnB,EAAsC;IAC/C,MAAMD,GAAN,EAAWE,eAAA,CAASC,KAApB,EAA2BF,KAA3B;EACD;;EAEDG,WAAW,GAAG;IACZ,MAAM;MAAEC;IAAF,IAAY,KAAKJ,KAAvB;;IACA,IAAI,CAACI,KAAL,EAAY;MACV,OAAO;QACLC,GAAG,EAAE;UAAEC,CAAC,EAAE,CAAL;UAAQC,CAAC,EAAE,CAAX;UAAcC,KAAK,EAAE,CAArB;UAAwBC,MAAM,EAAE;QAAhC,CADA;QAELC,GAAG,EAAE;UAAEJ,CAAC,EAAE,CAAL;UAAQC,CAAC,EAAE,CAAX;UAAcC,KAAK,EAAE,CAArB;UAAwBC,MAAM,EAAE;QAAhC;MAFA,CAAP;IAID;;IACD,MAAME,GAAG,GAAG,KAAKX,KAAL,CAAWW,GAAX,IAAkB,SAA9B;IACA,MAAMC,IAAI,GAAG,IAAAC,sBAAA,EAAY,KAAKC,IAAjB,EAAuB,KAAKd,KAA5B,CAAb;IACA,MAAM;MAAEK,GAAF;MAAOK;IAAP,IAAe,IAAAK,mBAAA,EACnBJ,GADmB,EAEnB;MACEL,CAAC,EAAE,CADL;MAEEC,CAAC,EAAE,CAFL;MAGEC,KAAK,EAAEJ,KAAK,CAACI,KAAN,EAHT;MAIEC,MAAM,EAAEL,KAAK,CAACK,MAAN;IAJV,CAFmB,EAQnBG,IARmB,CAArB;IAUA,OAAO;MAAEP,GAAF;MAAOK;IAAP,CAAP;EACD;;EAEDM,IAAI,OAAoC;IAAA,IAAnC;MAAEC,MAAF;MAAUC;IAAV,CAAmC;IACtC,MAAM;MAAEd;IAAF,IAAY,KAAKJ,KAAvB;;IACA,IAAI,CAAC,KAAKmB,OAAV,EAAmB;MACjB,MAAM,IAAIC,KAAJ,CAAU,sCAAV,CAAN;IACD;;IACD,MAAM;MAAEf,GAAF;MAAOK;IAAP,IAAe,KAAKS,OAA1B;;IACA,IAAIf,KAAJ,EAAW;MACTa,MAAM,CAACI,aAAP,CAAqBjB,KAArB,EAA4BC,GAA5B,EAAiCK,GAAjC,EAAsCQ,KAAtC;IACD;EACF;;AArCD"}
@@ -27,6 +27,11 @@ class ImageSVGNode extends _DrawingNode.JsiDrawingNode {
27
27
  const {
28
28
  svg
29
29
  } = this.props;
30
+
31
+ if (!svg) {
32
+ return;
33
+ }
34
+
30
35
  const {
31
36
  x,
32
37
  y,
@@ -1 +1 @@
1
- {"version":3,"names":["ImageSVGNode","JsiDrawingNode","constructor","ctx","props","NodeType","ImageSVG","deriveProps","draw","canvas","svg","x","y","width","height","processRect","Skia","save","translate","drawSvg","restore"],"sources":["ImageSVG.ts"],"sourcesContent":["import type { DrawingContext, ImageSVGProps } from \"../../types\";\nimport { NodeType } from \"../../types\";\nimport { processRect } from \"../datatypes\";\nimport { JsiDrawingNode } from \"../DrawingNode\";\nimport type { NodeContext } from \"../Node\";\n\nexport class ImageSVGNode extends JsiDrawingNode<ImageSVGProps, null> {\n constructor(ctx: NodeContext, props: ImageSVGProps) {\n super(ctx, NodeType.ImageSVG, props);\n }\n\n deriveProps() {\n return null;\n }\n\n draw({ canvas }: DrawingContext) {\n const { svg } = this.props;\n const { x, y, width, height } = processRect(this.Skia, this.props);\n canvas.save();\n canvas.translate(x, y);\n canvas.drawSvg(svg, width, height);\n canvas.restore();\n }\n}\n"],"mappings":";;;;;;;AACA;;AACA;;AACA;;AAGO,MAAMA,YAAN,SAA2BC,2BAA3B,CAA+D;EACpEC,WAAW,CAACC,GAAD,EAAmBC,KAAnB,EAAyC;IAClD,MAAMD,GAAN,EAAWE,eAAA,CAASC,QAApB,EAA8BF,KAA9B;EACD;;EAEDG,WAAW,GAAG;IACZ,OAAO,IAAP;EACD;;EAEDC,IAAI,OAA6B;IAAA,IAA5B;MAAEC;IAAF,CAA4B;IAC/B,MAAM;MAAEC;IAAF,IAAU,KAAKN,KAArB;IACA,MAAM;MAAEO,CAAF;MAAKC,CAAL;MAAQC,KAAR;MAAeC;IAAf,IAA0B,IAAAC,sBAAA,EAAY,KAAKC,IAAjB,EAAuB,KAAKZ,KAA5B,CAAhC;IACAK,MAAM,CAACQ,IAAP;IACAR,MAAM,CAACS,SAAP,CAAiBP,CAAjB,EAAoBC,CAApB;IACAH,MAAM,CAACU,OAAP,CAAeT,GAAf,EAAoBG,KAApB,EAA2BC,MAA3B;IACAL,MAAM,CAACW,OAAP;EACD;;AAhBmE"}
1
+ {"version":3,"names":["ImageSVGNode","JsiDrawingNode","constructor","ctx","props","NodeType","ImageSVG","deriveProps","draw","canvas","svg","x","y","width","height","processRect","Skia","save","translate","drawSvg","restore"],"sources":["ImageSVG.ts"],"sourcesContent":["import type { DrawingContext, ImageSVGProps } from \"../../types\";\nimport { NodeType } from \"../../types\";\nimport { processRect } from \"../datatypes\";\nimport { JsiDrawingNode } from \"../DrawingNode\";\nimport type { NodeContext } from \"../Node\";\n\nexport class ImageSVGNode extends JsiDrawingNode<ImageSVGProps, null> {\n constructor(ctx: NodeContext, props: ImageSVGProps) {\n super(ctx, NodeType.ImageSVG, props);\n }\n\n deriveProps() {\n return null;\n }\n\n draw({ canvas }: DrawingContext) {\n const { svg } = this.props;\n if (!svg) {\n return;\n }\n const { x, y, width, height } = processRect(this.Skia, this.props);\n canvas.save();\n canvas.translate(x, y);\n canvas.drawSvg(svg, width, height);\n canvas.restore();\n }\n}\n"],"mappings":";;;;;;;AACA;;AACA;;AACA;;AAGO,MAAMA,YAAN,SAA2BC,2BAA3B,CAA+D;EACpEC,WAAW,CAACC,GAAD,EAAmBC,KAAnB,EAAyC;IAClD,MAAMD,GAAN,EAAWE,eAAA,CAASC,QAApB,EAA8BF,KAA9B;EACD;;EAEDG,WAAW,GAAG;IACZ,OAAO,IAAP;EACD;;EAEDC,IAAI,OAA6B;IAAA,IAA5B;MAAEC;IAAF,CAA4B;IAC/B,MAAM;MAAEC;IAAF,IAAU,KAAKN,KAArB;;IACA,IAAI,CAACM,GAAL,EAAU;MACR;IACD;;IACD,MAAM;MAAEC,CAAF;MAAKC,CAAL;MAAQC,KAAR;MAAeC;IAAf,IAA0B,IAAAC,sBAAA,EAAY,KAAKC,IAAjB,EAAuB,KAAKZ,KAA5B,CAAhC;IACAK,MAAM,CAACQ,IAAP;IACAR,MAAM,CAACS,SAAP,CAAiBP,CAAjB,EAAoBC,CAApB;IACAH,MAAM,CAACU,OAAP,CAAeT,GAAf,EAAoBG,KAApB,EAA2BC,MAA3B;IACAL,MAAM,CAACW,OAAP;EACD;;AAnBmE"}