Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/certificate_viewer_mac.h" | 5 #import "chrome/browser/ui/certificate_viewer_mac.h" |
| 6 | 6 |
| 7 #import <objc/runtime.h> | |
| 8 | |
| 7 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
| 10 #include "base/mac/mac_util.h" | |
| 8 #include "base/mac/scoped_cftyperef.h" | 11 #include "base/mac/scoped_cftyperef.h" |
| 9 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
| 10 #include "content/public/browser/web_contents.h" | 13 #include "content/public/browser/web_contents.h" |
| 11 #include "net/cert/x509_certificate.h" | 14 #include "net/cert/x509_certificate.h" |
| 12 #include "net/cert/x509_util_mac.h" | 15 #include "net/cert/x509_util_mac.h" |
| 13 | 16 |
| 17 namespace { | |
| 18 | |
| 19 // The maximum height of the certificate panel. Imposed whenever Sierra's buggy | |
| 20 // autolayout algorithm tries to change it. Doesn't affect user resizes. | |
| 21 const CGFloat kMaxPanelSetFrameHeight = 400; | |
| 22 | |
| 23 // Pointer to the real implementation of -[SFCertificatePanel setFrame:..]. This | |
| 24 // is cached so a correct lookup is performed before we add the override. | |
| 25 IMP g_real_certificate_panel_setframe = nullptr; | |
| 26 | |
| 27 // Provide a workaround for a buggy autolayout algorithm in macOS Sierra when | |
| 28 // running Chrome linked against the 10.10 SDK on macOS 10.12. | |
| 29 // See http://crbug.com/643123 for more details. | |
| 30 // Note it's not possible to inherit from SFCertificatePanel without triggering | |
| 31 // *** Assertion failure in -[BrowserCrApplication | |
| 32 // _commonBeginModalSessionForWindow:relativeToWindow:modalDelegate: | |
| 33 // didEndSelector:contextInfo:], .../AppKit.subproj/NSApplication.m:4077 | |
| 34 // After that assertion, the sheet simply refuses to continue loading. | |
| 35 // It's also not possible to swizzle the -setFrame: method because | |
| 36 // SFCertificatePanel doesn't define it. Attempting to swizzle that would | |
| 37 // replace the implementation on NSWindow and constrain all dialogs. | |
| 38 // So, provide a regular C method and append it to the SFCertificatePanel | |
| 39 // implementation using the objc runtime. | |
| 40 // TODO(tapted): Remove all of this when Chrome's SDK target gets bumped. | |
| 41 id SFCertificatePanelSetFrameOverride(id self, | |
| 42 SEL _cmd, | |
| 43 NSRect frame, | |
| 44 BOOL display, | |
| 45 BOOL animate) { | |
| 46 if (frame.size.height > kMaxPanelSetFrameHeight) | |
| 47 frame.size.height = kMaxPanelSetFrameHeight; | |
| 48 | |
| 49 DCHECK(g_real_certificate_panel_setframe); | |
| 50 return g_real_certificate_panel_setframe(self, _cmd, frame, display, animate); | |
| 51 } | |
| 52 | |
| 53 void MaybeConstrainPanelSizeForSierraBug() { | |
| 54 #if defined(MAC_OS_X_VERSION_10_11) && \ | |
| 55 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11 | |
| 56 // This is known not to be required when linking against the 10.11 SDK. Early | |
| 57 // exit in that case but assume anything earlier is broken. | |
| 58 return; | |
| 59 #endif | |
| 60 | |
| 61 // It's also not required when running on El Capitan or earlier. | |
| 62 if (base::mac::IsAtMostOS10_11() || g_real_certificate_panel_setframe) | |
| 63 return; | |
| 64 | |
| 65 const SEL kSetFrame = @selector(setFrame:display:animate:); | |
| 66 Method real_method = | |
| 67 class_getInstanceMethod([SFCertificatePanel class], kSetFrame); | |
| 68 const char* type_encoding = method_getTypeEncoding(real_method); | |
| 69 g_real_certificate_panel_setframe = method_getImplementation(real_method); | |
| 70 DCHECK(g_real_certificate_panel_setframe); | |
| 71 IMP method = reinterpret_cast<IMP>(&SFCertificatePanelSetFrameOverride); | |
| 72 class_addMethod([SFCertificatePanel class], kSetFrame, method, type_encoding); | |
|
Mark Mentovai
2016/09/21 12:30:16
Check the return value, at least via a DCHECK. Thi
tapted
2016/09/21 13:07:04
Done.
| |
| 73 } | |
| 74 | |
| 75 } // namespace | |
| 76 | |
| 14 @interface SFCertificatePanel (SystemPrivate) | 77 @interface SFCertificatePanel (SystemPrivate) |
| 15 // A system-private interface that dismisses a panel whose sheet was started by | 78 // A system-private interface that dismisses a panel whose sheet was started by |
| 16 // -beginSheetForWindow: | 79 // -beginSheetForWindow: |
| 17 // modalDelegate: | 80 // modalDelegate: |
| 18 // didEndSelector: | 81 // didEndSelector: |
| 19 // contextInfo: | 82 // contextInfo: |
| 20 // certificates: | 83 // certificates: |
| 21 // showGroup: | 84 // showGroup: |
| 22 // as though the user clicked the button identified by returnCode. Verified | 85 // as though the user clicked the button identified by returnCode. Verified |
| 23 // present in 10.8. | 86 // present in 10.8. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 return self; | 144 return self; |
| 82 } | 145 } |
| 83 | 146 |
| 84 - (void)sheetDidEnd:(NSWindow*)parent | 147 - (void)sheetDidEnd:(NSWindow*)parent |
| 85 returnCode:(NSInteger)returnCode | 148 returnCode:(NSInteger)returnCode |
| 86 context:(void*)context { | 149 context:(void*)context { |
| 87 NOTREACHED(); // Subclasses must implement this. | 150 NOTREACHED(); // Subclasses must implement this. |
| 88 } | 151 } |
| 89 | 152 |
| 90 - (void)showCertificateSheet:(NSWindow*)window { | 153 - (void)showCertificateSheet:(NSWindow*)window { |
| 154 MaybeConstrainPanelSizeForSierraBug(); | |
| 155 | |
| 91 [panel_ beginSheetForWindow:window | 156 [panel_ beginSheetForWindow:window |
| 92 modalDelegate:self | 157 modalDelegate:self |
| 93 didEndSelector:@selector(sheetDidEnd:returnCode:context:) | 158 didEndSelector:@selector(sheetDidEnd:returnCode:context:) |
| 94 contextInfo:nil | 159 contextInfo:nil |
| 95 certificates:certificates_ | 160 certificates:certificates_ |
| 96 showGroup:YES]; | 161 showGroup:YES]; |
| 97 } | 162 } |
| 98 | 163 |
| 99 - (void)closeCertificateSheet { | 164 - (void)closeCertificateSheet { |
| 100 // Closing the sheet using -[NSApp endSheet:] doesn't work so use the private | 165 // Closing the sheet using -[NSApp endSheet:] doesn't work so use the private |
| 101 // method. | 166 // method. |
| 102 [panel_ _dismissWithCode:NSFileHandlingPanelCancelButton]; | 167 [panel_ _dismissWithCode:NSFileHandlingPanelCancelButton]; |
| 103 certificates_.reset(); | 168 certificates_.reset(); |
| 104 } | 169 } |
| 105 | 170 |
| 106 - (void)releaseSheetWindow { | 171 - (void)releaseSheetWindow { |
| 107 panel_.reset(); | 172 panel_.reset(); |
| 108 } | 173 } |
| 109 | 174 |
| 110 - (NSWindow*)certificatePanel { | 175 - (NSWindow*)certificatePanel { |
| 111 return panel_; | 176 return panel_; |
| 112 } | 177 } |
| 113 | 178 |
| 114 @end | 179 @end |
| OLD | NEW |