@shopify/react-native-skia 2.0.0-next.2 → 2.0.0-next.4

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.
Files changed (175) hide show
  1. package/android/build.gradle +14 -10
  2. package/cpp/api/JsiSkCanvas.h +45 -2
  3. package/cpp/api/recorder/Drawings.h +31 -2
  4. package/cpp/api/recorder/Shaders.h +40 -0
  5. package/cpp/skia/include/codec/SkCodec.h +39 -1
  6. package/cpp/skia/include/config/SkUserConfig.h +1 -10
  7. package/cpp/skia/include/core/SkCanvas.h +8 -4
  8. package/cpp/skia/include/core/SkContourMeasure.h +2 -2
  9. package/cpp/skia/include/core/SkMilestone.h +1 -1
  10. package/cpp/skia/include/core/SkPaint.h +8 -5
  11. package/cpp/skia/include/core/SkStream.h +8 -3
  12. package/cpp/skia/include/core/SkTextBlob.h +9 -9
  13. package/cpp/skia/include/core/SkTypeface.h +4 -6
  14. package/cpp/skia/include/core/SkTypes.h +5 -0
  15. package/cpp/skia/include/docs/SkPDFDocument.h +47 -2
  16. package/cpp/skia/include/docs/SkPDFJpegHelpers.h +41 -0
  17. package/cpp/skia/include/effects/SkRuntimeEffect.h +5 -1
  18. package/cpp/skia/include/effects/SkTableMaskFilter.h +4 -0
  19. package/cpp/skia/include/gpu/graphite/BackendTexture.h +0 -2
  20. package/cpp/skia/include/gpu/graphite/ContextOptions.h +17 -0
  21. package/cpp/skia/include/gpu/graphite/GraphiteTypes.h +21 -18
  22. package/cpp/skia/include/gpu/graphite/PrecompileContext.h +24 -0
  23. package/cpp/skia/include/gpu/graphite/TextureInfo.h +87 -42
  24. package/cpp/skia/include/gpu/graphite/YUVABackendTextures.h +13 -4
  25. package/cpp/skia/include/gpu/graphite/dawn/DawnBackendContext.h +9 -0
  26. package/cpp/skia/include/gpu/graphite/dawn/DawnGraphiteTypes.h +166 -0
  27. package/cpp/skia/include/gpu/graphite/dawn/DawnTypes.h +3 -141
  28. package/cpp/skia/include/gpu/graphite/dawn/DawnUtils.h +2 -21
  29. package/cpp/skia/include/gpu/graphite/mtl/MtlBackendContext.h +4 -0
  30. package/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypes.h +30 -6
  31. package/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypesUtils.h +4 -42
  32. package/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteTypes_cpp.h +50 -0
  33. package/cpp/skia/include/gpu/graphite/mtl/MtlGraphiteUtils.h +2 -20
  34. package/cpp/skia/include/gpu/graphite/precompile/Precompile.h +14 -4
  35. package/cpp/skia/include/gpu/graphite/precompile/PrecompileShader.h +14 -6
  36. package/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteContext.h +31 -0
  37. package/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteTypes.h +36 -14
  38. package/cpp/skia/include/gpu/graphite/vk/VulkanGraphiteUtils.h +3 -21
  39. package/cpp/skia/include/ports/SkTypeface_fontations.h +3 -0
  40. package/cpp/skia/include/private/SkJpegMetadataDecoder.h +7 -0
  41. package/cpp/skia/include/private/base/SkAnySubclass.h +6 -0
  42. package/cpp/skia/include/private/chromium/SkPMColor.h +38 -0
  43. package/cpp/skia/modules/skparagraph/include/Paragraph.h +2 -2
  44. package/cpp/skia/modules/skunicode/include/SkUnicode.h +10 -6
  45. package/cpp/skia/modules/svg/include/SkSVGDOM.h +1 -3
  46. package/cpp/skia/src/base/SkTInternalLList.h +1 -1
  47. package/cpp/skia/src/core/SkLRUCache.h +6 -3
  48. package/lib/commonjs/external/reanimated/textures.d.ts +2 -4
  49. package/lib/commonjs/external/reanimated/textures.js +8 -15
  50. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  51. package/lib/commonjs/renderer/Canvas.d.ts +1 -2
  52. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  53. package/lib/commonjs/sksg/HostConfig.js +2 -1
  54. package/lib/commonjs/sksg/HostConfig.js.map +1 -1
  55. package/lib/commonjs/sksg/Recorder/Player.d.ts +1 -1
  56. package/lib/commonjs/sksg/Recorder/Player.js.map +1 -1
  57. package/lib/commonjs/sksg/Recorder/commands/Box.js +2 -2
  58. package/lib/commonjs/sksg/Recorder/commands/Box.js.map +1 -1
  59. package/lib/commonjs/sksg/Recorder/commands/Drawing.d.ts +1 -3
  60. package/lib/commonjs/sksg/Recorder/commands/Drawing.js +1 -58
  61. package/lib/commonjs/sksg/Recorder/commands/Drawing.js.map +1 -1
  62. package/lib/module/external/reanimated/textures.d.ts +2 -4
  63. package/lib/module/external/reanimated/textures.js +7 -12
  64. package/lib/module/external/reanimated/textures.js.map +1 -1
  65. package/lib/module/renderer/Canvas.d.ts +1 -2
  66. package/lib/module/renderer/Canvas.js.map +1 -1
  67. package/lib/module/sksg/HostConfig.js +2 -1
  68. package/lib/module/sksg/HostConfig.js.map +1 -1
  69. package/lib/module/sksg/Recorder/Player.d.ts +1 -1
  70. package/lib/module/sksg/Recorder/Player.js.map +1 -1
  71. package/lib/module/sksg/Recorder/commands/Box.js +2 -2
  72. package/lib/module/sksg/Recorder/commands/Box.js.map +1 -1
  73. package/lib/module/sksg/Recorder/commands/Drawing.d.ts +1 -3
  74. package/lib/module/sksg/Recorder/commands/Drawing.js +2 -58
  75. package/lib/module/sksg/Recorder/commands/Drawing.js.map +1 -1
  76. package/lib/typescript/lib/commonjs/external/reanimated/textures.d.ts +1 -3
  77. package/lib/typescript/lib/commonjs/sksg/HostConfig.d.ts +1 -1
  78. package/lib/typescript/lib/commonjs/sksg/Recorder/commands/Drawing.d.ts +0 -1
  79. package/lib/typescript/lib/module/external/reanimated/textures.d.ts +1 -3
  80. package/lib/typescript/lib/module/sksg/HostConfig.d.ts +1 -1
  81. package/lib/typescript/lib/module/sksg/Recorder/commands/Drawing.d.ts +0 -1
  82. package/lib/typescript/src/external/reanimated/textures.d.ts +2 -4
  83. package/lib/typescript/src/renderer/Canvas.d.ts +1 -2
  84. package/lib/typescript/src/sksg/Recorder/Player.d.ts +1 -1
  85. package/lib/typescript/src/sksg/Recorder/commands/Drawing.d.ts +1 -3
  86. package/libs/android/arm64-v8a/libskia.a +0 -0
  87. package/libs/android/arm64-v8a/libskottie.a +0 -0
  88. package/libs/android/arm64-v8a/libskparagraph.a +0 -0
  89. package/libs/android/arm64-v8a/libsksg.a +0 -0
  90. package/libs/android/arm64-v8a/libskshaper.a +0 -0
  91. package/libs/android/arm64-v8a/libskunicode_icu.a +0 -0
  92. package/libs/android/arm64-v8a/libsvg.a +0 -0
  93. package/libs/android/armeabi-v7a/libskia.a +0 -0
  94. package/libs/android/armeabi-v7a/libskottie.a +0 -0
  95. package/libs/android/armeabi-v7a/libskparagraph.a +0 -0
  96. package/libs/android/armeabi-v7a/libsksg.a +0 -0
  97. package/libs/android/armeabi-v7a/libskshaper.a +0 -0
  98. package/libs/android/armeabi-v7a/libskunicode_icu.a +0 -0
  99. package/libs/android/armeabi-v7a/libsvg.a +0 -0
  100. package/libs/android/x86/libskia.a +0 -0
  101. package/libs/android/x86/libskottie.a +0 -0
  102. package/libs/android/x86/libskparagraph.a +0 -0
  103. package/libs/android/x86/libsksg.a +0 -0
  104. package/libs/android/x86/libskshaper.a +0 -0
  105. package/libs/android/x86/libskunicode_icu.a +0 -0
  106. package/libs/android/x86/libsvg.a +0 -0
  107. package/libs/android/x86_64/libskia.a +0 -0
  108. package/libs/android/x86_64/libskottie.a +0 -0
  109. package/libs/android/x86_64/libskparagraph.a +0 -0
  110. package/libs/android/x86_64/libsksg.a +0 -0
  111. package/libs/android/x86_64/libskshaper.a +0 -0
  112. package/libs/android/x86_64/libskunicode_icu.a +0 -0
  113. package/libs/android/x86_64/libsvg.a +0 -0
  114. package/libs/apple/libskia.xcframework/Info.plist +15 -15
  115. package/libs/apple/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  116. package/libs/apple/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  117. package/libs/apple/libskia.xcframework/macos-arm64_x86_64/libskia.a +0 -0
  118. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e/libskia.a +0 -0
  119. package/libs/apple/libskia.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  120. package/libs/apple/libskottie.xcframework/Info.plist +7 -7
  121. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e/libskottie.a +0 -0
  122. package/libs/apple/libskottie.xcframework/ios-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  123. package/libs/apple/libskottie.xcframework/macos-arm64_x86_64/libskottie.a +0 -0
  124. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e/libskottie.a +0 -0
  125. package/libs/apple/libskottie.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  126. package/libs/apple/libskparagraph.xcframework/Info.plist +13 -13
  127. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e/libskparagraph.a +0 -0
  128. package/libs/apple/libskparagraph.xcframework/ios-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  129. package/libs/apple/libskparagraph.xcframework/macos-arm64_x86_64/libskparagraph.a +0 -0
  130. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e/libskparagraph.a +0 -0
  131. package/libs/apple/libskparagraph.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  132. package/libs/apple/libsksg.xcframework/Info.plist +13 -13
  133. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e/libsksg.a +0 -0
  134. package/libs/apple/libsksg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  135. package/libs/apple/libsksg.xcframework/macos-arm64_x86_64/libsksg.a +0 -0
  136. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e/libsksg.a +0 -0
  137. package/libs/apple/libsksg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  138. package/libs/apple/libskshaper.xcframework/Info.plist +14 -14
  139. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  140. package/libs/apple/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  141. package/libs/apple/libskshaper.xcframework/macos-arm64_x86_64/libskshaper.a +0 -0
  142. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e/libskshaper.a +0 -0
  143. package/libs/apple/libskshaper.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  144. package/libs/apple/libskunicode_core.xcframework/Info.plist +12 -12
  145. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e/libskunicode_core.a +0 -0
  146. package/libs/apple/libskunicode_core.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  147. package/libs/apple/libskunicode_core.xcframework/macos-arm64_x86_64/libskunicode_core.a +0 -0
  148. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e/libskunicode_core.a +0 -0
  149. package/libs/apple/libskunicode_core.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_core.a +0 -0
  150. package/libs/apple/libskunicode_libgrapheme.xcframework/Info.plist +15 -15
  151. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  152. package/libs/apple/libskunicode_libgrapheme.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  153. package/libs/apple/libskunicode_libgrapheme.xcframework/macos-arm64_x86_64/libskunicode_libgrapheme.a +0 -0
  154. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e/libskunicode_libgrapheme.a +0 -0
  155. package/libs/apple/libskunicode_libgrapheme.xcframework/tvos-arm64_arm64e_x86_64-simulator/libskunicode_libgrapheme.a +0 -0
  156. package/libs/apple/libsvg.xcframework/Info.plist +8 -8
  157. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  158. package/libs/apple/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  159. package/libs/apple/libsvg.xcframework/macos-arm64_x86_64/libsvg.a +0 -0
  160. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e/libsvg.a +0 -0
  161. package/libs/apple/libsvg.xcframework/tvos-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  162. package/package.json +3 -3
  163. package/src/__tests__/snapshots/box/box-shadow-opacity.png +0 -0
  164. package/src/__tests__/snapshots/platform-buffer.png +0 -0
  165. package/src/__tests__/snapshots/screens/snapshot2-android-ci.png +0 -0
  166. package/src/external/reanimated/textures.tsx +12 -20
  167. package/src/renderer/Canvas.tsx +1 -1
  168. package/src/renderer/__tests__/e2e/Box.spec.tsx +22 -0
  169. package/src/renderer/__tests__/e2e/NativeBuffer.spec.tsx +2 -0
  170. package/src/sksg/HostConfig.ts +2 -1
  171. package/src/sksg/Recorder/Player.ts +1 -1
  172. package/src/sksg/Recorder/commands/Box.ts +2 -2
  173. package/src/sksg/Recorder/commands/Drawing.ts +0 -65
  174. package/cpp/skia/include/core/SkColorPriv.h +0 -165
  175. package/cpp/skia/include/private/SkColorData.h +0 -385
