Skip to content

Commit eeffc34

Browse files
Merge pull request #2432 from DataDog/gonzalezreal/RUM-11242/swiftui-shape
RUM-11242: [Session Replay] Capture SwiftUI shapes as SVG image resources Co-authored-by: gonzalezreal <guille.gonzalez@datadoghq.com>
2 parents 5245546 + 35e2b32 commit eeffc34

35 files changed

Lines changed: 777 additions & 97 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [IMPROVEMENT] Remove fatal errors from Logs. See [#2359][]
1515
- [IMPROVEMENT] Introduce new category for network errors. See [#2341][]
1616
- [IMPROVEMENT] Add opt-out API to disable tracking memory warnings as RUM Errors. See [#2355][]
17+
- [IMPROVEMENT] Improve SwiftUI system image and SF symbol capture in Session Replay through shape SVG recording, image maskColor support, and drawing rasterization. See [#2432][] [#2428][] [#2391][]
1718

1819
# 2.30.0 / 28-07-2025
1920

Datadog/Datadog.xcodeproj/project.pbxproj

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -450,10 +450,15 @@
450450
49D8C0BE2AC5F2BC0075E427 /* Logs+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D8C0B92AC5F21F0075E427 /* Logs+Internal.swift */; };
451451
5B0A9B8B2E3BB98E00A8131C /* GraphicsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0A9B8A2E3BB98500A8131C /* GraphicsFilter.swift */; };
452452
5B0A9B8D2E3BBB4500A8131C /* GraphicsFilter+Reflection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0A9B8C2E3BBB3D00A8131C /* GraphicsFilter+Reflection.swift */; };
453+
5B3AF8AA2E4B3AE9009E5375 /* EnrichedResourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3AF8A92E4B3AE6009E5375 /* EnrichedResourceTests.swift */; };
454+
5B9B20C52E460A0600C95B6C /* ShapeResourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9B20C42E4609FC00C95B6C /* ShapeResourceTests.swift */; };
453455
5B9CB9E32E41F6F9005485E6 /* ImageRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9CB9E22E41F6F6005485E6 /* ImageRepresentable.swift */; };
454456
5B9CB9E52E41FD60005485E6 /* Drawing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9CB9E42E41FD5C005485E6 /* Drawing.swift */; };
455457
5B9CB9E72E420ACB005485E6 /* ImageRendererTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9CB9E62E420AC4005485E6 /* ImageRendererTests.swift */; };
456458
5BCBC0CD2DF85B6A0094DCC2 /* SessionReplayPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BCBC0CC2DF85AFE0094DCC2 /* SessionReplayPrivacyView.swift */; };
459+
5BF7B51F2E44F7D300E0B772 /* ShapeResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF7B51E2E44F7CE00E0B772 /* ShapeResource.swift */; };
460+
5BF7B5212E45032600E0B772 /* CGPath+SessionReplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF7B5202E45031C00E0B772 /* CGPath+SessionReplay.swift */; };
461+
5BF7B5232E45045600E0B772 /* CGPath+SessionReplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF7B5222E45045600E0B772 /* CGPath+SessionReplayTests.swift */; };
457462
5BFDD7A92E28FDD3009A2CEE /* RUMWebViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFDD7A82E28FDC9009A2CEE /* RUMWebViewContext.swift */; };
458463
5BFDD7AA2E28FDD3009A2CEE /* RUMWebViewContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFDD7A82E28FDC9009A2CEE /* RUMWebViewContext.swift */; };
459464
5BFE7B7B2E3CFCDE00B8FAA8 /* ImageRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFE7B7A2E3CFCDA00B8FAA8 /* ImageRenderer.swift */; };
@@ -2450,10 +2455,15 @@
24502455
49D8C0B92AC5F21F0075E427 /* Logs+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logs+Internal.swift"; sourceTree = "<group>"; };
24512456
5B0A9B8A2E3BB98500A8131C /* GraphicsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicsFilter.swift; sourceTree = "<group>"; };
24522457
5B0A9B8C2E3BBB3D00A8131C /* GraphicsFilter+Reflection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GraphicsFilter+Reflection.swift"; sourceTree = "<group>"; };
2458+
5B3AF8A92E4B3AE6009E5375 /* EnrichedResourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnrichedResourceTests.swift; sourceTree = "<group>"; };
2459+
5B9B20C42E4609FC00C95B6C /* ShapeResourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShapeResourceTests.swift; sourceTree = "<group>"; };
24532460
5B9CB9E22E41F6F6005485E6 /* ImageRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRepresentable.swift; sourceTree = "<group>"; };
24542461
5B9CB9E42E41FD5C005485E6 /* Drawing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Drawing.swift; sourceTree = "<group>"; };
24552462
5B9CB9E62E420AC4005485E6 /* ImageRendererTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRendererTests.swift; sourceTree = "<group>"; };
24562463
5BCBC0CC2DF85AFE0094DCC2 /* SessionReplayPrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionReplayPrivacyView.swift; sourceTree = "<group>"; };
2464+
5BF7B51E2E44F7CE00E0B772 /* ShapeResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShapeResource.swift; sourceTree = "<group>"; };
2465+
5BF7B5202E45031C00E0B772 /* CGPath+SessionReplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPath+SessionReplay.swift"; sourceTree = "<group>"; };
2466+
5BF7B5222E45045600E0B772 /* CGPath+SessionReplayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGPath+SessionReplayTests.swift"; sourceTree = "<group>"; };
24572467
5BFDD7A82E28FDC9009A2CEE /* RUMWebViewContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMWebViewContext.swift; sourceTree = "<group>"; };
24582468
5BFE7B7A2E3CFCDA00B8FAA8 /* ImageRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRenderer.swift; sourceTree = "<group>"; };
24592469
61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundLocationMonitor.swift; sourceTree = "<group>"; };
@@ -4014,6 +4024,14 @@
40144024
path = WatchdogTerminations;
40154025
sourceTree = "<group>";
40164026
};
4027+
5B3AF8A82E4B3A7F009E5375 /* Models */ = {
4028+
isa = PBXGroup;
4029+
children = (
4030+
5B3AF8A92E4B3AE6009E5375 /* EnrichedResourceTests.swift */,
4031+
);
4032+
path = Models;
4033+
sourceTree = "<group>";
4034+
};
40174035
61020C272757AD63005EEAEA /* BackgroundEvents */ = {
40184036
isa = PBXGroup;
40194037
children = (
@@ -4047,18 +4065,19 @@
40474065
61054E022A6EE0DB00AAA894 /* DatadogSessionReplayTests */ = {
40484066
isa = PBXGroup;
40494067
children = (
4050-
960B26C12D03611400D7196F /* Resources */,
4051-
96E863712C9C547B0023BF78 /* SessionReplayOverrideTests.swift */,
4052-
61054F482A6EE1B900AAA894 /* SessionReplayTests.swift */,
4053-
61054F3D2A6EE1B900AAA894 /* SessionReplayConfigurationTests.swift */,
4054-
D2A434AD2A8E426C0028E329 /* DDSessionReplayTests.swift */,
4055-
96E863752C9C7E800023BF78 /* DDSessionReplayOverridesTests.swift */,
40564068
61054F882A6EE1BA00AAA894 /* Feature */,
40574069
61054F922A6EE1BA00AAA894 /* Helpers */,
4070+
5B3AF8A82E4B3A7F009E5375 /* Models */,
40584071
61054F4E2A6EE1BA00AAA894 /* Processor */,
40594072
61054F592A6EE1BA00AAA894 /* Recorder */,
4073+
960B26C12D03611400D7196F /* Resources */,
40604074
61054F3E2A6EE1B900AAA894 /* Utilities */,
40614075
61054F492A6EE1BA00AAA894 /* Writer */,
4076+
96E863712C9C547B0023BF78 /* SessionReplayOverrideTests.swift */,
4077+
61054F482A6EE1B900AAA894 /* SessionReplayTests.swift */,
4078+
61054F3D2A6EE1B900AAA894 /* SessionReplayConfigurationTests.swift */,
4079+
D2A434AD2A8E426C0028E329 /* DDSessionReplayTests.swift */,
4080+
96E863752C9C7E800023BF78 /* DDSessionReplayOverridesTests.swift */,
40624081
);
40634082
name = DatadogSessionReplayTests;
40644083
path = ../DatadogSessionReplay/Tests;
@@ -4102,6 +4121,7 @@
41024121
children = (
41034122
61054E142A6EE10A00AAA894 /* UIImage+SessionReplay.swift */,
41044123
962D72BE2CF7538800F86EF0 /* CGImage+SessionReplay.swift */,
4124+
5BF7B5202E45031C00E0B772 /* CGPath+SessionReplay.swift */,
41054125
D22442C42CA301DA002E71E4 /* UIColor+SessionReplay.swift */,
41064126
61054E152A6EE10A00AAA894 /* UIView+SessionReplay.swift */,
41074127
61054E162A6EE10A00AAA894 /* CFType+Safety.swift */,
@@ -4394,6 +4414,7 @@
43944414
children = (
43954415
61054F5D2A6EE1BA00AAA894 /* UIView+SessionReplayTests.swift */,
43964416
61054F5F2A6EE1BA00AAA894 /* CGRect+SessionReplayTests.swift */,
4417+
5BF7B5222E45045600E0B772 /* CGPath+SessionReplayTests.swift */,
43974418
);
43984419
path = Utilties;
43994420
sourceTree = "<group>";
@@ -5883,6 +5904,7 @@
58835904
960B26BA2D03541900D7196F /* SwiftUI */ = {
58845905
isa = PBXGroup;
58855906
children = (
5907+
5B9B20C42E4609FC00C95B6C /* ShapeResourceTests.swift */,
58865908
5B9CB9E62E420AC4005485E6 /* ImageRendererTests.swift */,
58875909
D21331C02D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift */,
58885910
962D72C42CF7806300F86EF0 /* GraphicsImageReflectionTests.swift */,
@@ -6144,10 +6166,8 @@
61446166
E2AA55E62C32C6D9002FEF28 /* ApplicationNotifications.swift */,
61456167
D23039B3298D5235001A1FA3 /* AppState.swift */,
61466168
D23039B5298D5235001A1FA3 /* BatteryStatus.swift */,
6147-
6174D6122BFDF16C00EC7469 /* BundleType.swift */,
61486169
D23039B6298D5235001A1FA3 /* CarrierInfo.swift */,
61496170
D23039BA298D5235001A1FA3 /* DatadogContext.swift */,
6150-
D2F8235229915E12003C7E99 /* DatadogSite.swift */,
61516171
D23039B7298D5235001A1FA3 /* DateProvider.swift */,
61526172
D23039BC298D5235001A1FA3 /* DeviceInfo.swift */,
61536173
D23039BE298D5235001A1FA3 /* LaunchTime.swift */,
@@ -6156,7 +6176,6 @@
61566176
D23039B8298D5235001A1FA3 /* Sysctl.swift */,
61576177
D23039BB298D5235001A1FA3 /* TrackingConsent.swift */,
61586178
D23039B4298D5235001A1FA3 /* UserInfo.swift */,
6159-
8648D07A2E01ABB0002F226B /* BrightnessStatus.swift */,
61606179
D2F8235229915E12003C7E99 /* DatadogSite.swift */,
61616180
6174D6122BFDF16C00EC7469 /* BundleType.swift */,
61626181
8648D07A2E01ABB0002F226B /* BrightnessLevel.swift */,
@@ -6575,6 +6594,7 @@
65756594
962D72BB2CF6436600F86EF0 /* GraphicsImage+Reflection.swift */,
65766595
5B9CB9E22E41F6F6005485E6 /* ImageRepresentable.swift */,
65776596
5BFE7B7A2E3CFCDA00B8FAA8 /* ImageRenderer.swift */,
6597+
5BF7B51E2E44F7CE00E0B772 /* ShapeResource.swift */,
65786598
D2AD1CBE2CE4AE6600106C74 /* SwiftUIWireframesBuilder.swift */,
65796599
D2AD1CBF2CE4AE6600106C74 /* Text.swift */,
65806600
D2AD1CC02CE4AE6600106C74 /* Text+Reflection.swift */,
@@ -8496,6 +8516,7 @@
84968516
61054E972A6EE10A00AAA894 /* Diff.swift in Sources */,
84978517
61054E6E2A6EE10A00AAA894 /* RecordingCoordinator.swift in Sources */,
84988518
61054E9F2A6EE10B00AAA894 /* Errors.swift in Sources */,
8519+
5BF7B51F2E44F7D300E0B772 /* ShapeResource.swift in Sources */,
84998520
D29A470D2D2ED49F0092BC79 /* Xoshiro.swift in Sources */,
85008521
61054E642A6EE10A00AAA894 /* SessionReplay.swift in Sources */,
85018522
61054E952A6EE10A00AAA894 /* SnapshotProcessor.swift in Sources */,
@@ -8530,6 +8551,7 @@
85308551
D22442C52CA301DA002E71E4 /* UIColor+SessionReplay.swift in Sources */,
85318552
61054E8E2A6EE10A00AAA894 /* SRContextPublisher.swift in Sources */,
85328553
61054E732A6EE10A00AAA894 /* WindowTouchSnapshotProducer.swift in Sources */,
8554+
5BF7B5212E45032600E0B772 /* CGPath+SessionReplay.swift in Sources */,
85338555
96F25A822CC7EA4400459567 /* SessionReplayPrivacyOverrides+objc.swift in Sources */,
85348556
A70ADCD22B583B1300321BC9 /* UIImageResource.swift in Sources */,
85358557
61054E792A6EE10A00AAA894 /* UITextViewRecorder.swift in Sources */,
@@ -8547,7 +8569,9 @@
85478569
960B26C32D075BD200D7196F /* DisplayListReflectionTests.swift in Sources */,
85488570
61054FD42A6EE1BA00AAA894 /* SegmentRequestBuilderTests.swift in Sources */,
85498571
61054FB52A6EE1BA00AAA894 /* UISliderRecorderTests.swift in Sources */,
8572+
5B9B20C52E460A0600C95B6C /* ShapeResourceTests.swift in Sources */,
85508573
61054FB22A6EE1BA00AAA894 /* UILabelRecorderTests.swift in Sources */,
8574+
5B3AF8AA2E4B3AE9009E5375 /* EnrichedResourceTests.swift in Sources */,
85518575
D2C5D52D2B84F6D800B63F36 /* WebViewRecordReceiverTests.swift in Sources */,
85528576
61054FBA2A6EE1BA00AAA894 /* UIImageViewRecorderTests.swift in Sources */,
85538577
61054FC02A6EE1BA00AAA894 /* UITextViewRecorderTests.swift in Sources */,
@@ -8576,6 +8600,7 @@
85768600
61054FBD2A6EE1BA00AAA894 /* UIViewRecorderTests.swift in Sources */,
85778601
61054F952A6EE1BA00AAA894 /* SessionReplayConfigurationTests.swift in Sources */,
85788602
61054FAC2A6EE1BA00AAA894 /* CGRect+SessionReplayTests.swift in Sources */,
8603+
5BF7B5232E45045600E0B772 /* CGPath+SessionReplayTests.swift in Sources */,
85798604
D218B0482D072CF300E3F82C /* SessionReplayTelemetryTests.swift in Sources */,
85808605
D21331C12D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift in Sources */,
85818606
61054FA42A6EE1BA00AAA894 /* DiffTests.swift in Sources */,

DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
5BA0067B2E49F6A3000148DB /* UIImage+SVG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA0067A2E49F698000148DB /* UIImage+SVG.swift */; };
11+
5BA0067D2E49F8BF000148DB /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA0067C2E49F8B3000148DB /* UIColor+Hex.swift */; };
1012
5BB746152E02ABB900B568F1 /* SwiftUIFixture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB746142E02ABB500B568F1 /* SwiftUIFixture.swift */; };
1113
5BB746182E02B4CD00B568F1 /* SwiftUIViewWithPrivacyOverrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB746172E02B4CD00B568F1 /* SwiftUIViewWithPrivacyOverrides.swift */; };
1214
614396642A5E8C0600197326 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614396632A5E8C0600197326 /* Environment.swift */; };
@@ -40,6 +42,8 @@
4042
/* End PBXContainerItemProxy section */
4143

4244
/* Begin PBXFileReference section */
45+
5BA0067A2E49F698000148DB /* UIImage+SVG.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SVG.swift"; sourceTree = "<group>"; };
46+
5BA0067C2E49F8B3000148DB /* UIColor+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
4347
5BB746142E02ABB500B568F1 /* SwiftUIFixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIFixture.swift; sourceTree = "<group>"; };
4448
5BB746172E02B4CD00B568F1 /* SwiftUIViewWithPrivacyOverrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIViewWithPrivacyOverrides.swift; sourceTree = "<group>"; };
4549
614396632A5E8C0600197326 /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Environment.swift; path = SRHost/Environment.swift; sourceTree = "<group>"; };
@@ -101,6 +105,8 @@
101105
619C49B529955106006B66A6 /* Utils */ = {
102106
isa = PBXGroup;
103107
children = (
108+
5BA0067C2E49F8B3000148DB /* UIColor+Hex.swift */,
109+
5BA0067A2E49F698000148DB /* UIImage+SVG.swift */,
104110
5BB746142E02ABB500B568F1 /* SwiftUIFixture.swift */,
105111
619C49B329952E12006B66A6 /* SnapshotTestCase.swift */,
106112
96363B2B2CD26AF3006FEC9D /* PrivacyOverrides.swift */,
@@ -304,8 +310,10 @@
304310
files = (
305311
619C49BB299639BC006B66A6 /* ImageRendering.swift in Sources */,
306312
614396652A5E8C0600197326 /* Environment.swift in Sources */,
313+
5BA0067B2E49F6A3000148DB /* UIImage+SVG.swift in Sources */,
307314
61B3BC652993BEAF0032C78A /* SRSnapshotTests.swift in Sources */,
308315
96363B2C2CD26AF3006FEC9D /* PrivacyOverrides.swift in Sources */,
316+
5BA0067D2E49F8BF000148DB /* UIColor+Hex.swift in Sources */,
309317
61BB975F2A5D675400AFFF86 /* ImageComposition.swift in Sources */,
310318
5BB746182E02B4CD00B568F1 /* SwiftUIViewWithPrivacyOverrides.swift in Sources */,
311319
619C49B72995512A006B66A6 /* ImageComparison.swift in Sources */,

DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,15 @@ private extension SRWireframe {
5959
case .textWireframe(let text):
6060
return text.toFrame()
6161
case .imageWireframe(value: let image):
62-
return image.toFrame(
63-
imageData: resources
64-
.first { $0.calculateIdentifier() == image.resourceId }?
65-
.calculateData()
66-
)
62+
let resource = resources.first {
63+
$0.calculateIdentifier() == image.resourceId
64+
}
65+
switch resource?.mimeType {
66+
case .some("image/svg+xml"):
67+
return image.toFrame(svgData: resource?.calculateData())
68+
default:
69+
return image.toFrame(imageData: resource?.calculateData())
70+
}
6771
case .placeholderWireframe(value: let placeholder):
6872
return placeholder.toFrame()
6973
case .webviewWireframe(value: let webview):
@@ -115,6 +119,19 @@ private extension SRImageWireframe {
115119
content: .init(imageData: imageData)
116120
)
117121
}
122+
123+
func toFrame(svgData: Data?) -> BlueprintFrame {
124+
BlueprintFrame(
125+
x: x,
126+
y: y,
127+
width: width,
128+
height: height,
129+
border: border,
130+
style: shapeStyle,
131+
clip: clip,
132+
content: .init(svgData: svgData)
133+
)
134+
}
118135
}
119136

120137
private extension SRWebviewWireframe {
@@ -267,23 +284,10 @@ extension BlueprintFrame.Content {
267284
let contentType: BlueprintFrame.Content.ContentType = .image(image: image)
268285
self.init(contentType: contentType)
269286
}
270-
}
271-
272-
private extension UIColor {
273-
convenience init(hexString: String) {
274-
precondition(hexString.count == 9, "Invalid `hexString` - expected 9 characters, got '\(hexString)'")
275-
precondition(hexString.hasPrefix("#"), "Invalid `hexString` - expected # prefix, got '\(hexString)'")
276287

277-
guard let hex8 = UInt64(hexString.dropFirst(), radix: 16) else {
278-
preconditionFailure("Invalid `hexString`` - expected hexadecimal value, got '\(hexString)'")
279-
}
280-
281-
let mask: UInt64 = 0x00000000FF
282-
self.init(
283-
red: CGFloat((hex8 >> 24) & mask) / CGFloat(255),
284-
green: CGFloat((hex8 >> 16) & mask) / CGFloat(255),
285-
blue: CGFloat((hex8 >> 8) & mask) / CGFloat(255),
286-
alpha: CGFloat(hex8 & mask) / CGFloat(255)
287-
)
288+
init(svgData: Data?) {
289+
let image = svgData.flatMap { UIImage(svgData: $0, scale: UIScreen.main.scale) } ?? UIImage()
290+
let contentType: BlueprintFrame.Content.ContentType = .image(image: image)
291+
self.init(contentType: contentType)
288292
}
289293
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2019-Present Datadog, Inc.
5+
*/
6+
7+
import UIKit
8+
9+
extension UIColor {
10+
convenience init(hexString: String) {
11+
precondition(hexString.count == 9, "Invalid `hexString` - expected 9 characters, got '\(hexString)'")
12+
precondition(hexString.hasPrefix("#"), "Invalid `hexString` - expected # prefix, got '\(hexString)'")
13+
14+
guard let hex8 = UInt64(hexString.dropFirst(), radix: 16) else {
15+
preconditionFailure("Invalid `hexString`` - expected hexadecimal value, got '\(hexString)'")
16+
}
17+
18+
let mask: UInt64 = 0x00000000FF
19+
self.init(
20+
red: CGFloat((hex8 >> 24) & mask) / CGFloat(255),
21+
green: CGFloat((hex8 >> 16) & mask) / CGFloat(255),
22+
blue: CGFloat((hex8 >> 8) & mask) / CGFloat(255),
23+
alpha: CGFloat(hex8 & mask) / CGFloat(255)
24+
)
25+
}
26+
}

0 commit comments

Comments
 (0)