1// Copyright 2017 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "headless/lib/browser/headless_browser_impl.h" 6 7#import "base/mac/scoped_objc_class_swizzler.h" 8#include "base/no_destructor.h" 9#include "content/public/browser/render_widget_host_view.h" 10#include "content/public/browser/web_contents.h" 11#include "headless/lib/browser/headless_web_contents_impl.h" 12#import "ui/base/cocoa/base_view.h" 13#import "ui/gfx/mac/coordinate_conversion.h" 14 15// Overrides events and actions for NSPopUpButtonCell. 16@interface FakeNSPopUpButtonCell : NSObject 17@end 18 19@implementation FakeNSPopUpButtonCell 20 21- (void)performClickWithFrame:(NSRect)frame inView:(NSView*)view { 22} 23 24- (void)attachPopUpWithFrame:(NSRect)frame inView:(NSView*)view { 25} 26 27@end 28 29namespace headless { 30 31namespace { 32 33// Swizzles all event and acctions for NSPopUpButtonCell to avoid showing in 34// headless mode. 35class HeadlessPopUpMethods { 36 public: 37 static void Init() { 38 static base::NoDestructor<HeadlessPopUpMethods> swizzler; 39 ALLOW_UNUSED_LOCAL(swizzler); 40 } 41 42 private: 43 friend class base::NoDestructor<HeadlessPopUpMethods>; 44 HeadlessPopUpMethods() 45 : popup_perform_click_swizzler_([NSPopUpButtonCell class], 46 [FakeNSPopUpButtonCell class], 47 @selector(performClickWithFrame:inView:)), 48 popup_attach_swizzler_([NSPopUpButtonCell class], 49 [FakeNSPopUpButtonCell class], 50 @selector(attachPopUpWithFrame:inView:)) {} 51 52 base::mac::ScopedObjCClassSwizzler popup_perform_click_swizzler_; 53 base::mac::ScopedObjCClassSwizzler popup_attach_swizzler_; 54 55 DISALLOW_COPY_AND_ASSIGN(HeadlessPopUpMethods); 56}; 57 58NSString* const kActivityReason = @"Batch headless process"; 59const NSActivityOptions kActivityOptions = 60 (NSActivityUserInitiatedAllowingIdleSystemSleep | 61 NSActivityLatencyCritical) & 62 ~(NSActivitySuddenTerminationDisabled | 63 NSActivityAutomaticTerminationDisabled); 64 65} // namespace 66 67void HeadlessBrowserImpl::PlatformInitialize() { 68 HeadlessPopUpMethods::Init(); 69} 70 71void HeadlessBrowserImpl::PlatformStart() { 72 // Disallow headless to be throttled as a background process. 73 [[NSProcessInfo processInfo] beginActivityWithOptions:kActivityOptions 74 reason:kActivityReason]; 75} 76 77void HeadlessBrowserImpl::PlatformInitializeWebContents( 78 HeadlessWebContentsImpl* web_contents) { 79 NSView* web_view = 80 web_contents->web_contents()->GetNativeView().GetNativeNSView(); 81 [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 82 // TODO(eseckler): Support enabling BeginFrameControl on Mac. This is tricky 83 // because it's a ui::Compositor startup setting and ui::Compositors are 84 // recycled on Mac, see browser_compositor_view_mac.mm. 85} 86 87void HeadlessBrowserImpl::PlatformSetWebContentsBounds( 88 HeadlessWebContentsImpl* web_contents, 89 const gfx::Rect& bounds) { 90 NSView* web_view = 91 web_contents->web_contents()->GetNativeView().GetNativeNSView(); 92 NSRect frame = gfx::ScreenRectToNSRect(bounds); 93 [web_view setFrame:frame]; 94 95 content::RenderWidgetHostView* host_view = 96 web_contents->web_contents()->GetRenderWidgetHostView(); 97 if (host_view) 98 host_view->SetWindowFrameInScreen(bounds); 99} 100 101ui::Compositor* HeadlessBrowserImpl::PlatformGetCompositor( 102 HeadlessWebContentsImpl* web_contents) { 103 // TODO(eseckler): Support BeginFrameControl on Mac. 104 return nullptr; 105} 106 107} // namespace headless 108