diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-22 22:39:53 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-22 22:39:53 +0000 |
commit | cf6fc7ca949c0e05ac36cf72ecd223e59ae1ce90 (patch) | |
tree | d37d1567b27de4084a40396bf1daf8c8576ab367 /chrome | |
parent | 7e9f4a8e17e918412cfba8337e55873abed112cb (diff) | |
download | chromium_src-cf6fc7ca949c0e05ac36cf72ecd223e59ae1ce90.zip chromium_src-cf6fc7ca949c0e05ac36cf72ecd223e59ae1ce90.tar.gz chromium_src-cf6fc7ca949c0e05ac36cf72ecd223e59ae1ce90.tar.bz2 |
Fix handling of Mac accelerated plugin layers across tab switch.
A few related changes to make tab switching work with accelerated plugins:
- Re-attach our layer to the view layer whenever it changes; using setWantsLayer: creates a layer that AppKit manages at will, so we can't rely on it.
- Override setFrame: on our layer to ignore bogus values sent by the view's layer.
- Notify the accelerated surface when our parent (and thus drawing context) changes, so it can associate its texture with the new context.
BUG=37701
TEST=Load the pepper test plugin (or a CA plugin in a build with CA enabled) and switch tabs away and back. The plugin should still be visible.
Review URL: http://codereview.chromium.org/1166002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42273 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
6 files changed, 132 insertions, 61 deletions
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc index 8d3827c..f77ad3d 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc +++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc @@ -15,7 +15,8 @@ AcceleratedSurfaceContainerMac::AcceleratedSurfaceContainerMac() surface_(NULL), width_(0), height_(0), - texture_(0) { + texture_(0), + texture_needs_upload_(true) { } AcceleratedSurfaceContainerMac::~AcceleratedSurfaceContainerMac() { @@ -77,22 +78,7 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) { glBindTexture(target, texture_); glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // When using an IOSurface, the texture does not need to be repeatedly - // uploaded, so bind the IOSurface once during texture gen in this case. - if (io_surface_support) { - DCHECK(surface_); - // Don't think we need to identify a plane. - GLuint plane = 0; - io_surface_support->CGLTexImageIOSurface2D(context, - target, - GL_RGBA, - width_, - height_, - GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, - surface_, - plane); - } else { + if (!io_surface_support) { // Reserve space on the card for the actual texture upload, done with the // glTexSubImage2D() call, below. glTexImage2D(target, @@ -107,6 +93,24 @@ void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) { } } + // When using an IOSurface, the texture does not need to be repeatedly + // uploaded, just when we've been told we have to. + if (io_surface_support && texture_needs_upload_) { + DCHECK(surface_); + glBindTexture(target, texture_); + // Don't think we need to identify a plane. + GLuint plane = 0; + io_surface_support->CGLTexImageIOSurface2D(context, + target, + GL_RGBA, + width_, + height_, + GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, + surface_, + plane); + texture_needs_upload_ = false; + } // If using TransportDIBs, the texture needs to be uploaded every frame. if (transport_dib_.get() != NULL) { void* pixel_memory = transport_dib_->memory(); diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_mac.h index 5f2d12e..1778ea9 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_mac.h +++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.h @@ -67,6 +67,10 @@ class AcceleratedSurfaceContainerMac { // coordinate system will work out. void Draw(CGLContextObj context); + // Causes the next Draw call to trigger a texture upload. Should be called any + // time the drawing context has changed. + void ForceTextureReload() { texture_needs_upload_ = true; } + // Enqueue our texture for later deletion. Call this before deleting // this object. void EnqueueTextureForDeletion( @@ -104,6 +108,9 @@ class AcceleratedSurfaceContainerMac { // with it. GLuint texture_; + // True if we need to upload the texture again during the next draw. + bool texture_needs_upload_; + DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerMac); }; diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc index f7c39e5..2afbb0f 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc +++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc @@ -81,6 +81,15 @@ void AcceleratedSurfaceContainerManagerMac::Draw(CGLContextObj context) { glFlush(); } +void AcceleratedSurfaceContainerManagerMac::ForceTextureReload() { + for (PluginWindowToContainerMap::const_iterator i = + plugin_window_to_container_map_.begin(); + i != plugin_window_to_container_map_.end(); ++i) { + AcceleratedSurfaceContainerMac* container = i->second; + container->ForceTextureReload(); + } +} + void AcceleratedSurfaceContainerManagerMac::EnqueueTextureForDeletion( GLuint texture) { if (texture) { diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h index 2456186..bcfd0aa 100644 --- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h +++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h @@ -53,6 +53,10 @@ class AcceleratedSurfaceContainerManagerMac { // context, which must already be current. void Draw(CGLContextObj context); + // Causes the next Draw call on each container to trigger a texture upload. + // Should be called any time the drawing context has changed. + void ForceTextureReload(); + // Called by the container to enqueue its OpenGL texture objects for // deletion. void EnqueueTextureForDeletion(GLuint texture); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index bc9fbe9..fdbb497 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -52,11 +52,20 @@ class RWHVMEditCommandHelper; // insertText: and insertNewline: to synthesize the corresponding Char event. scoped_nsobject<NSEvent> currentKeyEvent_; NSWindow* lastWindow_; // weak + + // The Core Animation layer, if any, hosting the accelerated plugins' output. + scoped_nsobject<CALayer> accelerated_plugin_layer_; } - (void)setCanBeKeyView:(BOOL)can; - (void)setCloseOnDeactivate:(BOOL)b; - (void)setToolTipAtMousePoint:(NSString *)string; +// Makes sure that the initial layer setup for accelerated plugin drawing has +// been done. Can be called multiple times. +- (void)ensureAcceleratedPluginLayer; +// Triggers a refresh of the accelerated plugin layer; should be called whenever +// the shared surface for one of the plugins is updated. +- (void)drawAcceleratedPluginLayer; @end /////////////////////////////////////////////////////////////////////////////// @@ -139,6 +148,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void AcceleratedSurfaceBuffersSwapped(gfx::PluginWindowHandle window); // Draws the current GPU-accelerated plug-in instances into the given context. virtual void DrawAcceleratedSurfaceInstances(CGLContextObj context); + // Informs the plug-in instances that their drawing context has changed. + virtual void AcceleratedSurfaceContextChanged(); + virtual void SetVisuallyDeemphasized(bool deemphasized); void KillSelf(); @@ -207,9 +219,6 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { // methods needs it. NSRect im_caret_rect_; - // The Core Animation layer, if any, hosting the GPU plugins' output. - scoped_nsobject<CALayer> gpu_plugin_layer_; - private: // Updates the display cursor to the current cursor if the cursor is over this // render view. 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 c671881..300dc3a 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -49,6 +49,7 @@ static inline int ToWebKitModifiers(NSUInteger flags) { - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; - (void)cancelChildPopups; - (void)callSetNeedsDisplayInRect:(NSValue*)rect; +- (void)attachPluginLayer; @end namespace { @@ -58,19 +59,19 @@ const size_t kMaxTooltipLength = 1024; } -// GPUPluginLayer -------------------------------------------------------------- +// AcceleratedPluginLayer ------------------------------------------------------ -// This subclass of CAOpenGLLayer hosts the output of the GPU-accelerated -// plugins on the page. +// This subclass of CAOpenGLLayer hosts the output of accelerated plugins on +// the page. -@interface GPUPluginLayer : CAOpenGLLayer { +@interface AcceleratedPluginLayer : CAOpenGLLayer { RenderWidgetHostViewMac* renderWidgetHostView_; // weak } - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; @end -@implementation GPUPluginLayer +@implementation AcceleratedPluginLayer - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { self = [super init]; if (self != nil) { @@ -79,16 +80,27 @@ const size_t kMaxTooltipLength = 1024; return self; } --(void)drawInCGLContext:(CGLContextObj)glContext - pixelFormat:(CGLPixelFormatObj)pixelFormat - forLayerTime:(CFTimeInterval)timeInterval - displayTime:(const CVTimeStamp *)timeStamp { +- (void)drawInCGLContext:(CGLContextObj)glContext + pixelFormat:(CGLPixelFormatObj)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval + displayTime:(const CVTimeStamp *)timeStamp { renderWidgetHostView_->DrawAcceleratedSurfaceInstances(glContext); [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; } + +- (void)setFrame:(CGRect)rect { + // The frame we get when the superlayer resizes doesn't make sense, so ignore + // it and just match the superlayer's size. See the email thread referenced in + // ensureAcceleratedPluginLayer for an explanation of why the superlayer + // isn't trustworthy. + if ([self superlayer]) + [super setFrame:[[self superlayer] bounds]]; + else + [super setFrame:rect]; +} @end // RenderWidgetHostView -------------------------------------------------------- @@ -217,9 +229,8 @@ gfx::NativeView RenderWidgetHostViewMac::GetNativeView() { void RenderWidgetHostViewMac::MovePluginWindows( const std::vector<webkit_glue::WebPluginGeometry>& moves) { - // The only case we need to notice plugin window moves is the case - // of the GPU plugin. As soon as the GPU plugin becomes the GPU - // process all of this code will go away. + // Handle movement of accelerated plugins, which are the only "windowed" + // plugins that exist on the Mac. if (moves.size() > 0) { for (std::vector<webkit_glue::WebPluginGeometry>::const_iterator iter = moves.begin(); @@ -236,9 +247,6 @@ void RenderWidgetHostViewMac::MovePluginWindows( } } } - - // All plugin stuff is TBD. TODO(avi,awalker): fill in - // http://crbug.com/8192 } void RenderWidgetHostViewMac::Focus() { @@ -516,29 +524,8 @@ void RenderWidgetHostViewMac::KillSelf() { gfx::PluginWindowHandle RenderWidgetHostViewMac::AllocateFakePluginWindowHandle() { - // If we don't already have a GPUPluginLayer allocated for our view, - // set one up now. - if (gpu_plugin_layer_.get() == nil) { - RenderWidgetHostViewCocoa* our_view = native_view(); - // Try to get AppKit to allocate the layer - [our_view setWantsLayer:YES]; - CALayer* root_layer = [our_view layer]; - if (root_layer == nil) { - root_layer = [CALayer layer]; - [our_view setLayer:root_layer]; - } - - GPUPluginLayer* gpu_layer = - [[GPUPluginLayer alloc] initWithRenderWidgetHostViewMac:this]; - - // Make our layer resize to fit the superlayer - gpu_layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; - // Set up its initial size - [gpu_layer setFrame:NSRectToCGRect([our_view bounds])]; - - [root_layer addSublayer:gpu_layer]; - gpu_plugin_layer_.reset(gpu_layer); - } + // Make sure we have a layer for the plugin to draw into. + [cocoa_view_ ensureAcceleratedPluginLayer]; return plugin_container_manager_.AllocateFakePluginWindowHandle(); } @@ -572,7 +559,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB( void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( gfx::PluginWindowHandle window) { - [gpu_plugin_layer_.get() setNeedsDisplay]; + [cocoa_view_ drawAcceleratedPluginLayer]; } void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstances( @@ -590,6 +577,10 @@ void RenderWidgetHostViewMac::DrawAcceleratedSurfaceInstances( plugin_container_manager_.Draw(context); } +void RenderWidgetHostViewMac::AcceleratedSurfaceContextChanged() { + plugin_container_manager_.ForceTextureReload(); +} + void RenderWidgetHostViewMac::SetVisuallyDeemphasized(bool deemphasized) { // Mac uses tab-modal sheets, so this is a no-op. } @@ -1061,9 +1052,9 @@ bool RenderWidgetHostViewMac::ContainsNativeView( renderWidgetHostView_->whiteout_start_time_ = base::TimeTicks::Now(); } - // This helps keep the GPU plugins' output in better sync with the + // This helps keep accelerated plugins' output in better sync with the // window as it resizes. - [renderWidgetHostView_->gpu_plugin_layer_.get() setNeedsDisplay]; + [accelerated_plugin_layer_.get() setNeedsDisplay]; } - (BOOL)canBecomeKeyView { @@ -1678,4 +1669,51 @@ extern NSString *NSTextInputReplacementRangeAttributeName; } } +- (void)ensureAcceleratedPluginLayer { + if (accelerated_plugin_layer_.get()) + return; + + AcceleratedPluginLayer* plugin_layer = [[AcceleratedPluginLayer alloc] + initWithRenderWidgetHostViewMac:renderWidgetHostView_.get()]; + accelerated_plugin_layer_.reset(plugin_layer); + // Make our layer resize to fit the superlayer + plugin_layer.autoresizingMask = kCALayerWidthSizable | + kCALayerHeightSizable; + // Make the view layer-backed so that there will be a layer to hang the + // |layer| off of. This is not the "right" way to host a sublayer in a view, + // but the right way would require making the whole view's drawing system + // layer-based (using setLayer:). We don't want to do that (at least not + // yet) so instead we override setLayer: and re-bind our plugin layer each + // time the view's layer changes. For discussion see: + // http://lists.apple.com/archives/Cocoa-dev/2009/Feb/msg01132.html + [self setWantsLayer:YES]; + [self attachPluginLayer]; +} + +- (void)attachPluginLayer { + CALayer* plugin_layer = accelerated_plugin_layer_.get(); + if (!plugin_layer) + return; + + CALayer* root_layer = [self layer]; + DCHECK(root_layer != nil); + [plugin_layer setFrame:NSRectToCGRect([self bounds])]; + [root_layer addSublayer:plugin_layer]; + renderWidgetHostView_->AcceleratedSurfaceContextChanged(); +} + +- (void)setLayer:(CALayer *)newLayer { + CALayer* plugin_layer = accelerated_plugin_layer_.get(); + if (!newLayer && [plugin_layer superlayer]) + [plugin_layer removeFromSuperlayer]; + + [super setLayer:newLayer]; + if ([self layer]) + [self attachPluginLayer]; +} + +- (void)drawAcceleratedPluginLayer { + [accelerated_plugin_layer_.get() setNeedsDisplay]; +} + @end |