 Chromium Code Reviews
 Chromium Code Reviews Issue 3176027:
  Mac: Well-behaved accelerated plugins, actual fix  (Closed)
    
  
    Issue 3176027:
  Mac: Well-behaved accelerated plugins, actual fix  (Closed) 
  | Index: chrome/browser/renderer_host/render_widget_host_view_mac.mm | 
| diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm | 
| index 4a634b2b2c32afd7dbd6bbf49cfce77f2ccf6c31..37bd963d564fb9fe8c084560f789dd7e1d7bc3e1 100644 | 
| --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm | 
| +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm | 
| @@ -135,6 +135,13 @@ void DisablePasswordInput() { | 
| // This subclass of NSView hosts the output of accelerated plugins on | 
| // the page. | 
| +// Informat protocol implemented by windows that need to be informed explicitly | 
| +// about underlay surfaces. | 
| +@protocol UnderlayableSurface | 
| 
pink (ping after 24hrs)
2010/08/24 17:18:55
If it's a @protocol, then it's formal. s/Informal/
 
Nico
2010/08/24 17:27:55
Not really, since nothing implements this protocol
 | 
| +- (void)underlaySurfaceAdded; | 
| +- (void)underlaySurfaceRemoved; | 
| +@end | 
| + | 
| @interface AcceleratedPluginView : NSView { | 
| scoped_nsobject<NSOpenGLPixelFormat> glPixelFormat_; | 
| CGLPixelFormatObj cglPixelFormat_; // weak, backed by |glPixelFormat_|. | 
| @@ -148,10 +155,15 @@ void DisablePasswordInput() { | 
| // True if the backing IO surface was updated since we last painted. | 
| BOOL surfaceWasSwapped_; | 
| + | 
| + // True if the surface might contain transparent pixels that need to be | 
| + // blended. | 
| + BOOL canDrawTransparent_; | 
| } | 
| - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r | 
| - pluginHandle:(gfx::PluginWindowHandle)pluginHandle; | 
| + pluginHandle:(gfx::PluginWindowHandle)pluginHandle | 
| + canDrawTransparent:(BOOL)canDrawTransparent; | 
| - (void)drawView; | 
| // This _must_ be atomic, since it's accessed from several threads. | 
| @@ -187,11 +199,30 @@ static CVReturn DrawOneAcceleratedPluginCallback( | 
| return result; | 
| } | 
| +- (BOOL)drawAsUnderlaySurface { | 
| + // Transparent plugins really need to be handled by the GPU process. Until | 
| + // then, we have the coice of two evils: | 
| 
pink (ping after 24hrs)
2010/08/24 17:18:55
choice
 
Nico
2010/08/24 17:27:55
will fix when i touch this file again (probably so
 | 
| + // 1.) They are drawn as underlay surface, blending with whatever is behind | 
| + // the browser window (instead of blending with the webpage as intended) | 
| + // 2.) They are blended with the web page but drawn on top of sibling windows | 
| + // such as the find bar and the fullscreen window overlay. | 
| + // Option 2 seems less bad, so don't show transparent plugins as underlays. | 
| + // | 
| + // Note that this never happens in practice at the moment, because | 
| + // |canDrawTransparent| will only be true for flash with wmode=transparent and | 
| + // sliverlight with a transparent background, and these don't use | 
| + // CoreAnimation when they're transparent. | 
| + return !canDrawTransparent_ && !CommandLine::ForCurrentProcess()->HasSwitch( | 
| + switches::kDisableHolePunching); | 
| +} | 
| + | 
| - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r | 
| - pluginHandle:(gfx::PluginWindowHandle)pluginHandle { | 
| + pluginHandle:(gfx::PluginWindowHandle)pluginHandle | 
| + canDrawTransparent:(BOOL)canDrawTransparent { | 
| if ((self = [super initWithFrame:NSZeroRect])) { | 
| renderWidgetHostView_ = r; | 
| pluginHandle_ = pluginHandle; | 
| + canDrawTransparent_ = canDrawTransparent; | 
| [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin]; | 
| @@ -203,6 +234,13 @@ static CVReturn DrawOneAcceleratedPluginCallback( | 
| glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_ | 
| shareContext:nil]); | 
| + if ([self drawAsUnderlaySurface]) { | 
| + // We "punch a hole" in the window, and have the WindowServer render the | 
| + // OpenGL surface underneath so we can draw over it. | 
| + GLint belowWindow = -1; | 
| + [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder]; | 
| + } | 
| + | 
| cglContext_ = (CGLContextObj)[glContext_ CGLContextObj]; | 
| cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj]; | 
| @@ -210,7 +248,6 @@ static CVReturn DrawOneAcceleratedPluginCallback( | 
| GLint swapInterval = 1; | 
| [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; | 
| - | 
| // Set up a display link to do OpenGL rendering on a background thread. | 
| CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_); | 
| CVDisplayLinkSetOutputCallback(displayLink_, | 
| @@ -234,6 +271,16 @@ static CVReturn DrawOneAcceleratedPluginCallback( | 
| } | 
| - (void)drawRect:(NSRect)rect { | 
| + if ([self drawAsUnderlaySurface]) { | 
| + const NSRect* dirtyRects; | 
| + int dirtyRectCount; | 
| + | 
| + [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; | 
| + // Punch a hole so that the OpenGL view shows through. | 
| + [[NSColor clearColor] set]; | 
| + NSRectFillList(dirtyRects, dirtyRectCount); | 
| + } | 
| + | 
| [self drawView]; | 
| } | 
| @@ -287,6 +334,22 @@ static CVReturn DrawOneAcceleratedPluginCallback( | 
| [[NSNotificationCenter defaultCenter] removeObserver:self]; | 
| [super dealloc]; | 
| } | 
| + | 
| +- (void)viewWillMoveToWindow:(NSWindow*)newWindow { | 
| + if (![self drawAsUnderlaySurface]) { | 
| + return; | 
| + } | 
| + | 
| + if ([self window] && | 
| 
pink (ping after 24hrs)
2010/08/24 17:18:55
do you need the extra window null checks? [nil res
 
Nico
2010/08/24 17:27:55
i don't need them, but i thought it's clearer.
si
 | 
| + [[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { | 
| + [static_cast<id>([self window]) underlaySurfaceRemoved]; | 
| + } | 
| + | 
| + if (newWindow && | 
| + [newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) { | 
| + [static_cast<id>(newWindow) underlaySurfaceAdded]; | 
| + } | 
| +} | 
| @end | 
| // RenderWidgetHostView -------------------------------------------------------- | 
| @@ -763,16 +826,16 @@ void RenderWidgetHostViewMac::KillSelf() { | 
| } | 
| } | 
| -gfx::PluginWindowHandle | 
| -RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque, | 
| - bool root) { | 
| +gfx::PluginWindowHandle RenderWidgetHostViewMac::AllocateFakePluginWindowHandle( | 
| + bool opaque, bool can_draw_transparent, bool root) { | 
| // Create an NSView to host the plugin's/compositor's pixels. | 
| gfx::PluginWindowHandle handle = | 
| plugin_container_manager_.AllocateFakePluginWindowHandle(opaque, root); | 
| - scoped_nsobject<NSView> plugin_view( | 
| - [[AcceleratedPluginView alloc] initWithRenderWidgetHostViewMac:this | 
| - pluginHandle:handle]); | 
| + scoped_nsobject<NSView> plugin_view([[AcceleratedPluginView alloc] | 
| + initWithRenderWidgetHostViewMac:this | 
| + pluginHandle:handle | 
| + canDrawTransparent:can_draw_transparent]); | 
| [plugin_view setHidden:YES]; | 
| [cocoa_view_ addSubview:plugin_view]; |