From 44ab84cdf01e2e78823beb760c458c5c21e6cb3f Mon Sep 17 00:00:00 2001 From: Andrew Watt Date: Tue, 11 Apr 2023 14:29:07 -0700 Subject: [PATCH 1/3] Caffeinated layout contract conformances --- .../Sources/Extensions/CGSize+Blueprint.swift | 16 ++++ .../Extensions/FloatingPoint+Blueprint.swift | 10 +++ .../Extensions/CGSize+Extensions.swift | 2 +- .../Sources/Internal/LayoutModeKey.swift | 2 +- BlueprintUI/Sources/Layout/LayoutMode.swift | 20 +++++ .../{Internal => Layout}/LayoutOptions.swift | 0 BlueprintUICommonControls/Sources/Image.swift | 18 ++++- .../Sources/TextField.swift | 18 +++-- .../Tests/Sources/ImageTests.swift | 78 +++++++++++++++---- .../Tests/Sources/LayoutMode+Testing.swift | 16 ++++ .../Tests/Sources/TextFieldTests.swift | 17 ++++ 11 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 BlueprintUI/Sources/Extensions/CGSize+Blueprint.swift create mode 100644 BlueprintUI/Sources/Extensions/FloatingPoint+Blueprint.swift rename BlueprintUI/Sources/{Internal => Layout}/LayoutOptions.swift (100%) create mode 100644 BlueprintUICommonControls/Tests/Sources/LayoutMode+Testing.swift diff --git a/BlueprintUI/Sources/Extensions/CGSize+Blueprint.swift b/BlueprintUI/Sources/Extensions/CGSize+Blueprint.swift new file mode 100644 index 000000000..fa892aea9 --- /dev/null +++ b/BlueprintUI/Sources/Extensions/CGSize+Blueprint.swift @@ -0,0 +1,16 @@ +import CoreGraphics + +extension CGSize { + /// A size with `infinity` in both dimensions. + public static let infinity = CGSize(width: CGFloat.infinity, height: .infinity) + + /// Returns a size with infinite dimensions replaced by the values from the given replacement. + public func replacingInfinity(with replacement: CGSize) -> CGSize { + assert(replacement.isFinite, "Infinity replacement value must be finite") + + return CGSize( + width: width.replacingInfinity(with: replacement.width), + height: height.replacingInfinity(with: replacement.height) + ) + } +} diff --git a/BlueprintUI/Sources/Extensions/FloatingPoint+Blueprint.swift b/BlueprintUI/Sources/Extensions/FloatingPoint+Blueprint.swift new file mode 100644 index 000000000..5112f085d --- /dev/null +++ b/BlueprintUI/Sources/Extensions/FloatingPoint+Blueprint.swift @@ -0,0 +1,10 @@ +import Foundation + +extension FloatingPoint { + /// Returns `replacement` if `self.isInfinite` is `true`, or `self` if `self` is finite. + public func replacingInfinity(with replacement: Self) -> Self { + assert(replacement.isFinite, "Infinity replacement value must be finite") + + return isInfinite ? replacement : self + } +} diff --git a/BlueprintUI/Sources/Internal/Extensions/CGSize+Extensions.swift b/BlueprintUI/Sources/Internal/Extensions/CGSize+Extensions.swift index 4924f9d28..aa4fa1998 100644 --- a/BlueprintUI/Sources/Internal/Extensions/CGSize+Extensions.swift +++ b/BlueprintUI/Sources/Internal/Extensions/CGSize+Extensions.swift @@ -1,4 +1,4 @@ -import CoreGraphics +import UIKit extension CGSize { static func + (lhs: CGSize, rhs: CGSize) -> CGSize { diff --git a/BlueprintUI/Sources/Internal/LayoutModeKey.swift b/BlueprintUI/Sources/Internal/LayoutModeKey.swift index 560e5bf16..9beedb91f 100644 --- a/BlueprintUI/Sources/Internal/LayoutModeKey.swift +++ b/BlueprintUI/Sources/Internal/LayoutModeKey.swift @@ -7,7 +7,7 @@ enum LayoutModeKey: EnvironmentKey { extension Environment { /// This mode will be inherited by descendant BlueprintViews that do not have an explicit /// mode set. - var layoutMode: LayoutMode { + public internal(set) var layoutMode: LayoutMode { get { self[LayoutModeKey.self] } set { self[LayoutModeKey.self] = newValue } } diff --git a/BlueprintUI/Sources/Layout/LayoutMode.swift b/BlueprintUI/Sources/Layout/LayoutMode.swift index 84dccb22a..4848bda00 100644 --- a/BlueprintUI/Sources/Layout/LayoutMode.swift +++ b/BlueprintUI/Sources/Layout/LayoutMode.swift @@ -33,6 +33,26 @@ public enum LayoutMode: Equatable { public static let caffeinated = Self.caffeinated() } +extension LayoutMode: CustomStringConvertible { + public var description: String { + switch self { + case .legacy: + return "Legacy" + case .caffeinated(let options): + switch (options.hintRangeBoundaries, options.searchUnconstrainedKeys) { + case (true, true): + return "Caffeinated (hint+search)" + case (true, false): + return "Caffeinated (hint)" + case (false, true): + return "Caffeinated (search)" + case (false, false): + return "Caffeinated" + } + } + } +} + extension Notification.Name { static let defaultLayoutModeChanged: Self = .init( "com.squareup.blueprint.defaultLayoutModeChanged" diff --git a/BlueprintUI/Sources/Internal/LayoutOptions.swift b/BlueprintUI/Sources/Layout/LayoutOptions.swift similarity index 100% rename from BlueprintUI/Sources/Internal/LayoutOptions.swift rename to BlueprintUI/Sources/Layout/LayoutOptions.swift diff --git a/BlueprintUICommonControls/Sources/Image.swift b/BlueprintUICommonControls/Sources/Image.swift index df0b9f21d..5ec12f8e2 100644 --- a/BlueprintUICommonControls/Sources/Image.swift +++ b/BlueprintUICommonControls/Sources/Image.swift @@ -34,7 +34,9 @@ public struct Image: Element { public var content: ElementContent { let measurer = Measurer(contentMode: contentMode, imageSize: image?.size) - return ElementContent(measurable: measurer) + return ElementContent { constraint, environment in + measurer.measure(in: constraint, layoutMode: environment.layoutMode) + } } public func backingViewDescription(with context: ViewDescriptionContext) -> ViewDescription? { @@ -106,18 +108,19 @@ extension CGSize { extension Image { - fileprivate struct Measurer: Measurable { + fileprivate struct Measurer { var contentMode: ContentMode var imageSize: CGSize? - func measure(in constraint: SizeConstraint) -> CGSize { + func measure(in constraint: SizeConstraint, layoutMode: LayoutMode) -> CGSize { guard let imageSize = imageSize else { return .zero } enum Mode { case fitWidth(CGFloat) case fitHeight(CGFloat) case useImageSize + case infinite } let mode: Mode @@ -137,7 +140,12 @@ extension Image { } else if case .atMost(let height) = constraint.height { mode = .fitHeight(height) } else { - mode = .useImageSize + switch layoutMode { + case .legacy: + mode = .useImageSize + case .caffeinated: + mode = .infinite + } } } @@ -154,6 +162,8 @@ extension Image { ) case .useImageSize: return imageSize + case .infinite: + return .infinity } diff --git a/BlueprintUICommonControls/Sources/TextField.swift b/BlueprintUICommonControls/Sources/TextField.swift index b8bd98427..1a44a62f5 100644 --- a/BlueprintUICommonControls/Sources/TextField.swift +++ b/BlueprintUICommonControls/Sources/TextField.swift @@ -79,11 +79,19 @@ public struct TextField: Element { } public var content: ElementContent { - ElementContent { constraint -> CGSize in - CGSize( - width: max(constraint.maximum.width, 44), - height: 44.0 - ) + ElementContent { constraint, environment -> CGSize in + switch environment.layoutMode { + case .legacy: + return CGSize( + width: max(constraint.maximum.width, 44), + height: 44.0 + ) + case .caffeinated: + return CGSize( + width: constraint.width.constrainedValue.map { max($0, 44) } ?? .infinity, + height: 44 + ) + } } } diff --git a/BlueprintUICommonControls/Tests/Sources/ImageTests.swift b/BlueprintUICommonControls/Tests/Sources/ImageTests.swift index 61443f374..eb97b6506 100644 --- a/BlueprintUICommonControls/Tests/Sources/ImageTests.swift +++ b/BlueprintUICommonControls/Tests/Sources/ImageTests.swift @@ -42,12 +42,14 @@ class ImageTests: XCTestCase { size: CGSize, constraint: SizeConstraint, expectedValue: CGSize, + layoutModes: [LayoutMode] = LayoutMode.testModes, line: UInt = #line ) { self.validate( contentMode: .aspectFill, imageSize: size, constraint: constraint, + layoutModes: layoutModes, expectedValue: expectedValue, line: line ) @@ -58,7 +60,15 @@ class ImageTests: XCTestCase { validate( size: .init(width: 20, height: 10), constraint: .init(width: .unconstrained, height: .unconstrained), - expectedValue: .init(width: 20, height: 10) + expectedValue: .init(width: 20, height: 10), + layoutModes: [.legacy] + ) + + validate( + size: .init(width: 20, height: 10), + constraint: .init(width: .unconstrained, height: .unconstrained), + expectedValue: .infinity, + layoutModes: [.caffeinated] ) validate( @@ -108,7 +118,15 @@ class ImageTests: XCTestCase { validate( size: .init(width: 10, height: 20), constraint: .init(width: .unconstrained, height: .unconstrained), - expectedValue: .init(width: 10, height: 20) + expectedValue: .init(width: 10, height: 20), + layoutModes: [.legacy] + ) + + validate( + size: .init(width: 10, height: 20), + constraint: .init(width: .unconstrained, height: .unconstrained), + expectedValue: .infinity, + layoutModes: [.caffeinated] ) validate( @@ -159,12 +177,14 @@ class ImageTests: XCTestCase { size: CGSize, constraint: SizeConstraint, expectedValue: CGSize, + layoutModes: [LayoutMode] = LayoutMode.testModes, line: UInt = #line ) { self.validate( contentMode: .aspectFit, imageSize: size, constraint: constraint, + layoutModes: layoutModes, expectedValue: expectedValue, line: line ) @@ -175,7 +195,15 @@ class ImageTests: XCTestCase { validate( size: .init(width: 20, height: 10), constraint: .init(width: .unconstrained, height: .unconstrained), - expectedValue: .init(width: 20, height: 10) + expectedValue: .init(width: 20, height: 10), + layoutModes: [.legacy] + ) + + validate( + size: .init(width: 20, height: 10), + constraint: .init(width: .unconstrained, height: .unconstrained), + expectedValue: .infinity, + layoutModes: [.caffeinated] ) validate( @@ -225,7 +253,15 @@ class ImageTests: XCTestCase { validate( size: .init(width: 10, height: 20), constraint: .init(width: .unconstrained, height: .unconstrained), - expectedValue: .init(width: 10, height: 20) + expectedValue: .init(width: 10, height: 20), + layoutModes: [.legacy] + ) + + validate( + size: .init(width: 10, height: 20), + constraint: .init(width: .unconstrained, height: .unconstrained), + expectedValue: .infinity, + layoutModes: [.caffeinated] ) validate( @@ -276,12 +312,14 @@ class ImageTests: XCTestCase { size: CGSize, constraint: SizeConstraint, expectedValue: CGSize, + layoutModes: [LayoutMode] = LayoutMode.testModes, line: UInt = #line ) { self.validate( contentMode: .center, imageSize: size, constraint: constraint, + layoutModes: layoutModes, expectedValue: expectedValue, line: line ) @@ -393,12 +431,14 @@ class ImageTests: XCTestCase { size: CGSize, constraint: SizeConstraint, expectedValue: CGSize, + layoutModes: [LayoutMode] = LayoutMode.testModes, line: UInt = #line ) { self.validate( contentMode: .stretch, imageSize: size, constraint: constraint, + layoutModes: layoutModes, expectedValue: expectedValue, line: line ) @@ -509,6 +549,7 @@ class ImageTests: XCTestCase { contentMode: Image.ContentMode, imageSize: CGSize, constraint: SizeConstraint, + layoutModes: [LayoutMode], expectedValue: CGSize, line: UInt = #line ) { @@ -518,17 +559,24 @@ class ImageTests: XCTestCase { contentMode: contentMode ) - XCTAssertEqual( - element.content.measure(in: constraint), - expectedValue, - """ - Image in content mode: \(contentMode), - of size (\(Int(imageSize.width))x\(Int(imageSize.height))) - expected to be measured as (\(Int(expectedValue.width))x\(Int(expectedValue.height))) - in constraint: (\(constraint)) - """, - line: line - ) + for layoutMode in layoutModes { + let actualSize = layoutMode.performAsDefault { + element.content.measure(in: constraint) + } + + XCTAssertEqual( + actualSize, + expectedValue, + """ + Image in content mode: \(contentMode), + of size \(imageSize) + expected to be measured as \(expectedValue) + in constraint: (\(constraint)) + and layout mode: \(layoutMode) + """, + line: line + ) + } } } diff --git a/BlueprintUICommonControls/Tests/Sources/LayoutMode+Testing.swift b/BlueprintUICommonControls/Tests/Sources/LayoutMode+Testing.swift new file mode 100644 index 000000000..9411755c1 --- /dev/null +++ b/BlueprintUICommonControls/Tests/Sources/LayoutMode+Testing.swift @@ -0,0 +1,16 @@ +import BlueprintUI + +extension LayoutMode { + static let testModes: [LayoutMode] = [.legacy, .caffeinated] + + /// Run the given block with `self` as the default layout mode, restoring the previous default + /// afterwards, and returning the result of the block. + func performAsDefault(block: () throws -> Result) rethrows -> Result { + let oldLayoutMode = LayoutMode.default + defer { LayoutMode.default = oldLayoutMode } + + LayoutMode.default = self + + return try block() + } +} diff --git a/BlueprintUICommonControls/Tests/Sources/TextFieldTests.swift b/BlueprintUICommonControls/Tests/Sources/TextFieldTests.swift index 760d16b9b..87aec6c99 100644 --- a/BlueprintUICommonControls/Tests/Sources/TextFieldTests.swift +++ b/BlueprintUICommonControls/Tests/Sources/TextFieldTests.swift @@ -5,6 +5,23 @@ import XCTest class TextFieldTests: XCTestCase { + func test_measuring() { + LayoutMode.legacy.performAsDefault { + let size = TextField(text: "").content.measure(in: .unconstrained) + XCTAssert(size.height > 0) + XCTAssert(size.height < .infinity) + XCTAssert(size.width > 0) + XCTAssert(size.width < .infinity) + } + + LayoutMode.caffeinated.performAsDefault { + let size = TextField(text: "").content.measure(in: .unconstrained) + XCTAssert(size.height > 0) + XCTAssert(size.height < .infinity) + XCTAssertEqual(size.width, .infinity) + } + } + func test_snapshots() { do { From 21a3cd59f7f1952a546ef198cc9ebe58eda59470 Mon Sep 17 00:00:00 2001 From: Andrew Watt Date: Tue, 11 Apr 2023 14:31:10 -0700 Subject: [PATCH 2/3] ScrollView infinity safety --- .../Sources/ScrollView.swift | 10 +++- ..._infiniteContent_fittingContent_iOS-16.png | Bin 0 -> 631 bytes ...t_infiniteContent_fittingHeight_iOS-16.png | Bin 0 -> 631 bytes ...st_infiniteContent_fittingWidth_iOS-16.png | Bin 0 -> 631 bytes .../Tests/Sources/ScrollViewTests.swift | 44 ++++++++++++++++++ .../Tests/Sources/XCTestCaseExtensions.swift | 31 ++++++++---- 6 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-16.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-16.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-16.png diff --git a/BlueprintUICommonControls/Sources/ScrollView.swift b/BlueprintUICommonControls/Sources/ScrollView.swift index 60d5990dc..981ed9945 100644 --- a/BlueprintUICommonControls/Sources/ScrollView.swift +++ b/BlueprintUICommonControls/Sources/ScrollView.swift @@ -198,8 +198,12 @@ extension ScrollView { result.width += contentInset.left + contentInset.right result.height += contentInset.top + contentInset.bottom - result.width = min(result.width, proposal.width.maximum) - result.height = min(result.height, proposal.height.maximum) + if let maxWidth = proposal.width.constrainedValue { + result.width = min(result.width, maxWidth) + } + if let maxHeight = proposal.height.constrainedValue { + result.height = min(result.height, maxHeight) + } return result } @@ -210,6 +214,8 @@ extension ScrollView { insetSize.height -= contentInset.top + contentInset.bottom var itemSize = fittedSize(in: .init(insetSize), subelement: subelement) + .replacingInfinity(with: insetSize) + if contentSize == .fittingHeight { itemSize.width = insetSize.width } else if contentSize == .fittingWidth { diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-16.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-16.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0c0729d4eb5996033af0c790965f76d1f8652b GIT binary patch literal 631 zcmeAS@N?(olHy`uVBq!ia0vp^DImx5*2E{9B$bjv*C{Z>~D>H5&*VIPmBHc!o6kRsNxM{f zx+O#BUzP?2q1g^^taunz%o=Z$N-%lkFl~Ho@MNpQwdr%e|Kl+`_+FanSgpkKH)iv> zBTTXP3pOB14Ga>hnvN~P>*CvJ)g*-kjgp5wp}sR!7hRQ_KTP8k^VrhGI+ZBxvXx5*2E{9B$bjv*C{Z>~D>H5&*VIPmBHc!o6kRsNxM{f zx+O#BUzP?2q1g^^taunz%o=Z$N-%lkFl~Ho@MNpQwdr%e|Kl+`_+FanSgpkKH)iv> zBTTXP3pOB14Ga>hnvN~P>*CvJ)g*-kjgp5wp}sR!7hRQ_KTP8k^VrhGI+ZBxvXx5*2E{9B$bjv*C{Z>~D>H5&*VIPmBHc!o6kRsNxM{f zx+O#BUzP?2q1g^^taunz%o=Z$N-%lkFl~Ho@MNpQwdr%e|Kl+`_+FanSgpkKH)iv> zBTTXP3pOB14Ga>hnvN~P>*CvJ)g*-kjgp5wp}sR!7hRQ_KTP8k^VrhGI+ZBxvX ViewDescription? { + UIView.describe { view in + view[\.backgroundColor] = .red + } + } + } + + compareSnapshot( + of: InfiniteBox() + .scrollable(.fittingContent) + .inset(uniform: 10), + size: CGSize(width: 100, height: 100), + identifier: "fittingContent", + layoutModes: [.caffeinated] + ) + + compareSnapshot( + of: InfiniteBox() + .scrollable(.fittingWidth) + .inset(uniform: 10), + size: CGSize(width: 100, height: 100), + identifier: "fittingWidth", + layoutModes: [.caffeinated] + ) + + compareSnapshot( + of: InfiniteBox() + .scrollable(.fittingHeight) + .inset(uniform: 10), + size: CGSize(width: 100, height: 100), + identifier: "fittingHeight", + layoutModes: [.caffeinated] + ) + } + func test_calculateContentInset() { // No inset diff --git a/BlueprintUICommonControls/Tests/Sources/XCTestCaseExtensions.swift b/BlueprintUICommonControls/Tests/Sources/XCTestCaseExtensions.swift index caeedbe41..ec2892a5e 100644 --- a/BlueprintUICommonControls/Tests/Sources/XCTestCaseExtensions.swift +++ b/BlueprintUICommonControls/Tests/Sources/XCTestCaseExtensions.swift @@ -101,22 +101,33 @@ extension XCTestCase { size: CGSize? = nil, identifier: String? = nil, scale: CGFloat = 1, + layoutModes: [LayoutMode] = LayoutMode.testModes, file: StaticString = #file, testName: String = #function, line: UInt = #line ) { - let view = BlueprintView(element: element) - view.name = "Snapshot Host" + for layoutMode in layoutModes { + let view = BlueprintView(element: element) + view.name = "Snapshot Host" + view.layoutMode = layoutMode - if let size = size { - view.frame = CGRect(origin: .zero, size: size) - } else { - view.sizeToFit() - view.frame.size.width.round(.up, by: scale) - view.frame.size.height.round(.up, by: scale) - } + if let size = size { + view.frame = CGRect(origin: .zero, size: size) + } else { + view.sizeToFit() + view.frame.size.width.round(.up, by: scale) + view.frame.size.height.round(.up, by: scale) + } - compareSnapshot(of: view, identifier: identifier, scale: scale, file: file, testName: testName, line: line) + compareSnapshot( + of: view, + identifier: identifier, + scale: scale, + file: file, + testName: testName, + line: line + ) + } } } From 3a113ef0eaa0964813de376529444e5eea531818 Mon Sep 17 00:00:00 2001 From: Andrew Watt Date: Thu, 13 Apr 2023 15:43:39 -0700 Subject: [PATCH 3/3] ios 14 and 15 snapshots --- ...test_infiniteContent_fittingContent_iOS-14.png | Bin 0 -> 643 bytes ...test_infiniteContent_fittingContent_iOS-15.png | Bin 0 -> 643 bytes .../test_infiniteContent_fittingHeight_iOS-14.png | Bin 0 -> 643 bytes .../test_infiniteContent_fittingHeight_iOS-15.png | Bin 0 -> 643 bytes .../test_infiniteContent_fittingWidth_iOS-14.png | Bin 0 -> 643 bytes .../test_infiniteContent_fittingWidth_iOS-15.png | Bin 0 -> 643 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-14.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-15.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-14.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-15.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-14.png create mode 100644 BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-15.png diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-14.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-14.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001 diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-15.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingContent_iOS-15.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001 diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-14.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-14.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001 diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-15.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingHeight_iOS-15.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001 diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-14.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-14.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001 diff --git a/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-15.png b/BlueprintUICommonControls/Tests/Sources/Resources/ReferenceImages/ScrollViewTests/test_infiniteContent_fittingWidth_iOS-15.png new file mode 100644 index 0000000000000000000000000000000000000000..b56d9f9c19b61ee28899e78e69bf66344f0a14e1 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^DImjUH7srqa#y3|T`I-#`4jlON|MHfa1knZT!MsAt3p%dd z*v;pk#iU&-J>8O_^Dj#SgV1b;H3DrSv0N+p;)a+o&0Hh8kt;o9`M-~aKL9egj% zbgWk5`5UwO-0?R&#nQ~Nzfkhy4md=cGI$vklHZUlqPZHhCAmEUa zxhcVF^OfXp3``w!Ji{;y`_`ON3-sLo|7_R^|^e*4AC_DFxA PR~bBA{an^LB{Ts5kk8s+ literal 0 HcmV?d00001