Chromium Code Reviews| Index: chrome/browser/ui/certificate_viewer_mac.mm |
| diff --git a/chrome/browser/ui/certificate_viewer_mac.mm b/chrome/browser/ui/certificate_viewer_mac.mm |
| index 93dd9c2c91598b5b31e85855632c83042b44fe2f..bed695be3f4044c54dc74dcca4d7f773e7127736 100644 |
| --- a/chrome/browser/ui/certificate_viewer_mac.mm |
| +++ b/chrome/browser/ui/certificate_viewer_mac.mm |
| @@ -4,13 +4,76 @@ |
| #import "chrome/browser/ui/certificate_viewer_mac.h" |
| +#import <objc/runtime.h> |
| + |
| #include "base/mac/foundation_util.h" |
| +#include "base/mac/mac_util.h" |
| #include "base/mac/scoped_cftyperef.h" |
| #import "base/mac/scoped_nsobject.h" |
| #include "content/public/browser/web_contents.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util_mac.h" |
| +namespace { |
| + |
| +// The maximum height of the certificate panel. Imposed whenever Sierra's buggy |
| +// autolayout algorithm tries to change it. Doesn't affect user resizes. |
| +const CGFloat kMaxPanelSetFrameHeight = 400; |
| + |
| +// Pointer to the real implementation of -[SFCertificatePanel setFrame:..]. This |
| +// is cached so a correct lookup is performed before we add the override. |
| +IMP g_real_certificate_panel_setframe = nullptr; |
| + |
| +// Provide a workaround for a buggy autolayout algorithm in macOS Sierra when |
| +// running Chrome linked against the 10.10 SDK on macOS 10.12. |
| +// See http://crbug.com/643123 for more details. |
| +// Note it's not possible to inherit from SFCertificatePanel without triggering |
| +// *** Assertion failure in -[BrowserCrApplication |
| +// _commonBeginModalSessionForWindow:relativeToWindow:modalDelegate: |
| +// didEndSelector:contextInfo:], .../AppKit.subproj/NSApplication.m:4077 |
| +// After that assertion, the sheet simply refuses to continue loading. |
| +// It's also not possible to swizzle the -setFrame: method because |
| +// SFCertificatePanel doesn't define it. Attempting to swizzle that would |
| +// replace the implementation on NSWindow and constrain all dialogs. |
| +// So, provide a regular C method and append it to the SFCertificatePanel |
| +// implementation using the objc runtime. |
| +// TODO(tapted): Remove all of this when Chrome's SDK target gets bumped. |
| +id SFCertificatePanelSetFrameOverride(id self, |
| + SEL _cmd, |
| + NSRect frame, |
| + BOOL display, |
| + BOOL animate) { |
| + if (frame.size.height > kMaxPanelSetFrameHeight) |
| + frame.size.height = kMaxPanelSetFrameHeight; |
| + |
| + DCHECK(g_real_certificate_panel_setframe); |
| + return g_real_certificate_panel_setframe(self, _cmd, frame, display, animate); |
| +} |
| + |
| +void MaybeConstrainPanelSizeForSierraBug() { |
| +#if defined(MAC_OS_X_VERSION_10_11) && \ |
| + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11 |
| + // This is known not to be required when linking against the 10.11 SDK. Early |
| + // exit in that case but assume anything earlier is broken. |
| + return; |
| +#endif |
| + |
| + // It's also not required when running on El Capitan or earlier. |
| + if (base::mac::IsAtMostOS10_11() || g_real_certificate_panel_setframe) |
| + return; |
| + |
| + const SEL kSetFrame = @selector(setFrame:display:animate:); |
| + Method real_method = |
| + class_getInstanceMethod([SFCertificatePanel class], kSetFrame); |
| + const char* type_encoding = method_getTypeEncoding(real_method); |
| + g_real_certificate_panel_setframe = method_getImplementation(real_method); |
| + DCHECK(g_real_certificate_panel_setframe); |
| + IMP method = reinterpret_cast<IMP>(&SFCertificatePanelSetFrameOverride); |
| + 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.
|
| +} |
| + |
| +} // namespace |
| + |
| @interface SFCertificatePanel (SystemPrivate) |
| // A system-private interface that dismisses a panel whose sheet was started by |
| // -beginSheetForWindow: |
| @@ -88,6 +151,8 @@ |
| } |
| - (void)showCertificateSheet:(NSWindow*)window { |
| + MaybeConstrainPanelSizeForSierraBug(); |
| + |
| [panel_ beginSheetForWindow:window |
| modalDelegate:self |
| didEndSelector:@selector(sheetDidEnd:returnCode:context:) |