@swiftbrowser/swift 0.0.0-stage → 0.2.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 (400) hide show
  1. package/Package.swift +214 -0
  2. package/README.md +10 -2
  3. package/Sources/AVFoundation/AVFoundation.swift +131 -0
  4. package/Sources/AVFoundation/Asset.swift +487 -0
  5. package/Sources/AVFoundation/AudioSession.swift +144 -0
  6. package/Sources/AVFoundation/CMTime.swift +303 -0
  7. package/Sources/AVFoundation/Capture.swift +688 -0
  8. package/Sources/AVFoundation/Player.swift +749 -0
  9. package/Sources/AVFoundation/PlayerView.swift +117 -0
  10. package/Sources/AVKit/AVKit.swift +132 -0
  11. package/Sources/Accelerate/Accelerate.swift +122 -0
  12. package/Sources/AppIntents/AppIntents.swift +144 -0
  13. package/Sources/AppIntents/Parameters.swift +220 -0
  14. package/Sources/AppIntents/Shortcuts.swift +159 -0
  15. package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
  16. package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
  17. package/Sources/AuthenticationServices/Authorization.swift +251 -0
  18. package/Sources/Charts/Charts.swift +61 -0
  19. package/Sources/Combine/AnyCancellable.swift +65 -0
  20. package/Sources/Combine/AnyPublisher.swift +148 -0
  21. package/Sources/Combine/AnySubscriber.swift +230 -0
  22. package/Sources/Combine/Cancellable.swift +35 -0
  23. package/Sources/Combine/Codable.swift +29 -0
  24. package/Sources/Combine/CombineIdentifier.swift +45 -0
  25. package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
  26. package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
  27. package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
  28. package/Sources/Combine/CurrentValueSubject.swift +252 -0
  29. package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
  30. package/Sources/Combine/Future.swift +228 -0
  31. package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
  32. package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
  33. package/Sources/Combine/Helpers/ConduitList.swift +59 -0
  34. package/Sources/Combine/Helpers/DebugHook.swift +177 -0
  35. package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
  36. package/Sources/Combine/Helpers/Locking.swift +30 -0
  37. package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
  38. package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
  39. package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
  40. package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
  41. package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
  42. package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
  43. package/Sources/Combine/Helpers/Utils.swift +30 -0
  44. package/Sources/Combine/Helpers/Violations.swift +33 -0
  45. package/Sources/Combine/ImmediateScheduler.swift +178 -0
  46. package/Sources/Combine/LICENSE +21 -0
  47. package/Sources/Combine/NotificationPublisher.swift +48 -0
  48. package/Sources/Combine/ObjectWillChange.swift +46 -0
  49. package/Sources/Combine/PassthroughSubject.swift +222 -0
  50. package/Sources/Combine/Publisher+Subscribe.swift +53 -0
  51. package/Sources/Combine/Publishers/Deferred.swift +48 -0
  52. package/Sources/Combine/Publishers/Empty.swift +54 -0
  53. package/Sources/Combine/Publishers/Fail.swift +42 -0
  54. package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
  55. package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
  56. package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
  57. package/Sources/Combine/Publishers/Just.swift +313 -0
  58. package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
  59. package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
  60. package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
  61. package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
  62. package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
  63. package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
  64. package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
  65. package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
  66. package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
  67. package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
  68. package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
  69. package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
  70. package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
  71. package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
  72. package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
  73. package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
  74. package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
  75. package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
  76. package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
  77. package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
  78. package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
  79. package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
  80. package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
  81. package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
  82. package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
  83. package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
  84. package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
  85. package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
  86. package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
  87. package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
  88. package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
  89. package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
  90. package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
  91. package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
  92. package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
  93. package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
  94. package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
  95. package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
  96. package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
  97. package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
  98. package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
  99. package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
  100. package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
  101. package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
  102. package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
  103. package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
  104. package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
  105. package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
  106. package/Sources/Combine/Publishers/Publishers.swift +13 -0
  107. package/Sources/Combine/Publishers/Record.swift +237 -0
  108. package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
  109. package/Sources/Combine/Result.swift +46 -0
  110. package/Sources/Combine/Scheduler.swift +89 -0
  111. package/Sources/Combine/Schedulers.swift +211 -0
  112. package/Sources/Combine/Subject+Void.swift +17 -0
  113. package/Sources/Combine/Subscriber+Void.swift +20 -0
  114. package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
  115. package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
  116. package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
  117. package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
  118. package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
  119. package/Sources/Combine/Subscription.swift +22 -0
  120. package/Sources/Combine/Subscriptions.swift +42 -0
  121. package/Sources/Combine/SwiftUIObservation.swift +10 -0
  122. package/Sources/Combine/_Introspection.swift +107 -0
  123. package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
  124. package/Sources/Compression/Compression.swift +365 -0
  125. package/Sources/Compression/Deflate.swift +407 -0
  126. package/Sources/Compression/Zlib.swift +179 -0
  127. package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
  128. package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
  129. package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
  130. package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
  131. package/Sources/CoreImage/CIColor.swift +41 -0
  132. package/Sources/CoreImage/CIContext.swift +31 -0
  133. package/Sources/CoreImage/CIDetector.swift +57 -0
  134. package/Sources/CoreImage/CIFilter.swift +243 -0
  135. package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
  136. package/Sources/CoreImage/CIImage.swift +162 -0
  137. package/Sources/CoreImage/QRCode.swift +393 -0
  138. package/Sources/CoreLocation/Coordinate.swift +30 -0
  139. package/Sources/CoreLocation/Location.swift +65 -0
  140. package/Sources/CoreML/Evaluation.swift +414 -0
  141. package/Sources/CoreML/FeatureValue.swift +266 -0
  142. package/Sources/CoreML/Model.swift +269 -0
  143. package/Sources/CoreML/MultiArray.swift +92 -0
  144. package/Sources/CoreML/Specification.swift +233 -0
  145. package/Sources/CoreText/CoreText.swift +64 -0
  146. package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
  147. package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
  148. package/Sources/CryptoKit/CryptoKit.swift +375 -0
  149. package/Sources/CryptoKit/Curve25519.swift +317 -0
  150. package/Sources/CryptoKit/P256.swift +321 -0
  151. package/Sources/FoundationBridge/AppStorage.swift +165 -0
  152. package/Sources/FoundationBridge/AssetResources.swift +90 -0
  153. package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
  154. package/Sources/FoundationBridge/AsyncImage.swift +116 -0
  155. package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
  156. package/Sources/FoundationBridge/Bundle.swift +119 -0
  157. package/Sources/FoundationBridge/CombineExports.swift +8 -0
  158. package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
  159. package/Sources/FoundationBridge/Dispatch.swift +458 -0
  160. package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
  161. package/Sources/FoundationBridge/FileImporter.swift +128 -0
  162. package/Sources/FoundationBridge/FileSystem.swift +68 -0
  163. package/Sources/FoundationBridge/FoundationBridge.swift +29 -0
  164. package/Sources/FoundationBridge/HostResolution.swift +31 -0
  165. package/Sources/FoundationBridge/ItemProvider.swift +655 -0
  166. package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
  167. package/Sources/FoundationBridge/Links.swift +127 -0
  168. package/Sources/FoundationBridge/ListFormatter.swift +32 -0
  169. package/Sources/FoundationBridge/Locale.swift +86 -0
  170. package/Sources/FoundationBridge/Localization.swift +149 -0
  171. package/Sources/FoundationBridge/Locks.swift +50 -0
  172. package/Sources/FoundationBridge/Markdown.swift +527 -0
  173. package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
  174. package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
  175. package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
  176. package/Sources/FoundationBridge/Operation.swift +195 -0
  177. package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
  178. package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
  179. package/Sources/FoundationBridge/SceneStorage.swift +78 -0
  180. package/Sources/FoundationBridge/SecurityExports.swift +8 -0
  181. package/Sources/FoundationBridge/Selector.swift +226 -0
  182. package/Sources/FoundationBridge/StringComparators.swift +17 -0
  183. package/Sources/FoundationBridge/Table.swift +211 -0
  184. package/Sources/FoundationBridge/TextAttributes.swift +42 -0
  185. package/Sources/FoundationBridge/Timer.swift +53 -0
  186. package/Sources/FoundationBridge/UITextChecker.swift +30 -0
  187. package/Sources/FoundationBridge/URLSession.swift +718 -0
  188. package/Sources/FoundationBridge/UserDefaults.swift +183 -0
  189. package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
  190. package/Sources/FoundationBridge/WebSocket.swift +187 -0
  191. package/Sources/FoundationModels/FoundationModels.swift +1098 -0
  192. package/Sources/ImageIO/GIF.swift +72 -0
  193. package/Sources/ImageIO/ImageIO.swift +248 -0
  194. package/Sources/ImageIO/ImageTypes.swift +28 -0
  195. package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
  196. package/Sources/LocalAuthentication/LAContext.swift +86 -0
  197. package/Sources/MapKit/Geometry.swift +223 -0
  198. package/Sources/MapKit/Map.swift +638 -0
  199. package/Sources/MapKit/MapView.swift +229 -0
  200. package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
  201. package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
  202. package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
  203. package/Sources/OSLog/OSLog.swift +6 -0
  204. package/Sources/Photos/Photos.swift +572 -0
  205. package/Sources/PhotosUI/PhotosPicker.swift +248 -0
  206. package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
  207. package/Sources/QuickLook/QuickLook.swift +168 -0
  208. package/Sources/SafariServices/SafariServices.swift +106 -0
  209. package/Sources/Security/Security.swift +332 -0
  210. package/Sources/StoreKit/AppStore.swift +207 -0
  211. package/Sources/StoreKit/Products.swift +280 -0
  212. package/Sources/StoreKit/RequestReview.swift +28 -0
  213. package/Sources/StoreKit/StoreKit1.swift +486 -0
  214. package/Sources/StoreKit/StoreViews.swift +428 -0
  215. package/Sources/StoreKit/Transactions.swift +197 -0
  216. package/Sources/SwiftData/Macros.swift +58 -0
  217. package/Sources/SwiftData/ModelActor.swift +38 -0
  218. package/Sources/SwiftData/ModelContainer.swift +129 -0
  219. package/Sources/SwiftData/ModelContext.swift +451 -0
  220. package/Sources/SwiftData/PersistentModel.swift +238 -0
  221. package/Sources/SwiftData/Properties.swift +261 -0
  222. package/Sources/SwiftData/Query.swift +256 -0
  223. package/Sources/SwiftData/Schema.swift +192 -0
  224. package/Sources/SwiftData/Store.swift +146 -0
  225. package/Sources/SwiftData/StringPredicates.swift +125 -0
  226. package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
  227. package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
  228. package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
  229. package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
  230. package/Sources/SwiftDataMacros/Plugin.swift +18 -0
  231. package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
  232. package/Sources/SwiftUI/API/Accessibility.swift +181 -0
  233. package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
  234. package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
  235. package/Sources/SwiftUI/API/Alert.swift +221 -0
  236. package/Sources/SwiftUI/API/AlignmentGuides.swift +65 -0
  237. package/Sources/SwiftUI/API/Animation.swift +285 -0
  238. package/Sources/SwiftUI/API/App.swift +87 -0
  239. package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
  240. package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
  241. package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
  242. package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
  243. package/Sources/SwiftUI/API/Canvas.swift +337 -0
  244. package/Sources/SwiftUI/API/Color.swift +237 -0
  245. package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
  246. package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
  247. package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
  248. package/Sources/SwiftUI/API/Commands.swift +106 -0
  249. package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
  250. package/Sources/SwiftUI/API/ContentShape.swift +33 -0
  251. package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
  252. package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
  253. package/Sources/SwiftUI/API/Controls.swift +300 -0
  254. package/Sources/SwiftUI/API/CustomLayout.swift +442 -0
  255. package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
  256. package/Sources/SwiftUI/API/Decorations.swift +92 -0
  257. package/Sources/SwiftUI/API/EditMode.swift +212 -0
  258. package/Sources/SwiftUI/API/Effects.swift +388 -0
  259. package/Sources/SwiftUI/API/Entry.swift +8 -0
  260. package/Sources/SwiftUI/API/Environment.swift +439 -0
  261. package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
  262. package/Sources/SwiftUI/API/Focus.swift +137 -0
  263. package/Sources/SwiftUI/API/Font.swift +131 -0
  264. package/Sources/SwiftUI/API/Gauge.swift +290 -0
  265. package/Sources/SwiftUI/API/Geometry.swift +89 -0
  266. package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
  267. package/Sources/SwiftUI/API/GeometryReader.swift +135 -0
  268. package/Sources/SwiftUI/API/GestureState.swift +65 -0
  269. package/Sources/SwiftUI/API/Gestures.swift +342 -0
  270. package/Sources/SwiftUI/API/Glass.swift +127 -0
  271. package/Sources/SwiftUI/API/Grid.swift +188 -0
  272. package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
  273. package/Sources/SwiftUI/API/KeyPress.swift +54 -0
  274. package/Sources/SwiftUI/API/LabelStyle.swift +124 -0
  275. package/Sources/SwiftUI/API/Layout.swift +220 -0
  276. package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
  277. package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
  278. package/Sources/SwiftUI/API/Lists.swift +331 -0
  279. package/Sources/SwiftUI/API/Menu.swift +58 -0
  280. package/Sources/SwiftUI/API/Modifiers.swift +313 -0
  281. package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
  282. package/Sources/SwiftUI/API/Namespace.swift +44 -0
  283. package/Sources/SwiftUI/API/Navigation.swift +386 -0
  284. package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
  285. package/Sources/SwiftUI/API/ObservableObject.swift +293 -0
  286. package/Sources/SwiftUI/API/OnChange.swift +48 -0
  287. package/Sources/SwiftUI/API/Path.swift +543 -0
  288. package/Sources/SwiftUI/API/Phase8Controls.swift +411 -0
  289. package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
  290. package/Sources/SwiftUI/API/Picker.swift +185 -0
  291. package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
  292. package/Sources/SwiftUI/API/Popover.swift +41 -0
  293. package/Sources/SwiftUI/API/Preferences.swift +262 -0
  294. package/Sources/SwiftUI/API/Presentation.swift +122 -0
  295. package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
  296. package/Sources/SwiftUI/API/Primitives.swift +517 -0
  297. package/Sources/SwiftUI/API/Publishers.swift +107 -0
  298. package/Sources/SwiftUI/API/Redaction.swift +75 -0
  299. package/Sources/SwiftUI/API/RowActions.swift +84 -0
  300. package/Sources/SwiftUI/API/Scenes.swift +131 -0
  301. package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
  302. package/Sources/SwiftUI/API/ScrollTargets.swift +104 -0
  303. package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
  304. package/Sources/SwiftUI/API/SectionSupplements.swift +96 -0
  305. package/Sources/SwiftUI/API/Shape.swift +214 -0
  306. package/Sources/SwiftUI/API/ShapeStyle.swift +409 -0
  307. package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
  308. package/Sources/SwiftUI/API/Sharing.swift +193 -0
  309. package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
  310. package/Sources/SwiftUI/API/State.swift +144 -0
  311. package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
  312. package/Sources/SwiftUI/API/StrokeStyle.swift +30 -0
  313. package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
  314. package/Sources/SwiftUI/API/TabContent.swift +841 -0
  315. package/Sources/SwiftUI/API/Table.swift +382 -0
  316. package/Sources/SwiftUI/API/Tabs.swift +263 -0
  317. package/Sources/SwiftUI/API/Tasks.swift +35 -0
  318. package/Sources/SwiftUI/API/Text.swift +386 -0
  319. package/Sources/SwiftUI/API/TextDates.swift +61 -0
  320. package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
  321. package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
  322. package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
  323. package/Sources/SwiftUI/API/Timeline.swift +212 -0
  324. package/Sources/SwiftUI/API/Toolbar.swift +251 -0
  325. package/Sources/SwiftUI/API/Transfer.swift +145 -0
  326. package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
  327. package/Sources/SwiftUI/API/Video.swift +64 -0
  328. package/Sources/SwiftUI/API/View.swift +215 -0
  329. package/Sources/SwiftUI/API/ViewModifier.swift +43 -0
  330. package/Sources/SwiftUI/API/VisualEffect.swift +155 -0
  331. package/Sources/SwiftUI/API/Windows.swift +25 -0
  332. package/Sources/SwiftUI/Charts/Axis.swift +325 -0
  333. package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
  334. package/Sources/SwiftUI/Charts/Chart.swift +660 -0
  335. package/Sources/SwiftUI/Charts/ChartContent.swift +376 -0
  336. package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
  337. package/Sources/SwiftUI/Charts/Marks.swift +204 -0
  338. package/Sources/SwiftUI/Charts/Plottable.swift +99 -0
  339. package/Sources/SwiftUI/Charts/Scales.swift +326 -0
  340. package/Sources/SwiftUI/Localization/Localization.swift +498 -0
  341. package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
  342. package/Sources/SwiftUI/Runtime/Executor.swift +85 -0
  343. package/Sources/SwiftUI/Runtime/Exports.swift +101 -0
  344. package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
  345. package/Sources/SwiftUI/Runtime/JSON.swift +143 -0
  346. package/Sources/SwiftUI/Runtime/JSONParser.swift +443 -0
  347. package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
  348. package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
  349. package/Sources/SwiftUI/Runtime/Ops.swift +152 -0
  350. package/Sources/SwiftUI/Runtime/Reconciler.swift +219 -0
  351. package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
  352. package/Sources/SwiftUI/Runtime/Runtime.swift +2146 -0
  353. package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
  354. package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
  355. package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
  356. package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
  357. package/Sources/Symbols/Symbols.swift +25 -0
  358. package/Sources/Translation/Translation.swift +423 -0
  359. package/Sources/UIKit/Activity.swift +213 -0
  360. package/Sources/UIKit/Alerts.swift +69 -0
  361. package/Sources/UIKit/AppDelegate.swift +222 -0
  362. package/Sources/UIKit/Appearance.swift +84 -0
  363. package/Sources/UIKit/ColorConversions.swift +70 -0
  364. package/Sources/UIKit/Controls.swift +225 -0
  365. package/Sources/UIKit/Device.swift +200 -0
  366. package/Sources/UIKit/Feedback.swift +65 -0
  367. package/Sources/UIKit/Font.swift +307 -0
  368. package/Sources/UIKit/Graphics.swift +204 -0
  369. package/Sources/UIKit/HostingController.swift +185 -0
  370. package/Sources/UIKit/Identity.swift +24 -0
  371. package/Sources/UIKit/Introspectable.swift +510 -0
  372. package/Sources/UIKit/Pasteboard.swift +363 -0
  373. package/Sources/UIKit/PhotoAlbum.swift +81 -0
  374. package/Sources/UIKit/RemoteNotifications.swift +15 -0
  375. package/Sources/UIKit/Representable.swift +288 -0
  376. package/Sources/UIKit/SafeArea.swift +12 -0
  377. package/Sources/UIKit/SceneDelegates.swift +132 -0
  378. package/Sources/UIKit/Scenes.swift +40 -0
  379. package/Sources/UIKit/ScrollView.swift +157 -0
  380. package/Sources/UIKit/ShortcutItems.swift +67 -0
  381. package/Sources/UIKit/SymbolConfiguration.swift +124 -0
  382. package/Sources/UIKit/TargetAction.swift +123 -0
  383. package/Sources/UIKit/TextPaste.swift +161 -0
  384. package/Sources/UIKit/TextView.swift +538 -0
  385. package/Sources/UIKit/UIKit.swift +292 -0
  386. package/Sources/UIKit/UIView.swift +855 -0
  387. package/Sources/UIKit/ViewTranslation.swift +311 -0
  388. package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
  389. package/Sources/UserNotifications/Content.swift +370 -0
  390. package/Sources/UserNotifications/NotificationCenter.swift +309 -0
  391. package/Sources/WeatherKit/WeatherKit.swift +228 -0
  392. package/Sources/WebKit/WebKit.swift +245 -0
  393. package/Sources/os/os.swift +376 -0
  394. package/Sources/zlib/zlib.swift +6 -0
  395. package/index.d.ts +2 -0
  396. package/index.mjs +16 -0
  397. package/manifest.d.mts +2 -0
  398. package/manifest.mjs +39 -0
  399. package/package.json +30 -4
  400. package/sync-sources.mjs +33 -0
