Skip to content

Commit 42f0341

Browse files
Mykola Mokhnachimurchie
authored andcommitted
Properly adjust the orientation for full-screen shots (#16)
* Properly adjust the orientation for full-screen shots * Only fix the orientation if needed * Revert "Only fix the orientation if needed" This reverts commit fae7914d5df7752ef131af2845e4bfc2131021ed. * Tune error messages * Fix taking screenshots for elements with 'correct' frames in landscape mode * Apply some small refactoring * Use appFrame everywhere
1 parent 8496615 commit 42f0341

File tree

6 files changed

+49
-29
lines changed

6 files changed

+49
-29
lines changed

WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ - (NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error
5656
}
5757

5858
id mainScreen = [xcScreen valueForKey:@"mainScreen"];
59-
CGSize screenSize = FBAdjustDimensionsForApplication(FBApplication.fb_activeApplication.frame.size, (UIInterfaceOrientation)[self.class sharedDevice].orientation);
59+
FBApplication *activeApplication = FBApplication.fb_activeApplication;
60+
UIInterfaceOrientation orientation = activeApplication.interfaceOrientation;
6061
SEL mSelector = NSSelectorFromString(@"screenshotDataForQuality:rect:error:");
6162
NSMethodSignature *mSignature = [mainScreen methodSignatureForSelector:mSelector];
6263
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:mSignature];
@@ -67,18 +68,17 @@ - (NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error
6768
// and the resulting screenshot does not fit the memory buffer preallocated for it by the operating system
6869
NSUInteger quality = 1;
6970
[invocation setArgument:&quality atIndex:2];
71+
CGSize screenSize = FBAdjustDimensionsForApplication(activeApplication.frame.size, orientation);
7072
CGRect screenRect = CGRectMake(0, 0, screenSize.width, screenSize.height);
7173
[invocation setArgument:&screenRect atIndex:3];
7274
[invocation setArgument:&error atIndex:4];
7375
[invocation invoke];
74-
NSData __unsafe_unretained *result;
75-
[invocation getReturnValue:&result];
76-
if (nil == result) {
76+
NSData __unsafe_unretained *imageData;
77+
[invocation getReturnValue:&imageData];
78+
if (nil == imageData) {
7779
return nil;
7880
}
79-
// The resulting data is a JPEG image, so we need to convert it to PNG representation
80-
UIImage *image = [UIImage imageWithData:result];
81-
return (NSData *)UIImagePNGRepresentation(image);
81+
return FBAdjustScreenshotOrientationForApplication(imageData, orientation);
8282
}
8383

8484
- (BOOL)fb_fingerTouchShouldMatch:(BOOL)shouldMatch

WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ - (NSData *)fb_screenshotWithError:(NSError **)error
153153
NSUInteger quality = 1;
154154
[invocation setArgument:&quality atIndex:2];
155155
CGRect elementRect = self.frame;
156+
UIInterfaceOrientation orientation = self.application.interfaceOrientation;
157+
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
158+
// Workaround XCTest bug when element frame is returned as in portrait mode even if the screenshot is rotated
159+
XCElementSnapshot *parentWindow = [self.fb_lastSnapshot fb_parentMatchingType:XCUIElementTypeWindow];
160+
CGRect appFrame = self.application.frame;
161+
if (CGRectEqualToRect(appFrame, nil == parentWindow ? elementRect : parentWindow.frame)) {
162+
CGPoint fixedOrigin = orientation == UIInterfaceOrientationLandscapeLeft ?
163+
CGPointMake(appFrame.size.height - elementRect.origin.y - elementRect.size.height, elementRect.origin.x) :
164+
CGPointMake(elementRect.origin.y, appFrame.size.width - elementRect.origin.x - elementRect.size.width);
165+
elementRect = CGRectMake(fixedOrigin.x, fixedOrigin.y, elementRect.size.height, elementRect.size.width);
166+
}
167+
}
156168
[invocation setArgument:&elementRect atIndex:3];
157169
[invocation setArgument:&error atIndex:4];
158170
[invocation invoke];
@@ -161,26 +173,7 @@ - (NSData *)fb_screenshotWithError:(NSError **)error
161173
if (nil == imageData) {
162174
return nil;
163175
}
164-
165-
UIImage *image = [UIImage imageWithData:imageData];
166-
UIInterfaceOrientation orientation = self.application.interfaceOrientation;
167-
UIImageOrientation imageOrientation = UIImageOrientationUp;
168-
// The received element screenshot will be rotated, if the current interface orientation differs from portrait, so we need to fix that first
169-
if (orientation == UIInterfaceOrientationLandscapeRight) {
170-
imageOrientation = UIImageOrientationLeft;
171-
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
172-
imageOrientation = UIImageOrientationRight;
173-
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
174-
imageOrientation = UIImageOrientationDown;
175-
}
176-
CGSize size = image.size;
177-
UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));
178-
[[UIImage imageWithCGImage:(CGImageRef)[image CGImage] scale:1.0 orientation:imageOrientation] drawInRect:CGRectMake(0, 0, size.width, size.height)];
179-
UIImage *fixedImage = UIGraphicsGetImageFromCurrentImageContext();
180-
UIGraphicsEndImageContext();
181-
182-
// The resulting data is a JPEG image, so we need to convert it to PNG representation
183-
return (NSData *)UIImagePNGRepresentation(fixedImage);
176+
return FBAdjustScreenshotOrientationForApplication(imageData, orientation);
184177
}
185178

