mirror of
https://github.com/hanzoai/Detox.git
synced 2026-09-24 16:55:12 +00:00
Different drawing algorithm
This commit is contained in:
@@ -207,21 +207,18 @@ DTX_DIRECT_MEMBERS
|
||||
|
||||
DTXAssert(indexOfTestedWindow != NSNotFound, @"Window hierarchy mutated while iterated; should not happen");
|
||||
|
||||
if(testedView != nil)
|
||||
{
|
||||
[windowToUse dtx_drawViewHierarchyUpToSubview:testedView inRect:windowToUse.bounds afterScreenUpdates:NO];
|
||||
}
|
||||
else
|
||||
if(testedView == nil)
|
||||
{
|
||||
[UIColor.blackColor setFill];
|
||||
[[UIBezierPath bezierPathWithRect:windowToUse.bounds] fill];
|
||||
[windowToUse drawViewHierarchyInRect:windowToUse.bounds afterScreenUpdates:NO];
|
||||
}
|
||||
|
||||
[windowToUse dtx_drawViewHierarchyUpToSubview:testedView inRect:windowToUse.bounds afterScreenUpdates:NO];
|
||||
|
||||
for (NSUInteger idx = indexOfTestedWindow + 1; idx < windows.count; idx++) {
|
||||
UIWindow* currentWindow = windows[idx];
|
||||
|
||||
[currentWindow drawViewHierarchyInRect:currentWindow.bounds afterScreenUpdates:NO];
|
||||
[currentWindow dtx_drawViewHierarchyUpToSubview:nil inRect:currentWindow.bounds afterScreenUpdates:NO];
|
||||
}
|
||||
|
||||
//Overlay the keyboard scene windows on top
|
||||
@@ -233,7 +230,7 @@ DTX_DIRECT_MEMBERS
|
||||
windows = [UIWindow dtx_allWindowsForScene:scene];
|
||||
|
||||
for (UIWindow* keyboardSceneWindow in windows) {
|
||||
[keyboardSceneWindow drawViewHierarchyInRect:keyboardSceneWindow.bounds afterScreenUpdates:NO];
|
||||
[keyboardSceneWindow dtx_drawViewHierarchyUpToSubview:nil inRect:keyboardSceneWindow.bounds afterScreenUpdates:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,126 @@
|
||||
#import "UIView+Drawing.h"
|
||||
@import ObjectiveC;
|
||||
|
||||
@interface CALayer ()
|
||||
|
||||
- (void)_renderSublayersInContext:(struct CGContext *)arg1;
|
||||
- (void)_renderForegroundInContext:(struct CGContext *)arg1;
|
||||
- (void)_renderBackgroundInContext:(struct CGContext *)arg1;
|
||||
|
||||
@end
|
||||
|
||||
@interface CALayer (BackdropDrawingUtils) @end
|
||||
@implementation CALayer (BackdropDrawingUtils)
|
||||
|
||||
static BOOL _hack = NO;
|
||||
static BOOL _found = NO;
|
||||
static UIView* _lookingFor = nil;
|
||||
|
||||
static NSArray* (*__orig_CALayer_sublayers)(id self, SEL _cmd);
|
||||
static NSArray* _dtx_layer_sublayers(id self, SEL _cmd)
|
||||
{
|
||||
if(_hack == NO)
|
||||
{
|
||||
return __orig_CALayer_sublayers(self, _cmd);
|
||||
}
|
||||
|
||||
NSArray* zSorted = [__orig_CALayer_sublayers(self, _cmd) sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(CALayer* _Nonnull obj1, CALayer* _Nonnull obj2) {
|
||||
return [@(obj1.zPosition) compare:@(obj2.zPosition)];
|
||||
}];
|
||||
|
||||
return zSorted;
|
||||
}
|
||||
|
||||
static void (*__orig_CALayer_renderForegroundInContext)(id self, SEL _cmd, CGContextRef ctx);
|
||||
static void _dtx_layer_renderForegroundInContext(CALayer* self, SEL _cmd, CGContextRef ctx)
|
||||
{
|
||||
if(_hack == NO)
|
||||
{
|
||||
__orig_CALayer_renderForegroundInContext(self, _cmd, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
UIView* delegate = (self.delegate != nil && [self.delegate isKindOfClass:UIView.class]) ? (id)self.delegate : nil;
|
||||
|
||||
if(_found == NO && (delegate == nil || [_lookingFor isDescendantOfView:delegate] == NO))
|
||||
{
|
||||
//This layer tree is under the subview we are looking for.
|
||||
return;
|
||||
}
|
||||
|
||||
if([_lookingFor isDescendantOfView:delegate] == YES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__orig_CALayer_renderForegroundInContext(self, _cmd, ctx);
|
||||
}
|
||||
|
||||
static void (*__orig_CALayer_renderBackgroundInContext)(id self, SEL _cmd, CGContextRef ctx);
|
||||
static void _dtx_layer_renderBackgroundInContext(CALayer* self, SEL _cmd, CGContextRef ctx)
|
||||
{
|
||||
if(_hack == NO)
|
||||
{
|
||||
__orig_CALayer_renderBackgroundInContext(self, _cmd, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
UIView* delegate = (self.delegate != nil && [self.delegate isKindOfClass:UIView.class]) ? (id)self.delegate : nil;
|
||||
|
||||
if(_found == NO && (delegate == nil || [_lookingFor isDescendantOfView:delegate] == NO))
|
||||
{
|
||||
//This layer tree is under the subview we are looking for.
|
||||
return;
|
||||
}
|
||||
|
||||
if([_lookingFor isDescendantOfView:delegate] == YES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__orig_CALayer_renderBackgroundInContext(self, _cmd, ctx);
|
||||
}
|
||||
|
||||
static void (*__orig_CALayer_renderInContext)(id self, SEL _cmd, CGContextRef ctx);
|
||||
static void _dtx_layer_renderInContext(CALayer* self, SEL _cmd, CGContextRef ctx)
|
||||
{
|
||||
if(_hack == NO)
|
||||
{
|
||||
__orig_CALayer_renderInContext(self, _cmd, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
UIView* delegate = (self.delegate != nil && [self.delegate isKindOfClass:UIView.class]) ? (id)self.delegate : nil;
|
||||
|
||||
if(_found == NO && (delegate == nil || [_lookingFor isDescendantOfView:delegate] == NO))
|
||||
{
|
||||
//This layer tree is under the subview we are looking for.
|
||||
return;
|
||||
}
|
||||
|
||||
if(delegate == _lookingFor)
|
||||
{
|
||||
//This layer tree is the one we are looking for, mark as found and return.
|
||||
_found = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
if(_found == YES)
|
||||
{
|
||||
__orig_CALayer_renderInContext(self, _cmd, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// [self _renderSublayersInContext:ctx];
|
||||
__orig_CALayer_renderInContext(self, _cmd, ctx);
|
||||
}
|
||||
|
||||
static void (*__orig_VKMapView_renderInContext)(id self, SEL _cmd, CGContextRef ctx);
|
||||
+ (void)_dtx_applyDrawingFixes
|
||||
{
|
||||
_hack = YES;
|
||||
_found = NO;
|
||||
|
||||
Class cls = NSClassFromString(@"VKMapView");
|
||||
if(cls != nil)
|
||||
{
|
||||
@@ -34,6 +147,8 @@ static void (*__orig_VKMapView_renderInContext)(id self, SEL _cmd, CGContextRef
|
||||
__orig_VKMapView_renderInContext = (void*)method_getImplementation(m);
|
||||
method_setImplementation(m, (void*)__orig_VKMapView_renderInContext);
|
||||
}
|
||||
|
||||
_hack = NO;
|
||||
}
|
||||
|
||||
+ (void)load
|
||||
@@ -42,10 +157,26 @@ static void (*__orig_VKMapView_renderInContext)(id self, SEL _cmd, CGContextRef
|
||||
{
|
||||
Method m = class_getInstanceMethod(CALayer.class, @selector(renderInContext:));
|
||||
class_addMethod(NSClassFromString(@"CABackdropLayer"), method_getName(m), (IMP)_dtx_backdrop_renderInContext, method_getTypeEncoding(m));
|
||||
|
||||
m = class_getInstanceMethod(CALayer.class, @selector(renderInContext:));
|
||||
__orig_CALayer_renderInContext = (void*)method_getImplementation(m);
|
||||
method_setImplementation(m, (void*)_dtx_layer_renderInContext);
|
||||
|
||||
m = class_getInstanceMethod(CALayer.class, @selector(_renderForegroundInContext:));
|
||||
__orig_CALayer_renderForegroundInContext = (void*)method_getImplementation(m);
|
||||
method_setImplementation(m, (void*)_dtx_layer_renderForegroundInContext);
|
||||
|
||||
m = class_getInstanceMethod(CALayer.class, @selector(_renderBackgroundInContext:));
|
||||
__orig_CALayer_renderBackgroundInContext = (void*)method_getImplementation(m);
|
||||
method_setImplementation(m, (void*)_dtx_layer_renderBackgroundInContext);
|
||||
|
||||
m = class_getInstanceMethod(CALayer.class, @selector(sublayers));
|
||||
__orig_CALayer_sublayers = (void*)method_getImplementation(m);
|
||||
method_setImplementation(m, (void*)_dtx_layer_sublayers);
|
||||
}
|
||||
}
|
||||
|
||||
static void _dtx_map_renderInContext(CALayer* self, SEL _sel, CGContextRef ctx)
|
||||
static void _dtx_map_renderInContext(CALayer* self, SEL _cmd, CGContextRef ctx)
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextBeginTransparencyLayer(ctx, nil);
|
||||
@@ -69,7 +200,7 @@ static void _dtx_map_renderInContext(CALayer* self, SEL _sel, CGContextRef ctx)
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
static void _dtx_backdrop_renderInContext(CALayer* self, SEL _sel, CGContextRef ctx)
|
||||
static void _dtx_backdrop_renderInContext(CALayer* self, SEL _cmd, CGContextRef ctx)
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextBeginTransparencyLayer(ctx, nil);
|
||||
@@ -89,60 +220,37 @@ static void _dtx_backdrop_renderInContext(CALayer* self, SEL _sel, CGContextRef
|
||||
DTX_DIRECT_MEMBERS
|
||||
@implementation UIView (Drawing)
|
||||
|
||||
- (void)dtx_drawViewHierarchyUpToSubview:(UIView*)subview inRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates
|
||||
{
|
||||
[CALayer _dtx_applyDrawingFixes];
|
||||
|
||||
[self _dtx_drawViewHierarchyUpToSubview:subview rootView:self inRect:rect afterScreenUpdates:afterUpdates];
|
||||
|
||||
[CALayer _dtx_restoreDrawingDefaults];
|
||||
}
|
||||
|
||||
CALayer* _DTXLayerForView(UIView* view, BOOL afterUpdates)
|
||||
{
|
||||
return afterUpdates ? view.layer : view.layer.presentationLayer;
|
||||
}
|
||||
|
||||
- (void)_dtx_drawViewHierarchyUpToSubview:(UIView*)subview rootView:(UIView*)rootView inRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates
|
||||
- (void)dtx_drawViewHierarchyUpToSubview:(UIView*)subview inRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates
|
||||
{
|
||||
[CALayer _dtx_applyDrawingFixes];
|
||||
_lookingFor = subview;
|
||||
|
||||
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
||||
CGContextSaveGState(ctx);
|
||||
|
||||
if(subview == self)
|
||||
// Center the context around the view's anchor point
|
||||
CGContextTranslateCTM(ctx, self.center.x, self.center.y);
|
||||
// Apply the view's transform about the anchor point
|
||||
CGContextConcatCTM(ctx, self.transform);
|
||||
// Offset by the portion of the bounds left of and above the anchor point
|
||||
CGContextTranslateCTM(ctx, -self.bounds.size.width * self.layer.anchorPoint.x, -self.bounds.size.height * self.layer.anchorPoint.y);
|
||||
|
||||
if(subview == nil)
|
||||
{
|
||||
return;
|
||||
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:afterUpdates];
|
||||
}
|
||||
|
||||
if([subview isDescendantOfView:self] == NO)
|
||||
else
|
||||
{
|
||||
[_DTXLayerForView(self, afterUpdates) renderInContext:ctx];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray* zSorted = [self.subviews.reverseObjectEnumerator.allObjects sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(UIView* _Nonnull obj1, UIView* _Nonnull obj2) {
|
||||
return [@(obj2.layer.zPosition) compare:@(obj1.layer.zPosition)];
|
||||
}];
|
||||
|
||||
for (UIView* obj in zSorted) {
|
||||
if([subview isDescendantOfView:obj] == NO)
|
||||
{
|
||||
CGContextSaveGState(ctx);
|
||||
CGRect bounds = obj.bounds;
|
||||
CGRect boundsInRootViewCoords = [rootView convertRect:bounds fromView:obj];
|
||||
CGContextTranslateCTM(ctx, boundsInRootViewCoords.origin.x, boundsInRootViewCoords.origin.y);
|
||||
CALayer* layer = _DTXLayerForView(obj, afterUpdates);
|
||||
CGContextConcatCTM(ctx, [layer affineTransform]);
|
||||
[layer renderInContext:ctx];
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
[obj _dtx_drawViewHierarchyUpToSubview:subview rootView:rootView inRect:obj.bounds afterScreenUpdates:afterUpdates];
|
||||
|
||||
//Everything else is now under the view we are searching for.
|
||||
return;
|
||||
}
|
||||
}
|
||||
CGContextRestoreGState(ctx);
|
||||
[CALayer _dtx_restoreDrawingDefaults];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user