@apollohg/react-native-rich-text-editor 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (494) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +259 -0
  3. package/RUST-STANDARD-LIBRARY-NOTICES.html +8266 -0
  4. package/ReactNativeProseEditor.podspec +59 -0
  5. package/THIRD_PARTY_NOTICES.md +31155 -0
  6. package/android/build.gradle +188 -0
  7. package/android/consumer-rules.pro +18 -0
  8. package/android/expo/build.gradle +17 -0
  9. package/android/src/debug/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +7 -0
  10. package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
  11. package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
  12. package/android/src/main/java/com/apollohg/editor/AndroidApiCompat.kt +19 -0
  13. package/android/src/main/java/com/apollohg/editor/AndroidCollaborationTransport.kt +860 -0
  14. package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +91 -0
  15. package/android/src/main/java/com/apollohg/editor/CodeHighlighting.kt +141 -0
  16. package/android/src/main/java/com/apollohg/editor/DecodedBitmapBudget.kt +250 -0
  17. package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +133 -0
  18. package/android/src/main/java/com/apollohg/editor/EditorBlockSpacing.kt +51 -0
  19. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawable.kt +16 -0
  20. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawing.kt +234 -0
  21. package/android/src/main/java/com/apollohg/editor/EditorCheckboxSpan.kt +87 -0
  22. package/android/src/main/java/com/apollohg/editor/EditorCodeHighlighting.kt +120 -0
  23. package/android/src/main/java/com/apollohg/editor/EditorDecorationLayer.java +18 -0
  24. package/android/src/main/java/com/apollohg/editor/EditorDocumentLayout.kt +626 -0
  25. package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +1042 -0
  26. package/android/src/main/java/com/apollohg/editor/EditorEditTextAnnotations.kt +191 -0
  27. package/android/src/main/java/com/apollohg/editor/EditorEditTextCaret.kt +100 -0
  28. package/android/src/main/java/com/apollohg/editor/EditorEditTextClipboard.kt +101 -0
  29. package/android/src/main/java/com/apollohg/editor/EditorEditTextComposition.kt +220 -0
  30. package/android/src/main/java/com/apollohg/editor/EditorEditTextConfiguration.kt +316 -0
  31. package/android/src/main/java/com/apollohg/editor/EditorEditTextCorrection.kt +303 -0
  32. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeferredUpdates.kt +327 -0
  33. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeletion.kt +258 -0
  34. package/android/src/main/java/com/apollohg/editor/EditorEditTextDiagnostics.kt +83 -0
  35. package/android/src/main/java/com/apollohg/editor/EditorEditTextDragDrop.kt +67 -0
  36. package/android/src/main/java/com/apollohg/editor/EditorEditTextExternalComposition.kt +357 -0
  37. package/android/src/main/java/com/apollohg/editor/EditorEditTextHardwareInput.kt +277 -0
  38. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +280 -0
  39. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputLifecycle.kt +183 -0
  40. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputPreparation.kt +79 -0
  41. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputTraits.kt +384 -0
  42. package/android/src/main/java/com/apollohg/editor/EditorEditTextLayout.kt +100 -0
  43. package/android/src/main/java/com/apollohg/editor/EditorEditTextNativeMutation.kt +243 -0
  44. package/android/src/main/java/com/apollohg/editor/EditorEditTextPlaceholder.kt +154 -0
  45. package/android/src/main/java/com/apollohg/editor/EditorEditTextRenderPatch.kt +347 -0
  46. package/android/src/main/java/com/apollohg/editor/EditorEditTextRendering.kt +313 -0
  47. package/android/src/main/java/com/apollohg/editor/EditorEditTextRustCommands.kt +281 -0
  48. package/android/src/main/java/com/apollohg/editor/EditorEditTextSelection.kt +352 -0
  49. package/android/src/main/java/com/apollohg/editor/EditorEditTextState.kt +113 -0
  50. package/android/src/main/java/com/apollohg/editor/EditorEditTextTaskMarkers.kt +92 -0
  51. package/android/src/main/java/com/apollohg/editor/EditorEditTextTextCommit.kt +327 -0
  52. package/android/src/main/java/com/apollohg/editor/EditorEditTextToolbar.kt +84 -0
  53. package/android/src/main/java/com/apollohg/editor/EditorEditTextUpdates.kt +245 -0
  54. package/android/src/main/java/com/apollohg/editor/EditorGlyphHeightCursorDrawable.kt +42 -0
  55. package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +13 -0
  56. package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +923 -0
  57. package/android/src/main/java/com/apollohg/editor/EditorInputCoordinates.kt +191 -0
  58. package/android/src/main/java/com/apollohg/editor/EditorInputCorrection.kt +107 -0
  59. package/android/src/main/java/com/apollohg/editor/EditorInputCursorGeometry.kt +128 -0
  60. package/android/src/main/java/com/apollohg/editor/EditorInputSnapshots.kt +134 -0
  61. package/android/src/main/java/com/apollohg/editor/EditorInputSurroundingDeletion.kt +321 -0
  62. package/android/src/main/java/com/apollohg/editor/EditorKeyboardToolbarView.kt +851 -0
  63. package/android/src/main/java/com/apollohg/editor/EditorMentionStyle.kt +192 -0
  64. package/android/src/main/java/com/apollohg/editor/EditorReconciliationWatcher.kt +46 -0
  65. package/android/src/main/java/com/apollohg/editor/EditorStyleSheet.kt +303 -0
  66. package/android/src/main/java/com/apollohg/editor/EditorStyleSheetSpans.kt +253 -0
  67. package/android/src/main/java/com/apollohg/editor/EditorSurfaceInputConnection.kt +67 -0
  68. package/android/src/main/java/com/apollohg/editor/EditorTextDecorationDrawing.kt +143 -0
  69. package/android/src/main/java/com/apollohg/editor/EditorTextSurface.kt +712 -0
  70. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceDragDrop.kt +94 -0
  71. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceInteraction.kt +708 -0
  72. package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +650 -0
  73. package/android/src/main/java/com/apollohg/editor/EditorV2Adapter.kt +912 -0
  74. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterMutations.kt +402 -0
  75. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterRendering.kt +123 -0
  76. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterSelection.kt +203 -0
  77. package/android/src/main/java/com/apollohg/editor/EditorV2Backend.kt +120 -0
  78. package/android/src/main/java/com/apollohg/editor/EditorV2Driver.kt +87 -0
  79. package/android/src/main/java/com/apollohg/editor/EditorV2Registry.kt +97 -0
  80. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +409 -0
  81. package/android/src/main/java/com/apollohg/editor/ExpoAutoGrowStyleSizePublisher.kt +34 -0
  82. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +266 -0
  83. package/android/src/main/java/com/apollohg/editor/ImeTextCoordinateMapper.kt +102 -0
  84. package/android/src/main/java/com/apollohg/editor/KeyboardToolbarImeAnimationController.kt +101 -0
  85. package/android/src/main/java/com/apollohg/editor/MentionSuggestionChipView.kt +234 -0
  86. package/android/src/main/java/com/apollohg/editor/NativeCollaborationTransportRegistry.kt +493 -0
  87. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +813 -0
  88. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewAtoms.kt +68 -0
  89. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewBinding.kt +126 -0
  90. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewDiagnostics.kt +208 -0
  91. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewErrors.kt +146 -0
  92. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewEvents.kt +150 -0
  93. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewExternalComposition.kt +39 -0
  94. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewFocus.kt +176 -0
  95. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewLifecycle.kt +302 -0
  96. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewMentions.kt +259 -0
  97. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewNativeActions.kt +179 -0
  98. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewOutsideTap.kt +214 -0
  99. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPendingUpdates.kt +376 -0
  100. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewProperties.kt +234 -0
  101. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPropertyRetries.kt +197 -0
  102. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewToolbar.kt +285 -0
  103. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewTypes.kt +28 -0
  104. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewUpdates.kt +271 -0
  105. package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +687 -0
  106. package/android/src/main/java/com/apollohg/editor/NativeEditorOutsideTapDispatcher.kt +380 -0
  107. package/android/src/main/java/com/apollohg/editor/NativeEditorV2Numbers.kt +45 -0
  108. package/android/src/main/java/com/apollohg/editor/NativeEditorViewRegistry.kt +372 -0
  109. package/android/src/main/java/com/apollohg/editor/NativeImagePipeline.kt +22 -0
  110. package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +193 -0
  111. package/android/src/main/java/com/apollohg/editor/NativeToolbarIcons.kt +177 -0
  112. package/android/src/main/java/com/apollohg/editor/NativeToolbarItem.kt +274 -0
  113. package/android/src/main/java/com/apollohg/editor/OkHttpCollaborationSocket.kt +102 -0
  114. package/android/src/main/java/com/apollohg/editor/OrderedListMarkerFormatter.kt +130 -0
  115. package/android/src/main/java/com/apollohg/editor/PointerTransparentView.java +18 -0
  116. package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +128 -0
  117. package/android/src/main/java/com/apollohg/editor/ProseViewerView.kt +854 -0
  118. package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +314 -0
  119. package/android/src/main/java/com/apollohg/editor/RenderBlockSpans.kt +314 -0
  120. package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +224 -0
  121. package/android/src/main/java/com/apollohg/editor/RenderBridgeBlockStyles.kt +407 -0
  122. package/android/src/main/java/com/apollohg/editor/RenderBridgeElements.kt +544 -0
  123. package/android/src/main/java/com/apollohg/editor/RenderBridgeInlineAndAtoms.kt +631 -0
  124. package/android/src/main/java/com/apollohg/editor/RenderBridgeParagraphs.kt +215 -0
  125. package/android/src/main/java/com/apollohg/editor/RenderImageDecoder.kt +748 -0
  126. package/android/src/main/java/com/apollohg/editor/RenderImageLoader.kt +900 -0
  127. package/android/src/main/java/com/apollohg/editor/RenderLayoutConstants.kt +117 -0
  128. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +337 -0
  129. package/android/src/main/java/com/apollohg/editor/RenderParagraphSpans.kt +182 -0
  130. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +951 -0
  131. package/android/src/main/java/com/apollohg/editor/SharedNativeImagePipeline.kt +78 -0
  132. package/android/src/main/java/com/apollohg/editor/UniffiEditorV2Backend.kt +261 -0
  133. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1656 -0
  134. package/android/src/main/java/com/apollohg/editor/viewer/FabricAttachmentSidecars.kt +80 -0
  135. package/android/src/main/java/com/apollohg/editor/viewer/FabricLeaseHandleBridge.kt +59 -0
  136. package/android/src/main/java/com/apollohg/editor/viewer/FallbackSelectionGeometry.kt +450 -0
  137. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseDrawingView.kt +678 -0
  138. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseInstrumentation.kt +608 -0
  139. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayout.kt +186 -0
  140. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutCache.kt +393 -0
  141. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutRegistry.kt +828 -0
  142. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseTheme.kt +316 -0
  143. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerManager.kt +900 -0
  144. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerPackage.kt +16 -0
  145. package/android/src/main/java/com/apollohg/editor/viewer/PreparedViewerAtoms.kt +89 -0
  146. package/android/src/main/java/com/apollohg/editor/viewer/ViewerCodeHighlighting.kt +91 -0
  147. package/android/src/main/java/com/apollohg/editor/viewer/ViewerDocument.kt +453 -0
  148. package/android/src/main/java/com/apollohg/editor/viewer/ViewerFontEnvironment.kt +282 -0
  149. package/android/src/main/java/com/apollohg/editor/viewer/ViewerImagePipeline.kt +460 -0
  150. package/android/src/main/jni/CMakeLists.txt +85 -0
  151. package/android/src/main/jni/PreparedProseViewerMeasurementsManager.cpp +334 -0
  152. package/android/src/main/jni/ReactNativeProseEditorSpec.h +17 -0
  153. package/android/src/main/jni/reactnativeproseeditor.h +6 -0
  154. package/android/src/main/res/values/attrs.xml +6 -0
  155. package/android/src/release/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +9 -0
  156. package/app.plugin.js +62 -0
  157. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseMeasurementsManager.h +62 -0
  158. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerComponentDescriptor.h +30 -0
  159. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.cpp +192 -0
  160. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.h +46 -0
  161. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerState.h +145 -0
  162. package/dist/AtomHost.d.ts +17 -0
  163. package/dist/AtomHost.js +135 -0
  164. package/dist/DefaultAtomChip.d.ts +2 -0
  165. package/dist/DefaultAtomChip.js +22 -0
  166. package/dist/EditorAddon.d.ts +32 -0
  167. package/dist/EditorAddon.js +29 -0
  168. package/dist/EditorAddonNormalization.d.ts +6 -0
  169. package/dist/EditorAddonNormalization.js +48 -0
  170. package/dist/EditorMentionThemeNormalization.d.ts +8 -0
  171. package/dist/EditorMentionThemeNormalization.js +22 -0
  172. package/dist/EditorMentionThemeValidation.d.ts +12 -0
  173. package/dist/EditorMentionThemeValidation.js +95 -0
  174. package/dist/EditorStyleSheet.d.ts +4 -0
  175. package/dist/EditorStyleSheet.js +10 -0
  176. package/dist/EditorStyleSheetNormalization.d.ts +3 -0
  177. package/dist/EditorStyleSheetNormalization.js +226 -0
  178. package/dist/EditorStyleSheetTypes.d.ts +151 -0
  179. package/dist/EditorStyleSheetTypes.js +2 -0
  180. package/dist/EditorTheme.d.ts +117 -0
  181. package/dist/EditorTheme.js +41 -0
  182. package/dist/EditorToolbar.d.ts +4 -0
  183. package/dist/EditorToolbar.js +17 -0
  184. package/dist/EditorToolbarComponent.d.ts +13 -0
  185. package/dist/EditorToolbarComponent.js +24 -0
  186. package/dist/EditorToolbarItems.d.ts +9 -0
  187. package/dist/EditorToolbarItems.js +58 -0
  188. package/dist/EditorToolbarRegistry.d.ts +59 -0
  189. package/dist/EditorToolbarRegistry.js +175 -0
  190. package/dist/EditorToolbarTypes.d.ts +273 -0
  191. package/dist/EditorToolbarTypes.js +2 -0
  192. package/dist/EditorToolbarVisuals.d.ts +154 -0
  193. package/dist/EditorToolbarVisuals.js +228 -0
  194. package/dist/EditorUpdateRevision.d.ts +8 -0
  195. package/dist/EditorUpdateRevision.js +22 -0
  196. package/dist/ExternalTextComposition.d.ts +45 -0
  197. package/dist/ExternalTextComposition.js +537 -0
  198. package/dist/ImageLoadingPolicy.d.ts +54 -0
  199. package/dist/ImageLoadingPolicy.js +60 -0
  200. package/dist/NativeEditorBoundaryError.d.ts +111 -0
  201. package/dist/NativeEditorBoundaryError.js +268 -0
  202. package/dist/NativeEditorBridge.d.ts +9 -0
  203. package/dist/NativeEditorBridge.js +37 -0
  204. package/dist/NativeEditorCollaborationTransport.d.ts +154 -0
  205. package/dist/NativeEditorCollaborationTransport.js +275 -0
  206. package/dist/NativeEditorCreateConfig.d.ts +16 -0
  207. package/dist/NativeEditorCreateConfig.js +249 -0
  208. package/dist/NativeEditorCreateJson.d.ts +76 -0
  209. package/dist/NativeEditorCreateJson.js +474 -0
  210. package/dist/NativeEditorCreateValidation.d.ts +32 -0
  211. package/dist/NativeEditorCreateValidation.js +150 -0
  212. package/dist/NativeEditorDocumentBridge.d.ts +72 -0
  213. package/dist/NativeEditorDocumentBridge.js +305 -0
  214. package/dist/NativeEditorDocumentHandle.d.ts +70 -0
  215. package/dist/NativeEditorDocumentHandle.js +89 -0
  216. package/dist/NativeEditorLocalAwareness.d.ts +34 -0
  217. package/dist/NativeEditorLocalAwareness.js +153 -0
  218. package/dist/NativeEditorNativeModule.d.ts +48 -0
  219. package/dist/NativeEditorNativeModule.js +34 -0
  220. package/dist/NativeEditorRenderNormalization.d.ts +22 -0
  221. package/dist/NativeEditorRenderNormalization.js +274 -0
  222. package/dist/NativeEditorResultNormalization.d.ts +108 -0
  223. package/dist/NativeEditorResultNormalization.js +400 -0
  224. package/dist/NativeEditorTypes.d.ts +318 -0
  225. package/dist/NativeEditorTypes.js +15 -0
  226. package/dist/NativeEditorV2Decimal.d.ts +5 -0
  227. package/dist/NativeEditorV2Decimal.js +18 -0
  228. package/dist/NativeProseViewer.d.ts +122 -0
  229. package/dist/NativeProseViewer.js +130 -0
  230. package/dist/NativeRichTextEditor.d.ts +3 -0
  231. package/dist/NativeRichTextEditor.js +6 -0
  232. package/dist/ResourceLimits.d.ts +100 -0
  233. package/dist/ResourceLimits.js +80 -0
  234. package/dist/RichTextEditor.d.ts +4 -0
  235. package/dist/RichTextEditor.js +25 -0
  236. package/dist/RichTextEditorNativeTypes.d.ts +122 -0
  237. package/dist/RichTextEditorNativeTypes.js +2 -0
  238. package/dist/RichTextEditorNativeView.d.ts +12 -0
  239. package/dist/RichTextEditorNativeView.js +15 -0
  240. package/dist/RichTextEditorSerialization.d.ts +53 -0
  241. package/dist/RichTextEditorSerialization.js +283 -0
  242. package/dist/RichTextEditorTypes.d.ts +281 -0
  243. package/dist/RichTextEditorTypes.js +2 -0
  244. package/dist/ViewerConfiguration.d.ts +22 -0
  245. package/dist/ViewerConfiguration.js +6 -0
  246. package/dist/YjsCollaboration.d.ts +146 -0
  247. package/dist/YjsCollaboration.js +496 -0
  248. package/dist/addons.d.ts +193 -0
  249. package/dist/addons.js +122 -0
  250. package/dist/atomConstants.d.ts +3 -0
  251. package/dist/atomConstants.js +6 -0
  252. package/dist/atomInstances.d.ts +35 -0
  253. package/dist/atomInstances.js +79 -0
  254. package/dist/atomPolicy.d.ts +4 -0
  255. package/dist/atomPolicy.js +47 -0
  256. package/dist/atomUpdates.d.ts +2 -0
  257. package/dist/atomUpdates.js +38 -0
  258. package/dist/atoms.d.ts +92 -0
  259. package/dist/atoms.js +222 -0
  260. package/dist/attributeValidation.d.ts +4 -0
  261. package/dist/attributeValidation.js +97 -0
  262. package/dist/contentExpression.d.ts +6 -0
  263. package/dist/contentExpression.js +335 -0
  264. package/dist/index.d.ts +21 -0
  265. package/dist/index.js +78 -0
  266. package/dist/listMarkers.d.ts +15 -0
  267. package/dist/listMarkers.js +21 -0
  268. package/dist/schemaDefinition.d.ts +143 -0
  269. package/dist/schemaDefinition.js +206 -0
  270. package/dist/schemaDocument.d.ts +17 -0
  271. package/dist/schemaDocument.js +69 -0
  272. package/dist/schemaDocumentConstruction.d.ts +5 -0
  273. package/dist/schemaDocumentConstruction.js +125 -0
  274. package/dist/schemaNormalization.d.ts +29 -0
  275. package/dist/schemaNormalization.js +313 -0
  276. package/dist/schemaPresets.d.ts +68 -0
  277. package/dist/schemaPresets.js +198 -0
  278. package/dist/schemaResolution.d.ts +9 -0
  279. package/dist/schemaResolution.js +211 -0
  280. package/dist/schemas.d.ts +5 -0
  281. package/dist/schemas.js +28 -0
  282. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +37 -0
  283. package/dist/specs/PreparedProseViewerNativeComponent.js +6 -0
  284. package/dist/useEditorToolbarInteractions.d.ts +12 -0
  285. package/dist/useEditorToolbarInteractions.js +218 -0
  286. package/dist/useEditorToolbarItems.d.ts +8 -0
  287. package/dist/useEditorToolbarItems.js +280 -0
  288. package/dist/useEditorToolbarPresentation.d.ts +4 -0
  289. package/dist/useEditorToolbarPresentation.js +203 -0
  290. package/dist/useEditorToolbarState.d.ts +63 -0
  291. package/dist/useEditorToolbarState.js +108 -0
  292. package/dist/useFocusPreservingFrames.d.ts +17 -0
  293. package/dist/useFocusPreservingFrames.js +108 -0
  294. package/dist/useNativeEditor.d.ts +66 -0
  295. package/dist/useNativeEditor.js +370 -0
  296. package/dist/useRichTextEditorCommands.d.ts +21 -0
  297. package/dist/useRichTextEditorCommands.js +299 -0
  298. package/dist/useRichTextEditorEvents.d.ts +18 -0
  299. package/dist/useRichTextEditorEvents.js +216 -0
  300. package/dist/useRichTextEditorMentions.d.ts +11 -0
  301. package/dist/useRichTextEditorMentions.js +316 -0
  302. package/dist/useRichTextEditorPresentation.d.ts +5 -0
  303. package/dist/useRichTextEditorPresentation.js +178 -0
  304. package/dist/useRichTextEditorState.d.ts +180 -0
  305. package/dist/useRichTextEditorState.js +405 -0
  306. package/dist/useRichTextEditorUpdates.d.ts +10 -0
  307. package/dist/useRichTextEditorUpdates.js +308 -0
  308. package/dist/useViewerAtoms.d.ts +38 -0
  309. package/dist/useViewerAtoms.js +288 -0
  310. package/expo-module.config.json +13 -0
  311. package/ios/EditorAddons.swift +354 -0
  312. package/ios/EditorCodeHighlighting.swift +184 -0
  313. package/ios/EditorCore.xcframework/Info.plist +44 -0
  314. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  315. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  316. package/ios/EditorInteractionOverlays.swift +697 -0
  317. package/ios/EditorLayoutManager.swift +971 -0
  318. package/ios/EditorNodeTypes.swift +37 -0
  319. package/ios/EditorStyleSheet.swift +461 -0
  320. package/ios/EditorTextView+AttributedPatch.swift +305 -0
  321. package/ios/EditorTextView+Binding.swift +61 -0
  322. package/ios/EditorTextView+Caret.swift +333 -0
  323. package/ios/EditorTextView+Commands.swift +203 -0
  324. package/ios/EditorTextView+Delegate.swift +65 -0
  325. package/ios/EditorTextView+Diagnostics.swift +225 -0
  326. package/ios/EditorTextView+DragDrop.swift +290 -0
  327. package/ios/EditorTextView+ExternalComposition.swift +364 -0
  328. package/ios/EditorTextView+Images.swift +354 -0
  329. package/ios/EditorTextView+InputTraits.swift +200 -0
  330. package/ios/EditorTextView+KeyboardInput.swift +318 -0
  331. package/ios/EditorTextView+Layout.swift +245 -0
  332. package/ios/EditorTextView+MarkedText.swift +267 -0
  333. package/ios/EditorTextView+NativeInputLifecycle.swift +372 -0
  334. package/ios/EditorTextView+NativeMutation.swift +471 -0
  335. package/ios/EditorTextView+Reconciliation.swift +97 -0
  336. package/ios/EditorTextView+RenderPatch.swift +573 -0
  337. package/ios/EditorTextView+Rendering.swift +539 -0
  338. package/ios/EditorTextView+Selection.swift +542 -0
  339. package/ios/EditorTextView.swift +953 -0
  340. package/ios/EditorTheme.swift +626 -0
  341. package/ios/EditorV2Adapter+Commands.swift +204 -0
  342. package/ios/EditorV2Adapter+Envelope.swift +238 -0
  343. package/ios/EditorV2Adapter+Mutation.swift +392 -0
  344. package/ios/EditorV2Adapter+Registry.swift +185 -0
  345. package/ios/EditorV2Adapter+RenderState.swift +360 -0
  346. package/ios/EditorV2Adapter+RenderValidation.swift +420 -0
  347. package/ios/EditorV2Adapter+Selection.swift +329 -0
  348. package/ios/EditorV2Adapter+TextCommands.swift +430 -0
  349. package/ios/EditorV2Adapter.swift +376 -0
  350. package/ios/EditorV2Shadow.swift +353 -0
  351. package/ios/Generated_editor_core.swift +2378 -0
  352. package/ios/NativeCodeHighlighting.swift +159 -0
  353. package/ios/NativeCollaborationSocket.swift +144 -0
  354. package/ios/NativeCollaborationTransport+Protocol.swift +258 -0
  355. package/ios/NativeCollaborationTransport+Socket.swift +379 -0
  356. package/ios/NativeCollaborationTransport+Validation.swift +103 -0
  357. package/ios/NativeCollaborationTransport.swift +322 -0
  358. package/ios/NativeCollaborationTransportRegistry.swift +521 -0
  359. package/ios/NativeEditorExpoView+AccessoryRetry.swift +219 -0
  360. package/ios/NativeEditorExpoView+Binding.swift +268 -0
  361. package/ios/NativeEditorExpoView+Diagnostics.swift +66 -0
  362. package/ios/NativeEditorExpoView+Events.swift +131 -0
  363. package/ios/NativeEditorExpoView+Focus.swift +169 -0
  364. package/ios/NativeEditorExpoView+MentionRetry.swift +288 -0
  365. package/ios/NativeEditorExpoView+Mentions.swift +288 -0
  366. package/ios/NativeEditorExpoView+Properties.swift +300 -0
  367. package/ios/NativeEditorExpoView+Toolbar.swift +86 -0
  368. package/ios/NativeEditorExpoView+Updates.swift +312 -0
  369. package/ios/NativeEditorExpoView.swift +349 -0
  370. package/ios/NativeEditorModule.swift +856 -0
  371. package/ios/NativeEditorViewRegistry.swift +226 -0
  372. package/ios/NativeToolbar+ButtonStyle.swift +214 -0
  373. package/ios/NativeToolbar+Buttons.swift +228 -0
  374. package/ios/NativeToolbar+Diagnostics.swift +114 -0
  375. package/ios/NativeToolbar+Menu.swift +101 -0
  376. package/ios/NativeToolbar+Models.swift +519 -0
  377. package/ios/NativeToolbar+Placeholder.swift +39 -0
  378. package/ios/NativeToolbar.swift +612 -0
  379. package/ios/OrderedListMarkerFormatter.swift +103 -0
  380. package/ios/PositionBridge.swift +596 -0
  381. package/ios/ProseViewerView.swift +462 -0
  382. package/ios/RenderBridge+Atoms.swift +288 -0
  383. package/ios/RenderBridge+Attachments.swift +246 -0
  384. package/ios/RenderBridge+BlockBoundaries.swift +313 -0
  385. package/ios/RenderBridge+Style.swift +343 -0
  386. package/ios/RenderBridge.swift +704 -0
  387. package/ios/RichTextEditorView.swift +930 -0
  388. package/ios/SharedNativeImagePipeline+Cache.swift +189 -0
  389. package/ios/SharedNativeImagePipeline+Transport.swift +328 -0
  390. package/ios/SharedNativeImagePipeline.swift +533 -0
  391. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +436 -0
  392. package/ios/Viewer/CoreTextProseLayoutEngine+Models.swift +322 -0
  393. package/ios/Viewer/CoreTextProseLayoutEngine.swift +635 -0
  394. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.h +4 -0
  395. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.mm +767 -0
  396. package/ios/Viewer/Fabric/PreparedProseMeasurementsManager.mm +118 -0
  397. package/ios/Viewer/NativeSVGImageDecoder.h +9 -0
  398. package/ios/Viewer/NativeSVGImageDecoder.mm +106 -0
  399. package/ios/Viewer/NativeSVGPreflight.h +11 -0
  400. package/ios/Viewer/NativeSVGPreflight.mm +219 -0
  401. package/ios/Viewer/PreparedProseDrawingView.swift +639 -0
  402. package/ios/Viewer/PreparedProseInstrumentation.swift +387 -0
  403. package/ios/Viewer/PreparedProseLayout.swift +326 -0
  404. package/ios/Viewer/PreparedProseLayoutCache.swift +766 -0
  405. package/ios/Viewer/PreparedProseLayoutRegistry+Artifacts.swift +377 -0
  406. package/ios/Viewer/PreparedProseLayoutRegistry+Fabric.swift +582 -0
  407. package/ios/Viewer/PreparedProseLayoutRegistry+FabricOwnership.swift +128 -0
  408. package/ios/Viewer/PreparedProseLayoutRegistry.swift +381 -0
  409. package/ios/Viewer/ViewerDocument.swift +575 -0
  410. package/ios/Viewer/ViewerFontEnvironment.swift +283 -0
  411. package/ios/Viewer/ViewerImagePipeline.swift +478 -0
  412. package/ios/editor_coreFFI/editor_coreFFI.h +1023 -0
  413. package/ios/editor_coreFFI/module.modulemap +7 -0
  414. package/package.json +151 -0
  415. package/react-native.config.js +17 -0
  416. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  417. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  418. package/rust/android/x86/libeditor_core.so +0 -0
  419. package/rust/android/x86_64/libeditor_core.so +0 -0
  420. package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +3146 -0
  421. package/src/AtomHost.tsx +180 -0
  422. package/src/DefaultAtomChip.tsx +27 -0
  423. package/src/EditorAddon.ts +65 -0
  424. package/src/EditorAddonNormalization.ts +49 -0
  425. package/src/EditorMentionThemeNormalization.ts +25 -0
  426. package/src/EditorMentionThemeValidation.ts +133 -0
  427. package/src/EditorStyleSheet.ts +9 -0
  428. package/src/EditorStyleSheetNormalization.ts +219 -0
  429. package/src/EditorStyleSheetTypes.ts +189 -0
  430. package/src/EditorTheme.ts +196 -0
  431. package/src/EditorToolbar.tsx +31 -0
  432. package/src/EditorToolbarComponent.tsx +23 -0
  433. package/src/EditorToolbarItems.tsx +64 -0
  434. package/src/EditorToolbarRegistry.tsx +254 -0
  435. package/src/EditorToolbarTypes.tsx +322 -0
  436. package/src/EditorToolbarVisuals.tsx +270 -0
  437. package/src/EditorUpdateRevision.ts +26 -0
  438. package/src/ExternalTextComposition.ts +658 -0
  439. package/src/ImageLoadingPolicy.ts +125 -0
  440. package/src/NativeEditorBoundaryError.ts +345 -0
  441. package/src/NativeEditorBridge.ts +93 -0
  442. package/src/NativeEditorCollaborationTransport.ts +493 -0
  443. package/src/NativeEditorCreateConfig.ts +326 -0
  444. package/src/NativeEditorCreateJson.ts +579 -0
  445. package/src/NativeEditorCreateValidation.ts +178 -0
  446. package/src/NativeEditorDocumentBridge.ts +485 -0
  447. package/src/NativeEditorDocumentHandle.ts +168 -0
  448. package/src/NativeEditorLocalAwareness.ts +168 -0
  449. package/src/NativeEditorNativeModule.ts +97 -0
  450. package/src/NativeEditorRenderNormalization.ts +320 -0
  451. package/src/NativeEditorResultNormalization.ts +469 -0
  452. package/src/NativeEditorTypes.ts +366 -0
  453. package/src/NativeEditorV2Decimal.ts +13 -0
  454. package/src/NativeProseViewer.tsx +356 -0
  455. package/src/NativeRichTextEditor.tsx +33 -0
  456. package/src/ResourceLimits.ts +187 -0
  457. package/src/RichTextEditor.tsx +27 -0
  458. package/src/RichTextEditorNativeTypes.tsx +144 -0
  459. package/src/RichTextEditorNativeView.tsx +21 -0
  460. package/src/RichTextEditorSerialization.tsx +381 -0
  461. package/src/RichTextEditorTypes.tsx +327 -0
  462. package/src/ViewerConfiguration.ts +23 -0
  463. package/src/YjsCollaboration.ts +692 -0
  464. package/src/addons.ts +311 -0
  465. package/src/atomConstants.ts +3 -0
  466. package/src/atomInstances.ts +123 -0
  467. package/src/atomPolicy.ts +47 -0
  468. package/src/atomUpdates.ts +52 -0
  469. package/src/atoms.ts +379 -0
  470. package/src/attributeValidation.ts +116 -0
  471. package/src/contentExpression.ts +338 -0
  472. package/src/index.ts +295 -0
  473. package/src/listMarkers.ts +18 -0
  474. package/src/schemaDefinition.ts +395 -0
  475. package/src/schemaDocument.ts +92 -0
  476. package/src/schemaDocumentConstruction.ts +148 -0
  477. package/src/schemaNormalization.ts +367 -0
  478. package/src/schemaPresets.ts +250 -0
  479. package/src/schemaResolution.ts +242 -0
  480. package/src/schemas.ts +43 -0
  481. package/src/specs/PreparedProseViewerNativeComponent.ts +40 -0
  482. package/src/useEditorToolbarInteractions.tsx +329 -0
  483. package/src/useEditorToolbarItems.tsx +390 -0
  484. package/src/useEditorToolbarPresentation.tsx +483 -0
  485. package/src/useEditorToolbarState.tsx +172 -0
  486. package/src/useFocusPreservingFrames.ts +171 -0
  487. package/src/useNativeEditor.ts +534 -0
  488. package/src/useRichTextEditorCommands.tsx +478 -0
  489. package/src/useRichTextEditorEvents.tsx +342 -0
  490. package/src/useRichTextEditorMentions.tsx +441 -0
  491. package/src/useRichTextEditorPresentation.tsx +563 -0
  492. package/src/useRichTextEditorState.tsx +620 -0
  493. package/src/useRichTextEditorUpdates.tsx +403 -0
  494. package/src/useViewerAtoms.tsx +427 -0
