Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/renderer_host/accelerated_plugin_view_mac.h" | 5 #import "chrome/browser/renderer_host/accelerated_plugin_view_mac.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
| 9 #import "base/mac/scoped_nsautorelease_pool.h" | |
| 10 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 9 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
| 11 #include "chrome/common/chrome_switches.h" | 10 #include "chrome/common/chrome_switches.h" |
| 11 #include "content/browser/browser_thread.h" | |
| 12 #include "ui/gfx/gl/gl_switches.h" | 12 #include "ui/gfx/gl/gl_switches.h" |
| 13 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | 13 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" |
| 14 | 14 |
| 15 @implementation AcceleratedPluginView | 15 @implementation AcceleratedPluginView |
| 16 @synthesize cachedSize = cachedSize_; | |
| 17 | |
| 18 - (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime { | |
| 19 // There is no autorelease pool when this method is called because it will be | |
| 20 // called from a background thread. | |
| 21 base::mac::ScopedNSAutoreleasePool pool; | |
| 22 | |
| 23 bool sendAck = (rendererId_ != 0 || routeId_ != 0); | |
| 24 uint64 currentSwapBuffersCount = swapBuffersCount_; | |
| 25 if (currentSwapBuffersCount == acknowledgedSwapBuffersCount_) { | |
| 26 return kCVReturnSuccess; | |
| 27 } | |
| 28 | |
| 29 [self drawView]; | |
| 30 | |
| 31 acknowledgedSwapBuffersCount_ = currentSwapBuffersCount; | |
| 32 if (sendAck && renderWidgetHostView_) { | |
| 33 renderWidgetHostView_->AcknowledgeSwapBuffers( | |
| 34 rendererId_, | |
| 35 routeId_, | |
| 36 gpuHostId_, | |
| 37 acknowledgedSwapBuffersCount_); | |
| 38 } | |
| 39 | |
| 40 return kCVReturnSuccess; | |
| 41 } | |
| 42 | |
| 43 // This is the renderer output callback function | |
| 44 static CVReturn DrawOneAcceleratedPluginCallback( | |
| 45 CVDisplayLinkRef displayLink, | |
| 46 const CVTimeStamp* now, | |
| 47 const CVTimeStamp* outputTime, | |
| 48 CVOptionFlags flagsIn, | |
| 49 CVOptionFlags* flagsOut, | |
| 50 void* displayLinkContext) { | |
| 51 CVReturn result = | |
| 52 [(AcceleratedPluginView*)displayLinkContext getFrameForTime:outputTime]; | |
| 53 return result; | |
| 54 } | |
| 55 | 16 |
| 56 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r | 17 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r |
| 57 pluginHandle:(gfx::PluginWindowHandle)pluginHandle { | 18 pluginHandle:(gfx::PluginWindowHandle)pluginHandle { |
| 19 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 58 if ((self = [super initWithFrame:NSZeroRect])) { | 20 if ((self = [super initWithFrame:NSZeroRect])) { |
| 21 TRACE_EVENT0("browser", | |
| 22 "AcceleratedPluginView::initWithRenderWidgetHostViewMac"); | |
| 59 renderWidgetHostView_ = r; | 23 renderWidgetHostView_ = r; |
| 60 pluginHandle_ = pluginHandle; | 24 pluginHandle_ = pluginHandle; |
| 61 cachedSize_ = NSZeroSize; | |
| 62 swapBuffersCount_ = 0; | |
| 63 acknowledgedSwapBuffersCount_ = 0; | |
| 64 rendererId_ = 0; | |
| 65 routeId_ = 0; | |
| 66 gpuHostId_ = 0; | |
| 67 | 25 |
| 68 [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin]; | 26 [self setAutoresizingMask:NSViewMaxXMargin|NSViewMinYMargin]; |
| 69 | 27 |
| 70 NSOpenGLPixelFormatAttribute attributes[] = | 28 NSOpenGLPixelFormatAttribute attributes[] = |
| 71 { NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, 0}; | 29 { NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, 0}; |
| 72 | 30 |
| 73 glPixelFormat_.reset([[NSOpenGLPixelFormat alloc] | 31 glPixelFormat_.reset([[NSOpenGLPixelFormat alloc] |
| 74 initWithAttributes:attributes]); | 32 initWithAttributes:attributes]); |
| 75 glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_ | 33 glContext_.reset([[NSOpenGLContext alloc] initWithFormat:glPixelFormat_ |
| 76 shareContext:nil]); | 34 shareContext:nil]); |
| 77 | 35 |
| 78 // We "punch a hole" in the window, and have the WindowServer render the | 36 // We "punch a hole" in the window, and have the WindowServer render the |
| 79 // OpenGL surface underneath so we can draw over it. | 37 // OpenGL surface underneath so we can draw over it. |
| 80 GLint belowWindow = -1; | 38 GLint belowWindow = -1; |
| 81 [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder]; | 39 [glContext_ setValues:&belowWindow forParameter:NSOpenGLCPSurfaceOrder]; |
| 82 | 40 |
| 83 cglContext_ = (CGLContextObj)[glContext_ CGLContextObj]; | 41 cglContext_ = (CGLContextObj)[glContext_ CGLContextObj]; |
| 84 cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj]; | 42 cglPixelFormat_ = (CGLPixelFormatObj)[glPixelFormat_ CGLPixelFormatObj]; |
| 85 | 43 |
| 86 // Draw at beam vsync. | 44 // Draw at beam vsync. |
| 87 GLint swapInterval; | 45 GLint swapInterval; |
| 88 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) | 46 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) |
| 89 swapInterval = 0; | 47 swapInterval = 0; |
| 90 else | 48 else |
| 91 swapInterval = 1; | 49 swapInterval = 1; |
| 92 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; | 50 [glContext_ setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; |
| 93 | |
| 94 // Set up a display link to do OpenGL rendering on a background thread. | |
| 95 CVDisplayLinkCreateWithActiveCGDisplays(&displayLink_); | |
| 96 } | 51 } |
| 97 return self; | 52 return self; |
| 98 } | 53 } |
| 99 | 54 |
| 100 - (void)dealloc { | 55 - (void)dealloc { |
| 101 CVDisplayLinkRelease(displayLink_); | |
| 102 if (renderWidgetHostView_) | 56 if (renderWidgetHostView_) |
| 103 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); | 57 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); |
| 104 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 58 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 105 [super dealloc]; | 59 [super dealloc]; |
| 106 } | 60 } |
| 107 | 61 |
| 108 - (void)drawView { | 62 - (void)drawView { |
| 109 TRACE_EVENT1("browser", "AcceleratedPluginViewMac::drawView", | 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 110 "frameNum", swapBuffersCount_); | 64 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::drawView"); |
| 111 // Called on a background thread. Synchronized via the CGL context lock. | 65 // Called on the UI thread. |
| 112 CGLLockContext(cglContext_); | |
| 113 | |
| 114 if (renderWidgetHostView_) { | 66 if (renderWidgetHostView_) { |
| 115 // TODO(thakis): Pixel or view coordinates for size? | 67 // TODO(thakis): Pixel or view coordinates for size? |
| 68 NSRect frame = [self frame]; | |
|
Nico
2011/06/08 16:52:46
no need for a variable
jbates
2011/06/08 17:54:42
Done.
| |
| 116 renderWidgetHostView_->DrawAcceleratedSurfaceInstance( | 69 renderWidgetHostView_->DrawAcceleratedSurfaceInstance( |
| 117 cglContext_, pluginHandle_, [self cachedSize]); | 70 cglContext_, pluginHandle_, frame.size); |
| 118 } | 71 } |
| 119 | 72 |
| 120 CGLFlushDrawable(cglContext_); | 73 CGLFlushDrawable(cglContext_); |
| 121 CGLSetCurrentContext(0); | 74 CGLSetCurrentContext(0); |
| 122 CGLUnlockContext(cglContext_); | |
| 123 } | 75 } |
| 124 | 76 |
| 125 - (void)setCutoutRects:(NSArray*)cutout_rects { | 77 - (void)setCutoutRects:(NSArray*)cutout_rects { |
| 126 cutoutRects_.reset([cutout_rects copy]); | 78 cutoutRects_.reset([cutout_rects copy]); |
| 127 } | 79 } |
| 128 | 80 |
| 129 - (void)updateSwapBuffersCount:(uint64)count | |
| 130 fromRenderer:(int)rendererId | |
| 131 routeId:(int32)routeId | |
| 132 gpuHostId:(int)gpuHostId { | |
| 133 if (rendererId == 0 && routeId == 0) { | |
| 134 // This notification is coming from a plugin process, for which we | |
| 135 // don't have flow control implemented right now. Fake up a swap | |
| 136 // buffers count so that we can at least skip useless renders. | |
| 137 ++swapBuffersCount_; | |
| 138 } else { | |
| 139 rendererId_ = rendererId; | |
| 140 routeId_ = routeId; | |
| 141 gpuHostId_ = gpuHostId; | |
| 142 swapBuffersCount_ = count; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 - (void)onRenderWidgetHostViewGone { | 81 - (void)onRenderWidgetHostViewGone { |
| 82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 147 if (!renderWidgetHostView_) | 83 if (!renderWidgetHostView_) |
| 148 return; | 84 return; |
| 149 | 85 |
| 150 CGLLockContext(cglContext_); | |
| 151 // Deallocate the plugin handle while we still can. | 86 // Deallocate the plugin handle while we still can. |
| 152 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); | 87 renderWidgetHostView_->DeallocFakePluginWindowHandle(pluginHandle_); |
| 153 renderWidgetHostView_ = NULL; | 88 renderWidgetHostView_ = NULL; |
| 154 CGLUnlockContext(cglContext_); | |
| 155 } | 89 } |
| 156 | 90 |
| 157 - (void)drawRect:(NSRect)rect { | 91 - (void)drawRect:(NSRect)rect { |
| 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 158 const NSRect* dirtyRects; | 93 const NSRect* dirtyRects; |
| 159 int dirtyRectCount; | 94 int dirtyRectCount; |
| 160 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; | 95 [self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; |
| 161 | 96 |
| 162 { | 97 { |
| 163 gfx::ScopedNSGraphicsContextSaveGState scopedGState; | 98 gfx::ScopedNSGraphicsContextSaveGState scopedGState; |
| 164 | 99 |
| 165 // Mask out any cutout rects--somewhat counterintuitively cutout rects are | 100 // Mask out any cutout rects--somewhat counterintuitively cutout rects are |
| 166 // places where clearColor is *not* drawn. The trick is that drawing nothing | 101 // places where clearColor is *not* drawn. The trick is that drawing nothing |
| 167 // lets the parent view (i.e., the web page) show through, whereas drawing | 102 // lets the parent view (i.e., the web page) show through, whereas drawing |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 196 - (void)rightMouseDown:(NSEvent*)event { | 131 - (void)rightMouseDown:(NSEvent*)event { |
| 197 // The NSResponder documentation: "Note: The NSView implementation of this | 132 // The NSResponder documentation: "Note: The NSView implementation of this |
| 198 // method does not pass the message up the responder chain, it handles it | 133 // method does not pass the message up the responder chain, it handles it |
| 199 // directly." | 134 // directly." |
| 200 // That's bad, we want the next responder (RWHVMac) to handle this event to | 135 // That's bad, we want the next responder (RWHVMac) to handle this event to |
| 201 // dispatch it to the renderer. | 136 // dispatch it to the renderer. |
| 202 [[self nextResponder] rightMouseDown:event]; | 137 [[self nextResponder] rightMouseDown:event]; |
| 203 } | 138 } |
| 204 | 139 |
| 205 - (void)globalFrameDidChange:(NSNotification*)notification { | 140 - (void)globalFrameDidChange:(NSNotification*)notification { |
| 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 206 globalFrameDidChangeCGLLockCount_++; | 142 globalFrameDidChangeCGLLockCount_++; |
| 207 CGLLockContext(cglContext_); | |
| 208 // This call to -update can call -globalFrameDidChange: again, see | 143 // This call to -update can call -globalFrameDidChange: again, see |
| 209 // http://crbug.com/55754 comments 22 and 24. | 144 // http://crbug.com/55754 comments 22 and 24. |
| 210 [glContext_ update]; | 145 [glContext_ update]; |
| 211 | 146 |
| 212 // You would think that -update updates the viewport. You would be wrong. | 147 // You would think that -update updates the viewport. You would be wrong. |
| 213 CGLSetCurrentContext(cglContext_); | 148 CGLSetCurrentContext(cglContext_); |
| 214 NSSize size = [self frame].size; | 149 NSSize size = [self frame].size; |
| 215 glViewport(0, 0, size.width, size.height); | 150 glViewport(0, 0, size.width, size.height); |
| 216 | 151 |
| 217 CGLSetCurrentContext(0); | 152 CGLSetCurrentContext(0); |
| 218 CGLUnlockContext(cglContext_); | |
| 219 globalFrameDidChangeCGLLockCount_--; | 153 globalFrameDidChangeCGLLockCount_--; |
| 220 | |
| 221 if (globalFrameDidChangeCGLLockCount_ == 0) { | |
| 222 // Make sure the view is synchronized with the correct display. | |
| 223 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext( | |
| 224 displayLink_, cglContext_, cglPixelFormat_); | |
| 225 } | |
| 226 } | 154 } |
| 227 | 155 |
| 228 - (void)renewGState { | 156 - (void)renewGState { |
| 229 // Synchronize with window server to avoid flashes or corrupt drawing. | 157 // Synchronize with window server to avoid flashes or corrupt drawing. |
| 230 [[self window] disableScreenUpdatesUntilFlush]; | 158 [[self window] disableScreenUpdatesUntilFlush]; |
| 231 [self globalFrameDidChange:nil]; | 159 [self globalFrameDidChange:nil]; |
| 232 [super renewGState]; | 160 [super renewGState]; |
| 233 } | 161 } |
| 234 | 162 |
| 235 - (void)lockFocus { | 163 - (void)lockFocus { |
| 236 [super lockFocus]; | 164 [super lockFocus]; |
| 237 | 165 |
| 238 // If we're using OpenGL, make sure it is connected and that the display link | 166 // If we're using OpenGL, make sure it is connected. |
| 239 // is running. | |
| 240 if ([glContext_ view] != self) { | 167 if ([glContext_ view] != self) { |
| 241 [glContext_ setView:self]; | 168 [glContext_ setView:self]; |
| 242 | 169 |
| 243 [[NSNotificationCenter defaultCenter] | 170 [[NSNotificationCenter defaultCenter] |
| 244 addObserver:self | 171 addObserver:self |
| 245 selector:@selector(globalFrameDidChange:) | 172 selector:@selector(globalFrameDidChange:) |
| 246 name:NSViewGlobalFrameDidChangeNotification | 173 name:NSViewGlobalFrameDidChangeNotification |
| 247 object:self]; | 174 object:self]; |
| 248 CVDisplayLinkSetOutputCallback( | |
| 249 displayLink_, &DrawOneAcceleratedPluginCallback, self); | |
| 250 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext( | |
| 251 displayLink_, cglContext_, cglPixelFormat_); | |
| 252 CVDisplayLinkStart(displayLink_); | |
| 253 } | 175 } |
| 254 [glContext_ makeCurrentContext]; | 176 [glContext_ makeCurrentContext]; |
| 255 } | 177 } |
| 256 | 178 |
| 257 - (void)viewWillMoveToWindow:(NSWindow*)newWindow { | 179 - (void)viewWillMoveToWindow:(NSWindow*)newWindow { |
| 258 // Stop the display link thread while the view is not visible. | 180 TRACE_EVENT0("renderer", "viewWillMoveToWindow"); |
| 259 if (newWindow) { | |
| 260 if (displayLink_ && !CVDisplayLinkIsRunning(displayLink_)) | |
| 261 CVDisplayLinkStart(displayLink_); | |
| 262 } else { | |
| 263 if (displayLink_ && CVDisplayLinkIsRunning(displayLink_)) | |
| 264 CVDisplayLinkStop(displayLink_); | |
| 265 } | |
| 266 | |
| 267 // Inform the window hosting this accelerated view that it needs to be | 181 // Inform the window hosting this accelerated view that it needs to be |
| 268 // transparent. | 182 // transparent. |
| 269 if (![self isHiddenOrHasHiddenAncestor]) { | 183 if (![self isHiddenOrHasHiddenAncestor]) { |
| 270 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) | 184 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) |
| 271 [static_cast<id>([self window]) underlaySurfaceRemoved]; | 185 [static_cast<id>([self window]) underlaySurfaceRemoved]; |
| 272 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) | 186 if ([newWindow respondsToSelector:@selector(underlaySurfaceAdded)]) |
| 273 [static_cast<id>(newWindow) underlaySurfaceAdded]; | 187 [static_cast<id>(newWindow) underlaySurfaceAdded]; |
| 274 } | 188 } |
| 275 } | 189 } |
| 276 | 190 |
| 277 - (void)viewDidHide { | 191 - (void)viewDidHide { |
| 278 [super viewDidHide]; | 192 [super viewDidHide]; |
| 279 | 193 |
| 280 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { | 194 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { |
| 281 [static_cast<id>([self window]) underlaySurfaceRemoved]; | 195 [static_cast<id>([self window]) underlaySurfaceRemoved]; |
| 282 } | 196 } |
| 283 } | 197 } |
| 284 | 198 |
| 285 - (void)viewDidUnhide { | 199 - (void)viewDidUnhide { |
| 286 [super viewDidUnhide]; | 200 [super viewDidUnhide]; |
| 287 | 201 |
| 288 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { | 202 if ([[self window] respondsToSelector:@selector(underlaySurfaceRemoved)]) { |
| 289 [static_cast<id>([self window]) underlaySurfaceAdded]; | 203 [static_cast<id>([self window]) underlaySurfaceAdded]; |
| 290 } | 204 } |
| 291 } | 205 } |
| 292 | 206 |
| 293 - (void)setFrame:(NSRect)frameRect { | 207 - (void)setFrame:(NSRect)frameRect { |
| 294 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame"); | 208 TRACE_EVENT0("browser", "AcceleratedPluginViewMac::setFrame"); |
| 295 [self setCachedSize:frameRect.size]; | |
| 296 [super setFrame:frameRect]; | 209 [super setFrame:frameRect]; |
| 297 } | 210 } |
|
Nico
2011/06/08 16:52:46
If you don't need the trace output, remove this me
jbates
2011/06/08 17:54:42
Done.
| |
| 298 | 211 |
| 299 - (void)setFrameSize:(NSSize)newSize { | 212 - (void)setFrameSize:(NSSize)newSize { |
| 300 [self setCachedSize:newSize]; | |
| 301 [super setFrameSize:newSize]; | 213 [super setFrameSize:newSize]; |
| 302 } | 214 } |
|
Nico
2011/06/08 16:52:46
Remove this method?
jbates
2011/06/08 17:54:42
Done.
| |
| 303 | 215 |
| 304 - (BOOL)acceptsFirstResponder { | 216 - (BOOL)acceptsFirstResponder { |
| 305 // Accept first responder if the first responder isn't the RWHVMac, and if the | 217 // Accept first responder if the first responder isn't the RWHVMac, and if the |
| 306 // RWHVMac accepts first responder. If the RWHVMac does not accept first | 218 // RWHVMac accepts first responder. If the RWHVMac does not accept first |
| 307 // responder, do not accept on its behalf. | 219 // responder, do not accept on its behalf. |
| 308 return ([[self window] firstResponder] != [self superview] && | 220 return ([[self window] firstResponder] != [self superview] && |
| 309 [[self superview] acceptsFirstResponder]); | 221 [[self superview] acceptsFirstResponder]); |
| 310 } | 222 } |
| 311 | 223 |
| 312 - (BOOL)becomeFirstResponder { | 224 - (BOOL)becomeFirstResponder { |
| 313 // Delegate first responder to the RWHVMac. | 225 // Delegate first responder to the RWHVMac. |
| 314 [[self window] makeFirstResponder:[self superview]]; | 226 [[self window] makeFirstResponder:[self superview]]; |
| 315 return YES; | 227 return YES; |
| 316 } | 228 } |
| 317 | 229 |
| 318 - (void)viewDidMoveToSuperview { | 230 - (void)viewDidMoveToSuperview { |
| 319 if (![self superview]) | 231 if (![self superview]) |
| 320 [self onRenderWidgetHostViewGone]; | 232 [self onRenderWidgetHostViewGone]; |
| 321 } | 233 } |
| 322 @end | 234 @end |
| 323 | 235 |
| OLD | NEW |