From 163d311ff32dde95c171f1a6f4e2e7b37f221c53 Mon Sep 17 00:00:00 2001 From: ricky cancro Date: Tue, 13 Apr 2021 15:29:49 -0700 Subject: [PATCH 1/2] [Layout] Add RTL support to LayoutSpecs This is largely a slight update for https://github.com/TextureGroup/Texture/pull/1805. If RTL is enabled, `calculateLayoutLayoutSpec:` will flip the origin of all sublayouts. The new part of the diff is that ASBatchFetching now supports proper fetching on RTL horizontal scrollViews. --- Source/ASDisplayNode+LayoutSpec.mm | 21 ++++++++++++++++++++ Source/ASDisplayNode.mm | 15 ++++++++++++++ Source/Private/ASBatchFetching.h | 1 + Source/Private/ASBatchFetching.mm | 11 ++++++++-- Source/Private/ASDisplayNode+UIViewBridge.mm | 7 ++++--- Source/Private/ASDisplayNodeInternal.h | 6 +++++- 6 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Source/ASDisplayNode+LayoutSpec.mm b/Source/ASDisplayNode+LayoutSpec.mm index 93ce0e6dd..04ca0f6ab 100644 --- a/Source/ASDisplayNode+LayoutSpec.mm +++ b/Source/ASDisplayNode+LayoutSpec.mm @@ -107,6 +107,27 @@ - (ASLayout *)calculateLayoutLayoutSpec:(ASSizeRange)constrainedSize } layout = [layout filteredNodeLayoutTree]; + // Flip layout if layout should be rendered right-to-left + BOOL shouldRenderRTLLayout = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:_semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; + if (shouldRenderRTLLayout) { + for (ASLayout *sublayout in layout.sublayouts) { + switch (_semanticContentAttribute) { + case UISemanticContentAttributeUnspecified: + case UISemanticContentAttributeForceRightToLeft: { + // Flip + CGPoint flippedPosition = CGPointMake(layout.size.width - CGRectGetWidth(sublayout.frame) - sublayout.position.x, sublayout.position.y); + sublayout.position = flippedPosition; + } + case UISemanticContentAttributePlayback: + case UISemanticContentAttributeForceLeftToRight: + case UISemanticContentAttributeSpatial: + // Don't flip + break; + } + } + } + + return layout; } diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index abb339bdd..b96a77477 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -1625,6 +1625,21 @@ - (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType }); } +- (void)updateSemanticContentAttributeWithAttribute:(UISemanticContentAttribute)attribute +{ + __instanceLock__.lock(); + UISemanticContentAttribute oldAttribute = _semanticContentAttribute; + _semanticContentAttribute = attribute; + __instanceLock__.unlock(); + + ASPerformBlockOnMainThread(^{ + // If the value has changed we should attempt to relayout. + if (attribute != oldAttribute) { + [self setNeedsLayout]; + } + }); +} + - (void)recursivelySetDisplaySuspended:(BOOL)flag { _recursivelySetDisplaySuspended(self, nil, flag); diff --git a/Source/Private/ASBatchFetching.h b/Source/Private/ASBatchFetching.h index fec0c6764..0da10cd7e 100644 --- a/Source/Private/ASBatchFetching.h +++ b/Source/Private/ASBatchFetching.h @@ -67,6 +67,7 @@ ASDK_EXTERN BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, CGPoint targetOffset, CGFloat leadingScreens, BOOL visible, + BOOL shouldRenderRTLLayout, CGPoint velocity, _Nullable id delegate); diff --git a/Source/Private/ASBatchFetching.mm b/Source/Private/ASBatchFetching.mm index cf3c100ea..eb62f5054 100644 --- a/Source/Private/ASBatchFetching.mm +++ b/Source/Private/ASBatchFetching.mm @@ -29,7 +29,8 @@ BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView delegate = scrollView.batchFetchingDelegate; BOOL visible = (scrollView.window != nil); - return ASDisplayShouldFetchBatchForContext(context, scrollDirection, scrollableDirections, bounds, contentSize, contentOffset, leadingScreens, visible, velocity, delegate); + BOOL shouldRenderRTLLayout = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:scrollView.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; + return ASDisplayShouldFetchBatchForContext(context, scrollDirection, scrollableDirections, bounds, contentSize, contentOffset, leadingScreens, visible, shouldRenderRTLLayout, velocity, delegate); } BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, @@ -40,6 +41,7 @@ BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, CGPoint targetOffset, CGFloat leadingScreens, BOOL visible, + BOOL shouldRenderRTLLayout, CGPoint velocity, id delegate) { @@ -79,13 +81,18 @@ BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context, } // If they are scrolling toward the head of content, don't batch fetch. - BOOL isScrollingTowardHead = (ASScrollDirectionContainsUp(scrollDirection) || ASScrollDirectionContainsLeft(scrollDirection)); + BOOL isScrollingTowardHead = (ASScrollDirectionContainsUp(scrollDirection) || (shouldRenderRTLLayout ? ASScrollDirectionContainsRight(scrollDirection) : ASScrollDirectionContainsLeft(scrollDirection))); if (isScrollingTowardHead) { return NO; } CGFloat triggerDistance = viewLength * leadingScreens; CGFloat remainingDistance = contentLength - viewLength - offset; + if (shouldRenderRTLLayout && ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) { + remainingDistance = offset; + } else { + remainingDistance = contentLength - viewLength - offset; + } BOOL result = remainingDistance <= triggerDistance; if (delegate != nil && velocityLength > 0.0) { diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm index 8be28957f..114e8119f 100644 --- a/Source/Private/ASDisplayNode+UIViewBridge.mm +++ b/Source/Private/ASDisplayNode+UIViewBridge.mm @@ -944,14 +944,15 @@ - (void)setEdgeAntialiasingMask:(CAEdgeAntialiasingMask)edgeAntialiasingMask - (UISemanticContentAttribute)semanticContentAttribute { - _bridge_prologue_read; - return _getFromViewOnly(semanticContentAttribute); + AS::MutexLocker l(__instanceLock__); + return _semanticContentAttribute; } - (void)setSemanticContentAttribute:(UISemanticContentAttribute)semanticContentAttribute { - _bridge_prologue_write; + AS::MutexLocker l(__instanceLock__); _setToViewOnly(semanticContentAttribute, semanticContentAttribute); + _semanticContentAttribute = semanticContentAttribute; #if YOGA [self semanticContentAttributeDidChange:semanticContentAttribute]; #endif diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h index 22f36483b..b9f5f40d4 100644 --- a/Source/Private/ASDisplayNodeInternal.h +++ b/Source/Private/ASDisplayNodeInternal.h @@ -258,7 +258,8 @@ static constexpr CACornerMask kASCACornerAllCorners = // These properties are used on iOS 10 and lower, where safe area is not supported by UIKit. UIEdgeInsets _fallbackSafeAreaInsets; - + // Right-to-Left layout support + UISemanticContentAttribute _semanticContentAttribute; #pragma mark - ASDisplayNode (Debugging) ASLayout *_unflattenedLayout; @@ -332,6 +333,9 @@ static constexpr CACornerMask kASCACornerAllCorners = cornerRadius:(CGFloat)newCornerRadius maskedCorners:(CACornerMask)newMaskedCorners; +/// Update the Semantic Content Attribute. Trigger layout if this value has changed. +- (void)updateSemanticContentAttributeWithAttribute:(UISemanticContentAttribute)attribute; + /// Alternative initialiser for backing with a custom view class. Supports asynchronous display with _ASDisplayView subclasses. - (instancetype)initWithViewClass:(Class)viewClass; From 2116ddaf6826651b0690bd6f3514d9c54f2bead8 Mon Sep 17 00:00:00 2001 From: ricky cancro Date: Wed, 14 Apr 2021 09:23:06 -0700 Subject: [PATCH 2/2] Fix build and add RTL batch fetching tests --- Tests/ASBatchFetchingTests.mm | 81 ++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/Tests/ASBatchFetchingTests.mm b/Tests/ASBatchFetchingTests.mm index 99b67f05c..54c2b786c 100644 --- a/Tests/ASBatchFetchingTests.mm +++ b/Tests/ASBatchFetchingTests.mm @@ -30,91 +30,142 @@ @implementation ASBatchFetchingTests - (void)testBatchNullState { ASBatchContext *context = [[ASBatchContext alloc] init]; - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, CGRectZero, CGSizeZero, CGPointZero, 0.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, CGRectZero, CGSizeZero, CGPointZero, 0.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == NO, @"Should not fetch in the null state"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, CGRectZero, CGSizeZero, CGPointZero, 0.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == NO, @"Should not fetch in the null state"); } - (void)testBatchAlreadyFetching { ASBatchContext *context = [[ASBatchContext alloc] init]; [context beginBatchFetching]; - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == NO, @"Should not fetch when context is already fetching"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == NO, @"Should not fetch when context is already fetching"); } - (void)testUnsupportedScrollDirections { ASBatchContext *context = [[ASBatchContext alloc] init]; - BOOL fetchRight = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil); + BOOL fetchRight = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, NO, CGPointZero, nil); XCTAssert(fetchRight == YES, @"Should fetch for scrolling right"); - BOOL fetchDown = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil); + BOOL fetchDown = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, NO, CGPointZero, nil); XCTAssert(fetchDown == YES, @"Should fetch for scrolling down"); - BOOL fetchUp = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionUp, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil); + BOOL fetchUp = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionUp, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, NO, CGPointZero, nil); XCTAssert(fetchUp == NO, @"Should not fetch for scrolling up"); - BOOL fetchLeft = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil); + BOOL fetchLeft = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, NO, CGPointZero, nil); XCTAssert(fetchLeft == NO, @"Should not fetch for scrolling left"); + + // test RTL + BOOL fetchRightRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, YES, CGPointZero, nil); + XCTAssert(fetchRightRTL == NO, @"Should not fetch for scrolling right"); + BOOL fetchDownRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, YES, CGPointZero, nil); + XCTAssert(fetchDownRTL == YES, @"Should fetch for scrolling down"); + BOOL fetchUpRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionUp, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, YES, CGPointZero, nil); + XCTAssert(fetchUpRTL == NO, @"Should not fetch for scrolling up"); + BOOL fetchLeftRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, YES, CGPointZero, nil); + XCTAssert(fetchLeftRTL == YES, @"Should fetch for scrolling left"); + } - (void)testVerticalScrollToExactLeading { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // scroll to 1-screen top offset, height is 1 screen, so bottom is 1 screen away from end of content - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 1.0), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 1.0), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling to exactly 1 leading screen away"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 1.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when vertically scrolling to exactly 1 leading screen away"); } - (void)testVerticalScrollToLessThanLeading { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // 3 screens of content, scroll only 1/2 of one screen - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 0.5), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 0.5), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == NO, @"Fetch should not begin when vertically scrolling less than the leading distance away"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 0.5), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == NO, @"Fetch should not begin when vertically scrolling less than the leading distance away"); } - (void)testVerticalScrollingPastContentSize { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // 3 screens of content, top offset to 3-screens, height 1 screen, so its 1 screen past the leading - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 3.0), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 3.0), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling past the content size"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 3.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when vertically scrolling past the content size"); } - (void)testHorizontalScrollToExactLeading { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // scroll to 1-screen left offset, width is 1 screen, so right is 1 screen away from end of content - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionVerticalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 1.0), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionVerticalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 1.0), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == YES, @"Fetch should begin when horizontally scrolling to exactly 1 leading screen away"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionVerticalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 1.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when horizontally scrolling to exactly 1 leading screen away"); } - (void)testHorizontalScrollToLessThanLeading { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // 3 screens of content, scroll only 1/2 of one screen - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 0.5), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 0.5), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == NO, @"Fetch should not begin when horizontally scrolling less than the leading distance away"); + + // In RTL since scrolling is reversed, our remaining distance is actually our offset (0.5) which is less than our leading screen (1). So we do want to fetch + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 0.5), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when horizontally scrolling less than the leading distance away"); } - (void)testHorizontalScrollingPastContentSize { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // 3 screens of content, left offset to 3-screens, width 1 screen, so its 1 screen past the leading - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 3.0), 1.0, YES, CGPointZero, nil); - XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling past the content size"); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 3.0), 1.0, YES, NO, CGPointZero, nil); + XCTAssert(shouldFetch == YES, @"Fetch should begin when horizontally scrolling past the content size"); + + // In RTL scrolling is reversed, our remaining distance is actually our offset (3) which is more than our leading screen (1). So we do no fetch + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 3.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == NO, @"Fetch not should begin when horizontally scrolling past the content size"); } - (void)testVerticalScrollingSmallContentSize { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // when the content size is < screen size, the target offset will always be 0 - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 0.5), VERTICAL_OFFSET(0.0), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 0.5), VERTICAL_OFFSET(0.0), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 0.5), VERTICAL_OFFSET(0.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree"); } - (void)testHorizontalScrollingSmallContentSize { CGFloat screen = 1.0; ASBatchContext *context = [[ASBatchContext alloc] init]; // when the content size is < screen size, the target offset will always be 0 - BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 0.5), HORIZONTAL_OFFSET(0.0), 1.0, YES, CGPointZero, nil); + BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 0.5), HORIZONTAL_OFFSET(0.0), 1.0, YES, NO, CGPointZero, nil); XCTAssert(shouldFetch == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree"); + + // test RTL + BOOL shouldFetchRTL = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 0.5), HORIZONTAL_OFFSET(0.0), 1.0, YES, YES, CGPointZero, nil); + XCTAssert(shouldFetchRTL == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree"); } @end