@@ -0,0 +1,533 @@
1
+ import CryptoKit
2
+ import ImageIO
3
+ import UIKit
4
+
5
+ final class RenderImageLoadOwner {
6
+ typealias Delivery = (@escaping () -> Void) -> Void
7
+ typealias Now = () -> TimeInterval
8
+ typealias TimeoutSchedule = (TimeInterval, @escaping () -> Void) -> ImageLoadingTask
9
+ final class ImageLoadReceipt {
10
+ private let lock = NSLock()
11
+ private var cancellation: (() -> Void)?
12
+
13
+ fileprivate init(cancellation: @escaping () -> Void) {
14
+ self.cancellation = cancellation
15
+ }
16
+
17
+ func cancel() {
18
+ lock.lock()
19
+ let cancellation = self.cancellation
20
+ self.cancellation = nil
21
+ lock.unlock()
22
+ cancellation?()
23
+ }
24
+ }
25
+
26
+ private struct Request {
27
+ let id: UUID
28
+ let source: String
29
+ let generation: UInt64
30
+ let deadline: TimeInterval
31
+ let completion: (UIImage?) -> Void
32
+ let onAcceptedStart: () -> Void
33
+ }
34
+
35
+ private final class ActiveRequest {
36
+ let request: Request
37
+ var task: ImageLoadingTask?
38
+
39
+ init(request: Request) {
40
+ self.request = request
41
+ }
42
+ }
43
+
44
+ private enum DeliveryState { case pending, running, cancelled, finished }
45
+
46
+ private final class DeliveryTicket {
47
+ // All transitions happen on stateQueue. Once a ticket is running, the
48
+ // callback owns delivery; cancellation suppresses pending tickets but
49
+ // never waits on arbitrary user code.
50
+ private var state: DeliveryState = .pending
51
+
52
+ func begin() -> Bool {
53
+ guard state == .pending else { return false }
54
+ state = .running
55
+ return true
56
+ }
57
+
58
+ func cancel() {
59
+ if state == .pending { state = .cancelled }
60
+ }
61
+
62
+ func finish() {
63
+ if state == .running { state = .finished }
64
+ }
65
+ }
66
+
67
+ struct DataURLHeaderScan {
68
+ let commaIndex: String.Index?
69
+ let scannedByteCount: Int
70
+ let exceededLimit: Bool
71
+ }
72
+
73
+ private static let contextKey = "com.apollohg.editor.image-load-owner"
74
+ private static let suppressKey = "com.apollohg.editor.suppress-image-loads"
75
+ private static let dataURLHeaderByteLimit = 256
76
+ private static let dataURLEncodedOverheadByteLimit = 4_096
77
+
78
+ private let stateQueue = DispatchQueue(label: "com.apollohg.editor.image-owner-state")
79
+ private let decodeQueue = DispatchQueue(
80
+ label: "com.apollohg.editor.image-decode",
81
+ qos: .userInitiated,
82
+ attributes: .concurrent
83
+ )
84
+ private let transport: ImageLoadingTransport
85
+ private let decoder: ImageDataDecoding
86
+ let deliver: Delivery
87
+ let now: Now
88
+ private let scheduleTimeout: TimeoutSchedule
89
+ private var storedPolicy: ImageLoadingPolicy
90
+ var generation: UInt64 = 0
91
+ private var pending: [Request] = []
92
+ private var active: [UUID: ActiveRequest] = [:]
93
+ private var decodeWorkIds = Set<UUID>()
94
+ private var deliveryTickets: [UUID: DeliveryTicket] = [:]
95
+ private var deadlineTasks: [UUID: ImageLoadingTask] = [:]
96
+
97
+ init(
98
+ policy: ImageLoadingPolicy,
99
+ transport: ImageLoadingTransport = URLSessionImageTransport(),
100
+ decoder: ImageDataDecoding = DefaultImageDataDecoder(),
101
+ deliver: @escaping Delivery = { action in DispatchQueue.main.async(execute: action) },
102
+ now: @escaping Now = { ProcessInfo.processInfo.systemUptime },
103
+ scheduleTimeout: @escaping TimeoutSchedule = { delay, action in
104
+ DispatchImageTimeoutTask(delay: delay, action: action)
105
+ }
106
+ ) {
107
+ storedPolicy = policy
108
+ self.transport = transport
109
+ self.decoder = decoder
110
+ self.deliver = deliver
111
+ self.now = now
112
+ self.scheduleTimeout = scheduleTimeout
113
+ }
114
+
115
+ var policy: ImageLoadingPolicy {
116
+ stateQueue.sync { storedPolicy }
117
+ }
118
+
119
+ func updatePolicy(_ policy: ImageLoadingPolicy) {
120
+ stateQueue.sync {
121
+ cancelAllLocked()
122
+ storedPolicy = policy
123
+ }
124
+ }
125
+
126
+ @discardableResult
127
+ func loadImage(source: String, completion: @escaping (UIImage?) -> Void) -> Bool {
128
+ startImageLoad(source: source, completion: completion) != nil
129
+ }
130
+
131
+ @discardableResult
132
+ func startImageLoad(
133
+ source: String,
134
+ completion: @escaping (UIImage?) -> Void,
135
+ onAcceptedStart: @escaping () -> Void = {}
136
+ ) -> ImageLoadReceipt? {
137
+ let request: Request? = stateQueue.sync {
138
+ let request = Request(
139
+ id: UUID(),
140
+ source: source,
141
+ generation: generation,
142
+ deadline: now() + storedPolicy.requestTimeout,
143
+ completion: completion,
144
+ onAcceptedStart: onAcceptedStart
145
+ )
146
+ if occupiedWorkCountLocked >= storedPolicy.maxConcurrentRequests {
147
+ guard pending.count < storedPolicy.maxPendingRequests else { return nil }
148
+ scheduleDeadlineLocked(for: request)
149
+ pending.append(request)
150
+ return request
151
+ }
152
+ scheduleDeadlineLocked(for: request)
153
+ startLocked(request)
154
+ return request
155
+ }
156
+ guard let request else { return nil }
157
+ return ImageLoadReceipt { [weak self] in
158
+ self?.cancel(request)
159
+ }
160
+ }
161
+
162
+ func cancelAll() {
163
+ stateQueue.sync { cancelAllLocked() }
164
+ }
165
+
166
+ func withCurrent<T>(_ body: () throws -> T) rethrows -> T {
167
+ let dictionary = Thread.current.threadDictionary
168
+ let previous = dictionary[Self.contextKey]
169
+ dictionary[Self.contextKey] = self
170
+ defer {
171
+ if let previous {
172
+ dictionary[Self.contextKey] = previous
173
+ } else {
174
+ dictionary.removeObject(forKey: Self.contextKey)
175
+ }
176
+ }
177
+ return try body()
178
+ }
179
+
180
+ static func withoutLoading<T>(_ body: () throws -> T) rethrows -> T {
181
+ let dictionary = Thread.current.threadDictionary
182
+ let previous = dictionary[suppressKey]
183
+ dictionary[suppressKey] = true
184
+ defer {
185
+ if let previous {
186
+ dictionary[suppressKey] = previous
187
+ } else {
188
+ dictionary.removeObject(forKey: suppressKey)
189
+ }
190
+ }
191
+ return try body()
192
+ }
193
+
194
+ static var current: RenderImageLoadOwner? {
195
+ guard Thread.current.threadDictionary[suppressKey] == nil else { return nil }
196
+ return Thread.current.threadDictionary[contextKey] as? RenderImageLoadOwner
197
+ }
198
+
199
+ private func startLocked(_ request: Request) {
200
+ guard isWithinDeadline(request) else {
201
+ expireLocked(request)
202
+ return
203
+ }
204
+ let activeRequest = ActiveRequest(request: request)
205
+ active[request.id] = activeRequest
206
+ let policy = storedPolicy
207
+ let cacheKey = RenderImageCache.key(source: request.source, policy: policy)
208
+ guard isWithinDeadline(request) else {
209
+ expireLocked(request)
210
+ return
211
+ }
212
+ if let cached = RenderImageCache.cache.image(forKey: cacheKey) {
213
+ request.onAcceptedStart()
214
+ finishLocked(request, image: cached)
215
+ return
216
+ }
217
+
218
+ if Self.isDataURL(request.source) {
219
+ guard Self.decodedDataURLByteCount(
220
+ request.source,
221
+ maxBytes: policy.maxSourceBytes
222
+ ) != nil, isWithinDeadline(request) else {
223
+ finishLocked(request, image: nil)
224
+ return
225
+ }
226
+ request.onAcceptedStart()
227
+ decodeWorkIds.insert(request.id)
228
+ decodeQueue.async { [weak self] in
229
+ guard let self else { return }
230
+ guard self.isLiveAndWithinDeadline(request) else {
231
+ self.finishDecode(request, image: nil, cacheKey: cacheKey)
232
+ return
233
+ }
234
+ let data = Self.decodeDataURL(request.source, maxBytes: policy.maxSourceBytes)
235
+ let image: UIImage? = data.flatMap { data -> UIImage? in
236
+ guard self.isLiveAndWithinDeadline(request) else { return nil }
237
+ return self.decoder.decode(data, maxDimension: policy.maxDecodeDimension)
238
+ }
239
+ self.finishDecode(request, image: image, cacheKey: cacheKey)
240
+ }
241
+ return
242
+ }
243
+
244
+ guard let url = URL(string: request.source),
245
+ let scheme = url.scheme?.lowercased(),
246
+ scheme == "https" || scheme == "http",
247
+ isWithinDeadline(request)
248
+ else {
249
+ finishLocked(request, image: nil)
250
+ return
251
+ }
252
+ request.onAcceptedStart()
253
+ activeRequest.task = transport.load(url, policy: policy) { [weak self] result in
254
+ guard let self else { return }
255
+ self.stateQueue.async {
256
+ guard request.generation == self.generation,
257
+ self.active[request.id] != nil,
258
+ self.isWithinDeadline(request)
259
+ else {
260
+ return
261
+ }
262
+ self.decodeWorkIds.insert(request.id)
263
+ self.decodeQueue.async {
264
+ guard self.isLiveAndWithinDeadline(request) else {
265
+ self.finishDecode(request, image: nil, cacheKey: cacheKey)
266
+ return
267
+ }
268
+ let image: UIImage?
269
+ switch result {
270
+ case let .success(data) where data.count <= policy.maxSourceBytes:
271
+ image = self.isLiveAndWithinDeadline(request)
272
+ ? self.decoder.decode(data, maxDimension: policy.maxDecodeDimension)
273
+ : nil
274
+ default:
275
+ image = nil
276
+ }
277
+ self.finishDecode(request, image: image, cacheKey: cacheKey)
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ private func scheduleDeadlineLocked(for request: Request) {
284
+ let remaining = max(0, request.deadline - now())
285
+ deadlineTasks[request.id] = scheduleTimeout(remaining) { [weak self] in
286
+ self?.expire(request)
287
+ }
288
+ }
289
+
290
+ private func finishDecode(_ request: Request, image: UIImage?, cacheKey: String) {
291
+ stateQueue.async { [weak self] in
292
+ guard let self else { return }
293
+ decodeWorkIds.remove(request.id)
294
+ if request.generation == generation,
295
+ active[request.id] != nil,
296
+ isWithinDeadline(request),
297
+ let image {
298
+ let cost = RenderImageCache.retainedCost(image)
299
+ if isWithinDeadline(request) {
300
+ RenderImageCache.cache.insert(image, forKey: cacheKey, cost: cost)
301
+ }
302
+ }
303
+ if request.generation == generation,
304
+ active[request.id] != nil,
305
+ isWithinDeadline(request) {
306
+ finishLocked(request, image: image)
307
+ } else {
308
+ expireLocked(request)
309
+ drainLocked()
310
+ }
311
+ }
312
+ }
313
+
314
+ private func finishLocked(_ request: Request, image: UIImage?) {
315
+ guard request.generation == generation,
316
+ active[request.id] != nil,
317
+ isWithinDeadline(request),
318
+ deliveryTickets[request.id] == nil
319
+ else {
320
+ return
321
+ }
322
+ let ticket = DeliveryTicket()
323
+ deliveryTickets[request.id] = ticket
324
+ deliver { [weak self] in
325
+ guard let self else { return }
326
+ let shouldDeliver = stateQueue.sync {
327
+ guard request.generation == self.generation,
328
+ self.isWithinDeadline(request),
329
+ self.active.removeValue(forKey: request.id) != nil,
330
+ self.deliveryTickets.removeValue(forKey: request.id) === ticket,
331
+ ticket.begin()
332
+ else {
333
+ return false
334
+ }
335
+ self.drainLocked()
336
+ self.deadlineTasks.removeValue(forKey: request.id)?.cancel()
337
+ return true
338
+ }
339
+ guard shouldDeliver else { return }
340
+ request.completion(image)
341
+ ticket.finish()
342
+ }
343
+ }
344
+
345
+ private func drainLocked() {
346
+ while occupiedWorkCountLocked < storedPolicy.maxConcurrentRequests, !pending.isEmpty {
347
+ startLocked(pending.removeFirst())
348
+ }
349
+ }
350
+
351
+ private var occupiedWorkCountLocked: Int {
352
+ Set(active.keys).union(decodeWorkIds).count
353
+ }
354
+
355
+ private func cancelAllLocked() {
356
+ generation &+= 1
357
+ let tasks = active.values.compactMap(\.task)
358
+ let deadlineTasks = Array(self.deadlineTasks.values)
359
+ deliveryTickets.values.forEach { $0.cancel() }
360
+ active.removeAll()
361
+ pending.removeAll()
362
+ deliveryTickets.removeAll()
363
+ self.deadlineTasks.removeAll()
364
+ tasks.forEach { $0.cancel() }
365
+ deadlineTasks.forEach { $0.cancel() }
366
+ }
367
+
368
+ private func cancel(_ request: Request) {
369
+ stateQueue.sync {
370
+ guard request.generation == generation else { return }
371
+ if let index = pending.firstIndex(where: { $0.id == request.id }) {
372
+ pending.remove(at: index)
373
+ deadlineTasks.removeValue(forKey: request.id)?.cancel()
374
+ return
375
+ }
376
+ guard let activeRequest = active.removeValue(forKey: request.id) else { return }
377
+ deliveryTickets.removeValue(forKey: request.id)?.cancel()
378
+ activeRequest.task?.cancel()
379
+ deadlineTasks.removeValue(forKey: request.id)?.cancel()
380
+ drainLocked()
381
+ }
382
+ }
383
+
384
+ private func isWithinDeadline(_ request: Request) -> Bool {
385
+ now() < request.deadline
386
+ }
387
+
388
+ private func isLiveAndWithinDeadline(_ request: Request) -> Bool {
389
+ stateQueue.sync {
390
+ request.generation == generation
391
+ && active[request.id] != nil
392
+ && isWithinDeadline(request)
393
+ }
394
+ }
395
+
396
+ private func expire(_ request: Request) {
397
+ stateQueue.sync { expireLocked(request) }
398
+ }
399
+
400
+ private func expireLocked(_ request: Request) {
401
+ if let index = pending.firstIndex(where: { $0.id == request.id }) {
402
+ pending.remove(at: index)
403
+ }
404
+ let activeRequest = active.removeValue(forKey: request.id)
405
+ activeRequest?.task?.cancel()
406
+ deliveryTickets.removeValue(forKey: request.id)?.cancel()
407
+ deadlineTasks.removeValue(forKey: request.id)?.cancel()
408
+ drainLocked()
409
+ }
410
+
411
+ private static func isDataURL(_ source: String) -> Bool {
412
+ let scan = scanDataURLHeader(source)
413
+ guard let comma = scan.commaIndex, !scan.exceededLimit else { return false }
414
+ let trimmed = source[..<comma].drop(while: { $0.isWhitespace })
415
+ return trimmed.prefix("data:image/".count).lowercased() == "data:image/"
416
+ }
417
+
418
+ static func scanDataURLHeader(_ source: String) -> DataURLHeaderScan {
419
+ var scannedBytes = 0
420
+ let bytes = source.utf8
421
+ var index = bytes.startIndex
422
+ while index < bytes.endIndex {
423
+ let byte = bytes[index]
424
+ if byte == 44 {
425
+ return DataURLHeaderScan(
426
+ commaIndex: index,
427
+ scannedByteCount: scannedBytes + 1,
428
+ exceededLimit: false
429
+ )
430
+ }
431
+ guard scannedBytes < dataURLHeaderByteLimit else {
432
+ return DataURLHeaderScan(
433
+ commaIndex: nil,
434
+ scannedByteCount: scannedBytes,
435
+ exceededLimit: true
436
+ )
437
+ }
438
+ scannedBytes += 1
439
+ index = bytes.index(after: index)
440
+ }
441
+ return DataURLHeaderScan(
442
+ commaIndex: nil,
443
+ scannedByteCount: scannedBytes,
444
+ exceededLimit: false
445
+ )
446
+ }
447
+
448
+ static func decodedDataURLByteCount(_ source: String, maxBytes: Int) -> Int? {
449
+ let scan = scanDataURLHeader(source)
450
+ guard maxBytes >= 0,
451
+ let comma = scan.commaIndex,
452
+ !scan.exceededLimit
453
+ else {
454
+ return nil
455
+ }
456
+ let completeGroups = maxBytes / 3
457
+ let maxSymbols: Int
458
+ let (groupSymbols, overflow) = completeGroups.multipliedReportingOverflow(by: 4)
459
+ if overflow {
460
+ maxSymbols = Int.max
461
+ } else if maxBytes % 3 == 0 {
462
+ maxSymbols = groupSymbols
463
+ } else {
464
+ let (symbols, additionOverflow) = groupSymbols.addingReportingOverflow(4)
465
+ maxSymbols = additionOverflow ? Int.max : symbols
466
+ }
467
+
468
+ let (encodedLimit, encodedLimitOverflow) = maxSymbols.addingReportingOverflow(
469
+ dataURLEncodedOverheadByteLimit
470
+ )
471
+ let maxEncodedBytes = encodedLimitOverflow ? Int.max : encodedLimit
472
+ var encodedByteCount = 0
473
+ var symbolCount = 0
474
+ var trailingPadding = 0
475
+ var sawPadding = false
476
+ for byte in source[source.index(after: comma)...].utf8 {
477
+ let (nextEncodedCount, encodedCountOverflow) = encodedByteCount.addingReportingOverflow(1)
478
+ guard !encodedCountOverflow, nextEncodedCount <= maxEncodedBytes else { return nil }
479
+ encodedByteCount = nextEncodedCount
480
+ if byte == 9 || byte == 10 || byte == 13 || byte == 32 { continue }
481
+ let isBase64Symbol = (65...90).contains(byte)
482
+ || (97...122).contains(byte)
483
+ || (48...57).contains(byte)
484
+ || byte == 43
485
+ || byte == 47
486
+ guard isBase64Symbol || byte == 61 else { return nil }
487
+ let (nextCount, countOverflow) = symbolCount.addingReportingOverflow(1)
488
+ guard !countOverflow, nextCount <= maxSymbols else { return nil }
489
+ symbolCount = nextCount
490
+ if byte == 61 {
491
+ guard trailingPadding < 2 else { return nil }
492
+ trailingPadding += 1
493
+ sawPadding = true
494
+ } else {
495
+ guard !sawPadding else { return nil }
496
+ trailingPadding = 0
497
+ }
498
+ }
499
+ guard trailingPadding <= 2 else { return nil }
500
+ let groups = symbolCount / 4
501
+ let remainder = symbolCount % 4
502
+ let (groupBytes, byteOverflow) = groups.multipliedReportingOverflow(by: 3)
503
+ guard !byteOverflow else { return nil }
504
+ let remainderBytes = remainder == 0 ? 0 : max(0, remainder - 1)
505
+ let (bytesBeforePadding, additionOverflow) = groupBytes.addingReportingOverflow(remainderBytes)
506
+ guard !additionOverflow, trailingPadding <= bytesBeforePadding else { return nil }
507
+ let bytes = bytesBeforePadding - trailingPadding
508
+ return bytes <= maxBytes ? bytes : nil
509
+ }
510
+
511
+ private static func decodeDataURL(_ source: String, maxBytes: Int) -> Data? {
512
+ let scan = scanDataURLHeader(source)
513
+ guard let comma = scan.commaIndex,
514
+ !scan.exceededLimit else { return nil }
515
+ let trimmed = source[...].drop(while: { $0.isWhitespace })
516
+ guard trimmed.indices.contains(comma),
517
+ trimmed[..<comma].lowercased().contains(";base64")
518
+ else {
519
+ return nil
520
+ }
521
+ let payload = trimmed[trimmed.index(after: comma)...]
522
+ guard let data = Data(base64Encoded: String(payload), options: [.ignoreUnknownCharacters]),
523
+ data.count <= maxBytes
524
+ else {
525
+ return nil
526
+ }
527
+ return data
528
+ }
529
+ }
530
+
531
+ // MARK: - Constants
532
+
533
+ /// Custom NSAttributedString attribute keys for editor metadata.