186179
@end

WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ - (nullable NSValue *)hitpointWithElement:(nullable XCUIElement *)element positi
5252
XCElementSnapshot *snapshot = element.fb_lastSnapshot;
5353
CGRect frameInWindow = snapshot.fb_frameInWindow;
5454
if (CGRectIsEmpty(frameInWindow)) {
55-
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen", element.debugDescription];
55+
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable", element.description];
5656
if (error) {
5757
*error = [[FBErrorBuilder.builder withDescription:description] build];
5858
}

WebDriverAgentLib/Utilities/FBMathUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ CGPoint FBInvertOffsetForOrientation(CGPoint offset, UIInterfaceOrientation orie
3636

3737
/*! Inverts size if necessary to match current screen orientation */
3838
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation);
39+
40+
/*! Fixes the screenshot orientation if necessary to match current screen orientation */
41+
NSData *FBAdjustScreenshotOrientationForApplication(NSData *screenshotData, UIInterfaceOrientation orientation);

WebDriverAgentLib/Utilities/FBMathUtils.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,27 @@ This verification is just to make sure the bug is still there (since height is n
8282
}
8383
return actualSize;
8484
}
85+
86+
NSData *FBAdjustScreenshotOrientationForApplication(NSData *screenshotData, UIInterfaceOrientation orientation)
87+
{
88+
UIImage *image = [UIImage imageWithData:screenshotData];
89+
UIImageOrientation imageOrientation;
90+
if (orientation == UIInterfaceOrientationLandscapeRight) {
91+
imageOrientation = UIImageOrientationLeft;
92+
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
93+
imageOrientation = UIImageOrientationRight;
94+
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
95+
imageOrientation = UIImageOrientationDown;
96+
} else {
97+
return (NSData *)UIImagePNGRepresentation(image);
98+
}
99+
100+
UIGraphicsBeginImageContext(CGSizeMake(image.size.width, image.size.height));
101+
[[UIImage imageWithCGImage:(CGImageRef)[image CGImage] scale:1.0 orientation:imageOrientation]
102+
drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
103+
UIImage *fixedImage = UIGraphicsGetImageFromCurrentImageContext();
104+
UIGraphicsEndImageContext();
105+
106+
// The resulting data should be a PNG image
107+
return (NSData *)UIImagePNGRepresentation(fixedImage);
108+
}

WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ - (nullable NSValue *)hitpointWithElement:(nullable XCUIElement *)element positi
131131
// An offset relative to the element is defined
132132
XCElementSnapshot *snapshot = element.fb_lastSnapshot;
133133
if (CGRectIsEmpty(snapshot.fb_frameInWindow)) {
134-
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen", element.debugDescription];
134+
NSString *description = [NSString stringWithFormat:@"The element '%@' is not visible on the screen and thus is not interactable", element.description];
135135
if (error) {
136136
*error = [[FBErrorBuilder.builder withDescription:description] build];
137137
}

0 commit comments

Comments
 (0)