@@ -0,0 +1,85 @@
1
+ @_spi(ExperimentalCustomExecutors) @_spi(ExperimentalScheduling) import _Concurrency
2
+
3
+ /// A host-driven cooperative executor. Jobs created by `Task`, `.task` and
4
+ /// sleeps queue here until the host calls `sb_run_jobs`; delays become
5
+ /// timers against a clock the host sets (real time in the browser, a
6
+ /// virtual clock in headless mode). See docs/ops-protocol.md (Phase 4).
7
+ final class _HostExecutor: MainExecutor, SchedulingExecutor, TaskExecutor, @unchecked Sendable {
8
+ static let shared = _HostExecutor()
9
+
10
+ private var queue: [UnownedJob] = []
11
+ private var timers: [(deadlineNs: UInt64, job: UnownedJob)] = []
12
+ /// The executor's clock in nanoseconds; origin is arbitrary.
13
+ var nowNs: UInt64 = 0
14
+
15
+ func enqueue(_ job: consuming ExecutorJob) {
16
+ queue.append(UnownedJob(job))
17
+ }
18
+
19
+ func run() throws {}
20
+ func stop() {}
21
+ func checkIsolated() {}
22
+ func isIsolatingCurrentContext() -> Bool? { true }
23
+
24
+ func enqueue<C: Clock>(_ job: consuming ExecutorJob, after delay: C.Duration, tolerance: C.Duration?, clock: C) {
25
+ timers.append((nowNs + nanoseconds(of: delay), UnownedJob(job)))
26
+ }
27
+
28
+ func enqueue<C: Clock>(_ job: consuming ExecutorJob, at instant: C.Instant, tolerance: C.Duration?, clock: C) {
29
+ let delay = clock.now.duration(to: instant)
30
+ timers.append((nowNs + nanoseconds(of: delay), UnownedJob(job)))
31
+ }
32
+
33
+ /// Delays are rounded so timers stay aligned and headless runs are
34
+ /// deterministic.
35
+ private func nanoseconds<D: DurationProtocol>(of duration: D) -> UInt64 {
36
+ guard let duration = duration as? Duration else { return 0 }
37
+ let (seconds, attoseconds) = duration.components
38
+ let ns = Double(max(0, seconds)) * 1e9 + Double(max(0, attoseconds)) / 1e9
39
+ // 10 ms granularity: the WASI clock is coarse, and `Task.sleep(for:)`
40
+ // computes an absolute instant from it before we see the delay.
41
+ return UInt64((ns / 1e7).rounded() * 1e7)
42
+ }
43
+
44
+ /// Runs every queued job and every due timer, repeatedly, until the
45
+ /// queue is empty. Returns nanoseconds until the next timer, or -1.
46
+ func runJobs() -> Int64 {
47
+ var ran = 0
48
+ repeat {
49
+ ran = 0
50
+ while !queue.isEmpty {
51
+ let job = queue.removeFirst()
52
+ job.runSynchronously(on: asUnownedSerialExecutor())
53
+ ran += 1
54
+ }
55
+ timers.sort { $0.deadlineNs < $1.deadlineNs }
56
+ while let first = timers.first, first.deadlineNs <= nowNs {
57
+ timers.removeFirst()
58
+ queue.append(first.job)
59
+ ran += 1
60
+ }
61
+ } while ran > 0
62
+ guard let next = timers.first else { return -1 }
63
+ return Int64(next.deadlineNs - nowNs)
64
+ }
65
+
66
+ var hasTimers: Bool { !timers.isEmpty }
67
+ /// Whether jobs are waiting to run now (enqueued since the last `runJobs`).
68
+ var hasQueuedJobs: Bool { !queue.isEmpty }
69
+ }
70
+
71
+ enum _HostExecutorFactory: ExecutorFactory {
72
+ static var mainExecutor: any MainExecutor { _HostExecutor.shared }
73
+ static var defaultExecutor: any TaskExecutor { _HostExecutor.shared }
74
+ }
75
+
76
+ nonisolated(unsafe) private var executorInstalled = false
77
+
78
+ /// Installs the host-driven executor. Must run before any task is created;
79
+ /// `App.main()` calls it. Native test processes must not install it, since
80
+ /// the test runner drives the main actor itself.
81
+ public func _installHostExecutor() {
82
+ guard !executorInstalled else { return }
83
+ executorInstalled = true
84
+ _createExecutors(factory: _HostExecutorFactory.self)
85
+ }
@@ -0,0 +1,101 @@
1
+ // C-ABI entry points for the browser renderer. See docs/ops-protocol.md.
2
+ // Wasm is single-threaded, so the main actor is the only executor.
3
+
4
+ @_cdecl("sb_event")
5
+ public func _sb_event(_ id: Int32) {
6
+ MainActor.assumeIsolated {
7
+ _Runtime.shared.dispatch(tap: Int(id))
8
+ }
9
+ }
10
+
11
+ @_cdecl("sb_ops_ptr")
12
+ public func _sb_ops_ptr() -> Int32 {
13
+ MainActor.assumeIsolated { _BufferedHost.shared.pointer }
14
+ }
15
+
16
+ @_cdecl("sb_ops_len")
17
+ public func _sb_ops_len() -> Int32 {
18
+ MainActor.assumeIsolated { _BufferedHost.shared.length }
19
+ }
20
+
21
+ @_cdecl("sb_ops_clear")
22
+ public func _sb_ops_clear() {
23
+ MainActor.assumeIsolated { _BufferedHost.shared.clear() }
24
+ }
25
+
26
+ /// The number of byte buffers beside the pending ops (`{"$bytes": n}` values).
27
+ @_cdecl("sb_bytes_count")
28
+ public func _sb_bytes_count() -> Int32 {
29
+ MainActor.assumeIsolated { Int32(_BufferedHost.shared.bytes.count) }
30
+ }
31
+
32
+ /// Where the pending ops' `n`th byte buffer starts in linear memory.
33
+ @_cdecl("sb_bytes_ptr")
34
+ public func _sb_bytes_ptr(_ index: Int32) -> Int32 {
35
+ MainActor.assumeIsolated {
36
+ let items = _BufferedHost.shared.bytes
37
+ guard items.indices.contains(Int(index)) else { return 0 }
38
+ return Int32(Int(bitPattern: items[Int(index)].baseAddress))
39
+ }
40
+ }
41
+
42
+ /// The length of the pending ops' `n`th byte buffer.
43
+ @_cdecl("sb_bytes_len")
44
+ public func _sb_bytes_len(_ index: Int32) -> Int32 {
45
+ MainActor.assumeIsolated {
46
+ let items = _BufferedHost.shared.bytes
47
+ guard items.indices.contains(Int(index)) else { return 0 }
48
+ return Int32(items[Int(index)].count)
49
+ }
50
+ }
51
+
52
+ /// Takes a buffer from `sb_alloc` that the renderer filled with bytes for
53
+ /// the next event, and answers the `n` the event names them by (`{"$bytes": n}`).
54
+ @_cdecl("sb_bytes")
55
+ public func _sb_bytes(_ pointer: Int32, _ length: Int32) -> Int32 {
56
+ guard let base = UnsafeMutablePointer<UInt8>(bitPattern: Int(pointer)) else { return 0 }
57
+ let bytes = Array(UnsafeBufferPointer(start: base, count: Int(length)))
58
+ base.deallocate()
59
+ return MainActor.assumeIsolated { Int32(_BytesInbox.shared.add(bytes)) }
60
+ }
61
+
62
+ /// Allocates a buffer the renderer fills before calling `sb_event_json`.
63
+ @_cdecl("sb_alloc")
64
+ public func _sb_alloc(_ length: Int32) -> Int32 {
65
+ let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(max(length, 1)))
66
+ return Int32(Int(bitPattern: pointer))
67
+ }
68
+
69
+ /// Delivers one UTF-8 JSON event written into a buffer from `sb_alloc`.
70
+ @_cdecl("sb_event_json")
71
+ public func _sb_event_json(_ pointer: Int32, _ length: Int32) {
72
+ guard let base = UnsafeMutablePointer<UInt8>(bitPattern: Int(pointer)) else { return }
73
+ let text = String(decoding: UnsafeBufferPointer(start: base, count: Int(length)), as: UTF8.self)
74
+ base.deallocate()
75
+ MainActor.assumeIsolated {
76
+ guard let event = try? _JSON.parse(text) else {
77
+ print("[SwiftUI] ignoring malformed event: \(text)")
78
+ return
79
+ }
80
+ _Runtime.shared.dispatch(event: _BytesInbox.shared.resolve(event))
81
+ }
82
+ }
83
+
84
+ @_cdecl("sb_state_ptr")
85
+ public func _sb_state_ptr() -> Int32 {
86
+ MainActor.assumeIsolated {
87
+ _StateBuffer.shared.refresh(with: _Runtime.shared.snapshot())
88
+ return _StateBuffer.shared.pointer
89
+ }
90
+ }
91
+
92
+ @_cdecl("sb_state_len")
93
+ public func _sb_state_len() -> Int32 {
94
+ MainActor.assumeIsolated { _StateBuffer.shared.length }
95
+ }
96
+
97
+ /// Drives Swift concurrency: see `_Runtime.runJobs(nowMilliseconds:)`.
98
+ @_cdecl("sb_run_jobs")
99
+ public func _sb_run_jobs(_ nowMilliseconds: Double) -> Double {
100
+ MainActor.assumeIsolated { _Runtime.shared.runJobs(nowMilliseconds: nowMilliseconds) }
101
+ }
@@ -0,0 +1,310 @@
1
+ import Foundation
2
+
3
+ // Bitmaps (`UIImage`, `CGImage`, Core Image's `CIImage`) never hold decoded
4
+ // pixels in Swift. Each is a recipe: a source (an encoded file's bytes, or a
5
+ // small pixel buffer a generator made) plus the Core Image steps applied to
6
+ // it, in order. The page decodes the source and runs the steps when it draws
7
+ // the image (Web/src/bitmaps.ts, docs/ops-protocol.md, "Bitmaps and Core
8
+ // Image"). Swift only needs sizes, which it reads from the file's header, so
9
+ // `UIImage(data:)` stays synchronous as on iOS while the browser decodes
10
+ // asynchronously.
11
+
12
+ /// What an encoded image's header says: its media type and its pixel size,
13
+ /// with the EXIF (JPEG) or `irot` (HEIF) rotation applied, as browsers draw it.
14
+ public struct _ImageHeader: Equatable, Sendable {
15
+ public let mime: String
16
+ public let width: Int
17
+ public let height: Int
18
+
19
+ public init(mime: String, width: Int, height: Int) {
20
+ self.mime = mime
21
+ self.width = width
22
+ self.height = height
23
+ }
24
+
25
+ /// The header of a PNG, JPEG, GIF, WebP, BMP, HEIC or AVIF file; nil for
26
+ /// anything else, or a header too short or malformed to give a size.
27
+ public static func parse(_ bytes: [UInt8]) -> _ImageHeader? {
28
+ let reader = _ByteReader(bytes)
29
+ let parsed = parsePNG(reader) ?? parseJPEG(reader) ?? parseGIF(reader) ?? parseWebP(reader)
30
+ ?? parseBMP(reader) ?? parseHEIF(reader)
31
+ guard let parsed, parsed.width > 0, parsed.height > 0 else { return nil }
32
+ return parsed
33
+ }
34
+
35
+ private static func parsePNG(_ r: _ByteReader) -> _ImageHeader? {
36
+ guard r.matches([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A], at: 0), r.matches(Array("IHDR".utf8), at: 12),
37
+ let width = r.u32be(16), let height = r.u32be(20) else { return nil }
38
+ return _ImageHeader(mime: "image/png", width: Int(width), height: Int(height))
39
+ }
40
+
41
+ private static func parseGIF(_ r: _ByteReader) -> _ImageHeader? {
42
+ guard r.matches(Array("GIF87a".utf8), at: 0) || r.matches(Array("GIF89a".utf8), at: 0),
43
+ let width = r.u16le(6), let height = r.u16le(8) else { return nil }
44
+ return _ImageHeader(mime: "image/gif", width: Int(width), height: Int(height))
45
+ }
46
+
47
+ private static func parseBMP(_ r: _ByteReader) -> _ImageHeader? {
48
+ guard r.matches(Array("BM".utf8), at: 0), let width = r.u32le(18), let height = r.u32le(22) else { return nil }
49
+ // The height is negative for a top-down bitmap.
50
+ return _ImageHeader(mime: "image/bmp", width: Int(Int32(bitPattern: width).magnitude), height: Int(Int32(bitPattern: height).magnitude))
51
+ }
52
+
53
+ private static func parseWebP(_ r: _ByteReader) -> _ImageHeader? {
54
+ guard r.matches(Array("RIFF".utf8), at: 0), r.matches(Array("WEBP".utf8), at: 8) else { return nil }
55
+ if r.matches(Array("VP8 ".utf8), at: 12) {
56
+ // Lossy: a key frame's start code, then 14-bit width and height.
57
+ guard r.matches([0x9D, 0x01, 0x2A], at: 23), let width = r.u16le(26), let height = r.u16le(28) else { return nil }
58
+ return _ImageHeader(mime: "image/webp", width: Int(width & 0x3FFF), height: Int(height & 0x3FFF))
59
+ }
60
+ if r.matches(Array("VP8L".utf8), at: 12) {
61
+ // Lossless: a signature byte, then width - 1 and height - 1 in 14 bits each.
62
+ guard r.byte(20) == 0x2F, let b0 = r.byte(21), let b1 = r.byte(22), let b2 = r.byte(23), let b3 = r.byte(24) else { return nil }
63
+ let width = 1 + (Int(b0) | (Int(b1 & 0x3F) << 8))
64
+ let height = 1 + ((Int(b1) >> 6) | (Int(b2) << 2) | (Int(b3 & 0x0F) << 10))
65
+ return _ImageHeader(mime: "image/webp", width: width, height: height)
66
+ }
67
+ if r.matches(Array("VP8X".utf8), at: 12) {
68
+ // Extended: the canvas size, minus one, in 24 bits each.
69
+ guard let width = r.u24le(24), let height = r.u24le(27) else { return nil }
70
+ return _ImageHeader(mime: "image/webp", width: Int(width) + 1, height: Int(height) + 1)
71
+ }
72
+ return nil
73
+ }
74
+
75
+ private static func parseJPEG(_ r: _ByteReader) -> _ImageHeader? {
76
+ guard r.matches([0xFF, 0xD8], at: 0) else { return nil }
77
+ var index = 2
78
+ var orientation = 1
79
+ while index + 4 <= r.count {
80
+ guard r.byte(index) == 0xFF, let marker = r.byte(index + 1) else { return nil }
81
+ if marker == 0xFF { index += 1; continue } // fill byte
82
+ index += 2
83
+ // Markers without a length: TEM, RSTn, SOI.
84
+ if marker == 0x01 || (0xD0...0xD8).contains(marker) { continue }
85
+ // End of image or start of scan before any frame header: no size.
86
+ if marker == 0xD9 || marker == 0xDA { return nil }
87
+ guard let length = r.u16be(index), length >= 2 else { return nil }
88
+ if marker == 0xE1, let value = exifOrientation(r, segment: index + 2, length: Int(length) - 2) {
89
+ orientation = value
90
+ }
91
+ // SOF0...SOF15, except DHT (C4), JPG (C8) and DAC (CC).
92
+ if (0xC0...0xCF).contains(marker), marker != 0xC4, marker != 0xC8, marker != 0xCC {
93
+ guard let height = r.u16be(index + 3), let width = r.u16be(index + 5) else { return nil }
94
+ // Orientations 5 to 8 turn the picture a quarter: browsers draw it (and
95
+ // UIImage reports it) with width and height swapped.
96
+ let turned = orientation >= 5 && orientation <= 8
97
+ return _ImageHeader(mime: "image/jpeg", width: Int(turned ? height : width), height: Int(turned ? width : height))
98
+ }
99
+ index += Int(length)
100
+ }
101
+ return nil
102
+ }
103
+
104
+ /// The orientation tag (0x0112) of an APP1 Exif segment's first IFD.
105
+ private static func exifOrientation(_ r: _ByteReader, segment: Int, length: Int) -> Int? {
106
+ guard length > 14, r.matches(Array("Exif".utf8) + [0, 0], at: segment) else { return nil }
107
+ let tiff = segment + 6
108
+ let little: Bool
109
+ if r.matches(Array("II".utf8), at: tiff) { little = true }
110
+ else if r.matches(Array("MM".utf8), at: tiff) { little = false }
111
+ else { return nil }
112
+ let u16 = { (at: Int) in little ? r.u16le(at) : r.u16be(at) }
113
+ let u32 = { (at: Int) in little ? r.u32le(at) : r.u32be(at) }
114
+ guard let ifd = u32(tiff + 4), let count = u16(tiff + Int(ifd)) else { return nil }
115
+ for entry in 0..<Int(count) {
116
+ let at = tiff + Int(ifd) + 2 + entry * 12
117
+ guard at + 12 <= segment + length, let tag = u16(at) else { return nil }
118
+ if tag == 0x0112, let value = u16(at + 8) { return Int(value) }
119
+ }
120
+ return nil
121
+ }
122
+
123
+ /// HEIC and AVIF (ISO base media files): the largest `ispe` (image spatial
124
+ /// extent) property is the primary image's size; an `irot` of a quarter
125
+ /// or three quarters swaps it.
126
+ private static func parseHEIF(_ r: _ByteReader) -> _ImageHeader? {
127
+ guard r.matches(Array("ftyp".utf8), at: 4), let boxSize = r.u32be(0) else { return nil }
128
+ let brands = Set(stride(from: 8, to: min(Int(boxSize), r.count) - 3, by: 4).compactMap { at -> String? in
129
+ guard at != 12, let bytes = r.slice(at, 4) else { return nil } // 12: the minor version
130
+ return String(decoding: bytes, as: UTF8.self)
131
+ })
132
+ let isAVIF = !brands.isDisjoint(with: ["avif", "avis"])
133
+ guard isAVIF || !brands.isDisjoint(with: ["heic", "heix", "hevc", "hevx", "heim", "heis", "mif1", "msf1"]) else { return nil }
134
+ var best: (width: Int, height: Int)?
135
+ var turned = false
136
+ let ispe = Array("ispe".utf8), irot = Array("irot".utf8)
137
+ // The `meta` box is near the start; the image data comes after it.
138
+ let limit = min(r.count, 1 << 20)
139
+ var at = 4
140
+ while at + 5 <= limit {
141
+ if r.matches(ispe, at: at), let width = r.u32be(at + 8), let height = r.u32be(at + 12) {
142
+ if Int(width) * Int(height) > (best.map { $0.width * $0.height } ?? 0) { best = (Int(width), Int(height)) }
143
+ at += 16
144
+ continue
145
+ }
146
+ if r.matches(irot, at: at), let angle = r.byte(at + 4) { turned = (angle & 0x03) % 2 == 1 }
147
+ at += 1
148
+ }
149
+ guard let best else { return nil }
150
+ return _ImageHeader(mime: isAVIF ? "image/avif" : "image/heic",
151
+ width: turned ? best.height : best.width, height: turned ? best.width : best.height)
152
+ }
153
+ }
154
+
155
+ /// Bounds-checked reads from a byte array; every read past the end is nil.
156
+ struct _ByteReader {
157
+ let bytes: [UInt8]
158
+ init(_ bytes: [UInt8]) { self.bytes = bytes }
159
+
160
+ var count: Int { bytes.count }
161
+ func byte(_ at: Int) -> UInt8? { at >= 0 && at < bytes.count ? bytes[at] : nil }
162
+ func slice(_ at: Int, _ length: Int) -> ArraySlice<UInt8>? {
163
+ at >= 0 && length >= 0 && at + length <= bytes.count ? bytes[at..<(at + length)] : nil
164
+ }
165
+ func matches(_ pattern: [UInt8], at: Int) -> Bool { slice(at, pattern.count).map { $0.elementsEqual(pattern) } ?? false }
166
+ func u16be(_ at: Int) -> UInt16? { slice(at, 2).map { UInt16($0[at]) << 8 | UInt16($0[at + 1]) } }
167
+ func u16le(_ at: Int) -> UInt16? { slice(at, 2).map { UInt16($0[at + 1]) << 8 | UInt16($0[at]) } }
168
+ func u24le(_ at: Int) -> UInt32? { slice(at, 3).map { UInt32($0[at + 2]) << 16 | UInt32($0[at + 1]) << 8 | UInt32($0[at]) } }
169
+ func u32be(_ at: Int) -> UInt32? {
170
+ slice(at, 4).map { UInt32($0[at]) << 24 | UInt32($0[at + 1]) << 16 | UInt32($0[at + 2]) << 8 | UInt32($0[at + 3]) }
171
+ }
172
+ func u32le(_ at: Int) -> UInt32? {
173
+ slice(at, 4).map { UInt32($0[at + 3]) << 24 | UInt32($0[at + 2]) << 16 | UInt32($0[at + 1]) << 8 | UInt32($0[at]) }
174
+ }
175
+ }
176
+
177
+ /// Where a bitmap's pixels come from: an encoded image file, or a pixel
178
+ /// buffer (one gray or four RGBA bytes per pixel, rows from the top). The
179
+ /// page receives it once, in an `imagedata` op, under its `key` (a hash of
180
+ /// the content, so the same bytes are sent once however many images use them).
181
+ public final class _ImageSource: Equatable, @unchecked Sendable {
182
+ public enum PixelFormat: String, Sendable {
183
+ case gray, rgba
184
+ }
185
+
186
+ enum Payload {
187
+ case encoded([UInt8], mime: String)
188
+ case pixels([UInt8], PixelFormat)
189
+ }
190
+
191
+ public let key: String
192
+ /// The size in pixels, as the page draws it (orientation applied).
193
+ public let width: Int
194
+ public let height: Int
195
+ let payload: Payload
196
+
197
+ /// An encoded image file; nil when its header is not one the page can draw.
198
+ public init?(encoded bytes: [UInt8]) {
199
+ guard let header = _ImageHeader.parse(bytes) else { return nil }
200
+ key = "f" + _fnv1a(bytes)
201
+ width = header.width
202
+ height = header.height
203
+ payload = .encoded(bytes, mime: header.mime)
204
+ }
205
+
206
+ /// A pixel buffer: `width * height` bytes for `.gray`, four times that
207
+ /// (straight, not premultiplied, alpha) for `.rgba`.
208
+ public init(pixels: [UInt8], width: Int, height: Int, format: PixelFormat) {
209
+ precondition(pixels.count == width * height * (format == .gray ? 1 : 4), "pixel buffer size does not match \(width)×\(height) \(format)")
210
+ key = "p" + _fnv1a(pixels + Array("\(width)x\(height)\(format.rawValue)".utf8))
211
+ self.width = width
212
+ self.height = height
213
+ payload = .pixels(pixels, format)
214
+ }
215
+
216
+ public static func == (lhs: _ImageSource, rhs: _ImageSource) -> Bool { lhs.key == rhs.key }
217
+
218
+ /// The media type of an encoded source; nil for pixels.
219
+ public var mime: String? {
220
+ if case .encoded(_, let mime) = payload { return mime }
221
+ return nil
222
+ }
223
+
224
+ /// The `imagedata` op's fields.
225
+ var json: _JSON {
226
+ var fields: [String: _JSON] = ["key": .string(key), "width": .number(Double(width)), "height": .number(Double(height))]
227
+ switch payload {
228
+ case .encoded(let bytes, let mime):
229
+ fields["mime"] = .string(mime)
230
+ fields["data"] = .bytes(bytes)
231
+ case .pixels(let bytes, let format):
232
+ fields["format"] = .string(format.rawValue)
233
+ fields["pixels"] = .bytes(bytes)
234
+ }
235
+ return .object(fields)
236
+ }
237
+ }
238
+
239
+ /// A bitmap as the page will draw it: its source and the Core Image steps
240
+ /// applied to it. `extent` is Core Image's: in source pixels, origin at the
241
+ /// bottom left, possibly infinite (`clampedToExtent()`). A `CGImage`'s
242
+ /// recipe ends at its own pixel grid: its extent is `(0, 0, width, height)`.
243
+ public struct _ImageRecipe: Equatable, Sendable {
244
+ /// Nil for an empty image (`UIImage()`, `CIImage.empty()`).
245
+ public let source: _ImageSource?
246
+ /// Each step is an object whose `op` names it (docs/ops-protocol.md).
247
+ public let steps: [_JSON]
248
+ public let extent: CGRect
249
+ /// The frame of an animated source (a GIF) the steps start from, whole as
250
+ /// the file's earlier frames leave the canvas; nil for the file as it is
251
+ /// (its first frame).
252
+ public let frame: Int?
253
+
254
+ public init(source: _ImageSource?, steps: [_JSON] = [], extent: CGRect, frame: Int? = nil) {
255
+ self.source = source
256
+ self.steps = steps
257
+ self.extent = extent
258
+ self.frame = frame
259
+ }
260
+
261
+ /// The source on its own: extent `(0, 0, width, height)`.
262
+ public init(source: _ImageSource, frame: Int? = nil) {
263
+ self.init(source: source, extent: CGRect(x: 0, y: 0, width: Double(source.width), height: Double(source.height)), frame: frame)
264
+ }
265
+
266
+ public static let empty = _ImageRecipe(source: nil, extent: .null)
267
+
268
+ /// This recipe followed by `step`, which gives the image `extent`.
269
+ public func adding(_ step: _JSON, extent: CGRect) -> _ImageRecipe {
270
+ _ImageRecipe(source: source, steps: steps + [step], extent: extent, frame: frame)
271
+ }
272
+
273
+ /// The image inside `rect` (Core Image coordinates) as a bitmap of its own,
274
+ /// `(0, 0, width, height)` in pixels: clear where the image does not reach
275
+ /// (`CIContext.createCGImage(_:from:)`). Nil for an infinite or empty rect.
276
+ public func rendered(in rect: CGRect) -> _ImageRecipe? {
277
+ guard !rect.isInfinite, !rect.isNull else { return nil }
278
+ let box = rect.integral
279
+ guard box.width >= 1, box.height >= 1 else { return nil }
280
+ let step: _JSON = .object(["op": .string("render"), "x": .number(box.minX), "y": .number(box.minY),
281
+ "width": .number(box.width), "height": .number(box.height)])
282
+ return adding(step, extent: CGRect(x: 0, y: 0, width: box.width, height: box.height))
283
+ }
284
+
285
+ /// The `bitmap` prop of an `image` element: the source's key, the frame
286
+ /// of an animated one, and the steps; `width` / `height` are the result's
287
+ /// size in pixels.
288
+ var json: _JSON {
289
+ let finite = !extent.isNull && !extent.isInfinite
290
+ var fields: [String: _JSON] = [
291
+ "source": source.map { .string($0.key) } ?? .null,
292
+ "steps": .array(steps),
293
+ "width": .number(finite ? extent.width : 0),
294
+ "height": .number(finite ? extent.height : 0),
295
+ ]
296
+ if let frame { fields["frame"] = .number(Double(frame)) }
297
+ return .object(fields)
298
+ }
299
+ }
300
+
301
+ /// FNV-1a, 64 bits, as 16 hex digits: content keys for image sources.
302
+ func _fnv1a(_ bytes: [UInt8]) -> String {
303
+ var hash: UInt64 = 0xCBF2_9CE4_8422_2325
304
+ for byte in bytes {
305
+ hash ^= UInt64(byte)
306
+ hash = hash &* 0x0000_0100_0000_01B3
307
+ }
308
+ let hex = String(hash, radix: 16)
309
+ return String(repeating: "0", count: 16 - hex.count) + hex
310
+ }
@@ -0,0 +1,143 @@
1
+ /// A minimal JSON value. The shim avoids Foundation (see Geometry.swift), so it
2
+ /// carries its own serializer. Object keys serialize in sorted order so the
3
+ /// output is byte-stable for snapshot tests.
4
+ public enum _JSON: Equatable, Sendable {
5
+ case null
6
+ case bool(Bool)
7
+ case number(Double)
8
+ case string(String)
9
+ case array([_JSON])
10
+ case object([String: _JSON])
11
+ /// Raw bytes: a fetched body, an image file. Serialized as a base64
12
+ /// string, except into the browser's ops buffer, where they pass through
13
+ /// linear memory as `{"$bytes": n}` (docs/ops-protocol.md, "Bytes").
14
+ case bytes([UInt8])
15
+
16
+ public var serialized: String {
17
+ var out = ""
18
+ write(into: &out, outbox: nil)
19
+ return out
20
+ }
21
+
22
+ /// Serialized with `.bytes` values moved to `outbox`, each written as `{"$bytes": n}`.
23
+ func serialized(outbox: _BytesOutbox) -> String {
24
+ var out = ""
25
+ write(into: &out, outbox: outbox)
26
+ return out
27
+ }
28
+
29
+ private func write(into out: inout String, outbox: _BytesOutbox?) {
30
+ switch self {
31
+ case .null:
32
+ out += "null"
33
+ case .bool(let value):
34
+ out += value ? "true" : "false"
35
+ case .number(let value):
36
+ if value.isFinite, value == value.rounded(), abs(value) < 1e15 {
37
+ out += String(Int64(value))
38
+ } else if value.isFinite {
39
+ out += "\(value)"
40
+ } else {
41
+ out += "null"
42
+ }
43
+ case .string(let value):
44
+ _JSON.writeString(value, into: &out)
45
+ case .array(let items):
46
+ out += "["
47
+ for (index, item) in items.enumerated() {
48
+ if index > 0 { out += "," }
49
+ item.write(into: &out, outbox: outbox)
50
+ }
51
+ out += "]"
52
+ case .object(let members):
53
+ out += "{"
54
+ for (index, key) in members.keys.sorted().enumerated() {
55
+ if index > 0 { out += "," }
56
+ _JSON.writeString(key, into: &out)
57
+ out += ":"
58
+ members[key]!.write(into: &out, outbox: outbox)
59
+ }
60
+ out += "}"
61
+ case .bytes(let bytes):
62
+ if let outbox {
63
+ out += "{\"$bytes\":\(outbox.add(bytes))}"
64
+ } else {
65
+ out += "\""
66
+ out += _base64(bytes)
67
+ out += "\""
68
+ }
69
+ }
70
+ }
71
+
72
+ private static func writeString(_ value: String, into out: inout String) {
73
+ out += "\""
74
+ for scalar in value.unicodeScalars {
75
+ switch scalar {
76
+ case "\"": out += "\\\""
77
+ case "\\": out += "\\\\"
78
+ case "\n": out += "\\n"
79
+ case "\r": out += "\\r"
80
+ case "\t": out += "\\t"
81
+ case _ where scalar.value < 0x20:
82
+ let hex = String(scalar.value, radix: 16)
83
+ out += "\\u" + String(repeating: "0", count: 4 - hex.count) + hex
84
+ default:
85
+ out.unicodeScalars.append(scalar)
86
+ }
87
+ }
88
+ out += "\""
89
+ }
90
+ }
91
+
92
+ /// Bytes on their way to the page beside the ops buffer (`sb_bytes_*`
93
+ /// exports): the `n` of each `{"$bytes": n}` in the ops is an index here.
94
+ final class _BytesOutbox {
95
+ private(set) var items: [UnsafeMutableBufferPointer<UInt8>] = []
96
+
97
+ func add(_ bytes: [UInt8]) -> Int {
98
+ let buffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: max(bytes.count, 1))
99
+ _ = buffer.initialize(from: bytes)
100
+ items.append(UnsafeMutableBufferPointer(rebasing: buffer[0..<bytes.count]))
101
+ return items.count - 1
102
+ }
103
+
104
+ func removeAll() {
105
+ for item in items { item.deallocate() }
106
+ items.removeAll()
107
+ }
108
+ }
109
+
110
+ /// Bytes the page put in linear memory for the next `sb_event_json` (the
111
+ /// `sb_bytes` export), by the `n` of the event's `{"$bytes": n}` values.
112
+ @MainActor
113
+ final class _BytesInbox {
114
+ static let shared = _BytesInbox()
115
+ private var items: [Int: [UInt8]] = [:]
116
+ private var nextID = 1
117
+
118
+ func add(_ bytes: [UInt8]) -> Int {
119
+ let id = nextID
120
+ nextID += 1
121
+ items[id] = bytes
122
+ return id
123
+ }
124
+
125
+ /// `event` with each `{"$bytes": n}` replaced by its bytes; whatever it did not name is dropped.
126
+ func resolve(_ event: _JSON) -> _JSON {
127
+ guard !items.isEmpty else { return event }
128
+ defer { items.removeAll() }
129
+ return replace(event)
130
+ }
131
+
132
+ private func replace(_ value: _JSON) -> _JSON {
133
+ switch value {
134
+ case .object(let members):
135
+ if members.count == 1, case .number(let n)? = members["$bytes"], let bytes = items[Int(n)] { return .bytes(bytes) }
136
+ return .object(members.mapValues(replace))
137
+ case .array(let items):
138
+ return .array(items.map(replace))
139
+ default:
140
+ return value
141
+ }
142
+ }
143
+ }