@@ -295,13 +295,17 @@ afterEvaluate { project ->
295
295
  }
296
296
  }
297
297
 
298
+ def localBuildDir = buildDir
299
+ def headersConfiguration = configurations.extractHeaders
300
+ def jniConfiguration = configurations.extractJNI
301
+
298
302
  task extractAARHeaders {
299
303
  doLast {
300
- configurations.extractHeaders.files.each {
301
- def file = it.absoluteFile
302
- copy {
303
- from zipTree(file)
304
- into "$buildDir/$file.name"
304
+ headersConfiguration.files.each { file ->
305
+ def absFile = file.absoluteFile
306
+ project.copy {
307
+ from project.zipTree(absFile)
308
+ into "${localBuildDir}/${absFile.name}"
305
309
  include "**/*.h"
306
310
  }
307
311
  }
@@ -310,11 +314,11 @@ task extractAARHeaders {
310
314
 
311
315
  task extractJNIFiles {
312
316
  doLast {
313
- configurations.extractJNI.files.each {
314
- def file = it.absoluteFile
315
- copy {
316
- from zipTree(file)
317
- into "$buildDir/$file.name"
317
+ jniConfiguration.files.each { file ->
318
+ def absFile = file.absoluteFile
319
+ project.copy {
320
+ from project.zipTree(absFile)
321
+ into "${localBuildDir}/${absFile.name}"
318
322
  include "jni/**/*"
319
323
  }
320
324
  }
@@ -243,6 +243,12 @@ public:
243
243
 
244
244
  auto jsiPoints = arguments[1].asObject(runtime).asArray(runtime);
245
245
  auto pointsSize = jsiPoints.size(runtime);
246
+
247
+ // Check if we have at least one point
248
+ if (pointsSize == 0) {
249
+ throw std::invalid_argument("Points array must not be empty");
250
+ }
251
+
246
252
  points.reserve(pointsSize);
247
253
 
248
254
  for (int i = 0; i < pointsSize; i++) {
@@ -274,6 +280,12 @@ public:
274
280
 
275
281
  auto jsiCubics = arguments[0].asObject(runtime).asArray(runtime);
276
282
  auto cubicsSize = jsiCubics.size(runtime);
283
+
284
+ // Validate cubic points - must be exactly 12 points
285
+ if (cubicsSize != 12) {
286
+ throw std::invalid_argument("Cubic points array must contain exactly 12 points");
287
+ }
288
+
277
289
  cubics.reserve(cubicsSize);
278
290
  for (int i = 0; i < cubicsSize; i++) {
279
291
  std::shared_ptr<SkPoint> point = JsiSkPoint::fromValue(
@@ -284,6 +296,12 @@ public:
284
296
  if (count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined()) {
285
297
  auto jsiColors = arguments[1].asObject(runtime).asArray(runtime);
286
298
  auto colorsSize = jsiColors.size(runtime);
299
+
300
+ // Validate colors array - must be exactly 4 colors
301
+ if (colorsSize != 4) {
302
+ throw std::invalid_argument("Colors array must contain exactly 4 colors");
303
+ }
304
+
287
305
  colors.reserve(colorsSize);
288
306
  for (int i = 0; i < colorsSize; i++) {
289
307
  SkColor color = JsiSkColor::fromValue(
@@ -295,6 +313,12 @@ public:
295
313
  if (count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined()) {
296
314
  auto jsiTexs = arguments[2].asObject(runtime).asArray(runtime);
297
315
  auto texsSize = jsiTexs.size(runtime);
316
+
317
+ // Validate textures array - must be exactly 4 points
318
+ if (texsSize != 4) {
319
+ throw std::invalid_argument("Texture coordinates array must contain exactly 4 points");
320
+ }
321
+
298
322
  texs.reserve(texsSize);
299
323
  for (int i = 0; i < texsSize; i++) {
300
324
  auto point = JsiSkPoint::fromValue(
@@ -306,7 +330,8 @@ public:
306
330
  auto paint =
307
331
  count >= 4 ? JsiSkPaint::fromValue(runtime, arguments[4]) : nullptr;
308
332
  auto blendMode = static_cast<SkBlendMode>(arguments[3].asNumber());
309
- _canvas->drawPatch(cubics.data(), colors.data(), texs.data(), blendMode,
333
+ _canvas->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
334
+ texs.empty() ? nullptr : texs.data(), blendMode,
310
335
  *paint);
311
336
  return jsi::Value::undefined();
312
337
  }
@@ -364,6 +389,12 @@ public:
364
389
 
365
390
  std::vector<SkGlyphID> glyphs;
366
391
  int glyphsSize = static_cast<int>(jsiGlyphs.size(runtime));
392
+
393
+ // Validate that glyphs and positions arrays have the same size
394
+ if (glyphsSize != pointsSize) {
395
+ throw std::invalid_argument("Glyphs and positions arrays must have the same length");
396
+ }
397
+
367
398
  glyphs.reserve(glyphsSize);
368
399
  for (int i = 0; i < glyphsSize; i++) {
369
400
  glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber());
@@ -522,11 +553,22 @@ public:
522
553
  runtime, rects.getValueAtIndex(runtime, i).asObject(runtime));
523
554
  skRects.push_back(*rect.get());
524
555
  }
556
+
557
+ // Validate transforms and rects have the same size
558
+ if (xformsSize != rectsSize) {
559
+ throw std::invalid_argument("Transforms and rects arrays must have the same length");
560
+ }
525
561
 
526
562
  std::vector<SkColor> colors;
527
563
  if (count > 5 && !arguments[5].isUndefined()) {
528
564
  auto colorsArray = arguments[5].asObject(runtime).asArray(runtime);
529
565
  int colorsSize = static_cast<int>(colorsArray.size(runtime));
566
+
567
+ // Validate colors array matches the size of sprites and transforms
568
+ if (colorsSize != rectsSize) {
569
+ throw std::invalid_argument("Colors array must have the same length as rects/transforms");
570
+ }
571
+
530
572
  colors.reserve(colorsSize);
531
573
  for (int i = 0; i < colorsSize; i++) {
532
574
  // Convert from [r,g,b,a] in [0,1] to SkColor
@@ -551,7 +593,8 @@ public:
551
593
  sampling = SamplingOptionsFromValue(runtime, arguments[6]);
552
594
  }
553
595
  _canvas->drawAtlas(atlas.get(), xforms.data(), skRects.data(),
554
- colors.data(), skRects.size(), blendMode, sampling,
596
+ colors.empty() ? nullptr : colors.data(),
597
+ skRects.size(), blendMode, sampling,
555
598
  nullptr, paint.get());
556
599
 
557
600
  return jsi::Value::undefined();
@@ -418,7 +418,7 @@ public:
418
418
  SkPaint shadowPaint;
419
419
  shadowPaint.setAntiAlias(true);
420
420
  shadowPaint.setColor(shadow.color.value_or(SK_ColorBLACK));
421
- shadowPaint.setAlphaf(opacity);
421
+ shadowPaint.setAlphaf(opacity * shadowPaint.getAlphaf());
422
422
  shadowPaint.setMaskFilter(SkMaskFilter::MakeBlur(
423
423
  SkBlurStyle::kNormal_SkBlurStyle, shadow.blur, true));
424
424
 
@@ -442,7 +442,7 @@ public:
442
442
  SkPaint shadowPaint;
443
443
  shadowPaint.setAntiAlias(true);
444
444
  shadowPaint.setColor(shadow.color.value_or(SK_ColorBLACK));
445
- shadowPaint.setAlphaf(opacity);
445
+ shadowPaint.setAlphaf(opacity * shadowPaint.getAlphaf());
446
446
  shadowPaint.setMaskFilter(SkMaskFilter::MakeBlur(
447
447
  SkBlurStyle::kNormal_SkBlurStyle, shadow.blur, true));
448
448
 
@@ -637,6 +637,16 @@ public:
637
637
  }
638
638
 
639
639
  void draw(DrawingCtx *ctx) {
640
+ // Validate colors array has exactly 4 colors if provided
641
+ if (props.colors.has_value() && props.colors.value().size() != 4) {
642
+ throw std::invalid_argument("Colors array for patch must have exactly 4 colors");
643
+ }
644
+
645
+ // Validate texture array has exactly 4 points if provided
646
+ if (props.texture.has_value() && props.texture.value().size() != 4) {
647
+ throw std::invalid_argument("Texture coordinates array for patch must have exactly 4 points");
648
+ }
649
+
640
650
  // Determine default blend mode based on presence of colors
641
651
  SkBlendMode defaultBlendMode = props.colors.has_value()
642
652
  ? SkBlendMode::kDstOver
@@ -676,6 +686,15 @@ public:
676
686
  }
677
687
 
678
688
  void draw(DrawingCtx *ctx) {
689
+ // Validate array sizes
690
+ if (props.colors.has_value() && props.colors.value().size() != props.vertices.size()) {
691
+ throw std::invalid_argument("Colors array must have the same size as vertices array");
692
+ }
693
+
694
+ if (props.textures.has_value() && props.textures.value().size() != props.vertices.size()) {
695
+ throw std::invalid_argument("Textures array must have the same size as vertices array");
696
+ }
697
+
679
698
  // Create vertices using MakeCopy
680
699
  auto vertices = SkVertices::MakeCopy(
681
700
  props.mode, static_cast<int>(props.vertices.size()),
@@ -909,6 +928,16 @@ public:
909
928
 
910
929
  void draw(DrawingCtx *ctx) {
911
930
  if (props.image) {
931
+ // Validate transforms and sprites have the same size
932
+ if (props.transforms.size() != props.sprites.size()) {
933
+ throw std::invalid_argument("transforms and sprites arrays must have the same length");
934
+ }
935
+
936
+ // Validate colors array matches if provided
937
+ if (props.colors.has_value() && props.colors.value().size() != props.transforms.size()) {
938
+ throw std::invalid_argument("colors array must have the same length as transforms/sprites");
939
+ }
940
+
912
941
  auto colors =
913
942
  props.colors.has_value() ? props.colors.value().data() : nullptr;
914
943
  auto blendMode = props.blendMode.value_or(SkBlendMode::kDstOver);
@@ -239,6 +239,16 @@ public:
239
239
  }
240
240
 
241
241
  void pushShader(DrawingCtx *ctx) {
242
+ // Validate colors array has at least 2 colors
243
+ if (props.colors.size() < 2) {
244
+ throw std::invalid_argument("Colors array must have at least 2 colors");
245
+ }
246
+
247
+ // Validate positions array matches colors array in size
248
+ if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
249
+ throw std::invalid_argument("Positions array must have the same size as colors array");
250
+ }
251
+
242
252
  SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
243
253
  const SkPoint pts[2] = {props.start, props.end};
244
254
  auto shader = SkGradientShader::MakeLinear(
@@ -276,6 +286,16 @@ public:
276
286
  }
277
287
 
278
288
  void pushShader(DrawingCtx *ctx) {
289
+ // Validate colors array has at least 2 colors
290
+ if (props.colors.size() < 2) {
291
+ throw std::invalid_argument("Colors array must have at least 2 colors");
292
+ }
293
+
294
+ // Validate positions array matches colors array in size
295
+ if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
296
+ throw std::invalid_argument("Positions array must have the same size as colors array");
297
+ }
298
+
279
299
  SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
280
300
  auto shader = SkGradientShader::MakeRadial(
281
301
  props.center, props.radius, props.colors.data(),
@@ -314,6 +334,16 @@ public:
314
334
  }
315
335
 
316
336
  void pushShader(DrawingCtx *ctx) {
337
+ // Validate colors array has at least 2 colors
338
+ if (props.colors.size() < 2) {
339
+ throw std::invalid_argument("Colors array must have at least 2 colors");
340
+ }
341
+
342
+ // Validate positions array matches colors array in size
343
+ if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
344
+ throw std::invalid_argument("Positions array must have the same size as colors array");
345
+ }
346
+
317
347
  SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
318
348
  auto shader = SkGradientShader::MakeSweep(
319
349
  props.center.x(), props.center.y(), props.colors.data(),
@@ -355,6 +385,16 @@ public:
355
385
  }
356
386
 
357
387
  void pushShader(DrawingCtx *ctx) {
388
+ // Validate colors array has at least 2 colors
389
+ if (props.colors.size() < 2) {
390
+ throw std::invalid_argument("Colors array must have at least 2 colors");
391
+ }
392
+
393
+ // Validate positions array matches colors array in size
394
+ if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
395
+ throw std::invalid_argument("Positions array must have the same size as colors array");
396
+ }
397
+
358
398
  SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
359
399
  auto shader = SkGradientShader::MakeTwoPointConical(
360
400
  props.start, props.startRadius, props.end, props.endRadius,
@@ -784,12 +784,46 @@ public:
784
784
  *
785
785
  * As such, future decoding calls may require a rewind.
786
786
  *
787
- * For still (non-animated) image codecs, this will return 0.
787
+ * `getRepetitionCount` will return `0` in two cases:
788
+ * 1. Still (non-animated) images.
789
+ * 2. Animated images that only play the animation once (i.e. that don't
790
+ * repeat the animation)
791
+ * `isAnimated` can be used to disambiguate between these two cases.
788
792
  */
789
793
  int getRepetitionCount() {
790
794
  return this->onGetRepetitionCount();
791
795
  }
792
796
 
797
+ /**
798
+ * `isAnimated` returns whether the full input is expected to contain an
799
+ * animated image (i.e. more than 1 image frame). This can be used to
800
+ * disambiguate the meaning of `getRepetitionCount` returning `0` (see
801
+ * `getRepetitionCount`'s doc comment for more details).
802
+ *
803
+ * Note that in some codecs `getFrameCount()` only returns the number of
804
+ * frames for which all the metadata has been already successfully decoded.
805
+ * Therefore for a partial input `isAnimated()` may return "yes", even
806
+ * though `getFrameCount()` may temporarily return `1` until more of the
807
+ * input is available.
808
+ *
809
+ * When handling partial input, some codecs may not know until later (e.g.
810
+ * until encountering additional image frames) whether the given image has
811
+ * more than one frame. Such codecs may initially return
812
+ * `IsAnimated::kUnknown` and only later give a definitive "yes" or "no"
813
+ * answer. GIF format is one example where this may happen.
814
+ *
815
+ * Other codecs may be able to decode the information from the metadata
816
+ * present before the first image frame. Such codecs should be able to give
817
+ * a definitive "yes" or "no" answer as soon as they are constructed. PNG
818
+ * format is one example where this happens.
819
+ */
820
+ enum class IsAnimated {
821
+ kYes,
822
+ kNo,
823
+ kUnknown,
824
+ };
825
+ IsAnimated isAnimated() { return this->onIsAnimated(); }
826
+
793
827
  // Register a decoder at runtime by passing two function pointers:
794
828
  // - peek() to return true if the span of bytes appears to be your encoded format;
795
829
  // - make() to attempt to create an SkCodec from the given stream.
@@ -937,6 +971,10 @@ protected:
937
971
  return 0;
938
972
  }
939
973
 
974
+ virtual IsAnimated onIsAnimated() {
975
+ return IsAnimated::kNo;
976
+ }
977
+
940
978
  private:
941
979
  const SkEncodedInfo fEncodedInfo;
942
980
  XformFormat fSrcXformFormat;
@@ -80,16 +80,6 @@
80
80
  */
81
81
  //#define SK_CANVAS_SAVE_RESTORE_PREALLOC_COUNT 32
82
82
 
83
- /* Determines whether to build code that supports the Ganesh GPU backend. Some classes
84
- that are not GPU-specific, such as SkShader subclasses, have optional code
85
- that is used allows them to interact with this GPU backend. If you'd like to
86
- include this code, include -DSK_GANESH in your cflags or uncomment below.
87
- Defaults to not set (No Ganesh GPU backend).
88
- This define affects the ABI of Skia, so make sure it matches the client which uses
89
- the compiled version of Skia.
90
- */
91
- //#define SK_GANESH
92
-
93
83
  /* Skia makes use of histogram logging macros to trace the frequency of
94
84
  events. By default, Skia provides no-op versions of these macros.
95
85
  Skia consumers can provide their own definitions of these macros to
@@ -99,6 +89,7 @@
99
89
  //#define SK_HISTOGRAM_ENUMERATION(name, sampleEnum, enumSize)
100
90
  //#define SK_HISTOGRAM_EXACT_LINEAR(name, sample, valueMax)
101
91
  //#define SK_HISTOGRAM_MEMORY_KB(name, sample)
92
+ //#define SK_HISTOGRAM_CUSTOM_COUNTS(name, sample, countMin, countMax, bucketCount)
102
93
  //#define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
103
94
 
104
95
  /*
@@ -54,6 +54,7 @@ class GrRecordingContext;
54
54
 
55
55
  class SkBitmap;
56
56
  class SkBlender;
57
+ class SkBlurMaskFilterImpl;
57
58
  class SkColorSpace;
58
59
  class SkData;
59
60
  class SkDevice;
@@ -2679,11 +2680,14 @@ private:
2679
2680
  // into the canvas' global space.
2680
2681
  SkRect computeDeviceClipBounds(bool outsetForAA=true) const;
2681
2682
 
2682
- // Attempt to draw a rrect with an analytic blur. If the paint does not contain a blur, or the
2683
- // geometry can't be drawn with an analytic blur by the device, a layer is returned for a
2684
- // regular draw. If the draw succeeds or predrawNotify fails, nullopt is returned indicating
2685
- // that nothing further should be drawn.
2683
+ // Returns the paint's mask filter if it can be used to draw an rrect with an analytic blur, and
2684
+ // returns null otherwise.
2685
+ const SkBlurMaskFilterImpl* canAttemptBlurredRRectDraw(const SkPaint&) const;
2686
+
2687
+ // Attempt to draw a rrect with an analytic blur. If the draw succeeds or predrawNotify fails,
2688
+ // nullopt is returned indicating that nothing further should be drawn.
2686
2689
  std::optional<AutoLayerForImageFilter> attemptBlurredRRectDraw(const SkRRect&,
2690
+ const SkBlurMaskFilterImpl*,
2687
2691
  const SkPaint&,
2688
2692
  SkEnumBitMask<PredrawFlags>);
2689
2693
 
@@ -91,13 +91,13 @@ public:
91
91
  return *this;
92
92
  }
93
93
 
94
- bool operator==(const ForwardVerbIterator& other) {
94
+ bool operator==(const ForwardVerbIterator& other) const {
95
95
  SkASSERT(fSegments.data() != other.fSegments.data() ||
96
96
  fSegments.size() == other.fSegments.size());
97
97
  return fSegments.data() == other.fSegments.data();
98
98
  }
99
99
 
100
- bool operator!=(const ForwardVerbIterator& other) {
100
+ bool operator!=(const ForwardVerbIterator& other) const {
101
101
  return !((*this) == other);
102
102
  }
103
103
 
@@ -5,5 +5,5 @@
5
5
  * found in the LICENSE file.
6
6
  */
7
7
  #ifndef SK_MILESTONE
8
- #define SK_MILESTONE 134
8
+ #define SK_MILESTONE 136
9
9
  #endif
@@ -317,15 +317,18 @@ public:
317
317
  */
318
318
  SkScalar getStrokeMiter() const { return fMiterLimit; }
319
319
 
320
- /** Sets the limit at which a sharp corner is drawn beveled.
321
- Valid values are zero and greater.
322
- Has no effect if miter is less than zero.
320
+ /** When stroking a small joinAngle with miter, the miterLength may be very long.
321
+ When miterLength > maxMiterLength (or joinAngle < minJoinAngle) the join will become bevel.
322
+ miterLimit = maxMiterLength / strokeWidth or miterLimit = 1 / sin(minJoinAngle / 2).
323
323
 
324
- @param miter zero and greater miter limit
324
+ This call has no effect if the miterLimit passed is less than zero.
325
+ Values less than one will be treated as bevel.
326
+
327
+ @param miterLimit zero and greater miter limit
325
328
 
326
329
  example: https://fiddle.skia.org/c/@Paint_setStrokeMiter
327
330
  */
328
- void setStrokeMiter(SkScalar miter);
331
+ void setStrokeMiter(SkScalar miterLimit);
329
332
 
330
333
  /** \enum SkPaint::Cap
331
334
  Cap draws at the beginning and end of an open path contour.
@@ -79,10 +79,12 @@ public:
79
79
  [[nodiscard]] bool readS8(int8_t*);
80
80
  [[nodiscard]] bool readS16(int16_t*);
81
81
  [[nodiscard]] bool readS32(int32_t*);
82
+ [[nodiscard]] bool readS64(int64_t*);
82
83
 
83
- [[nodiscard]] bool readU8(uint8_t* i) { return this->readS8((int8_t*)i); }
84
+ [[nodiscard]] bool readU8(uint8_t* i) { return this->readS8((int8_t*)i); }
84
85
  [[nodiscard]] bool readU16(uint16_t* i) { return this->readS16((int16_t*)i); }
85
86
  [[nodiscard]] bool readU32(uint32_t* i) { return this->readS32((int32_t*)i); }
87
+ [[nodiscard]] bool readU64(uint64_t* i) { return this->readS64((int64_t*)i); }
86
88
 
87
89
  [[nodiscard]] bool readBool(bool* b) {
88
90
  uint8_t i;
@@ -240,8 +242,11 @@ public:
240
242
  uint16_t v = SkToU16(value);
241
243
  return this->write(&v, 2);
242
244
  }
243
- bool write32(uint32_t v) {
244
- return this->write(&v, 4);
245
+ bool write32(uint32_t value) {
246
+ return this->write(&value, 4);
247
+ }
248
+ bool write64(uint64_t value) {
249
+ return this->write(&value, 8);
245
250
  }
246
251
 
247
252
  bool writeText(const char text[]) {
@@ -209,13 +209,13 @@ public:
209
209
  class SK_API Iter {
210
210
  public:
211
211
  struct Run {
212
- SkTypeface* fTypeface;
213
- int fGlyphCount;
214
- const uint16_t* fGlyphIndices;
212
+ SkTypeface* fTypeface;
213
+ int fGlyphCount;
214
+ const SkGlyphID* fGlyphIndices;
215
215
  #ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
216
216
  const uint32_t* fClusterIndex_forTest;
217
- int fUtf8Size_forTest;
218
- const char* fUtf8_forTest;
217
+ int fUtf8Size_forTest;
218
+ const char* fUtf8_forTest;
219
219
  #endif
220
220
  };
221
221
 
@@ -229,10 +229,10 @@ public:
229
229
 
230
230
  // Experimental, DO NO USE, will change/go-away
231
231
  struct ExperimentalRun {
232
- SkFont font;
233
- int count;
234
- const uint16_t* glyphs;
235
- const SkPoint* positions;
232
+ SkFont font;
233
+ int count;
234
+ const SkGlyphID* glyphs;
235
+ const SkPoint* positions;
236
236
  };
237
237
  bool experimentalNext(ExperimentalRun*);
238
238
 
@@ -366,12 +366,10 @@ protected:
366
366
  virtual bool onGetFixedPitch() const; // TODO: = 0;
367
367
 
368
368
  // Must return a valid scaler context. It can not return nullptr.
369
- virtual std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
370
- const SkDescriptor*) const = 0;
369
+ virtual std::unique_ptr<SkScalerContext> onCreateScalerContext(
370
+ const SkScalerContextEffects&, const SkDescriptor*) const = 0;
371
371
  virtual std::unique_ptr<SkScalerContext> onCreateScalerContextAsProxyTypeface
372
- (const SkScalerContextEffects&,
373
- const SkDescriptor*,
374
- sk_sp<SkTypeface>) const;
372
+ (const SkScalerContextEffects&, const SkDescriptor*, SkTypeface* proxyTypeface) const;
375
373
  virtual void onFilterRec(SkScalerContextRec*) const = 0;
376
374
  friend class SkScalerContext; // onFilterRec
377
375
 
@@ -442,8 +440,8 @@ private:
442
440
  friend class SkRandomTypeface; // getAdvancedMetrics
443
441
  friend class SkPDFFont; // getAdvancedMetrics
444
442
  friend class SkTypeface_proxy;
445
-
446
443
  friend class SkFontPriv; // getGlyphToUnicodeMap
444
+ friend void TestSkTypefaceGlyphToUnicodeMap(SkTypeface&, SkUnichar*);
447
445
 
448
446
  private:
449
447
  SkTypefaceID fUniqueID;
@@ -97,6 +97,7 @@
97
97
  defined(SK_HISTOGRAM_BOOLEAN) || \
98
98
  defined(SK_HISTOGRAM_EXACT_LINEAR) || \
99
99
  defined(SK_HISTOGRAM_MEMORY_KB) || \
100
+ defined(SK_HISTOGRAM_CUSTOM_COUNTS)|| \
100
101
  defined(SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES)
101
102
  # define SK_HISTOGRAMS_ENABLED 1
102
103
  #else
@@ -119,6 +120,10 @@
119
120
  # define SK_HISTOGRAM_MEMORY_KB(name, sample)
120
121
  #endif
121
122
 
123
+ #ifndef SK_HISTOGRAM_CUSTOM_COUNTS
124
+ # define SK_HISTOGRAM_CUSTOM_COUNTS(name, sample, countMin, countMax, bucketCount)
125
+ #endif
126
+
122
127
  #ifndef SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES
123
128
  # define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
124
129
  #endif
@@ -16,9 +16,12 @@
16
16
  #include <vector>
17
17
 
18
18
  class SkCanvas;
19
+ class SkCodec;
20
+ class SkData;
19
21
  class SkExecutor;
20
22
  class SkPDFArray;
21
23
  class SkPDFStructTree;
24
+ class SkPixmap;
22
25
  class SkWStream;
23
26
 
24
27
  #define SKPDF_STRING(X) SKPDF_STRING_IMPL(X)
@@ -80,6 +83,9 @@ struct DateTime {
80
83
  void toISO8601(SkString* dst) const;
81
84
  };
82
85
 
86
+ using DecodeJpegCallback = std::unique_ptr<SkCodec> (*)(sk_sp<SkData>);
87
+ using EncodeJpegCallback = bool (*)(SkWStream* dst, const SkPixmap& src, int quality);
88
+
83
89
  /** Optional metadata to be passed into the PDF factory function.
84
90
  */
85
91
  struct Metadata {
@@ -157,6 +163,7 @@ struct Metadata {
157
163
  enum class Outline : int {
158
164
  None = 0,
159
165
  StructureElementHeaders = 1,
166
+ StructureElements = 2,
160
167
  } fOutline = Outline::None;
161
168
 
162
169
  /** Executor to handle threaded work within PDF Backend. If this is nullptr,
@@ -186,14 +193,50 @@ struct Metadata {
186
193
  enum Subsetter {
187
194
  kHarfbuzz_Subsetter,
188
195
  } fSubsetter = kHarfbuzz_Subsetter;
196
+
197
+ /** Clients can provide a way to decode jpeg. To use Skia's JPEG decoder, pass in
198
+ SkJpegDecoder::Decode. If not supplied, all images will need to be re-encoded
199
+ as jpegs or deflated images before embedding. If supplied, Skia may be able to
200
+ skip the re-encoding step.
201
+ Skia's JPEG decoder can be used here.
202
+ */
203
+ SkPDF::DecodeJpegCallback jpegDecoder = nullptr;
204
+
205
+ /** Clients can provide a way to encode jpeg. If not supplied, images will be embedded
206
+ as a deflated image, potentially making them much larger. If clients provide
207
+ their own implementation, JPEGs should be encoded to RGB (not YUV) otherwise they
208
+ will have the wrong surrounding metadata provided by Skia.
209
+ Skia's JPEG encoder can be used here.
210
+ */
211
+ SkPDF::EncodeJpegCallback jpegEncoder = nullptr;
212
+
213
+ // Skia's PDF support depends on having both a jpeg encoder and decoder for writing
214
+ // compact PDFs. It will technically work, but produce larger than optimal PDFs
215
+ // if either the decoder or encoder are left as nullptr. If clients will be creating
216
+ // PDFs that don't use images or otherwise want to incur this cost (with the upside
217
+ // of not having a jpeg library), they should set this to true to avoid an internal
218
+ // assert from firing.
219
+ bool allowNoJpegs = false;
189
220
  };
190
221
 
222
+ namespace NodeID {
223
+ static const constexpr int Nothing = 0;
224
+ static const constexpr int OtherArtifact = -1;
225
+ static const constexpr int PaginationArtifact = -2;
226
+ static const constexpr int PaginationHeaderArtifact = -3;
227
+ static const constexpr int PaginationFooterArtifact = -4;
228
+ static const constexpr int PaginationWatermarkArtifact = -5;
229
+ static const constexpr int LayoutArtifact = -6;
230
+ static const constexpr int PageArtifact = -7;
231
+ static const constexpr int BackgroundArtifact = -8;
232
+ } // namespace NodeID
233
+
191
234
  /** Associate a node ID with subsequent drawing commands in an
192
235
  SkCanvas. The same node ID can appear in a StructureElementNode
193
236
  in order to associate a document's structure element tree with
194
237
  its content.
195
238
 
196
- A node ID of zero indicates no node ID.
239
+ A node ID of zero indicates no node ID. Negative node IDs are reserved.
197
240
 
198
241
  @param canvas The canvas used to draw to the PDF.
199
242
  @param nodeId The node ID for subsequent drawing commands.
@@ -207,15 +250,17 @@ SK_API void SetNodeId(SkCanvas* dst, int nodeID);
207
250
  @param stream A PDF document will be written to this stream. The document may write
208
251
  to the stream at anytime during its lifetime, until either close() is
209
252
  called or the document is deleted.
210
- @param metadata a PDFmetadata object. Any fields may be left empty.
253
+ @param metadata a PDFmetadata object. Some fields may be left empty.
211
254
 
212
255
  @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument.
213
256
  */
214
257
  SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata);
215
258
 
259
+ #if !defined(SK_DISABLE_LEGACY_PDF_JPEG)
216
260
  static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) {
217
261
  return MakeDocument(stream, Metadata());
218
262
  }
263
+ #endif
219
264
 
220
265
  } // namespace SkPDF
221
266