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 |