Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/full_size_content_window.h" | 5 #import "chrome/browser/ui/cocoa/full_size_content_window.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/mac/foundation_util.h" | 8 #include "base/mac/foundation_util.h" |
| 9 #include "base/mac/scoped_objc_class_swizzler.h" | |
| 9 | 10 |
| 10 @interface FullSizeContentWindow () | 11 @interface FullSizeContentWindow () |
| 11 | 12 |
| 12 + (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle; | 13 + (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle; |
| 13 | 14 |
| 14 @end | 15 @end |
| 15 | 16 |
| 16 // This view always takes the size of its superview. It is intended to be used | 17 // This view always takes the size of its superview. It is intended to be used |
| 17 // as a NSWindow's contentView. It is needed because NSWindow's implementation | 18 // as a NSWindow's contentView. It is needed because NSWindow's implementation |
| 18 // explicitly resizes the contentView at inopportune times. | 19 // explicitly resizes the contentView at inopportune times. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 37 } | 38 } |
| 38 | 39 |
| 39 - (void)forceFrame:(NSRect)frame { | 40 - (void)forceFrame:(NSRect)frame { |
| 40 forceFrameFlag_ = YES; | 41 forceFrameFlag_ = YES; |
| 41 [super setFrame:frame]; | 42 [super setFrame:frame]; |
| 42 forceFrameFlag_ = NO; | 43 forceFrameFlag_ = NO; |
| 43 } | 44 } |
| 44 | 45 |
| 45 @end | 46 @end |
| 46 | 47 |
| 48 static BOOL disableSymbolication = NO; | |
| 49 | |
| 50 @implementation NSObject (FullSizeContentWindowSwizzling) | |
| 51 | |
| 52 // This is the replacement method for | |
| 53 // [_NSCallStackArray descriptionWithLocale:indent:] (see +load below). | |
| 54 // _NSCallStackArray can't be linked against because it's a private class, | |
| 55 // so it's not possible to add this method to the class as a category. Instead, | |
| 56 // just add it to NSObject, which is an ancestor class to _NSCallStackArray. | |
|
erikchen
2016/01/05 20:48:44
I'm not a huge fan of adding methods to NSObject,
shrike
2016/01/05 21:27:37
Yeah, that should work - I will work on that.
shrike
2016/01/05 22:03:17
Turns out that doing this makes it a little tricke
| |
| 57 - (NSString*)chromeSwizzledDescriptionWithLocale:(id)aLocale | |
| 58 indent:(unsigned long long)indent { | |
| 59 return disableSymbolication ? | |
| 60 @"" : [self chromeSwizzledDescriptionWithLocale:aLocale indent:indent]; | |
| 61 } | |
| 62 | |
| 63 @end | |
| 64 | |
| 47 @implementation FullSizeContentWindow | 65 @implementation FullSizeContentWindow |
| 48 | 66 |
| 49 #pragma mark - Lifecycle | 67 #pragma mark - Lifecycle |
| 50 | 68 |
| 69 // In initWithContentRect:styleMask:backing:defer:, the call to | |
| 70 // [NSView addSubview:positioned:relativeTo:] causes NSWindow to complain that | |
| 71 // an unknown view is being added to it, and to generate a stack trace. | |
| 72 // Not only does this stack trace pollute the console, it can also take hundreds | |
| 73 // of milliseconds to generate (because of symbolication). The AppKit uses an | |
| 74 // _NSCallStackArray to dump the symbols to the console - by swizzling | |
| 75 // descriptionWithLocale:indent: we can disable this output. See | |
| 76 // crbug.com/520373 . | |
| 77 + (void)load { | |
|
erikchen
2016/01/05 20:48:44
Instead of doing this in +load, can we do it right
shrike
2016/01/05 21:27:37
Doing it that way would be simpler, and would allo
erikchen
2016/01/05 21:33:28
Hm. Fair enough. Let's keep it in +load then.
| |
| 78 static dispatch_once_t onceToken; | |
| 79 dispatch_once(&onceToken, ^{ | |
| 80 Class callStackArrayClass = NSClassFromString(@"_NSCallStackArray"); | |
| 81 SEL originalSelector = @selector(descriptionWithLocale:indent:); | |
| 82 SEL swizzledSelector = | |
| 83 @selector(chromeSwizzledDescriptionWithLocale:indent:); | |
| 84 | |
| 85 if (callStackArrayClass && originalSelector && swizzledSelector) { | |
| 86 CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler, | |
| 87 callStackSupressor, (callStackArrayClass, | |
| 88 originalSelector, swizzledSelector)); | |
| 89 | |
| 90 // Prevent compiler from complaining about callStackSupressor never being | |
| 91 // used. | |
| 92 callStackSupressor.GetOriginalImplementation(); | |
|
erikchen
2016/01/05 20:48:44
better to suppress the clang diagnostic error:
ht
shrike
2016/01/05 21:27:37
Great! I wasn't sure how to deal with this.
| |
| 93 } | |
| 94 }); | |
| 95 } | |
| 96 | |
| 51 - (instancetype)init { | 97 - (instancetype)init { |
| 52 NOTREACHED(); | 98 NOTREACHED(); |
| 53 return nil; | 99 return nil; |
| 54 } | 100 } |
| 55 | 101 |
| 56 - (instancetype)initWithContentRect:(NSRect)contentRect | 102 - (instancetype)initWithContentRect:(NSRect)contentRect |
| 57 styleMask:(NSUInteger)windowStyle | 103 styleMask:(NSUInteger)windowStyle |
| 58 backing:(NSBackingStoreType)bufferingType | 104 backing:(NSBackingStoreType)bufferingType |
| 59 defer:(BOOL)deferCreation { | 105 defer:(BOOL)deferCreation { |
| 60 return [self initWithContentRect:contentRect | 106 return [self initWithContentRect:contentRect |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 80 chromeWindowView_.reset([[FullSizeContentView alloc] init]); | 126 chromeWindowView_.reset([[FullSizeContentView alloc] init]); |
| 81 [chromeWindowView_ | 127 [chromeWindowView_ |
| 82 setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; | 128 setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
| 83 [self setContentView:chromeWindowView_]; | 129 [self setContentView:chromeWindowView_]; |
| 84 [chromeWindowView_ setFrame:[[chromeWindowView_ superview] bounds]]; | 130 [chromeWindowView_ setFrame:[[chromeWindowView_ superview] bounds]]; |
| 85 | 131 |
| 86 // Our content view overlaps the window control buttons, so we must ensure | 132 // Our content view overlaps the window control buttons, so we must ensure |
| 87 // it is positioned below the buttons. | 133 // it is positioned below the buttons. |
| 88 NSView* superview = [chromeWindowView_ superview]; | 134 NSView* superview = [chromeWindowView_ superview]; |
| 89 [chromeWindowView_ removeFromSuperview]; | 135 [chromeWindowView_ removeFromSuperview]; |
| 136 | |
| 137 // Prevent the AppKit from sending a complaint to the console in | |
| 138 // response to our upcoming call to addSubview:positioned:relativeTo: by | |
| 139 // temporarily routing stdErr to /dev/null. | |
| 140 static int devNullFD = -1; | |
| 141 if (devNullFD == -1) { | |
| 142 devNullFD = open("/dev/null", O_WRONLY); | |
|
erikchen
2016/01/05 20:48:44
Can you use [NSFileHandle fileHandleWithNullDevice
erikchen
2016/01/05 20:53:43
nevermind. It's probably easier to just use what y
| |
| 143 } | |
| 144 int stdErrorDescriptor = dup(2); | |
| 145 dup2(devNullFD, 2); | |
| 146 | |
| 147 // The AppKit's complaint also contains a backtrace, which can take | |
| 148 // significant time to symbolicate. See +load for more info. | |
| 149 disableSymbolication = YES; | |
| 150 | |
| 90 [superview addSubview:chromeWindowView_ | 151 [superview addSubview:chromeWindowView_ |
| 91 positioned:NSWindowBelow | 152 positioned:NSWindowBelow |
| 92 relativeTo:nil]; | 153 relativeTo:nil]; |
| 154 | |
| 155 // Clean up from the AppKit console message workaround. | |
| 156 disableSymbolication = NO; | |
| 157 dup2(stdErrorDescriptor, 2); | |
| 158 close(stdErrorDescriptor); | |
|
erikchen
2016/01/05 20:48:44
Is this call necessary? Doesn't the call to dup2 a
shrike
2016/01/05 21:27:37
The man page says, "dup2() makes newfd be the copy
erikchen
2016/01/05 21:33:28
you're right. I confused stdErrorDescriptor with d
| |
| 93 } | 159 } |
| 94 } | 160 } |
| 95 return self; | 161 return self; |
| 96 } | 162 } |
| 97 | 163 |
| 98 - (void)forceContentViewFrame:(NSRect)frame { | 164 - (void)forceContentViewFrame:(NSRect)frame { |
| 99 FullSizeContentView* contentView = | 165 FullSizeContentView* contentView = |
| 100 base::mac::ObjCCast<FullSizeContentView>(chromeWindowView_); | 166 base::mac::ObjCCast<FullSizeContentView>(chromeWindowView_); |
| 101 [contentView forceFrame:frame]; | 167 [contentView forceFrame:frame]; |
| 102 } | 168 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 127 return [super contentRectForFrameRect:fRect styleMask:aStyle]; | 193 return [super contentRectForFrameRect:fRect styleMask:aStyle]; |
| 128 } | 194 } |
| 129 | 195 |
| 130 - (NSRect)contentRectForFrameRect:(NSRect)frameRect { | 196 - (NSRect)contentRectForFrameRect:(NSRect)frameRect { |
| 131 if (chromeWindowView_) | 197 if (chromeWindowView_) |
| 132 return frameRect; | 198 return frameRect; |
| 133 return [super contentRectForFrameRect:frameRect]; | 199 return [super contentRectForFrameRect:frameRect]; |
| 134 } | 200 } |
| 135 | 201 |
| 136 @end | 202 @end |
| OLD | NEW |