|
1 /* |
|
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
|
3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. |
|
4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
|
5 * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> |
|
6 * |
|
7 * Redistribution and use in source and binary forms, with or without |
|
8 * modification, are permitted provided that the following conditions |
|
9 * are met: |
|
10 * 1. Redistributions of source code must retain the above copyright |
|
11 * notice, this list of conditions and the following disclaimer. |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
|
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
|
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include "config.h" |
|
30 #include "PluginView.h" |
|
31 |
|
32 #include "Bridge.h" |
|
33 #include "Document.h" |
|
34 #include "DocumentLoader.h" |
|
35 #include "Element.h" |
|
36 #include "EventNames.h" |
|
37 #include "FocusController.h" |
|
38 #include "FrameLoader.h" |
|
39 #include "FrameLoadRequest.h" |
|
40 #include "FrameTree.h" |
|
41 #include "Frame.h" |
|
42 #include "FrameView.h" |
|
43 #include "GraphicsContext.h" |
|
44 #include "HostWindow.h" |
|
45 #include "HTMLNames.h" |
|
46 #include "HTMLPlugInElement.h" |
|
47 #include "Image.h" |
|
48 #include "JSDOMBinding.h" |
|
49 #include "KeyboardEvent.h" |
|
50 #include "MouseEvent.h" |
|
51 #include "NotImplemented.h" |
|
52 #include "Page.h" |
|
53 #include "PlatformMouseEvent.h" |
|
54 #include "PlatformKeyboardEvent.h" |
|
55 #include "PluginDebug.h" |
|
56 #include "PluginPackage.h" |
|
57 #include "PluginMainThreadScheduler.h" |
|
58 #include "RenderLayer.h" |
|
59 #include "ScriptController.h" |
|
60 #include "Settings.h" |
|
61 #include "npruntime_impl.h" |
|
62 #include "runtime_root.h" |
|
63 #include <runtime/JSLock.h> |
|
64 #include <runtime/JSValue.h> |
|
65 #include <wtf/RetainPtr.h> |
|
66 |
|
67 |
|
68 using JSC::ExecState; |
|
69 using JSC::Interpreter; |
|
70 using JSC::JSLock; |
|
71 using JSC::JSObject; |
|
72 using JSC::JSValue; |
|
73 using JSC::UString; |
|
74 |
|
75 #if PLATFORM(QT) |
|
76 #include <QWidget> |
|
77 #include <QKeyEvent> |
|
78 #include <QPainter> |
|
79 #include "QWebPageClient.h" |
|
80 QT_BEGIN_NAMESPACE |
|
81 extern Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget* w); |
|
82 QT_END_NAMESPACE |
|
83 #endif |
|
84 |
|
85 #if PLATFORM(WX) |
|
86 #include <wx/defs.h> |
|
87 #include <wx/wx.h> |
|
88 #endif |
|
89 |
|
90 using std::min; |
|
91 |
|
92 using namespace WTF; |
|
93 |
|
94 namespace WebCore { |
|
95 |
|
96 using namespace HTMLNames; |
|
97 |
|
98 #ifndef NP_NO_CARBON |
|
99 static int modifiersForEvent(UIEventWithKeyState *event); |
|
100 #endif |
|
101 |
|
102 static inline WindowRef nativeWindowFor(PlatformWidget widget) |
|
103 { |
|
104 #if PLATFORM(QT) |
|
105 if (widget) |
|
106 #if QT_MAC_USE_COCOA |
|
107 return static_cast<WindowRef>([qt_mac_window_for(widget) windowRef]); |
|
108 #else |
|
109 return static_cast<WindowRef>(qt_mac_window_for(widget)); |
|
110 #endif |
|
111 #elif PLATFORM(WX) |
|
112 if (widget) |
|
113 return (WindowRef)widget->MacGetTopLevelWindowRef(); |
|
114 #endif |
|
115 return 0; |
|
116 } |
|
117 |
|
118 static inline CGContextRef cgHandleFor(PlatformWidget widget) |
|
119 { |
|
120 #if PLATFORM(QT) |
|
121 if (widget) |
|
122 return (CGContextRef)widget->macCGHandle(); |
|
123 #endif |
|
124 #if PLATFORM(WX) |
|
125 if (widget) |
|
126 return (CGContextRef)widget->MacGetCGContextRef(); |
|
127 #endif |
|
128 return 0; |
|
129 } |
|
130 |
|
131 static inline IntPoint topLevelOffsetFor(PlatformWidget widget) |
|
132 { |
|
133 #if PLATFORM(QT) |
|
134 if (widget) { |
|
135 PlatformWidget topLevel = widget->window(); |
|
136 return widget->mapTo(topLevel, QPoint(0, 0)) + topLevel->geometry().topLeft() - topLevel->pos(); |
|
137 } |
|
138 #endif |
|
139 #if PLATFORM(WX) |
|
140 if (widget) { |
|
141 PlatformWidget toplevel = wxGetTopLevelParent(widget); |
|
142 return toplevel->ScreenToClient(widget->GetScreenPosition()); |
|
143 } |
|
144 #endif |
|
145 return IntPoint(); |
|
146 } |
|
147 |
|
148 // --------------- Lifetime management ----------------- |
|
149 |
|
150 bool PluginView::platformStart() |
|
151 { |
|
152 ASSERT(m_isStarted); |
|
153 ASSERT(m_status == PluginStatusLoadedSuccessfully); |
|
154 |
|
155 if (m_drawingModel == NPDrawingModel(-1)) { |
|
156 // We default to QuickDraw, even though we don't support it, |
|
157 // since that's what Safari does, and some plugins expect this |
|
158 // behavior and never set the drawing model explicitly. |
|
159 #ifndef NP_NO_QUICKDRAW |
|
160 m_drawingModel = NPDrawingModelQuickDraw; |
|
161 #else |
|
162 // QuickDraw not available, so we have to default to CoreGraphics |
|
163 m_drawingModel = NPDrawingModelCoreGraphics; |
|
164 #endif |
|
165 } |
|
166 |
|
167 if (m_eventModel == NPEventModel(-1)) { |
|
168 // If the plug-in did not specify an event model |
|
169 // we default to Carbon, when it is available. |
|
170 #ifndef NP_NO_CARBON |
|
171 m_eventModel = NPEventModelCarbon; |
|
172 #else |
|
173 m_eventModel = NPEventModelCocoa; |
|
174 #endif |
|
175 } |
|
176 |
|
177 // Gracefully handle unsupported drawing or event models. We can do this |
|
178 // now since the drawing and event model can only be set during NPP_New. |
|
179 #ifndef NP_NO_CARBON |
|
180 NPBool eventModelSupported; |
|
181 if (getValueStatic(NPNVariable(NPNVsupportsCarbonBool + m_eventModel), &eventModelSupported) != NPERR_NO_ERROR |
|
182 || !eventModelSupported) { |
|
183 #endif |
|
184 m_status = PluginStatusCanNotLoadPlugin; |
|
185 LOG(Plugins, "Plug-in '%s' uses unsupported event model %s", |
|
186 m_plugin->name().utf8().data(), prettyNameForEventModel(m_eventModel)); |
|
187 return false; |
|
188 #ifndef NP_NO_CARBON |
|
189 } |
|
190 #endif |
|
191 |
|
192 #ifndef NP_NO_QUICKDRAW |
|
193 NPBool drawingModelSupported; |
|
194 if (getValueStatic(NPNVariable(NPNVsupportsQuickDrawBool + m_drawingModel), &drawingModelSupported) != NPERR_NO_ERROR |
|
195 || !drawingModelSupported) { |
|
196 #endif |
|
197 m_status = PluginStatusCanNotLoadPlugin; |
|
198 LOG(Plugins, "Plug-in '%s' uses unsupported drawing model %s", |
|
199 m_plugin->name().utf8().data(), prettyNameForDrawingModel(m_drawingModel)); |
|
200 return false; |
|
201 #ifndef NP_NO_QUICKDRAW |
|
202 } |
|
203 #endif |
|
204 |
|
205 #if PLATFORM(QT) |
|
206 // Set the platformPluginWidget only in the case of QWebView so that the context menu appears in the right place. |
|
207 // In all other cases, we use off-screen rendering |
|
208 if (QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient()) { |
|
209 if (QWidget* widget = qobject_cast<QWidget*>(client->pluginParent())) |
|
210 setPlatformPluginWidget(widget); |
|
211 } |
|
212 #endif |
|
213 #if PLATFORM(WX) |
|
214 if (wxWindow* widget = m_parentFrame->view()->hostWindow()->platformPageClient()) |
|
215 setPlatformPluginWidget(widget); |
|
216 #endif |
|
217 |
|
218 // Create a fake window relative to which all events will be sent when using offscreen rendering |
|
219 if (!platformPluginWidget()) { |
|
220 #ifndef NP_NO_CARBON |
|
221 // Make the default size really big. It is unclear why this is required but with a smaller size, mouse move |
|
222 // events don't get processed. Resizing the fake window to flash's size doesn't help. |
|
223 ::Rect windowBounds = { 0, 0, 1000, 1000 }; |
|
224 CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes, &windowBounds, &m_fakeWindow); |
|
225 // Flash requires the window to be hilited to process mouse move events. |
|
226 HiliteWindow(m_fakeWindow, true); |
|
227 #endif |
|
228 } |
|
229 |
|
230 show(); |
|
231 |
|
232 // TODO: Implement null timer throttling depending on plugin activation |
|
233 m_nullEventTimer.set(new Timer<PluginView>(this, &PluginView::nullEventTimerFired)); |
|
234 m_nullEventTimer->startRepeating(0.02); |
|
235 |
|
236 m_lastMousePos.h = m_lastMousePos.v = 0; |
|
237 |
|
238 return true; |
|
239 } |
|
240 |
|
241 void PluginView::platformDestroy() |
|
242 { |
|
243 if (platformPluginWidget()) |
|
244 setPlatformPluginWidget(0); |
|
245 else { |
|
246 CGContextRelease(m_contextRef); |
|
247 #ifndef NP_NO_CARBON |
|
248 if (m_fakeWindow) |
|
249 DisposeWindow(m_fakeWindow); |
|
250 #endif |
|
251 } |
|
252 } |
|
253 |
|
254 // Used before the plugin view has been initialized properly, and as a |
|
255 // fallback for variables that do not require a view to resolve. |
|
256 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) |
|
257 { |
|
258 switch (variable) { |
|
259 case NPNVToolkit: |
|
260 *static_cast<uint32_t*>(value) = 0; |
|
261 *result = NPERR_NO_ERROR; |
|
262 return true; |
|
263 |
|
264 case NPNVjavascriptEnabledBool: |
|
265 *static_cast<NPBool*>(value) = true; |
|
266 *result = NPERR_NO_ERROR; |
|
267 return true; |
|
268 |
|
269 #ifndef NP_NO_CARBON |
|
270 case NPNVsupportsCarbonBool: |
|
271 *static_cast<NPBool*>(value) = true; |
|
272 *result = NPERR_NO_ERROR; |
|
273 return true; |
|
274 |
|
275 #endif |
|
276 case NPNVsupportsCocoaBool: |
|
277 *static_cast<NPBool*>(value) = false; |
|
278 *result = NPERR_NO_ERROR; |
|
279 return true; |
|
280 |
|
281 // CoreGraphics is the only drawing model we support |
|
282 case NPNVsupportsCoreGraphicsBool: |
|
283 *static_cast<NPBool*>(value) = true; |
|
284 *result = NPERR_NO_ERROR; |
|
285 return true; |
|
286 |
|
287 #ifndef NP_NO_QUICKDRAW |
|
288 // QuickDraw is deprecated in 10.5 and not supported on 64-bit |
|
289 case NPNVsupportsQuickDrawBool: |
|
290 #endif |
|
291 case NPNVsupportsOpenGLBool: |
|
292 case NPNVsupportsCoreAnimationBool: |
|
293 *static_cast<NPBool*>(value) = false; |
|
294 *result = NPERR_NO_ERROR; |
|
295 return true; |
|
296 |
|
297 default: |
|
298 return false; |
|
299 } |
|
300 } |
|
301 |
|
302 // Used only for variables that need a view to resolve |
|
303 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* error) |
|
304 { |
|
305 return false; |
|
306 } |
|
307 |
|
308 void PluginView::setParent(ScrollView* parent) |
|
309 { |
|
310 LOG(Plugins, "PluginView::setParent(%p)", parent); |
|
311 |
|
312 Widget::setParent(parent); |
|
313 |
|
314 if (parent) |
|
315 init(); |
|
316 } |
|
317 |
|
318 // -------------- Geometry and painting ---------------- |
|
319 |
|
320 void PluginView::show() |
|
321 { |
|
322 LOG(Plugins, "PluginView::show()"); |
|
323 |
|
324 setSelfVisible(true); |
|
325 |
|
326 Widget::show(); |
|
327 } |
|
328 |
|
329 void PluginView::hide() |
|
330 { |
|
331 LOG(Plugins, "PluginView::hide()"); |
|
332 |
|
333 setSelfVisible(false); |
|
334 |
|
335 Widget::hide(); |
|
336 } |
|
337 |
|
338 void PluginView::setFocus(bool focused) |
|
339 { |
|
340 LOG(Plugins, "PluginView::setFocus(%d)", focused); |
|
341 if (!focused) { |
|
342 Widget::setFocus(focused); |
|
343 return; |
|
344 } |
|
345 |
|
346 if (platformPluginWidget()) |
|
347 #if PLATFORM(QT) |
|
348 platformPluginWidget()->setFocus(Qt::OtherFocusReason); |
|
349 #else |
|
350 platformPluginWidget()->SetFocus(); |
|
351 #endif |
|
352 else |
|
353 Widget::setFocus(focused); |
|
354 |
|
355 // TODO: Also handle and pass on blur events (focus lost) |
|
356 |
|
357 #ifndef NP_NO_CARBON |
|
358 EventRecord record; |
|
359 record.what = getFocusEvent; |
|
360 record.message = 0; |
|
361 record.when = TickCount(); |
|
362 record.where = globalMousePosForPlugin(); |
|
363 record.modifiers = GetCurrentKeyModifiers(); |
|
364 |
|
365 if (!dispatchNPEvent(record)) |
|
366 LOG(Events, "PluginView::setFocus(%d): Focus event not accepted", focused); |
|
367 #endif |
|
368 } |
|
369 |
|
370 void PluginView::setParentVisible(bool visible) |
|
371 { |
|
372 if (isParentVisible() == visible) |
|
373 return; |
|
374 |
|
375 Widget::setParentVisible(visible); |
|
376 } |
|
377 |
|
378 void PluginView::setNPWindowRect(const IntRect&) |
|
379 { |
|
380 setNPWindowIfNeeded(); |
|
381 } |
|
382 |
|
383 void PluginView::setNPWindowIfNeeded() |
|
384 { |
|
385 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) |
|
386 return; |
|
387 |
|
388 CGContextRef newContextRef = 0; |
|
389 WindowRef newWindowRef = 0; |
|
390 if (platformPluginWidget()) { |
|
391 newContextRef = cgHandleFor(platformPluginWidget()); |
|
392 newWindowRef = nativeWindowFor(platformPluginWidget()); |
|
393 m_npWindow.type = NPWindowTypeWindow; |
|
394 } else { |
|
395 newContextRef = m_contextRef; |
|
396 newWindowRef = m_fakeWindow; |
|
397 m_npWindow.type = NPWindowTypeDrawable; |
|
398 } |
|
399 |
|
400 if (!newContextRef || !newWindowRef) |
|
401 return; |
|
402 |
|
403 m_npWindow.window = (void*)&m_npCgContext; |
|
404 #ifndef NP_NO_CARBON |
|
405 m_npCgContext.window = newWindowRef; |
|
406 #endif |
|
407 m_npCgContext.context = newContextRef; |
|
408 |
|
409 m_npWindow.x = m_windowRect.x(); |
|
410 m_npWindow.y = m_windowRect.y(); |
|
411 m_npWindow.width = m_windowRect.width(); |
|
412 m_npWindow.height = m_windowRect.height(); |
|
413 |
|
414 // TODO: (also clip against scrollbars, etc.) |
|
415 m_npWindow.clipRect.left = max(0, m_windowRect.x()); |
|
416 m_npWindow.clipRect.top = max(0, m_windowRect.y()); |
|
417 m_npWindow.clipRect.right = m_windowRect.x() + m_windowRect.width(); |
|
418 m_npWindow.clipRect.bottom = m_windowRect.y() + m_windowRect.height(); |
|
419 |
|
420 LOG(Plugins, "PluginView::setNPWindowIfNeeded(): window=%p, context=%p," |
|
421 " window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d", |
|
422 newWindowRef, newContextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height, |
|
423 m_npWindow.clipRect.right - m_npWindow.clipRect.left, m_npWindow.clipRect.bottom - m_npWindow.clipRect.top); |
|
424 |
|
425 PluginView::setCurrentPluginView(this); |
|
426 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
|
427 setCallingPlugin(true); |
|
428 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); |
|
429 setCallingPlugin(false); |
|
430 PluginView::setCurrentPluginView(0); |
|
431 } |
|
432 |
|
433 void PluginView::updatePluginWidget() |
|
434 { |
|
435 if (!parent()) |
|
436 return; |
|
437 |
|
438 ASSERT(parent()->isFrameView()); |
|
439 FrameView* frameView = static_cast<FrameView*>(parent()); |
|
440 |
|
441 IntRect oldWindowRect = m_windowRect; |
|
442 IntRect oldClipRect = m_clipRect; |
|
443 |
|
444 m_windowRect = frameView->contentsToWindow(frameRect()); |
|
445 IntPoint offset = topLevelOffsetFor(platformPluginWidget()); |
|
446 m_windowRect.move(offset.x(), offset.y()); |
|
447 |
|
448 if (!platformPluginWidget()) { |
|
449 if (m_windowRect.size() != oldWindowRect.size()) { |
|
450 CGContextRelease(m_contextRef); |
|
451 #if PLATFORM(QT) |
|
452 m_pixmap = QPixmap(m_windowRect.size()); |
|
453 m_pixmap.fill(Qt::transparent); |
|
454 m_contextRef = m_pixmap.isNull() ? 0 : qt_mac_cg_context(&m_pixmap); |
|
455 #endif |
|
456 } |
|
457 } |
|
458 |
|
459 m_clipRect = windowClipRect(); |
|
460 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); |
|
461 |
|
462 if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) |
|
463 setNPWindowIfNeeded(); |
|
464 } |
|
465 |
|
466 void PluginView::paint(GraphicsContext* context, const IntRect& rect) |
|
467 { |
|
468 if (!m_isStarted || m_status != PluginStatusLoadedSuccessfully) { |
|
469 paintMissingPluginIcon(context, rect); |
|
470 return; |
|
471 } |
|
472 |
|
473 if (context->paintingDisabled()) |
|
474 return; |
|
475 |
|
476 setNPWindowIfNeeded(); |
|
477 |
|
478 CGContextRef cgContext = m_npCgContext.context; |
|
479 if (!cgContext) |
|
480 return; |
|
481 |
|
482 CGContextSaveGState(cgContext); |
|
483 if (platformPluginWidget()) { |
|
484 IntPoint offset = frameRect().location(); |
|
485 CGContextTranslateCTM(cgContext, offset.x(), offset.y()); |
|
486 } |
|
487 |
|
488 IntRect targetRect(frameRect()); |
|
489 targetRect.intersects(rect); |
|
490 |
|
491 // clip the context so that plugin only updates the interested area. |
|
492 CGRect r; |
|
493 r.origin.x = targetRect.x() - frameRect().x(); |
|
494 r.origin.y = targetRect.y() - frameRect().y(); |
|
495 r.size.width = targetRect.width(); |
|
496 r.size.height = targetRect.height(); |
|
497 CGContextClipToRect(cgContext, r); |
|
498 |
|
499 if (!platformPluginWidget() && m_isTransparent) { // clean the pixmap in transparent mode |
|
500 #if PLATFORM(QT) |
|
501 QPainter painter(&m_pixmap); |
|
502 painter.setCompositionMode(QPainter::CompositionMode_Clear); |
|
503 painter.fillRect(QRectF(r.origin.x, r.origin.y, r.size.width, r.size.height), Qt::transparent); |
|
504 #endif |
|
505 } |
|
506 |
|
507 #ifndef NP_NO_CARBON |
|
508 EventRecord event; |
|
509 event.what = updateEvt; |
|
510 event.message = (long unsigned int)m_npCgContext.window; |
|
511 event.when = TickCount(); |
|
512 event.where.h = 0; |
|
513 event.where.v = 0; |
|
514 event.modifiers = GetCurrentKeyModifiers(); |
|
515 |
|
516 if (!dispatchNPEvent(event)) |
|
517 LOG(Events, "PluginView::paint(): Paint event not accepted"); |
|
518 #endif |
|
519 |
|
520 CGContextRestoreGState(cgContext); |
|
521 |
|
522 if (!platformPluginWidget()) { |
|
523 #if PLATFORM(QT) |
|
524 QPainter* painter = context->platformContext(); |
|
525 painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap, |
|
526 targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height()); |
|
527 #endif |
|
528 } |
|
529 } |
|
530 |
|
531 void PluginView::invalidateRect(const IntRect& rect) |
|
532 { |
|
533 if (platformPluginWidget()) |
|
534 #if PLATFORM(QT) |
|
535 platformPluginWidget()->update(convertToContainingWindow(rect)); |
|
536 #else |
|
537 platformPluginWidget()->RefreshRect(convertToContainingWindow(rect)); |
|
538 #endif |
|
539 else |
|
540 invalidateWindowlessPluginRect(rect); |
|
541 } |
|
542 |
|
543 void PluginView::invalidateRect(NPRect* rect) |
|
544 { |
|
545 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); |
|
546 invalidateRect(r); |
|
547 } |
|
548 |
|
549 void PluginView::invalidateRegion(NPRegion region) |
|
550 { |
|
551 // TODO: optimize |
|
552 invalidate(); |
|
553 } |
|
554 |
|
555 void PluginView::forceRedraw() |
|
556 { |
|
557 notImplemented(); |
|
558 } |
|
559 |
|
560 |
|
561 // ----------------- Event handling -------------------- |
|
562 |
|
563 void PluginView::handleMouseEvent(MouseEvent* event) |
|
564 { |
|
565 if (!m_isStarted) |
|
566 return; |
|
567 |
|
568 #ifndef NP_NO_CARBON |
|
569 EventRecord record; |
|
570 |
|
571 if (event->type() == eventNames().mousemoveEvent) { |
|
572 // Mouse movement is handled by null timer events |
|
573 m_lastMousePos = mousePosForPlugin(event); |
|
574 return; |
|
575 } else if (event->type() == eventNames().mouseoverEvent) { |
|
576 record.what = adjustCursorEvent; |
|
577 } else if (event->type() == eventNames().mouseoutEvent) { |
|
578 record.what = adjustCursorEvent; |
|
579 } else if (event->type() == eventNames().mousedownEvent) { |
|
580 record.what = mouseDown; |
|
581 // The plugin needs focus to receive keyboard events |
|
582 if (Page* page = m_parentFrame->page()) |
|
583 page->focusController()->setFocusedFrame(m_parentFrame); |
|
584 m_parentFrame->document()->setFocusedNode(m_element); |
|
585 } else if (event->type() == eventNames().mouseupEvent) { |
|
586 record.what = mouseUp; |
|
587 } else { |
|
588 return; |
|
589 } |
|
590 record.where = mousePosForPlugin(event); |
|
591 record.modifiers = modifiersForEvent(event); |
|
592 |
|
593 if (!event->buttonDown()) |
|
594 record.modifiers |= btnState; |
|
595 |
|
596 if (event->button() == 2) |
|
597 record.modifiers |= controlKey; |
|
598 |
|
599 if (!dispatchNPEvent(record)) { |
|
600 if (record.what == adjustCursorEvent) |
|
601 return; // Signals that the plugin wants a normal cursor |
|
602 |
|
603 LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted", |
|
604 record.what, record.where.h, record.where.v); |
|
605 } else { |
|
606 event->setDefaultHandled(); |
|
607 } |
|
608 #endif |
|
609 } |
|
610 |
|
611 void PluginView::handleKeyboardEvent(KeyboardEvent* event) |
|
612 { |
|
613 if (!m_isStarted) |
|
614 return; |
|
615 |
|
616 LOG(Plugins, "PluginView::handleKeyboardEvent() ----------------- "); |
|
617 |
|
618 LOG(Plugins, "PV::hKE(): KE.keyCode: 0x%02X, KE.charCode: %d", |
|
619 event->keyCode(), event->charCode()); |
|
620 |
|
621 #ifndef NP_NO_CARBON |
|
622 EventRecord record; |
|
623 |
|
624 if (event->type() == eventNames().keydownEvent) { |
|
625 // This event is the result of a PlatformKeyboardEvent::KeyDown which |
|
626 // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since |
|
627 // we don't have access to the text here, we return, and wait for the |
|
628 // corresponding event based on PlatformKeyboardEvent::Char. |
|
629 return; |
|
630 } else if (event->type() == eventNames().keypressEvent) { |
|
631 // Which would be this one. This event was disambiguated from the same |
|
632 // PlatformKeyboardEvent::KeyDown, but to a PlatformKeyboardEvent::Char, |
|
633 // which retains the text from the original event. So, we can safely pass |
|
634 // on the event as a key-down event to the plugin. |
|
635 record.what = keyDown; |
|
636 } else if (event->type() == eventNames().keyupEvent) { |
|
637 // PlatformKeyboardEvent::KeyUp events always have the text, so nothing |
|
638 // fancy here. |
|
639 record.what = keyUp; |
|
640 } else { |
|
641 return; |
|
642 } |
|
643 |
|
644 const PlatformKeyboardEvent* platformEvent = event->keyEvent(); |
|
645 int keyCode = platformEvent->nativeVirtualKeyCode(); |
|
646 |
|
647 const String text = platformEvent->text(); |
|
648 if (text.length() < 1) { |
|
649 event->setDefaultHandled(); |
|
650 return; |
|
651 } |
|
652 |
|
653 WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString()); |
|
654 |
|
655 LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s", |
|
656 text.ascii().data(), platformEvent->unmodifiedText().ascii().data(), |
|
657 platformEvent->keyIdentifier().ascii().data()); |
|
658 |
|
659 char charCodes[2] = { 0, 0 }; |
|
660 if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) { |
|
661 LOG_ERROR("Could not resolve character code using system encoding."); |
|
662 event->setDefaultHandled(); |
|
663 return; |
|
664 } |
|
665 |
|
666 record.where = globalMousePosForPlugin(); |
|
667 record.modifiers = modifiersForEvent(event); |
|
668 record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF); |
|
669 record.when = TickCount(); |
|
670 |
|
671 LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers); |
|
672 |
|
673 #if PLATFORM(QT) |
|
674 LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d", |
|
675 keyCode, int(uchar(charCodes[0]))); |
|
676 #endif |
|
677 |
|
678 if (!dispatchNPEvent(record)) |
|
679 LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what); |
|
680 else |
|
681 event->setDefaultHandled(); |
|
682 #endif |
|
683 } |
|
684 |
|
685 #ifndef NP_NO_CARBON |
|
686 void PluginView::nullEventTimerFired(Timer<PluginView>*) |
|
687 { |
|
688 EventRecord record; |
|
689 |
|
690 record.what = nullEvent; |
|
691 record.message = 0; |
|
692 record.when = TickCount(); |
|
693 record.where = m_lastMousePos; |
|
694 record.modifiers = GetCurrentKeyModifiers(); |
|
695 if (!Button()) |
|
696 record.modifiers |= btnState; |
|
697 |
|
698 if (!dispatchNPEvent(record)) |
|
699 LOG(Events, "PluginView::nullEventTimerFired(): Null event not accepted"); |
|
700 } |
|
701 #endif |
|
702 |
|
703 #ifndef NP_NO_CARBON |
|
704 static int modifiersForEvent(UIEventWithKeyState* event) |
|
705 { |
|
706 int modifiers = 0; |
|
707 |
|
708 if (event->ctrlKey()) |
|
709 modifiers |= controlKey; |
|
710 |
|
711 if (event->altKey()) |
|
712 modifiers |= optionKey; |
|
713 |
|
714 if (event->metaKey()) |
|
715 modifiers |= cmdKey; |
|
716 |
|
717 if (event->shiftKey()) |
|
718 modifiers |= shiftKey; |
|
719 |
|
720 return modifiers; |
|
721 } |
|
722 #endif |
|
723 |
|
724 #ifndef NP_NO_CARBON |
|
725 static bool tigerOrBetter() |
|
726 { |
|
727 static SInt32 systemVersion = 0; |
|
728 |
|
729 if (!systemVersion) { |
|
730 if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr) |
|
731 return false; |
|
732 } |
|
733 |
|
734 return systemVersion >= 0x1040; |
|
735 } |
|
736 #endif |
|
737 |
|
738 #ifndef NP_NO_CARBON |
|
739 Point PluginView::globalMousePosForPlugin() const |
|
740 { |
|
741 Point pos; |
|
742 GetGlobalMouse(&pos); |
|
743 |
|
744 float scaleFactor = tigerOrBetter() ? HIGetScaleFactor() : 1; |
|
745 |
|
746 pos.h = short(pos.h * scaleFactor); |
|
747 pos.v = short(pos.v * scaleFactor); |
|
748 |
|
749 #if PLATFORM(WX) |
|
750 // make sure the titlebar/toolbar size is included |
|
751 WindowRef windowRef = nativeWindowFor(platformPluginWidget()); |
|
752 ::Rect content, structure; |
|
753 |
|
754 GetWindowBounds(windowRef, kWindowStructureRgn, &structure); |
|
755 GetWindowBounds(windowRef, kWindowContentRgn, &content); |
|
756 |
|
757 int top = content.top - structure.top; |
|
758 pos.v -= top; |
|
759 #endif |
|
760 |
|
761 return pos; |
|
762 } |
|
763 #endif |
|
764 |
|
765 #ifndef NP_NO_CARBON |
|
766 Point PluginView::mousePosForPlugin(MouseEvent* event) const |
|
767 { |
|
768 ASSERT(event); |
|
769 if (platformPluginWidget()) |
|
770 return globalMousePosForPlugin(); |
|
771 |
|
772 if (event->button() == 2) { |
|
773 // always pass the global position for right-click since Flash uses it to position the context menu |
|
774 return globalMousePosForPlugin(); |
|
775 } |
|
776 |
|
777 Point pos; |
|
778 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); |
|
779 pos.h = postZoomPos.x() + m_windowRect.x(); |
|
780 // The number 22 is the height of the title bar. As to why it figures in the calculation below |
|
781 // is left as an exercise to the reader :-) |
|
782 pos.v = postZoomPos.y() + m_windowRect.y() - 22; |
|
783 return pos; |
|
784 } |
|
785 #endif |
|
786 |
|
787 #ifndef NP_NO_CARBON |
|
788 bool PluginView::dispatchNPEvent(NPEvent& event) |
|
789 { |
|
790 PluginView::setCurrentPluginView(this); |
|
791 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); |
|
792 setCallingPlugin(true); |
|
793 |
|
794 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); |
|
795 |
|
796 setCallingPlugin(false); |
|
797 PluginView::setCurrentPluginView(0); |
|
798 return accepted; |
|
799 } |
|
800 #endif |
|
801 |
|
802 // ------------------- Miscellaneous ------------------ |
|
803 |
|
804 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) |
|
805 { |
|
806 String filename(buf, len); |
|
807 |
|
808 if (filename.startsWith("file:///")) |
|
809 filename = filename.substring(8); |
|
810 |
|
811 if (!fileExists(filename)) |
|
812 return NPERR_FILE_NOT_FOUND; |
|
813 |
|
814 FILE* fileHandle = fopen((filename.utf8()).data(), "r"); |
|
815 |
|
816 if (fileHandle == 0) |
|
817 return NPERR_FILE_NOT_FOUND; |
|
818 |
|
819 int bytesRead = fread(buffer.data(), 1, 0, fileHandle); |
|
820 |
|
821 fclose(fileHandle); |
|
822 |
|
823 if (bytesRead <= 0) |
|
824 return NPERR_FILE_NOT_FOUND; |
|
825 |
|
826 return NPERR_NO_ERROR; |
|
827 } |
|
828 |
|
829 void PluginView::halt() |
|
830 { |
|
831 } |
|
832 |
|
833 void PluginView::restart() |
|
834 { |
|
835 } |
|
836 |
|
837 } // namespace WebCore |