CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / layout / generic / nsObjectFrame.cpp
blobc41499893883f24f29c101326ae0ab19e265039b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:set ts=2 sts=2 sw=2 et cin:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Jacek Piskozub <piskozub@iopan.gda.pl>
26 * Leon Sha <leon.sha@sun.com>
27 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
28 * Robert O'Callahan <roc+moz@cs.cmu.edu>
29 * Christian Biesinger <cbiesinger@web.de>
30 * Josh Aas <josh@mozilla.com>
31 * Mats Palmgren <matspal@gmail.com>
33 * Alternatively, the contents of this file may be used under the terms of
34 * either of the GNU General Public License Version 2 or later (the "GPL"),
35 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 * in which case the provisions of the GPL or the LGPL are applicable instead
37 * of those above. If you wish to allow use of your version of this file only
38 * under the terms of either the GPL or the LGPL, and not to allow others to
39 * use your version of this file under the terms of the MPL, indicate your
40 * decision by deleting the provisions above and replace them with the notice
41 * and other provisions required by the GPL or the LGPL. If you do not delete
42 * the provisions above, a recipient may use your version of this file under
43 * the terms of any one of the MPL, the GPL or the LGPL.
45 * ***** END LICENSE BLOCK ***** */
47 /* rendering objects for replaced elements implemented by a plugin */
49 #ifdef MOZ_WIDGET_QT
50 #include <QWidget>
51 #include <QKeyEvent>
52 #ifdef MOZ_X11
53 #include <QX11Info>
54 #endif
55 #undef slots
56 #endif
58 #ifdef MOZ_IPC
59 #include "mozilla/plugins/PluginMessageUtils.h"
60 #endif
62 #ifdef MOZ_X11
63 #include <cairo-xlib.h>
64 #include "gfxXlibSurface.h"
65 /* X headers suck */
66 enum { XKeyPress = KeyPress };
67 #ifdef KeyPress
68 #undef KeyPress
69 #endif
70 #endif
72 #include "nscore.h"
73 #include "nsCOMPtr.h"
74 #include "nsPresContext.h"
75 #include "nsIPresShell.h"
76 #include "nsWidgetsCID.h"
77 #include "nsIView.h"
78 #include "nsIViewManager.h"
79 #include "nsIDOMKeyListener.h"
80 #include "nsIDOMDragEvent.h"
81 #include "nsIPluginHost.h"
82 #include "nsString.h"
83 #include "nsReadableUtils.h"
84 #include "prmem.h"
85 #include "nsGkAtoms.h"
86 #include "nsIAppShell.h"
87 #include "nsIDocument.h"
88 #include "nsINodeInfo.h"
89 #include "nsIURL.h"
90 #include "nsNetUtil.h"
91 #include "nsIPluginInstanceOwner.h"
92 #include "nsIPluginInstance.h"
93 #include "nsIPluginTagInfo.h"
94 #include "plstr.h"
95 #include "nsILinkHandler.h"
96 #include "nsIScrollPositionListener.h"
97 #include "nsITimer.h"
98 #include "nsIDocShellTreeItem.h"
99 #include "nsIDocShellTreeOwner.h"
100 #include "nsDocShellCID.h"
101 #include "nsIWebBrowserChrome.h"
102 #include "nsIDOMElement.h"
103 #include "nsIDOMNodeList.h"
104 #include "nsIDOMHTMLObjectElement.h"
105 #include "nsIDOMHTMLEmbedElement.h"
106 #include "nsIDOMHTMLAppletElement.h"
107 #include "nsIDOMWindow.h"
108 #include "nsIDOMDocumentEvent.h"
109 #include "nsIDOMMouseListener.h"
110 #include "nsIDOMMouseMotionListener.h"
111 #include "nsIDOMFocusListener.h"
112 #include "nsIDOMContextMenuListener.h"
113 #include "nsIDOMEventTarget.h"
114 #include "nsIDOMNSEvent.h"
115 #include "nsIPrivateDOMEvent.h"
116 #include "nsIDocumentEncoder.h"
117 #include "nsXPIDLString.h"
118 #include "nsIDOMRange.h"
119 #include "nsIPluginWidget.h"
120 #include "nsGUIEvent.h"
121 #include "nsIRenderingContext.h"
122 #include "npapi.h"
123 #include "nsTransform2D.h"
124 #include "nsIImageLoadingContent.h"
125 #include "nsIObjectLoadingContent.h"
126 #include "nsPIDOMWindow.h"
127 #include "nsIDOMElement.h"
128 #include "nsContentUtils.h"
129 #include "nsDisplayList.h"
130 #include "nsAttrName.h"
131 #include "nsDataHashtable.h"
132 #include "nsDOMClassInfo.h"
133 #include "nsFocusManager.h"
134 #include "nsLayoutUtils.h"
135 #include "nsFrameManager.h"
136 #include "nsComponentManagerUtils.h"
137 #include "nsIObserverService.h"
138 #include "nsIScrollableFrame.h"
140 // headers for plugin scriptability
141 #include "nsIScriptGlobalObject.h"
142 #include "nsIScriptContext.h"
143 #include "nsIXPConnect.h"
144 #include "nsIXPCScriptable.h"
145 #include "nsIClassInfo.h"
146 #include "nsIDOMClientRect.h"
148 #include "nsObjectFrame.h"
149 #include "nsIObjectFrame.h"
150 #include "nsPluginNativeWindow.h"
151 #include "nsIPluginDocument.h"
152 #include "FrameLayerBuilder.h"
154 #include "nsThreadUtils.h"
156 #include "gfxContext.h"
157 #include "gfxPlatform.h"
159 #ifdef XP_WIN
160 #include "gfxWindowsNativeDrawing.h"
161 #include "gfxWindowsSurface.h"
162 #endif
164 #include "gfxImageSurface.h"
165 #include "gfxUtils.h"
166 #include "Layers.h"
167 #include "ReadbackLayer.h"
169 // accessibility support
170 #ifdef ACCESSIBILITY
171 #include "nsAccessibilityService.h"
172 #endif
174 #ifdef MOZ_LOGGING
175 #define FORCE_PR_LOG 1 /* Allow logging in the release build */
176 #endif /* MOZ_LOGGING */
177 #include "prlog.h"
179 #include <errno.h>
181 #include "nsContentCID.h"
182 static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
183 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
185 #ifdef XP_MACOSX
186 #include "gfxQuartzNativeDrawing.h"
187 #include "nsPluginUtilsOSX.h"
188 #include "nsCoreAnimationSupport.h"
189 #endif
191 #ifdef MOZ_X11
192 #if (MOZ_PLATFORM_MAEMO == 5) && defined(MOZ_WIDGET_GTK2)
193 #define MOZ_COMPOSITED_PLUGINS 1
194 #define MOZ_USE_IMAGE_EXPOSE 1
195 #include <X11/Xutil.h>
196 #include <X11/Xatom.h>
197 #include <X11/extensions/XShm.h>
198 #include <sys/ipc.h>
199 #include <sys/shm.h>
200 #endif
202 #ifdef MOZ_WIDGET_GTK2
203 #include <gdk/gdk.h>
204 #include <gdk/gdkx.h>
205 #include <gtk/gtk.h>
206 #include "gfxXlibNativeRenderer.h"
207 #endif
208 #endif
210 #ifdef MOZ_WIDGET_QT
211 #include "gfxQtNativeRenderer.h"
212 #endif
214 #ifdef MOZ_X11
215 #include "mozilla/X11Util.h"
216 using mozilla::DefaultXDisplay;
217 #endif
219 #ifdef XP_WIN
220 #include <wtypes.h>
221 #include <winuser.h>
222 #endif
224 #ifdef XP_OS2
225 #define INCL_PM
226 #define INCL_GPI
227 #include <os2.h>
228 #endif
230 #ifdef CreateEvent // Thank you MS.
231 #undef CreateEvent
232 #endif
234 #ifdef PR_LOGGING
235 static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
236 #endif /* PR_LOGGING */
238 #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
239 #define MAC_CARBON_PLUGINS
240 #endif
242 using namespace mozilla;
243 #ifdef MOZ_IPC
244 using namespace mozilla::plugins;
245 #endif
246 using namespace mozilla::layers;
248 // special class for handeling DOM context menu events because for
249 // some reason it starves other mouse events if implemented on the
250 // same class
251 class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener
253 public:
254 nsPluginDOMContextMenuListener();
255 virtual ~nsPluginDOMContextMenuListener();
257 NS_DECL_ISUPPORTS
259 NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
261 nsresult Init(nsIContent* aContent);
262 nsresult Destroy(nsIContent* aContent);
264 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent)
266 return NS_OK;
268 nsEventStatus ProcessEvent(const nsGUIEvent& anEvent)
270 return nsEventStatus_eConsumeNoDefault;
275 class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
276 public nsIPluginInstanceOwner_MOZILLA_2_0_BRANCH,
277 public nsIPluginTagInfo,
278 public nsIDOMMouseListener,
279 public nsIDOMMouseMotionListener,
280 public nsIDOMKeyListener,
281 public nsIDOMFocusListener,
282 public nsIScrollPositionListener
284 public:
285 nsPluginInstanceOwner();
286 virtual ~nsPluginInstanceOwner();
288 NS_DECL_ISUPPORTS
290 //nsIPluginInstanceOwner interface
291 NS_DECL_NSIPLUGININSTANCEOWNER
292 NS_DECL_NSIPLUGININSTANCEOWNER_MOZILLA_2_0_BRANCH
294 NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
295 nsIInputStream *aPostStream,
296 void *aHeadersData, PRUint32 aHeadersDataLen);
298 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
300 NPError ShowNativeContextMenu(NPMenu* menu, void* event);
302 NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
303 double *destX, double *destY, NPCoordinateSpace destSpace);
305 //nsIPluginTagInfo interface
306 NS_DECL_NSIPLUGINTAGINFO
308 // nsIDOMMouseListener interfaces
309 NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
310 NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
311 NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
312 NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
313 NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
314 NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
315 NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
317 // nsIDOMMouseMotionListener interfaces
318 NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
319 NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
321 // nsIDOMKeyListener interfaces
322 NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
323 NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
324 NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
326 // nsIDOMFocusListener interfaces
327 NS_IMETHOD Focus(nsIDOMEvent * aFocusEvent);
328 NS_IMETHOD Blur(nsIDOMEvent * aFocusEvent);
330 nsresult Destroy();
332 void PrepareToStop(PRBool aDelayedStop);
334 #ifdef XP_WIN
335 void Paint(const RECT& aDirty, HDC aDC);
336 #elif defined(XP_MACOSX)
337 void Paint(const gfxRect& aDirtyRect, CGContextRef cgContext);
338 void RenderCoreAnimation(CGContextRef aCGContext, int aWidth, int aHeight);
339 void DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext);
340 #elif defined(MOZ_X11)
341 void Paint(gfxContext* aContext,
342 const gfxRect& aFrameRect,
343 const gfxRect& aDirtyRect);
344 #elif defined(XP_OS2)
345 void Paint(const nsRect& aDirtyRect, HPS aHPS);
346 #endif
348 #ifdef MAC_CARBON_PLUGINS
349 void CancelTimer();
350 void StartTimer(PRBool isVisible);
351 #endif
352 void SendIdleEvent();
354 // nsIScrollPositionListener interface
355 virtual void ScrollPositionWillChange(nscoord aX, nscoord aY);
356 virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
358 //locals
360 nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
361 nsIContent* aContent);
363 void* GetPluginPortFromWidget();
364 void ReleasePluginPort(void* pluginPort);
366 void SetPluginHost(nsIPluginHost* aHost);
368 nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
370 #ifdef XP_MACOSX
371 NPDrawingModel GetDrawingModel();
372 PRBool IsRemoteDrawingCoreAnimation();
373 NPEventModel GetEventModel();
374 static void CARefresh(nsITimer *aTimer, void *aClosure);
375 static void AddToCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
376 static void RemoveFromCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
377 void SetupCARefresh();
378 void* FixUpPluginWindow(PRInt32 inPaintState);
379 void HidePluginWindow();
380 // Set a flag that (if true) indicates the plugin port info has changed and
381 // SetWindow() needs to be called.
382 void SetPluginPortChanged(PRBool aState) { mPluginPortChanged = aState; }
383 // Return a pointer to the internal nsPluginPort structure that's used to
384 // store a copy of plugin port info and to detect when it's been changed.
385 void* GetPluginPortCopy();
386 // Set plugin port info in the plugin (in the 'window' member of the
387 // NPWindow structure passed to the plugin by SetWindow()) and set a
388 // flag (mPluginPortChanged) to indicate whether or not this info has
389 // changed, and SetWindow() needs to be called again.
390 void* SetPluginPortAndDetectChange();
391 // Flag when we've set up a Thebes (and CoreGraphics) context in
392 // nsObjectFrame::PaintPlugin(). We need to know this in
393 // FixUpPluginWindow() (i.e. we need to know when FixUpPluginWindow() has
394 // been called from nsObjectFrame::PaintPlugin() when we're using the
395 // CoreGraphics drawing model).
396 void BeginCGPaint();
397 void EndCGPaint();
398 #else // XP_MACOSX
399 void UpdateWindowPositionAndClipRect(PRBool aSetWindow);
400 void CallSetWindow();
401 void UpdateWindowVisibility(PRBool aVisible);
402 #endif // XP_MACOSX
404 void SetOwner(nsObjectFrame *aOwner)
406 mObjectFrame = aOwner;
409 PRUint32 GetLastEventloopNestingLevel() const {
410 return mLastEventloopNestingLevel;
413 static PRUint32 GetEventloopNestingLevel();
415 void ConsiderNewEventloopNestingLevel() {
416 PRUint32 currentLevel = GetEventloopNestingLevel();
418 if (currentLevel < mLastEventloopNestingLevel) {
419 mLastEventloopNestingLevel = currentLevel;
423 const char* GetPluginName()
425 if (mInstance && mPluginHost) {
426 const char* name = NULL;
427 if (NS_SUCCEEDED(mPluginHost->GetPluginName(mInstance, &name)) && name)
428 return name;
430 return "";
433 #ifdef MOZ_X11
434 void GetPluginDescription(nsACString& aDescription)
436 aDescription.Truncate();
437 if (mInstance && mPluginHost) {
438 nsCOMPtr<nsIPluginTag> pluginTag;
439 mPluginHost->GetPluginTagForInstance(mInstance,
440 getter_AddRefs(pluginTag));
441 if (pluginTag) {
442 pluginTag->GetDescription(aDescription);
446 #endif
448 PRBool SendNativeEvents()
450 #ifdef XP_WIN
451 return mPluginWindow->type == NPWindowTypeDrawable &&
452 MatchPluginName("Shockwave Flash");
453 #elif defined(MOZ_X11) || defined(XP_MACOSX)
454 return PR_TRUE;
455 #else
456 return PR_FALSE;
457 #endif
460 PRBool MatchPluginName(const char *aPluginName)
462 return strncmp(GetPluginName(), aPluginName, strlen(aPluginName)) == 0;
465 #ifdef MOZ_USE_IMAGE_EXPOSE
466 nsresult SetAbsoluteScreenPosition(nsIDOMElement* element,
467 nsIDOMClientRect* position,
468 nsIDOMClientRect* clip);
469 #endif
471 void NotifyPaintWaiter(nsDisplayListBuilder* aBuilder);
472 // Return true if we set image with valid surface
473 PRBool SetCurrentImage(ImageContainer* aContainer);
475 // Methods to update the background image we send to async plugins.
476 // The eventual target of these operations is PluginInstanceParent,
477 // but it takes several hops to get there.
478 void SetBackgroundUnknown();
479 already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect);
480 void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect);
482 PRBool UseAsyncRendering()
484 PRBool useAsyncRendering;
485 return (mInstance &&
486 NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
487 useAsyncRendering &&
488 (!mPluginWindow ||
489 mPluginWindow->type == NPWindowTypeDrawable));
492 private:
494 // return FALSE if LayerSurface dirty (newly created and don't have valid plugin content yet)
495 PRBool IsUpToDate()
497 nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
498 if (!container) {
499 return PR_FALSE;
502 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = do_QueryInterface(mInstance);
503 if (!inst) {
504 return PR_FALSE;
507 nsRefPtr<Image> image;
508 if (!NS_SUCCEEDED(inst->GetImage(container, getter_AddRefs(image))) || !image)
509 return PR_FALSE;
511 container->SetCurrentImage(image);
513 if (container->GetCurrentSize() != gfxIntSize(mPluginWindow->width, mPluginWindow->height))
514 return PR_FALSE;
515 return PR_TRUE;
518 already_AddRefed<nsIPluginInstance_MOZILLA_2_0_BRANCH>
519 GetInstance()
521 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = do_QueryInterface(mInstance);
522 return inst.forget();
525 void FixUpURLS(const nsString &name, nsAString &value);
527 nsPluginNativeWindow *mPluginWindow;
528 nsCOMPtr<nsIPluginInstance> mInstance;
529 nsObjectFrame *mObjectFrame; // owns nsPluginInstanceOwner
530 nsCOMPtr<nsIContent> mContent;
531 nsCString mDocumentBase;
532 char *mTagText;
533 nsCOMPtr<nsIWidget> mWidget;
534 nsCOMPtr<nsIPluginHost> mPluginHost;
536 #ifdef XP_MACOSX
537 NP_CGContext mCGPluginPortCopy;
538 #ifndef NP_NO_QUICKDRAW
539 NP_Port mQDPluginPortCopy;
540 #endif
541 PRInt32 mInCGPaintLevel;
542 nsIOSurface *mIOSurface;
543 nsCARenderer mCARenderer;
544 static nsCOMPtr<nsITimer> *sCATimer;
545 static nsTArray<nsPluginInstanceOwner*> *sCARefreshListeners;
546 PRBool mSentInitialTopLevelWindowEvent;
547 #endif
549 // Initially, the event loop nesting level we were created on, it's updated
550 // if we detect the appshell is on a lower level as long as we're not stopped.
551 // We delay DoStopPlugin() until the appshell reaches this level or lower.
552 PRUint32 mLastEventloopNestingLevel;
553 PRPackedBool mContentFocused;
554 PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
555 #ifdef XP_MACOSX
556 PRPackedBool mPluginPortChanged;
557 #endif
558 #ifdef MOZ_X11
559 // Used with windowless plugins only, initialized in CreateWidget().
560 PRPackedBool mFlash10Quirks;
561 #endif
562 PRPackedBool mPluginWindowVisible;
564 // If true, destroy the widget on destruction. Used when plugin stop
565 // is being delayed to a safer point in time.
566 PRPackedBool mDestroyWidget;
567 PRUint16 mNumCachedAttrs;
568 PRUint16 mNumCachedParams;
569 char **mCachedAttrParamNames;
570 char **mCachedAttrParamValues;
572 #ifdef MOZ_COMPOSITED_PLUGINS
573 nsIntPoint mLastPoint;
574 #endif
576 #ifdef XP_MACOSX
577 NPEventModel mEventModel;
578 #endif
580 // pointer to wrapper for nsIDOMContextMenuListener
581 nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
583 nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
584 nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
585 nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
587 nsresult EnsureCachedAttrParamArrays();
589 #ifdef MOZ_COMPOSITED_PLUGINS
590 nsEventStatus ProcessEventX11Composited(const nsGUIEvent & anEvent);
591 #endif
593 #ifdef MOZ_X11
594 class Renderer
595 #if defined(MOZ_WIDGET_GTK2)
596 : public gfxXlibNativeRenderer
597 #elif defined(MOZ_WIDGET_QT)
598 : public gfxQtNativeRenderer
599 #endif
601 public:
602 Renderer(NPWindow* aWindow, nsPluginInstanceOwner* aInstanceOwner,
603 const nsIntSize& aPluginSize, const nsIntRect& aDirtyRect)
604 : mWindow(aWindow), mInstanceOwner(aInstanceOwner),
605 mPluginSize(aPluginSize), mDirtyRect(aDirtyRect)
607 virtual nsresult DrawWithXlib(gfxXlibSurface* surface, nsIntPoint offset,
608 nsIntRect* clipRects, PRUint32 numClipRects);
609 private:
610 NPWindow* mWindow;
611 nsPluginInstanceOwner* mInstanceOwner;
612 const nsIntSize& mPluginSize;
613 const nsIntRect& mDirtyRect;
615 #endif
617 #ifdef MOZ_USE_IMAGE_EXPOSE
619 // On hildon, we attempt to use NPImageExpose which allows us faster
620 // painting.
622 // used to keep track of how big our buffer is.
623 nsIntSize mPluginSize;
625 // The absolute position on the screen to draw to.
626 gfxRect mAbsolutePosition;
628 // The clip region that we should draw into.
629 gfxRect mAbsolutePositionClip;
631 GC mXlibSurfGC;
632 Window mBlitWindow;
633 XImage *mSharedXImage;
634 XShmSegmentInfo mSharedSegmentInfo;
636 PRBool SetupXShm();
637 void ReleaseXShm();
638 void NativeImageDraw(NPRect* invalidRect = nsnull);
639 PRBool UpdateVisibility(PRBool aVisible);
641 #endif
643 PRPackedBool mWaitingForPaint;
646 class PluginBackgroundSink : public ReadbackSink {
647 public:
648 PluginBackgroundSink(nsObjectFrame* aFrame, PRUint64 aStartSequenceNumber)
649 : mLastSequenceNumber(aStartSequenceNumber), mFrame(aFrame) {}
650 ~PluginBackgroundSink()
652 if (mFrame) {
653 mFrame->mBackgroundSink = nsnull;
657 virtual void SetUnknown(PRUint64 aSequenceNumber)
659 if (!AcceptUpdate(aSequenceNumber))
660 return;
661 mFrame->mInstanceOwner->SetBackgroundUnknown();
664 virtual already_AddRefed<gfxContext>
665 BeginUpdate(const nsIntRect& aRect, PRUint64 aSequenceNumber)
667 if (!AcceptUpdate(aSequenceNumber))
668 return nsnull;
669 return mFrame->mInstanceOwner->BeginUpdateBackground(aRect);
672 virtual void EndUpdate(gfxContext* aContext, const nsIntRect& aRect)
674 return mFrame->mInstanceOwner->EndUpdateBackground(aContext, aRect);
677 void Destroy() { mFrame = nsnull; }
679 protected:
680 PRBool AcceptUpdate(PRUint64 aSequenceNumber) {
681 if (aSequenceNumber > mLastSequenceNumber && mFrame &&
682 mFrame->mInstanceOwner) {
683 mLastSequenceNumber = aSequenceNumber;
684 return PR_TRUE;
686 return PR_FALSE;
689 PRUint64 mLastSequenceNumber;
690 nsObjectFrame* mFrame;
693 // Mac specific code to fix up port position and clip
694 #ifdef XP_MACOSX
696 enum { ePluginPaintEnable, ePluginPaintDisable };
698 #endif // XP_MACOSX
700 nsObjectFrame::nsObjectFrame(nsStyleContext* aContext)
701 : nsObjectFrameSuper(aContext)
702 , mReflowCallbackPosted(PR_FALSE)
704 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
705 ("Created new nsObjectFrame %p\n", this));
708 nsObjectFrame::~nsObjectFrame()
710 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
711 ("nsObjectFrame %p deleted\n", this));
714 NS_QUERYFRAME_HEAD(nsObjectFrame)
715 NS_QUERYFRAME_ENTRY(nsIObjectFrame)
716 NS_QUERYFRAME_TAIL_INHERITING(nsObjectFrameSuper)
718 #ifdef ACCESSIBILITY
719 already_AddRefed<nsAccessible>
720 nsObjectFrame::CreateAccessible()
722 nsAccessibilityService* accService = nsIPresShell::AccService();
723 return accService ?
724 accService->CreateHTMLObjectFrameAccessible(this, mContent,
725 PresContext()->PresShell()) :
726 nsnull;
729 #ifdef XP_WIN
730 NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
732 *aPort = (HWND) mInstanceOwner->GetPluginPortFromWidget();
733 return NS_OK;
735 #endif
736 #endif
738 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
740 NS_IMETHODIMP
741 nsObjectFrame::Init(nsIContent* aContent,
742 nsIFrame* aParent,
743 nsIFrame* aPrevInFlow)
745 NS_PRECONDITION(aContent, "How did that happen?");
746 mPreventInstantiation =
747 (aContent->GetCurrentDoc()->GetDisplayDocument() != nsnull);
749 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
750 ("Initializing nsObjectFrame %p for content %p\n", this, aContent));
752 nsresult rv = nsObjectFrameSuper::Init(aContent, aParent, aPrevInFlow);
754 return rv;
757 void
758 nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
760 NS_ASSERTION(!mPreventInstantiation ||
761 (mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
762 "about to crash due to bug 136927");
764 // we need to finish with the plugin before native window is destroyed
765 // doing this in the destructor is too late.
766 StopPluginInternal(PR_TRUE);
768 // StopPluginInternal might have disowned the widget; if it has,
769 // mWidget will be null.
770 if (mWidget) {
771 mInnerView->DetachWidgetEventHandler(mWidget);
772 mWidget->Destroy();
775 if (mBackgroundSink) {
776 mBackgroundSink->Destroy();
779 nsObjectFrameSuper::DestroyFrom(aDestructRoot);
782 /* virtual */ void
783 nsObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
785 if (HasView()) {
786 nsIView* view = GetView();
787 nsIViewManager* vm = view->GetViewManager();
788 if (vm) {
789 nsViewVisibility visibility =
790 IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow;
791 vm->SetViewVisibility(view, visibility);
795 nsObjectFrameSuper::DidSetStyleContext(aOldStyleContext);
798 nsIAtom*
799 nsObjectFrame::GetType() const
801 return nsGkAtoms::objectFrame;
804 #ifdef DEBUG
805 NS_IMETHODIMP
806 nsObjectFrame::GetFrameName(nsAString& aResult) const
808 return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
810 #endif
812 nsresult
813 nsObjectFrame::CreateWidget(nscoord aWidth,
814 nscoord aHeight,
815 PRBool aViewOnly)
817 nsIView* view = GetView();
818 NS_ASSERTION(view, "Object frames must have views");
819 if (!view) {
820 return NS_OK; //XXX why OK? MMP
823 PRBool needsWidget = !aViewOnly;
824 PRBool canCreateWidget = !nsIWidget::UsePuppetWidgets();
825 if (needsWidget && !canCreateWidget) {
826 NS_WARNING("Can't use native widgets, and can't hand a plugins a PuppetWidget");
829 nsIViewManager* viewMan = view->GetViewManager();
830 // mark the view as hidden since we don't know the (x,y) until Paint
831 // XXX is the above comment correct?
832 viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
834 nsCOMPtr<nsIDeviceContext> dx;
835 viewMan->GetDeviceContext(*getter_AddRefs(dx));
837 //this is ugly. it was ripped off from didreflow(). MMP
838 // Position and size view relative to its parent, not relative to our
839 // parent frame (our parent frame may not have a view).
841 nsIView* parentWithView;
842 nsPoint origin;
843 nsRect r(0, 0, mRect.width, mRect.height);
845 GetOffsetFromView(origin, &parentWithView);
846 viewMan->ResizeView(view, r);
847 viewMan->MoveViewTo(view, origin.x, origin.y);
849 nsRootPresContext* rpc = PresContext()->GetRootPresContext();
850 if (!rpc) {
851 return NS_ERROR_FAILURE;
854 if (needsWidget && !mWidget && canCreateWidget) {
855 // XXX this breaks plugins in popups ... do we care?
856 nsIWidget* parentWidget =
857 rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
858 if (!parentWidget)
859 return NS_ERROR_FAILURE;
861 mInnerView = viewMan->CreateView(GetContentRect() - GetPosition(), view);
862 if (!mInnerView) {
863 NS_ERROR("Could not create inner view");
864 return NS_ERROR_OUT_OF_MEMORY;
866 viewMan->InsertChild(view, mInnerView, nsnull, PR_TRUE);
868 nsresult rv;
869 mWidget = do_CreateInstance(kWidgetCID, &rv);
870 if (NS_FAILED(rv))
871 return rv;
873 nsWidgetInitData initData;
874 initData.mWindowType = eWindowType_plugin;
875 initData.mUnicode = PR_FALSE;
876 initData.clipChildren = PR_TRUE;
877 initData.clipSiblings = PR_TRUE;
878 // We want mWidget to be able to deliver events to us, especially on
879 // Mac where events to the plugin are routed through Gecko. So we
880 // allow the view to attach its event handler to mWidget even though
881 // mWidget isn't the view's designated widget.
882 EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget);
883 rv = mWidget->Create(parentWidget, nsnull, nsIntRect(0,0,0,0),
884 eventHandler, dx, nsnull, nsnull, &initData);
885 if (NS_FAILED(rv)) {
886 mWidget->Destroy();
887 mWidget = nsnull;
888 return rv;
891 mWidget->EnableDragDrop(PR_TRUE);
893 // If this frame has an ancestor with a widget which is not
894 // the root prescontext's widget, then this plugin should not be
895 // displayed, so don't show the widget. If we show the widget, the
896 // plugin may appear in the main window. In Web content this would
897 // only happen with a plugin in a XUL popup.
898 if (parentWidget == GetNearestWidget()) {
899 mWidget->Show(PR_TRUE);
900 #ifdef XP_MACOSX
901 // On Mac, we need to invalidate ourselves since even windowed
902 // plugins are painted through Thebes and we need to ensure
903 // the Thebes layer containing the plugin is updated.
904 Invalidate(GetContentRect() - GetPosition());
905 #endif
909 if (mWidget) {
910 rpc->RegisterPluginForGeometryUpdates(this);
911 rpc->RequestUpdatePluginGeometry(this);
913 // Here we set the background color for this widget because some plugins will use
914 // the child window background color when painting. If it's not set, it may default to gray
915 // Sometimes, a frame doesn't have a background color or is transparent. In this
916 // case, walk up the frame tree until we do find a frame with a background color
917 for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
918 nscolor bgcolor =
919 frame->GetVisitedDependentColor(eCSSProperty_background_color);
920 if (NS_GET_A(bgcolor) > 0) { // make sure we got an actual color
921 mWidget->SetBackgroundColor(bgcolor);
922 break;
926 #ifdef XP_MACOSX
927 // Now that we have a widget we want to set the event model before
928 // any events are processed.
929 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
930 if (!pluginWidget)
931 return NS_ERROR_FAILURE;
932 pluginWidget->SetPluginEventModel(mInstanceOwner->GetEventModel());
933 pluginWidget->SetPluginDrawingModel(mInstanceOwner->GetDrawingModel());
935 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation) {
936 mInstanceOwner->SetupCARefresh();
938 #endif
939 } else {
940 #ifndef XP_MACOSX
941 rpc->RegisterPluginForGeometryUpdates(this);
942 #endif
945 if (!IsHidden()) {
946 viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
949 return (needsWidget && !canCreateWidget) ? NS_ERROR_NOT_AVAILABLE : NS_OK;
952 #define EMBED_DEF_WIDTH 240
953 #define EMBED_DEF_HEIGHT 200
955 /* virtual */ nscoord
956 nsObjectFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
958 nscoord result = 0;
960 if (!IsHidden(PR_FALSE)) {
961 nsIAtom *atom = mContent->Tag();
962 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
963 result = nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH);
967 DISPLAY_MIN_WIDTH(this, result);
968 return result;
971 /* virtual */ nscoord
972 nsObjectFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
974 return nsObjectFrame::GetMinWidth(aRenderingContext);
977 void
978 nsObjectFrame::GetDesiredSize(nsPresContext* aPresContext,
979 const nsHTMLReflowState& aReflowState,
980 nsHTMLReflowMetrics& aMetrics)
982 // By default, we have no area
983 aMetrics.width = 0;
984 aMetrics.height = 0;
986 if (IsHidden(PR_FALSE)) {
987 return;
990 aMetrics.width = aReflowState.ComputedWidth();
991 aMetrics.height = aReflowState.ComputedHeight();
993 // for EMBED and APPLET, default to 240x200 for compatibility
994 nsIAtom *atom = mContent->Tag();
995 if (atom == nsGkAtoms::applet || atom == nsGkAtoms::embed) {
996 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
997 aMetrics.width = NS_MIN(NS_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_WIDTH),
998 aReflowState.mComputedMinWidth),
999 aReflowState.mComputedMaxWidth);
1001 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
1002 aMetrics.height = NS_MIN(NS_MAX(nsPresContext::CSSPixelsToAppUnits(EMBED_DEF_HEIGHT),
1003 aReflowState.mComputedMinHeight),
1004 aReflowState.mComputedMaxHeight);
1007 #if defined (MOZ_WIDGET_GTK2)
1008 // We need to make sure that the size of the object frame does not
1009 // exceed the maximum size of X coordinates. See bug #225357 for
1010 // more information. In theory Gtk2 can handle large coordinates,
1011 // but underlying plugins can't.
1012 aMetrics.height = NS_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.height);
1013 aMetrics.width = NS_MIN(aPresContext->DevPixelsToAppUnits(PR_INT16_MAX), aMetrics.width);
1014 #endif
1017 // At this point, the width has an unconstrained value only if we have
1018 // nothing to go on (no width set, no information from the plugin, nothing).
1019 // Make up a number.
1020 if (aMetrics.width == NS_UNCONSTRAINEDSIZE) {
1021 aMetrics.width =
1022 (aReflowState.mComputedMinWidth != NS_UNCONSTRAINEDSIZE) ?
1023 aReflowState.mComputedMinWidth : 0;
1026 // At this point, the height has an unconstrained value only in two cases:
1027 // a) We are in standards mode with percent heights and parent is auto-height
1028 // b) We have no height information at all.
1029 // In either case, we have to make up a number.
1030 if (aMetrics.height == NS_UNCONSTRAINEDSIZE) {
1031 aMetrics.height =
1032 (aReflowState.mComputedMinHeight != NS_UNCONSTRAINEDSIZE) ?
1033 aReflowState.mComputedMinHeight : 0;
1036 // XXXbz don't add in the border and padding, because we screw up our
1037 // plugin's size and positioning if we do... Eventually we _do_ want to
1038 // paint borders, though! At that point, we will need to adjust the desired
1039 // size either here or in Reflow.... Further, we will need to fix Paint() to
1040 // call the superclass in all cases.
1043 NS_IMETHODIMP
1044 nsObjectFrame::Reflow(nsPresContext* aPresContext,
1045 nsHTMLReflowMetrics& aMetrics,
1046 const nsHTMLReflowState& aReflowState,
1047 nsReflowStatus& aStatus)
1049 DO_GLOBAL_REFLOW_COUNT("nsObjectFrame");
1050 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
1052 // Get our desired size
1053 GetDesiredSize(aPresContext, aReflowState, aMetrics);
1054 aMetrics.SetOverflowAreasToDesiredBounds();
1055 FinishAndStoreOverflow(&aMetrics);
1057 // delay plugin instantiation until all children have
1058 // arrived. Otherwise there may be PARAMs or other stuff that the
1059 // plugin needs to see that haven't arrived yet.
1060 if (!GetContent()->IsDoneAddingChildren()) {
1061 aStatus = NS_FRAME_COMPLETE;
1062 return NS_OK;
1065 // if we are printing or print previewing, bail for now
1066 if (aPresContext->Medium() == nsGkAtoms::print) {
1067 aStatus = NS_FRAME_COMPLETE;
1068 return NS_OK;
1071 nsRect r(0, 0, aMetrics.width, aMetrics.height);
1072 r.Deflate(aReflowState.mComputedBorderPadding);
1074 if (mInnerView) {
1075 nsIViewManager* vm = mInnerView->GetViewManager();
1076 vm->MoveViewTo(mInnerView, r.x, r.y);
1077 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), r.Size()), PR_TRUE);
1080 FixupWindow(r.Size());
1081 if (!mReflowCallbackPosted) {
1082 mReflowCallbackPosted = PR_TRUE;
1083 aPresContext->PresShell()->PostReflowCallback(this);
1086 aStatus = NS_FRAME_COMPLETE;
1088 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
1089 return NS_OK;
1092 ///////////// nsIReflowCallback ///////////////
1094 PRBool
1095 nsObjectFrame::ReflowFinished()
1097 mReflowCallbackPosted = PR_FALSE;
1098 CallSetWindow();
1099 return PR_TRUE;
1102 void
1103 nsObjectFrame::ReflowCallbackCanceled()
1105 mReflowCallbackPosted = PR_FALSE;
1108 nsresult
1109 nsObjectFrame::InstantiatePlugin(nsIPluginHost* aPluginHost,
1110 const char* aMimeType,
1111 nsIURI* aURI)
1113 NS_ASSERTION(mPreventInstantiation,
1114 "Instantiation should be prevented here!");
1116 // If you add early return(s), be sure to balance this call to
1117 // appShell->SuspendNative() with additional call(s) to
1118 // appShell->ReturnNative().
1119 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
1120 if (appShell) {
1121 appShell->SuspendNative();
1124 NS_ASSERTION(mContent, "We should have a content node.");
1126 nsIDocument* doc = mContent->GetOwnerDoc();
1127 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
1128 PRBool fullPageMode = PR_FALSE;
1129 if (pDoc) {
1130 pDoc->GetWillHandleInstantiation(&fullPageMode);
1133 nsresult rv;
1134 if (fullPageMode) { /* full-page mode */
1135 nsCOMPtr<nsIStreamListener> stream;
1136 rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI, mInstanceOwner, getter_AddRefs(stream));
1137 if (NS_SUCCEEDED(rv))
1138 pDoc->SetStreamListener(stream);
1139 } else { /* embedded mode */
1140 rv = aPluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI,
1141 mInstanceOwner);
1144 // Note that |this| may very well be destroyed already!
1146 if (appShell) {
1147 appShell->ResumeNative();
1150 return rv;
1153 void
1154 nsObjectFrame::FixupWindow(const nsSize& aSize)
1156 nsPresContext* presContext = PresContext();
1158 if (!mInstanceOwner)
1159 return;
1161 NPWindow *window;
1162 mInstanceOwner->GetWindow(window);
1164 NS_ENSURE_TRUE(window, /**/);
1166 #ifdef XP_MACOSX
1167 mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
1168 #endif
1170 PRBool windowless = (window->type == NPWindowTypeDrawable);
1172 nsIntPoint origin = GetWindowOriginInPixels(windowless);
1174 window->x = origin.x;
1175 window->y = origin.y;
1177 window->width = presContext->AppUnitsToDevPixels(aSize.width);
1178 window->height = presContext->AppUnitsToDevPixels(aSize.height);
1180 // on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
1181 // us from drawing on screen until the widget is properly positioned, which will not
1182 // happen until we have finished the reflow process.
1183 #ifdef XP_MACOSX
1184 window->clipRect.top = 0;
1185 window->clipRect.left = 0;
1186 window->clipRect.bottom = 0;
1187 window->clipRect.right = 0;
1188 #else
1189 mInstanceOwner->UpdateWindowPositionAndClipRect(PR_FALSE);
1190 #endif
1192 NotifyPluginReflowObservers();
1195 nsresult
1196 nsObjectFrame::CallSetWindow(PRBool aCheckIsHidden)
1198 NPWindow *win = nsnull;
1200 nsresult rv = NS_ERROR_FAILURE;
1201 nsCOMPtr<nsIPluginInstance> pi;
1202 if (!mInstanceOwner ||
1203 NS_FAILED(rv = mInstanceOwner->GetInstance(*getter_AddRefs(pi))) ||
1204 !pi ||
1205 NS_FAILED(rv = mInstanceOwner->GetWindow(win)) ||
1206 !win)
1207 return rv;
1209 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
1210 #ifdef XP_MACOSX
1211 mInstanceOwner->FixUpPluginWindow(ePluginPaintDisable);
1212 #endif
1214 if (aCheckIsHidden && IsHidden())
1215 return NS_ERROR_FAILURE;
1217 // refresh the plugin port as well
1218 window->window = mInstanceOwner->GetPluginPortFromWidget();
1220 // Adjust plugin dimensions according to pixel snap results
1221 // and reduce amount of SetWindow calls
1222 nsPresContext* presContext = PresContext();
1223 nsRootPresContext* rootPC = presContext->GetRootPresContext();
1224 if (!rootPC)
1225 return NS_ERROR_FAILURE;
1226 PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
1227 nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
1228 nsRect bounds = GetContentRect() + GetParent()->GetOffsetToCrossDoc(rootFrame);
1229 nsIntRect intBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
1230 window->x = intBounds.x;
1231 window->y = intBounds.y;
1232 window->width = intBounds.width;
1233 window->height = intBounds.height;
1235 // this will call pi->SetWindow and take care of window subclassing
1236 // if needed, see bug 132759.
1237 if (mInstanceOwner->UseAsyncRendering()) {
1238 rv = pi->AsyncSetWindow(window);
1240 else {
1241 rv = window->CallSetWindow(pi);
1244 mInstanceOwner->ReleasePluginPort(window->window);
1245 return rv;
1248 PRBool
1249 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
1251 if (aTabIndex)
1252 *aTabIndex = -1;
1253 return nsObjectFrameSuper::IsFocusable(aTabIndex, aWithMouse);
1256 PRBool
1257 nsObjectFrame::IsHidden(PRBool aCheckVisibilityStyle) const
1259 if (aCheckVisibilityStyle) {
1260 if (!GetStyleVisibility()->IsVisibleOrCollapsed())
1261 return PR_TRUE;
1264 // only <embed> tags support the HIDDEN attribute
1265 if (mContent->Tag() == nsGkAtoms::embed) {
1266 // Yes, these are really the kooky ways that you could tell 4.x
1267 // not to hide the <embed> once you'd put the 'hidden' attribute
1268 // on the tag...
1270 // HIDDEN w/ no attributes gets translated as we are hidden for
1271 // compatibility w/ 4.x and IE so we don't create a non-painting
1272 // widget in layout. See bug 188959.
1273 nsAutoString hidden;
1274 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, hidden) &&
1275 (hidden.IsEmpty() ||
1276 (!hidden.LowerCaseEqualsLiteral("false") &&
1277 !hidden.LowerCaseEqualsLiteral("no") &&
1278 !hidden.LowerCaseEqualsLiteral("off")))) {
1279 return PR_TRUE;
1283 return PR_FALSE;
1286 nsIntPoint nsObjectFrame::GetWindowOriginInPixels(PRBool aWindowless)
1288 nsIView * parentWithView;
1289 nsPoint origin(0,0);
1291 GetOffsetFromView(origin, &parentWithView);
1293 // if it's windowless, let's make sure we have our origin set right
1294 // it may need to be corrected, like after scrolling
1295 if (aWindowless && parentWithView) {
1296 nsPoint offsetToWidget;
1297 parentWithView->GetNearestWidget(&offsetToWidget);
1298 origin += offsetToWidget;
1300 // It's OK to use GetUsedBorderAndPadding here (and below) since
1301 // GetSkipSides always returns 0; we don't split nsObjectFrames
1302 origin += GetUsedBorderAndPadding().TopLeft();
1304 return nsIntPoint(PresContext()->AppUnitsToDevPixels(origin.x),
1305 PresContext()->AppUnitsToDevPixels(origin.y));
1308 NS_IMETHODIMP
1309 nsObjectFrame::DidReflow(nsPresContext* aPresContext,
1310 const nsHTMLReflowState* aReflowState,
1311 nsDidReflowStatus aStatus)
1313 // Do this check before calling the superclass, as that clears
1314 // NS_FRAME_FIRST_REFLOW
1315 if (aStatus == NS_FRAME_REFLOW_FINISHED &&
1316 (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1317 nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
1318 NS_ASSERTION(objContent, "Why not an object loading content?");
1319 objContent->HasNewFrame(this);
1322 nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
1324 // The view is created hidden; once we have reflowed it and it has been
1325 // positioned then we show it.
1326 if (aStatus != NS_FRAME_REFLOW_FINISHED)
1327 return rv;
1329 if (HasView()) {
1330 nsIView* view = GetView();
1331 nsIViewManager* vm = view->GetViewManager();
1332 if (vm)
1333 vm->SetViewVisibility(view, IsHidden() ? nsViewVisibility_kHide : nsViewVisibility_kShow);
1336 return rv;
1339 /* static */ void
1340 nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
1341 const nsRect& aDirtyRect, nsPoint aPt)
1343 nsPoint pt = aPt + aFrame->GetUsedBorderAndPadding().TopLeft();
1344 nsIRenderingContext::AutoPushTranslation translate(aCtx, pt.x, pt.y);
1345 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
1346 static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
1349 class nsDisplayPluginReadback : public nsDisplayItem {
1350 public:
1351 nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
1352 : nsDisplayItem(aBuilder, aFrame)
1354 MOZ_COUNT_CTOR(nsDisplayPluginReadback);
1356 #ifdef NS_BUILD_REFCNT_LOGGING
1357 virtual ~nsDisplayPluginReadback() {
1358 MOZ_COUNT_DTOR(nsDisplayPluginReadback);
1360 #endif
1362 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
1363 virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
1364 nsRegion* aVisibleRegion,
1365 const nsRect& aAllowVisibleRegionExpansion,
1366 PRBool& aContainsRootContentDocBG);
1368 NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
1370 virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
1371 LayerManager* aManager)
1373 return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
1376 virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
1377 LayerManager* aManager)
1379 return LAYER_ACTIVE;
1383 static nsRect
1384 GetDesiredDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
1386 nsRect r = aFrame->GetContentRect() - aFrame->GetPosition() +
1387 aItem->ToReferenceFrame();
1388 return r;
1391 static nsRect
1392 GetDrawnDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
1394 nsRect r = aFrame->GetContentRect() - aFrame->GetPosition() +
1395 aItem->ToReferenceFrame();
1397 #ifndef XP_MACOSX
1398 nsObjectFrame* f = static_cast<nsObjectFrame*>(aFrame);
1399 if (LAYER_ACTIVE == f->GetLayerState(aBuilder, nsnull)) {
1400 ImageContainer* c = f->GetImageContainer();
1401 if (c) {
1402 gfxIntSize size = c->GetCurrentSize();
1403 PRInt32 appUnitsPerDevPixel = f->PresContext()->AppUnitsPerDevPixel();
1404 nsSize sizeAppUnits(size.width*appUnitsPerDevPixel, size.height*appUnitsPerDevPixel);
1405 r += nsPoint((r.width - sizeAppUnits.width) / 2,
1406 (r.height - sizeAppUnits.height) / 2);
1407 r.SizeTo(sizeAppUnits);
1410 #endif
1411 return r;
1414 nsRect
1415 nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder)
1417 return GetDesiredDisplayItemBounds(aBuilder, this, mFrame);
1420 PRBool
1421 nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1422 nsRegion* aVisibleRegion,
1423 const nsRect& aAllowVisibleRegionExpansion,
1424 PRBool& aContainsRootContentDocBG)
1426 if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1427 aAllowVisibleRegionExpansion,
1428 aContainsRootContentDocBG))
1429 return PR_FALSE;
1431 nsRect expand;
1432 expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder));
1433 // *Add* our bounds to the visible region so that stuff underneath us is
1434 // likely to be made visible, so we can use it for a background! This is
1435 // a bit crazy since we normally only subtract from the visible region.
1436 aVisibleRegion->Or(*aVisibleRegion, expand);
1437 return PR_TRUE;
1440 nsRect
1441 nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
1443 // We use display lists to notify plugins of visibility. But we
1444 // also need to return the "real" visible bounds, possibly those of
1445 // our Image, when actually painting. Usually those will be the
1446 // same, but for the plugin to paint initially, something needs to
1447 // notify it that it's visible. So return whichever the appropriate
1448 // rect here.
1449 return aBuilder->IsForPluginGeometry() ?
1450 GetDesiredDisplayItemBounds(aBuilder, this, mFrame) :
1451 GetDrawnDisplayItemBounds(aBuilder, this, mFrame);
1454 void
1455 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
1456 nsIRenderingContext* aCtx)
1458 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1459 f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder));
1462 PRBool
1463 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
1464 nsRegion* aVisibleRegion,
1465 const nsRect& aAllowVisibleRegionExpansion,
1466 PRBool& aContainsRootContentDocBG)
1468 mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder));
1469 return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
1470 aAllowVisibleRegionExpansion,
1471 aContainsRootContentDocBG);
1474 nsRegion
1475 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
1476 PRBool* aForceTransparentSurface)
1478 if (aForceTransparentSurface) {
1479 *aForceTransparentSurface = PR_FALSE;
1481 nsRegion result;
1482 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1483 if (!aBuilder->IsForPluginGeometry()) {
1484 nsIWidget* widget = f->GetWidget();
1485 if (widget) {
1486 nsTArray<nsIntRect> clip;
1487 widget->GetWindowClipRegion(&clip);
1488 nsTArray<nsIWidget::Configuration> configuration;
1489 GetWidgetConfiguration(aBuilder, &configuration);
1490 NS_ASSERTION(configuration.Length() == 1, "No configuration found");
1491 if (clip != configuration[0].mClipRegion) {
1492 // Something has clipped us unexpectedly. Perhaps there is a translucent
1493 // chrome element overlaying us that forced us to be clipped away. Treat
1494 // us as non-opaque since we may have holes.
1495 return result;
1499 if (f->IsOpaque()) {
1500 result = GetBounds(aBuilder);
1502 return result;
1505 void
1506 nsDisplayPlugin::GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
1507 nsTArray<nsIWidget::Configuration>* aConfigurations)
1509 nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
1510 nsPoint pluginOrigin = mFrame->GetUsedBorderAndPadding().TopLeft() +
1511 ToReferenceFrame();
1512 f->ComputeWidgetGeometry(mVisibleRegion, pluginOrigin, aConfigurations);
1515 void
1516 nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
1517 const nsPoint& aPluginOrigin,
1518 nsTArray<nsIWidget::Configuration>* aConfigurations)
1520 if (!mWidget) {
1521 #ifndef XP_MACOSX
1522 if (mInstanceOwner) {
1523 // UpdateWindowVisibility will notify the plugin of position changes
1524 // by updating the NPWindow and calling NPP_SetWindow/AsyncSetWindow.
1525 mInstanceOwner->UpdateWindowVisibility(!aRegion.IsEmpty());
1527 #endif
1528 return;
1531 nsPresContext* presContext = PresContext();
1532 nsRootPresContext* rootPC = presContext->GetRootPresContext();
1533 if (!rootPC)
1534 return;
1536 nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
1537 if (!configuration)
1538 return;
1539 configuration->mChild = mWidget;
1541 PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
1542 nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
1543 nsRect bounds = GetContentRect() + GetParent()->GetOffsetToCrossDoc(rootFrame);
1544 configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
1546 // This should produce basically the same rectangle (but not relative
1547 // to the root frame). We only call this here for the side-effect of
1548 // setting mViewToWidgetOffset on the view.
1549 mInnerView->CalcWidgetBounds(eWindowType_plugin);
1551 nsRegionRectIterator iter(aRegion);
1552 nsIntPoint pluginOrigin = aPluginOrigin.ToNearestPixels(appUnitsPerDevPixel);
1553 for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
1554 // Snap *r to pixels while it's relative to the painted widget, to
1555 // improve consistency with rectangle and image drawing
1556 nsIntRect pixRect =
1557 r->ToNearestPixels(appUnitsPerDevPixel) - pluginOrigin;
1558 if (!pixRect.IsEmpty()) {
1559 configuration->mClipRegion.AppendElement(pixRect);
1564 nsresult
1565 nsObjectFrame::SetAbsoluteScreenPosition(nsIDOMElement* element,
1566 nsIDOMClientRect* position,
1567 nsIDOMClientRect* clip)
1569 #ifdef MOZ_USE_IMAGE_EXPOSE
1570 if (!mInstanceOwner)
1571 return NS_ERROR_NOT_AVAILABLE;
1572 return mInstanceOwner->SetAbsoluteScreenPosition(element, position, clip);
1573 #else
1574 return NS_ERROR_NOT_IMPLEMENTED;
1575 #endif
1578 nsresult
1579 nsObjectFrame::PluginEventNotifier::Run() {
1580 nsCOMPtr<nsIObserverService> obsSvc =
1581 mozilla::services::GetObserverService();
1582 obsSvc->NotifyObservers(nsnull, "plugin-changed-event", mEventType.get());
1583 return NS_OK;
1586 void
1587 nsObjectFrame::NotifyPluginReflowObservers()
1589 nsContentUtils::AddScriptRunner(new PluginEventNotifier(NS_LITERAL_STRING("reflow")));
1592 void
1593 nsObjectFrame::DidSetWidgetGeometry()
1595 #if defined(XP_MACOSX)
1596 if (mInstanceOwner) {
1597 mInstanceOwner->FixUpPluginWindow(ePluginPaintEnable);
1599 #endif
1602 PRBool
1603 nsObjectFrame::IsOpaque() const
1605 #if defined(XP_MACOSX)
1606 // ???
1607 return PR_FALSE;
1608 #else
1609 return !IsTransparentMode();
1610 #endif
1613 PRBool
1614 nsObjectFrame::IsTransparentMode() const
1616 #if defined(XP_MACOSX)
1617 // ???
1618 return PR_FALSE;
1619 #else
1620 if (!mInstanceOwner)
1621 return PR_FALSE;
1623 NPWindow *window;
1624 mInstanceOwner->GetWindow(window);
1625 if (window->type != NPWindowTypeDrawable)
1626 return PR_FALSE;
1628 nsresult rv;
1629 nsCOMPtr<nsIPluginInstance> pi;
1630 rv = mInstanceOwner->GetInstance(*getter_AddRefs(pi));
1631 if (NS_FAILED(rv) || !pi)
1632 return PR_FALSE;
1634 PRBool transparent = PR_FALSE;
1635 pi->IsTransparent(&transparent);
1636 return transparent;
1637 #endif
1640 NS_IMETHODIMP
1641 nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1642 const nsRect& aDirtyRect,
1643 const nsDisplayListSet& aLists)
1645 AddStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
1647 // XXX why are we painting collapsed object frames?
1648 if (!IsVisibleOrCollapsedForPainting(aBuilder))
1649 return NS_OK;
1651 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
1652 NS_ENSURE_SUCCESS(rv, rv);
1654 nsPresContext::nsPresContextType type = PresContext()->Type();
1656 // If we are painting in Print Preview do nothing....
1657 if (type == nsPresContext::eContext_PrintPreview)
1658 return NS_OK;
1660 DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame");
1662 #ifndef XP_MACOSX
1663 if (mWidget && aBuilder->IsInTransform()) {
1664 // Windowed plugins should not be rendered inside a transform.
1665 return NS_OK;
1667 #endif
1669 nsDisplayList replacedContent;
1671 if (aBuilder->IsForPainting() && mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
1672 NPWindow* window = nsnull;
1673 mInstanceOwner->GetWindow(window);
1674 PRBool isVisible = window && window->width > 0 && window->height > 0;
1675 if (isVisible && aBuilder->ShouldSyncDecodeImages()) {
1676 #ifndef XP_MACOSX
1677 mInstanceOwner->UpdateWindowVisibility(PR_TRUE);
1678 #endif
1681 ImageContainer* container = GetImageContainer();
1682 nsRefPtr<Image> currentImage = container ? container->GetCurrentImage() : nsnull;
1683 if (!currentImage || !isVisible ||
1684 container->GetCurrentSize() != gfxIntSize(window->width, window->height)) {
1685 mInstanceOwner->NotifyPaintWaiter(aBuilder);
1689 // determine if we are printing
1690 if (type == nsPresContext::eContext_Print) {
1691 rv = replacedContent.AppendNewToTop(new (aBuilder)
1692 nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
1693 nsDisplayItem::TYPE_PRINT_PLUGIN));
1694 } else {
1695 if (aBuilder->IsPaintingToWindow() &&
1696 GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE &&
1697 IsTransparentMode()) {
1698 rv = replacedContent.AppendNewToTop(new (aBuilder)
1699 nsDisplayPluginReadback(aBuilder, this));
1700 NS_ENSURE_SUCCESS(rv, rv);
1703 rv = replacedContent.AppendNewToTop(new (aBuilder)
1704 nsDisplayPlugin(aBuilder, this));
1706 NS_ENSURE_SUCCESS(rv, rv);
1708 WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
1710 return NS_OK;
1713 void
1714 nsObjectFrame::PrintPlugin(nsIRenderingContext& aRenderingContext,
1715 const nsRect& aDirtyRect)
1717 nsCOMPtr<nsIObjectLoadingContent> obj(do_QueryInterface(mContent));
1718 if (!obj)
1719 return;
1721 nsIFrame* frame = nsnull;
1722 obj->GetPrintFrame(&frame);
1723 if (!frame)
1724 return;
1726 nsPresContext* presContext = PresContext();
1727 // make sure this is REALLY an nsIObjectFrame
1728 // we may need to go through the children to get it
1729 nsIObjectFrame* objectFrame = do_QueryFrame(frame);
1730 if (!objectFrame)
1731 objectFrame = GetNextObjectFrame(presContext,frame);
1732 if (!objectFrame)
1733 return;
1735 // finally we can get our plugin instance
1736 nsCOMPtr<nsIPluginInstance> pi;
1737 if (NS_FAILED(objectFrame->GetPluginInstance(*getter_AddRefs(pi))) || !pi)
1738 return;
1740 // now we need to setup the correct location for printing
1741 NPWindow window;
1742 window.window = nsnull;
1744 // prepare embedded mode printing struct
1745 NPPrint npprint;
1746 npprint.mode = NP_EMBED;
1748 // we need to find out if we are windowless or not
1749 PRBool windowless = PR_FALSE;
1750 pi->IsWindowless(&windowless);
1751 window.type = windowless ? NPWindowTypeDrawable : NPWindowTypeWindow;
1753 window.clipRect.bottom = 0; window.clipRect.top = 0;
1754 window.clipRect.left = 0; window.clipRect.right = 0;
1756 // platform specific printing code
1757 #ifdef MAC_CARBON_PLUGINS
1758 nsSize contentSize = GetContentRect().Size();
1759 window.x = 0;
1760 window.y = 0;
1761 window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1762 window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1764 gfxContext *ctx = aRenderingContext.ThebesContext();
1765 if (!ctx)
1766 return;
1767 gfxContextAutoSaveRestore save(ctx);
1769 ctx->NewPath();
1771 gfxRect rect(window.x, window.y, window.width, window.height);
1773 ctx->Rectangle(rect);
1774 ctx->Clip();
1776 gfxQuartzNativeDrawing nativeDraw(ctx, rect);
1777 CGContextRef cgContext = nativeDraw.BeginNativeDrawing();
1778 if (!cgContext) {
1779 nativeDraw.EndNativeDrawing();
1780 return;
1783 window.clipRect.right = window.width;
1784 window.clipRect.bottom = window.height;
1785 window.type = NPWindowTypeDrawable;
1787 Rect gwBounds;
1788 ::SetRect(&gwBounds, 0, 0, window.width, window.height);
1790 nsTArray<char> buffer(window.width * window.height * 4);
1791 CGColorSpaceRef cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1792 if (!cspace) {
1793 nativeDraw.EndNativeDrawing();
1794 return;
1796 CGContextRef cgBuffer =
1797 ::CGBitmapContextCreate(buffer.Elements(),
1798 window.width, window.height, 8, window.width * 4,
1799 cspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedFirst);
1800 ::CGColorSpaceRelease(cspace);
1801 if (!cgBuffer) {
1802 nativeDraw.EndNativeDrawing();
1803 return;
1805 GWorldPtr gWorld;
1806 if (::NewGWorldFromPtr(&gWorld, k32ARGBPixelFormat, &gwBounds, NULL, NULL, 0,
1807 buffer.Elements(), window.width * 4) != noErr) {
1808 ::CGContextRelease(cgBuffer);
1809 nativeDraw.EndNativeDrawing();
1810 return;
1813 window.clipRect.right = window.width;
1814 window.clipRect.bottom = window.height;
1815 window.type = NPWindowTypeDrawable;
1816 // Setting nsPluginPrint/NPPrint.print.embedPrint.window.window to
1817 // &GWorldPtr and nsPluginPrint/NPPrint.print.embedPrint.platformPrint to
1818 // GWorldPtr isn't any kind of standard (it's not documented anywhere).
1819 // But that's what WebKit does. And it's what the Flash plugin (apparently
1820 // the only NPAPI plugin on OS X to support printing) seems to expect. So
1821 // we do the same. The Flash plugin uses the CoreGraphics drawing mode.
1822 // But a GWorldPtr should be usable in either CoreGraphics or QuickDraw
1823 // drawing mode. See bug 191046.
1824 window.window = &gWorld;
1825 npprint.print.embedPrint.platformPrint = gWorld;
1826 npprint.print.embedPrint.window = window;
1827 nsresult rv = pi->Print(&npprint);
1829 ::CGContextTranslateCTM(cgContext, 0.0f, float(window.height));
1830 ::CGContextScaleCTM(cgContext, 1.0f, -1.0f);
1831 CGImageRef image = ::CGBitmapContextCreateImage(cgBuffer);
1832 if (!image) {
1833 ::CGContextRestoreGState(cgContext);
1834 ::CGContextRelease(cgBuffer);
1835 ::DisposeGWorld(gWorld);
1836 nativeDraw.EndNativeDrawing();
1837 return;
1839 ::CGContextDrawImage(cgContext,
1840 ::CGRectMake(0, 0, window.width, window.height),
1841 image);
1842 ::CGImageRelease(image);
1843 ::CGContextRelease(cgBuffer);
1845 ::DisposeGWorld(gWorld);
1847 nativeDraw.EndNativeDrawing();
1848 #elif defined(XP_UNIX)
1850 /* XXX this just flat-out doesn't work in a thebes world --
1851 * RenderEPS is a no-op. So don't bother to do any work here.
1854 #elif defined(XP_OS2)
1855 void *hps = aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_OS2_PS);
1856 if (!hps)
1857 return;
1859 npprint.print.embedPrint.platformPrint = hps;
1860 npprint.print.embedPrint.window = window;
1861 // send off print info to plugin
1862 pi->Print(&npprint);
1863 #elif defined(XP_WIN)
1865 /* On Windows, we use the win32 printing surface to print. This, in
1866 * turn, uses the Cairo paginated surface, which in turn uses the
1867 * meta surface to record all operations and then play them back.
1868 * This doesn't work too well for plugins, because if plugins render
1869 * directly into the DC, the meta surface won't have any knowledge
1870 * of them, and so at the end when it actually does the replay step,
1871 * it'll fill the background with white and draw over whatever was
1872 * rendered before.
1874 * So, to avoid this, we use PushGroup, which creates a new windows
1875 * surface, the plugin renders to that, and then we use normal
1876 * cairo methods to composite that in such that it's recorded using the
1877 * meta surface.
1880 /* we'll already be translated into the right spot by gfxWindowsNativeDrawing */
1881 nsSize contentSize = GetContentRect().Size();
1882 window.x = 0;
1883 window.y = 0;
1884 window.width = presContext->AppUnitsToDevPixels(contentSize.width);
1885 window.height = presContext->AppUnitsToDevPixels(contentSize.height);
1887 gfxContext *ctx = aRenderingContext.ThebesContext();
1889 ctx->Save();
1891 /* Make sure plugins don't do any damage outside of where they're supposed to */
1892 ctx->NewPath();
1893 gfxRect r(window.x, window.y, window.width, window.height);
1894 ctx->Rectangle(r);
1895 ctx->Clip();
1897 gfxWindowsNativeDrawing nativeDraw(ctx, r);
1898 do {
1899 HDC dc = nativeDraw.BeginNativeDrawing();
1900 if (!dc)
1901 return;
1903 // XXX don't we need to call nativeDraw.TransformToNativeRect here?
1904 npprint.print.embedPrint.platformPrint = dc;
1905 npprint.print.embedPrint.window = window;
1906 // send off print info to plugin
1907 pi->Print(&npprint);
1909 nativeDraw.EndNativeDrawing();
1910 } while (nativeDraw.ShouldRenderAgain());
1911 nativeDraw.PaintToContext();
1913 ctx->Restore();
1914 #endif
1916 // XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
1917 // XXX Calling DidReflow here makes no sense!!!
1918 nsDidReflowStatus status = NS_FRAME_REFLOW_FINISHED; // should we use a special status?
1919 frame->DidReflow(presContext,
1920 nsnull, status); // DidReflow will take care of it
1923 ImageContainer*
1924 nsObjectFrame::GetImageContainer(LayerManager* aManager)
1926 nsRefPtr<LayerManager> manager = aManager;
1928 if (!manager) {
1929 manager = nsContentUtils::LayerManagerForDocument(mContent->GetOwnerDoc());
1931 if (!manager) {
1932 return nsnull;
1935 // XXX - in the future image containers will be manager independent and
1936 // we can remove the manager equals check and only check the backend type.
1937 if (mImageContainer &&
1938 (!mImageContainer->Manager() || mImageContainer->Manager() == manager) &&
1939 mImageContainer->GetBackendType() == manager->GetBackendType()) {
1940 return mImageContainer;
1943 mImageContainer = manager->CreateImageContainer();
1944 return mImageContainer;
1947 class AsyncPaintWaitEvent : public nsRunnable
1949 public:
1950 AsyncPaintWaitEvent(nsIContent* aContent, PRBool aFinished) :
1951 mContent(aContent), mFinished(aFinished)
1955 NS_IMETHOD Run()
1957 nsContentUtils::DispatchTrustedEvent(mContent->GetOwnerDoc(), mContent,
1958 mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"),
1959 PR_TRUE, PR_TRUE);
1960 return NS_OK;
1963 private:
1964 nsCOMPtr<nsIContent> mContent;
1965 PRPackedBool mFinished;
1968 void
1969 nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
1971 // This is notification for reftests about async plugin paint start
1972 if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
1973 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, PR_FALSE);
1974 // Run this event as soon as it's safe to do so, since listeners need to
1975 // receive it immediately
1976 mWaitingForPaint = nsContentUtils::AddScriptRunner(event);
1980 static void DrawPlugin(ImageContainer* aContainer, void* aObjectFrame)
1982 static_cast<nsObjectFrame*>(aObjectFrame)->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
1985 void
1986 nsObjectFrame::UpdateImageLayer(ImageContainer* aContainer, const gfxRect& aRect)
1988 #ifdef XP_MACOSX
1989 mInstanceOwner->DoCocoaEventDrawRect(aRect, nsnull);
1990 #endif
1992 mInstanceOwner->SetCurrentImage(aContainer);
1995 PRBool
1996 nsPluginInstanceOwner::SetCurrentImage(ImageContainer* aContainer)
1998 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = do_QueryInterface(mInstance);
1999 if (inst) {
2000 nsRefPtr<Image> image;
2001 inst->GetImage(aContainer, getter_AddRefs(image));
2002 if (image) {
2003 #ifdef XP_MACOSX
2004 if (image->GetFormat() == Image::MAC_IO_SURFACE) {
2005 MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
2006 oglImage->SetCallback(&DrawPlugin, mObjectFrame);
2008 #endif
2009 aContainer->SetCurrentImage(image);
2010 return PR_TRUE;
2013 aContainer->SetCurrentImage(nsnull);
2014 return PR_FALSE;
2017 void
2018 nsPluginInstanceOwner::SetBackgroundUnknown()
2020 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = GetInstance();
2021 if (inst) {
2022 inst->SetBackgroundUnknown();
2026 already_AddRefed<gfxContext>
2027 nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
2029 nsIntRect rect = aRect;
2030 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = GetInstance();
2031 nsRefPtr<gfxContext> ctx;
2032 if (inst &&
2033 NS_SUCCEEDED(inst->BeginUpdateBackground(&rect, getter_AddRefs(ctx)))) {
2034 return ctx.forget();
2036 return nsnull;
2039 void
2040 nsPluginInstanceOwner::EndUpdateBackground(gfxContext* aContext,
2041 const nsIntRect& aRect)
2043 nsIntRect rect = aRect;
2044 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = GetInstance();
2045 if (inst) {
2046 inst->EndUpdateBackground(aContext, &rect);
2050 mozilla::LayerState
2051 nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
2052 LayerManager* aManager)
2054 if (!mInstanceOwner)
2055 return mozilla::LAYER_NONE;
2057 #ifdef XP_MACOSX
2058 if (aManager &&
2059 aManager->GetBackendType() == LayerManager::LAYERS_OPENGL &&
2060 mInstanceOwner->GetEventModel() == NPEventModelCocoa &&
2061 mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics &&
2062 mInstanceOwner->IsRemoteDrawingCoreAnimation())
2064 return mozilla::LAYER_ACTIVE;
2066 #endif
2068 if (!mInstanceOwner->UseAsyncRendering())
2069 return mozilla::LAYER_NONE;
2071 return mozilla::LAYER_ACTIVE;
2074 already_AddRefed<Layer>
2075 nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
2076 LayerManager* aManager,
2077 nsDisplayItem* aItem)
2079 if (!mInstanceOwner)
2080 return nsnull;
2082 NPWindow* window = nsnull;
2083 mInstanceOwner->GetWindow(window);
2084 if (!window)
2085 return nsnull;
2087 if (window->width <= 0 || window->height <= 0)
2088 return nsnull;
2090 // Create image
2091 nsRefPtr<ImageContainer> container = GetImageContainer(aManager);
2092 if (!container)
2093 return nsnull;
2094 if (GetStateBits() & NS_OBJECT_NEEDS_SET_IMAGE) {
2095 RemoveStateBits(NS_OBJECT_NEEDS_SET_IMAGE);
2096 if (!mInstanceOwner->SetCurrentImage(container)) {
2097 return nsnull;
2100 gfxIntSize size = container->GetCurrentSize();
2102 nsRect area = GetContentRect() + aBuilder->ToReferenceFrame(GetParent());
2103 gfxRect r = nsLayoutUtils::RectToGfxRect(area, PresContext()->AppUnitsPerDevPixel());
2104 // to provide crisper and faster drawing.
2105 r.Round();
2106 nsRefPtr<Layer> layer =
2107 (aBuilder->LayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem));
2109 if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) {
2110 if (!layer) {
2111 mInstanceOwner->NotifyPaintWaiter(aBuilder);
2112 // Initialize ImageLayer
2113 layer = aManager->CreateImageLayer();
2114 if (!layer)
2115 return nsnull;
2118 NS_ASSERTION(layer->GetType() == Layer::TYPE_IMAGE, "Bad layer type");
2120 ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
2121 UpdateImageLayer(container, r);
2123 imglayer->SetContainer(container);
2124 imglayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
2126 layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
2127 } else {
2128 NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
2129 "Unknown item type");
2130 NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds");
2132 if (!layer) {
2133 layer = aManager->CreateReadbackLayer();
2134 if (!layer)
2135 return nsnull;
2137 NS_ASSERTION(layer->GetType() == Layer::TYPE_READBACK, "Bad layer type");
2139 ReadbackLayer* readback = static_cast<ReadbackLayer*>(layer.get());
2140 if (readback->GetSize() != nsIntSize(size.width, size.height)) {
2141 // This will destroy any old background sink and notify us that the
2142 // background is now unknown
2143 readback->SetSink(nsnull);
2144 NS_ASSERTION(!mBackgroundSink, "Should have been cleared");
2146 readback->SetSize(nsIntSize(size.width, size.height));
2148 mBackgroundSink =
2149 new PluginBackgroundSink(this,
2150 readback->AllocateSequenceNumber());
2151 readback->SetSink(mBackgroundSink);
2152 // The layer has taken ownership of our sink. When either the sink dies
2153 // or the frame dies, the connection from the surviving object is nulled out.
2157 // Set a transform on the layer to draw the plugin in the right place
2158 gfxMatrix transform;
2159 // Center plugin if layer size != frame rect
2160 r.pos.x += (r.Width() - size.width) / 2;
2161 r.pos.y += (r.Height() - size.height) / 2;
2162 transform.Translate(r.pos);
2164 layer->SetTransform(gfx3DMatrix::From2D(transform));
2165 return layer.forget();
2168 void
2169 nsObjectFrame::PaintPlugin(nsDisplayListBuilder* aBuilder,
2170 nsIRenderingContext& aRenderingContext,
2171 const nsRect& aDirtyRect, const nsRect& aPluginRect)
2173 // Screen painting code
2174 #if defined(XP_MACOSX)
2175 // delegate all painting to the plugin instance.
2176 if (mInstanceOwner) {
2177 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreGraphics ||
2178 mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
2179 mInstanceOwner->GetDrawingModel() ==
2180 NPDrawingModelInvalidatingCoreAnimation) {
2181 PRInt32 appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
2182 // Clip to the content area where the plugin should be drawn. If
2183 // we don't do this, the plugin can draw outside its bounds.
2184 nsIntRect contentPixels = aPluginRect.ToNearestPixels(appUnitsPerDevPixel);
2185 nsIntRect dirtyPixels = aDirtyRect.ToOutsidePixels(appUnitsPerDevPixel);
2186 nsIntRect clipPixels;
2187 clipPixels.IntersectRect(contentPixels, dirtyPixels);
2189 // Don't invoke the drawing code if the clip is empty.
2190 if (clipPixels.IsEmpty())
2191 return;
2193 gfxRect nativeClipRect(clipPixels.x, clipPixels.y,
2194 clipPixels.width, clipPixels.height);
2195 gfxContext* ctx = aRenderingContext.ThebesContext();
2197 gfxContextAutoSaveRestore save(ctx);
2198 ctx->NewPath();
2199 ctx->Rectangle(nativeClipRect);
2200 ctx->Clip();
2201 gfxPoint offset(contentPixels.x, contentPixels.y);
2202 ctx->Translate(offset);
2204 gfxQuartzNativeDrawing nativeDrawing(ctx, nativeClipRect - offset);
2206 CGContextRef cgContext = nativeDrawing.BeginNativeDrawing();
2207 if (!cgContext) {
2208 NS_WARNING("null CGContextRef during PaintPlugin");
2209 return;
2212 nsCOMPtr<nsIPluginInstance> inst;
2213 GetPluginInstance(*getter_AddRefs(inst));
2214 if (!inst) {
2215 NS_WARNING("null plugin instance during PaintPlugin");
2216 nativeDrawing.EndNativeDrawing();
2217 return;
2219 NPWindow* window;
2220 mInstanceOwner->GetWindow(window);
2221 if (!window) {
2222 NS_WARNING("null plugin window during PaintPlugin");
2223 nativeDrawing.EndNativeDrawing();
2224 return;
2226 NP_CGContext* cgPluginPortCopy =
2227 static_cast<NP_CGContext*>(mInstanceOwner->GetPluginPortCopy());
2228 if (!cgPluginPortCopy) {
2229 NS_WARNING("null plugin port copy during PaintPlugin");
2230 nativeDrawing.EndNativeDrawing();
2231 return;
2233 #ifndef NP_NO_CARBON
2234 if (mInstanceOwner->GetEventModel() == NPEventModelCarbon &&
2235 !mInstanceOwner->SetPluginPortAndDetectChange()) {
2236 NS_WARNING("null plugin port during PaintPlugin");
2237 nativeDrawing.EndNativeDrawing();
2238 return;
2241 // In the Carbon event model...
2242 // If gfxQuartzNativeDrawing hands out a CGContext different from the
2243 // one set by SetPluginPortAndDetectChange(), we need to pass it to the
2244 // plugin via SetWindow(). This will happen in nsPluginInstanceOwner::
2245 // FixUpPluginWindow(), called from nsPluginInstanceOwner::Paint().
2246 // (If SetPluginPortAndDetectChange() made any changes itself, this has
2247 // already been detected in that method, and will likewise result in a
2248 // call to SetWindow() from FixUpPluginWindow().)
2249 NP_CGContext* windowContext = static_cast<NP_CGContext*>(window->window);
2250 if (mInstanceOwner->GetEventModel() == NPEventModelCarbon &&
2251 windowContext->context != cgContext) {
2252 windowContext->context = cgContext;
2253 cgPluginPortCopy->context = cgContext;
2254 mInstanceOwner->SetPluginPortChanged(PR_TRUE);
2256 #endif
2258 mInstanceOwner->BeginCGPaint();
2259 if (mInstanceOwner->GetDrawingModel() == NPDrawingModelCoreAnimation ||
2260 mInstanceOwner->GetDrawingModel() ==
2261 NPDrawingModelInvalidatingCoreAnimation) {
2262 // CoreAnimation is updated, render the layer and perform a readback.
2263 mInstanceOwner->RenderCoreAnimation(cgContext, window->width, window->height);
2264 } else {
2265 mInstanceOwner->Paint(nativeClipRect - offset, cgContext);
2267 mInstanceOwner->EndCGPaint();
2269 nativeDrawing.EndNativeDrawing();
2270 } else {
2271 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
2272 nsIRenderingContext::AutoPushTranslation
2273 translate(&aRenderingContext, aPluginRect.x, aPluginRect.y);
2275 // this rect is used only in the CoreGraphics drawing model
2276 gfxRect tmpRect(0, 0, 0, 0);
2277 mInstanceOwner->Paint(tmpRect, NULL);
2280 #elif defined(MOZ_X11)
2281 if (mInstanceOwner) {
2282 NPWindow *window;
2283 mInstanceOwner->GetWindow(window);
2284 #ifdef MOZ_COMPOSITED_PLUGINS
2286 #else
2287 if (window->type == NPWindowTypeDrawable) {
2288 #endif
2289 gfxRect frameGfxRect =
2290 PresContext()->AppUnitsToGfxUnits(aPluginRect);
2291 gfxRect dirtyGfxRect =
2292 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
2293 gfxContext* ctx = aRenderingContext.ThebesContext();
2295 mInstanceOwner->Paint(ctx, frameGfxRect, dirtyGfxRect);
2298 #elif defined(XP_WIN)
2299 nsCOMPtr<nsIPluginInstance> inst;
2300 GetPluginInstance(*getter_AddRefs(inst));
2301 if (inst) {
2302 gfxRect frameGfxRect =
2303 PresContext()->AppUnitsToGfxUnits(aPluginRect);
2304 gfxRect dirtyGfxRect =
2305 PresContext()->AppUnitsToGfxUnits(aDirtyRect);
2306 gfxContext *ctx = aRenderingContext.ThebesContext();
2307 gfxMatrix currentMatrix = ctx->CurrentMatrix();
2309 if (ctx->UserToDevicePixelSnapped(frameGfxRect, PR_FALSE)) {
2310 dirtyGfxRect = ctx->UserToDevice(dirtyGfxRect);
2311 ctx->IdentityMatrix();
2313 dirtyGfxRect.RoundOut();
2315 // Look if it's windowless
2316 NPWindow *window;
2317 mInstanceOwner->GetWindow(window);
2319 if (window->type == NPWindowTypeDrawable) {
2320 // the offset of the DC
2321 nsPoint origin;
2323 gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect);
2324 #ifdef MOZ_IPC
2325 if (nativeDraw.IsDoublePass()) {
2326 // OOP plugin specific: let the shim know before we paint if we are doing a
2327 // double pass render. If this plugin isn't oop, the register window message
2328 // will be ignored.
2329 NPEvent pluginEvent;
2330 pluginEvent.event = DoublePassRenderingEvent();
2331 pluginEvent.wParam = 0;
2332 pluginEvent.lParam = 0;
2333 if (pluginEvent.event)
2334 inst->HandleEvent(&pluginEvent, nsnull);
2336 #endif
2337 do {
2338 HDC hdc = nativeDraw.BeginNativeDrawing();
2339 if (!hdc)
2340 return;
2342 RECT dest;
2343 nativeDraw.TransformToNativeRect(frameGfxRect, dest);
2344 RECT dirty;
2345 nativeDraw.TransformToNativeRect(dirtyGfxRect, dirty);
2347 window->window = hdc;
2348 window->x = dest.left;
2349 window->y = dest.top;
2350 window->clipRect.left = 0;
2351 window->clipRect.top = 0;
2352 // if we're painting, we're visible.
2353 window->clipRect.right = window->width;
2354 window->clipRect.bottom = window->height;
2356 // Windowless plugins on windows need a special event to update their location,
2357 // see bug 135737.
2359 // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
2360 // relative to the window it is contained in, which is useful for the plugin to
2361 // correctly translate mouse coordinates.
2363 // this does not mesh with the comments for bug 135737 which imply that the rectangle
2364 // must be clipped in some way to prevent the plugin attempting to paint over areas
2365 // it shouldn't.
2367 // since the two uses of the rectangle are mutually exclusive in some cases, and
2368 // since I don't see any incorrect painting (at least with Flash and ViewPoint -
2369 // the originator of bug 135737), it seems that windowless plugins are not relying
2370 // on information here for clipping their drawing, and we can safely use this message
2371 // to tell the plugin exactly where it is in all cases.
2373 nsIntPoint origin = GetWindowOriginInPixels(PR_TRUE);
2374 nsIntRect winlessRect = nsIntRect(origin, nsIntSize(window->width, window->height));
2376 if (mWindowlessRect != winlessRect) {
2377 mWindowlessRect = winlessRect;
2379 WINDOWPOS winpos;
2380 memset(&winpos, 0, sizeof(winpos));
2381 winpos.x = mWindowlessRect.x;
2382 winpos.y = mWindowlessRect.y;
2383 winpos.cx = mWindowlessRect.width;
2384 winpos.cy = mWindowlessRect.height;
2386 // finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
2387 NPEvent pluginEvent;
2388 pluginEvent.event = WM_WINDOWPOSCHANGED;
2389 pluginEvent.wParam = 0;
2390 pluginEvent.lParam = (LPARAM)&winpos;
2391 inst->HandleEvent(&pluginEvent, nsnull);
2394 inst->SetWindow(window);
2396 mInstanceOwner->Paint(dirty, hdc);
2397 nativeDraw.EndNativeDrawing();
2398 } while (nativeDraw.ShouldRenderAgain());
2399 nativeDraw.PaintToContext();
2402 ctx->SetMatrix(currentMatrix);
2404 #elif defined(XP_OS2)
2405 nsCOMPtr<nsIPluginInstance> inst;
2406 GetPluginInstance(*getter_AddRefs(inst));
2407 if (inst) {
2408 // Look if it's windowless
2409 NPWindow *window;
2410 mInstanceOwner->GetWindow(window);
2412 if (window->type == NPWindowTypeDrawable) {
2413 // FIXME - Bug 385435: Doesn't aDirtyRect need translating too?
2414 nsIRenderingContext::AutoPushTranslation
2415 translate(&aRenderingContext, aPluginRect.x, aPluginRect.y);
2417 // check if we need to call SetWindow with updated parameters
2418 PRBool doupdatewindow = PR_FALSE;
2419 // the offset of the DC
2420 nsIntPoint origin;
2423 * Layout now has an optimized way of painting. Now we always get
2424 * a new drawing surface, sized to be just what's needed. Windowless
2425 * plugins need a transform applied to their origin so they paint
2426 * in the right place. Since |SetWindow| is no longer being used
2427 * to tell the plugin where it is, we dispatch a NPWindow through
2428 * |HandleEvent| to tell the plugin when its window moved
2430 gfxContext *ctx = aRenderingContext.ThebesContext();
2432 gfxMatrix ctxMatrix = ctx->CurrentMatrix();
2433 if (ctxMatrix.HasNonTranslation()) {
2434 // soo; in the future, we should be able to render
2435 // the object content to an offscreen DC, and then
2436 // composite it in with the right transforms.
2438 // But, we don't bother doing that, because we don't
2439 // have the event handling story figured out yet.
2440 // Instead, let's just bail.
2442 return;
2445 origin.x = NSToIntRound(float(ctxMatrix.GetTranslation().x));
2446 origin.y = NSToIntRound(float(ctxMatrix.GetTranslation().y));
2448 /* Need to force the clip to be set */
2449 ctx->UpdateSurfaceClip();
2451 /* Set the device offsets as appropriate, for whatever our current group offsets might be */
2452 gfxFloat xoff, yoff;
2453 nsRefPtr<gfxASurface> surf = ctx->CurrentSurface(&xoff, &yoff);
2455 if (surf->CairoStatus() != 0) {
2456 NS_WARNING("Plugin is being asked to render to a surface that's in error!");
2457 return;
2460 // check if we need to update the PS
2461 HPS hps = (HPS)aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_OS2_PS);
2462 if (reinterpret_cast<HPS>(window->window) != hps) {
2463 window->window = reinterpret_cast<void*>(hps);
2464 doupdatewindow = PR_TRUE;
2466 LONG lPSid = GpiSavePS(hps);
2467 RECTL rclViewport;
2468 if (GpiQueryDevice(hps) != NULLHANDLE) { // ensure that we have an associated HDC
2469 if (GpiQueryPageViewport(hps, &rclViewport)) {
2470 rclViewport.xLeft += (LONG)xoff;
2471 rclViewport.xRight += (LONG)xoff;
2472 rclViewport.yBottom += (LONG)yoff;
2473 rclViewport.yTop += (LONG)yoff;
2474 GpiSetPageViewport(hps, &rclViewport);
2478 if ((window->x != origin.x) || (window->y != origin.y)) {
2479 window->x = origin.x;
2480 window->y = origin.y;
2481 doupdatewindow = PR_TRUE;
2484 // if our location or visible area has changed, we need to tell the plugin
2485 if (doupdatewindow) {
2486 inst->SetWindow(window);
2489 mInstanceOwner->Paint(aDirtyRect, hps);
2490 if (lPSid >= 1) {
2491 GpiRestorePS(hps, lPSid);
2493 surf->MarkDirty();
2496 #endif
2499 NS_IMETHODIMP
2500 nsObjectFrame::HandleEvent(nsPresContext* aPresContext,
2501 nsGUIEvent* anEvent,
2502 nsEventStatus* anEventStatus)
2504 NS_ENSURE_ARG_POINTER(anEvent);
2505 NS_ENSURE_ARG_POINTER(anEventStatus);
2506 nsresult rv = NS_OK;
2508 if (!mInstanceOwner)
2509 return NS_ERROR_NULL_POINTER;
2511 mInstanceOwner->ConsiderNewEventloopNestingLevel();
2513 if (anEvent->message == NS_PLUGIN_ACTIVATE) {
2514 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2515 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(GetContent());
2516 if (fm && elem)
2517 return fm->SetFocus(elem, 0);
2519 else if (anEvent->message == NS_PLUGIN_FOCUS) {
2520 nsIFocusManager_MOZILLA_2_0_BRANCH* fm = nsFocusManager::GetFocusManager();
2521 if (fm)
2522 return fm->FocusPlugin(GetContent());
2525 if (mInstanceOwner->SendNativeEvents() &&
2526 (NS_IS_PLUGIN_EVENT(anEvent) || NS_IS_NON_RETARGETED_PLUGIN_EVENT(anEvent))) {
2527 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
2528 return rv;
2531 #ifdef XP_WIN
2532 rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
2533 return rv;
2534 #endif
2536 #ifdef XP_MACOSX
2537 // we want to process some native mouse events in the cocoa event model
2538 if ((anEvent->message == NS_MOUSE_ENTER || anEvent->message == NS_MOUSE_SCROLL) &&
2539 mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
2540 *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
2541 return rv;
2543 #endif
2545 if (anEvent->message == NS_DESTROY) {
2546 #ifdef MAC_CARBON_PLUGINS
2547 mInstanceOwner->CancelTimer();
2548 #endif
2549 return rv;
2552 return nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
2555 #ifdef XP_MACOSX
2556 // Needed to make the routing of mouse events while dragging conform to
2557 // standard OS X practice, and to the Cocoa NPAPI spec. See bug 525078.
2558 NS_IMETHODIMP
2559 nsObjectFrame::HandlePress(nsPresContext* aPresContext,
2560 nsGUIEvent* anEvent,
2561 nsEventStatus* anEventStatus)
2563 nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
2564 return nsObjectFrameSuper::HandlePress(aPresContext, anEvent, anEventStatus);
2566 #endif
2568 nsresult
2569 nsObjectFrame::GetPluginInstance(nsIPluginInstance*& aPluginInstance)
2571 aPluginInstance = nsnull;
2573 if (!mInstanceOwner)
2574 return NS_OK;
2576 return mInstanceOwner->GetInstance(aPluginInstance);
2579 nsresult
2580 nsObjectFrame::PrepareInstanceOwner()
2582 nsWeakFrame weakFrame(this);
2584 // First, have to stop any possibly running plugins.
2585 StopPluginInternal(PR_FALSE);
2587 if (!weakFrame.IsAlive()) {
2588 return NS_ERROR_NOT_AVAILABLE;
2591 NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
2593 mInstanceOwner = new nsPluginInstanceOwner();
2595 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
2596 ("Created new instance owner %p for frame %p\n", mInstanceOwner.get(),
2597 this));
2599 if (!mInstanceOwner)
2600 return NS_ERROR_OUT_OF_MEMORY;
2602 // Note, |this| may very well be gone after this call.
2603 return mInstanceOwner->Init(PresContext(), this, GetContent());
2606 nsresult
2607 nsObjectFrame::Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
2609 if (mPreventInstantiation) {
2610 return NS_OK;
2613 // Note: If PrepareInstanceOwner() returns an error, |this| may very
2614 // well be deleted already.
2615 nsresult rv = PrepareInstanceOwner();
2616 NS_ENSURE_SUCCESS(rv, rv);
2618 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
2619 if (NS_FAILED(rv))
2620 return rv;
2621 mInstanceOwner->SetPluginHost(pluginHost);
2623 // This must be done before instantiating the plugin
2624 FixupWindow(GetContentRect().Size());
2626 // Ensure we redraw when a plugin is instantiated
2627 Invalidate(GetContentRect() - GetPosition());
2629 nsWeakFrame weakFrame(this);
2631 NS_ASSERTION(!mPreventInstantiation, "Say what?");
2632 mPreventInstantiation = PR_TRUE;
2633 rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
2635 if (!weakFrame.IsAlive()) {
2636 return NS_ERROR_NOT_AVAILABLE;
2639 NS_ASSERTION(mPreventInstantiation,
2640 "Instantiation should still be prevented!");
2641 mPreventInstantiation = PR_FALSE;
2643 #ifdef ACCESSIBILITY
2644 nsAccessibilityService* accService = nsIPresShell::AccService();
2645 if (accService) {
2646 accService->RecreateAccessible(PresContext()->PresShell(), mContent);
2648 #endif
2650 return rv;
2653 nsresult
2654 nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
2656 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
2657 ("nsObjectFrame::Instantiate(%s) called on frame %p\n", aMimeType,
2658 this));
2660 if (mPreventInstantiation) {
2661 return NS_OK;
2664 // XXXbz can aMimeType ever actually be null here? If not, either
2665 // the callers are wrong (and passing "" instead of null) or we can
2666 // remove the codepaths dealing with null aMimeType in
2667 // InstantiateEmbeddedPlugin.
2668 NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
2670 // Note: If PrepareInstanceOwner() returns an error, |this| may very
2671 // well be deleted already.
2672 nsresult rv = PrepareInstanceOwner();
2673 NS_ENSURE_SUCCESS(rv, rv);
2675 nsWeakFrame weakFrame(this);
2677 // This must be done before instantiating the plugin
2678 FixupWindow(GetContentRect().Size());
2680 // Ensure we redraw when a plugin is instantiated
2681 Invalidate(GetContentRect() - GetPosition());
2683 // get the nsIPluginHost service
2684 nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
2685 if (NS_FAILED(rv))
2686 return rv;
2687 mInstanceOwner->SetPluginHost(pluginHost);
2689 NS_ASSERTION(!mPreventInstantiation, "Say what?");
2690 mPreventInstantiation = PR_TRUE;
2692 rv = InstantiatePlugin(pluginHost, aMimeType, aURI);
2694 if (!weakFrame.IsAlive()) {
2695 return NS_ERROR_NOT_AVAILABLE;
2698 // finish up
2699 if (NS_SUCCEEDED(rv)) {
2700 TryNotifyContentObjectWrapper();
2702 if (!weakFrame.IsAlive()) {
2703 return NS_ERROR_NOT_AVAILABLE;
2706 CallSetWindow();
2709 NS_ASSERTION(mPreventInstantiation,
2710 "Instantiation should still be prevented!");
2712 #ifdef ACCESSIBILITY
2713 nsAccessibilityService* accService = nsIPresShell::AccService();
2714 if (accService) {
2715 accService->RecreateAccessible(PresContext()->PresShell(), mContent);
2717 #endif
2719 mPreventInstantiation = PR_FALSE;
2721 return rv;
2724 void
2725 nsObjectFrame::TryNotifyContentObjectWrapper()
2727 nsCOMPtr<nsIPluginInstance> inst;
2728 mInstanceOwner->GetInstance(*getter_AddRefs(inst));
2729 if (inst) {
2730 // The plugin may have set up new interfaces; we need to mess with our JS
2731 // wrapper. Note that we DO NOT want to call this if there is no plugin
2732 // instance! That would just reenter Instantiate(), trying to create
2733 // said plugin instance.
2734 NotifyContentObjectWrapper();
2738 class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
2740 public:
2741 NS_DECL_ISUPPORTS_INHERITED
2743 nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
2744 : mInstanceOwner(aInstanceOwner)
2746 NS_ASSERTION(aInstanceOwner, "need an owner");
2749 // nsRunnable
2750 NS_IMETHOD Run();
2752 // nsITimerCallback
2753 NS_IMETHOD Notify(nsITimer *timer);
2755 private:
2756 nsCOMPtr<nsITimer> mTimer;
2757 nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
2760 NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
2762 static const char*
2763 GetMIMEType(nsIPluginInstance *aPluginInstance)
2765 if (aPluginInstance) {
2766 const char* mime = nsnull;
2767 if (NS_SUCCEEDED(aPluginInstance->GetMIMEType(&mime)) && mime)
2768 return mime;
2770 return "";
2773 static PRBool
2774 DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
2776 #if (MOZ_PLATFORM_MAEMO==5)
2777 // Don't delay stop on Maemo/Hildon (bug 530739).
2778 if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
2779 return PR_FALSE;
2780 #endif
2782 // Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
2783 // XStandard (bug 430219), CMISS Zinc (bug 429604).
2784 if (aDelayedStop
2785 #if !(defined XP_WIN || defined MOZ_X11)
2786 && !aInstanceOwner->MatchPluginName("QuickTime")
2787 && !aInstanceOwner->MatchPluginName("Flip4Mac")
2788 && !aInstanceOwner->MatchPluginName("XStandard plugin")
2789 && !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
2790 #endif
2792 nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(aInstanceOwner);
2793 NS_DispatchToCurrentThread(evt);
2794 return PR_TRUE;
2796 return PR_FALSE;
2799 static void
2800 DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
2802 nsCOMPtr<nsIPluginInstance> inst;
2803 aInstanceOwner->GetInstance(*getter_AddRefs(inst));
2804 if (inst) {
2805 NPWindow *win;
2806 aInstanceOwner->GetWindow(win);
2807 nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
2808 nsCOMPtr<nsIPluginInstance> nullinst;
2810 if (window)
2811 window->CallSetWindow(nullinst);
2812 else
2813 inst->SetWindow(nsnull);
2815 if (DoDelayedStop(aInstanceOwner, aDelayedStop))
2816 return;
2818 #if defined(XP_MACOSX)
2819 aInstanceOwner->HidePluginWindow();
2820 #endif
2822 nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
2823 NS_ASSERTION(pluginHost, "Without a pluginHost, how can we have an instance to destroy?");
2824 pluginHost->StopPluginInstance(inst);
2826 // the frame is going away along with its widget so tell the
2827 // window to forget its widget too
2828 if (window)
2829 window->SetPluginWidget(nsnull);
2832 aInstanceOwner->Destroy();
2835 NS_IMETHODIMP
2836 nsStopPluginRunnable::Notify(nsITimer *aTimer)
2838 return Run();
2841 NS_IMETHODIMP
2842 nsStopPluginRunnable::Run()
2844 // InitWithCallback calls Release before AddRef so we need to hold a
2845 // strong ref on 'this' since we fall through to this scope if it fails.
2846 nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
2847 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
2848 if (appShell) {
2849 PRUint32 currentLevel = 0;
2850 appShell->GetEventloopNestingLevel(&currentLevel);
2851 if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
2852 if (!mTimer)
2853 mTimer = do_CreateInstance("@mozilla.org/timer;1");
2854 if (mTimer) {
2855 // Fire 100ms timer to try to tear down this plugin as quickly as
2856 // possible once the nesting level comes back down.
2857 nsresult rv = mTimer->InitWithCallback(this, 100, nsITimer::TYPE_ONE_SHOT);
2858 if (NS_SUCCEEDED(rv)) {
2859 return rv;
2862 NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
2863 "time). Stopping the plugin now, this might crash.");
2867 mTimer = nsnull;
2869 DoStopPlugin(mInstanceOwner, PR_FALSE);
2871 return NS_OK;
2874 void
2875 nsObjectFrame::StopPlugin()
2877 PRBool delayedStop = PR_FALSE;
2878 #ifdef XP_WIN
2879 nsCOMPtr<nsIPluginInstance> inst;
2880 if (mInstanceOwner)
2881 mInstanceOwner->GetInstance(*getter_AddRefs(inst));
2882 if (inst) {
2883 // Delayed stop for Real plugin only; see bug 420886, 426852.
2884 const char* pluginType = ::GetMIMEType(inst);
2885 delayedStop = strcmp(pluginType, "audio/x-pn-realaudio-plugin") == 0;
2887 #endif
2888 StopPluginInternal(delayedStop);
2891 void
2892 nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
2894 if (!mInstanceOwner) {
2895 return;
2898 nsRootPresContext* rpc = PresContext()->GetRootPresContext();
2899 if (!rpc) {
2900 NS_ASSERTION(PresContext()->PresShell()->IsFrozen(),
2901 "unable to unregister the plugin frame");
2903 else if (mWidget) {
2904 rpc->UnregisterPluginForGeometryUpdates(this);
2906 // Make sure the plugin is hidden in case an update of plugin geometry
2907 // hasn't happened since this plugin became hidden.
2908 nsIWidget* parent = mWidget->GetParent();
2909 if (parent) {
2910 nsTArray<nsIWidget::Configuration> configurations;
2911 GetEmptyClipConfiguration(&configurations);
2912 parent->ConfigureChildren(configurations);
2915 else {
2916 #ifndef XP_MACOSX
2917 rpc->UnregisterPluginForGeometryUpdates(this);
2918 #endif
2921 // Transfer the reference to the instance owner onto the stack so
2922 // that if we do end up re-entering this code, or if we unwind back
2923 // here witha deleted frame (this), we can still continue to stop
2924 // the plugin. Note that due to that, the ordering of the code in
2925 // this function is extremely important.
2927 nsRefPtr<nsPluginInstanceOwner> owner;
2928 owner.swap(mInstanceOwner);
2930 // Make sure that our windowless rect has been zeroed out, so if we
2931 // get reinstantiated we'll send the right messages to the plug-in.
2932 mWindowlessRect.Empty();
2934 PRBool oldVal = mPreventInstantiation;
2935 mPreventInstantiation = PR_TRUE;
2937 nsWeakFrame weakFrame(this);
2939 #if defined(XP_WIN) || defined(MOZ_X11)
2940 if (aDelayedStop && mWidget) {
2941 // If we're asked to do a delayed stop it means we're stopping the
2942 // plugin because we're destroying the frame. In that case, disown
2943 // the widget.
2944 mInnerView->DetachWidgetEventHandler(mWidget);
2945 mWidget = nsnull;
2947 #endif
2949 // From this point on, |this| could have been deleted, so don't
2950 // touch it!
2951 owner->PrepareToStop(aDelayedStop);
2953 DoStopPlugin(owner, aDelayedStop);
2955 // If |this| is still alive, reset mPreventInstantiation.
2956 if (weakFrame.IsAlive()) {
2957 NS_ASSERTION(mPreventInstantiation,
2958 "Instantiation should still be prevented!");
2960 mPreventInstantiation = oldVal;
2963 // Break relationship between frame and plugin instance owner
2964 owner->SetOwner(nsnull);
2967 void
2968 nsObjectFrame::NotifyContentObjectWrapper()
2970 nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
2971 if (!doc)
2972 return;
2974 nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
2975 if (!sgo)
2976 return;
2978 nsIScriptContext *scx = sgo->GetContext();
2979 if (!scx)
2980 return;
2982 JSContext *cx = (JSContext *)scx->GetNativeContext();
2984 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
2985 nsContentUtils::XPConnect()->
2986 GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), mContent,
2987 NS_GET_IID(nsISupports),
2988 getter_AddRefs(wrapper));
2990 if (!wrapper) {
2991 // Nothing to do here if there's no wrapper for mContent. The proto
2992 // chain will be fixed appropriately when the wrapper is created.
2993 return;
2996 JSObject *obj = nsnull;
2997 nsresult rv = wrapper->GetJSObject(&obj);
2998 if (NS_FAILED(rv))
2999 return;
3001 nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
3004 // static
3005 nsIObjectFrame *
3006 nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)
3008 nsIFrame* child = aRoot->GetFirstChild(nsnull);
3010 while (child) {
3011 nsIObjectFrame* outFrame = do_QueryFrame(child);
3012 if (outFrame) {
3013 nsCOMPtr<nsIPluginInstance> pi;
3014 outFrame->GetPluginInstance(*getter_AddRefs(pi)); // make sure we have a REAL plugin
3015 if (pi)
3016 return outFrame;
3019 outFrame = GetNextObjectFrame(aPresContext, child);
3020 if (outFrame)
3021 return outFrame;
3022 child = child->GetNextSibling();
3025 return nsnull;
3028 /*static*/ void
3029 nsObjectFrame::BeginSwapDocShells(nsIContent* aContent, void*)
3031 NS_PRECONDITION(aContent, "");
3033 // This function is called from a document content enumerator so we need
3034 // to filter out the nsObjectFrames and ignore the rest.
3035 nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
3036 if (!obj)
3037 return;
3039 nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
3040 NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
3041 "Plugin windows must not be toplevel");
3042 nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
3043 NS_ASSERTION(rootPC, "unable to unregister the plugin frame");
3044 rootPC->UnregisterPluginForGeometryUpdates(objectFrame);
3047 /*static*/ void
3048 nsObjectFrame::EndSwapDocShells(nsIContent* aContent, void*)
3050 NS_PRECONDITION(aContent, "");
3052 // This function is called from a document content enumerator so we need
3053 // to filter out the nsObjectFrames and ignore the rest.
3054 nsIObjectFrame* obj = do_QueryFrame(aContent->GetPrimaryFrame());
3055 if (!obj)
3056 return;
3058 nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
3059 nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
3060 NS_ASSERTION(rootPC, "unable to register the plugin frame");
3061 nsIWidget* widget = objectFrame->GetWidget();
3062 if (widget) {
3063 // Reparent the widget.
3064 nsIWidget* parent =
3065 rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
3066 widget->SetParent(parent);
3067 objectFrame->CallSetWindow();
3069 // Register for geometry updates and make a request.
3070 rootPC->RegisterPluginForGeometryUpdates(objectFrame);
3071 rootPC->RequestUpdatePluginGeometry(objectFrame);
3075 nsIFrame*
3076 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
3078 return new (aPresShell) nsObjectFrame(aContext);
3081 NS_IMPL_FRAMEARENA_HELPERS(nsObjectFrame)
3084 // nsPluginDOMContextMenuListener class implementation
3086 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener()
3090 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
3094 NS_IMPL_ISUPPORTS2(nsPluginDOMContextMenuListener,
3095 nsIDOMContextMenuListener,
3096 nsIDOMEventListener)
3098 NS_IMETHODIMP
3099 nsPluginDOMContextMenuListener::ContextMenu(nsIDOMEvent* aContextMenuEvent)
3101 aContextMenuEvent->PreventDefault(); // consume event
3103 return NS_OK;
3106 nsresult nsPluginDOMContextMenuListener::Init(nsIContent* aContent)
3108 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
3109 if (receiver) {
3110 receiver->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
3111 return NS_OK;
3114 return NS_ERROR_NO_INTERFACE;
3117 nsresult nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
3119 // Unregister context menu listener
3120 nsCOMPtr<nsIDOMEventTarget> receiver(do_QueryInterface(aContent));
3121 if (receiver) {
3122 receiver->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, PR_TRUE);
3125 return NS_OK;
3128 //plugin instance owner
3130 nsPluginInstanceOwner::nsPluginInstanceOwner()
3132 // create nsPluginNativeWindow object, it is derived from NPWindow
3133 // struct and allows to manipulate native window procedure
3134 nsCOMPtr<nsIPluginHost> ph = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
3135 if (ph)
3136 ph->NewPluginNativeWindow(&mPluginWindow);
3137 else
3138 mPluginWindow = nsnull;
3140 mObjectFrame = nsnull;
3141 mTagText = nsnull;
3142 #ifdef XP_MACOSX
3143 memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
3144 #ifndef NP_NO_QUICKDRAW
3145 memset(&mQDPluginPortCopy, 0, sizeof(NP_Port));
3146 #endif
3147 mInCGPaintLevel = 0;
3148 mSentInitialTopLevelWindowEvent = PR_FALSE;
3149 mIOSurface = nsnull;
3150 mPluginPortChanged = PR_FALSE;
3151 #endif
3152 mContentFocused = PR_FALSE;
3153 mWidgetVisible = PR_TRUE;
3154 mPluginWindowVisible = PR_FALSE;
3155 mNumCachedAttrs = 0;
3156 mNumCachedParams = 0;
3157 mCachedAttrParamNames = nsnull;
3158 mCachedAttrParamValues = nsnull;
3159 mDestroyWidget = PR_FALSE;
3161 #ifdef MOZ_COMPOSITED_PLUGINS
3162 mLastPoint = nsIntPoint(0,0);
3163 #endif
3165 #ifdef MOZ_USE_IMAGE_EXPOSE
3166 mPluginSize = nsIntSize(0,0);
3167 mXlibSurfGC = None;
3168 mBlitWindow = nsnull;
3169 mSharedXImage = nsnull;
3170 mSharedSegmentInfo.shmaddr = nsnull;
3171 #endif
3173 #ifdef XP_MACOSX
3174 #ifndef NP_NO_QUICKDRAW
3175 mEventModel = NPEventModelCarbon;
3176 #else
3177 mEventModel = NPEventModelCocoa;
3178 #endif
3179 #endif
3181 mWaitingForPaint = PR_FALSE;
3183 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
3184 ("nsPluginInstanceOwner %p created\n", this));
3187 nsPluginInstanceOwner::~nsPluginInstanceOwner()
3189 PRInt32 cnt;
3191 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
3192 ("nsPluginInstanceOwner %p deleted\n", this));
3194 if (mWaitingForPaint) {
3195 // We don't care when the event is dispatched as long as it's "soon",
3196 // since whoever needs it will be wwaiting for it
3197 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, PR_TRUE);
3198 NS_DispatchToMainThread(event);
3201 #ifdef MAC_CARBON_PLUGINS
3202 CancelTimer();
3203 #endif
3205 mObjectFrame = nsnull;
3207 for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
3208 if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
3209 NS_Free(mCachedAttrParamNames[cnt]);
3210 mCachedAttrParamNames[cnt] = nsnull;
3213 if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
3214 NS_Free(mCachedAttrParamValues[cnt]);
3215 mCachedAttrParamValues[cnt] = nsnull;
3219 if (mCachedAttrParamNames) {
3220 NS_Free(mCachedAttrParamNames);
3221 mCachedAttrParamNames = nsnull;
3224 if (mCachedAttrParamValues) {
3225 NS_Free(mCachedAttrParamValues);
3226 mCachedAttrParamValues = nsnull;
3229 if (mTagText) {
3230 NS_Free(mTagText);
3231 mTagText = nsnull;
3234 // clean up plugin native window object
3235 nsCOMPtr<nsIPluginHost> ph = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
3236 if (ph) {
3237 ph->DeletePluginNativeWindow(mPluginWindow);
3238 mPluginWindow = nsnull;
3241 if (mInstance) {
3242 mInstance->InvalidateOwner();
3245 #ifdef MOZ_USE_IMAGE_EXPOSE
3246 ReleaseXShm();
3247 #endif
3251 * nsISupports Implementation
3254 NS_IMPL_ADDREF(nsPluginInstanceOwner)
3255 NS_IMPL_RELEASE(nsPluginInstanceOwner)
3257 NS_INTERFACE_MAP_BEGIN(nsPluginInstanceOwner)
3258 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
3259 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner_MOZILLA_2_0_BRANCH)
3260 NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo)
3261 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
3262 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
3263 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
3264 NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
3265 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
3266 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPluginInstanceOwner)
3267 NS_INTERFACE_MAP_END
3269 NS_IMETHODIMP
3270 nsPluginInstanceOwner::SetInstance(nsIPluginInstance *aInstance)
3272 NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!");
3274 // If we're going to null out mInstance after use, be sure to call
3275 // mInstance->InvalidateOwner() here, since it now won't be called
3276 // from our destructor. This fixes bug 613376.
3277 if (mInstance && !aInstance)
3278 mInstance->InvalidateOwner();
3280 mInstance = aInstance;
3282 return NS_OK;
3285 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow)
3287 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
3288 aWindow = mPluginWindow;
3289 return NS_OK;
3292 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(PRInt32 *aMode)
3294 nsCOMPtr<nsIDocument> doc;
3295 nsresult rv = GetDocument(getter_AddRefs(doc));
3296 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
3298 if (pDoc) {
3299 *aMode = NP_FULL;
3300 } else {
3301 *aMode = NP_EMBED;
3304 return rv;
3307 NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n,
3308 const char*const*& names,
3309 const char*const*& values)
3311 nsresult rv = EnsureCachedAttrParamArrays();
3312 NS_ENSURE_SUCCESS(rv, rv);
3314 n = mNumCachedAttrs;
3315 names = (const char **)mCachedAttrParamNames;
3316 values = (const char **)mCachedAttrParamValues;
3318 return rv;
3321 NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
3323 NS_ENSURE_ARG_POINTER(name);
3324 NS_ENSURE_ARG_POINTER(result);
3326 nsresult rv = EnsureCachedAttrParamArrays();
3327 NS_ENSURE_SUCCESS(rv, rv);
3329 *result = nsnull;
3331 for (int i = 0; i < mNumCachedAttrs; i++) {
3332 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
3333 *result = mCachedAttrParamValues[i];
3334 return NS_OK;
3338 return NS_ERROR_FAILURE;
3341 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
3343 return CallQueryInterface(mContent, result);
3346 NS_IMETHODIMP nsPluginInstanceOwner::GetInstance(nsIPluginInstance *&aInstance)
3348 NS_IF_ADDREF(aInstance = mInstance);
3350 return NS_OK;
3353 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
3354 const char *aTarget,
3355 nsIInputStream *aPostStream,
3356 void *aHeadersData,
3357 PRUint32 aHeadersDataLen)
3359 NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
3361 if (mContent->IsEditable()) {
3362 return NS_OK;
3365 // the container of the pres context will give us the link handler
3366 nsCOMPtr<nsISupports> container = mObjectFrame->PresContext()->GetContainer();
3367 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
3368 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
3369 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
3371 nsAutoString unitarget;
3372 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
3374 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
3376 // Create an absolute URL
3377 nsCOMPtr<nsIURI> uri;
3378 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
3380 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
3382 nsCOMPtr<nsIInputStream> headersDataStream;
3383 if (aPostStream && aHeadersData) {
3384 if (!aHeadersDataLen)
3385 return NS_ERROR_UNEXPECTED;
3387 nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
3388 if (!sis)
3389 return NS_ERROR_OUT_OF_MEMORY;
3391 rv = sis->SetData((char *)aHeadersData, aHeadersDataLen);
3392 NS_ENSURE_SUCCESS(rv, rv);
3393 headersDataStream = do_QueryInterface(sis);
3396 PRInt32 blockPopups =
3397 nsContentUtils::GetIntPref("privacy.popups.disable_from_plugins");
3398 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
3400 rv = lh->OnLinkClick(mContent, uri, unitarget.get(),
3401 aPostStream, headersDataStream);
3403 return rv;
3406 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
3408 nsresult rv = NS_ERROR_FAILURE;
3410 rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get());
3412 return rv;
3415 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const PRUnichar *aStatusMsg)
3417 nsresult rv = NS_ERROR_FAILURE;
3419 if (!mObjectFrame) {
3420 return rv;
3422 nsCOMPtr<nsISupports> cont = mObjectFrame->PresContext()->GetContainer();
3423 if (!cont) {
3424 return NS_OK;
3427 nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(cont, &rv));
3428 if (NS_FAILED(rv) || !docShellItem) {
3429 return rv;
3432 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3433 rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
3434 if (NS_FAILED(rv) || !treeOwner) {
3435 return rv;
3438 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
3439 if (NS_FAILED(rv) || !browserChrome) {
3440 return rv;
3442 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3443 aStatusMsg);
3445 return rv;
3448 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
3450 if (!aDocument)
3451 return NS_ERROR_NULL_POINTER;
3453 // XXX sXBL/XBL2 issue: current doc or owner doc?
3454 // But keep in mind bug 322414 comment 33
3455 NS_IF_ADDREF(*aDocument = mContent->GetOwnerDoc());
3456 return NS_OK;
3459 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
3461 if (mWaitingForPaint && IsUpToDate()) {
3462 // We don't care when the event is dispatched as long as it's "soon",
3463 // since whoever needs it will be wwaiting for it
3464 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, PR_TRUE);
3465 NS_DispatchToMainThread(event);
3466 mWaitingForPaint = false;
3469 if (!mObjectFrame || !invalidRect || !mWidgetVisible)
3470 return NS_ERROR_FAILURE;
3472 // Each time an asynchronously-drawing plugin sends a new surface to display,
3473 // InvalidateRect is called. We notify reftests that painting is up to
3474 // date and update our ImageContainer with the new surface.
3475 nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
3476 if (container) {
3477 SetCurrentImage(container);
3480 #ifdef MOZ_USE_IMAGE_EXPOSE
3481 PRBool simpleImageRender = PR_FALSE;
3482 mInstance->GetValueFromPlugin(NPPVpluginWindowlessLocalBool,
3483 &simpleImageRender);
3484 if (simpleImageRender) {
3485 NativeImageDraw(invalidRect);
3486 return NS_OK;
3488 #endif
3490 #ifndef XP_MACOSX
3491 // Windowed plugins should not be calling NPN_InvalidateRect, but
3492 // Silverlight does and expects it to "work"
3493 if (mWidget) {
3494 mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
3495 invalidRect->right - invalidRect->left,
3496 invalidRect->bottom - invalidRect->top),
3497 PR_FALSE);
3498 return NS_OK;
3500 #endif
3502 nsPresContext* presContext = mObjectFrame->PresContext();
3503 nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
3504 presContext->DevPixelsToAppUnits(invalidRect->top),
3505 presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
3506 presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top));
3507 #ifndef XP_MACOSX
3508 mObjectFrame->InvalidateLayer(rect + mObjectFrame->GetUsedBorderAndPadding().TopLeft(), nsDisplayItem::TYPE_PLUGIN);
3509 #else
3510 if (mozilla::FrameLayerBuilder::HasDedicatedLayer(mObjectFrame, nsDisplayItem::TYPE_PLUGIN)) {
3511 mObjectFrame->InvalidateWithFlags(rect + mObjectFrame->GetUsedBorderAndPadding().TopLeft(),
3512 nsIFrame::INVALIDATE_NO_UPDATE_LAYER_TREE);
3513 } else {
3514 mObjectFrame->Invalidate(rect + mObjectFrame->GetUsedBorderAndPadding().TopLeft());
3516 #endif
3517 return NS_OK;
3520 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
3522 return NS_ERROR_NOT_IMPLEMENTED;
3525 NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
3527 NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
3528 nsIView* view = mObjectFrame->GetView();
3529 if (view) {
3530 return view->GetViewManager()->Composite();
3533 return NS_OK;
3536 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
3538 if (!mObjectFrame) {
3539 NS_WARNING("plugin owner has no owner in getting doc's window handle");
3540 return NS_ERROR_FAILURE;
3543 #if defined(XP_WIN) || defined(XP_OS2)
3544 void** pvalue = (void**)value;
3545 nsIViewManager* vm = mObjectFrame->PresContext()->GetPresShell()->GetViewManager();
3546 if (!vm)
3547 return NS_ERROR_FAILURE;
3548 #if defined(XP_WIN)
3549 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
3550 // in, so it can translate mouse coordinates it receives directly from the operating system
3551 // to coordinates relative to itself.
3553 // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
3554 // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc
3556 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
3557 // determines the window handle of the mozilla window containing the "windowless" plugin.
3559 // Given that this HWND may not be that of the document's window, there is a slight risk
3560 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
3561 // does not suggest this HWND IS that of the document window, rather that of the window
3562 // the plugin is drawn in, this seems like a safe fix.
3564 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
3565 // to change any behaviour for the much more common windowed plugins,
3566 // though why this method would even be being called for a windowed plugin escapes me.
3567 if (mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) {
3568 // it turns out that flash also uses this window for determining focus, and is currently
3569 // unable to show a caret correctly if we return the enclosing window. Therefore for
3570 // now we only return the enclosing window when there is an actual offset which
3571 // would otherwise cause coordinates to be offset incorrectly. (i.e.
3572 // if the enclosing window if offset from the document window)
3574 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
3575 // does not seem to be possible without a change to the flash plugin
3577 nsIWidget* win = mObjectFrame->GetNearestWidget();
3578 if (win) {
3579 nsIView *view = nsIView::GetViewFor(win);
3580 NS_ASSERTION(view, "No view for widget");
3581 nsPoint offset = view->GetOffsetTo(nsnull);
3583 if (offset.x || offset.y) {
3584 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
3585 // so that mouse co-ordinates are not messed up.
3586 *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
3587 if (*pvalue)
3588 return NS_OK;
3592 #endif
3593 // simply return the topmost document window
3594 nsCOMPtr<nsIWidget> widget;
3595 nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
3596 if (widget) {
3597 *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
3598 } else {
3599 NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
3602 return rv;
3603 #elif defined(MOZ_WIDGET_GTK2)
3604 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
3605 nsIWidget* win = mObjectFrame->GetNearestWidget();
3606 if (!win)
3607 return NS_ERROR_FAILURE;
3608 GdkWindow* gdkWindow = static_cast<GdkWindow*>(win->GetNativeData(NS_NATIVE_WINDOW));
3609 if (!gdkWindow)
3610 return NS_ERROR_FAILURE;
3611 gdkWindow = gdk_window_get_toplevel(gdkWindow);
3612 #ifdef MOZ_X11
3613 *static_cast<Window*>(value) = GDK_WINDOW_XID(gdkWindow);
3614 #endif
3615 return NS_OK;
3616 #elif defined(MOZ_WIDGET_QT)
3617 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
3618 nsIWidget* win = mObjectFrame->GetNearestWidget();
3619 if (!win)
3620 return NS_ERROR_FAILURE;
3621 QWidget* widget = static_cast<QWidget*>(win->GetNativeData(NS_NATIVE_WINDOW));
3622 if (!widget)
3623 return NS_ERROR_FAILURE;
3624 #ifdef MOZ_X11
3625 *static_cast<Window*>(value) = widget->handle();
3626 return NS_OK;
3627 #endif
3628 return NS_ERROR_FAILURE;
3629 #else
3630 return NS_ERROR_NOT_IMPLEMENTED;
3631 #endif
3634 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(PRInt32 eventModel)
3636 #ifdef XP_MACOSX
3637 mEventModel = static_cast<NPEventModel>(eventModel);
3638 return NS_OK;
3639 #else
3640 return NS_ERROR_NOT_IMPLEMENTED;
3641 #endif
3644 NS_IMETHODIMP nsPluginInstanceOwner::SetWindow()
3646 NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
3647 return mObjectFrame->CallSetWindow(PR_FALSE);
3650 NPError nsPluginInstanceOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
3652 if (!menu || !event)
3653 return NPERR_GENERIC_ERROR;
3655 #ifdef XP_MACOSX
3656 if (GetEventModel() != NPEventModelCocoa)
3657 return NPERR_INCOMPATIBLE_VERSION_ERROR;
3659 return NS_NPAPI_ShowCocoaContextMenu(static_cast<void*>(menu), mWidget,
3660 static_cast<NPCocoaEvent*>(event));
3661 #else
3662 return NPERR_INCOMPATIBLE_VERSION_ERROR;
3663 #endif
3666 NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
3667 double *destX, double *destY, NPCoordinateSpace destSpace)
3669 #ifdef XP_MACOSX
3670 if (!mWidget)
3671 return PR_FALSE;
3673 return NS_NPAPI_ConvertPointCocoa(mWidget->GetNativeData(NS_NATIVE_WIDGET),
3674 sourceX, sourceY, sourceSpace, destX, destY, destSpace);
3675 #else
3676 // we should implement this for all platforms
3677 return PR_FALSE;
3678 #endif
3681 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
3683 NS_ENSURE_ARG_POINTER(result);
3685 *result = nsPluginTagType_Unknown;
3687 nsIAtom *atom = mContent->Tag();
3689 if (atom == nsGkAtoms::applet)
3690 *result = nsPluginTagType_Applet;
3691 else if (atom == nsGkAtoms::embed)
3692 *result = nsPluginTagType_Embed;
3693 else if (atom == nsGkAtoms::object)
3694 *result = nsPluginTagType_Object;
3696 return NS_OK;
3699 NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result)
3701 NS_ENSURE_ARG_POINTER(result);
3702 if (nsnull == mTagText) {
3703 nsresult rv;
3704 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent, &rv));
3705 if (NS_FAILED(rv))
3706 return rv;
3708 nsCOMPtr<nsIDocument> document;
3709 rv = GetDocument(getter_AddRefs(document));
3710 if (NS_FAILED(rv))
3711 return rv;
3713 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
3714 NS_ASSERTION(domDoc, "Need a document");
3716 nsCOMPtr<nsIDocumentEncoder> docEncoder(do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html", &rv));
3717 if (NS_FAILED(rv))
3718 return rv;
3719 rv = docEncoder->Init(domDoc, NS_LITERAL_STRING("text/html"), nsIDocumentEncoder::OutputEncodeBasicEntities);
3720 if (NS_FAILED(rv))
3721 return rv;
3723 nsCOMPtr<nsIDOMRange> range(do_CreateInstance(kRangeCID,&rv));
3724 if (NS_FAILED(rv))
3725 return rv;
3727 rv = range->SelectNode(node);
3728 if (NS_FAILED(rv))
3729 return rv;
3731 docEncoder->SetRange(range);
3732 nsString elementHTML;
3733 rv = docEncoder->EncodeToString(elementHTML);
3734 if (NS_FAILED(rv))
3735 return rv;
3737 mTagText = ToNewUTF8String(elementHTML);
3738 if (!mTagText)
3739 return NS_ERROR_OUT_OF_MEMORY;
3741 *result = mTagText;
3742 return NS_OK;
3745 NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values)
3747 nsresult rv = EnsureCachedAttrParamArrays();
3748 NS_ENSURE_SUCCESS(rv, rv);
3750 n = mNumCachedParams;
3751 if (n) {
3752 names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
3753 values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
3754 } else
3755 names = values = nsnull;
3757 return rv;
3760 NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
3762 NS_ENSURE_ARG_POINTER(name);
3763 NS_ENSURE_ARG_POINTER(result);
3765 nsresult rv = EnsureCachedAttrParamArrays();
3766 NS_ENSURE_SUCCESS(rv, rv);
3768 *result = nsnull;
3770 for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
3771 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
3772 *result = mCachedAttrParamValues[i];
3773 return NS_OK;
3777 return NS_ERROR_FAILURE;
3780 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result)
3782 NS_ENSURE_ARG_POINTER(result);
3783 nsresult rv = NS_OK;
3784 if (mDocumentBase.IsEmpty()) {
3785 if (!mObjectFrame) {
3786 *result = nsnull;
3787 return NS_ERROR_FAILURE;
3790 nsIDocument* doc = mContent->GetOwnerDoc();
3791 NS_ASSERTION(doc, "Must have an owner doc");
3792 rv = doc->GetDocBaseURI()->GetSpec(mDocumentBase);
3794 if (NS_SUCCEEDED(rv))
3795 *result = ToNewCString(mDocumentBase);
3796 return rv;
3799 static nsDataHashtable<nsDepCharHashKey, const char *> * gCharsetMap;
3800 typedef struct {
3801 char mozName[16];
3802 char javaName[12];
3803 } moz2javaCharset;
3805 /* XXX If you add any strings longer than
3806 * {"x-mac-cyrillic", "MacCyrillic"},
3807 * {"x-mac-ukrainian", "MacUkraine"},
3808 * to the following array then you MUST update the
3809 * sizes of the arrays in the moz2javaCharset struct
3812 static const moz2javaCharset charsets[] =
3814 {"windows-1252", "Cp1252"},
3815 {"IBM850", "Cp850"},
3816 {"IBM852", "Cp852"},
3817 {"IBM855", "Cp855"},
3818 {"IBM857", "Cp857"},
3819 {"IBM828", "Cp862"},
3820 {"IBM864", "Cp864"},
3821 {"IBM866", "Cp866"},
3822 {"windows-1250", "Cp1250"},
3823 {"windows-1251", "Cp1251"},
3824 {"windows-1253", "Cp1253"},
3825 {"windows-1254", "Cp1254"},
3826 {"windows-1255", "Cp1255"},
3827 {"windows-1256", "Cp1256"},
3828 {"windows-1257", "Cp1257"},
3829 {"windows-1258", "Cp1258"},
3830 {"EUC-JP", "EUC_JP"},
3831 {"EUC-KR", "EUC_KR"},
3832 {"x-euc-tw", "EUC_TW"},
3833 {"gb18030", "GB18030"},
3834 {"x-gbk", "GBK"},
3835 {"ISO-2022-JP", "ISO2022JP"},
3836 {"ISO-2022-KR", "ISO2022KR"},
3837 {"ISO-8859-2", "ISO8859_2"},
3838 {"ISO-8859-3", "ISO8859_3"},
3839 {"ISO-8859-4", "ISO8859_4"},
3840 {"ISO-8859-5", "ISO8859_5"},
3841 {"ISO-8859-6", "ISO8859_6"},
3842 {"ISO-8859-7", "ISO8859_7"},
3843 {"ISO-8859-8", "ISO8859_8"},
3844 {"ISO-8859-9", "ISO8859_9"},
3845 {"ISO-8859-13", "ISO8859_13"},
3846 {"x-johab", "Johab"},
3847 {"KOI8-R", "KOI8_R"},
3848 {"TIS-620", "MS874"},
3849 {"windows-936", "MS936"},
3850 {"x-windows-949", "MS949"},
3851 {"x-mac-arabic", "MacArabic"},
3852 {"x-mac-croatian", "MacCroatia"},
3853 {"x-mac-cyrillic", "MacCyrillic"},
3854 {"x-mac-greek", "MacGreek"},
3855 {"x-mac-hebrew", "MacHebrew"},
3856 {"x-mac-icelandic", "MacIceland"},
3857 {"x-mac-roman", "MacRoman"},
3858 {"x-mac-romanian", "MacRomania"},
3859 {"x-mac-ukrainian", "MacUkraine"},
3860 {"Shift_JIS", "SJIS"},
3861 {"TIS-620", "TIS620"}
3864 NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentEncoding(const char* *result)
3866 NS_ENSURE_ARG_POINTER(result);
3867 *result = nsnull;
3869 nsresult rv;
3870 // XXX sXBL/XBL2 issue: current doc or owner doc?
3871 nsCOMPtr<nsIDocument> doc;
3872 rv = GetDocument(getter_AddRefs(doc));
3873 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get document");
3874 if (NS_FAILED(rv))
3875 return rv;
3877 const nsCString &charset = doc->GetDocumentCharacterSet();
3879 if (charset.IsEmpty())
3880 return NS_OK;
3882 // common charsets and those not requiring conversion first
3883 if (charset.EqualsLiteral("us-ascii")) {
3884 *result = PL_strdup("US_ASCII");
3885 } else if (charset.EqualsLiteral("ISO-8859-1") ||
3886 !nsCRT::strncmp(PromiseFlatCString(charset).get(), "UTF", 3)) {
3887 *result = ToNewCString(charset);
3888 } else {
3889 if (!gCharsetMap) {
3890 const int NUM_CHARSETS = sizeof(charsets) / sizeof(moz2javaCharset);
3891 gCharsetMap = new nsDataHashtable<nsDepCharHashKey, const char*>();
3892 if (!gCharsetMap || !gCharsetMap->Init(NUM_CHARSETS))
3893 return NS_ERROR_OUT_OF_MEMORY;
3895 for (PRUint16 i = 0; i < NUM_CHARSETS; i++) {
3896 gCharsetMap->Put(charsets[i].mozName, charsets[i].javaName);
3899 // if found mapping, return it; otherwise return original charset
3900 const char *mapping;
3901 *result = gCharsetMap->Get(charset.get(), &mapping) ? PL_strdup(mapping) :
3902 ToNewCString(charset);
3905 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
3908 NS_IMETHODIMP nsPluginInstanceOwner::GetAlignment(const char* *result)
3910 return GetAttribute("ALIGN", result);
3913 NS_IMETHODIMP nsPluginInstanceOwner::GetWidth(PRUint32 *result)
3915 NS_ENSURE_ARG_POINTER(result);
3917 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
3919 *result = mPluginWindow->width;
3921 return NS_OK;
3924 NS_IMETHODIMP nsPluginInstanceOwner::GetHeight(PRUint32 *result)
3926 NS_ENSURE_ARG_POINTER(result);
3928 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
3930 *result = mPluginWindow->height;
3932 return NS_OK;
3936 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderVertSpace(PRUint32 *result)
3938 nsresult rv;
3939 const char *vspace;
3941 rv = GetAttribute("VSPACE", &vspace);
3943 if (NS_OK == rv) {
3944 if (*result != 0)
3945 *result = (PRUint32)atol(vspace);
3946 else
3947 *result = 0;
3949 else
3950 *result = 0;
3952 return rv;
3955 NS_IMETHODIMP nsPluginInstanceOwner::GetBorderHorizSpace(PRUint32 *result)
3957 nsresult rv;
3958 const char *hspace;
3960 rv = GetAttribute("HSPACE", &hspace);
3962 if (NS_OK == rv) {
3963 if (*result != 0)
3964 *result = (PRUint32)atol(hspace);
3965 else
3966 *result = 0;
3968 else
3969 *result = 0;
3971 return rv;
3974 NS_IMETHODIMP nsPluginInstanceOwner::GetUniqueID(PRUint32 *result)
3976 NS_ENSURE_ARG_POINTER(result);
3977 *result = NS_PTR_TO_INT32(mObjectFrame);
3978 return NS_OK;
3981 // Cache the attributes and/or parameters of our tag into a single set
3982 // of arrays to be compatible with Netscape 4.x. The attributes go first,
3983 // followed by a PARAM/null and then any PARAM tags. Also, hold the
3984 // cached array around for the duration of the life of the instance
3985 // because Netscape 4.x did. See bug 111008.
3986 nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
3988 if (mCachedAttrParamValues)
3989 return NS_OK;
3991 NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
3992 !mCachedAttrParamNames,
3993 "re-cache of attrs/params not implemented! use the DOM "
3994 "node directy instead");
3995 NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
3997 // Convert to a 16-bit count. Subtract 2 in case we add an extra
3998 // "src" or "wmode" entry below.
3999 PRUint32 cattrs = mContent->GetAttrCount();
4000 if (cattrs < 0x0000FFFD) {
4001 mNumCachedAttrs = static_cast<PRUint16>(cattrs);
4002 } else {
4003 mNumCachedAttrs = 0xFFFD;
4006 // now, we need to find all the PARAM tags that are children of us
4007 // however, be careful not to include any PARAMs that don't have us
4008 // as a direct parent. For nested object (or applet) tags, be sure
4009 // to only round up the param tags that coorespond with THIS
4010 // instance. And also, weed out any bogus tags that may get in the
4011 // way, see bug 39609. Then, with any param tag that meet our
4012 // qualification, temporarly cache them in an nsCOMArray until
4013 // we can figure out what size to make our fixed char* array.
4014 nsCOMArray<nsIDOMElement> ourParams;
4016 // Get all dependent PARAM tags, even if they are not direct children.
4017 nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
4018 NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
4020 // Making DOM method calls can cause our frame to go away.
4021 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
4023 nsCOMPtr<nsIDOMNodeList> allParams;
4024 NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
4025 mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
4026 getter_AddRefs(allParams));
4027 if (allParams) {
4028 PRUint32 numAllParams;
4029 allParams->GetLength(&numAllParams);
4030 for (PRUint32 i = 0; i < numAllParams; i++) {
4031 nsCOMPtr<nsIDOMNode> pnode;
4032 allParams->Item(i, getter_AddRefs(pnode));
4033 nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
4034 if (domelement) {
4035 // Ignore params without a name attribute.
4036 nsAutoString name;
4037 domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
4038 if (!name.IsEmpty()) {
4039 // Find the first object or applet parent.
4040 nsCOMPtr<nsIDOMNode> parent;
4041 nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
4042 nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
4043 pnode->GetParentNode(getter_AddRefs(parent));
4044 while (!(domobject || domapplet) && parent) {
4045 domobject = do_QueryInterface(parent);
4046 domapplet = do_QueryInterface(parent);
4047 nsCOMPtr<nsIDOMNode> temp;
4048 parent->GetParentNode(getter_AddRefs(temp));
4049 parent = temp;
4051 if (domapplet || domobject) {
4052 if (domapplet) {
4053 parent = domapplet;
4055 else {
4056 parent = domobject;
4058 nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
4059 if (parent == mydomNode) {
4060 ourParams.AppendObject(domelement);
4068 // We're done with DOM method calls now. Make sure we still have a frame.
4069 NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_OUT_OF_MEMORY);
4071 // Convert to a 16-bit count.
4072 PRUint32 cparams = ourParams.Count();
4073 if (cparams < 0x0000FFFF) {
4074 mNumCachedParams = static_cast<PRUint16>(cparams);
4075 } else {
4076 mNumCachedParams = 0xFFFF;
4079 PRUint16 numRealAttrs = mNumCachedAttrs;
4081 // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
4082 // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
4083 // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
4084 // look for "data", lets instead copy the "data" attribute and add another entry
4085 // to the bottom of the array if there isn't already a "src" specified.
4086 nsAutoString data;
4087 if (mContent->Tag() == nsGkAtoms::object &&
4088 !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
4089 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data) &&
4090 !data.IsEmpty()) {
4091 mNumCachedAttrs++;
4094 // "plugins.force.wmode" preference is forcing wmode type for plugins
4095 // possible values - "opaque", "transparent", "windowed"
4096 nsAdoptingCString wmodeType = nsContentUtils::GetCharPref("plugins.force.wmode");
4097 if (!wmodeType.IsEmpty()) {
4098 mNumCachedAttrs++;
4101 mCachedAttrParamNames = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
4102 NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
4103 mCachedAttrParamValues = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
4104 NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
4106 // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
4107 // attribute order. So we want to make sure we give the plugin the
4108 // attributes in the order they came in in the source, to be compatible with
4109 // other browsers. Now in HTML, the storage order is the reverse of the
4110 // source order, while in XML and XHTML it's the same as the source order
4111 // (see the AddAttributes functions in the HTML and XML content sinks).
4112 PRInt32 start, end, increment;
4113 if (mContent->IsHTML() &&
4114 mContent->IsInHTMLDocument()) {
4115 // HTML. Walk attributes in reverse order.
4116 start = numRealAttrs - 1;
4117 end = -1;
4118 increment = -1;
4119 } else {
4120 // XHTML or XML. Walk attributes in forward order.
4121 start = 0;
4122 end = numRealAttrs;
4123 increment = 1;
4126 // Set to the next slot to fill in name and value cache arrays.
4127 PRUint32 nextAttrParamIndex = 0;
4129 // Potentially add WMODE attribute.
4130 if (!wmodeType.IsEmpty()) {
4131 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
4132 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
4133 nextAttrParamIndex++;
4136 // Add attribute name/value pairs.
4137 for (PRInt32 index = start; index != end; index += increment) {
4138 const nsAttrName* attrName = mContent->GetAttrNameAt(index);
4139 nsIAtom* atom = attrName->LocalName();
4140 nsAutoString value;
4141 mContent->GetAttr(attrName->NamespaceID(), atom, value);
4142 nsAutoString name;
4143 atom->ToString(name);
4145 FixUpURLS(name, value);
4147 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
4148 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
4149 nextAttrParamIndex++;
4152 // Potentially add SRC attribute.
4153 if (!data.IsEmpty()) {
4154 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
4155 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data);
4156 nextAttrParamIndex++;
4159 // Add PARAM and null separator.
4160 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
4161 mCachedAttrParamValues[nextAttrParamIndex] = nsnull;
4162 nextAttrParamIndex++;
4164 // Add PARAM name/value pairs.
4165 for (PRUint16 i = 0; i < mNumCachedParams; i++) {
4166 nsIDOMElement* param = ourParams.ObjectAt(i);
4167 if (!param) {
4168 continue;
4171 nsAutoString name;
4172 nsAutoString value;
4173 param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
4174 param->GetAttribute(NS_LITERAL_STRING("value"), value);
4176 FixUpURLS(name, value);
4179 * According to the HTML 4.01 spec, at
4180 * http://www.w3.org/TR/html4/types.html#type-cdata
4181 * ''User agents may ignore leading and trailing
4182 * white space in CDATA attribute values (e.g., "
4183 * myval " may be interpreted as "myval"). Authors
4184 * should not declare attribute values with
4185 * leading or trailing white space.''
4186 * However, do not trim consecutive spaces as in bug 122119
4188 name.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
4189 value.Trim(" \n\r\t\b", PR_TRUE, PR_TRUE, PR_FALSE);
4190 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
4191 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
4192 nextAttrParamIndex++;
4195 return NS_OK;
4199 // Here's where we forward events to plugins.
4201 #ifdef XP_MACOSX
4203 #ifndef NP_NO_CARBON
4204 static void InitializeEventRecord(EventRecord* event, Point* aMousePosition)
4206 memset(event, 0, sizeof(EventRecord));
4207 if (aMousePosition) {
4208 event->where = *aMousePosition;
4209 } else {
4210 ::GetGlobalMouse(&event->where);
4212 event->when = ::TickCount();
4213 event->modifiers = ::GetCurrentKeyModifiers();
4215 #endif
4217 static void InitializeNPCocoaEvent(NPCocoaEvent* event)
4219 memset(event, 0, sizeof(NPCocoaEvent));
4222 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
4224 #ifndef NP_NO_QUICKDRAW
4225 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
4226 #else
4227 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
4228 #endif
4230 if (!mInstance)
4231 return drawingModel;
4233 mInstance->GetDrawingModel((PRInt32*)&drawingModel);
4234 return drawingModel;
4237 PRBool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
4239 nsCOMPtr<nsIPluginInstance_MOZILLA_2_0_BRANCH> inst = do_QueryInterface(mInstance);
4240 if (!inst)
4241 return PR_FALSE;
4243 PRBool coreAnimation;
4244 if (!NS_SUCCEEDED(inst->IsRemoteDrawingCoreAnimation(&coreAnimation)))
4245 return PR_FALSE;
4247 return coreAnimation;
4250 NPEventModel nsPluginInstanceOwner::GetEventModel()
4252 return mEventModel;
4255 #define DEFAULT_REFRESH_RATE 20 // 50 FPS
4257 nsCOMPtr<nsITimer> *nsPluginInstanceOwner::sCATimer = NULL;
4258 nsTArray<nsPluginInstanceOwner*> *nsPluginInstanceOwner::sCARefreshListeners = NULL;
4260 void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) {
4261 if (!sCARefreshListeners) {
4262 return;
4264 for (size_t i = 0; i < sCARefreshListeners->Length(); i++) {
4265 nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i];
4266 NPWindow *window;
4267 instanceOwner->GetWindow(window);
4268 if (!window) {
4269 continue;
4271 NPRect r;
4272 r.left = 0;
4273 r.top = 0;
4274 r.right = window->width;
4275 r.bottom = window->height;
4276 instanceOwner->InvalidateRect(&r);
4280 void nsPluginInstanceOwner::AddToCARefreshTimer(nsPluginInstanceOwner *aPluginInstance) {
4281 if (!sCARefreshListeners) {
4282 sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
4283 if (!sCARefreshListeners) {
4284 return;
4288 NS_ASSERTION(!sCARefreshListeners->Contains(aPluginInstance),
4289 "pluginInstanceOwner already registered as a listener");
4290 sCARefreshListeners->AppendElement(aPluginInstance);
4292 if (!sCATimer) {
4293 sCATimer = new nsCOMPtr<nsITimer>();
4294 if (!sCATimer) {
4295 return;
4299 if (sCARefreshListeners->Length() == 1) {
4300 *sCATimer = do_CreateInstance("@mozilla.org/timer;1");
4301 (*sCATimer)->InitWithFuncCallback(CARefresh, NULL,
4302 DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK);
4306 void nsPluginInstanceOwner::RemoveFromCARefreshTimer(nsPluginInstanceOwner *aPluginInstance) {
4307 if (!sCARefreshListeners || sCARefreshListeners->Contains(aPluginInstance) == false) {
4308 return;
4311 sCARefreshListeners->RemoveElement(aPluginInstance);
4313 if (sCARefreshListeners->Length() == 0) {
4314 if (sCATimer) {
4315 (*sCATimer)->Cancel();
4316 delete sCATimer;
4317 sCATimer = NULL;
4319 delete sCARefreshListeners;
4320 sCARefreshListeners = NULL;
4324 void nsPluginInstanceOwner::SetupCARefresh()
4326 const char* pluginType = GetMIMEType(mInstance);
4327 if (strcmp(pluginType, "application/x-shockwave-flash") != 0) {
4328 // We don't need a timer since Flash is invoking InvalidateRect for us.
4329 AddToCARefreshTimer(this);
4333 void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
4334 int aWidth, int aHeight)
4336 if (aWidth == 0 || aHeight == 0)
4337 return;
4339 if (!mIOSurface ||
4340 (mIOSurface->GetWidth() != (size_t)aWidth ||
4341 mIOSurface->GetHeight() != (size_t)aHeight)) {
4342 if (mIOSurface) {
4343 delete mIOSurface;
4346 // If the renderer is backed by an IOSurface, resize it as required.
4347 mIOSurface = nsIOSurface::CreateIOSurface(aWidth, aHeight);
4348 if (mIOSurface) {
4349 nsIOSurface *attachSurface = nsIOSurface::LookupSurface(
4350 mIOSurface->GetIOSurfaceID());
4351 if (attachSurface) {
4352 mCARenderer.AttachIOSurface(attachSurface);
4353 } else {
4354 NS_ERROR("IOSurface attachment failed");
4355 delete attachSurface;
4356 delete mIOSurface;
4357 mIOSurface = NULL;
4362 if (mCARenderer.isInit() == false) {
4363 void *caLayer = NULL;
4364 mInstance->GetValueFromPlugin(NPPVpluginCoreAnimationLayer, &caLayer);
4365 if (!caLayer) {
4366 return;
4369 mCARenderer.SetupRenderer(caLayer, aWidth, aHeight);
4371 // Setting up the CALayer requires resetting the painting otherwise we
4372 // get garbage for the first few frames.
4373 FixUpPluginWindow(ePluginPaintDisable);
4374 FixUpPluginWindow(ePluginPaintEnable);
4377 CGImageRef caImage = NULL;
4378 nsresult rt = mCARenderer.Render(aWidth, aHeight, &caImage);
4379 if (rt == NS_OK && mIOSurface) {
4380 nsCARenderer::DrawSurfaceToCGContext(aCGContext, mIOSurface, CreateSystemColorSpace(),
4381 0, 0, aWidth, aHeight);
4382 } else if (rt == NS_OK && caImage != NULL) {
4383 // Significant speed up by resetting the scaling
4384 ::CGContextSetInterpolationQuality(aCGContext, kCGInterpolationNone );
4385 ::CGContextTranslateCTM(aCGContext, 0, aHeight);
4386 ::CGContextScaleCTM(aCGContext, 1.0, -1.0);
4388 ::CGContextDrawImage(aCGContext, CGRectMake(0,0,aWidth,aHeight), caImage);
4389 } else {
4390 NS_NOTREACHED("nsCARenderer::Render failure");
4394 void* nsPluginInstanceOwner::GetPluginPortCopy()
4396 #ifndef NP_NO_QUICKDRAW
4397 if (GetDrawingModel() == NPDrawingModelQuickDraw)
4398 return &mQDPluginPortCopy;
4399 #endif
4400 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
4401 GetDrawingModel() == NPDrawingModelCoreAnimation ||
4402 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
4403 return &mCGPluginPortCopy;
4404 return nsnull;
4407 // Currently (on OS X in Cocoa widgets) any changes made as a result of
4408 // calling GetPluginPortFromWidget() are immediately reflected in the NPWindow
4409 // structure that has been passed to the plugin via SetWindow(). This is
4410 // because calls to nsChildView::GetNativeData(NS_NATIVE_PLUGIN_PORT_CG)
4411 // always return a pointer to the same internal (private) object, but may
4412 // make changes inside that object. All calls to GetPluginPortFromWidget() made while
4413 // the plugin is active (i.e. excluding those made at our initialization)
4414 // need to take this into account. The easiest way to do so is to replace
4415 // them with calls to SetPluginPortAndDetectChange(). This method keeps track
4416 // of when calls to GetPluginPortFromWidget() result in changes, and sets a flag to make
4417 // sure SetWindow() gets called the next time through FixUpPluginWindow(), so
4418 // that the plugin is notified of these changes.
4419 void* nsPluginInstanceOwner::SetPluginPortAndDetectChange()
4421 if (!mPluginWindow)
4422 return nsnull;
4423 void* pluginPort = GetPluginPortFromWidget();
4424 if (!pluginPort)
4425 return nsnull;
4426 mPluginWindow->window = pluginPort;
4428 #ifndef NP_NO_QUICKDRAW
4429 NPDrawingModel drawingModel = GetDrawingModel();
4430 if (drawingModel == NPDrawingModelQuickDraw) {
4431 NP_Port* windowQDPort = static_cast<NP_Port*>(mPluginWindow->window);
4432 if (windowQDPort->port != mQDPluginPortCopy.port) {
4433 mQDPluginPortCopy.port = windowQDPort->port;
4434 mPluginPortChanged = PR_TRUE;
4436 } else if (drawingModel == NPDrawingModelCoreGraphics ||
4437 drawingModel == NPDrawingModelCoreAnimation ||
4438 drawingModel == NPDrawingModelInvalidatingCoreAnimation)
4439 #endif
4441 #ifndef NP_NO_CARBON
4442 if (GetEventModel() == NPEventModelCarbon) {
4443 NP_CGContext* windowCGPort = static_cast<NP_CGContext*>(mPluginWindow->window);
4444 if ((windowCGPort->context != mCGPluginPortCopy.context) ||
4445 (windowCGPort->window != mCGPluginPortCopy.window)) {
4446 mCGPluginPortCopy.context = windowCGPort->context;
4447 mCGPluginPortCopy.window = windowCGPort->window;
4448 mPluginPortChanged = PR_TRUE;
4451 #endif
4454 return mPluginWindow->window;
4457 void nsPluginInstanceOwner::BeginCGPaint()
4459 ++mInCGPaintLevel;
4462 void nsPluginInstanceOwner::EndCGPaint()
4464 --mInCGPaintLevel;
4465 NS_ASSERTION(mInCGPaintLevel >= 0, "Mismatched call to nsPluginInstanceOwner::EndCGPaint()!");
4468 #endif
4470 // static
4471 PRUint32
4472 nsPluginInstanceOwner::GetEventloopNestingLevel()
4474 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
4475 PRUint32 currentLevel = 0;
4476 if (appShell) {
4477 appShell->GetEventloopNestingLevel(&currentLevel);
4478 #ifdef XP_MACOSX
4479 // Cocoa widget code doesn't process UI events through the normal
4480 // appshell event loop, so it needs an additional count here.
4481 currentLevel++;
4482 #endif
4485 // No idea how this happens... but Linux doesn't consistently
4486 // process UI events through the appshell event loop. If we get a 0
4487 // here on any platform we increment the level just in case so that
4488 // we make sure we always tear the plugin down eventually.
4489 if (!currentLevel) {
4490 currentLevel++;
4493 return currentLevel;
4496 void nsPluginInstanceOwner::ScrollPositionWillChange(nscoord aX, nscoord aY)
4498 #ifdef MAC_CARBON_PLUGINS
4499 if (GetEventModel() != NPEventModelCarbon)
4500 return;
4502 CancelTimer();
4504 if (mInstance) {
4505 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
4506 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
4507 EventRecord scrollEvent;
4508 InitializeEventRecord(&scrollEvent, nsnull);
4509 scrollEvent.what = NPEventType_ScrollingBeginsEvent;
4511 void* window = FixUpPluginWindow(ePluginPaintDisable);
4512 if (window) {
4513 mInstance->HandleEvent(&scrollEvent, nsnull);
4515 pluginWidget->EndDrawPlugin();
4518 #endif
4521 void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY)
4523 #ifdef MAC_CARBON_PLUGINS
4524 if (GetEventModel() != NPEventModelCarbon)
4525 return;
4527 if (mInstance) {
4528 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
4529 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
4530 EventRecord scrollEvent;
4531 InitializeEventRecord(&scrollEvent, nsnull);
4532 scrollEvent.what = NPEventType_ScrollingEndsEvent;
4534 void* window = FixUpPluginWindow(ePluginPaintEnable);
4535 if (window) {
4536 mInstance->HandleEvent(&scrollEvent, nsnull);
4538 pluginWidget->EndDrawPlugin();
4541 #endif
4544 /*=============== nsIDOMFocusListener ======================*/
4545 nsresult nsPluginInstanceOwner::Focus(nsIDOMEvent * aFocusEvent)
4547 mContentFocused = PR_TRUE;
4548 return DispatchFocusToPlugin(aFocusEvent);
4551 nsresult nsPluginInstanceOwner::Blur(nsIDOMEvent * aFocusEvent)
4553 mContentFocused = PR_FALSE;
4554 return DispatchFocusToPlugin(aFocusEvent);
4557 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
4559 #ifndef XP_MACOSX
4560 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
4561 // continue only for cases without child window
4562 return aFocusEvent->PreventDefault(); // consume event
4564 #endif
4566 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aFocusEvent));
4567 if (privateEvent) {
4568 nsEvent * theEvent = privateEvent->GetInternalNSEvent();
4569 if (theEvent) {
4570 // we only care about the message in ProcessEvent
4571 nsGUIEvent focusEvent(NS_IS_TRUSTED_EVENT(theEvent), theEvent->message,
4572 nsnull);
4573 nsEventStatus rv = ProcessEvent(focusEvent);
4574 if (nsEventStatus_eConsumeNoDefault == rv) {
4575 aFocusEvent->PreventDefault();
4576 aFocusEvent->StopPropagation();
4579 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, focusEvent null");
4581 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, privateEvent null");
4583 return NS_OK;
4587 /*=============== nsIKeyListener ======================*/
4588 nsresult nsPluginInstanceOwner::KeyDown(nsIDOMEvent* aKeyEvent)
4590 return DispatchKeyToPlugin(aKeyEvent);
4593 nsresult nsPluginInstanceOwner::KeyUp(nsIDOMEvent* aKeyEvent)
4595 return DispatchKeyToPlugin(aKeyEvent);
4598 nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent)
4600 #ifdef XP_MACOSX
4601 #ifndef NP_NO_CARBON
4602 if (GetEventModel() == NPEventModelCarbon) {
4603 // KeyPress events are really synthesized keyDown events.
4604 // Here we check the native message of the event so that
4605 // we won't send the plugin two keyDown events.
4606 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
4607 if (privateEvent) {
4608 nsEvent *theEvent = privateEvent->GetInternalNSEvent();
4609 const nsGUIEvent *guiEvent = (nsGUIEvent*)theEvent;
4610 const EventRecord *ev = (EventRecord*)(guiEvent->pluginEvent);
4611 if (guiEvent &&
4612 guiEvent->message == NS_KEY_PRESS &&
4613 ev &&
4614 ev->what == keyDown)
4615 return aKeyEvent->PreventDefault(); // consume event
4618 // Nasty hack to avoid recursive event dispatching with Java. Java can
4619 // dispatch key events to a TSM handler, which comes back and calls
4620 // [ChildView insertText:] on the cocoa widget, which sends a key
4621 // event back down.
4622 static PRBool sInKeyDispatch = PR_FALSE;
4624 if (sInKeyDispatch)
4625 return aKeyEvent->PreventDefault(); // consume event
4627 sInKeyDispatch = PR_TRUE;
4628 nsresult rv = DispatchKeyToPlugin(aKeyEvent);
4629 sInKeyDispatch = PR_FALSE;
4630 return rv;
4632 #endif
4634 return DispatchKeyToPlugin(aKeyEvent);
4635 #else
4636 if (SendNativeEvents())
4637 DispatchKeyToPlugin(aKeyEvent);
4639 if (mInstance) {
4640 // If this event is going to the plugin, we want to kill it.
4641 // Not actually sending keypress to the plugin, since we didn't before.
4642 aKeyEvent->PreventDefault();
4643 aKeyEvent->StopPropagation();
4645 return NS_OK;
4646 #endif
4649 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
4651 #if !defined(XP_MACOSX) && !defined(MOZ_COMPOSITED_PLUGINS)
4652 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
4653 return aKeyEvent->PreventDefault(); // consume event
4654 // continue only for cases without child window
4655 #endif
4657 if (mInstance) {
4658 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
4659 if (privateEvent) {
4660 nsKeyEvent *keyEvent = (nsKeyEvent *) privateEvent->GetInternalNSEvent();
4661 if (keyEvent) {
4662 nsEventStatus rv = ProcessEvent(*keyEvent);
4663 if (nsEventStatus_eConsumeNoDefault == rv) {
4664 aKeyEvent->PreventDefault();
4665 aKeyEvent->StopPropagation();
4668 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, keyEvent null");
4670 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, privateEvent null");
4673 return NS_OK;
4676 /*=============== nsIDOMMouseMotionListener ======================*/
4678 nsresult
4679 nsPluginInstanceOwner::MouseMove(nsIDOMEvent* aMouseEvent)
4681 #if !defined(XP_MACOSX)
4682 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
4683 return aMouseEvent->PreventDefault(); // consume event
4684 // continue only for cases without child window
4685 #endif
4687 // don't send mouse events if we are hidden
4688 if (!mWidgetVisible)
4689 return NS_OK;
4691 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
4692 if (privateEvent) {
4693 nsMouseEvent* mouseEvent = (nsMouseEvent *) privateEvent->GetInternalNSEvent();
4694 if (mouseEvent) {
4695 nsEventStatus rv = ProcessEvent(*mouseEvent);
4696 if (nsEventStatus_eConsumeNoDefault == rv) {
4697 return aMouseEvent->PreventDefault(); // consume event
4700 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, mouseEvent null");
4702 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, privateEvent null");
4704 return NS_OK;
4707 /*=============== nsIDOMMouseListener ======================*/
4709 nsresult
4710 nsPluginInstanceOwner::MouseDown(nsIDOMEvent* aMouseEvent)
4712 #if !defined(XP_MACOSX) && !defined(MOZ_COMPOSITED_PLUGINS)
4713 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
4714 return aMouseEvent->PreventDefault(); // consume event
4715 // continue only for cases without child window
4716 #endif
4718 // if the plugin is windowless, we need to set focus ourselves
4719 // otherwise, we might not get key events
4720 if (mObjectFrame && mPluginWindow &&
4721 mPluginWindow->type == NPWindowTypeDrawable) {
4723 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4724 if (fm) {
4725 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
4726 fm->SetFocus(elem, 0);
4730 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
4731 if (privateEvent) {
4732 nsMouseEvent* mouseEvent = (nsMouseEvent *) privateEvent->GetInternalNSEvent();
4733 if (mouseEvent) {
4734 nsEventStatus rv = ProcessEvent(*mouseEvent);
4735 if (nsEventStatus_eConsumeNoDefault == rv) {
4736 return aMouseEvent->PreventDefault(); // consume event
4739 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, mouseEvent null");
4741 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, privateEvent null");
4743 return NS_OK;
4746 nsresult
4747 nsPluginInstanceOwner::MouseUp(nsIDOMEvent* aMouseEvent)
4749 return DispatchMouseToPlugin(aMouseEvent);
4752 nsresult
4753 nsPluginInstanceOwner::MouseClick(nsIDOMEvent* aMouseEvent)
4755 return DispatchMouseToPlugin(aMouseEvent);
4758 nsresult
4759 nsPluginInstanceOwner::MouseDblClick(nsIDOMEvent* aMouseEvent)
4761 return DispatchMouseToPlugin(aMouseEvent);
4764 nsresult
4765 nsPluginInstanceOwner::MouseOver(nsIDOMEvent* aMouseEvent)
4767 return DispatchMouseToPlugin(aMouseEvent);
4770 nsresult
4771 nsPluginInstanceOwner::MouseOut(nsIDOMEvent* aMouseEvent)
4773 return DispatchMouseToPlugin(aMouseEvent);
4776 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
4778 #if !defined(XP_MACOSX) && !defined(MOZ_COMPOSITED_PLUGINS)
4779 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
4780 return aMouseEvent->PreventDefault(); // consume event
4781 // continue only for cases without child window
4782 #endif
4783 // don't send mouse events if we are hidden
4784 if (!mWidgetVisible)
4785 return NS_OK;
4787 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
4788 if (privateEvent) {
4789 nsMouseEvent* mouseEvent = (nsMouseEvent *) privateEvent->GetInternalNSEvent();
4790 if (mouseEvent) {
4791 nsEventStatus rv = ProcessEvent(*mouseEvent);
4792 if (nsEventStatus_eConsumeNoDefault == rv) {
4793 aMouseEvent->PreventDefault();
4794 aMouseEvent->StopPropagation();
4797 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, mouseEvent null");
4799 else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, privateEvent null");
4801 return NS_OK;
4804 nsresult
4805 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
4807 if (mInstance) {
4808 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
4809 nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
4810 if (privateEvent && dragEvent) {
4811 nsEvent* ievent = privateEvent->GetInternalNSEvent();
4812 if (ievent && NS_IS_TRUSTED_EVENT(ievent) &&
4813 (ievent->message == NS_DRAGDROP_ENTER || ievent->message == NS_DRAGDROP_OVER)) {
4814 // set the allowed effect to none here. The plugin should set it if necessary
4815 nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
4816 dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
4817 if (dataTransfer)
4818 dataTransfer->SetEffectAllowed(NS_LITERAL_STRING("none"));
4821 // Let the plugin handle drag events.
4822 aEvent->PreventDefault();
4823 aEvent->StopPropagation();
4826 return NS_OK;
4829 #ifdef MOZ_X11
4830 static unsigned int XInputEventState(const nsInputEvent& anEvent)
4832 unsigned int state = 0;
4833 if (anEvent.isShift) state |= ShiftMask;
4834 if (anEvent.isControl) state |= ControlMask;
4835 if (anEvent.isAlt) state |= Mod1Mask;
4836 if (anEvent.isMeta) state |= Mod4Mask;
4837 return state;
4839 #endif
4841 #ifdef MOZ_COMPOSITED_PLUGINS
4842 static void find_dest_id(XID top, XID *root, XID *dest, int target_x, int target_y)
4844 XID target_id = top;
4845 XID parent;
4846 XID *children;
4847 unsigned int nchildren;
4849 Display *display = DefaultXDisplay();
4851 while (1) {
4852 loop:
4853 //printf("searching %x\n", target_id);
4854 if (!XQueryTree(display, target_id, root, &parent, &children, &nchildren) ||
4855 !nchildren)
4856 break;
4857 for (unsigned int i=0; i<nchildren; i++) {
4858 Window root;
4859 int x, y;
4860 unsigned int width, height;
4861 unsigned int border_width, depth;
4862 XGetGeometry(display, children[i], &root, &x, &y,
4863 &width, &height, &border_width,
4864 &depth);
4865 //printf("target: %d %d\n", target_x, target_y);
4866 //printf("geom: %dx%x @ %dx%d\n", width, height, x, y);
4867 // XXX: we may need to be more careful here, i.e. if
4868 // this condition matches more than one child
4869 if (target_x >= x && target_y >= y &&
4870 target_x <= x + int(width) &&
4871 target_y <= y + int(height)) {
4872 target_id = children[i];
4873 // printf("found new target: %x\n", target_id);
4874 XFree(children);
4875 goto loop;
4878 XFree(children);
4879 /* no children contain the target */
4880 break;
4882 *dest = target_id;
4884 #endif
4886 #ifdef MOZ_COMPOSITED_PLUGINS
4887 nsEventStatus nsPluginInstanceOwner::ProcessEventX11Composited(const nsGUIEvent& anEvent)
4889 //printf("nsGUIEvent.message: %d\n", anEvent.message);
4890 nsEventStatus rv = nsEventStatus_eIgnore;
4891 if (!mInstance || !mObjectFrame) // if mInstance is null, we shouldn't be here
4892 return rv;
4894 // this code supports windowless plugins
4895 nsIWidget* widget = anEvent.widget;
4896 XEvent pluginEvent;
4897 pluginEvent.type = 0;
4899 switch(anEvent.eventStructType)
4901 case NS_MOUSE_EVENT:
4903 switch (anEvent.message)
4905 case NS_MOUSE_CLICK:
4906 case NS_MOUSE_DOUBLECLICK:
4907 // Button up/down events sent instead.
4908 return rv;
4911 // Get reference point relative to plugin origin.
4912 const nsPresContext* presContext = mObjectFrame->PresContext();
4913 nsPoint appPoint =
4914 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
4915 mObjectFrame->GetUsedBorderAndPadding().TopLeft();
4916 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
4917 presContext->AppUnitsToDevPixels(appPoint.y));
4918 mLastPoint = pluginPoint;
4919 const nsMouseEvent& mouseEvent =
4920 static_cast<const nsMouseEvent&>(anEvent);
4921 // Get reference point relative to screen:
4922 nsIntPoint rootPoint(-1,-1);
4923 if (widget)
4924 rootPoint = anEvent.refPoint + widget->WidgetToScreenOffset();
4925 #ifdef MOZ_WIDGET_GTK2
4926 Window root = GDK_ROOT_WINDOW();
4927 #elif defined(MOZ_WIDGET_QT)
4928 Window root = QX11Info::appRootWindow();
4929 #else
4930 Window root = None;
4931 #endif
4933 switch (anEvent.message)
4935 case NS_MOUSE_ENTER_SYNTH:
4936 case NS_MOUSE_EXIT_SYNTH:
4938 XCrossingEvent& event = pluginEvent.xcrossing;
4939 event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
4940 EnterNotify : LeaveNotify;
4941 event.root = root;
4942 event.time = anEvent.time;
4943 event.x = pluginPoint.x;
4944 event.y = pluginPoint.y;
4945 event.x_root = rootPoint.x;
4946 event.y_root = rootPoint.y;
4947 event.state = XInputEventState(mouseEvent);
4948 // information lost
4949 event.subwindow = None;
4950 event.mode = -1;
4951 event.detail = NotifyDetailNone;
4952 event.same_screen = True;
4953 event.focus = mContentFocused;
4955 break;
4956 case NS_MOUSE_MOVE:
4958 XMotionEvent& event = pluginEvent.xmotion;
4959 event.type = MotionNotify;
4960 event.root = root;
4961 event.time = anEvent.time;
4962 event.x = pluginPoint.x;
4963 event.y = pluginPoint.y;
4964 event.x_root = rootPoint.x;
4965 event.y_root = rootPoint.y;
4966 event.state = XInputEventState(mouseEvent);
4967 // information lost
4968 event.subwindow = None;
4969 event.is_hint = NotifyNormal;
4970 event.same_screen = True;
4971 XEvent be;
4972 be.xmotion = pluginEvent.xmotion;
4973 //printf("xmotion: %d %d\n", be.xmotion.x, be.xmotion.y);
4974 XID w = (XID)mPluginWindow->window;
4975 be.xmotion.window = w;
4976 XSendEvent (be.xmotion.display, w,
4977 FALSE, ButtonMotionMask, &be);
4980 break;
4981 case NS_MOUSE_BUTTON_DOWN:
4982 case NS_MOUSE_BUTTON_UP:
4984 XButtonEvent& event = pluginEvent.xbutton;
4985 event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ?
4986 ButtonPress : ButtonRelease;
4987 event.root = root;
4988 event.time = anEvent.time;
4989 event.x = pluginPoint.x;
4990 event.y = pluginPoint.y;
4991 event.x_root = rootPoint.x;
4992 event.y_root = rootPoint.y;
4993 event.state = XInputEventState(mouseEvent);
4994 switch (mouseEvent.button)
4996 case nsMouseEvent::eMiddleButton:
4997 event.button = 2;
4998 break;
4999 case nsMouseEvent::eRightButton:
5000 event.button = 3;
5001 break;
5002 default: // nsMouseEvent::eLeftButton;
5003 event.button = 1;
5004 break;
5006 // information lost:
5007 event.subwindow = None;
5008 event.same_screen = True;
5009 XEvent be;
5010 be.xbutton = event;
5011 XID target;
5012 XID root;
5013 int wx, wy;
5014 unsigned int width, height, border_width, depth;
5016 //printf("xbutton: %d %d %d\n", anEvent.message, be.xbutton.x, be.xbutton.y);
5017 XID w = (XID)mPluginWindow->window;
5018 XGetGeometry(DefaultXDisplay(), w, &root, &wx, &wy, &width, &height, &border_width, &depth);
5019 find_dest_id(w, &root, &target, pluginPoint.x + wx, pluginPoint.y + wy);
5020 be.xbutton.window = target;
5021 XSendEvent (DefaultXDisplay(), target,
5022 FALSE, event.type == ButtonPress ? ButtonPressMask : ButtonReleaseMask, &be);
5025 break;
5028 break;
5030 //XXX case NS_MOUSE_SCROLL_EVENT: not received.
5032 case NS_KEY_EVENT:
5033 if (anEvent.pluginEvent)
5035 XKeyEvent &event = pluginEvent.xkey;
5036 #ifdef MOZ_WIDGET_GTK2
5037 event.root = GDK_ROOT_WINDOW();
5038 event.time = anEvent.time;
5039 const GdkEventKey* gdkEvent =
5040 static_cast<const GdkEventKey*>(anEvent.pluginEvent);
5041 event.keycode = gdkEvent->hardware_keycode;
5042 event.state = gdkEvent->state;
5043 switch (anEvent.message)
5045 case NS_KEY_DOWN:
5046 // Handle NS_KEY_DOWN for modifier key presses
5047 // For non-modifiers we get NS_KEY_PRESS
5048 if (gdkEvent->is_modifier)
5049 event.type = XKeyPress;
5050 break;
5051 case NS_KEY_PRESS:
5052 event.type = XKeyPress;
5053 break;
5054 case NS_KEY_UP:
5055 event.type = KeyRelease;
5056 break;
5058 #endif
5060 #ifdef MOZ_WIDGET_QT
5061 const nsKeyEvent& keyEvent = static_cast<const nsKeyEvent&>(anEvent);
5063 memset( &event, 0, sizeof(event) );
5064 event.time = anEvent.time;
5066 QWidget* qWidget = static_cast<QWidget*>(widget->GetNativeData(NS_NATIVE_WINDOW));
5067 if (qWidget)
5068 event.root = qWidget->x11Info().appRootWindow();
5070 // deduce keycode from the information in the attached QKeyEvent
5071 const QKeyEvent* qtEvent = static_cast<const QKeyEvent*>(anEvent.pluginEvent);
5072 if (qtEvent) {
5074 if (qtEvent->nativeModifiers())
5075 event.state = qtEvent->nativeModifiers();
5076 else // fallback
5077 event.state = XInputEventState(keyEvent);
5079 if (qtEvent->nativeScanCode())
5080 event.keycode = qtEvent->nativeScanCode();
5081 else // fallback
5082 event.keycode = XKeysymToKeycode( (widget ? static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nsnull), qtEvent->key());
5085 switch (anEvent.message)
5087 case NS_KEY_DOWN:
5088 event.type = XKeyPress;
5089 break;
5090 case NS_KEY_UP:
5091 event.type = KeyRelease;
5092 break;
5094 #endif
5096 // Information that could be obtained from pluginEvent but we may not
5097 // want to promise to provide:
5098 event.subwindow = None;
5099 event.x = 0;
5100 event.y = 0;
5101 event.x_root = -1;
5102 event.y_root = -1;
5103 event.same_screen = False;
5104 XEvent be;
5105 be.xkey = event;
5106 XID target;
5107 XID root;
5108 int wx, wy;
5109 unsigned int width, height, border_width, depth;
5111 //printf("xkey: %d %d %d\n", anEvent.message, be.xkey.keycode, be.xkey.state);
5112 XID w = (XID)mPluginWindow->window;
5113 XGetGeometry(DefaultXDisplay(), w, &root, &wx, &wy, &width, &height, &border_width, &depth);
5114 find_dest_id(w, &root, &target, mLastPoint.x + wx, mLastPoint.y + wy);
5115 be.xkey.window = target;
5116 XSendEvent (DefaultXDisplay(), target,
5117 FALSE, event.type == XKeyPress ? KeyPressMask : KeyReleaseMask, &be);
5121 else
5123 // If we need to send synthesized key events, then
5124 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
5125 // gdk_keymap_get_entries_for_keyval will be useful, but the
5126 // mappings will not be unique.
5127 NS_WARNING("Synthesized key event not sent to plugin");
5129 break;
5131 default:
5132 switch (anEvent.message)
5134 case NS_FOCUS_CONTENT:
5135 case NS_BLUR_CONTENT:
5137 XFocusChangeEvent &event = pluginEvent.xfocus;
5138 event.type =
5139 anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut;
5140 // information lost:
5141 event.mode = -1;
5142 event.detail = NotifyDetailNone;
5144 break;
5148 if (!pluginEvent.type) {
5149 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
5150 ("Unhandled event message %d with struct type %d\n",
5151 anEvent.message, anEvent.eventStructType));
5152 return rv;
5155 // Fill in (useless) generic event information.
5156 XAnyEvent& event = pluginEvent.xany;
5157 event.display = widget ?
5158 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nsnull;
5159 event.window = None; // not a real window
5160 // information lost:
5161 event.serial = 0;
5162 event.send_event = False;
5164 #if 0
5165 /* we've sent the event via XSendEvent so don't send it directly to the plugin */
5166 PRInt16 response = kNPEventNotHandled;
5167 mInstance->HandleEvent(&pluginEvent, &response);
5168 if (response == kNPEventHandled)
5169 rv = nsEventStatus_eConsumeNoDefault;
5170 #endif
5172 return rv;
5174 #endif
5176 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
5178 // printf("nsGUIEvent.message: %d\n", anEvent.message);
5180 #ifdef MOZ_COMPOSITED_PLUGINS
5181 if (mPluginWindow && (mPluginWindow->type != NPWindowTypeDrawable))
5182 return ProcessEventX11Composited(anEvent);
5183 #endif
5185 nsEventStatus rv = nsEventStatus_eIgnore;
5187 if (!mInstance || !mObjectFrame) // if mInstance is null, we shouldn't be here
5188 return nsEventStatus_eIgnore;
5190 #ifdef XP_MACOSX
5191 if (!mWidget)
5192 return nsEventStatus_eIgnore;
5194 // we never care about synthesized mouse enter
5195 if (anEvent.message == NS_MOUSE_ENTER_SYNTH)
5196 return nsEventStatus_eIgnore;
5198 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
5199 if (!pluginWidget || NS_FAILED(pluginWidget->StartDrawPlugin()))
5200 return nsEventStatus_eIgnore;
5202 NPEventModel eventModel = GetEventModel();
5204 // If we have to synthesize an event we'll use one of these.
5205 #ifndef NP_NO_CARBON
5206 EventRecord synthCarbonEvent;
5207 #endif
5208 NPCocoaEvent synthCocoaEvent;
5209 void* event = anEvent.pluginEvent;
5210 nsPoint pt =
5211 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
5212 mObjectFrame->GetUsedBorderAndPadding().TopLeft();
5213 nsPresContext* presContext = mObjectFrame->PresContext();
5214 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
5215 presContext->AppUnitsToDevPixels(pt.y));
5216 #ifndef NP_NO_CARBON
5217 nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
5218 Point carbonPt = { ptPx.y + geckoScreenCoords.y, ptPx.x + geckoScreenCoords.x };
5219 if (eventModel == NPEventModelCarbon) {
5220 if (event && anEvent.eventStructType == NS_MOUSE_EVENT) {
5221 static_cast<EventRecord*>(event)->where = carbonPt;
5224 #endif
5225 if (!event) {
5226 #ifndef NP_NO_CARBON
5227 if (eventModel == NPEventModelCarbon) {
5228 InitializeEventRecord(&synthCarbonEvent, &carbonPt);
5229 } else
5230 #endif
5232 InitializeNPCocoaEvent(&synthCocoaEvent);
5235 switch (anEvent.message) {
5236 case NS_FOCUS_CONTENT:
5237 case NS_BLUR_CONTENT:
5238 #ifndef NP_NO_CARBON
5239 if (eventModel == NPEventModelCarbon) {
5240 synthCarbonEvent.what = (anEvent.message == NS_FOCUS_CONTENT) ?
5241 NPEventType_GetFocusEvent : NPEventType_LoseFocusEvent;
5242 event = &synthCarbonEvent;
5244 #endif
5245 break;
5246 case NS_MOUSE_MOVE:
5248 // Ignore mouse-moved events that happen as part of a dragging
5249 // operation that started over another frame. See bug 525078.
5250 nsCOMPtr<nsFrameSelection> frameselection = mObjectFrame->GetFrameSelection();
5251 if (!frameselection->GetMouseDownState() ||
5252 (nsIPresShell::GetCapturingContent() == mObjectFrame->GetContent())) {
5253 #ifndef NP_NO_CARBON
5254 if (eventModel == NPEventModelCarbon) {
5255 synthCarbonEvent.what = osEvt;
5256 event = &synthCarbonEvent;
5257 } else
5258 #endif
5260 synthCocoaEvent.type = NPCocoaEventMouseMoved;
5261 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
5262 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
5263 event = &synthCocoaEvent;
5267 break;
5268 case NS_MOUSE_BUTTON_DOWN:
5269 #ifndef NP_NO_CARBON
5270 if (eventModel == NPEventModelCarbon) {
5271 synthCarbonEvent.what = mouseDown;
5272 event = &synthCarbonEvent;
5273 } else
5274 #endif
5276 synthCocoaEvent.type = NPCocoaEventMouseDown;
5277 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
5278 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
5279 event = &synthCocoaEvent;
5281 break;
5282 case NS_MOUSE_BUTTON_UP:
5283 // If we're in a dragging operation that started over another frame,
5284 // either ignore the mouse-up event (in the Carbon Event Model) or
5285 // convert it into a mouse-entered event (in the Cocoa Event Model).
5286 // See bug 525078.
5287 if ((static_cast<const nsMouseEvent&>(anEvent).button == nsMouseEvent::eLeftButton) &&
5288 (nsIPresShell::GetCapturingContent() != mObjectFrame->GetContent())) {
5289 if (eventModel == NPEventModelCocoa) {
5290 synthCocoaEvent.type = NPCocoaEventMouseEntered;
5291 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
5292 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
5293 event = &synthCocoaEvent;
5295 } else {
5296 #ifndef NP_NO_CARBON
5297 if (eventModel == NPEventModelCarbon) {
5298 synthCarbonEvent.what = mouseUp;
5299 event = &synthCarbonEvent;
5300 } else
5301 #endif
5303 synthCocoaEvent.type = NPCocoaEventMouseUp;
5304 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
5305 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
5306 event = &synthCocoaEvent;
5309 break;
5310 default:
5311 break;
5314 // If we still don't have an event, bail.
5315 if (!event) {
5316 pluginWidget->EndDrawPlugin();
5317 return nsEventStatus_eIgnore;
5321 #ifndef NP_NO_CARBON
5322 // Work around an issue in the Flash plugin, which can cache a pointer
5323 // to a doomed TSM document (one that belongs to a NSTSMInputContext)
5324 // and try to activate it after it has been deleted. See bug 183313.
5325 if (eventModel == NPEventModelCarbon && anEvent.message == NS_FOCUS_CONTENT)
5326 ::DeactivateTSMDocument(::TSMGetActiveDocument());
5327 #endif
5329 PRInt16 response = kNPEventNotHandled;
5330 void* window = FixUpPluginWindow(ePluginPaintEnable);
5331 if (window || (eventModel == NPEventModelCocoa)) {
5332 mInstance->HandleEvent(event, &response);
5335 if (eventModel == NPEventModelCocoa && response == kNPEventStartIME) {
5336 pluginWidget->StartComplexTextInputForCurrentEvent();
5339 if ((response == kNPEventHandled || response == kNPEventStartIME) &&
5340 !(anEvent.eventStructType == NS_MOUSE_EVENT &&
5341 anEvent.message == NS_MOUSE_BUTTON_DOWN &&
5342 static_cast<const nsMouseEvent&>(anEvent).button == nsMouseEvent::eLeftButton &&
5343 !mContentFocused))
5344 rv = nsEventStatus_eConsumeNoDefault;
5346 pluginWidget->EndDrawPlugin();
5347 #endif
5349 #ifdef XP_WIN
5350 // this code supports windowless plugins
5351 NPEvent *pPluginEvent = (NPEvent*)anEvent.pluginEvent;
5352 // we can get synthetic events from the nsEventStateManager... these
5353 // have no pluginEvent
5354 NPEvent pluginEvent;
5355 if (anEvent.eventStructType == NS_MOUSE_EVENT) {
5356 if (!pPluginEvent) {
5357 // XXX Should extend this list to synthesize events for more event
5358 // types
5359 pluginEvent.event = 0;
5360 const nsMouseEvent* mouseEvent = static_cast<const nsMouseEvent*>(&anEvent);
5361 switch (anEvent.message) {
5362 case NS_MOUSE_MOVE:
5363 pluginEvent.event = WM_MOUSEMOVE;
5364 break;
5365 case NS_MOUSE_BUTTON_DOWN: {
5366 static const int downMsgs[] =
5367 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
5368 static const int dblClickMsgs[] =
5369 { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
5370 if (mouseEvent->clickCount == 2) {
5371 pluginEvent.event = dblClickMsgs[mouseEvent->button];
5372 } else {
5373 pluginEvent.event = downMsgs[mouseEvent->button];
5375 break;
5377 case NS_MOUSE_BUTTON_UP: {
5378 static const int upMsgs[] =
5379 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
5380 pluginEvent.event = upMsgs[mouseEvent->button];
5381 break;
5383 // don't synthesize anything for NS_MOUSE_DOUBLECLICK, since that
5384 // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
5385 // messages are sent on mouse-down
5386 default:
5387 break;
5389 if (pluginEvent.event) {
5390 pPluginEvent = &pluginEvent;
5391 pluginEvent.wParam =
5392 (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
5393 (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) |
5394 (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) |
5395 (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) |
5396 (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) |
5397 (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) |
5398 (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
5401 if (pPluginEvent) {
5402 // Make event coordinates relative to our enclosing widget,
5403 // not the widget they were received on.
5404 // See use of NPEvent in widget/src/windows/nsWindow.cpp
5405 // for why this assert should be safe
5406 NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
5407 anEvent.message == NS_MOUSE_BUTTON_UP ||
5408 anEvent.message == NS_MOUSE_DOUBLECLICK ||
5409 anEvent.message == NS_MOUSE_ENTER_SYNTH ||
5410 anEvent.message == NS_MOUSE_EXIT_SYNTH ||
5411 anEvent.message == NS_MOUSE_MOVE,
5412 "Incorrect event type for coordinate translation");
5413 nsPoint pt =
5414 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
5415 mObjectFrame->GetUsedBorderAndPadding().TopLeft();
5416 nsPresContext* presContext = mObjectFrame->PresContext();
5417 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
5418 presContext->AppUnitsToDevPixels(pt.y));
5419 nsIntPoint widgetPtPx = ptPx + mObjectFrame->GetWindowOriginInPixels(PR_TRUE);
5420 pPluginEvent->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
5423 else if (!pPluginEvent) {
5424 switch (anEvent.message) {
5425 case NS_FOCUS_CONTENT:
5426 pluginEvent.event = WM_SETFOCUS;
5427 pluginEvent.wParam = 0;
5428 pluginEvent.lParam = 0;
5429 pPluginEvent = &pluginEvent;
5430 break;
5431 case NS_BLUR_CONTENT:
5432 pluginEvent.event = WM_KILLFOCUS;
5433 pluginEvent.wParam = 0;
5434 pluginEvent.lParam = 0;
5435 pPluginEvent = &pluginEvent;
5436 break;
5440 if (pPluginEvent && !pPluginEvent->event) {
5441 // Don't send null events to plugins.
5442 NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin.");
5443 return rv;
5446 if (pPluginEvent) {
5447 PRInt16 response = kNPEventNotHandled;
5448 mInstance->HandleEvent(pPluginEvent, &response);
5449 if (response == kNPEventHandled)
5450 rv = nsEventStatus_eConsumeNoDefault;
5452 #endif
5454 #ifdef MOZ_X11
5455 // this code supports windowless plugins
5456 nsIWidget* widget = anEvent.widget;
5457 XEvent pluginEvent = XEvent();
5458 pluginEvent.type = 0;
5460 switch(anEvent.eventStructType)
5462 case NS_MOUSE_EVENT:
5464 switch (anEvent.message)
5466 case NS_MOUSE_CLICK:
5467 case NS_MOUSE_DOUBLECLICK:
5468 // Button up/down events sent instead.
5469 return rv;
5472 // Get reference point relative to plugin origin.
5473 const nsPresContext* presContext = mObjectFrame->PresContext();
5474 nsPoint appPoint =
5475 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
5476 mObjectFrame->GetUsedBorderAndPadding().TopLeft();
5477 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
5478 presContext->AppUnitsToDevPixels(appPoint.y));
5479 const nsMouseEvent& mouseEvent =
5480 static_cast<const nsMouseEvent&>(anEvent);
5481 // Get reference point relative to screen:
5482 nsIntPoint rootPoint(-1,-1);
5483 if (widget)
5484 rootPoint = anEvent.refPoint + widget->WidgetToScreenOffset();
5485 #ifdef MOZ_WIDGET_GTK2
5486 Window root = GDK_ROOT_WINDOW();
5487 #elif defined(MOZ_WIDGET_QT)
5488 Window root = QX11Info::appRootWindow();
5489 #else
5490 Window root = None; // Could XQueryTree, but this is not important.
5491 #endif
5493 switch (anEvent.message)
5495 case NS_MOUSE_ENTER_SYNTH:
5496 case NS_MOUSE_EXIT_SYNTH:
5498 XCrossingEvent& event = pluginEvent.xcrossing;
5499 event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
5500 EnterNotify : LeaveNotify;
5501 event.root = root;
5502 event.time = anEvent.time;
5503 event.x = pluginPoint.x;
5504 event.y = pluginPoint.y;
5505 event.x_root = rootPoint.x;
5506 event.y_root = rootPoint.y;
5507 event.state = XInputEventState(mouseEvent);
5508 // information lost
5509 event.subwindow = None;
5510 event.mode = -1;
5511 event.detail = NotifyDetailNone;
5512 event.same_screen = True;
5513 event.focus = mContentFocused;
5515 break;
5516 case NS_MOUSE_MOVE:
5518 XMotionEvent& event = pluginEvent.xmotion;
5519 event.type = MotionNotify;
5520 event.root = root;
5521 event.time = anEvent.time;
5522 event.x = pluginPoint.x;
5523 event.y = pluginPoint.y;
5524 event.x_root = rootPoint.x;
5525 event.y_root = rootPoint.y;
5526 event.state = XInputEventState(mouseEvent);
5527 // information lost
5528 event.subwindow = None;
5529 event.is_hint = NotifyNormal;
5530 event.same_screen = True;
5532 break;
5533 case NS_MOUSE_BUTTON_DOWN:
5534 case NS_MOUSE_BUTTON_UP:
5536 XButtonEvent& event = pluginEvent.xbutton;
5537 event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ?
5538 ButtonPress : ButtonRelease;
5539 event.root = root;
5540 event.time = anEvent.time;
5541 event.x = pluginPoint.x;
5542 event.y = pluginPoint.y;
5543 event.x_root = rootPoint.x;
5544 event.y_root = rootPoint.y;
5545 event.state = XInputEventState(mouseEvent);
5546 switch (mouseEvent.button)
5548 case nsMouseEvent::eMiddleButton:
5549 event.button = 2;
5550 break;
5551 case nsMouseEvent::eRightButton:
5552 event.button = 3;
5553 break;
5554 default: // nsMouseEvent::eLeftButton;
5555 event.button = 1;
5556 break;
5558 // information lost:
5559 event.subwindow = None;
5560 event.same_screen = True;
5562 break;
5565 break;
5567 //XXX case NS_MOUSE_SCROLL_EVENT: not received.
5569 case NS_KEY_EVENT:
5570 if (anEvent.pluginEvent)
5572 XKeyEvent &event = pluginEvent.xkey;
5573 #ifdef MOZ_WIDGET_GTK2
5574 event.root = GDK_ROOT_WINDOW();
5575 event.time = anEvent.time;
5576 const GdkEventKey* gdkEvent =
5577 static_cast<const GdkEventKey*>(anEvent.pluginEvent);
5578 event.keycode = gdkEvent->hardware_keycode;
5579 event.state = gdkEvent->state;
5580 switch (anEvent.message)
5582 case NS_KEY_DOWN:
5583 // Handle NS_KEY_DOWN for modifier key presses
5584 // For non-modifiers we get NS_KEY_PRESS
5585 if (gdkEvent->is_modifier)
5586 event.type = XKeyPress;
5587 break;
5588 case NS_KEY_PRESS:
5589 event.type = XKeyPress;
5590 break;
5591 case NS_KEY_UP:
5592 event.type = KeyRelease;
5593 break;
5595 #endif
5597 #ifdef MOZ_WIDGET_QT
5598 const nsKeyEvent& keyEvent = static_cast<const nsKeyEvent&>(anEvent);
5600 memset( &event, 0, sizeof(event) );
5601 event.time = anEvent.time;
5603 QWidget* qWidget = static_cast<QWidget*>(widget->GetNativeData(NS_NATIVE_WINDOW));
5604 if (qWidget)
5605 event.root = qWidget->x11Info().appRootWindow();
5607 // deduce keycode from the information in the attached QKeyEvent
5608 const QKeyEvent* qtEvent = static_cast<const QKeyEvent*>(anEvent.pluginEvent);
5609 if (qtEvent) {
5611 if (qtEvent->nativeModifiers())
5612 event.state = qtEvent->nativeModifiers();
5613 else // fallback
5614 event.state = XInputEventState(keyEvent);
5616 if (qtEvent->nativeScanCode())
5617 event.keycode = qtEvent->nativeScanCode();
5618 else // fallback
5619 event.keycode = XKeysymToKeycode( (widget ? static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nsnull), qtEvent->key());
5622 switch (anEvent.message)
5624 case NS_KEY_DOWN:
5625 event.type = XKeyPress;
5626 break;
5627 case NS_KEY_UP:
5628 event.type = KeyRelease;
5629 break;
5631 #endif
5632 // Information that could be obtained from pluginEvent but we may not
5633 // want to promise to provide:
5634 event.subwindow = None;
5635 event.x = 0;
5636 event.y = 0;
5637 event.x_root = -1;
5638 event.y_root = -1;
5639 event.same_screen = False;
5641 else
5643 // If we need to send synthesized key events, then
5644 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
5645 // gdk_keymap_get_entries_for_keyval will be useful, but the
5646 // mappings will not be unique.
5647 NS_WARNING("Synthesized key event not sent to plugin");
5649 break;
5651 default:
5652 switch (anEvent.message)
5654 case NS_FOCUS_CONTENT:
5655 case NS_BLUR_CONTENT:
5657 XFocusChangeEvent &event = pluginEvent.xfocus;
5658 event.type =
5659 anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut;
5660 // information lost:
5661 event.mode = -1;
5662 event.detail = NotifyDetailNone;
5664 break;
5668 if (!pluginEvent.type) {
5669 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
5670 ("Unhandled event message %d with struct type %d\n",
5671 anEvent.message, anEvent.eventStructType));
5672 return rv;
5675 // Fill in (useless) generic event information.
5676 XAnyEvent& event = pluginEvent.xany;
5677 event.display = widget ?
5678 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nsnull;
5679 event.window = None; // not a real window
5680 // information lost:
5681 event.serial = 0;
5682 event.send_event = False;
5684 PRInt16 response = kNPEventNotHandled;
5685 mInstance->HandleEvent(&pluginEvent, &response);
5686 if (response == kNPEventHandled)
5687 rv = nsEventStatus_eConsumeNoDefault;
5688 #endif
5690 return rv;
5693 nsresult
5694 nsPluginInstanceOwner::Destroy()
5696 #ifdef MAC_CARBON_PLUGINS
5697 // stop the timer explicitly to reduce reference count.
5698 CancelTimer();
5699 #endif
5700 #ifdef XP_MACOSX
5701 RemoveFromCARefreshTimer(this);
5702 if (mIOSurface)
5703 delete mIOSurface;
5704 #endif
5706 // unregister context menu listener
5707 if (mCXMenuListener) {
5708 mCXMenuListener->Destroy(mContent);
5709 mCXMenuListener = nsnull;
5712 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
5713 if (target) {
5715 nsCOMPtr<nsIDOMEventListener> listener;
5716 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
5718 // Unregister focus event listener
5719 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
5721 // Unregister mouse event listener
5722 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
5724 // now for the mouse motion listener
5725 mContent->RemoveEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
5727 // Unregister key event listener;
5728 target->RemoveEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
5729 target->RemoveEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
5730 target->RemoveEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
5732 // Unregister drag event listener;
5733 target->RemoveEventListener(NS_LITERAL_STRING("drop"), listener, PR_TRUE);
5734 target->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
5735 target->RemoveEventListener(NS_LITERAL_STRING("drag"), listener, PR_TRUE);
5736 target->RemoveEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
5737 target->RemoveEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
5738 target->RemoveEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
5739 target->RemoveEventListener(NS_LITERAL_STRING("dragleave"), listener, PR_TRUE);
5740 target->RemoveEventListener(NS_LITERAL_STRING("dragstart"), listener, PR_TRUE);
5741 target->RemoveEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
5742 target->RemoveEventListener(NS_LITERAL_STRING("dragend"), listener, PR_TRUE);
5745 if (mWidget) {
5746 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
5747 if (pluginWidget)
5748 pluginWidget->SetPluginInstanceOwner(nsnull);
5750 if (mDestroyWidget)
5751 mWidget->Destroy();
5754 return NS_OK;
5758 * Prepare to stop
5760 void
5761 nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
5763 // Drop image reference because the child may destroy the surface after we return.
5764 nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
5765 if (container) {
5766 container->SetCurrentImage(nsnull);
5769 #if defined(XP_WIN) || defined(MOZ_X11)
5770 if (aDelayedStop && mWidget) {
5771 // To delay stopping a plugin we need to reparent the plugin
5772 // so that we can safely tear down the
5773 // plugin after its frame (and view) is gone.
5775 // Also hide and disable the widget to avoid it from appearing in
5776 // odd places after reparenting it, but before it gets destroyed.
5777 mWidget->Show(PR_FALSE);
5778 mWidget->Enable(PR_FALSE);
5780 // Reparent the plugins native window. This relies on the widget
5781 // and plugin et al not holding any other references to its
5782 // parent.
5783 mWidget->SetParent(nsnull);
5785 mDestroyWidget = PR_TRUE;
5787 #endif
5789 // Unregister scroll position listeners
5790 for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
5791 nsIScrollableFrame* sf = do_QueryFrame(f);
5792 if (sf) {
5793 sf->RemoveScrollPositionListener(this);
5798 // Paints are handled differently, so we just simulate an update event.
5800 #ifdef XP_MACOSX
5801 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
5803 if (!mInstance || !mObjectFrame)
5804 return;
5806 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
5807 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
5808 #ifndef NP_NO_CARBON
5809 void* window = FixUpPluginWindow(ePluginPaintEnable);
5810 if (GetEventModel() == NPEventModelCarbon && window) {
5811 EventRecord updateEvent;
5812 InitializeEventRecord(&updateEvent, nsnull);
5813 updateEvent.what = updateEvt;
5814 updateEvent.message = UInt32(window);
5816 mInstance->HandleEvent(&updateEvent, nsnull);
5817 } else if (GetEventModel() == NPEventModelCocoa)
5818 #endif
5820 DoCocoaEventDrawRect(aDirtyRect, cgContext);
5822 pluginWidget->EndDrawPlugin();
5826 void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
5828 // The context given here is only valid during the HandleEvent call.
5829 NPCocoaEvent updateEvent;
5830 InitializeNPCocoaEvent(&updateEvent);
5831 updateEvent.type = NPCocoaEventDrawRect;
5832 updateEvent.data.draw.context = cgContext;
5833 updateEvent.data.draw.x = aDrawRect.X();
5834 updateEvent.data.draw.y = aDrawRect.Y();
5835 updateEvent.data.draw.width = aDrawRect.Width();
5836 updateEvent.data.draw.height = aDrawRect.Height();
5838 mInstance->HandleEvent(&updateEvent, nsnull);
5840 #endif
5842 #ifdef XP_WIN
5843 void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
5845 if (!mInstance || !mObjectFrame)
5846 return;
5848 NPEvent pluginEvent;
5849 pluginEvent.event = WM_PAINT;
5850 pluginEvent.wParam = WPARAM(aDC);
5851 pluginEvent.lParam = LPARAM(&aDirty);
5852 mInstance->HandleEvent(&pluginEvent, nsnull);
5854 #endif
5856 #ifdef XP_OS2
5857 void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, HPS aHPS)
5859 if (!mInstance || !mObjectFrame)
5860 return;
5862 NPWindow *window;
5863 GetWindow(window);
5864 nsIntRect relDirtyRect = aDirtyRect.ToOutsidePixels(mObjectFrame->PresContext()->AppUnitsPerDevPixel());
5866 // we got dirty rectangle in relative window coordinates, but we
5867 // need it in absolute units and in the (left, top, right, bottom) form
5868 RECTL rectl;
5869 rectl.xLeft = relDirtyRect.x + window->x;
5870 rectl.yBottom = relDirtyRect.y + window->y;
5871 rectl.xRight = rectl.xLeft + relDirtyRect.width;
5872 rectl.yTop = rectl.yBottom + relDirtyRect.height;
5874 NPEvent pluginEvent;
5875 pluginEvent.event = WM_PAINT;
5876 pluginEvent.wParam = (uint32)aHPS;
5877 pluginEvent.lParam = (uint32)&rectl;
5878 mInstance->HandleEvent(&pluginEvent, nsnull);
5880 #endif
5882 #if defined(MOZ_X11)
5883 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
5884 const gfxRect& aFrameRect,
5885 const gfxRect& aDirtyRect)
5887 if (!mInstance || !mObjectFrame)
5888 return;
5890 #ifdef MOZ_USE_IMAGE_EXPOSE
5891 // through to be able to paint the context passed in. This allows
5892 // us to handle plugins that do not self invalidate (slowly, but
5893 // accurately), and it allows us to reduce flicker.
5894 PRBool simpleImageRender = PR_FALSE;
5895 mInstance->GetValueFromPlugin(NPPVpluginWindowlessLocalBool,
5896 &simpleImageRender);
5897 if (simpleImageRender) {
5898 gfxMatrix matrix = aContext->CurrentMatrix();
5899 if (!matrix.HasNonAxisAlignedTransform())
5900 NativeImageDraw();
5901 return;
5903 #endif
5905 // to provide crisper and faster drawing.
5906 gfxRect pluginRect = aFrameRect;
5907 if (aContext->UserToDevicePixelSnapped(pluginRect)) {
5908 pluginRect = aContext->DeviceToUser(pluginRect);
5911 // Round out the dirty rect to plugin pixels to ensure the plugin draws
5912 // enough pixels for interpolation to device pixels.
5913 gfxRect dirtyRect = aDirtyRect + -pluginRect.pos;
5914 dirtyRect.RoundOut();
5916 // Plugins can only draw an integer number of pixels.
5918 // With translation-only transformation matrices, pluginRect is already
5919 // pixel-aligned.
5921 // With more complex transformations, modifying the scales in the
5922 // transformation matrix could retain subpixel accuracy and let the plugin
5923 // draw a suitable number of pixels for interpolation to device pixels in
5924 // Renderer::Draw, but such cases are not common enough to warrant the
5925 // effort now.
5926 nsIntSize pluginSize(NS_lround(pluginRect.size.width),
5927 NS_lround(pluginRect.size.height));
5929 // Determine what the plugin needs to draw.
5930 nsIntRect pluginDirtyRect(PRInt32(dirtyRect.pos.x),
5931 PRInt32(dirtyRect.pos.y),
5932 PRInt32(dirtyRect.size.width),
5933 PRInt32(dirtyRect.size.height));
5934 if (!pluginDirtyRect.
5935 IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height),
5936 pluginDirtyRect))
5937 return;
5939 NPWindow* window;
5940 GetWindow(window);
5942 PRUint32 rendererFlags = 0;
5943 if (!mFlash10Quirks) {
5944 rendererFlags |=
5945 Renderer::DRAW_SUPPORTS_CLIP_RECT |
5946 Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL;
5949 PRBool transparent;
5950 mInstance->IsTransparent(&transparent);
5951 if (!transparent)
5952 rendererFlags |= Renderer::DRAW_IS_OPAQUE;
5954 // Renderer::Draw() draws a rectangle with top-left at the aContext origin.
5955 gfxContextAutoSaveRestore autoSR(aContext);
5956 aContext->Translate(pluginRect.pos);
5958 Renderer renderer(window, this, pluginSize, pluginDirtyRect);
5959 #ifdef MOZ_WIDGET_GTK2
5960 // This is the visual used by the widgets, 24-bit if available.
5961 GdkVisual* gdkVisual = gdk_rgb_get_visual();
5962 Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
5963 Screen* screen =
5964 gdk_x11_screen_get_xscreen(gdk_visual_get_screen(gdkVisual));
5965 #endif
5966 #ifdef MOZ_WIDGET_QT
5967 Display* dpy = QX11Info().display();
5968 Screen* screen = ScreenOfDisplay(dpy, QX11Info().screen());
5969 Visual* visual = static_cast<Visual*>(QX11Info().visual());
5970 #endif
5971 renderer.Draw(aContext, nsIntSize(window->width, window->height),
5972 rendererFlags, screen, visual, nsnull);
5975 #ifdef MOZ_USE_IMAGE_EXPOSE
5977 static GdkWindow* GetClosestWindow(nsIDOMElement *element)
5979 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
5980 nsIFrame* frame = content->GetPrimaryFrame();
5981 if (!frame)
5982 return nsnull;
5984 nsIWidget* win = frame->GetNearestWidget();
5985 if (!win)
5986 return nsnull;
5988 GdkWindow* w = static_cast<GdkWindow*>(win->GetNativeData(NS_NATIVE_WINDOW));
5989 return w;
5992 void
5993 nsPluginInstanceOwner::ReleaseXShm()
5995 if (mXlibSurfGC) {
5996 XFreeGC(gdk_x11_get_default_xdisplay(), mXlibSurfGC);
5997 mXlibSurfGC = None;
6000 if (mSharedSegmentInfo.shmaddr) {
6001 XShmDetach(gdk_x11_get_default_xdisplay(), &mSharedSegmentInfo);
6002 shmdt(mSharedSegmentInfo.shmaddr);
6003 mSharedSegmentInfo.shmaddr = nsnull;
6006 if (mSharedXImage) {
6007 XDestroyImage(mSharedXImage);
6008 mSharedXImage = nsnull;
6012 PRBool
6013 nsPluginInstanceOwner::SetupXShm()
6015 if (!mBlitWindow)
6016 return PR_FALSE;
6018 ReleaseXShm();
6020 mXlibSurfGC = XCreateGC(gdk_x11_get_default_xdisplay(),
6021 mBlitWindow,
6024 if (!mXlibSurfGC)
6025 return PR_FALSE;
6027 // we use 16 as the default depth because that is the value of the
6028 // screen, but not the default X default depth.
6029 XVisualInfo vinfo;
6030 int foundVisual = XMatchVisualInfo(gdk_x11_get_default_xdisplay(),
6031 gdk_x11_get_default_screen(),
6033 TrueColor,
6034 &vinfo);
6035 if (!foundVisual)
6036 return PR_FALSE;
6038 memset(&mSharedSegmentInfo, 0, sizeof(XShmSegmentInfo));
6039 mSharedXImage = XShmCreateImage(gdk_x11_get_default_xdisplay(),
6040 vinfo.visual,
6042 ZPixmap,
6044 &mSharedSegmentInfo,
6045 mPluginSize.width,
6046 mPluginSize.height);
6047 if (!mSharedXImage)
6048 return PR_FALSE;
6050 NS_ASSERTION(mSharedXImage->height, "do not call shmget with zero");
6051 mSharedSegmentInfo.shmid = shmget(IPC_PRIVATE,
6052 mSharedXImage->bytes_per_line * mSharedXImage->height,
6053 IPC_CREAT | 0600);
6054 if (mSharedSegmentInfo.shmid == -1) {
6055 XDestroyImage(mSharedXImage);
6056 mSharedXImage = nsnull;
6057 return PR_FALSE;
6060 mSharedXImage->data = static_cast<char*>(shmat(mSharedSegmentInfo.shmid, 0, 0));
6061 if (mSharedXImage->data == (char*) -1) {
6062 shmctl(mSharedSegmentInfo.shmid, IPC_RMID, 0);
6063 XDestroyImage(mSharedXImage);
6064 mSharedXImage = nsnull;
6065 return PR_FALSE;
6068 mSharedSegmentInfo.shmaddr = mSharedXImage->data;
6069 mSharedSegmentInfo.readOnly = False;
6071 Status s = XShmAttach(gdk_x11_get_default_xdisplay(), &mSharedSegmentInfo);
6072 XSync(gdk_x11_get_default_xdisplay(), False);
6073 shmctl(mSharedSegmentInfo.shmid, IPC_RMID, 0);
6074 if (!s) {
6075 // attach failed, call shmdt and null shmaddr before calling
6076 // ReleaseXShm().
6077 shmdt(mSharedSegmentInfo.shmaddr);
6078 mSharedSegmentInfo.shmaddr = nsnull;
6079 ReleaseXShm();
6080 return PR_FALSE;
6083 return PR_TRUE;
6087 // NativeImageDraw
6089 // This method supports the NPImageExpose API which is specific to the
6090 // HILDON platform. Basically what it allows us to do is to pass a
6091 // memory buffer into a plugin (namely flash), and have flash draw
6092 // directly into the buffer.
6094 // It may be faster if the rest of the system used offscreen image
6095 // surfaces, but right now offscreen surfaces are using X
6096 // surfaces. And because of this, we need to create a new image
6097 // surface and copy that to the passed gfx context.
6099 // This is not ideal and it should not be faster than what a
6100 // windowless plugin can do. However, in A/B testing of flash on the
6101 // N900, this approach is considerably faster.
6103 // Hopefully this API can die off in favor of a more robust plugin API.
6105 void
6106 nsPluginInstanceOwner::NativeImageDraw(NPRect* invalidRect)
6108 // if we haven't been positioned yet, ignore
6109 if (!mBlitWindow)
6110 return;
6112 // if the clip rect is zero, we have nothing to do.
6113 if (NSToIntCeil(mAbsolutePositionClip.Width()) == 0 ||
6114 NSToIntCeil(mAbsolutePositionClip.Height()) == 0)
6115 return;
6117 // The flash plugin on Maemo n900 requires the width/height to be
6118 // even.
6119 PRInt32 absPosWidth = NSToIntCeil(mAbsolutePosition.Width()) / 2 * 2;
6120 PRInt32 absPosHeight = NSToIntCeil(mAbsolutePosition.Height()) / 2 * 2;
6122 // if the plugin is hidden, nothing to draw.
6123 if (absPosHeight == 0 || absPosWidth == 0)
6124 return;
6126 // Making X or DOM method calls can cause our frame to go
6127 // away, which might kill us...
6128 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
6130 PRBool sizeChanged = (mPluginSize.width != absPosWidth ||
6131 mPluginSize.height != absPosHeight);
6133 if (!mSharedXImage || sizeChanged) {
6134 mPluginSize = nsIntSize(absPosWidth, absPosHeight);
6136 if (NS_FAILED(SetupXShm()))
6137 return;
6140 NPWindow* window;
6141 GetWindow(window);
6142 NS_ASSERTION(window, "Window can not be null");
6144 // setup window such that it knows about the size and clip. This
6145 // is to work around a flash clipping bug when using the Image
6146 // Expose API.
6147 if (!invalidRect && sizeChanged) {
6148 NPRect newClipRect;
6149 newClipRect.left = 0;
6150 newClipRect.top = 0;
6151 newClipRect.right = window->width;
6152 newClipRect.bottom = window->height;
6154 window->clipRect = newClipRect;
6155 window->x = 0;
6156 window->y = 0;
6158 NPSetWindowCallbackStruct* ws_info =
6159 static_cast<NPSetWindowCallbackStruct*>(window->ws_info);
6160 ws_info->visual = 0;
6161 ws_info->colormap = 0;
6162 ws_info->depth = 16;
6163 mInstance->SetWindow(window);
6166 NPEvent pluginEvent;
6167 NPImageExpose imageExpose;
6168 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
6170 // set the drawing info
6171 exposeEvent.type = GraphicsExpose;
6172 exposeEvent.display = 0;
6174 // Store imageExpose structure pointer as drawable member
6175 exposeEvent.drawable = (Drawable)&imageExpose;
6176 exposeEvent.count = 0;
6177 exposeEvent.serial = 0;
6178 exposeEvent.send_event = False;
6179 exposeEvent.major_code = 0;
6180 exposeEvent.minor_code = 0;
6182 exposeEvent.x = 0;
6183 exposeEvent.y = 0;
6184 exposeEvent.width = window->width;
6185 exposeEvent.height = window->height;
6187 imageExpose.x = 0;
6188 imageExpose.y = 0;
6189 imageExpose.width = window->width;
6190 imageExpose.height = window->height;
6192 imageExpose.depth = 16;
6194 imageExpose.translateX = 0;
6195 imageExpose.translateY = 0;
6197 if (window->width == 0)
6198 return;
6200 float scale = mAbsolutePosition.Width() / (float) window->width;
6202 imageExpose.scaleX = scale;
6203 imageExpose.scaleY = scale;
6205 imageExpose.stride = mPluginSize.width * 2;
6206 imageExpose.data = mSharedXImage->data;
6207 imageExpose.dataSize.width = mPluginSize.width;
6208 imageExpose.dataSize.height = mPluginSize.height;
6210 if (invalidRect)
6211 memset(mSharedXImage->data, 0, mPluginSize.width * mPluginSize.height * 2);
6213 PRInt16 response = kNPEventNotHandled;
6214 mInstance->HandleEvent(&pluginEvent, &response);
6215 if (response == kNPEventNotHandled)
6216 return;
6218 // Setup the clip rectangle
6219 XRectangle rect;
6220 rect.x = NSToIntFloor(mAbsolutePositionClip.X());
6221 rect.y = NSToIntFloor(mAbsolutePositionClip.Y());
6222 rect.width = NSToIntCeil(mAbsolutePositionClip.Width());
6223 rect.height = NSToIntCeil(mAbsolutePositionClip.Height());
6225 PRInt32 absPosX = NSToIntFloor(mAbsolutePosition.X());
6226 PRInt32 absPosY = NSToIntFloor(mAbsolutePosition.Y());
6228 XSetClipRectangles(gdk_x11_get_default_xdisplay(),
6229 mXlibSurfGC,
6230 absPosX,
6231 absPosY,
6232 &rect, 1,
6233 Unsorted);
6235 XShmPutImage(gdk_x11_get_default_xdisplay(),
6236 mBlitWindow,
6237 mXlibSurfGC,
6238 mSharedXImage,
6241 absPosX,
6242 absPosY,
6243 mPluginSize.width,
6244 mPluginSize.height,
6245 PR_FALSE);
6247 XSetClipRectangles(gdk_x11_get_default_xdisplay(), mXlibSurfGC, 0, 0, nsnull, 0, Unsorted);
6249 XFlush(gdk_x11_get_default_xdisplay());
6250 return;
6252 #endif
6254 nsresult
6255 nsPluginInstanceOwner::Renderer::DrawWithXlib(gfxXlibSurface* xsurface,
6256 nsIntPoint offset,
6257 nsIntRect *clipRects,
6258 PRUint32 numClipRects)
6260 Screen *screen = cairo_xlib_surface_get_screen(xsurface->CairoSurface());
6261 Colormap colormap;
6262 Visual* visual;
6263 if (!xsurface->GetColormapAndVisual(&colormap, &visual)) {
6264 NS_ERROR("Failed to get visual and colormap");
6265 return NS_ERROR_UNEXPECTED;
6268 nsIPluginInstance *instance = mInstanceOwner->mInstance;
6269 if (!instance)
6270 return NS_ERROR_FAILURE;
6272 // See if the plugin must be notified of new window parameters.
6273 PRBool doupdatewindow = PR_FALSE;
6275 if (mWindow->x != offset.x || mWindow->y != offset.y) {
6276 mWindow->x = offset.x;
6277 mWindow->y = offset.y;
6278 doupdatewindow = PR_TRUE;
6281 if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) {
6282 mWindow->width = mPluginSize.width;
6283 mWindow->height = mPluginSize.height;
6284 doupdatewindow = PR_TRUE;
6287 // The clip rect is relative to drawable top-left.
6288 NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
6289 nsIntRect clipRect;
6290 if (numClipRects) {
6291 clipRect.x = clipRects[0].x;
6292 clipRect.y = clipRects[0].y;
6293 clipRect.width = clipRects[0].width;
6294 clipRect.height = clipRects[0].height;
6295 // NPRect members are unsigned, but clip rectangles should be contained by
6296 // the surface.
6297 NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0,
6298 "Clip rectangle offsets are negative!");
6300 else {
6301 clipRect.x = offset.x;
6302 clipRect.y = offset.y;
6303 clipRect.width = mWindow->width;
6304 clipRect.height = mWindow->height;
6305 // Don't ask the plugin to draw outside the drawable.
6306 // This also ensures that the unsigned clip rectangle offsets won't be -ve.
6307 gfxIntSize surfaceSize = xsurface->GetSize();
6308 clipRect.IntersectRect(clipRect,
6309 nsIntRect(0, 0,
6310 surfaceSize.width, surfaceSize.height));
6313 NPRect newClipRect;
6314 newClipRect.left = clipRect.x;
6315 newClipRect.top = clipRect.y;
6316 newClipRect.right = clipRect.XMost();
6317 newClipRect.bottom = clipRect.YMost();
6318 if (mWindow->clipRect.left != newClipRect.left ||
6319 mWindow->clipRect.top != newClipRect.top ||
6320 mWindow->clipRect.right != newClipRect.right ||
6321 mWindow->clipRect.bottom != newClipRect.bottom) {
6322 mWindow->clipRect = newClipRect;
6323 doupdatewindow = PR_TRUE;
6326 NPSetWindowCallbackStruct* ws_info =
6327 static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
6328 #ifdef MOZ_X11
6329 if (ws_info->visual != visual || ws_info->colormap != colormap) {
6330 ws_info->visual = visual;
6331 ws_info->colormap = colormap;
6332 ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual);
6333 doupdatewindow = PR_TRUE;
6335 #endif
6337 #ifdef MOZ_COMPOSITED_PLUGINS
6338 if (mWindow->type == NPWindowTypeDrawable)
6339 #endif
6341 if (doupdatewindow)
6342 instance->SetWindow(mWindow);
6345 // Translate the dirty rect to drawable coordinates.
6346 nsIntRect dirtyRect = mDirtyRect + offset;
6347 if (mInstanceOwner->mFlash10Quirks) {
6348 // Work around a bug in Flash up to 10.1 d51 at least, where expose event
6349 // top left coordinates within the plugin-rect and not at the drawable
6350 // origin are misinterpreted. (We can move the top left coordinate
6351 // provided it is within the clipRect.)
6352 dirtyRect.SetRect(offset.x, offset.y,
6353 mDirtyRect.XMost(), mDirtyRect.YMost());
6355 // Intersect the dirty rect with the clip rect to ensure that it lies within
6356 // the drawable.
6357 if (!dirtyRect.IntersectRect(dirtyRect, clipRect))
6358 return NS_OK;
6360 #ifdef MOZ_COMPOSITED_PLUGINS
6361 if (mWindow->type == NPWindowTypeDrawable) {
6362 #endif
6363 XEvent pluginEvent = XEvent();
6364 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
6365 // set the drawing info
6366 exposeEvent.type = GraphicsExpose;
6367 exposeEvent.display = DisplayOfScreen(screen);
6368 exposeEvent.drawable = xsurface->XDrawable();
6369 exposeEvent.x = dirtyRect.x;
6370 exposeEvent.y = dirtyRect.y;
6371 exposeEvent.width = dirtyRect.width;
6372 exposeEvent.height = dirtyRect.height;
6373 exposeEvent.count = 0;
6374 // information not set:
6375 exposeEvent.serial = 0;
6376 exposeEvent.send_event = False;
6377 exposeEvent.major_code = 0;
6378 exposeEvent.minor_code = 0;
6380 instance->HandleEvent(&pluginEvent, nsnull);
6381 #ifdef MOZ_COMPOSITED_PLUGINS
6383 else {
6384 /* XXX: this is very nasty. We need a better way of getting at mPlugWindow */
6385 GtkWidget *plug = (GtkWidget*)(((nsPluginNativeWindow*)mWindow)->mPlugWindow);
6386 //GtkWidget *plug = (GtkWidget*)(((nsPluginNativeWindowGtk2*)mWindow)->mSocketWidget);
6388 /* Cairo has bugs with IncludeInferiors when using paint
6389 * so we use XCopyArea directly instead. */
6390 XGCValues gcv;
6391 gcv.subwindow_mode = IncludeInferiors;
6392 gcv.graphics_exposures = False;
6393 Drawable drawable = xsurface->XDrawable();
6394 GC gc = XCreateGC(DefaultXDisplay(), drawable, GCGraphicsExposures | GCSubwindowMode, &gcv);
6395 /* The source and destination appear to always line up, so src and dest
6396 * coords should be the same */
6397 XCopyArea(DefaultXDisplay(), gdk_x11_drawable_get_xid(plug->window),
6398 drawable,
6400 mDirtyRect.x,
6401 mDirtyRect.y,
6402 mDirtyRect.width,
6403 mDirtyRect.height,
6404 mDirtyRect.x,
6405 mDirtyRect.y);
6406 XFreeGC(DefaultXDisplay(), gc);
6408 #endif
6409 return NS_OK;
6411 #endif
6413 void nsPluginInstanceOwner::SendIdleEvent()
6415 #ifdef MAC_CARBON_PLUGINS
6416 // validate the plugin clipping information by syncing the plugin window info to
6417 // reflect the current widget location. This makes sure that everything is updated
6418 // correctly in the event of scrolling in the window.
6419 if (mInstance) {
6420 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
6421 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
6422 void* window = FixUpPluginWindow(ePluginPaintEnable);
6423 if (window) {
6424 EventRecord idleEvent;
6425 InitializeEventRecord(&idleEvent, nsnull);
6426 idleEvent.what = nullEvent;
6428 // give a bogus 'where' field of our null event when hidden, so Flash
6429 // won't respond to mouse moves in other tabs, see bug 120875
6430 if (!mWidgetVisible)
6431 idleEvent.where.h = idleEvent.where.v = 20000;
6433 mInstance->HandleEvent(&idleEvent, nsnull);
6436 pluginWidget->EndDrawPlugin();
6439 #endif
6442 #ifdef MAC_CARBON_PLUGINS
6443 void nsPluginInstanceOwner::StartTimer(PRBool isVisible)
6445 if (GetEventModel() != NPEventModelCarbon)
6446 return;
6448 mPluginHost->AddIdleTimeTarget(this, isVisible);
6451 void nsPluginInstanceOwner::CancelTimer()
6453 mPluginHost->RemoveIdleTimeTarget(this);
6455 #endif
6457 nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
6458 nsObjectFrame* aFrame,
6459 nsIContent* aContent)
6461 mLastEventloopNestingLevel = GetEventloopNestingLevel();
6463 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
6464 ("nsPluginInstanceOwner::Init() called on %p for frame %p\n", this,
6465 aFrame));
6467 mObjectFrame = aFrame;
6468 mContent = aContent;
6470 nsWeakFrame weakFrame(aFrame);
6472 // Some plugins require a specific sequence of shutdown and startup when
6473 // a page is reloaded. Shutdown happens usually when the last instance
6474 // is destroyed. Here we make sure the plugin instance in the old
6475 // document is destroyed before we try to create the new one.
6476 aPresContext->EnsureVisible();
6478 if (!weakFrame.IsAlive()) {
6479 PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
6480 ("nsPluginInstanceOwner::Init's EnsureVisible() call destroyed "
6481 "instance owner %p\n", this));
6483 return NS_ERROR_NOT_AVAILABLE;
6486 // register context menu listener
6487 mCXMenuListener = new nsPluginDOMContextMenuListener();
6488 if (mCXMenuListener) {
6489 mCXMenuListener->Init(aContent);
6492 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mContent));
6493 if (target) {
6495 nsCOMPtr<nsIDOMEventListener> listener;
6496 QueryInterface(NS_GET_IID(nsIDOMEventListener), getter_AddRefs(listener));
6498 // Register focus listener
6499 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMFocusListener));
6501 // Register mouse listener
6502 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseListener));
6504 // now do the mouse motion listener
6505 mContent->AddEventListenerByIID(listener, NS_GET_IID(nsIDOMMouseMotionListener));
6507 // Register key listener
6508 target->AddEventListener(NS_LITERAL_STRING("keypress"), listener, PR_TRUE);
6509 target->AddEventListener(NS_LITERAL_STRING("keydown"), listener, PR_TRUE);
6510 target->AddEventListener(NS_LITERAL_STRING("keyup"), listener, PR_TRUE);
6512 // Register drag listener
6513 target->AddEventListener(NS_LITERAL_STRING("drop"), listener, PR_TRUE);
6514 target->AddEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
6515 target->AddEventListener(NS_LITERAL_STRING("drag"), listener, PR_TRUE);
6516 target->AddEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
6517 target->AddEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
6518 target->AddEventListener(NS_LITERAL_STRING("dragleave"), listener, PR_TRUE);
6519 target->AddEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
6520 target->AddEventListener(NS_LITERAL_STRING("dragstart"), listener, PR_TRUE);
6521 target->AddEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
6522 target->AddEventListener(NS_LITERAL_STRING("dragend"), listener, PR_TRUE);
6525 // Register scroll position listeners
6526 // We need to register a scroll position listener on every scrollable
6527 // frame up to the top
6528 for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
6529 nsIScrollableFrame* sf = do_QueryFrame(f);
6530 if (sf) {
6531 sf->AddScrollPositionListener(this);
6535 return NS_OK;
6538 void* nsPluginInstanceOwner::GetPluginPortFromWidget()
6540 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
6542 void* result = NULL;
6543 if (mWidget) {
6544 #ifdef XP_WIN
6545 if (mPluginWindow && (mPluginWindow->type == NPWindowTypeDrawable))
6546 result = mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
6547 else
6548 #endif
6549 #ifdef XP_MACOSX
6550 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
6551 GetDrawingModel() == NPDrawingModelCoreAnimation ||
6552 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
6553 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG);
6554 else
6555 #endif
6556 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
6558 return result;
6561 void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort)
6563 #ifdef XP_WIN
6564 if (mWidget && mPluginWindow &&
6565 mPluginWindow->type == NPWindowTypeDrawable) {
6566 mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
6568 #endif
6571 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
6573 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
6575 nsresult rv = NS_ERROR_FAILURE;
6577 if (mObjectFrame) {
6578 if (!mWidget) {
6579 PRBool windowless = PR_FALSE;
6580 mInstance->IsWindowless(&windowless);
6582 // always create widgets in Twips, not pixels
6583 nsPresContext* context = mObjectFrame->PresContext();
6584 rv = mObjectFrame->CreateWidget(context->DevPixelsToAppUnits(mPluginWindow->width),
6585 context->DevPixelsToAppUnits(mPluginWindow->height),
6586 windowless);
6587 if (NS_OK == rv) {
6588 mWidget = mObjectFrame->GetWidget();
6590 if (PR_TRUE == windowless) {
6591 mPluginWindow->type = NPWindowTypeDrawable;
6593 // this needs to be a HDC according to the spec, but I do
6594 // not see the right way to release it so let's postpone
6595 // passing HDC till paint event when it is really
6596 // needed. Change spec?
6597 mPluginWindow->window = nsnull;
6598 #ifdef MOZ_X11
6599 // Fill in the display field.
6600 NPSetWindowCallbackStruct* ws_info =
6601 static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
6602 ws_info->display = DefaultXDisplay();
6604 nsCAutoString description;
6605 GetPluginDescription(description);
6606 NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
6607 mFlash10Quirks = StringBeginsWith(description, flash10Head);
6608 #endif
6610 // Changing to windowless mode changes the NPWindow geometry.
6611 mObjectFrame->FixupWindow(mObjectFrame->GetContentRect().Size());
6612 } else if (mWidget) {
6613 nsIWidget* parent = mWidget->GetParent();
6614 NS_ASSERTION(parent, "Plugin windows must not be toplevel");
6615 // Set the plugin window to have an empty cliprect. The cliprect
6616 // will be reset when nsRootPresContext::UpdatePluginGeometry
6617 // runs later. The plugin window does need to have the correct
6618 // size here. GetEmptyClipConfiguration will probably give it the
6619 // size, but just in case we haven't been reflowed or something, set
6620 // the size explicitly.
6621 nsAutoTArray<nsIWidget::Configuration,1> configuration;
6622 mObjectFrame->GetEmptyClipConfiguration(&configuration);
6623 if (configuration.Length() > 0) {
6624 configuration[0].mBounds.width = mPluginWindow->width;
6625 configuration[0].mBounds.height = mPluginWindow->height;
6627 parent->ConfigureChildren(configuration);
6629 // mPluginWindow->type is used in |GetPluginPort| so it must
6630 // be initialized first
6631 mPluginWindow->type = NPWindowTypeWindow;
6632 mPluginWindow->window = GetPluginPortFromWidget();
6634 #ifdef MAC_CARBON_PLUGINS
6635 // start the idle timer.
6636 StartTimer(PR_TRUE);
6637 #endif
6639 // tell the plugin window about the widget
6640 mPluginWindow->SetPluginWidget(mWidget);
6642 // tell the widget about the current plugin instance owner.
6643 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
6644 if (pluginWidget)
6645 pluginWidget->SetPluginInstanceOwner(this);
6651 return rv;
6654 void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
6656 mPluginHost = aHost;
6659 #ifdef MOZ_USE_IMAGE_EXPOSE
6660 PRBool nsPluginInstanceOwner::UpdateVisibility(PRBool aVisible)
6662 // NOTE: Death grip must be held by caller.
6663 if (!mInstance)
6664 return PR_TRUE;
6666 NPEvent pluginEvent;
6667 XVisibilityEvent& visibilityEvent = pluginEvent.xvisibility;
6668 visibilityEvent.type = VisibilityNotify;
6669 visibilityEvent.display = 0;
6670 visibilityEvent.state = aVisible ? VisibilityUnobscured : VisibilityFullyObscured;
6671 mInstance->HandleEvent(&pluginEvent, nsnull);
6673 mWidgetVisible = PR_TRUE;
6674 return PR_TRUE;
6676 #endif
6678 // Mac specific code to fix up the port location and clipping region
6679 #ifdef XP_MACOSX
6681 void* nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
6683 if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame)
6684 return nsnull;
6686 NPDrawingModel drawingModel = GetDrawingModel();
6687 NPEventModel eventModel = GetEventModel();
6689 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
6690 if (!pluginWidget)
6691 return nsnull;
6693 // If we've already set up a CGContext in nsObjectFrame::PaintPlugin(), we
6694 // don't want calls to SetPluginPortAndDetectChange() to step on our work.
6695 void* pluginPort = nsnull;
6696 if (mInCGPaintLevel > 0) {
6697 pluginPort = mPluginWindow->window;
6698 } else {
6699 pluginPort = SetPluginPortAndDetectChange();
6702 #ifdef MAC_CARBON_PLUGINS
6703 if (eventModel == NPEventModelCarbon && !pluginPort)
6704 return nsnull;
6705 #endif
6707 // We'll need the top-level Cocoa window for the Cocoa event model.
6708 void* cocoaTopLevelWindow = nsnull;
6709 if (eventModel == NPEventModelCocoa) {
6710 nsIWidget* widget = mObjectFrame->GetNearestWidget();
6711 if (!widget)
6712 return nsnull;
6713 cocoaTopLevelWindow = widget->GetNativeData(NS_NATIVE_WINDOW);
6714 if (!cocoaTopLevelWindow)
6715 return nsnull;
6718 nsIntPoint pluginOrigin;
6719 nsIntRect widgetClip;
6720 PRBool widgetVisible;
6721 pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, widgetVisible);
6722 mWidgetVisible = widgetVisible;
6724 // printf("GetPluginClipRect returning visible %d\n", widgetVisible);
6726 #ifndef NP_NO_QUICKDRAW
6727 // set the port coordinates
6728 if (drawingModel == NPDrawingModelQuickDraw) {
6729 mPluginWindow->x = -static_cast<NP_Port*>(pluginPort)->portx;
6730 mPluginWindow->y = -static_cast<NP_Port*>(pluginPort)->porty;
6732 else if (drawingModel == NPDrawingModelCoreGraphics ||
6733 drawingModel == NPDrawingModelCoreAnimation ||
6734 drawingModel == NPDrawingModelInvalidatingCoreAnimation)
6735 #endif
6737 // This would be a lot easier if we could use obj-c here,
6738 // but we can't. Since we have only nsIWidget and we can't
6739 // use its native widget (an obj-c object) we have to go
6740 // from the widget's screen coordinates to its window coords
6741 // instead of straight to window coords.
6742 nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
6744 nsRect windowRect;
6745 #ifndef NP_NO_CARBON
6746 if (eventModel == NPEventModelCarbon)
6747 NS_NPAPI_CarbonWindowFrame(static_cast<WindowRef>(static_cast<NP_CGContext*>(pluginPort)->window), windowRect);
6748 else
6749 #endif
6751 NS_NPAPI_CocoaWindowFrame(cocoaTopLevelWindow, windowRect);
6754 mPluginWindow->x = geckoScreenCoords.x - windowRect.x;
6755 mPluginWindow->y = geckoScreenCoords.y - windowRect.y;
6758 NPRect oldClipRect = mPluginWindow->clipRect;
6760 // fix up the clipping region
6761 mPluginWindow->clipRect.top = widgetClip.y;
6762 mPluginWindow->clipRect.left = widgetClip.x;
6764 if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
6765 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
6766 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
6768 else if (inPaintState == ePluginPaintEnable)
6770 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
6771 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
6774 // if the clip rect changed, call SetWindow()
6775 // (RealPlayer needs this to draw correctly)
6776 if (mPluginWindow->clipRect.left != oldClipRect.left ||
6777 mPluginWindow->clipRect.top != oldClipRect.top ||
6778 mPluginWindow->clipRect.right != oldClipRect.right ||
6779 mPluginWindow->clipRect.bottom != oldClipRect.bottom)
6781 mInstance->SetWindow(mPluginWindow);
6782 mPluginPortChanged = PR_FALSE;
6783 #ifdef MAC_CARBON_PLUGINS
6784 // if the clipRect is of size 0, make the null timer fire less often
6785 CancelTimer();
6786 if (mPluginWindow->clipRect.left == mPluginWindow->clipRect.right ||
6787 mPluginWindow->clipRect.top == mPluginWindow->clipRect.bottom) {
6788 StartTimer(PR_FALSE);
6790 else {
6791 StartTimer(PR_TRUE);
6793 #endif
6794 } else if (mPluginPortChanged) {
6795 mInstance->SetWindow(mPluginWindow);
6796 mPluginPortChanged = PR_FALSE;
6799 // After the first NPP_SetWindow call we need to send an initial
6800 // top-level window focus event.
6801 if (eventModel == NPEventModelCocoa && !mSentInitialTopLevelWindowEvent) {
6802 // Set this before calling ProcessEvent to avoid endless recursion.
6803 mSentInitialTopLevelWindowEvent = PR_TRUE;
6805 nsGUIEvent pluginEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, nsnull);
6806 NPCocoaEvent cocoaEvent;
6807 InitializeNPCocoaEvent(&cocoaEvent);
6808 cocoaEvent.type = NPCocoaEventWindowFocusChanged;
6809 cocoaEvent.data.focus.hasFocus = NS_NPAPI_CocoaWindowIsMain(cocoaTopLevelWindow);
6810 pluginEvent.pluginEvent = &cocoaEvent;
6811 ProcessEvent(pluginEvent);
6814 #ifndef NP_NO_QUICKDRAW
6815 if (drawingModel == NPDrawingModelQuickDraw)
6816 return ::GetWindowFromPort(static_cast<NP_Port*>(pluginPort)->port);
6817 #endif
6819 #ifdef MAC_CARBON_PLUGINS
6820 if (drawingModel == NPDrawingModelCoreGraphics && eventModel == NPEventModelCarbon)
6821 return static_cast<NP_CGContext*>(pluginPort)->window;
6822 #endif
6824 return nsnull;
6827 void
6828 nsPluginInstanceOwner::HidePluginWindow()
6830 if (!mPluginWindow || !mInstance) {
6831 return;
6834 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
6835 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
6836 mWidgetVisible = PR_FALSE;
6837 mInstance->SetWindow(mPluginWindow);
6840 #else // XP_MACOSX
6842 void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(PRBool aSetWindow)
6844 if (!mPluginWindow)
6845 return;
6847 // For windowless plugins a non-empty clip rectangle will be
6848 // passed to the plugin during paint, an additional update
6849 // of the the clip rectangle here is not required
6850 if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
6851 return;
6853 const NPWindow oldWindow = *mPluginWindow;
6855 PRBool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
6856 nsIntPoint origin = mObjectFrame->GetWindowOriginInPixels(windowless);
6858 mPluginWindow->x = origin.x;
6859 mPluginWindow->y = origin.y;
6861 mPluginWindow->clipRect.left = 0;
6862 mPluginWindow->clipRect.top = 0;
6864 if (mPluginWindowVisible) {
6865 mPluginWindow->clipRect.right = mPluginWindow->width;
6866 mPluginWindow->clipRect.bottom = mPluginWindow->height;
6867 } else {
6868 mPluginWindow->clipRect.right = 0;
6869 mPluginWindow->clipRect.bottom = 0;
6872 if (!aSetWindow)
6873 return;
6875 if (mPluginWindow->x != oldWindow.x ||
6876 mPluginWindow->y != oldWindow.y ||
6877 mPluginWindow->clipRect.left != oldWindow.clipRect.left ||
6878 mPluginWindow->clipRect.top != oldWindow.clipRect.top ||
6879 mPluginWindow->clipRect.right != oldWindow.clipRect.right ||
6880 mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) {
6881 CallSetWindow();
6885 void
6886 nsPluginInstanceOwner::CallSetWindow()
6888 if (!mInstance)
6889 return;
6891 if (UseAsyncRendering()) {
6892 mInstance->AsyncSetWindow(mPluginWindow);
6893 } else {
6894 mInstance->SetWindow(mPluginWindow);
6898 void
6899 nsPluginInstanceOwner::UpdateWindowVisibility(PRBool aVisible)
6901 mPluginWindowVisible = aVisible;
6902 UpdateWindowPositionAndClipRect(PR_TRUE);
6905 #endif // XP_MACOSX
6907 // Little helper function to resolve relative URL in
6908 // |value| for certain inputs of |name|
6909 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
6911 if (name.LowerCaseEqualsLiteral("pluginurl") ||
6912 name.LowerCaseEqualsLiteral("pluginspage")) {
6914 nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
6915 nsAutoString newURL;
6916 NS_MakeAbsoluteURI(newURL, value, baseURI);
6917 if (!newURL.IsEmpty())
6918 value = newURL;
6922 #ifdef MOZ_USE_IMAGE_EXPOSE
6923 nsresult
6924 nsPluginInstanceOwner::SetAbsoluteScreenPosition(nsIDOMElement* element,
6925 nsIDOMClientRect* position,
6926 nsIDOMClientRect* clip)
6928 if (!element || !position || !clip)
6929 return NS_ERROR_FAILURE;
6931 // Making X or DOM method calls can cause our frame to go
6932 // away, which might kill us...
6933 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
6935 if (!mBlitWindow) {
6936 mBlitWindow = GDK_WINDOW_XWINDOW(GetClosestWindow(element));
6937 if (!mBlitWindow)
6938 return NS_ERROR_FAILURE;
6941 float left, top, width, height;
6942 position->GetLeft(&left);
6943 position->GetTop(&top);
6944 position->GetWidth(&width);
6945 position->GetHeight(&height);
6947 mAbsolutePosition = gfxRect(left, top, width, height);
6949 clip->GetLeft(&left);
6950 clip->GetTop(&top);
6951 clip->GetWidth(&width);
6952 clip->GetHeight(&height);
6954 mAbsolutePositionClip = gfxRect(left, top, width, height);
6956 UpdateVisibility(!(width == 0 && height == 0));
6958 if (!mInstance)
6959 return NS_OK;
6961 PRBool simpleImageRender = PR_FALSE;
6962 mInstance->GetValueFromPlugin(NPPVpluginWindowlessLocalBool,
6963 &simpleImageRender);
6964 if (simpleImageRender)
6965 NativeImageDraw();
6966 return NS_OK;
6968 #endif